diff --git a/.cursor/rules/rush.mdc b/.cursor/rules/rush.mdc index fd58e89c740..5ab342e9133 100644 --- a/.cursor/rules/rush.mdc +++ b/.cursor/rules/rush.mdc @@ -1,7 +1,7 @@ --- -description: A comprehensive guide for managing dependencies in Rush monorepo +description: globs: -alwaysApply: false +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: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3353c683dff..d2b3f9087b0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,15 +1,6 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { - "name": "Node.js & TypeScript", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/typescript-node:0-16", - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/rust:1": {}, - "devwasm.azurecr.io/dev-wasm/dev-wasm-feature/rust-wasi:0": {} - }, - // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 935ac6772e0..6bce8df4efb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,24 +1,22 @@ -.github/CODEOWNERS @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill -common/autoinstallers/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill -common/config/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill +.github/CODEOWNERS @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +common/autoinstallers/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +common/config/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha -common/reviews/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft +common/reviews/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha -apps/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -build-tests/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -build-tests-samples/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -eslint/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -heft-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -libraries/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -repo-scripts/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -rigs/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -rush-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -stack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -tutorials/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -webpack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @TheLarkInn -rush.json @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -.gitattributes @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -.gitignore @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -README.md @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft - -libraries/load-themed-styles/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @dzearing +apps/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests-samples/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests-subspace/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +eslint/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +heft-plugins/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +libraries/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +repo-scripts/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +rigs/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +rush-plugins/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +vscode-extensions/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +webpack/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha @TheLarkInn +rush.json @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +.gitattributes @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +.gitignore @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +README.md @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha diff --git a/.github/ISSUE_TEMPLATE/rush.md b/.github/ISSUE_TEMPLATE/rush.md index 0958df66671..63cb15486e0 100644 --- a/.github/ISSUE_TEMPLATE/rush.md +++ b/.github/ISSUE_TEMPLATE/rush.md @@ -60,7 +60,8 @@ Please answer these questions to help us investigate your issue more quickly: | -------- | -------- | | `@microsoft/rush` globally installed version? | | | `rushVersion` from rush.json? | | -| `useWorkspaces` from rush.json? | | +| `pnpmVersion`, `npmVersion`, or `yarnVersion` from rush.json? | | +| (if pnpm) `useWorkspaces` from pnpm-config.json? | | | Operating system? | | | Would you consider contributing a PR? | | | Node.js version (`node -v`)? | | diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000000..6f7d69f118d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,409 @@ +You are a Rush monorepo development and management expert. Your role is to assist with Rush-related tasks while following these key principles and best practices: + +# 1. Core Principles + +- Follow Monorepo best practices +- Adhere to Rush's project isolation principles +- Maintain clear dependency management +- Use standardized versioning and change management +- Implement efficient build processes + +# 2. Project Structure and Organization + +## 2.1 Standard Directory Structure + +The standard directory structure for a Rush monorepo is as follows: + + ``` + / + ├── common/ # Rush common files directory + | ├── autoinstallers # Autoinstaller tool configuration + │ ├── config/ # Configuration files directory + │ │ ├── rush/ # Rush core configuration + │ │ │ ├── command-line.json # Command line configuration + │ │ │ ├── build-cache.json # Build cache configuration + │ │ │ └── subspaces.json # Subspace configuration + │ │ └── subspaces/ # Subspace configuration + │ │ └── # Specific Subspace + │ │ ├── pnpm-lock.yaml # Subspace dependency lock file + │ │ ├── .pnpmfile.cjs # PNPM hook script + │ │ ├── common-versions.json # Subspace version configuration + │ │ ├── pnpm-config.json # PNPM configuration + │ │ └── repo-state.json # subspace state hash value + │ ├── scripts/ # Common scripts + │ └── temp/ # Temporary files + └── rush.json # Rush main configuration file + ``` + +## 2.2 Important Configuration Files + +1. `rush.json` (Root Directory) + + - Rush's main configuration file + - Key configuration items: + ```json + { + "rushVersion": "5.x.x", // Rush version + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + "projectFolderMinDepth": 1, // Minimum project depth + "projectFolderMaxDepth": 3, // Maximum project depth + "projects": [], // Project list + "nodeSupportedVersionRange": ">=14.15.0", // Node.js version requirement + + // Project configuration + "projects": [ + { + "packageName": "@scope/project-a", // Project package name + "projectFolder": "packages/project-a", // Project path + "shouldPublish": true, // Whether to publish + "decoupledLocalDependencies": [], // Cyclic dependency projects + "subspaceName": "subspaceA", // Which Subspace it belongs to + } + ], + } + ``` + +2. `common/config/rush/command-line.json` + + - Custom commands and parameter configuration + - Command types: + 1. `bulk`: Batch commands, executed separately for each project + ```json + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true, // Whether to allow parallelism + "ignoreMissingScript": false // Whether to ignore missing scripts + } + ``` + 2. `global`: Global commands, executed once for the entire repository + ```json + { + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "shellCommand": "node common/scripts/deploy.js" + } + ``` + + - Parameter types: + ```json + "parameters": [ + { + "parameterKind": "flag", // Switch parameter --production + "longName": "--production" + }, + { + "parameterKind": "string", // String parameter --env dev + "longName": "--env" + }, + { + "parameterKind": "stringList", // String list --tag a --tag b + "longName": "--tag" + }, + { + "parameterKind": "choice", // Choice parameter --locale en-us + "longName": "--locale", + "alternatives": ["en-us", "zh-cn"] + }, + { + "parameterKind": "integer", // Integer parameter --timeout 30 + "longName": "--timeout" + }, + { + "parameterKind": "integerList" // Integer list --pr 1 --pr 2 + "longName": "--pr" + } + ] + ``` + +3. `common/config/subspaces//common-versions.json` + + - Configure NPM dependency versions affecting all projects + - Key configuration items: + ```json + { + // Specify preferred versions for specific packages + "preferredVersions": { + "react": "17.0.2", // Restrict react version + "typescript": "~4.5.0" // Restrict typescript version + }, + + // Whether to automatically add all dependencies to preferredVersions + "implicitlyPreferredVersions": true, + + // Allow certain dependencies to use multiple different versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +4. `common/config/rush/subspaces.json` + - Purpose: Configure Rush Subspace functionality + - Key configuration items: + ```json + { + // Whether to enable Subspace functionality + "subspacesEnabled": false, + + // Subspace name list + "subspaceNames": ["team-a", "team-b"], + } + ``` + +# 3. Command Usage + +## 3.1 Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. `rush` command + - Purpose: Execute operations affecting the entire repository or multiple projects + - Features: + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing, and other standard operations + +2. `rushx` command + - Purpose: Execute specific scripts for a single project + - Features: + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector to ensure toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: + - Running project-specific build scripts + - Executing tests + - Running development servers + +3. `rush-pnpm` command + - Purpose: Replace direct use of pnpm in Rush repository + - Features: + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +## 3.2 Common Commands Explained + +1. `rush update` + - Function: Install and update dependencies + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - `--network-concurrency COUNT`: Limit concurrent network requests + - Use cases: + - After first cloning repository + - After pulling new Git changes + - After modifying package.json + - When dependencies need updating + +2. `rush install` + - Function: Install dependencies based on existing shrinkwrap file + - Features: + - Read-only operation, won't modify shrinkwrap file + - Suitable for CI environment + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - Use cases: + - CI/CD pipeline + - Ensuring dependency version consistency + - Avoiding accidental shrinkwrap file updates + +3. `rush build` + - Function: Incremental project build + - Features: + - Only builds changed projects + - Supports parallel building + - Use cases: + - Daily development builds + - Quick change validation + +4. `rush rebuild` + - Function: Complete clean build + - Features: + - Builds all projects + - Cleans previous build artifacts + - Use cases: + - When complete build cleaning is needed + - When investigating build issues + +5. `rush add` + - Function: Add dependencies to project + - Usage: `rush add -p [--dev] [--exact]` + - Important parameters: + - `-p, --package`: Package name + - `--dev`: Add as development dependency + - `--exact`: Use exact version + - Use cases: Adding new dependency packages + - Note: Must be run in corresponding project directory + +6. `rush remove` + - Function: Remove project dependencies + - Usage: `rush remove -p ` + - Use cases: Clean up unnecessary dependencies + +7. `rush purge` + - Function: Clean temporary files and installation files + - Use cases: + - Clean build environment + - Resolve dependency issues + - Free up disk space + +# 4. Dependency Management + +## 4.1 Package Manager Selection + +Specify in `rush.json`: + ```json + { + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + } + ``` + +## 4.2 Version Management + +- Location: `common/config/subspaces//common-versions.json` +- Configuration example: + ```json + { + // Specify preferred versions for packages + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + + // Allow certain dependencies to use multiple versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +## 4.3 Subspace + +Using Subspace technology allows organizing related projects together, meaning multiple PNPM lock files can be used in a Rush Monorepo. Different project groups can have their own independent dependency version management without affecting each other, thus isolating projects, reducing risks from dependency updates, and significantly improving dependency installation and update speed. + +Declare which Subspaces exist in `common/config/rush/subspaces.json`, and declare which Subspace each project belongs to in `rush.json`'s `subspaceName`. + +# 5. Caching Capabilities + +## 5.1 Cache Principles + +Rush cache is a build caching system that accelerates the build process by caching project build outputs. Build results are cached in `common/temp/build-cache`, and when project source files, dependencies, environment variables, command line parameters, etc., haven't changed, the cache is directly extracted instead of rebuilding. + +## 5.2 Core Configuration + +Configuration file: `/config/rush-project.json` + +```json +{ + "operationSettings": [ + { + "operationName": "build", // Operation name + "outputFolderNames": ["lib", "dist"], // Output directories + "disableBuildCacheForOperation": false, // Whether to disable cache + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"], // Dependent environment variables + } + ] +} +``` + +# 6. Best Practices + +## 6.1 Selecting Specific Projects + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. To improve efficiency, Rush provides various project selection parameters that can be chosen based on different scenarios: + +1. `--to ` + - Function: Select specified project and all its dependencies + - Use cases: + - Build specific project and its dependencies + - Ensure complete dependency chain build + - Example: + ```bash + rush build --to @my-company/my-project + rush build --to my-project # If project name is unique, scope can be omitted + rush build --to . # Use current directory's project + ``` + +2. `--to-except ` + - Function: Select all dependencies of specified project, but not the project itself + - Use cases: + - Update project dependencies without processing project itself + - Pre-build dependencies + - Example: + ```bash + rush build --to-except @my-company/my-project + ``` + +3. `--from ` + - Function: Select specified project and all its downstream dependencies + - Use cases: + - Validate changes' impact on downstream projects + - Build all projects affected by specific project + - Example: + ```bash + rush build --from @my-company/my-project + ``` + +4. `--impacted-by ` + - Function: Select projects that might be affected by specified project changes, excluding dependencies + - Use cases: + - Quick test of project change impacts + - Use when dependency status is already correct + - Example: + ```bash + rush build --impacted-by @my-company/my-project + ``` + +5. `--impacted-by-except ` + - Function: Similar to `--impacted-by`, but excludes specified project itself + - Use cases: + - Project itself has been manually built + - Only need to test downstream impacts + - Example: + ```bash + rush build --impacted-by-except @my-company/my-project + ``` + +6. `--only ` + - Function: Only select specified project, completely ignore dependency relationships + - Use cases: + - Clearly know dependency status is correct + - Combine with other selection parameters + - Example: + ```bash + rush build --only @my-company/my-project + rush build --impacted-by projectA --only projectB + ``` + +## 6.2 Troubleshooting + +1. Dependency Issue Handling + - Avoid directly using `npm`, `pnpm`, `yarn` package managers + - Use `rush purge` to clean all temporary files + - Run `rush update --recheck` to force check all dependencies + +2. Build Issue Handling + - Use `rush rebuild` to skip cache and perform complete build + - Check project's `rushx build` command output + +3. Logging and Diagnostics + - Use `--verbose` parameter for detailed logs + - Verify command parameter correctness diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7cfeeb2c71..e0932cb45c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,20 +12,30 @@ jobs: fail-fast: false matrix: include: + # When Node 18 is removed, remove the special cases in + # - build-tests-samples/heft-storybook-v9-react-tutorial/build.js + # - build-tests-samples/heft-storybook-v9-react-tutorial-app/build.js + # - The "globalOverrides" entry for "@vscode/vsce>cheerio" in common/config/rush/pnpm-config.json + # - libraries/module-minifier/src/cryptoPolyfill.ts - NodeVersion: 18.20.x NodeVersionDisplayName: 18 OS: ubuntu-latest - NodeVersion: 20.18.x NodeVersionDisplayName: 20 OS: ubuntu-latest - - NodeVersion: 22.12.x + - NodeVersion: 22.19.x NodeVersionDisplayName: 22 OS: ubuntu-latest - - NodeVersion: 22.12.x - NodeVersionDisplayName: 22 + - NodeVersion: 24.11.x + NodeVersionDisplayName: 24 + OS: ubuntu-latest + - NodeVersion: 24.11.x + NodeVersionDisplayName: 24 OS: windows-latest name: Node.js v${{ matrix.NodeVersionDisplayName }} (${{ matrix.OS }}) runs-on: ${{ matrix.OS }} + env: + INSTALL_RUN_RUSH_LOCKFILE_PATH: ${{ github.workspace }}/repo-a/common/config/validation/rush-package-lock.json steps: - name: Create ~/.rush-user/settings.json shell: pwsh @@ -40,7 +50,7 @@ jobs: mkdir -p $HOME/.rush-user @{ buildCacheFolder = Join-Path ${{ github.workspace }} rush-cache } | ConvertTo-Json > $HOME/.rush-user/settings.json - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 with: fetch-depth: 2 path: repo-a @@ -51,7 +61,7 @@ jobs: git config --local user.email "rushbot@users.noreply.github.com" working-directory: repo-a - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: node-version: ${{ matrix.NodeVersion }} @@ -72,12 +82,24 @@ jobs: run: node common/scripts/install-run-rush.js retest --verbose --production working-directory: repo-a + - name: Run package manager integration tests + run: npm run test + working-directory: repo-a/build-tests/rush-package-manager-integration-test + - name: Ensure repo README is up-to-date - run: node repo-scripts/repo-toolbox/lib/start.js readme --verify + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js readme --verify + working-directory: repo-a + + - name: Collect JSON schemas + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-project-files --subfolder temp/json-schemas --output-path ${GITHUB_WORKSPACE}/artifacts/json-schemas + working-directory: repo-a + + - name: Collect API review files + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-project-files --subfolder temp/api --output-path ${GITHUB_WORKSPACE}/artifacts/api working-directory: repo-a - name: Clone another copy of the repo to test the build cache - uses: actions/checkout@v3 + uses: actions/checkout@v6 with: fetch-depth: 1 path: repo-b @@ -89,9 +111,13 @@ jobs: working-directory: repo-b - name: Rush update (rush-lib) - run: node ${{ github.workspace }}/repo-a/apps/rush/lib/start-dev.js update + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js update working-directory: repo-b - name: Rush test (rush-lib) - run: node ${{ github.workspace }}/repo-a/apps/rush/lib/start-dev.js test --verbose --production --timeline + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js test --verbose --production --timeline + working-directory: repo-b + + - name: Rush test (rush-lib) again to verify build cache hits + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js test --verbose --production --timeline working-directory: repo-b diff --git a/.github/workflows/file-doc-tickets.yml b/.github/workflows/file-doc-tickets.yml index a22ca91016d..b2968d451f7 100644 --- a/.github/workflows/file-doc-tickets.yml +++ b/.github/workflows/file-doc-tickets.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Use nodejs - uses: actions/setup-node@v3 + uses: actions/setup-node@v6 with: node-version: 16 - name: Parse PR body @@ -76,7 +76,7 @@ jobs: fi - name: File ticket if: ${{ env.FILE_TICKET == '1' }} - uses: peter-evans/create-issue-from-file@af31b99c72f9e91877aea8a2d96fd613beafac84 # @v4 (locked) + uses: peter-evans/create-issue-from-file@fca9117c27cdc29c6c4db3b86c48e4115a786710 # v6.0.0 with: repository: microsoft/rushstack-websites token: '${{ secrets.RUSHSTACK_WEBSITES_PR_TOKEN }}' diff --git a/.gitignore b/.gitignore index 68c897ad310..6f360c85f74 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,8 @@ jspm_packages/ .vscode/ !.vscode/tasks.json !.vscode/launch.json +!.vscode/debug-certificate-manager.json +!.vscode/mcp.json # Rush temporary files common/deploy/ @@ -107,6 +109,7 @@ common/autoinstallers/*/.npmrc *.lock # Common toolchain intermediate files +build/ temp/ lib/ lib-amd/ @@ -123,3 +126,14 @@ dist-storybook/ # Heft temporary files .cache/ .heft/ + +# VS Code test runner files +.vscode-test/ + +# Playwright test outputs +playwright-report/ +test-results/ + +# Claude Code local configuration +.claude/*.local.json +**/tmpclaude-*-cwd diff --git a/.prettierignore b/.prettierignore index 5f92ce14d67..45e09e79d75 100644 --- a/.prettierignore +++ b/.prettierignore @@ -114,6 +114,7 @@ temp/ lib/ lib-amd/ lib-es6/ +lib-esm/ lib-esnext/ lib-commonjs/ lib-shim/ diff --git a/.trae/project_rules.md b/.trae/project_rules.md new file mode 100644 index 00000000000..6f7d69f118d --- /dev/null +++ b/.trae/project_rules.md @@ -0,0 +1,409 @@ +You are a Rush monorepo development and management expert. Your role is to assist with Rush-related tasks while following these key principles and best practices: + +# 1. Core Principles + +- Follow Monorepo best practices +- Adhere to Rush's project isolation principles +- Maintain clear dependency management +- Use standardized versioning and change management +- Implement efficient build processes + +# 2. Project Structure and Organization + +## 2.1 Standard Directory Structure + +The standard directory structure for a Rush monorepo is as follows: + + ``` + / + ├── common/ # Rush common files directory + | ├── autoinstallers # Autoinstaller tool configuration + │ ├── config/ # Configuration files directory + │ │ ├── rush/ # Rush core configuration + │ │ │ ├── command-line.json # Command line configuration + │ │ │ ├── build-cache.json # Build cache configuration + │ │ │ └── subspaces.json # Subspace configuration + │ │ └── subspaces/ # Subspace configuration + │ │ └── # Specific Subspace + │ │ ├── pnpm-lock.yaml # Subspace dependency lock file + │ │ ├── .pnpmfile.cjs # PNPM hook script + │ │ ├── common-versions.json # Subspace version configuration + │ │ ├── pnpm-config.json # PNPM configuration + │ │ └── repo-state.json # subspace state hash value + │ ├── scripts/ # Common scripts + │ └── temp/ # Temporary files + └── rush.json # Rush main configuration file + ``` + +## 2.2 Important Configuration Files + +1. `rush.json` (Root Directory) + + - Rush's main configuration file + - Key configuration items: + ```json + { + "rushVersion": "5.x.x", // Rush version + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + "projectFolderMinDepth": 1, // Minimum project depth + "projectFolderMaxDepth": 3, // Maximum project depth + "projects": [], // Project list + "nodeSupportedVersionRange": ">=14.15.0", // Node.js version requirement + + // Project configuration + "projects": [ + { + "packageName": "@scope/project-a", // Project package name + "projectFolder": "packages/project-a", // Project path + "shouldPublish": true, // Whether to publish + "decoupledLocalDependencies": [], // Cyclic dependency projects + "subspaceName": "subspaceA", // Which Subspace it belongs to + } + ], + } + ``` + +2. `common/config/rush/command-line.json` + + - Custom commands and parameter configuration + - Command types: + 1. `bulk`: Batch commands, executed separately for each project + ```json + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true, // Whether to allow parallelism + "ignoreMissingScript": false // Whether to ignore missing scripts + } + ``` + 2. `global`: Global commands, executed once for the entire repository + ```json + { + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "shellCommand": "node common/scripts/deploy.js" + } + ``` + + - Parameter types: + ```json + "parameters": [ + { + "parameterKind": "flag", // Switch parameter --production + "longName": "--production" + }, + { + "parameterKind": "string", // String parameter --env dev + "longName": "--env" + }, + { + "parameterKind": "stringList", // String list --tag a --tag b + "longName": "--tag" + }, + { + "parameterKind": "choice", // Choice parameter --locale en-us + "longName": "--locale", + "alternatives": ["en-us", "zh-cn"] + }, + { + "parameterKind": "integer", // Integer parameter --timeout 30 + "longName": "--timeout" + }, + { + "parameterKind": "integerList" // Integer list --pr 1 --pr 2 + "longName": "--pr" + } + ] + ``` + +3. `common/config/subspaces//common-versions.json` + + - Configure NPM dependency versions affecting all projects + - Key configuration items: + ```json + { + // Specify preferred versions for specific packages + "preferredVersions": { + "react": "17.0.2", // Restrict react version + "typescript": "~4.5.0" // Restrict typescript version + }, + + // Whether to automatically add all dependencies to preferredVersions + "implicitlyPreferredVersions": true, + + // Allow certain dependencies to use multiple different versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +4. `common/config/rush/subspaces.json` + - Purpose: Configure Rush Subspace functionality + - Key configuration items: + ```json + { + // Whether to enable Subspace functionality + "subspacesEnabled": false, + + // Subspace name list + "subspaceNames": ["team-a", "team-b"], + } + ``` + +# 3. Command Usage + +## 3.1 Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. `rush` command + - Purpose: Execute operations affecting the entire repository or multiple projects + - Features: + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing, and other standard operations + +2. `rushx` command + - Purpose: Execute specific scripts for a single project + - Features: + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector to ensure toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: + - Running project-specific build scripts + - Executing tests + - Running development servers + +3. `rush-pnpm` command + - Purpose: Replace direct use of pnpm in Rush repository + - Features: + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +## 3.2 Common Commands Explained + +1. `rush update` + - Function: Install and update dependencies + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - `--network-concurrency COUNT`: Limit concurrent network requests + - Use cases: + - After first cloning repository + - After pulling new Git changes + - After modifying package.json + - When dependencies need updating + +2. `rush install` + - Function: Install dependencies based on existing shrinkwrap file + - Features: + - Read-only operation, won't modify shrinkwrap file + - Suitable for CI environment + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - Use cases: + - CI/CD pipeline + - Ensuring dependency version consistency + - Avoiding accidental shrinkwrap file updates + +3. `rush build` + - Function: Incremental project build + - Features: + - Only builds changed projects + - Supports parallel building + - Use cases: + - Daily development builds + - Quick change validation + +4. `rush rebuild` + - Function: Complete clean build + - Features: + - Builds all projects + - Cleans previous build artifacts + - Use cases: + - When complete build cleaning is needed + - When investigating build issues + +5. `rush add` + - Function: Add dependencies to project + - Usage: `rush add -p [--dev] [--exact]` + - Important parameters: + - `-p, --package`: Package name + - `--dev`: Add as development dependency + - `--exact`: Use exact version + - Use cases: Adding new dependency packages + - Note: Must be run in corresponding project directory + +6. `rush remove` + - Function: Remove project dependencies + - Usage: `rush remove -p ` + - Use cases: Clean up unnecessary dependencies + +7. `rush purge` + - Function: Clean temporary files and installation files + - Use cases: + - Clean build environment + - Resolve dependency issues + - Free up disk space + +# 4. Dependency Management + +## 4.1 Package Manager Selection + +Specify in `rush.json`: + ```json + { + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + } + ``` + +## 4.2 Version Management + +- Location: `common/config/subspaces//common-versions.json` +- Configuration example: + ```json + { + // Specify preferred versions for packages + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + + // Allow certain dependencies to use multiple versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +## 4.3 Subspace + +Using Subspace technology allows organizing related projects together, meaning multiple PNPM lock files can be used in a Rush Monorepo. Different project groups can have their own independent dependency version management without affecting each other, thus isolating projects, reducing risks from dependency updates, and significantly improving dependency installation and update speed. + +Declare which Subspaces exist in `common/config/rush/subspaces.json`, and declare which Subspace each project belongs to in `rush.json`'s `subspaceName`. + +# 5. Caching Capabilities + +## 5.1 Cache Principles + +Rush cache is a build caching system that accelerates the build process by caching project build outputs. Build results are cached in `common/temp/build-cache`, and when project source files, dependencies, environment variables, command line parameters, etc., haven't changed, the cache is directly extracted instead of rebuilding. + +## 5.2 Core Configuration + +Configuration file: `/config/rush-project.json` + +```json +{ + "operationSettings": [ + { + "operationName": "build", // Operation name + "outputFolderNames": ["lib", "dist"], // Output directories + "disableBuildCacheForOperation": false, // Whether to disable cache + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"], // Dependent environment variables + } + ] +} +``` + +# 6. Best Practices + +## 6.1 Selecting Specific Projects + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. To improve efficiency, Rush provides various project selection parameters that can be chosen based on different scenarios: + +1. `--to ` + - Function: Select specified project and all its dependencies + - Use cases: + - Build specific project and its dependencies + - Ensure complete dependency chain build + - Example: + ```bash + rush build --to @my-company/my-project + rush build --to my-project # If project name is unique, scope can be omitted + rush build --to . # Use current directory's project + ``` + +2. `--to-except ` + - Function: Select all dependencies of specified project, but not the project itself + - Use cases: + - Update project dependencies without processing project itself + - Pre-build dependencies + - Example: + ```bash + rush build --to-except @my-company/my-project + ``` + +3. `--from ` + - Function: Select specified project and all its downstream dependencies + - Use cases: + - Validate changes' impact on downstream projects + - Build all projects affected by specific project + - Example: + ```bash + rush build --from @my-company/my-project + ``` + +4. `--impacted-by ` + - Function: Select projects that might be affected by specified project changes, excluding dependencies + - Use cases: + - Quick test of project change impacts + - Use when dependency status is already correct + - Example: + ```bash + rush build --impacted-by @my-company/my-project + ``` + +5. `--impacted-by-except ` + - Function: Similar to `--impacted-by`, but excludes specified project itself + - Use cases: + - Project itself has been manually built + - Only need to test downstream impacts + - Example: + ```bash + rush build --impacted-by-except @my-company/my-project + ``` + +6. `--only ` + - Function: Only select specified project, completely ignore dependency relationships + - Use cases: + - Clearly know dependency status is correct + - Combine with other selection parameters + - Example: + ```bash + rush build --only @my-company/my-project + rush build --impacted-by projectA --only projectB + ``` + +## 6.2 Troubleshooting + +1. Dependency Issue Handling + - Avoid directly using `npm`, `pnpm`, `yarn` package managers + - Use `rush purge` to clean all temporary files + - Run `rush update --recheck` to force check all dependencies + +2. Build Issue Handling + - Use `rush rebuild` to skip cache and perform complete build + - Check project's `rushx build` command output + +3. Logging and Diagnostics + - Use `--verbose` parameter for detailed logs + - Verify command parameter correctness diff --git a/.vscode/debug-certificate-manager.json b/.vscode/debug-certificate-manager.json new file mode 100644 index 00000000000..c574800aa91 --- /dev/null +++ b/.vscode/debug-certificate-manager.json @@ -0,0 +1,3 @@ +{ + "storePath": "common/temp/debug-certificates" +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ca13c319af..265fd0e412d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Rush Debug", "type": "node", "request": "launch", - "program": "${workspaceRoot}/apps/rush/lib/start-dev.js", + "program": "${workspaceRoot}/apps/rush/lib-commonjs/start-dev.js", "stopOnEntry": true, "args": [ "start" @@ -36,9 +36,11 @@ "runtimeArgs": [ "--nolazy", "--inspect-brk", - "${workspaceFolder}/apps/heft/lib/start.js", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", "--debug", - "test-watch" + "test", + "--test-path-pattern", + "${fileBasenameNoExtension}" ], "skipFiles": ["/**"], "outFiles": [], @@ -54,7 +56,7 @@ "runtimeArgs": [ "--nolazy", "--inspect-brk", - "${workspaceFolder}/apps/heft/lib/start.js", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", "--debug", "build" ], @@ -64,6 +66,25 @@ "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" }, + { + "type": "node", + "request": "launch", + "name": "Debug Clean Build in Selected Project (Heft)", + "cwd": "${fileDirname}", + "runtimeArgs": [ + "--nolazy", + "--inspect-brk", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", + "--debug", + "build", + "--clean" + ], + "skipFiles": ["/**"], + "outFiles": [], + "sourceMaps": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, { "name": "Attach", "type": "node", @@ -77,12 +98,38 @@ "request": "launch", "cwd": "${workspaceFolder}/vscode-extensions/rush-vscode-extension", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/rush-vscode-extension" + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/rush-vscode-extension/dist/vsix/unpacked" ], "outFiles": [ - "${workspaceFolder}/vscode-extensions/rush-vscode-extension/dist/**/*.js" + "${workspaceFolder}/vscode-extensions/rush-vscode-extension/**" ] // "preLaunchTask": "npm: build:watch - vscode-extensions/rush-vscode-extension" + }, + { + "name": "Launch Debug Certificate Manager VS Code Extension", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/dist/vsix/unpacked", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/dist/vsix/unpacked" + ], + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/**" + ] + }, + { + "name": "Launch Playwright Local Browser Server VS Code Extension", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/dist/vsix/unpacked", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/dist/vsix/unpacked" + ], + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/**/*.js" + ] } ] } diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 00000000000..c956558d21b --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,12 @@ +{ + "servers": { + "playwright": { + "type": "stdio", + "command": "node", + "args": [ + "${workspaceFolder}/apps/playwright-browser-tunnel/lib/PlaywrightMcpBrowserTunnelClientCommandLine.js" + ] + } + }, + "inputs": [] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 5367d5843db..0fc07ff37ea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,35 @@ "files.associations": { "**/package.json": "json", "**/*.json": "jsonc" - } + }, + "json.schemas": [ + { + "fileMatch": ["/rush.json"], + "url": "./libraries/rush-lib/src/schemas/rush.schema.json" + }, + { + "fileMatch": ["**/rush-plugin.json"], + "url": "./libraries/rush-lib/src/schemas/rush-plugin-manifest.schema.json" + }, + { + "fileMatch": ["**/config/heft.json"], + "url": "./apps/heft/src/schemas/heft.schema.json" + }, + { + "fileMatch": ["**/config/rig.json"], + "url": "./libraries/rig-package/src/schemas/rig.schema.json" + }, + { + "fileMatch": ["**/config/rush-project.json"], + "url": "./libraries/rush-lib/src/schemas/rush-project.schema.json" + }, + { + "fileMatch": ["**/config/typescript.json"], + "url": "./heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json" + }, + { + "fileMatch": ["**/heft-plugin.json"], + "url": "./apps/heft/src/schemas/heft-plugin.schema.json" + } + ] } diff --git a/README.md b/README.md index a506c6af0e1..8a54e1dea4e 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,12 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/apps/cpu-profile-summarizer](./apps/cpu-profile-summarizer/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fcpu-profile-summarizer.svg)](https://badge.fury.io/js/%40rushstack%2Fcpu-profile-summarizer) | [changelog](./apps/cpu-profile-summarizer/CHANGELOG.md) | [@rushstack/cpu-profile-summarizer](https://www.npmjs.com/package/@rushstack/cpu-profile-summarizer) | | [/apps/heft](./apps/heft/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft.svg)](https://badge.fury.io/js/%40rushstack%2Fheft) | [changelog](./apps/heft/CHANGELOG.md) | [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) | | [/apps/lockfile-explorer](./apps/lockfile-explorer/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flockfile-explorer.svg)](https://badge.fury.io/js/%40rushstack%2Flockfile-explorer) | [changelog](./apps/lockfile-explorer/CHANGELOG.md) | [@rushstack/lockfile-explorer](https://www.npmjs.com/package/@rushstack/lockfile-explorer) | +| [/apps/playwright-browser-tunnel](./apps/playwright-browser-tunnel/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fplaywright-browser-tunnel.svg)](https://badge.fury.io/js/%40rushstack%2Fplaywright-browser-tunnel) | [changelog](./apps/playwright-browser-tunnel/CHANGELOG.md) | [@rushstack/playwright-browser-tunnel](https://www.npmjs.com/package/@rushstack/playwright-browser-tunnel) | | [/apps/rundown](./apps/rundown/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frundown.svg)](https://badge.fury.io/js/%40rushstack%2Frundown) | [changelog](./apps/rundown/CHANGELOG.md) | [@rushstack/rundown](https://www.npmjs.com/package/@rushstack/rundown) | | [/apps/rush](./apps/rush/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush.svg)](https://badge.fury.io/js/%40microsoft%2Frush) | [changelog](./apps/rush/CHANGELOG.md) | [@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) | | [/apps/rush-mcp-server](./apps/rush-mcp-server/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fmcp-server.svg)](https://badge.fury.io/js/%40rushstack%2Fmcp-server) | [changelog](./apps/rush-mcp-server/CHANGELOG.md) | [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) | | [/apps/trace-import](./apps/trace-import/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftrace-import.svg)](https://badge.fury.io/js/%40rushstack%2Ftrace-import) | [changelog](./apps/trace-import/CHANGELOG.md) | [@rushstack/trace-import](https://www.npmjs.com/package/@rushstack/trace-import) | +| [/apps/zipsync](./apps/zipsync/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fzipsync.svg)](https://badge.fury.io/js/%40rushstack%2Fzipsync) | [changelog](./apps/zipsync/CHANGELOG.md) | [@rushstack/zipsync](https://www.npmjs.com/package/@rushstack/zipsync) | | [/eslint/eslint-bulk](./eslint/eslint-bulk/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-bulk.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-bulk) | [changelog](./eslint/eslint-bulk/CHANGELOG.md) | [@rushstack/eslint-bulk](https://www.npmjs.com/package/@rushstack/eslint-bulk) | | [/eslint/eslint-config](./eslint/eslint-config/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-config.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-config) | [changelog](./eslint/eslint-config/CHANGELOG.md) | [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) | | [/eslint/eslint-patch](./eslint/eslint-patch/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-patch.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-patch) | [changelog](./eslint/eslint-patch/CHANGELOG.md) | [@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch) | @@ -67,16 +69,21 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/heft-plugins/heft-dev-cert-plugin](./heft-plugins/heft-dev-cert-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-dev-cert-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-dev-cert-plugin) | [changelog](./heft-plugins/heft-dev-cert-plugin/CHANGELOG.md) | [@rushstack/heft-dev-cert-plugin](https://www.npmjs.com/package/@rushstack/heft-dev-cert-plugin) | | [/heft-plugins/heft-isolated-typescript-transpile-plugin](./heft-plugins/heft-isolated-typescript-transpile-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-isolated-typescript-transpile-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-isolated-typescript-transpile-plugin) | [changelog](./heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md) | [@rushstack/heft-isolated-typescript-transpile-plugin](https://www.npmjs.com/package/@rushstack/heft-isolated-typescript-transpile-plugin) | | [/heft-plugins/heft-jest-plugin](./heft-plugins/heft-jest-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin) | [changelog](./heft-plugins/heft-jest-plugin/CHANGELOG.md) | [@rushstack/heft-jest-plugin](https://www.npmjs.com/package/@rushstack/heft-jest-plugin) | +| [/heft-plugins/heft-json-schema-typings-plugin](./heft-plugins/heft-json-schema-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-json-schema-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-json-schema-typings-plugin) | [changelog](./heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md) | [@rushstack/heft-json-schema-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-json-schema-typings-plugin) | | [/heft-plugins/heft-lint-plugin](./heft-plugins/heft-lint-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin) | [changelog](./heft-plugins/heft-lint-plugin/CHANGELOG.md) | [@rushstack/heft-lint-plugin](https://www.npmjs.com/package/@rushstack/heft-lint-plugin) | | [/heft-plugins/heft-localization-typings-plugin](./heft-plugins/heft-localization-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin) | [changelog](./heft-plugins/heft-localization-typings-plugin/CHANGELOG.md) | [@rushstack/heft-localization-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-localization-typings-plugin) | +| [/heft-plugins/heft-rspack-plugin](./heft-plugins/heft-rspack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-rspack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-rspack-plugin) | [changelog](./heft-plugins/heft-rspack-plugin/CHANGELOG.md) | [@rushstack/heft-rspack-plugin](https://www.npmjs.com/package/@rushstack/heft-rspack-plugin) | | [/heft-plugins/heft-sass-load-themed-styles-plugin](./heft-plugins/heft-sass-load-themed-styles-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin) | [changelog](./heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md) | [@rushstack/heft-sass-load-themed-styles-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-load-themed-styles-plugin) | | [/heft-plugins/heft-sass-plugin](./heft-plugins/heft-sass-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin) | [changelog](./heft-plugins/heft-sass-plugin/CHANGELOG.md) | [@rushstack/heft-sass-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-plugin) | | [/heft-plugins/heft-serverless-stack-plugin](./heft-plugins/heft-serverless-stack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin) | [changelog](./heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md) | [@rushstack/heft-serverless-stack-plugin](https://www.npmjs.com/package/@rushstack/heft-serverless-stack-plugin) | +| [/heft-plugins/heft-static-asset-typings-plugin](./heft-plugins/heft-static-asset-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-static-asset-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-static-asset-typings-plugin) | [changelog](./heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md) | [@rushstack/heft-static-asset-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-static-asset-typings-plugin) | | [/heft-plugins/heft-storybook-plugin](./heft-plugins/heft-storybook-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin) | [changelog](./heft-plugins/heft-storybook-plugin/CHANGELOG.md) | [@rushstack/heft-storybook-plugin](https://www.npmjs.com/package/@rushstack/heft-storybook-plugin) | | [/heft-plugins/heft-typescript-plugin](./heft-plugins/heft-typescript-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin) | [changelog](./heft-plugins/heft-typescript-plugin/CHANGELOG.md) | [@rushstack/heft-typescript-plugin](https://www.npmjs.com/package/@rushstack/heft-typescript-plugin) | +| [/heft-plugins/heft-vscode-extension-plugin](./heft-plugins/heft-vscode-extension-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin) | [changelog](./heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md) | [@rushstack/heft-vscode-extension-plugin](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-plugin) | | [/heft-plugins/heft-webpack4-plugin](./heft-plugins/heft-webpack4-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin) | [changelog](./heft-plugins/heft-webpack4-plugin/CHANGELOG.md) | [@rushstack/heft-webpack4-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack4-plugin) | | [/heft-plugins/heft-webpack5-plugin](./heft-plugins/heft-webpack5-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin) | [changelog](./heft-plugins/heft-webpack5-plugin/CHANGELOG.md) | [@rushstack/heft-webpack5-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack5-plugin) | | [/libraries/api-extractor-model](./libraries/api-extractor-model/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model.svg)](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model) | [changelog](./libraries/api-extractor-model/CHANGELOG.md) | [@microsoft/api-extractor-model](https://www.npmjs.com/package/@microsoft/api-extractor-model) | +| [/libraries/credential-cache](./libraries/credential-cache/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fcredential-cache.svg)](https://badge.fury.io/js/%40rushstack%2Fcredential-cache) | [changelog](./libraries/credential-cache/CHANGELOG.md) | [@rushstack/credential-cache](https://www.npmjs.com/package/@rushstack/credential-cache) | | [/libraries/debug-certificate-manager](./libraries/debug-certificate-manager/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager.svg)](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager) | [changelog](./libraries/debug-certificate-manager/CHANGELOG.md) | [@rushstack/debug-certificate-manager](https://www.npmjs.com/package/@rushstack/debug-certificate-manager) | | [/libraries/heft-config-file](./libraries/heft-config-file/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-config-file.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-config-file) | [changelog](./libraries/heft-config-file/CHANGELOG.md) | [@rushstack/heft-config-file](https://www.npmjs.com/package/@rushstack/heft-config-file) | | [/libraries/load-themed-styles](./libraries/load-themed-styles/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles.svg)](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles) | [changelog](./libraries/load-themed-styles/CHANGELOG.md) | [@microsoft/load-themed-styles](https://www.npmjs.com/package/@microsoft/load-themed-styles) | @@ -84,11 +91,16 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/libraries/lookup-by-path](./libraries/lookup-by-path/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flookup-by-path.svg)](https://badge.fury.io/js/%40rushstack%2Flookup-by-path) | [changelog](./libraries/lookup-by-path/CHANGELOG.md) | [@rushstack/lookup-by-path](https://www.npmjs.com/package/@rushstack/lookup-by-path) | | [/libraries/module-minifier](./libraries/module-minifier/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fmodule-minifier.svg)](https://badge.fury.io/js/%40rushstack%2Fmodule-minifier) | [changelog](./libraries/module-minifier/CHANGELOG.md) | [@rushstack/module-minifier](https://www.npmjs.com/package/@rushstack/module-minifier) | | [/libraries/node-core-library](./libraries/node-core-library/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fnode-core-library.svg)](https://badge.fury.io/js/%40rushstack%2Fnode-core-library) | [changelog](./libraries/node-core-library/CHANGELOG.md) | [@rushstack/node-core-library](https://www.npmjs.com/package/@rushstack/node-core-library) | +| [/libraries/npm-check-fork](./libraries/npm-check-fork/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fnpm-check-fork.svg)](https://badge.fury.io/js/%40rushstack%2Fnpm-check-fork) | [changelog](./libraries/npm-check-fork/CHANGELOG.md) | [@rushstack/npm-check-fork](https://www.npmjs.com/package/@rushstack/npm-check-fork) | | [/libraries/operation-graph](./libraries/operation-graph/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Foperation-graph.svg)](https://badge.fury.io/js/%40rushstack%2Foperation-graph) | [changelog](./libraries/operation-graph/CHANGELOG.md) | [@rushstack/operation-graph](https://www.npmjs.com/package/@rushstack/operation-graph) | | [/libraries/package-deps-hash](./libraries/package-deps-hash/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fpackage-deps-hash.svg)](https://badge.fury.io/js/%40rushstack%2Fpackage-deps-hash) | [changelog](./libraries/package-deps-hash/CHANGELOG.md) | [@rushstack/package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) | | [/libraries/package-extractor](./libraries/package-extractor/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fpackage-extractor.svg)](https://badge.fury.io/js/%40rushstack%2Fpackage-extractor) | [changelog](./libraries/package-extractor/CHANGELOG.md) | [@rushstack/package-extractor](https://www.npmjs.com/package/@rushstack/package-extractor) | +| [/libraries/problem-matcher](./libraries/problem-matcher/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fproblem-matcher.svg)](https://badge.fury.io/js/%40rushstack%2Fproblem-matcher) | [changelog](./libraries/problem-matcher/CHANGELOG.md) | [@rushstack/problem-matcher](https://www.npmjs.com/package/@rushstack/problem-matcher) | | [/libraries/rig-package](./libraries/rig-package/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frig-package.svg)](https://badge.fury.io/js/%40rushstack%2Frig-package) | [changelog](./libraries/rig-package/CHANGELOG.md) | [@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) | | [/libraries/rush-lib](./libraries/rush-lib/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-lib.svg)](https://badge.fury.io/js/%40microsoft%2Frush-lib) | | [@microsoft/rush-lib](https://www.npmjs.com/package/@microsoft/rush-lib) | +| [/libraries/rush-pnpm-kit-v10](./libraries/rush-pnpm-kit-v10/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v10.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v10) | [changelog](./libraries/rush-pnpm-kit-v10/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v10](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v10) | +| [/libraries/rush-pnpm-kit-v8](./libraries/rush-pnpm-kit-v8/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v8.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v8) | [changelog](./libraries/rush-pnpm-kit-v8/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v8](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v8) | +| [/libraries/rush-pnpm-kit-v9](./libraries/rush-pnpm-kit-v9/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v9.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v9) | [changelog](./libraries/rush-pnpm-kit-v9/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v9](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v9) | | [/libraries/rush-sdk](./libraries/rush-sdk/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-sdk.svg)](https://badge.fury.io/js/%40rushstack%2Frush-sdk) | | [@rushstack/rush-sdk](https://www.npmjs.com/package/@rushstack/rush-sdk) | | [/libraries/stream-collator](./libraries/stream-collator/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fstream-collator.svg)](https://badge.fury.io/js/%40rushstack%2Fstream-collator) | [changelog](./libraries/stream-collator/CHANGELOG.md) | [@rushstack/stream-collator](https://www.npmjs.com/package/@rushstack/stream-collator) | | [/libraries/terminal](./libraries/terminal/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fterminal.svg)](https://badge.fury.io/js/%40rushstack%2Fterminal) | [changelog](./libraries/terminal/CHANGELOG.md) | [@rushstack/terminal](https://www.npmjs.com/package/@rushstack/terminal) | @@ -97,11 +109,15 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/libraries/typings-generator](./libraries/typings-generator/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftypings-generator.svg)](https://badge.fury.io/js/%40rushstack%2Ftypings-generator) | [changelog](./libraries/typings-generator/CHANGELOG.md) | [@rushstack/typings-generator](https://www.npmjs.com/package/@rushstack/typings-generator) | | [/libraries/worker-pool](./libraries/worker-pool/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fworker-pool.svg)](https://badge.fury.io/js/%40rushstack%2Fworker-pool) | [changelog](./libraries/worker-pool/CHANGELOG.md) | [@rushstack/worker-pool](https://www.npmjs.com/package/@rushstack/worker-pool) | | [/rigs/heft-node-rig](./rigs/heft-node-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig) | [changelog](./rigs/heft-node-rig/CHANGELOG.md) | [@rushstack/heft-node-rig](https://www.npmjs.com/package/@rushstack/heft-node-rig) | +| [/rigs/heft-vscode-extension-rig](./rigs/heft-vscode-extension-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig) | [changelog](./rigs/heft-vscode-extension-rig/CHANGELOG.md) | [@rushstack/heft-vscode-extension-rig](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-rig) | | [/rigs/heft-web-rig](./rigs/heft-web-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig) | [changelog](./rigs/heft-web-rig/CHANGELOG.md) | [@rushstack/heft-web-rig](https://www.npmjs.com/package/@rushstack/heft-web-rig) | | [/rush-plugins/rush-amazon-s3-build-cache-plugin](./rush-plugins/rush-amazon-s3-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin) | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-amazon-s3-build-cache-plugin) | | [/rush-plugins/rush-azure-storage-build-cache-plugin](./rush-plugins/rush-azure-storage-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin) | | [@rushstack/rush-azure-storage-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-azure-storage-build-cache-plugin) | +| [/rush-plugins/rush-bridge-cache-plugin](./rush-plugins/rush-bridge-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-bridge-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-bridge-cache-plugin) | | [@rushstack/rush-bridge-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-bridge-cache-plugin) | | [/rush-plugins/rush-buildxl-graph-plugin](./rush-plugins/rush-buildxl-graph-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin) | | [@rushstack/rush-buildxl-graph-plugin](https://www.npmjs.com/package/@rushstack/rush-buildxl-graph-plugin) | | [/rush-plugins/rush-http-build-cache-plugin](./rush-plugins/rush-http-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin) | | [@rushstack/rush-http-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-http-build-cache-plugin) | +| [/rush-plugins/rush-mcp-docs-plugin](./rush-plugins/rush-mcp-docs-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin) | [changelog](./rush-plugins/rush-mcp-docs-plugin/CHANGELOG.md) | [@rushstack/rush-mcp-docs-plugin](https://www.npmjs.com/package/@rushstack/rush-mcp-docs-plugin) | +| [/rush-plugins/rush-published-versions-json-plugin](./rush-plugins/rush-published-versions-json-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin) | [changelog](./rush-plugins/rush-published-versions-json-plugin/CHANGELOG.md) | [@rushstack/rush-published-versions-json-plugin](https://www.npmjs.com/package/@rushstack/rush-published-versions-json-plugin) | | [/rush-plugins/rush-redis-cobuild-plugin](./rush-plugins/rush-redis-cobuild-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin) | | [@rushstack/rush-redis-cobuild-plugin](https://www.npmjs.com/package/@rushstack/rush-redis-cobuild-plugin) | | [/rush-plugins/rush-resolver-cache-plugin](./rush-plugins/rush-resolver-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin) | | [@rushstack/rush-resolver-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-resolver-cache-plugin) | | [/rush-plugins/rush-serve-plugin](./rush-plugins/rush-serve-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin) | | [@rushstack/rush-serve-plugin](https://www.npmjs.com/package/@rushstack/rush-serve-plugin) | @@ -131,9 +147,12 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/build-tests-samples/heft-node-jest-tutorial](./build-tests-samples/heft-node-jest-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-node-rig-tutorial](./build-tests-samples/heft-node-rig-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-serverless-stack-tutorial](./build-tests-samples/heft-serverless-stack-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | -| [/build-tests-samples/heft-storybook-react-tutorial](./build-tests-samples/heft-storybook-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | -| [/build-tests-samples/heft-storybook-react-tutorial-app](./build-tests-samples/heft-storybook-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | -| [/build-tests-samples/heft-storybook-react-tutorial-storykit](./build-tests-samples/heft-storybook-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-react-tutorial | +| [/build-tests-samples/heft-storybook-v6-react-tutorial](./build-tests-samples/heft-storybook-v6-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | +| [/build-tests-samples/heft-storybook-v6-react-tutorial-app](./build-tests-samples/heft-storybook-v6-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | +| [/build-tests-samples/heft-storybook-v6-react-tutorial-storykit](./build-tests-samples/heft-storybook-v6-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-v6-react-tutorial | +| [/build-tests-samples/heft-storybook-v9-react-tutorial](./build-tests-samples/heft-storybook-v9-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | +| [/build-tests-samples/heft-storybook-v9-react-tutorial-app](./build-tests-samples/heft-storybook-v9-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | +| [/build-tests-samples/heft-storybook-v9-react-tutorial-storykit](./build-tests-samples/heft-storybook-v9-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-v9-react-tutorial | | [/build-tests-samples/heft-web-rig-app-tutorial](./build-tests-samples/heft-web-rig-app-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-web-rig-library-tutorial](./build-tests-samples/heft-web-rig-library-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-webpack-basic-tutorial](./build-tests-samples/heft-webpack-basic-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | @@ -161,21 +180,27 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/build-tests/eslint-7-7-test](./build-tests/eslint-7-7-test/) | This project contains a build test to validate ESLint 7.7.0 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-7-test](./build-tests/eslint-7-test/) | This project contains a build test to validate ESLint 7 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-8-test](./build-tests/eslint-8-test/) | This project contains a build test to validate ESLint 8 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | +| [/build-tests/eslint-9-test](./build-tests/eslint-9-test/) | This project contains a build test to validate ESLint 9 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-bulk-suppressions-test](./build-tests/eslint-bulk-suppressions-test/) | Sample code to test eslint bulk suppressions | +| [/build-tests/eslint-bulk-suppressions-test-flat](./build-tests/eslint-bulk-suppressions-test-flat/) | Sample code to test eslint bulk suppressions with flat configs | | [/build-tests/eslint-bulk-suppressions-test-legacy](./build-tests/eslint-bulk-suppressions-test-legacy/) | Sample code to test eslint bulk suppressions for versions of eslint < 8.57.0 | +| [/build-tests/esm-node-import-test](./build-tests/esm-node-import-test/) | This project validates that importing a rushstack package from a 'type: module' Node.js project works correctly with the package.json 'exports' field. See https://github.com/microsoft/rushstack/issues/5644 | | [/build-tests/hashed-folder-copy-plugin-webpack5-test](./build-tests/hashed-folder-copy-plugin-webpack5-test/) | Building this project exercises @rushstack/hashed-folder-copy-plugin with Webpack 5. NOTE - THIS TEST IS CURRENTLY EXPECTED TO BE BROKEN | | [/build-tests/heft-copy-files-test](./build-tests/heft-copy-files-test/) | Building this project tests copying files with Heft | +| [/build-tests/heft-example-lifecycle-plugin](./build-tests/heft-example-lifecycle-plugin/) | This is an example heft plugin for testing the lifecycle hooks | | [/build-tests/heft-example-plugin-01](./build-tests/heft-example-plugin-01/) | This is an example heft plugin that exposes hooks for other plugins | | [/build-tests/heft-example-plugin-02](./build-tests/heft-example-plugin-02/) | This is an example heft plugin that taps the hooks exposed from heft-example-plugin-01 | | [/build-tests/heft-fastify-test](./build-tests/heft-fastify-test/) | This project tests Heft support for the Fastify framework for Node.js services | | [/build-tests/heft-jest-preset-test](./build-tests/heft-jest-preset-test/) | This project illustrates configuring a Jest preset in a minimal Heft project | | [/build-tests/heft-jest-reporters-test](./build-tests/heft-jest-reporters-test/) | This project illustrates configuring Jest reporters in a minimal Heft project | +| [/build-tests/heft-json-schema-typings-plugin-test](./build-tests/heft-json-schema-typings-plugin-test/) | This project illustrates configuring Jest reporters in a minimal Heft project | | [/build-tests/heft-minimal-rig-test](./build-tests/heft-minimal-rig-test/) | This is a minimal rig package that is imported by the 'heft-minimal-rig-usage-test' project | | [/build-tests/heft-minimal-rig-usage-test](./build-tests/heft-minimal-rig-usage-test/) | A test project for Heft that resolves its compiler from the 'heft-minimal-rig-test' package | | [/build-tests/heft-node-everything-esm-module-test](./build-tests/heft-node-everything-esm-module-test/) | Building this project tests every task and config file for Heft when targeting the Node.js runtime when configured to use ESM module support | | [/build-tests/heft-node-everything-test](./build-tests/heft-node-everything-test/) | Building this project tests every task and config file for Heft when targeting the Node.js runtime | | [/build-tests/heft-parameter-plugin](./build-tests/heft-parameter-plugin/) | This project contains a Heft plugin that adds a custom parameter to built-in actions | | [/build-tests/heft-parameter-plugin-test](./build-tests/heft-parameter-plugin-test/) | This project exercises a built-in Heft action with a custom parameter | +| [/build-tests/heft-rspack-everything-test](./build-tests/heft-rspack-everything-test/) | Building this project tests every task and config file for Heft when targeting the web browser runtime using Rspack | | [/build-tests/heft-sass-test](./build-tests/heft-sass-test/) | This project illustrates a minimal tutorial Heft project targeting the web browser runtime | | [/build-tests/heft-swc-test](./build-tests/heft-swc-test/) | Building this project tests building with SWC | | [/build-tests/heft-typescript-composite-test](./build-tests/heft-typescript-composite-test/) | Building this project tests behavior of Heft when the tsconfig.json file uses project references. | @@ -192,12 +217,16 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/build-tests/package-extractor-test-02](./build-tests/package-extractor-test-02/) | This project is used by tests in the @rushstack/package-extractor package. | | [/build-tests/package-extractor-test-03](./build-tests/package-extractor-test-03/) | This project is used by tests in the @rushstack/package-extractor package. | | [/build-tests/package-extractor-test-04](./build-tests/package-extractor-test-04/) | This project is used by tests in the @rushstack/package-extractor package. | +| [/build-tests/package-extractor-test-05](./build-tests/package-extractor-test-05/) | This project is used by tests in the @rushstack/package-extractor package. | | [/build-tests/run-scenarios-helpers](./build-tests/run-scenarios-helpers/) | Helpers for the *-scenarios test projects. | | [/build-tests/rush-amazon-s3-build-cache-plugin-integration-test](./build-tests/rush-amazon-s3-build-cache-plugin-integration-test/) | Tests connecting to an amazon S3 endpoint | | [/build-tests/rush-lib-declaration-paths-test](./build-tests/rush-lib-declaration-paths-test/) | This project ensures all of the paths in rush-lib/lib/... have imports that resolve correctly. If this project builds, all `lib/**/*.d.ts` files in the `@microsoft/rush-lib` package are valid. | +| [/build-tests/rush-mcp-example-plugin](./build-tests/rush-mcp-example-plugin/) | Example showing how to create a plugin for @rushstack/mcp-server | +| [/build-tests/rush-package-manager-integration-test](./build-tests/rush-package-manager-integration-test/) | Integration tests for non-pnpm package managers in Rush. | | [/build-tests/rush-project-change-analyzer-test](./build-tests/rush-project-change-analyzer-test/) | This is an example project that uses rush-lib's ProjectChangeAnalyzer to | | [/build-tests/rush-redis-cobuild-plugin-integration-test](./build-tests/rush-redis-cobuild-plugin-integration-test/) | Tests connecting to an redis server | | [/build-tests/set-webpack-public-path-plugin-test](./build-tests/set-webpack-public-path-plugin-test/) | Building this project tests the set-webpack-public-path-plugin | +| [/build-tests/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 | @@ -208,8 +237,11 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/rigs/local-node-rig](./rigs/local-node-rig/) | A rig package for Node.js projects that build using Heft inside the RushStack repository. | | [/rigs/local-web-rig](./rigs/local-web-rig/) | A rig package for Web projects that build using Heft inside the RushStack repository. | | [/rush-plugins/rush-litewatch-plugin](./rush-plugins/rush-litewatch-plugin/) | An experimental alternative approach for multi-project watch mode | +| [/vscode-extensions/debug-certificate-manager-vscode-extension](./vscode-extensions/debug-certificate-manager-vscode-extension/) | VS Code extension to manage debug TLS certificates and sync them to the VS Code workspace. Works with VS Code remote development (Codespaces, SSH, Dev Containers, WSL, VS Code Tunnels). | +| [/vscode-extensions/playwright-local-browser-server-vscode-extension](./vscode-extensions/playwright-local-browser-server-vscode-extension/) | VS Code extension to enable Playwright testing in remote VS Code environments (such as Codespaces, Dev Containers, VS Code Tunnels) while launching and driving the actual browser process on your local machine. | | [/vscode-extensions/rush-vscode-command-webview](./vscode-extensions/rush-vscode-command-webview/) | Part of the Rush Stack VSCode extension, provides a UI for invoking Rush commands | | [/vscode-extensions/rush-vscode-extension](./vscode-extensions/rush-vscode-extension/) | Enhanced experience for monorepos that use the Rush Stack toolchain | +| [/vscode-extensions/vscode-shared](./vscode-extensions/vscode-shared/) | | | [/webpack/webpack-deep-imports-plugin](./webpack/webpack-deep-imports-plugin/) | This plugin creates a bundle and commonJS files in a 'lib' folder mirroring modules in another 'lib' folder. | diff --git a/apps/api-documenter/.eslintrc.js b/apps/api-documenter/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/apps/api-documenter/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/api-documenter/.npmignore b/apps/api-documenter/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/apps/api-documenter/.npmignore +++ b/apps/api-documenter/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/api-documenter/CHANGELOG.json b/apps/api-documenter/CHANGELOG.json index 162e397cce9..64a5fcec368 100644 --- a/apps/api-documenter/CHANGELOG.json +++ b/apps/api-documenter/CHANGELOG.json @@ -1,6 +1,783 @@ { "name": "@microsoft/api-documenter", "entries": [ + { + "version": "7.30.5", + "tag": "@microsoft/api-documenter_v7.30.5", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "7.30.4", + "tag": "@microsoft/api-documenter_v7.30.4", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "7.30.3", + "tag": "@microsoft/api-documenter_v7.30.3", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "7.30.2", + "tag": "@microsoft/api-documenter_v7.30.2", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "7.30.1", + "tag": "@microsoft/api-documenter_v7.30.1", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "7.30.0", + "tag": "@microsoft/api-documenter_v7.30.0", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for @defaultValue in Markdown and Yaml documenters" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "7.29.11", + "tag": "@microsoft/api-documenter_v7.29.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "7.29.10", + "tag": "@microsoft/api-documenter_v7.29.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "7.29.9", + "tag": "@microsoft/api-documenter_v7.29.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "7.29.8", + "tag": "@microsoft/api-documenter_v7.29.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "7.29.7", + "tag": "@microsoft/api-documenter_v7.29.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "7.29.6", + "tag": "@microsoft/api-documenter_v7.29.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "7.29.5", + "tag": "@microsoft/api-documenter_v7.29.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "7.29.4", + "tag": "@microsoft/api-documenter_v7.29.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "7.29.3", + "tag": "@microsoft/api-documenter_v7.29.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "7.29.2", + "tag": "@microsoft/api-documenter_v7.29.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "7.29.1", + "tag": "@microsoft/api-documenter_v7.29.1", + "date": "Fri, 20 Feb 2026 00:15:03 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "7.29.0", + "tag": "@microsoft/api-documenter_v7.29.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "7.28.9", + "tag": "@microsoft/api-documenter_v7.28.9", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "7.28.8", + "tag": "@microsoft/api-documenter_v7.28.8", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "7.28.7", + "tag": "@microsoft/api-documenter_v7.28.7", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "7.28.6", + "tag": "@microsoft/api-documenter_v7.28.6", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "7.28.5", + "tag": "@microsoft/api-documenter_v7.28.5", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "7.28.4", + "tag": "@microsoft/api-documenter_v7.28.4", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "7.28.3", + "tag": "@microsoft/api-documenter_v7.28.3", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "7.28.2", + "tag": "@microsoft/api-documenter_v7.28.2", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "7.28.1", + "tag": "@microsoft/api-documenter_v7.28.1", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "7.28.0", + "tag": "@microsoft/api-documenter_v7.28.0", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@microsoft/tsdoc` dependency to `~0.16.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "7.27.4", + "tag": "@microsoft/api-documenter_v7.27.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "7.27.3", + "tag": "@microsoft/api-documenter_v7.27.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "7.27.2", + "tag": "@microsoft/api-documenter_v7.27.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "7.27.1", + "tag": "@microsoft/api-documenter_v7.27.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "7.27.0", + "tag": "@microsoft/api-documenter_v7.27.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "7.26.36", + "tag": "@microsoft/api-documenter_v7.26.36", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "7.26.35", + "tag": "@microsoft/api-documenter_v7.26.35", + "date": "Tue, 30 Sep 2025 20:33:50 GMT", + "comments": { + "patch": [ + { + "comment": "Upgraded `js-yaml` dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "7.26.34", + "tag": "@microsoft/api-documenter_v7.26.34", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "7.26.33", + "tag": "@microsoft/api-documenter_v7.26.33", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "7.26.32", + "tag": "@microsoft/api-documenter_v7.26.32", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "7.26.31", + "tag": "@microsoft/api-documenter_v7.26.31", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "7.26.30", + "tag": "@microsoft/api-documenter_v7.26.30", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "7.26.29", + "tag": "@microsoft/api-documenter_v7.26.29", + "date": "Tue, 24 Jun 2025 00:11:43 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure a new line is inserted after rendering a table" + } + ] + } + }, + { + "version": "7.26.28", + "tag": "@microsoft/api-documenter_v7.26.28", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, { "version": "7.26.27", "tag": "@microsoft/api-documenter_v7.26.27", diff --git a/apps/api-documenter/CHANGELOG.md b/apps/api-documenter/CHANGELOG.md index 0fbe93fc38b..880a6f6a431 100644 --- a/apps/api-documenter/CHANGELOG.md +++ b/apps/api-documenter/CHANGELOG.md @@ -1,6 +1,230 @@ # Change Log - @microsoft/api-documenter -This log was last generated on Tue, 13 May 2025 02:09:20 GMT and should not be manually modified. +This log was last generated on Mon, 20 Apr 2026 23:31:13 GMT and should not be manually modified. + +## 7.30.5 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 7.30.4 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 7.30.3 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 7.30.2 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 7.30.1 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 7.30.0 +Fri, 10 Apr 2026 22:46:34 GMT + +### Minor changes + +- Add support for @defaultValue in Markdown and Yaml documenters + +## 7.29.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 7.29.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 7.29.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 7.29.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 7.29.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 7.29.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 7.29.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 7.29.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 7.29.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 7.29.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 7.29.1 +Fri, 20 Feb 2026 00:15:03 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 7.29.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 7.28.9 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 7.28.8 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 7.28.7 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 7.28.6 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 7.28.5 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 7.28.4 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 7.28.3 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 7.28.2 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 7.28.1 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 7.28.0 +Wed, 12 Nov 2025 01:12:56 GMT + +### Minor changes + +- Bump the `@microsoft/tsdoc` dependency to `~0.16.0`. + +## 7.27.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 7.27.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 7.27.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 7.27.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 7.27.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 7.26.36 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 7.26.35 +Tue, 30 Sep 2025 20:33:50 GMT + +### Patches + +- Upgraded `js-yaml` dependency + +## 7.26.34 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 7.26.33 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 7.26.32 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 7.26.31 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 7.26.30 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 7.26.29 +Tue, 24 Jun 2025 00:11:43 GMT + +### Patches + +- Ensure a new line is inserted after rendering a table + +## 7.26.28 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ ## 7.26.27 Tue, 13 May 2025 02:09:20 GMT diff --git a/apps/api-documenter/bin/api-documenter b/apps/api-documenter/bin/api-documenter index aee68e80224..eef2fc27066 100755 --- a/apps/api-documenter/bin/api-documenter +++ b/apps/api-documenter/bin/api-documenter @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/api-documenter/config/api-extractor.json b/apps/api-documenter/config/api-extractor.json index aa9d8f810fd..d34381e01f3 100644 --- a/apps/api-documenter/config/api-extractor.json +++ b/apps/api-documenter/config/api-extractor.json @@ -1,17 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", "dtsRollup": { "enabled": true, diff --git a/apps/api-documenter/config/heft.json b/apps/api-documenter/config/heft.json new file mode 100644 index 00000000000..b3046cad172 --- /dev/null +++ b/apps/api-documenter/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/api-extractor/v7"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/apps/api-documenter/eslint.config.js b/apps/api-documenter/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/api-documenter/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/api-documenter/package.json b/apps/api-documenter/package.json index d4b5e7f7497..8983fbfdebc 100644 --- a/apps/api-documenter/package.json +++ b/apps/api-documenter/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-documenter", - "version": "7.26.27", + "version": "7.30.5", "description": "Read JSON files from api-extractor, generate documentation pages", "repository": { "type": "git", @@ -17,21 +17,50 @@ "bin": { "api-documenter": "./bin/api-documenter" }, - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rollup.d.ts", + "exports": { + ".": { + "types": "./dist/rollup.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "dependencies": { "@microsoft/api-extractor-model": "workspace:*", - "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc": "~0.16.0", "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", - "js-yaml": "~3.13.1", + "js-yaml": "~4.1.0", "resolve": "~1.22.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/resolve": "1.20.2", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts index b201d6456b6..cc6c6774111 100644 --- a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts +++ b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { CommandLineParser } from '@rushstack/ts-command-line'; + import { MarkdownAction } from './MarkdownAction'; import { YamlAction } from './YamlAction'; import { GenerateAction } from './GenerateAction'; diff --git a/apps/api-documenter/src/cli/BaseAction.ts b/apps/api-documenter/src/cli/BaseAction.ts index e45d679b9c4..fbd3f10a14f 100644 --- a/apps/api-documenter/src/cli/BaseAction.ts +++ b/apps/api-documenter/src/cli/BaseAction.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type * as tsdoc from '@microsoft/tsdoc'; +import * as path from 'node:path'; +import type * as tsdoc from '@microsoft/tsdoc'; import { CommandLineAction, type CommandLineStringParameter, diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index 91e5c726ff6..155b22320d1 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + +import { FileSystem } from '@rushstack/node-core-library'; import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; import { DocumenterConfig } from '../documenters/DocumenterConfig'; import { ExperimentalYamlDocumenter } from '../documenters/ExperimentalYamlDocumenter'; - -import { FileSystem } from '@rushstack/node-core-library'; import { MarkdownDocumenter } from '../documenters/MarkdownDocumenter'; export class GenerateAction extends BaseAction { diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 3c819af64f3..7ed4161fb2d 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -8,7 +8,6 @@ import type { import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; - import { YamlDocumenter, type YamlFormat } from '../documenters/YamlDocumenter'; import { OfficeYamlDocumenter } from '../documenters/OfficeYamlDocumenter'; diff --git a/apps/api-documenter/src/documenters/DocumenterConfig.ts b/apps/api-documenter/src/documenters/DocumenterConfig.ts index e3fee70e3cd..3a0e32c3736 100644 --- a/apps/api-documenter/src/documenters/DocumenterConfig.ts +++ b/apps/api-documenter/src/documenters/DocumenterConfig.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { JsonSchema, JsonFile, NewlineKind } from '@rushstack/node-core-library'; + import type { IConfigFile } from './IConfigFile'; import apiDocumenterSchema from '../schemas/api-documenter.schema.json'; diff --git a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts index 68895c679f4..203509cf816 100644 --- a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts +++ b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { PackageName, FileSystem, NewlineKind } from '@rushstack/node-core-library'; import { DocSection, @@ -272,6 +273,7 @@ export class MarkdownDocumenter { case ApiItemKind.Function: this._writeParameterTables(output, apiItem as ApiParameterListMixin); this._writeThrowsSection(output, apiItem); + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.Namespace: this._writePackageOrNamespaceTables(output, apiItem as ApiNamespace); @@ -284,10 +286,13 @@ export class MarkdownDocumenter { break; case ApiItemKind.Property: case ApiItemKind.PropertySignature: + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.TypeAlias: + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.Variable: + this._writeDefaultValueSection(output, apiItem); break; default: throw new Error('Unsupported API item kind: ' + apiItem.kind); @@ -468,6 +473,30 @@ export class MarkdownDocumenter { } } + private _writeDefaultValueSection(output: DocSection, apiItem: ApiItem): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + if (apiItem instanceof ApiDocumentedItem) { + const tsdocComment: DocComment | undefined = apiItem.tsdocComment; + + if (tsdocComment) { + // Write the @defaultValue blocks + const defaultValueBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase + ); + + if (defaultValueBlocks.length > 0) { + const heading: string = 'Default Value'; + output.appendNode(new DocHeading({ configuration, title: heading })); + + for (const defaultValueBlock of defaultValueBlocks) { + this._appendSection(output, defaultValueBlock.content); + } + } + } + } + } + /** * GENERATE PAGE: MODEL */ diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index 0050b7147ce..b8b178a9ce1 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import yaml = require('js-yaml'); import type { ApiModel } from '@microsoft/api-extractor-model'; @@ -48,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 */ diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index b165622ce84..73420328756 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import yaml = require('js-yaml'); + import { JsonFile, JsonSchema, @@ -50,6 +51,7 @@ import { Navigation, Meaning } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import type { IYamlApiFile, IYamlItem, @@ -425,6 +427,18 @@ export class YamlDocumenter { yamlItem.example = [...(yamlItem.example || []), example]; } } + + // Write the @defaultValue block + const defaultValueBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase + ); + + for (const defaultValueBlock of defaultValueBlocks) { + const defaultValueContent: string = this._renderMarkdown(defaultValueBlock.content, apiItem); + if (defaultValueContent) { + yamlItem.defaultValue = defaultValueContent.trim(); + } + } } if (tsdocComment.deprecatedBlock) { @@ -756,7 +770,7 @@ export class YamlDocumenter { ): void { JsonFile.validateNoUndefinedMembers(dataObject); - let stringified: string = yaml.safeDump(dataObject, { + let stringified: string = yaml.dump(dataObject, { lineWidth: 120 }); diff --git a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts index 73dc78a5f4f..5ec5bc9e90f 100644 --- a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts +++ b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts @@ -136,7 +136,7 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { } writer.write(''); writer.write(''); - writer.writeLine(); + writer.ensureSkippedLine(); break; } diff --git a/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts b/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts index 918dd32c675..5e545c8d39b 100644 --- a/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts +++ b/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts @@ -171,6 +171,13 @@ test('render Markdown from TSDoc', () => { ) ]); + output.appendNodes([ + new DocHeading({ configuration, title: 'After a table' }), + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: 'just checking lines after a table' }) + ]) + ]); + const stringBuilder: StringBuilder = new StringBuilder(); const apiModel: ApiModel = new ApiModel(); const markdownEmitter: CustomMarkdownEmitter = new CustomMarkdownEmitter(apiModel); diff --git a/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap b/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap index 7f57768d708..611349e525c 100644 --- a/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap +++ b/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`render Markdown from TSDoc 1`] = ` " @@ -75,5 +75,10 @@ Cell 2 + +## After a table + +just checking lines after a table + " `; diff --git a/apps/api-documenter/src/nodes/CustomDocNodeKind.ts b/apps/api-documenter/src/nodes/CustomDocNodeKind.ts index c1186d3fd38..9d0af5fdab8 100644 --- a/apps/api-documenter/src/nodes/CustomDocNodeKind.ts +++ b/apps/api-documenter/src/nodes/CustomDocNodeKind.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { TSDocConfiguration, DocNodeKind } from '@microsoft/tsdoc'; + import { DocEmphasisSpan } from './DocEmphasisSpan'; import { DocHeading } from './DocHeading'; import { DocNoteBox } from './DocNoteBox'; diff --git a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts index e48d8c3c340..bc2197689fc 100644 --- a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts +++ b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type DocNode, DocNodeContainer, type IDocNodeContainerParameters } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocHeading.ts b/apps/api-documenter/src/nodes/DocHeading.ts index 838e1a71f79..ee40a8bb6bc 100644 --- a/apps/api-documenter/src/nodes/DocHeading.ts +++ b/apps/api-documenter/src/nodes/DocHeading.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocNoteBox.ts b/apps/api-documenter/src/nodes/DocNoteBox.ts index f1075e5fcbb..cccece1460c 100644 --- a/apps/api-documenter/src/nodes/DocNoteBox.ts +++ b/apps/api-documenter/src/nodes/DocNoteBox.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocTable.ts b/apps/api-documenter/src/nodes/DocTable.ts index 19f09013b99..945098a4adb 100644 --- a/apps/api-documenter/src/nodes/DocTable.ts +++ b/apps/api-documenter/src/nodes/DocTable.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableRow } from './DocTableRow'; import type { DocTableCell } from './DocTableCell'; diff --git a/apps/api-documenter/src/nodes/DocTableCell.ts b/apps/api-documenter/src/nodes/DocTableCell.ts index f4fefe18eca..f0911dbfd59 100644 --- a/apps/api-documenter/src/nodes/DocTableCell.ts +++ b/apps/api-documenter/src/nodes/DocTableCell.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocTableRow.ts b/apps/api-documenter/src/nodes/DocTableRow.ts index 421be24fe9c..85bd873d907 100644 --- a/apps/api-documenter/src/nodes/DocTableRow.ts +++ b/apps/api-documenter/src/nodes/DocTableRow.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocPlainText } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableCell } from './DocTableCell'; diff --git a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts index a0ea2e8b82f..0666b8097b3 100644 --- a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts +++ b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts @@ -3,6 +3,7 @@ import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; import { TypeUuid } from '@rushstack/node-core-library'; + import { PluginFeature } from './PluginFeature'; import type { MarkdownDocumenterAccessor } from './MarkdownDocumenterAccessor'; diff --git a/apps/api-documenter/src/plugin/PluginLoader.ts b/apps/api-documenter/src/plugin/PluginLoader.ts index 543e674a94e..6d926f6ea66 100644 --- a/apps/api-documenter/src/plugin/PluginLoader.ts +++ b/apps/api-documenter/src/plugin/PluginLoader.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as resolve from 'resolve'; import type { IApiDocumenterPluginManifest, IFeatureDefinition } from './IApiDocumenterPluginManifest'; diff --git a/apps/api-documenter/src/start.ts b/apps/api-documenter/src/start.ts index e5b6330b6f7..e6266aa99fa 100644 --- a/apps/api-documenter/src/start.ts +++ b/apps/api-documenter/src/start.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; import { PackageJsonLookup } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; diff --git a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts index 2de3530d9fc..c81d01f6a18 100644 --- a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts +++ b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import path from 'node:path'; + +import yaml = require('js-yaml'); + +import { FileSystem, Encoding, NewlineKind } from '@rushstack/node-core-library'; + import type { IYamlItem, IYamlApiFile, @@ -17,9 +23,6 @@ import type { FunctionYamlModel, CommonYamlModel } from '../yaml/ISDPYamlFile'; -import path from 'path'; -import { FileSystem, Encoding, NewlineKind } from '@rushstack/node-core-library'; -import yaml = require('js-yaml'); export function convertUDPYamlToSDP(folderPath: string): void { convert(folderPath, folderPath); @@ -49,10 +52,10 @@ function convert(inputPath: string, outputPath: string): void { console.log(`convert file ${fpath} from udp to sdp`); - const file: IYamlApiFile = yaml.safeLoad(yamlContent) as IYamlApiFile; + const file: IYamlApiFile = yaml.load(yamlContent) as IYamlApiFile; const result: { model: CommonYamlModel; type: string } | undefined = convertToSDP(file); if (result && result.model) { - const stringified: string = `### YamlMime:TS${result.type}\n${yaml.safeDump(result.model, { + const stringified: string = `### YamlMime:TS${result.type}\n${yaml.dump(result.model, { lineWidth: 120 })}`; FileSystem.writeFile(`${outputPath}/${name}`, stringified, { @@ -301,6 +304,10 @@ function convertCommonYamlModel( result.example = []; } + if (element.defaultValue) { + result.defaultValue = element.defaultValue; + } + result.isPreview = element.isPreview; if (!result.isPreview) { result.isPreview = false; diff --git a/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap b/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap index 62778d301c8..115fb3887a6 100644 --- a/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap +++ b/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`01 Demo from docs 1`] = ` "begin diff --git a/apps/api-documenter/src/yaml/ISDPYamlFile.ts b/apps/api-documenter/src/yaml/ISDPYamlFile.ts index 413d73e8d6b..574434154d4 100644 --- a/apps/api-documenter/src/yaml/ISDPYamlFile.ts +++ b/apps/api-documenter/src/yaml/ISDPYamlFile.ts @@ -16,6 +16,7 @@ export type CommonYamlModel = IBaseYamlModel & { remarks?: string; example?: string[]; customDeprecatedMessage?: string; + defaultValue?: string; }; export type PackageYamlModel = CommonYamlModel & { diff --git a/apps/api-documenter/src/yaml/IYamlApiFile.ts b/apps/api-documenter/src/yaml/IYamlApiFile.ts index 58048a50d41..59f1b2ab1ad 100644 --- a/apps/api-documenter/src/yaml/IYamlApiFile.ts +++ b/apps/api-documenter/src/yaml/IYamlApiFile.ts @@ -327,6 +327,12 @@ export interface IYamlItem { * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. */ package?: string; + + /** + * The default value for the item. + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ + defaultValue?: string; } /** diff --git a/apps/api-documenter/src/yaml/typescript.schema.json b/apps/api-documenter/src/yaml/typescript.schema.json index cc1ad42ccf0..d5baf66d72a 100644 --- a/apps/api-documenter/src/yaml/typescript.schema.json +++ b/apps/api-documenter/src/yaml/typescript.schema.json @@ -262,6 +262,9 @@ }, "package": { "type": "string" + }, + "defaultValue": { + "type": "string" } }, "patternProperties": { diff --git a/apps/api-extractor/.eslintrc.js b/apps/api-extractor/.eslintrc.js deleted file mode 100644 index 07392ddae9d..00000000000 --- a/apps/api-extractor/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('decoupled-local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('decoupled-local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'decoupled-local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'decoupled-local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/api-extractor/.npmignore b/apps/api-extractor/.npmignore index 8b61d7caa66..64ed79eb4bc 100644 --- a/apps/api-extractor/.npmignore +++ b/apps/api-extractor/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/api-extractor/.vscode/launch.json b/apps/api-extractor/.vscode/launch.json index b9c74c3b15e..4a3f7bb4fa8 100644 --- a/apps/api-extractor/.vscode/launch.json +++ b/apps/api-extractor/.vscode/launch.json @@ -79,7 +79,7 @@ "run", "--local", "--config", - "./temp/configs/api-extractor-spanSorting.json" + "./temp/configs/api-extractor-destructuredParameters.json" ], "sourceMaps": true } diff --git a/apps/api-extractor/CHANGELOG.json b/apps/api-extractor/CHANGELOG.json index 30a7df2081a..4897455a20a 100644 --- a/apps/api-extractor/CHANGELOG.json +++ b/apps/api-extractor/CHANGELOG.json @@ -1,6 +1,698 @@ { "name": "@microsoft/api-extractor", "entries": [ + { + "version": "7.58.7", + "tag": "@microsoft/api-extractor_v7.58.7", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + } + ] + } + }, + { + "version": "7.58.6", + "tag": "@microsoft/api-extractor_v7.58.6", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where empty lines were included in DTS rollups in place of API items that were trimmed." + } + ] + } + }, + { + "version": "7.58.5", + "tag": "@microsoft/api-extractor_v7.58.5", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + } + ] + } + }, + { + "version": "7.58.4", + "tag": "@microsoft/api-extractor_v7.58.4", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + } + ] + } + }, + { + "version": "7.58.3", + "tag": "@microsoft/api-extractor_v7.58.3", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "patch": [ + { + "comment": "Remove dependecy on `lodash`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + } + ] + } + }, + { + "version": "7.58.2", + "tag": "@microsoft/api-extractor_v7.58.2", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + } + ] + } + }, + { + "version": "7.58.1", + "tag": "@microsoft/api-extractor_v7.58.1", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "patch": [ + { + "comment": "Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh" + } + ] + } + }, + { + "version": "7.58.0", + "tag": "@microsoft/api-extractor_v7.58.0", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.9.3" + } + ] + } + }, + { + "version": "7.57.8", + "tag": "@microsoft/api-extractor_v7.57.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + } + ] + } + }, + { + "version": "7.57.7", + "tag": "@microsoft/api-extractor_v7.57.7", + "date": "Mon, 09 Mar 2026 15:14:07 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903." + } + ] + } + }, + { + "version": "7.57.6", + "tag": "@microsoft/api-extractor_v7.57.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `@microsoft/tsdoc-config` to `~0.18.1` to mitigate CVE-2025-69873." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.4`" + } + ] + } + }, + { + "version": "7.57.5", + "tag": "@microsoft/api-extractor_v7.57.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + } + ] + } + }, + { + "version": "7.57.4", + "tag": "@microsoft/api-extractor_v7.57.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + } + ] + } + }, + { + "version": "7.57.3", + "tag": "@microsoft/api-extractor_v7.57.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing \"./extends/*.json\" to the package.json \"exports\" field so that \"@microsoft/api-extractor/extends/tsdoc-base.json\" is importable." + } + ] + } + }, + { + "version": "7.57.2", + "tag": "@microsoft/api-extractor_v7.57.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "patch": [ + { + "comment": "Bump minimatch from 10.1.2 to 10.2.1" + } + ] + } + }, + { + "version": "7.57.1", + "tag": "@microsoft/api-extractor_v7.57.1", + "date": "Fri, 20 Feb 2026 00:15:03 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + } + ] + } + }, + { + "version": "7.57.0", + "tag": "@microsoft/api-extractor_v7.57.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + } + ] + } + }, + { + "version": "7.56.3", + "tag": "@microsoft/api-extractor_v7.56.3", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`." + } + ] + } + }, + { + "version": "7.56.2", + "tag": "@microsoft/api-extractor_v7.56.2", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "patch": [ + { + "comment": "Update minimatch dependency from 10.0.3 to 10.1.2" + } + ] + } + }, + { + "version": "7.56.1", + "tag": "@microsoft/api-extractor_v7.56.1", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + } + ] + } + }, + { + "version": "7.56.0", + "tag": "@microsoft/api-extractor_v7.56.0", + "date": "Fri, 30 Jan 2026 01:16:12 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where destructured parameters produced an incorrect parameter name" + } + ] + } + }, + { + "version": "7.55.5", + "tag": "@microsoft/api-extractor_v7.55.5", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "patch": [ + { + "comment": "Fix missing 'export' keyword for namespace re-exports that produced invalid TypeScript output" + } + ] + } + }, + { + "version": "7.55.4", + "tag": "@microsoft/api-extractor_v7.55.4", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + } + ] + } + }, + { + "version": "7.55.3", + "tag": "@microsoft/api-extractor_v7.55.3", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + } + ] + } + }, + { + "version": "7.55.2", + "tag": "@microsoft/api-extractor_v7.55.2", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + } + ] + } + }, + { + "version": "7.55.1", + "tag": "@microsoft/api-extractor_v7.55.1", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + } + ] + } + }, + { + "version": "7.55.0", + "tag": "@microsoft/api-extractor_v7.55.0", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@microsoft/tsdoc` dependency to `~0.16.0`." + }, + { + "comment": "Bump the `@microsoft/tsdoc-config` dependency to `~0.18.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.0`" + } + ] + } + }, + { + "version": "7.54.0", + "tag": "@microsoft/api-extractor_v7.54.0", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new setting `IExtractorInvokeOptions.printApiReportDiff` that makes build logs easier to diagnose by printing a diff of any changes to API report files (*.api.md)." + }, + { + "comment": "Add a `--print-api-report-diff` CLI flag that causes a diff of any changes to API report files (*.api.md) to be printed." + } + ] + } + }, + { + "version": "7.53.3", + "tag": "@microsoft/api-extractor_v7.53.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + } + ] + } + }, + { + "version": "7.53.2", + "tag": "@microsoft/api-extractor_v7.53.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + } + ] + } + }, + { + "version": "7.53.1", + "tag": "@microsoft/api-extractor_v7.53.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + } + ] + } + }, + { + "version": "7.53.0", + "tag": "@microsoft/api-extractor_v7.53.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + } + ] + } + }, + { + "version": "7.52.15", + "tag": "@microsoft/api-extractor_v7.52.15", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + } + ] + } + }, + { + "version": "7.52.14", + "tag": "@microsoft/api-extractor_v7.52.14", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + } + ] + } + }, + { + "version": "7.52.13", + "tag": "@microsoft/api-extractor_v7.52.13", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes a bug in ExtractorAnalyzer._isExternalModulePath where type import declarations were not resolved." + } + ] + } + }, + { + "version": "7.52.12", + "tag": "@microsoft/api-extractor_v7.52.12", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + } + ] + } + }, + { + "version": "7.52.11", + "tag": "@microsoft/api-extractor_v7.52.11", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "patch": [ + { + "comment": "Fix self-package import resolution by removing outDir/declarationDir from compiler options" + } + ] + } + }, + { + "version": "7.52.10", + "tag": "@microsoft/api-extractor_v7.52.10", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency." + } + ] + } + }, + { + "version": "7.52.9", + "tag": "@microsoft/api-extractor_v7.52.9", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + } + ] + } + }, { "version": "7.52.8", "tag": "@microsoft/api-extractor_v7.52.8", diff --git a/apps/api-extractor/CHANGELOG.md b/apps/api-extractor/CHANGELOG.md index 3a96e1152fb..c77a98e9c9d 100644 --- a/apps/api-extractor/CHANGELOG.md +++ b/apps/api-extractor/CHANGELOG.md @@ -1,6 +1,245 @@ # Change Log - @microsoft/api-extractor -This log was last generated on Tue, 13 May 2025 02:09:20 GMT and should not be manually modified. +This log was last generated on Mon, 20 Apr 2026 23:31:13 GMT and should not be manually modified. + +## 7.58.7 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 7.58.6 +Mon, 20 Apr 2026 15:15:24 GMT + +### Patches + +- Fix an issue where empty lines were included in DTS rollups in place of API items that were trimmed. + +## 7.58.5 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 7.58.4 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 7.58.3 +Fri, 17 Apr 2026 15:14:57 GMT + +### Patches + +- Remove dependecy on `lodash`. + +## 7.58.2 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 7.58.1 +Sat, 04 Apr 2026 00:14:00 GMT + +### Patches + +- Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh + +## 7.58.0 +Wed, 01 Apr 2026 15:13:38 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 5.9.3 + +## 7.57.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 7.57.7 +Mon, 09 Mar 2026 15:14:07 GMT + +### Patches + +- Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903. + +## 7.57.6 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `@microsoft/tsdoc-config` to `~0.18.1` to mitigate CVE-2025-69873. + +## 7.57.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 7.57.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 7.57.3 +Mon, 23 Feb 2026 00:42:21 GMT + +### Patches + +- Add missing "./extends/*.json" to the package.json "exports" field so that "@microsoft/api-extractor/extends/tsdoc-base.json" is importable. + +## 7.57.2 +Fri, 20 Feb 2026 16:14:49 GMT + +### Patches + +- Bump minimatch from 10.1.2 to 10.2.1 + +## 7.57.1 +Fri, 20 Feb 2026 00:15:03 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 7.57.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 7.56.3 +Sat, 07 Feb 2026 01:13:26 GMT + +### Patches + +- Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`. + +## 7.56.2 +Wed, 04 Feb 2026 20:42:47 GMT + +### Patches + +- Update minimatch dependency from 10.0.3 to 10.1.2 + +## 7.56.1 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 7.56.0 +Fri, 30 Jan 2026 01:16:12 GMT + +### Minor changes + +- Fix an issue where destructured parameters produced an incorrect parameter name + +## 7.55.5 +Thu, 08 Jan 2026 01:12:30 GMT + +### Patches + +- Fix missing 'export' keyword for namespace re-exports that produced invalid TypeScript output + +## 7.55.4 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 7.55.3 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 7.55.2 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 7.55.1 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 7.55.0 +Wed, 12 Nov 2025 01:12:56 GMT + +### Minor changes + +- Bump the `@microsoft/tsdoc` dependency to `~0.16.0`. +- Bump the `@microsoft/tsdoc-config` dependency to `~0.18.0`. + +## 7.54.0 +Tue, 04 Nov 2025 08:15:14 GMT + +### Minor changes + +- Add a new setting `IExtractorInvokeOptions.printApiReportDiff` that makes build logs easier to diagnose by printing a diff of any changes to API report files (*.api.md). +- Add a `--print-api-report-diff` CLI flag that causes a diff of any changes to API report files (*.api.md) to be printed. + +## 7.53.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 7.53.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 7.53.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 7.53.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 7.52.15 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 7.52.14 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 7.52.13 +Fri, 12 Sep 2025 15:13:07 GMT + +### Patches + +- Fixes a bug in ExtractorAnalyzer._isExternalModulePath where type import declarations were not resolved. + +## 7.52.12 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 7.52.11 +Tue, 19 Aug 2025 20:45:02 GMT + +### Patches + +- Fix self-package import resolution by removing outDir/declarationDir from compiler options + +## 7.52.10 +Fri, 01 Aug 2025 00:12:48 GMT + +### Patches + +- Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency. + +## 7.52.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ ## 7.52.8 Tue, 13 May 2025 02:09:20 GMT diff --git a/apps/api-extractor/bin/api-extractor b/apps/api-extractor/bin/api-extractor index aee68e80224..eef2fc27066 100755 --- a/apps/api-extractor/bin/api-extractor +++ b/apps/api-extractor/bin/api-extractor @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/api-extractor/config/api-extractor.json b/apps/api-extractor/config/api-extractor.json index aa9d8f810fd..bf6aa143c60 100644 --- a/apps/api-extractor/config/api-extractor.json +++ b/apps/api-extractor/config/api-extractor.json @@ -1,17 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", "dtsRollup": { "enabled": true, diff --git a/apps/api-extractor/config/heft.json b/apps/api-extractor/config/heft.json index 0b965cec36a..f3b430106df 100644 --- a/apps/api-extractor/config/heft.json +++ b/apps/api-extractor/config/heft.json @@ -23,12 +23,29 @@ "copyOperations": [ { "sourcePath": "src", - "destinationFolders": ["lib"], + "destinationFolders": ["lib-commonjs"], "includeGlobs": ["**/test/test-data/**/*"] } ] } } + }, + + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/api-extractor/v7"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } } } } diff --git a/apps/api-extractor/eslint.config.js b/apps/api-extractor/eslint.config.js new file mode 100644 index 00000000000..2b99226b7c4 --- /dev/null +++ b/apps/api-extractor/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/api-extractor/package.json b/apps/api-extractor/package.json index f47e37f420a..e48c3369ddc 100644 --- a/apps/api-extractor/package.json +++ b/apps/api-extractor/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-extractor", - "version": "7.52.8", + "version": "7.58.7", "description": "Analyze the exported API for a TypeScript library and generate reviews, documentation, and .d.ts rollups", "keywords": [ "typescript", @@ -25,8 +25,33 @@ "directory": "apps/api-extractor" }, "homepage": "https://api-extractor.com", - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rollup.d.ts", + "exports": { + ".": { + "types": "./dist/rollup.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./extends/*.json": "./extends/*.json", + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "bin": { "api-extractor": "./bin/api-extractor" }, @@ -38,26 +63,29 @@ }, "dependencies": { "@microsoft/api-extractor-model": "workspace:*", - "@microsoft/tsdoc-config": "~0.17.1", - "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.18.1", + "@microsoft/tsdoc": "~0.16.0", "@rushstack/node-core-library": "workspace:*", "@rushstack/rig-package": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", - "lodash": "~4.17.15", - "minimatch": "~3.0.3", + "diff": "~8.0.2", + "minimatch": "10.2.3", "resolve": "~1.22.1", - "semver": "~7.5.4", + "semver": "~7.7.4", "source-map": "~0.6.1", - "typescript": "5.8.2" + "typescript": "5.9.3" }, "devDependencies": { - "decoupled-local-node-rig": "workspace:*", - "@rushstack/heft": "0.73.2", - "@types/lodash": "4.14.116", - "@types/minimatch": "3.0.5", + "@rushstack/heft": "1.2.17", "@types/resolve": "1.20.2", - "@types/semver": "7.5.0", + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", "local-eslint-config": "workspace:*" - } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/api-extractor/src/aedoc/PackageDocComment.ts b/apps/api-extractor/src/aedoc/PackageDocComment.ts index 09cca1835aa..3cc10e34526 100644 --- a/apps/api-extractor/src/aedoc/PackageDocComment.ts +++ b/apps/api-extractor/src/aedoc/PackageDocComment.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type { Collector } from '../collector/Collector'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; diff --git a/apps/api-extractor/src/analyzer/AstDeclaration.ts b/apps/api-extractor/src/analyzer/AstDeclaration.ts index 24a2a65e9c7..78cc4ed7337 100644 --- a/apps/api-extractor/src/analyzer/AstDeclaration.ts +++ b/apps/api-extractor/src/analyzer/AstDeclaration.ts @@ -2,9 +2,11 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + +import { InternalError } from '@rushstack/node-core-library'; + import type { AstSymbol } from './AstSymbol'; import { Span } from './Span'; -import { InternalError } from '@rushstack/node-core-library'; import type { AstEntity } from './AstEntity'; /** diff --git a/apps/api-extractor/src/analyzer/AstImport.ts b/apps/api-extractor/src/analyzer/AstImport.ts index bc2b685949d..38d4b1928a9 100644 --- a/apps/api-extractor/src/analyzer/AstImport.ts +++ b/apps/api-extractor/src/analyzer/AstImport.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { AstSymbol } from './AstSymbol'; import { InternalError } from '@rushstack/node-core-library'; + +import type { AstSymbol } from './AstSymbol'; import { AstSyntheticEntity } from './AstEntity'; /** diff --git a/apps/api-extractor/src/analyzer/AstReferenceResolver.ts b/apps/api-extractor/src/analyzer/AstReferenceResolver.ts index 25a1c359ef7..e51de2f1934 100644 --- a/apps/api-extractor/src/analyzer/AstReferenceResolver.ts +++ b/apps/api-extractor/src/analyzer/AstReferenceResolver.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import * as tsdoc from '@microsoft/tsdoc'; import type { AstSymbolTable } from './AstSymbolTable'; diff --git a/apps/api-extractor/src/analyzer/AstSymbol.ts b/apps/api-extractor/src/analyzer/AstSymbol.ts index a0a8d67251f..fb34e28efc2 100644 --- a/apps/api-extractor/src/analyzer/AstSymbol.ts +++ b/apps/api-extractor/src/analyzer/AstSymbol.ts @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import type * as ts from 'typescript'; -import type { AstDeclaration } from './AstDeclaration'; + import { InternalError } from '@rushstack/node-core-library'; + +import type { AstDeclaration } from './AstDeclaration'; import { AstEntity } from './AstEntity'; /** @@ -115,12 +117,20 @@ export class AstSymbol extends AstEntity { public constructor(options: IAstSymbolOptions) { super(); - this.followedSymbol = options.followedSymbol; - this.localName = options.localName; - this.isExternal = options.isExternal; - this.nominalAnalysis = options.nominalAnalysis; - this.parentAstSymbol = options.parentAstSymbol; - this.rootAstSymbol = options.rootAstSymbol || this; + const { + followedSymbol, + localName, + isExternal, + nominalAnalysis, + parentAstSymbol, + rootAstSymbol = this + } = options; + this.followedSymbol = followedSymbol; + this.localName = localName; + this.isExternal = isExternal; + this.nominalAnalysis = nominalAnalysis; + this.parentAstSymbol = parentAstSymbol; + this.rootAstSymbol = rootAstSymbol; this._astDeclarations = []; } diff --git a/apps/api-extractor/src/analyzer/AstSymbolTable.ts b/apps/api-extractor/src/analyzer/AstSymbolTable.ts index e589ea10097..1bfa982b578 100644 --- a/apps/api-extractor/src/analyzer/AstSymbolTable.ts +++ b/apps/api-extractor/src/analyzer/AstSymbolTable.ts @@ -4,6 +4,7 @@ /* eslint-disable no-bitwise */ // for ts.SymbolFlags import * as ts from 'typescript'; + import { type PackageJsonLookup, InternalError } from '@rushstack/node-core-library'; import { AstDeclaration } from './AstDeclaration'; diff --git a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index d8a68a2b76c..0bc6236aa4d 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -2,6 +2,7 @@ // 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'; @@ -264,9 +265,12 @@ export class ExportAnalyzer { importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, moduleSpecifier: string ): boolean { - const specifier: ts.TypeNode | ts.Expression | undefined = ts.isImportTypeNode(importOrExportDeclaration) + let specifier: ts.TypeNode | ts.Expression | undefined = ts.isImportTypeNode(importOrExportDeclaration) ? importOrExportDeclaration.argument : importOrExportDeclaration.moduleSpecifier; + if (specifier && ts.isLiteralTypeNode(specifier)) { + specifier = specifier.literal; + } const mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined = specifier && ts.isStringLiteralLike(specifier) ? TypeScriptInternals.getModeForUsageLocation( diff --git a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts b/apps/api-extractor/src/analyzer/PackageMetadataManager.ts index c234174829a..22b9be7e891 100644 --- a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts +++ b/apps/api-extractor/src/analyzer/PackageMetadataManager.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; + import semver from 'semver'; import { @@ -13,6 +14,7 @@ import { type JsonObject, type IPackageJsonExports } from '@rushstack/node-core-library'; + import { Extractor } from '../api/Extractor'; import type { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from '../api/ConsoleMessageId'; diff --git a/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts index 1a38c5541e4..939f9aa5ba2 100644 --- a/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts +++ b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; + import type * as ts from 'typescript'; -import * as path from 'path'; + import { Path, Text } from '@rushstack/node-core-library'; export interface ISourceFileLocationFormatOptions { diff --git a/apps/api-extractor/src/analyzer/Span.ts b/apps/api-extractor/src/analyzer/Span.ts index 96841d800a0..e4d1f2970ab 100644 --- a/apps/api-extractor/src/analyzer/Span.ts +++ b/apps/api-extractor/src/analyzer/Span.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import { InternalError, Sort, Text } from '@rushstack/node-core-library'; import { IndentedWriter } from '../generators/IndentedWriter'; diff --git a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts index d63e3ffe8d1..5c28b30d354 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts @@ -4,9 +4,11 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; + +import { InternalError } from '@rushstack/node-core-library'; + import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; import { TypeScriptInternals } from './TypeScriptInternals'; -import { InternalError } from '@rushstack/node-core-library'; export class TypeScriptHelpers { // Matches TypeScript's encoded names for well-known ECMAScript symbols like diff --git a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts index 1202a078f9d..88059f26e80 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts @@ -4,6 +4,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as ts from 'typescript'; + import { InternalError } from '@rushstack/node-core-library'; /** @@ -16,8 +17,8 @@ export interface IGlobalVariableAnalyzer { export class TypeScriptInternals { public static getImmediateAliasedSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/checker.ts - return (typeChecker as any).getImmediateAliasedSymbol(symbol); // eslint-disable-line @typescript-eslint/no-explicit-any + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/checker.ts + return (typeChecker as any).getImmediateAliasedSymbol(symbol); } /** @@ -60,7 +61,7 @@ export class TypeScriptInternals { */ public static getJSDocCommentRanges(node: ts.Node, text: string): ts.CommentRange[] | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v2.4.2/src/compiler/utilities.ts#L616 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/utilities.ts#L2710 return (ts as any).getJSDocCommentRanges.apply(this, arguments); } @@ -72,7 +73,7 @@ export class TypeScriptInternals { node: ts.Identifier | ts.StringLiteralLike | ts.NumericLiteral ): string { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/utilities.ts#L2721 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/utilities.ts#L5368 return (ts as any).getTextOfIdentifierOrLiteral(node); } @@ -88,7 +89,7 @@ export class TypeScriptInternals { mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined ): ts.ResolvedModuleFull | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/types.ts#L4698 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/types.ts#L5064 const result: ts.ResolvedModuleWithFailedLookupLocations | undefined = (program as any).getResolvedModule( sourceFile, moduleNameText, @@ -106,7 +107,7 @@ export class TypeScriptInternals { compilerOptions: ts.CompilerOptions ): ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v5.8.2/src/compiler/program.ts#L931 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/program.ts#L932 return ts.getModeForUsageLocation?.(file, usage, compilerOptions); } diff --git a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts index f1efae6064e..7f5acef9c2f 100644 --- a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts +++ b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -jest.mock('path', () => { - const actualPath: typeof import('path') = jest.requireActual('path'); +jest.mock('node:path', () => { + const actualPath: typeof import('path') = jest.requireActual('node:path'); return { ...actualPath, resolve: actualPath.posix.resolve diff --git a/apps/api-extractor/src/api/CompilerState.ts b/apps/api-extractor/src/api/CompilerState.ts index 7c9513884c9..7862c1c2e85 100644 --- a/apps/api-extractor/src/api/CompilerState.ts +++ b/apps/api-extractor/src/api/CompilerState.ts @@ -1,14 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; import { JsonFile } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { ExtractorConfig } from './ExtractorConfig'; import type { IExtractorInvokeOptions } from './Extractor'; -import { Colorize } from '@rushstack/terminal'; /** * Options for {@link CompilerState.create} @@ -67,6 +68,15 @@ export class CompilerState { ); } + // Delete outDir and declarationDir to prevent TypeScript from redirecting self-package + // imports to source files. When these options are set, TypeScript's module resolution + // tries to map output .d.ts files back to their source .ts files to avoid analyzing + // build outputs during compilation. However, API Extractor specifically wants to analyze + // the .d.ts build artifacts, not the source files. Since API Extractor doesn't emit any + // files, these options are unnecessary and interfere with correct module resolution. + delete commandLine.options.outDir; + delete commandLine.options.declarationDir; + const inputFilePaths: string[] = commandLine.fileNames.concat(extractorConfig.mainEntryPointFilePath); if (options && options.additionalEntryPoints) { inputFilePaths.push(...options.additionalEntryPoints); diff --git a/apps/api-extractor/src/api/ConsoleMessageId.ts b/apps/api-extractor/src/api/ConsoleMessageId.ts index 8fa2d53decc..5d1345a2093 100644 --- a/apps/api-extractor/src/api/ConsoleMessageId.ts +++ b/apps/api-extractor/src/api/ConsoleMessageId.ts @@ -61,6 +61,12 @@ export enum ConsoleMessageId { */ ApiReportNotCopied = 'console-api-report-not-copied', + /** + * Changes to the API report: + * ___ + */ + ApiReportDiff = 'console-api-report-diff', + /** * "You have changed the public API signature for this project. Updating ___" */ diff --git a/apps/api-extractor/src/api/Extractor.ts b/apps/api-extractor/src/api/Extractor.ts index f93c244a1d1..4542e9f8b60 100644 --- a/apps/api-extractor/src/api/Extractor.ts +++ b/apps/api-extractor/src/api/Extractor.ts @@ -1,13 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; import * as ts from 'typescript'; import * as resolve from 'resolve'; + +import type { ApiPackage } from '@microsoft/api-extractor-model'; +import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { FileSystem, - type NewlineKind, + NewlineKind, PackageJsonLookup, type IPackageJson, type INodePackageJson, @@ -18,7 +22,6 @@ import { ExtractorConfig, type IExtractorConfigApiReport } from './ExtractorConf import { Collector } from '../collector/Collector'; import { DtsRollupGenerator, DtsRollupKind } from '../generators/DtsRollupGenerator'; import { ApiModelGenerator } from '../generators/ApiModelGenerator'; -import type { ApiPackage } from '@microsoft/api-extractor-model'; import { ApiReportGenerator } from '../generators/ApiReportGenerator'; import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { ValidationEnhancer } from '../enhancers/ValidationEnhancer'; @@ -27,7 +30,6 @@ import { CompilerState } from './CompilerState'; import type { ExtractorMessage } from './ExtractorMessage'; import { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from './ConsoleMessageId'; -import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { SourceMapper } from '../collector/SourceMapper'; /** @@ -89,6 +91,15 @@ export interface IExtractorInvokeOptions { * the STDERR/STDOUT console. */ messageCallback?: (message: ExtractorMessage) => void; + + /** + * If true, then any differences between the actual and expected API reports will be + * printed on the console. + * + * @remarks + * The diff is not printed if the expected API report file has not been created yet. + */ + printApiReportDiff?: boolean; } /** @@ -142,12 +153,14 @@ export class ExtractorResult { /** @internal */ public constructor(properties: ExtractorResult) { - this.compilerState = properties.compilerState; - this.extractorConfig = properties.extractorConfig; - this.succeeded = properties.succeeded; - this.apiReportChanged = properties.apiReportChanged; - this.errorCount = properties.errorCount; - this.warningCount = properties.warningCount; + const { compilerState, extractorConfig, succeeded, apiReportChanged, errorCount, warningCount } = + properties; + this.compilerState = compilerState; + this.extractorConfig = extractorConfig; + this.succeeded = succeeded; + this.apiReportChanged = apiReportChanged; + this.errorCount = errorCount; + this.warningCount = warningCount; } } @@ -190,36 +203,52 @@ export class Extractor { * Invoke API Extractor using an already prepared `ExtractorConfig` object. */ public static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult { - if (!options) { - options = {}; - } - - const localBuild: boolean = options.localBuild || false; - - let compilerState: CompilerState | undefined; - if (options.compilerState) { - compilerState = options.compilerState; - } else { - compilerState = CompilerState.create(extractorConfig, options); - } + const { + packageFolder, + messages, + tsdocConfiguration, + tsdocConfigFile: { filePath: tsdocConfigFilePath, fileNotFound: tsdocConfigFileNotFound }, + apiJsonFilePath, + newlineKind, + reportTempFolder, + reportFolder, + apiReportEnabled, + reportConfigs, + testMode, + rollupEnabled, + publicTrimmedFilePath, + alphaTrimmedFilePath, + betaTrimmedFilePath, + untrimmedFilePath, + tsdocMetadataEnabled, + tsdocMetadataFilePath + } = extractorConfig; + const { + localBuild = false, + compilerState = CompilerState.create(extractorConfig, options), + messageCallback, + showVerboseMessages = false, + showDiagnostics = false, + printApiReportDiff = false + } = options ?? {}; const sourceMapper: SourceMapper = new SourceMapper(); const messageRouter: MessageRouter = new MessageRouter({ - workingPackageFolder: extractorConfig.packageFolder, - messageCallback: options.messageCallback, - messagesConfig: extractorConfig.messages || {}, - showVerboseMessages: !!options.showVerboseMessages, - showDiagnostics: !!options.showDiagnostics, - tsdocConfiguration: extractorConfig.tsdocConfiguration, + workingPackageFolder: packageFolder, + messageCallback, + messagesConfig: messages || {}, + showVerboseMessages, + showDiagnostics, + tsdocConfiguration, sourceMapper }); - if (extractorConfig.tsdocConfigFile.filePath && !extractorConfig.tsdocConfigFile.fileNotFound) { - if (!Path.isEqual(extractorConfig.tsdocConfigFile.filePath, ExtractorConfig._tsdocBaseFilePath)) { + if (tsdocConfigFilePath && !tsdocConfigFileNotFound) { + if (!Path.isEqual(tsdocConfigFilePath, ExtractorConfig._tsdocBaseFilePath)) { messageRouter.logVerbose( ConsoleMessageId.UsingCustomTSDocConfig, - 'Using custom TSDoc config from ' + extractorConfig.tsdocConfigFile.filePath + `Using custom TSDoc config from ${tsdocConfigFilePath}` ); } } @@ -241,9 +270,7 @@ export class Extractor { messageRouter.logDiagnosticHeader('TSDoc configuration'); // Convert the TSDocConfiguration into a tsdoc.json representation - const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser( - extractorConfig.tsdocConfiguration - ); + const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(tsdocConfiguration); const serializedTSDocConfig: object = MessageRouter.buildJsonDumpObject( combinedConfigFile.saveToObject() ); @@ -271,17 +298,14 @@ export class Extractor { } if (modelBuilder.docModelEnabled) { - messageRouter.logVerbose( - ConsoleMessageId.WritingDocModelFile, - 'Writing: ' + extractorConfig.apiJsonFilePath - ); - apiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, { + 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 }); } @@ -290,53 +314,51 @@ export class Extractor { collector, extractorConfig, messageRouter, - extractorConfig.reportTempFolder, - extractorConfig.reportFolder, + reportTempFolder, + reportFolder, reportConfig, - localBuild + localBuild, + printApiReportDiff ); } let anyReportChanged: boolean = false; - if (extractorConfig.apiReportEnabled) { - for (const reportConfig of extractorConfig.reportConfigs) { + if (apiReportEnabled) { + for (const reportConfig of reportConfigs) { anyReportChanged = writeApiReport(reportConfig) || anyReportChanged; } } - if (extractorConfig.rollupEnabled) { + if (rollupEnabled) { Extractor._generateRollupDtsFile( collector, - extractorConfig.publicTrimmedFilePath, + publicTrimmedFilePath, DtsRollupKind.PublicRelease, - extractorConfig.newlineKind + newlineKind ); Extractor._generateRollupDtsFile( collector, - extractorConfig.alphaTrimmedFilePath, + alphaTrimmedFilePath, DtsRollupKind.AlphaRelease, - extractorConfig.newlineKind + newlineKind ); Extractor._generateRollupDtsFile( collector, - extractorConfig.betaTrimmedFilePath, + betaTrimmedFilePath, DtsRollupKind.BetaRelease, - extractorConfig.newlineKind + newlineKind ); Extractor._generateRollupDtsFile( collector, - extractorConfig.untrimmedFilePath, + untrimmedFilePath, DtsRollupKind.InternalRelease, - extractorConfig.newlineKind + 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 @@ -371,6 +393,7 @@ export class Extractor { * @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). */ @@ -381,7 +404,8 @@ export class Extractor { reportTempDirectoryPath: string, reportDirectoryPath: string, reportConfig: IExtractorConfigApiReport, - localBuild: boolean + localBuild: boolean, + printApiReportDiff: boolean ): boolean { let apiReportChanged: boolean = false; @@ -409,7 +433,9 @@ export class Extractor { // Compare it against the expected file if (FileSystem.exists(expectedApiReportPath)) { - const expectedApiReportContent: string = FileSystem.readFile(expectedApiReportPath); + const expectedApiReportContent: string = FileSystem.readFile(expectedApiReportPath, { + convertLineEndings: NewlineKind.Lf + }); if ( !ApiReportGenerator.areEquivalentApiFileContents(actualApiReportContent, expectedApiReportContent) @@ -437,6 +463,26 @@ export class Extractor { 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, diff --git a/apps/api-extractor/src/api/ExtractorConfig.ts b/apps/api-extractor/src/api/ExtractorConfig.ts index 5f9a739c820..34a46b8fd46 100644 --- a/apps/api-extractor/src/api/ExtractorConfig.ts +++ b/apps/api-extractor/src/api/ExtractorConfig.ts @@ -1,13 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as resolve from 'resolve'; -import lodash = require('lodash'); + +import { EnumMemberOrder, ReleaseTag } from '@microsoft/api-extractor-model'; +import { TSDocConfiguration, TSDocTagDefinition } from '@microsoft/tsdoc'; +import { TSDocConfigFile } from '@microsoft/tsdoc-config'; +import { type IRigConfig, RigConfig } from '@rushstack/rig-package'; import { JsonFile, JsonSchema, FileSystem, + Objects, PackageJsonLookup, type INodePackageJson, PackageName, @@ -16,10 +22,6 @@ import { Path, NewlineKind } from '@rushstack/node-core-library'; -import { type IRigConfig, RigConfig } from '@rushstack/rig-package'; -import { EnumMemberOrder, ReleaseTag } from '@microsoft/api-extractor-model'; -import { TSDocConfiguration, TSDocTagDefinition } from '@microsoft/tsdoc'; -import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import type { ApiReportVariant, @@ -30,7 +32,6 @@ import type { import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { MessageRouter } from '../collector/MessageRouter'; import type { IApiModelGenerationOptions } from '../generators/ApiModelGenerator'; - import apiExtractorSchema from '../schemas/api-extractor.schema.json'; /** @@ -628,10 +629,10 @@ export class ExtractorConfig { 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) => { + // Arrays are overwritten rather than merged, which is the intuitive behavior for config files. + // For example, given a base config containing an array property with value ["foo", "bar"] and a + // derived config that specifies ["baz"] for that property, the result is ["baz"] (not ["baz", "bar"]). + const mergeCustomizer: Objects.MergeWithCustomizer = (objValue, srcValue) => { if (Array.isArray(srcValue)) { return srcValue; } @@ -679,11 +680,11 @@ export class ExtractorConfig { } // This step has to be performed in advance, since the currentConfigFolderPath information will be lost - // after lodash.merge() is performed. + // after the merge is performed. ExtractorConfig._resolveConfigFileRelativePaths(baseConfig, currentConfigFolderPath); // Merge extractorConfig into baseConfig, mutating baseConfig - lodash.mergeWith(baseConfig, configObject, mergeCustomizer); + Objects.mergeWith(baseConfig, configObject, mergeCustomizer); configObject = baseConfig; currentConfigFilePath = extendsField; @@ -693,11 +694,11 @@ export class ExtractorConfig { } // Lastly, apply the defaults - configObject = lodash.mergeWith( - lodash.cloneDeep(ExtractorConfig._defaultConfig), + configObject = Objects.mergeWith( + structuredClone(ExtractorConfig._defaultConfig), configObject, mergeCustomizer - ); + ) as Partial; ExtractorConfig.jsonSchema.validateObject(configObject, jsonFilePath); diff --git a/apps/api-extractor/src/api/ExtractorMessage.ts b/apps/api-extractor/src/api/ExtractorMessage.ts index 4b27f876e3b..60e9e95e274 100644 --- a/apps/api-extractor/src/api/ExtractorMessage.ts +++ b/apps/api-extractor/src/api/ExtractorMessage.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type * as tsdoc from '@microsoft/tsdoc'; + import type { ExtractorMessageId } from './ExtractorMessageId'; import { ExtractorLogLevel } from './ExtractorLogLevel'; import type { ConsoleMessageId } from './ConsoleMessageId'; @@ -131,16 +132,26 @@ export class ExtractorMessage { /** @internal */ public constructor(options: IExtractorMessageOptions) { - this.category = options.category; - this.messageId = options.messageId; - this.text = options.text; - this.sourceFilePath = options.sourceFilePath; - this.sourceFileLine = options.sourceFileLine; - this.sourceFileColumn = options.sourceFileColumn; - this.properties = options.properties || {}; + const { + category, + messageId, + text, + sourceFilePath, + sourceFileLine, + sourceFileColumn, + properties = {}, + logLevel = ExtractorLogLevel.None + } = options; + this.category = category; + this.messageId = messageId; + this.text = text; + this.sourceFilePath = sourceFilePath; + this.sourceFileLine = sourceFileLine; + this.sourceFileColumn = sourceFileColumn; + this.properties = properties; this._handled = false; - this._logLevel = options.logLevel || ExtractorLogLevel.None; + this._logLevel = logLevel; } /** diff --git a/apps/api-extractor/src/api/IConfigFile.ts b/apps/api-extractor/src/api/IConfigFile.ts index 4c7333f2818..f05b943f796 100644 --- a/apps/api-extractor/src/api/IConfigFile.ts +++ b/apps/api-extractor/src/api/IConfigFile.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { EnumMemberOrder } from '@microsoft/api-extractor-model'; + import type { ExtractorLogLevel } from './ExtractorLogLevel'; /** diff --git a/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts b/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts index dfe102bcea4..357e7c1dc00 100644 --- a/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts +++ b/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { StandardTags } from '@microsoft/tsdoc'; -import * as path from 'path'; +import * as path from 'node:path'; import { ExtractorConfig } from '../ExtractorConfig'; diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts index c2a771d0f80..e93e1d8b4ed 100644 --- a/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts +++ b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { Path } from '@rushstack/node-core-library'; import { ExtractorConfig } from '../ExtractorConfig'; diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts index ec7d52eed6c..d422c2fd54f 100644 --- a/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts +++ b/apps/api-extractor/src/api/test/ExtractorConfig-merge.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 { ExtractorConfig } from '../ExtractorConfig'; diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts index cc53a7fc5ba..0ca8ae974a9 100644 --- a/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts +++ b/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.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 { ExtractorConfig } from '../ExtractorConfig'; @@ -31,6 +31,6 @@ describe('ExtractorConfig-tagsToReport', () => { ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'invalid-tags-to-report/api-extractor.json') ) - ).toThrowError(expectedErrorMessage); + ).toThrow(expectedErrorMessage); }); }); diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts b/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts index 56c05a5cc6b..2c434e32cec 100644 --- a/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts +++ b/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; import { CommandLineParser, type CommandLineFlagParameter } from '@rushstack/ts-command-line'; import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; diff --git a/apps/api-extractor/src/cli/InitAction.ts b/apps/api-extractor/src/cli/InitAction.ts index 519115a77e0..834e2a7660f 100644 --- a/apps/api-extractor/src/cli/InitAction.ts +++ b/apps/api-extractor/src/cli/InitAction.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem } from '@rushstack/node-core-library'; import { CommandLineAction } from '@rushstack/ts-command-line'; import { Colorize } from '@rushstack/terminal'; diff --git a/apps/api-extractor/src/cli/RunAction.ts b/apps/api-extractor/src/cli/RunAction.ts index 4bfbf48333c..d0e60bb9326 100644 --- a/apps/api-extractor/src/cli/RunAction.ts +++ b/apps/api-extractor/src/cli/RunAction.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 os from 'os'; -import * as path from 'path'; +import * as os from 'node:os'; +import * as path from 'node:path'; + import { PackageJsonLookup, FileSystem, @@ -23,10 +24,11 @@ import { ExtractorConfig, type IExtractorConfigPrepareOptions } from '../api/Ext export class RunAction extends CommandLineAction { private readonly _configFileParameter: CommandLineStringParameter; - private readonly _localParameter: CommandLineFlagParameter; - private readonly _verboseParameter: CommandLineFlagParameter; + private readonly _localFlag: CommandLineFlagParameter; + private readonly _verboseFlag: CommandLineFlagParameter; private readonly _diagnosticsParameter: CommandLineFlagParameter; - private readonly _typescriptCompilerFolder: CommandLineStringParameter; + private readonly _typescriptCompilerFolderParameter: CommandLineStringParameter; + private readonly _printApiReportDiffFlag: CommandLineFlagParameter; public constructor(parser: ApiExtractorCommandLine) { super({ @@ -42,7 +44,7 @@ export class RunAction extends CommandLineAction { description: `Use the specified ${ExtractorConfig.FILENAME} file path, rather than guessing its location` }); - this._localParameter = this.defineFlagParameter({ + this._localFlag = this.defineFlagParameter({ parameterLongName: '--local', parameterShortName: '-l', description: @@ -52,7 +54,7 @@ export class RunAction extends CommandLineAction { ' report file is automatically copied in a local build.' }); - this._verboseParameter = this.defineFlagParameter({ + this._verboseFlag = this.defineFlagParameter({ parameterLongName: '--verbose', parameterShortName: '-v', description: 'Show additional informational messages in the output.' @@ -65,7 +67,7 @@ export class RunAction extends CommandLineAction { ' This flag also enables the "--verbose" flag.' }); - this._typescriptCompilerFolder = this.defineStringParameter({ + this._typescriptCompilerFolderParameter = this.defineStringParameter({ parameterLongName: '--typescript-compiler-folder', argumentName: 'PATH', description: @@ -75,13 +77,21 @@ export class RunAction extends CommandLineAction { ' "--typescriptCompilerFolder" option to specify the folder path where you installed the TypeScript package,' + " and API Extractor's compiler will use those system typings instead." }); + + this._printApiReportDiffFlag = this.defineFlagParameter({ + parameterLongName: '--print-api-report-diff', + description: + 'If provided, then any differences between the actual and expected API reports will be ' + + 'printed on the console. Note that the diff is not printed if the expected API report file has not been ' + + 'created yet.' + }); } protected 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,17 +102,17 @@ export class RunAction extends CommandLineAction { : undefined; if (!typescriptCompilerPackageJson) { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a package.` + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter is not a package.` ); } else if (typescriptCompilerPackageJson.name !== 'typescript') { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a TypeScript` + + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter is not a TypeScript` + ' compiler package.' ); } } else { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter does not exist.` + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter does not exist.` ); } } @@ -135,10 +145,11 @@ export class RunAction extends CommandLineAction { } const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { - localBuild: this._localParameter.value, - showVerboseMessages: this._verboseParameter.value, + localBuild: this._localFlag.value, + showVerboseMessages: this._verboseFlag.value, showDiagnostics: this._diagnosticsParameter.value, - typescriptCompilerFolder: typescriptCompilerFolder + typescriptCompilerFolder: typescriptCompilerFolder, + printApiReportDiff: this._printApiReportDiffFlag.value }); if (extractorResult.succeeded) { diff --git a/apps/api-extractor/src/collector/ApiItemMetadata.ts b/apps/api-extractor/src/collector/ApiItemMetadata.ts index 7355f3fe68f..a25b5da858a 100644 --- a/apps/api-extractor/src/collector/ApiItemMetadata.ts +++ b/apps/api-extractor/src/collector/ApiItemMetadata.ts @@ -3,6 +3,7 @@ import type * as tsdoc from '@microsoft/tsdoc'; import type { ReleaseTag } from '@microsoft/api-extractor-model'; + import { VisitorState } from './VisitorState'; /** @@ -93,13 +94,23 @@ export class ApiItemMetadata { public docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited; public constructor(options: IApiItemMetadataOptions) { - this.declaredReleaseTag = options.declaredReleaseTag; - this.effectiveReleaseTag = options.effectiveReleaseTag; - this.releaseTagSameAsParent = options.releaseTagSameAsParent; - this.isEventProperty = options.isEventProperty; - this.isOverride = options.isOverride; - this.isSealed = options.isSealed; - this.isVirtual = options.isVirtual; - this.isPreapproved = options.isPreapproved; + const { + declaredReleaseTag, + effectiveReleaseTag, + releaseTagSameAsParent, + isEventProperty, + isOverride, + isSealed, + isVirtual, + isPreapproved + } = options; + this.declaredReleaseTag = declaredReleaseTag; + this.effectiveReleaseTag = effectiveReleaseTag; + this.releaseTagSameAsParent = releaseTagSameAsParent; + this.isEventProperty = isEventProperty; + this.isOverride = isOverride; + this.isSealed = isSealed; + this.isVirtual = isVirtual; + this.isPreapproved = isPreapproved; } } diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index 2f006194e6b..131257996e2 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -2,7 +2,10 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; +import { minimatch } from 'minimatch'; + import * as tsdoc from '@microsoft/tsdoc'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; import { PackageJsonLookup, Sort, @@ -10,11 +13,8 @@ import { type INodePackageJson, PackageName } from '@rushstack/node-core-library'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; -import minimatch from 'minimatch'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; - import { CollectorEntity } from './CollectorEntity'; import { AstSymbolTable } from '../analyzer/AstSymbolTable'; import type { AstEntity } from '../analyzer/AstEntity'; @@ -107,11 +107,12 @@ export class Collector { public constructor(options: ICollectorOptions) { this.packageJsonLookup = new PackageJsonLookup(); - this._program = options.program; - this.extractorConfig = options.extractorConfig; - this.sourceMapper = options.sourceMapper; + const { program, extractorConfig, sourceMapper, messageRouter } = options; + this._program = program; + this.extractorConfig = extractorConfig; + this.sourceMapper = sourceMapper; - const entryPointSourceFile: ts.SourceFile | undefined = options.program.getSourceFile( + const entryPointSourceFile: ts.SourceFile | undefined = program.getSourceFile( this.extractorConfig.mainEntryPointFilePath ); @@ -131,10 +132,10 @@ export class Collector { entryPointSourceFile }); - this.messageRouter = options.messageRouter; + this.messageRouter = messageRouter; - this.program = options.program; - this.typeChecker = options.program.getTypeChecker(); + this.program = program; + this.typeChecker = program.getTypeChecker(); this.globalVariableAnalyzer = TypeScriptInternals.getGlobalVariableAnalyzer(this.program); this._tsdocParser = new tsdoc.TSDocParser(this.extractorConfig.tsdocConfiguration); diff --git a/apps/api-extractor/src/collector/CollectorEntity.ts b/apps/api-extractor/src/collector/CollectorEntity.ts index df75ffbe88a..36bb07353d9 100644 --- a/apps/api-extractor/src/collector/CollectorEntity.ts +++ b/apps/api-extractor/src/collector/CollectorEntity.ts @@ -3,9 +3,10 @@ import * as ts from 'typescript'; +import { Sort } from '@rushstack/node-core-library'; + import { AstSymbol } from '../analyzer/AstSymbol'; import { Collector } from './Collector'; -import { Sort } from '@rushstack/node-core-library'; import type { AstEntity } from '../analyzer/AstEntity'; import { AstNamespaceExport } from '../analyzer/AstNamespaceExport'; diff --git a/apps/api-extractor/src/collector/DeclarationMetadata.ts b/apps/api-extractor/src/collector/DeclarationMetadata.ts index 41aa83eea57..f3d44de3a17 100644 --- a/apps/api-extractor/src/collector/DeclarationMetadata.ts +++ b/apps/api-extractor/src/collector/DeclarationMetadata.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type * as tsdoc from '@microsoft/tsdoc'; + import type { AstDeclaration } from '../analyzer/AstDeclaration'; /** diff --git a/apps/api-extractor/src/collector/MessageRouter.ts b/apps/api-extractor/src/collector/MessageRouter.ts index 4ea05d81442..e35aa9571ea 100644 --- a/apps/api-extractor/src/collector/MessageRouter.ts +++ b/apps/api-extractor/src/collector/MessageRouter.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type * as tsdoc from '@microsoft/tsdoc'; import { Sort, InternalError } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; @@ -85,19 +86,28 @@ export class MessageRouter { public readonly showDiagnostics: boolean; public constructor(options: IMessageRouterOptions) { - this._workingPackageFolder = options.workingPackageFolder; - this._messageCallback = options.messageCallback; + const { + workingPackageFolder, + messageCallback, + sourceMapper, + tsdocConfiguration, + showVerboseMessages, + showDiagnostics, + messagesConfig + } = options; + this._workingPackageFolder = workingPackageFolder; + this._messageCallback = messageCallback; this._messages = []; this._associatedMessagesForAstDeclaration = new Map(); - this._sourceMapper = options.sourceMapper; - this._tsdocConfiguration = options.tsdocConfiguration; + this._sourceMapper = sourceMapper; + this._tsdocConfiguration = tsdocConfiguration; // showDiagnostics implies showVerboseMessages - this.showVerboseMessages = options.showVerboseMessages || options.showDiagnostics; - this.showDiagnostics = options.showDiagnostics; + this.showVerboseMessages = showVerboseMessages || showDiagnostics; + this.showDiagnostics = showDiagnostics; - this._applyMessagesConfig(options.messagesConfig); + this._applyMessagesConfig(messagesConfig); } /** @@ -421,7 +431,7 @@ export class MessageRouter { /** * This returns all remaining messages that were flagged with `addToApiReportFile`, but which were not - * retreieved using `fetchAssociatedMessagesForReviewFile()`. + * retrieved using `fetchAssociatedMessagesForReviewFile()`. */ public fetchUnassociatedMessagesForReviewFile(): ExtractorMessage[] { const messagesForApiReportFile: ExtractorMessage[] = []; diff --git a/apps/api-extractor/src/collector/SourceMapper.ts b/apps/api-extractor/src/collector/SourceMapper.ts index 7e7aee397af..368ea15fa07 100644 --- a/apps/api-extractor/src/collector/SourceMapper.ts +++ b/apps/api-extractor/src/collector/SourceMapper.ts @@ -1,11 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { SourceMapConsumer, type RawSourceMap, type MappingItem, type Position } from 'source-map'; -import { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library'; import type ts from 'typescript'; +import { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library'; + interface ISourceMap { sourceMapConsumer: SourceMapConsumer; diff --git a/apps/api-extractor/src/collector/WorkingPackage.ts b/apps/api-extractor/src/collector/WorkingPackage.ts index 537da4adeba..d85e88e4c11 100644 --- a/apps/api-extractor/src/collector/WorkingPackage.ts +++ b/apps/api-extractor/src/collector/WorkingPackage.ts @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. import type * as ts from 'typescript'; -import type * as tsdoc from '@microsoft/tsdoc'; +import type * as tsdoc from '@microsoft/tsdoc'; import type { INodePackageJson } from '@rushstack/node-core-library'; /** diff --git a/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts b/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts index dc7244e60b2..17b228afe35 100644 --- a/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts +++ b/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts @@ -2,13 +2,14 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import * as tsdoc from '@microsoft/tsdoc'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; import { VisitorState } from '../collector/VisitorState'; import { ResolverFailure } from '../analyzer/AstReferenceResolver'; diff --git a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts index dd6331b666c..09d80f862cc 100644 --- a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts +++ b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; + import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; @@ -11,7 +14,6 @@ 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'; diff --git a/apps/api-extractor/src/generators/ApiModelGenerator.ts b/apps/api-extractor/src/generators/ApiModelGenerator.ts index 2a9679c70f9..e03cfab218e 100644 --- a/apps/api-extractor/src/generators/ApiModelGenerator.ts +++ b/apps/api-extractor/src/generators/ApiModelGenerator.ts @@ -3,8 +3,10 @@ /* eslint-disable no-bitwise */ -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; + import type * as tsdoc from '@microsoft/tsdoc'; import { ApiModel, @@ -39,7 +41,7 @@ import { Path } from '@rushstack/node-core-library'; import type { Collector } from '../collector/Collector'; import type { ISourceLocation } from '../collector/SourceMapper'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ExcerptBuilder, type IExcerptBuilderNodeToCapture } from './ExcerptBuilder'; +import { ExcerptBuilder, type IExcerptBuilderNodeTransform } from './ExcerptBuilder'; import { AstSymbol } from '../analyzer/AstSymbol'; import { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; @@ -49,6 +51,7 @@ import type { AstEntity } from '../analyzer/AstEntity'; import type { AstModule } from '../analyzer/AstModule'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; import type { ExtractorConfig } from '../api/ExtractorConfig'; +import { DtsEmitHelpers } from './DtsEmitHelpers'; interface IProcessAstEntityContext { name: string; @@ -317,22 +320,24 @@ export class ApiModelGenerator { const callSignature: ts.CallSignatureDeclaration = astDeclaration.declaration as ts.CallSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: callSignature.type, tokenRange: returnTypeTokenRange }); + if (callSignature.type) { + nodeTransforms.push({ node: callSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, callSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, callSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -366,14 +371,14 @@ export class ApiModelGenerator { const constructorDeclaration: ts.ConstructorDeclaration = astDeclaration.declaration as ts.ConstructorDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, constructorDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -403,10 +408,10 @@ export class ApiModelGenerator { if (apiClass === undefined) { const classDeclaration: ts.ClassDeclaration = astDeclaration.declaration as ts.ClassDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, classDeclaration.typeParameters ); @@ -417,18 +422,18 @@ export class ApiModelGenerator { if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) { extendsTokenRange = ExcerptBuilder.createEmptyTokenRange(); if (heritageClause.types.length > 0) { - nodesToCapture.push({ node: heritageClause.types[0], tokenRange: extendsTokenRange }); + nodeTransforms.push({ node: heritageClause.types[0], captureTokenRange: extendsTokenRange }); } } else if (heritageClause.token === ts.SyntaxKind.ImplementsKeyword) { for (const heritageType of heritageClause.types) { const implementsTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); implementsTokenRanges.push(implementsTokenRange); - nodesToCapture.push({ node: heritageType, tokenRange: implementsTokenRange }); + nodeTransforms.push({ node: heritageType, captureTokenRange: implementsTokenRange }); } } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -474,22 +479,24 @@ export class ApiModelGenerator { const constructSignature: ts.ConstructSignatureDeclaration = astDeclaration.declaration as ts.ConstructSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: constructSignature.type, tokenRange: returnTypeTokenRange }); + if (constructSignature.type) { + nodeTransforms.push({ node: constructSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, constructSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, constructSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -554,15 +561,15 @@ export class ApiModelGenerator { if (apiEnumMember === undefined) { const enumMember: ts.EnumMember = astDeclaration.declaration as ts.EnumMember; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (enumMember.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ node: enumMember.initializer, captureTokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -597,22 +604,24 @@ export class ApiModelGenerator { const functionDeclaration: ts.FunctionDeclaration = altFunctionDeclaration ?? (astDeclaration.declaration as ts.FunctionDeclaration); - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: functionDeclaration.type, tokenRange: returnTypeTokenRange }); + if (functionDeclaration.type) { + nodeTransforms.push({ node: functionDeclaration.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, functionDeclaration.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, functionDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -648,17 +657,17 @@ export class ApiModelGenerator { const indexSignature: ts.IndexSignatureDeclaration = astDeclaration.declaration as ts.IndexSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: indexSignature.type, tokenRange: returnTypeTokenRange }); + nodeTransforms.push({ node: indexSignature.type, captureTokenRange: returnTypeTokenRange }); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, indexSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -692,10 +701,10 @@ export class ApiModelGenerator { const interfaceDeclaration: ts.InterfaceDeclaration = astDeclaration.declaration as ts.InterfaceDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, interfaceDeclaration.typeParameters ); @@ -706,12 +715,12 @@ export class ApiModelGenerator { for (const heritageType of heritageClause.types) { const extendsTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); extendsTokenRanges.push(extendsTokenRange); - nodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange }); + nodeTransforms.push({ node: heritageType, captureTokenRange: extendsTokenRange }); } } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -748,22 +757,24 @@ export class ApiModelGenerator { if (apiMethod === undefined) { const methodDeclaration: ts.MethodDeclaration = astDeclaration.declaration as ts.MethodDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange }); + if (methodDeclaration.type) { + nodeTransforms.push({ node: methodDeclaration.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, methodDeclaration.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, methodDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -811,22 +822,24 @@ export class ApiModelGenerator { if (apiMethodSignature === undefined) { const methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange }); + if (methodSignature.type) { + nodeTransforms.push({ node: methodSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, methodSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, methodSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -892,7 +905,7 @@ export class ApiModelGenerator { if (apiProperty === undefined) { const declaration: ts.Declaration = astDeclaration.declaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); let propertyTypeNode: ts.TypeNode | undefined; @@ -906,15 +919,17 @@ export class ApiModelGenerator { propertyTypeNode = declaration.parameters[0].type; } - nodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange }); + if (propertyTypeNode) { + nodeTransforms.push({ node: propertyTypeNode, captureTokenRange: propertyTypeTokenRange }); + } let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (ts.isPropertyDeclaration(declaration) && declaration.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ node: declaration.initializer, captureTokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -960,12 +975,14 @@ export class ApiModelGenerator { if (apiPropertySignature === undefined) { const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange }); + if (propertySignature.type) { + nodeTransforms.push({ node: propertySignature.type, captureTokenRange: propertyTypeTokenRange }); + } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1005,17 +1022,17 @@ export class ApiModelGenerator { const typeAliasDeclaration: ts.TypeAliasDeclaration = astDeclaration.declaration as ts.TypeAliasDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, typeAliasDeclaration.typeParameters ); const typeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeAliasDeclaration.type, tokenRange: typeTokenRange }); + nodeTransforms.push({ node: typeAliasDeclaration.type, captureTokenRange: typeTokenRange }); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1047,18 +1064,23 @@ export class ApiModelGenerator { const variableDeclaration: ts.VariableDeclaration = astDeclaration.declaration as ts.VariableDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const variableTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: variableDeclaration.type, tokenRange: variableTypeTokenRange }); + if (variableDeclaration.type) { + nodeTransforms.push({ node: variableDeclaration.type, captureTokenRange: variableTypeTokenRange }); + } let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (variableDeclaration.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: variableDeclaration.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ + node: variableDeclaration.initializer, + captureTokenRange: initializerTokenRange + }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1082,16 +1104,16 @@ export class ApiModelGenerator { } /** - * @param nodesToCapture - A list of child nodes whose token ranges we want to capture + * @param nodeTransforms - A list of child nodes whose token ranges we want to capture */ private _buildExcerptTokens( astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[] + nodeTransforms: IExcerptBuilderNodeTransform[] ): IExcerptToken[] { const excerptTokens: IExcerptToken[] = []; // Build the main declaration - ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodesToCapture, this._referenceGenerator); + ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodeTransforms, this._referenceGenerator); const declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration); @@ -1101,7 +1123,7 @@ export class ApiModelGenerator { ExcerptBuilder.addDeclaration( excerptTokens, ancillaryDeclaration, - nodesToCapture, + nodeTransforms, this._referenceGenerator ); } @@ -1110,17 +1132,21 @@ export class ApiModelGenerator { } private _captureTypeParameters( - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], typeParameterNodes: ts.NodeArray | undefined ): IApiTypeParameterOptions[] { const typeParameters: IApiTypeParameterOptions[] = []; if (typeParameterNodes) { for (const typeParameter of typeParameterNodes) { const constraintTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeParameter.constraint, tokenRange: constraintTokenRange }); + if (typeParameter.constraint) { + nodeTransforms.push({ node: typeParameter.constraint, captureTokenRange: constraintTokenRange }); + } const defaultTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeParameter.default, tokenRange: defaultTypeTokenRange }); + if (typeParameter.default) { + nodeTransforms.push({ node: typeParameter.default, captureTokenRange: defaultTypeTokenRange }); + } typeParameters.push({ typeParameterName: typeParameter.name.getText().trim(), @@ -1133,19 +1159,31 @@ export class ApiModelGenerator { } private _captureParameters( - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], parameterNodes: ts.NodeArray ): IApiParameterOptions[] { const parameters: IApiParameterOptions[] = []; - for (const parameter of parameterNodes) { - const parameterTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: parameter.type, tokenRange: parameterTypeTokenRange }); - parameters.push({ - parameterName: parameter.name.getText().trim(), - parameterTypeTokenRange, - isOptional: this._collector.typeChecker.isOptionalParameter(parameter) - }); - } + + DtsEmitHelpers.forEachParameterToNormalize( + parameterNodes, + (parameter: ts.ParameterDeclaration, syntheticName: string | undefined): void => { + const parameterTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); + if (parameter.type) { + nodeTransforms.push({ node: parameter.type, captureTokenRange: parameterTypeTokenRange }); + } + parameters.push({ + parameterName: syntheticName ?? parameter.name.getText().trim(), + parameterTypeTokenRange, + isOptional: this._collector.typeChecker.isOptionalParameter(parameter) + }); + + if (syntheticName !== undefined) { + // Replace the subexpression like "{ y, z }" with the synthesized parameter name + nodeTransforms.push({ node: parameter.name, replacementText: syntheticName }); + } + } + ); + return parameters; } diff --git a/apps/api-extractor/src/generators/ApiReportGenerator.ts b/apps/api-extractor/src/generators/ApiReportGenerator.ts index cf91d725ed4..a18a62fe05f 100644 --- a/apps/api-extractor/src/generators/ApiReportGenerator.ts +++ b/apps/api-extractor/src/generators/ApiReportGenerator.ts @@ -2,8 +2,9 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { Text, InternalError } from '@rushstack/node-core-library'; + import { ReleaseTag } from '@microsoft/api-extractor-model'; +import { Text, InternalError } from '@rushstack/node-core-library'; import { Collector } from '../collector/Collector'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; @@ -24,6 +25,12 @@ import { ExtractorMessageId } from '../api/ExtractorMessageId'; import type { ApiReportVariant } from '../api/IConfigFile'; import type { SymbolMetadata } from '../collector/SymbolMetadata'; +interface IContext { + collector: Collector; + reportVariant: ApiReportVariant; + alreadyProcessedSignatures: Set; +} + export class ApiReportGenerator { private static _trimSpacesRegExp: RegExp = / +$/gm; @@ -91,6 +98,12 @@ export class ApiReportGenerator { } writer.ensureSkippedLine(); + const context: IContext = { + collector, + reportVariant, + alreadyProcessedSignatures: new Set() + }; + // Emit the regular declarations for (const entity of collector.entities) { const astEntity: AstEntity = entity.astEntity; @@ -151,7 +164,7 @@ export class ApiReportGenerator { if (apiItemMetadata.isPreapproved) { ApiReportGenerator._modifySpanForPreapproved(span); } else { - ApiReportGenerator._modifySpan(collector, span, entity, astDeclaration, false, reportVariant); + ApiReportGenerator._modifySpan(span, entity, astDeclaration, false, context); } span.writeModifiedText(writer); @@ -275,15 +288,15 @@ export class ApiReportGenerator { * Before writing out a declaration, _modifySpan() applies various fixups to make it nice. */ private static _modifySpan( - collector: Collector, span: Span, entity: CollectorEntity, astDeclaration: AstDeclaration, insideTypeLiteral: boolean, - reportVariant: ApiReportVariant + context: IContext ): void { + const { collector, reportVariant } = context; + // Should we process this declaration at all? - // eslint-disable-next-line no-bitwise if (!ApiReportGenerator._shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) { span.modification.skipAll(); return; @@ -302,6 +315,14 @@ export class ApiReportGenerator { break; case ts.SyntaxKind.ExportKeyword: + if (DtsEmitHelpers.isExportKeywordInNamespaceExportDeclaration(span.node)) { + // This is an export declaration inside a namespace - preserve the export keyword + break; + } + // Otherwise, delete the export keyword -- we will re-add it below + span.modification.skipAll(); + break; + case ts.SyntaxKind.DefaultKeyword: case ts.SyntaxKind.DeclareKeyword: // Delete any explicit "export" or "declare" keywords -- we will re-add them below @@ -374,6 +395,19 @@ export class ApiReportGenerator { } break; + case ts.SyntaxKind.Parameter: + { + // (signature) -> SyntaxList -> Parameter + const signatureParent: Span | undefined = span.parent; + if (signatureParent) { + if (!context.alreadyProcessedSignatures.has(signatureParent)) { + context.alreadyProcessedSignatures.add(signatureParent); + DtsEmitHelpers.normalizeParameterNames(signatureParent); + } + } + } + break; + case ts.SyntaxKind.Identifier: const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( span.node as ts.Identifier @@ -406,12 +440,11 @@ export class ApiReportGenerator { astDeclaration, (childSpan, childAstDeclaration) => { ApiReportGenerator._modifySpan( - collector, childSpan, entity, childAstDeclaration, insideTypeLiteral, - reportVariant + context ); } ); @@ -452,14 +485,7 @@ export class ApiReportGenerator { } } - ApiReportGenerator._modifySpan( - collector, - child, - entity, - childAstDeclaration, - insideTypeLiteral, - reportVariant - ); + ApiReportGenerator._modifySpan(child, entity, childAstDeclaration, insideTypeLiteral, context); } } } diff --git a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts index 4171f819f94..6f136fb9829 100644 --- a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -3,6 +3,7 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; + import { DeclarationReference, ModuleSource, @@ -11,6 +12,7 @@ import { Meaning } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { type INodePackageJson, InternalError } from '@rushstack/node-core-library'; + import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; import type { Collector } from '../collector/Collector'; diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 3e7a339115e..7cde437bee8 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -4,6 +4,7 @@ import * as ts from 'typescript'; import { InternalError } from '@rushstack/node-core-library'; + import type { CollectorEntity } from '../collector/CollectorEntity'; import { AstImport, AstImportKind } from '../analyzer/AstImport'; import { AstDeclaration } from '../analyzer/AstDeclaration'; @@ -11,6 +12,7 @@ import type { Collector } from '../collector/Collector'; import type { Span } from '../analyzer/Span'; import type { IndentedWriter } from './IndentedWriter'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; /** * Some common code shared between DtsRollupGenerator and ApiReportGenerator. @@ -170,4 +172,124 @@ export class DtsEmitHelpers { } } } + + /** + * Checks if an export keyword is part of an ExportDeclaration inside a namespace + * (e.g., "export { Foo, Bar };" inside "declare namespace SDK { ... }"). + * In that case, the export keyword must be preserved, otherwise the output is invalid TypeScript. + */ + public static isExportKeywordInNamespaceExportDeclaration(node: ts.Node): boolean { + if (node.parent && ts.isExportDeclaration(node.parent)) { + const moduleBlock: ts.ModuleBlock | undefined = TypeScriptHelpers.findFirstParent( + node, + ts.SyntaxKind.ModuleBlock + ); + if (moduleBlock) { + return true; + } + } + return false; + } + + /** + * Given an array that includes some parameter nodes, this returns an array of the same length; + * elements that are not undefined correspond to a parameter that should be renamed. + */ + public static forEachParameterToNormalize( + nodes: ArrayLike, + action: (parameter: ts.ParameterDeclaration, syntheticName: string | undefined) => void + ): void { + let actionIndex: number = 0; + + // Optimistically assume that no parameters need to be normalized + for (actionIndex = 0; actionIndex < nodes.length; ++actionIndex) { + const parameter: ts.Node = nodes[actionIndex]; + if (!ts.isParameter(parameter)) { + continue; + } + action(parameter, undefined); + if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) { + // Our optimistic assumption was not true; we'll need to stop and calculate alreadyUsedNames + break; + } + } + + if (actionIndex === nodes.length) { + // Our optimistic assumption was true + return; + } + + // First, calculate alreadyUsedNames + const alreadyUsedNames: string[] = []; + + for (let index: number = 0; index < nodes.length; ++index) { + const parameter: ts.Node = nodes[index]; + if (!ts.isParameter(parameter)) { + continue; + } + + if (!(ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name))) { + alreadyUsedNames.push(parameter.name.text.trim()); + } + } + + // Now continue with the rest of the actions + for (; actionIndex < nodes.length; ++actionIndex) { + const parameter: ts.Node = nodes[actionIndex]; + if (!ts.isParameter(parameter)) { + continue; + } + + if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) { + // Examples: + // + // function f({ y, z }: { y: string, z: string }) + // ---> function f(input: { y: string, z: string }) + // + // function f(x: number, [a, b]: [number, number]) + // ---> function f(x: number, input: [number, number]) + // + // Example of a naming collision: + // + // function f({ a }: { a: string }, { b }: { b: string }, input2: string) + // ---> function f(input: { a: string }, input3: { b: string }, input2: string) + const baseName: string = 'input'; + let counter: number = 2; + + let syntheticName: string = baseName; + while (alreadyUsedNames.includes(syntheticName)) { + syntheticName = `${baseName}${counter++}`; + } + alreadyUsedNames.push(syntheticName); + + action(parameter, syntheticName); + } else { + action(parameter, undefined); + } + } + } + + public static normalizeParameterNames(signatureSpan: Span): void { + const syntheticNamesByNode: Map = new Map(); + + DtsEmitHelpers.forEachParameterToNormalize( + signatureSpan.node.getChildren(), + (parameter: ts.ParameterDeclaration, syntheticName: string | undefined): void => { + if (syntheticName !== undefined) { + syntheticNamesByNode.set(parameter.name, syntheticName); + } + } + ); + + if (syntheticNamesByNode.size > 0) { + signatureSpan.forEach((childSpan: Span): void => { + const syntheticName: string | undefined = syntheticNamesByNode.get(childSpan.node); + if (syntheticName !== undefined) { + childSpan.modification.prefix = syntheticName; + childSpan.modification.suffix = ''; + childSpan.modification.omitChildren = true; + } + }); + } + } } diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index 4ecea8e2c7f..9bb69345e05 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/* eslint-disable no-bitwise */ - import * as ts from 'typescript'; -import { FileSystem, type NewlineKind, InternalError } from '@rushstack/node-core-library'; + import { ReleaseTag } from '@microsoft/api-extractor-model'; +import { FileSystem, type NewlineKind, InternalError } from '@rushstack/node-core-library'; import type { Collector } from '../collector/Collector'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; @@ -271,6 +270,14 @@ export class DtsRollupGenerator { break; case ts.SyntaxKind.ExportKeyword: + if (DtsEmitHelpers.isExportKeywordInNamespaceExportDeclaration(span.node)) { + // This is an export declaration inside a namespace - preserve the export keyword + break; + } + // Otherwise, delete the export keyword -- we will re-add it below + span.modification.skipAll(); + break; + case ts.SyntaxKind.DefaultKeyword: case ts.SyntaxKind.DeclareKeyword: // Delete any explicit "export" or "declare" keywords -- we will re-add them below @@ -442,6 +449,12 @@ export class DtsRollupGenerator { } } + if (modification.suffix.trim().length === 0 && modification.prefix.trim().length === 0) { + // In case of blank prefix and suffix, remove indentation to avoid blank lines in place of removed members + modification.suffix = ''; + modification.prefix = ''; + } + trimmed = true; } } diff --git a/apps/api-extractor/src/generators/ExcerptBuilder.ts b/apps/api-extractor/src/generators/ExcerptBuilder.ts index 69bead2a9af..ce1662c789a 100644 --- a/apps/api-extractor/src/generators/ExcerptBuilder.ts +++ b/apps/api-extractor/src/generators/ExcerptBuilder.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { ExcerptTokenKind, @@ -16,16 +17,22 @@ import type { AstDeclaration } from '../analyzer/AstDeclaration'; /** * Used to provide ExcerptBuilder with a list of nodes whose token range we want to capture. */ -export interface IExcerptBuilderNodeToCapture { +export interface IExcerptBuilderNodeTransform { + /** + * The node to process + */ + node: ts.Node; + /** - * The node to capture + * A token range whose startIndex/endIndex will be overwritten with the indexes for the + * tokens corresponding to IExcerptBuilderNodeTransform.node */ - node: ts.Node | undefined; + captureTokenRange?: IExcerptTokenRange; + /** - * The token range whose startIndex/endIndex will be overwritten with the indexes for the - * tokens corresponding to IExcerptBuilderNodeToCapture.node + * Text that will replace the text of the given node during emit. */ - tokenRange: IExcerptTokenRange; + replacementText?: string; } /** @@ -50,7 +57,7 @@ interface IBuildSpanState { */ stopBeforeChildKind: ts.SyntaxKind | undefined; - tokenRangesByNode: Map; + transformsByNode: Map; /** * Tracks whether the last appended token was a separator. If so, and we're in the middle of @@ -79,12 +86,12 @@ export class ExcerptBuilder { /** * Appends the signature for the specified `AstDeclaration` to the `excerptTokens` list. * @param excerptTokens - The target token list to append to - * @param nodesToCapture - A list of child nodes whose token ranges we want to capture + * @param nodeTransforms - A list of child nodes whose token ranges we want to capture */ public static addDeclaration( excerptTokens: IExcerptToken[], astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], referenceGenerator: DeclarationReferenceGenerator ): void { let stopBeforeChildKind: ts.SyntaxKind | undefined = undefined; @@ -104,10 +111,12 @@ export class ExcerptBuilder { const span: Span = new Span(astDeclaration.declaration); - const tokenRangesByNode: Map = new Map(); - for (const excerpt of nodesToCapture || []) { - if (excerpt.node) { - tokenRangesByNode.set(excerpt.node, excerpt.tokenRange); + const transformsByNode: Map = new Map(); + const captureTokenRanges: IExcerptTokenRange[] = []; + for (const nodeTransform of nodeTransforms || []) { + transformsByNode.set(nodeTransform.node, nodeTransform); + if (nodeTransform.captureTokenRange) { + captureTokenRanges.push(nodeTransform.captureTokenRange); } } @@ -115,16 +124,18 @@ export class ExcerptBuilder { referenceGenerator: referenceGenerator, startingNode: span.node, stopBeforeChildKind, - tokenRangesByNode, + transformsByNode: transformsByNode, lastAppendedTokenIsSeparator: false }); - ExcerptBuilder._condenseTokens(excerptTokens, [...tokenRangesByNode.values()]); + + ExcerptBuilder._condenseTokens(excerptTokens, captureTokenRanges); } public static createEmptyTokenRange(): IExcerptTokenRange { return { startIndex: 0, endIndex: 0 }; } + /** @returns false if we encountered a token that causes iteration to stop. */ private static _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean { if (span.kind === ts.SyntaxKind.JSDocComment) { // Discard any comments @@ -132,10 +143,30 @@ export class ExcerptBuilder { } // Can this node start a excerpt? - const capturedTokenRange: IExcerptTokenRange | undefined = state.tokenRangesByNode.get(span.node); + const transform: IExcerptBuilderNodeTransform | undefined = state.transformsByNode.get(span.node); + + let captureTokenRange: IExcerptTokenRange | undefined = undefined; + + if (transform) { + captureTokenRange = transform.captureTokenRange; + if (transform.replacementText !== undefined) { + excerptTokens.push({ + kind: ExcerptTokenKind.Content, + text: transform.replacementText + }); + state.lastAppendedTokenIsSeparator = false; + + if (captureTokenRange) { + captureTokenRange.startIndex = excerptTokens.length; + captureTokenRange.endIndex = captureTokenRange.startIndex + 1; + } + return true; + } + } + let excerptStartIndex: number = 0; - if (capturedTokenRange) { + if (captureTokenRange) { // We will assign capturedTokenRange.startIndex to be the index of the next token to be appended excerptStartIndex = excerptTokens.length; } @@ -186,8 +217,8 @@ export class ExcerptBuilder { } // Are we building a excerpt? If so, set its range - if (capturedTokenRange) { - capturedTokenRange.startIndex = excerptStartIndex; + if (captureTokenRange) { + captureTokenRange.startIndex = excerptStartIndex; // 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 @@ -197,7 +228,7 @@ export class ExcerptBuilder { excerptEndIndex--; } - capturedTokenRange.endIndex = excerptEndIndex; + captureTokenRange.endIndex = excerptEndIndex; } return true; diff --git a/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap b/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap index 6803fe9f220..1665c736ea8 100644 --- a/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap +++ b/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`01 Demo from docs 1`] = ` "begin diff --git a/apps/api-extractor/src/start.ts b/apps/api-extractor/src/start.ts index 846e9fc4f96..2274fea6b22 100644 --- a/apps/api-extractor/src/start.ts +++ b/apps/api-extractor/src/start.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; + import { Colorize } from '@rushstack/terminal'; import { ApiExtractorCommandLine } from './cli/ApiExtractorCommandLine'; diff --git a/apps/cpu-profile-summarizer/.eslintrc.js b/apps/cpu-profile-summarizer/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/apps/cpu-profile-summarizer/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/cpu-profile-summarizer/.npmignore b/apps/cpu-profile-summarizer/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/apps/cpu-profile-summarizer/.npmignore +++ b/apps/cpu-profile-summarizer/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/cpu-profile-summarizer/CHANGELOG.json b/apps/cpu-profile-summarizer/CHANGELOG.json index 1a7584e74b4..f6d15728997 100644 --- a/apps/cpu-profile-summarizer/CHANGELOG.json +++ b/apps/cpu-profile-summarizer/CHANGELOG.json @@ -1,6 +1,700 @@ { "name": "@rushstack/cpu-profile-summarizer", "entries": [ + { + "version": "0.2.17", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.43", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.42", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.41", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.40", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.39", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.38", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.37", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.36", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.35", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.34", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.33", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.32", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.31", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.30", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.29", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.28", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.27", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.26", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.25", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.24", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.23", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.22", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.21", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, { "version": "0.1.20", "tag": "@rushstack/cpu-profile-summarizer_v0.1.20", diff --git a/apps/cpu-profile-summarizer/CHANGELOG.md b/apps/cpu-profile-summarizer/CHANGELOG.md index 7e6a90a5b5b..f8695b41e6f 100644 --- a/apps/cpu-profile-summarizer/CHANGELOG.md +++ b/apps/cpu-profile-summarizer/CHANGELOG.md @@ -1,6 +1,215 @@ # Change Log - @rushstack/cpu-profile-summarizer -This log was last generated on Tue, 13 May 2025 02:09:20 GMT and should not be manually modified. +This log was last generated on Mon, 20 Apr 2026 23:31:13 GMT and should not be manually modified. + +## 0.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 0.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 0.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.43 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.42 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.41 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.40 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.39 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.38 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.1.37 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.1.36 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.1.35 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.1.34 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.1.33 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 0.1.32 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.1.31 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.1.30 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.1.29 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 0.1.28 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.1.27 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.1.26 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.1.25 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.1.24 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.1.23 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.1.22 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.1.21 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ ## 0.1.20 Tue, 13 May 2025 02:09:20 GMT diff --git a/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator b/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator index aee68e80224..eef2fc27066 100644 --- a/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator +++ b/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); 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 index 0afe0826d52..6ab396a06a5 100644 --- a/apps/cpu-profile-summarizer/package.json +++ b/apps/cpu-profile-summarizer/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/cpu-profile-summarizer", - "version": "0.1.20", + "version": "0.2.17", "description": "CLI tool for running analytics on multiple V8 .cpuprofile files", "repository": { "type": "git", @@ -23,6 +23,27 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/heft/.eslintrc.js b/apps/heft/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/apps/heft/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/apps/heft/.npmignore b/apps/heft/.npmignore index 3b7d5ed9526..1d4b6d39ec5 100644 --- a/apps/heft/.npmignore +++ b/apps/heft/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -31,6 +35,4 @@ # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -!/includes/** !UPGRADING.md - diff --git a/apps/heft/CHANGELOG.json b/apps/heft/CHANGELOG.json index a02cb62abe7..0445d9804d3 100644 --- a/apps/heft/CHANGELOG.json +++ b/apps/heft/CHANGELOG.json @@ -1,6 +1,864 @@ { "name": "@rushstack/heft", "entries": [ + { + "version": "1.2.17", + "tag": "@rushstack/heft_v1.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.10`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.7`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft_v1.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.6`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft_v1.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.9`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.5`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft_v1.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.4`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft_v1.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.3`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.6`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.2`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.1`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.0`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.3`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.2`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.1`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.0`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.5`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.4`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.3`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.0`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + } + ] + } + }, + { + "version": "0.75.0", + "tag": "@rushstack/heft_v0.75.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Enhance logging in watch mode by allowing plugins to report detailed reasons for requesting rerun, e.g. specific changed files." + }, + { + "comment": "(BREAKING CHANGE) Make the `taskStart`/`taskFinish`/`phaseStart`/`phaseFinish` hooks synchronous to signify that they are not intended to be used for expensive work." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + } + ] + } + }, + { + "version": "0.74.5", + "tag": "@rushstack/heft_v0.74.5", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.13`" + } + ] + } + }, + { + "version": "0.74.4", + "tag": "@rushstack/heft_v0.74.4", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.12`" + } + ] + } + }, + { + "version": "0.74.3", + "tag": "@rushstack/heft_v0.74.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.11`" + } + ] + } + }, + { + "version": "0.74.2", + "tag": "@rushstack/heft_v0.74.2", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + } + ] + } + }, + { + "version": "0.74.1", + "tag": "@rushstack/heft_v0.74.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + } + ] + } + }, + { + "version": "0.74.0", + "tag": "@rushstack/heft_v0.74.0", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "minor": [ + { + "comment": "Added support for task and phase lifecycle events, `taskStart`, `taskFinish`, `phaseStart`, `phaseFinish`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.0`" + } + ] + } + }, { "version": "0.73.6", "tag": "@rushstack/heft_v0.73.6", diff --git a/apps/heft/CHANGELOG.md b/apps/heft/CHANGELOG.md index 83ff3583233..72a498b033d 100644 --- a/apps/heft/CHANGELOG.md +++ b/apps/heft/CHANGELOG.md @@ -1,6 +1,224 @@ # Change Log - @rushstack/heft -This log was last generated on Tue, 13 May 2025 02:09:20 GMT and should not be manually modified. +This log was last generated on Mon, 20 Apr 2026 23:31:13 GMT and should not be manually modified. + +## 1.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 1.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 1.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.75.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Enhance logging in watch mode by allowing plugins to report detailed reasons for requesting rerun, e.g. specific changed files. +- (BREAKING CHANGE) Make the `taskStart`/`taskFinish`/`phaseStart`/`phaseFinish` hooks synchronous to signify that they are not intended to be used for expensive work. + +## 0.74.5 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.74.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.74.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.74.2 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.74.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.74.0 +Sat, 21 Jun 2025 00:13:15 GMT + +### Minor changes + +- Added support for task and phase lifecycle events, `taskStart`, `taskFinish`, `phaseStart`, `phaseFinish`. ## 0.73.6 Tue, 13 May 2025 02:09:20 GMT diff --git a/apps/heft/bin/heft b/apps/heft/bin/heft index ef67d5db050..eb51ae89e3e 100755 --- a/apps/heft/bin/heft +++ b/apps/heft/bin/heft @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/startWithVersionSelector.js'); +require('../lib-commonjs/startWithVersionSelector.js'); diff --git a/apps/heft/config/api-extractor.json b/apps/heft/config/api-extractor.json index 34fb7776c9d..005e818a08b 100644 --- a/apps/heft/config/api-extractor.json +++ b/apps/heft/config/api-extractor.json @@ -1,15 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/apps/heft/config/heft.json b/apps/heft/config/heft.json new file mode 100644 index 00000000000..76eac0e3d31 --- /dev/null +++ b/apps/heft/config/heft.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + }, + + "copy-legacy-compatibility-start-js": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/legacy-compatibility", + "destinationFolders": ["lib"], + "includeGlobs": ["*"] + } + ] + } + } + } + } + } + } +} diff --git a/apps/heft/eslint.config.js b/apps/heft/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/apps/heft/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/heft/heft-plugin.json b/apps/heft/heft-plugin.json index d7c161a404f..417896dc263 100644 --- a/apps/heft/heft-plugin.json +++ b/apps/heft/heft-plugin.json @@ -6,17 +6,17 @@ "taskPlugins": [ { "pluginName": "copy-files-plugin", - "entryPoint": "./lib/plugins/CopyFilesPlugin", - "optionsSchema": "./lib/schemas/copy-files-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/CopyFilesPlugin", + "optionsSchema": "./lib-commonjs/schemas/copy-files-options.schema.json" }, { "pluginName": "delete-files-plugin", - "entryPoint": "./lib/plugins/DeleteFilesPlugin", - "optionsSchema": "./lib/schemas/delete-files-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/DeleteFilesPlugin", + "optionsSchema": "./lib-commonjs/schemas/delete-files-options.schema.json" }, { "pluginName": "node-service-plugin", - "entryPoint": "./lib/plugins/NodeServicePlugin", + "entryPoint": "./lib-commonjs/plugins/NodeServicePlugin", "parameterScope": "node-service", "parameters": [ { @@ -28,13 +28,13 @@ }, { "pluginName": "run-script-plugin", - "entryPoint": "./lib/plugins/RunScriptPlugin", - "optionsSchema": "./lib/schemas/run-script-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/RunScriptPlugin", + "optionsSchema": "./lib-commonjs/schemas/run-script-options.schema.json" }, { - "entryPoint": "./lib/plugins/SetEnvironmentVariablesPlugin", + "entryPoint": "./lib-commonjs/plugins/SetEnvironmentVariablesPlugin", "pluginName": "set-environment-variables-plugin", - "optionsSchema": "./lib/schemas/set-environment-variables-plugin.schema.json" + "optionsSchema": "./lib-commonjs/schemas/set-environment-variables-plugin.schema.json" } ] } diff --git a/apps/heft/package.json b/apps/heft/package.json index 73575de3bcd..53b0a30d1b9 100644 --- a/apps/heft/package.json +++ b/apps/heft/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft", - "version": "0.73.6", + "version": "1.2.17", "description": "Build all your JavaScript projects the same way: A way that works.", "keywords": [ "toolchain", @@ -21,15 +21,40 @@ "node": ">=10.13.0" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "dist/heft.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft.d.ts", + "exports": { + ".": { + "types": "./dist/heft.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "bin": { "heft": "./bin/heft" }, "license": "MIT", "scripts": { "build": "heft build --clean", - "start": "heft test --clean --watch", + "start": "heft build-watch --clean", "_phase:build": "heft run --only build -- --clean", "_phase:test": "heft run --only test -- --clean" }, @@ -49,9 +74,15 @@ }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "@rushstack/heft": "0.73.2", + "@rushstack/heft": "1.2.17", "@types/watchpack": "2.4.0", "decoupled-local-node-rig": "workspace:*", - "local-eslint-config": "workspace:*" - } + "eslint": "~9.37.0" + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-commonjs/startWithVersionSelector.js", + "lib-esm/start.js", + "lib-esm/startWithVersionSelector.js" + ] } diff --git a/apps/heft/src/cli/HeftActionRunner.ts b/apps/heft/src/cli/HeftActionRunner.ts index e60b78dbac7..b9d5c7f7f26 100644 --- a/apps/heft/src/cli/HeftActionRunner.ts +++ b/apps/heft/src/cli/HeftActionRunner.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { performance } from 'perf_hooks'; -import { createInterface, type Interface as ReadlineInterface } from 'readline'; -import os from 'os'; +import { performance } from 'node:perf_hooks'; +import { createInterface, type Interface as ReadlineInterface } from 'node:readline'; +import os from 'node:os'; import { AlreadyReportedError, InternalError, type IPackageJson } from '@rushstack/node-core-library'; import { Colorize, ConsoleTerminalProvider, type ITerminal } from '@rushstack/terminal'; @@ -12,6 +12,8 @@ import { type IWatchLoopState, Operation, OperationExecutionManager, + OperationGroupRecord, + type OperationRequestRunCallback, OperationStatus, WatchLoop } from '@rushstack/operation-graph'; @@ -28,7 +30,7 @@ import type { MetricsCollector } from '../metrics/MetricsCollector'; import { HeftParameterManager } from '../pluginFramework/HeftParameterManager'; import { TaskOperationRunner } from '../operations/runners/TaskOperationRunner'; import { PhaseOperationRunner } from '../operations/runners/PhaseOperationRunner'; -import type { HeftPhase } from '../pluginFramework/HeftPhase'; +import type { IHeftPhase, HeftPhase } from '../pluginFramework/HeftPhase'; import type { IHeftAction, IHeftActionOptions } from './actions/IHeftAction'; import type { IHeftLifecycleCleanHookOptions, @@ -37,7 +39,7 @@ import type { IHeftLifecycleToolStartHookOptions } from '../pluginFramework/HeftLifecycleSession'; import type { HeftLifecycle } from '../pluginFramework/HeftLifecycle'; -import type { HeftTask } from '../pluginFramework/HeftTask'; +import type { IHeftTask, HeftTask } from '../pluginFramework/HeftTask'; import { deleteFilesAsync, type IDeleteOperation } from '../plugins/DeleteFilesPlugin'; import { Constants } from '../utilities/Constants'; @@ -45,6 +47,23 @@ export interface IHeftActionRunnerOptions extends IHeftActionOptions { action: IHeftAction; } +/** + * Metadata for an operation that represents a task. + * @public + */ +export interface IHeftTaskOperationMetadata { + task: IHeftTask; + phase: IHeftPhase; +} + +/** + * Metadata for an operation that represents a phase. + * @public + */ +export interface IHeftPhaseOperationMetadata { + phase: IHeftPhase; +} + export function initializeHeft( heftConfiguration: HeftConfiguration, terminal: ITerminal, @@ -291,9 +310,13 @@ export class HeftActionRunner { initializeHeft(this._heftConfiguration, terminal, this.parameterManager.defaultParameters.verbose); - const operations: ReadonlySet = this._generateOperations(); + const operations: ReadonlySet> = + this._generateOperations(); - const executionManager: OperationExecutionManager = new OperationExecutionManager(operations); + const executionManager: OperationExecutionManager< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = new OperationExecutionManager(operations); const cliAbortSignal: AbortSignal = ensureCliAbortSignal(this._terminal); @@ -346,20 +369,52 @@ export class HeftActionRunner { } private async _executeOnceAsync( - executionManager: OperationExecutionManager, + executionManager: OperationExecutionManager, abortSignal: AbortSignal, - requestRun?: (requestor?: string) => void + requestRun?: OperationRequestRunCallback ): Promise { + const { taskStart, taskFinish, phaseStart, phaseFinish } = this._internalHeftSession.lifecycle.hooks; // Record this as the start of task execution. this._metricsCollector.setStartTime(); // Execute the action operations return await runWithLoggingAsync( () => { - const operationExecutionManagerOptions: IOperationExecutionOptions = { + const operationExecutionManagerOptions: IOperationExecutionOptions< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = { terminal: this._terminal, parallelism: this._parallelism, abortSignal, - requestRun + requestRun, + beforeExecuteOperation( + operation: Operation + ): void { + if (taskStart.isUsed()) { + taskStart.call({ operation }); + } + }, + afterExecuteOperation( + operation: Operation + ): void { + if (taskFinish.isUsed()) { + taskFinish.call({ operation }); + } + }, + beforeExecuteOperationGroup( + operationGroup: OperationGroupRecord + ): void { + if (operationGroup.metadata.phase && phaseStart.isUsed()) { + phaseStart.call({ operation: operationGroup }); + } + }, + afterExecuteOperationGroup( + operationGroup: OperationGroupRecord + ): void { + if (operationGroup.metadata.phase && phaseFinish.isUsed()) { + phaseFinish.call({ operation: operationGroup }); + } + } }; return executionManager.executeAsync(operationExecutionManagerOptions); @@ -373,10 +428,14 @@ export class HeftActionRunner { ); } - private _generateOperations(): Set { + private _generateOperations(): Set> { const { selectedPhases } = this._action; - const operations: Map = new Map(); + const operations: Map< + string, + Operation + > = new Map(); + const operationGroups: Map> = new Map(); const internalHeftSession: InternalHeftSession = this._internalHeftSession; let hasWarnedAboutSkippedPhases: boolean = false; @@ -399,18 +458,28 @@ export class HeftActionRunner { } // Create operation for the phase start node - const phaseOperation: Operation = _getOrCreatePhaseOperation(internalHeftSession, phase, operations); + const phaseOperation: Operation = _getOrCreatePhaseOperation( + internalHeftSession, + phase, + operations, + operationGroups + ); // Create operations for each task for (const task of phase.tasks) { - const taskOperation: Operation = _getOrCreateTaskOperation(internalHeftSession, task, operations); + const taskOperation: Operation = _getOrCreateTaskOperation( + internalHeftSession, + task, + operations, + operationGroups + ); // Set the phase operation as a dependency of the task operation to ensure the phase operation runs first taskOperation.addDependency(phaseOperation); // Set all dependency tasks as dependencies of the task operation for (const dependencyTask of task.dependencyTasks) { taskOperation.addDependency( - _getOrCreateTaskOperation(internalHeftSession, dependencyTask, operations) + _getOrCreateTaskOperation(internalHeftSession, dependencyTask, operations, operationGroups) ); } @@ -422,7 +491,8 @@ export class HeftActionRunner { const consumingPhaseOperation: Operation = _getOrCreatePhaseOperation( internalHeftSession, consumingPhase, - operations + operations, + operationGroups ); consumingPhaseOperation.addDependency(taskOperation); // This is purely to simplify the reported graph for phase circularities @@ -440,15 +510,24 @@ function _getOrCreatePhaseOperation( this: void, internalHeftSession: InternalHeftSession, phase: HeftPhase, - operations: Map + operations: Map, + operationGroups: Map> ): Operation { const key: string = phase.phaseName; let operation: Operation | undefined = operations.get(key); if (!operation) { + let group: OperationGroupRecord | undefined = operationGroups.get( + phase.phaseName + ); + if (!group) { + group = new OperationGroupRecord(phase.phaseName, { phase }); + operationGroups.set(phase.phaseName, group); + } // Only create the operation. Dependencies are hooked up separately operation = new Operation({ - groupName: phase.phaseName, + group, + name: phase.phaseName, runner: new PhaseOperationRunner({ phase, internalHeftSession }) }); operations.set(key, operation); @@ -460,18 +539,31 @@ function _getOrCreateTaskOperation( this: void, internalHeftSession: InternalHeftSession, task: HeftTask, - operations: Map + operations: Map, + operationGroups: Map> ): Operation { const key: string = `${task.parentPhase.phaseName}.${task.taskName}`; - let operation: Operation | undefined = operations.get(key); + let operation: Operation | undefined = operations.get( + key + ) as Operation; if (!operation) { + const group: OperationGroupRecord | undefined = operationGroups.get( + task.parentPhase.phaseName + ); + if (!group) { + throw new InternalError( + `Task ${task.taskName} in phase ${task.parentPhase.phaseName} has no group. This should not happen.` + ); + } operation = new Operation({ - groupName: task.parentPhase.phaseName, + group, runner: new TaskOperationRunner({ internalHeftSession, task - }) + }), + name: task.taskName, + metadata: { task, phase: task.parentPhase } }); operations.set(key, operation); } diff --git a/apps/heft/src/cli/HeftCommandLineParser.ts b/apps/heft/src/cli/HeftCommandLineParser.ts index ea96af713e4..67389a7d053 100644 --- a/apps/heft/src/cli/HeftCommandLineParser.ts +++ b/apps/heft/src/cli/HeftCommandLineParser.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import os from 'node:os'; + import { CommandLineParser, type AliasCommandLineAction, diff --git a/apps/heft/src/cli/actions/PhaseAction.ts b/apps/heft/src/cli/actions/PhaseAction.ts index b3891514529..f1f4643af3a 100644 --- a/apps/heft/src/cli/actions/PhaseAction.ts +++ b/apps/heft/src/cli/actions/PhaseAction.ts @@ -20,19 +20,21 @@ export class PhaseAction extends CommandLineAction implements IHeftAction { private _selectedPhases: Set | undefined; public constructor(options: IPhaseActionOptions) { + const { phase, watch = false } = options; + const { phaseName, phaseDescription } = phase; super({ - actionName: `${options.phase.phaseName}${options.watch ? '-watch' : ''}`, + actionName: `${phaseName}${watch ? '-watch' : ''}`, documentation: - `Runs to the ${options.phase.phaseName} phase, including all transitive dependencies` + - (options.watch ? ', in watch mode.' : '.') + - (options.phase.phaseDescription ? ` ${options.phase.phaseDescription}` : ''), + `Runs to the ${phaseName} phase, including all transitive dependencies` + + (watch ? ', in watch mode.' : '.') + + (phaseDescription ? ` ${phaseDescription}` : ''), summary: - `Runs to the ${options.phase.phaseName} phase, including all transitive dependencies` + - (options.watch ? ', in watch mode.' : '.') + `Runs to the ${phaseName} phase, including all transitive dependencies` + + (watch ? ', in watch mode.' : '.') }); - this.watch = options.watch ?? false; - this._phase = options.phase; + this.watch = watch; + this._phase = phase; this._actionRunner = new HeftActionRunner({ action: this, ...options }); this._actionRunner.defineParameters(); } diff --git a/apps/heft/src/configuration/HeftConfiguration.ts b/apps/heft/src/configuration/HeftConfiguration.ts index 6177278e7c4..e6079a8a3f6 100644 --- a/apps/heft/src/configuration/HeftConfiguration.ts +++ b/apps/heft/src/configuration/HeftConfiguration.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { type IPackageJson, PackageJsonLookup, InternalError, Path } from '@rushstack/node-core-library'; import { Terminal, type ITerminalProvider, type ITerminal } from '@rushstack/terminal'; import { diff --git a/apps/heft/src/configuration/HeftPluginDefinition.ts b/apps/heft/src/configuration/HeftPluginDefinition.ts index 21de40a5cb3..4ce4bd0c19a 100644 --- a/apps/heft/src/configuration/HeftPluginDefinition.ts +++ b/apps/heft/src/configuration/HeftPluginDefinition.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { InternalError, JsonSchema } from '@rushstack/node-core-library'; import type { IHeftPlugin } from '../pluginFramework/IHeftPlugin'; diff --git a/apps/heft/src/configuration/RigPackageResolver.ts b/apps/heft/src/configuration/RigPackageResolver.ts index bd40e3937e2..03a70db6dc4 100644 --- a/apps/heft/src/configuration/RigPackageResolver.ts +++ b/apps/heft/src/configuration/RigPackageResolver.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { PackageJsonLookup, Import, diff --git a/apps/heft/src/index.ts b/apps/heft/src/index.ts index 68d77c23d1d..0c6006dfc8c 100644 --- a/apps/heft/src/index.ts +++ b/apps/heft/src/index.ts @@ -30,7 +30,11 @@ export type { IHeftLifecycleHooks, IHeftLifecycleCleanHookOptions, IHeftLifecycleToolStartHookOptions, - IHeftLifecycleToolFinishHookOptions + IHeftLifecycleToolFinishHookOptions, + IHeftTaskStartHookOptions, + IHeftTaskFinishHookOptions, + IHeftPhaseStartHookOptions, + IHeftPhaseFinishHookOptions } from './pluginFramework/HeftLifecycleSession'; export type { @@ -79,3 +83,9 @@ export type { CommandLineStringListParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; + +export type { IHeftTaskOperationMetadata } from './cli/HeftActionRunner'; +export type { IHeftPhaseOperationMetadata } from './cli/HeftActionRunner'; + +export type { IHeftTask } from './pluginFramework/HeftTask'; +export type { IHeftPhase } from './pluginFramework/HeftPhase'; diff --git a/apps/heft/src/legacy-compatibility/start.js b/apps/heft/src/legacy-compatibility/start.js new file mode 100644 index 00000000000..5a4723e7d2e --- /dev/null +++ b/apps/heft/src/legacy-compatibility/start.js @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This file is specifically included for compatibility with older global installations of Heft. +require('../lib-commonjs/start.js'); diff --git a/apps/heft/src/metrics/MetricsCollector.ts b/apps/heft/src/metrics/MetricsCollector.ts index 82b70abf685..b7f6352387d 100644 --- a/apps/heft/src/metrics/MetricsCollector.ts +++ b/apps/heft/src/metrics/MetricsCollector.ts @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; +import { performance } from 'node:perf_hooks'; + import { AsyncParallelHook } from 'tapable'; -import { performance } from 'perf_hooks'; + import { InternalError } from '@rushstack/node-core-library'; /** diff --git a/apps/heft/src/operations/runners/TaskOperationRunner.ts b/apps/heft/src/operations/runners/TaskOperationRunner.ts index 995d10ffbed..5cdd397d9b4 100644 --- a/apps/heft/src/operations/runners/TaskOperationRunner.ts +++ b/apps/heft/src/operations/runners/TaskOperationRunner.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { createHash, type Hash } from 'node:crypto'; + import { glob } from 'fast-glob'; import { @@ -9,7 +10,6 @@ import { type IOperationRunnerContext, OperationStatus } from '@rushstack/operation-graph'; - import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; import type { HeftTask } from '../../pluginFramework/HeftTask'; diff --git a/apps/heft/src/pluginFramework/HeftLifecycle.ts b/apps/heft/src/pluginFramework/HeftLifecycle.ts index 95fc7ee3fb5..b762e23f238 100644 --- a/apps/heft/src/pluginFramework/HeftLifecycle.ts +++ b/apps/heft/src/pluginFramework/HeftLifecycle.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { AsyncParallelHook } from 'tapable'; +import { AsyncParallelHook, SyncHook } from 'tapable'; + import { InternalError } from '@rushstack/node-core-library'; import { HeftPluginConfiguration } from '../configuration/HeftPluginConfiguration'; @@ -19,7 +20,11 @@ import { type IHeftLifecycleHooks, type IHeftLifecycleToolStartHookOptions, type IHeftLifecycleToolFinishHookOptions, - type IHeftLifecycleSession + type IHeftLifecycleSession, + type IHeftTaskStartHookOptions, + type IHeftTaskFinishHookOptions, + type IHeftPhaseStartHookOptions, + type IHeftPhaseFinishHookOptions } from './HeftLifecycleSession'; import type { ScopedLogger } from './logging/ScopedLogger'; @@ -67,7 +72,11 @@ export class HeftLifecycle extends HeftPluginHost { clean: new AsyncParallelHook(), toolStart: new AsyncParallelHook(), toolFinish: new AsyncParallelHook(), - recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook + recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook, + taskStart: new SyncHook(['task']), + taskFinish: new SyncHook(['task']), + phaseStart: new SyncHook(['phase']), + phaseFinish: new SyncHook(['phase']) }; } diff --git a/apps/heft/src/pluginFramework/HeftLifecycleSession.ts b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts index 1105608446e..92d30a13fac 100644 --- a/apps/heft/src/pluginFramework/HeftLifecycleSession.ts +++ b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type { AsyncParallelHook } from 'tapable'; +import * as path from 'node:path'; + +import type { AsyncParallelHook, SyncHook } from 'tapable'; + +import type { Operation, OperationGroupRecord } from '@rushstack/operation-graph'; import type { IHeftRecordMetricsHookOptions, MetricsCollector } from '../metrics/MetricsCollector'; import type { ScopedLogger, IScopedLogger } from './logging/ScopedLogger'; @@ -11,6 +14,7 @@ import type { IHeftParameters } from './HeftParameterManager'; import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; import type { HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; import type { HeftPluginHost } from './HeftPluginHost'; +import type { IHeftPhaseOperationMetadata, IHeftTaskOperationMetadata } from '../cli/HeftActionRunner'; /** * The lifecycle session is responsible for providing session-specific information to Heft lifecycle @@ -67,6 +71,34 @@ export interface IHeftLifecycleSession { ): void; } +/** + * @public + */ +export interface IHeftTaskStartHookOptions { + operation: Operation; +} + +/** + * @public + */ +export interface IHeftTaskFinishHookOptions { + operation: Operation; +} + +/** + * @public + */ +export interface IHeftPhaseStartHookOptions { + operation: OperationGroupRecord; +} + +/** + * @public + */ +export interface IHeftPhaseFinishHookOptions { + operation: OperationGroupRecord; +} + /** * Hooks that are available to the lifecycle plugin. * @@ -111,6 +143,38 @@ export interface IHeftLifecycleHooks { * @public */ recordMetrics: AsyncParallelHook; + + /** + * The `taskStart` hook is called at the beginning of a task. It is called before the task has begun + * to execute. To use it, call `taskStart.tap(, )`. + * + * @public + */ + taskStart: SyncHook; + + /** + * The `taskFinish` hook is called at the end of a task. It is called after the task has completed + * execution. To use it, call `taskFinish.tap(, )`. + * + * @public + */ + taskFinish: SyncHook; + + /** + * The `phaseStart` hook is called at the beginning of a phase. It is called before the phase has + * begun to execute. To use it, call `phaseStart.tap(, )`. + * + * @public + */ + phaseStart: SyncHook; + + /** + * The `phaseFinish` hook is called at the end of a phase. It is called after the phase has completed + * execution. To use it, call `phaseFinish.tap(, )`. + * + * @public + */ + phaseFinish: SyncHook; } /** @@ -166,20 +230,22 @@ export class HeftLifecycleSession implements IHeftLifecycleSession { public constructor(options: IHeftLifecycleSessionOptions) { this._options = options; - this.logger = options.logger; - this.metricsCollector = options.metricsCollector; - this.hooks = options.lifecycleHooks; - this.parameters = options.lifecycleParameters; - this.debug = options.debug; + const { logger, metricsCollector, lifecycleHooks, lifecycleParameters, debug, pluginDefinition, heftConfiguration, pluginHost } = + options; + this.logger = logger; + this.metricsCollector = metricsCollector; + this.hooks = lifecycleHooks; + this.parameters = lifecycleParameters; + this.debug = debug; // Guranteed to be unique since phases are forbidden from using the name 'lifecycle' // and lifecycle plugin names are enforced to be unique. - const uniquePluginFolderName: string = `lifecycle.${options.pluginDefinition.pluginName}`; + const uniquePluginFolderName: string = `lifecycle.${pluginDefinition.pluginName}`; // /temp/. - this.tempFolderPath = path.join(options.heftConfiguration.tempFolderPath, uniquePluginFolderName); + this.tempFolderPath = path.join(heftConfiguration.tempFolderPath, uniquePluginFolderName); - this._pluginHost = options.pluginHost; + this._pluginHost = pluginHost; } public requestAccessToPluginByName( diff --git a/apps/heft/src/pluginFramework/HeftPhase.ts b/apps/heft/src/pluginFramework/HeftPhase.ts index 1a6de503ef9..e7ac8e65ca6 100644 --- a/apps/heft/src/pluginFramework/HeftPhase.ts +++ b/apps/heft/src/pluginFramework/HeftPhase.ts @@ -1,14 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { HeftTask } from './HeftTask'; +import { HeftTask, type IHeftTask } from './HeftTask'; import type { InternalHeftSession } from './InternalHeftSession'; import type { IHeftConfigurationJsonPhaseSpecifier } from '../utilities/CoreConfigFiles'; import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; const RESERVED_PHASE_NAMES: Set = new Set(['lifecycle']); -export class HeftPhase { +/** + * @public + */ +export interface IHeftPhase { + readonly phaseName: string; + readonly phaseDescription: string | undefined; + cleanFiles: ReadonlySet; + consumingPhases: ReadonlySet; + dependencyPhases: ReadonlySet; + tasks: ReadonlySet; + tasksByName: ReadonlyMap; +} + +/** + * @internal + */ +export class HeftPhase implements IHeftPhase { private _internalHeftSession: InternalHeftSession; private _phaseName: string; private _phaseSpecifier: IHeftConfigurationJsonPhaseSpecifier; diff --git a/apps/heft/src/pluginFramework/HeftPluginHost.ts b/apps/heft/src/pluginFramework/HeftPluginHost.ts index a6dc607feb1..9f3dad8edcc 100644 --- a/apps/heft/src/pluginFramework/HeftPluginHost.ts +++ b/apps/heft/src/pluginFramework/HeftPluginHost.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { SyncHook } from 'tapable'; + import { InternalError } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; diff --git a/apps/heft/src/pluginFramework/HeftTask.ts b/apps/heft/src/pluginFramework/HeftTask.ts index b7b8c539126..d5f098bd1d8 100644 --- a/apps/heft/src/pluginFramework/HeftTask.ts +++ b/apps/heft/src/pluginFramework/HeftTask.ts @@ -8,7 +8,7 @@ import type { HeftTaskPluginDefinition, HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; -import type { HeftPhase } from './HeftPhase'; +import type { HeftPhase, IHeftPhase } from './HeftPhase'; import type { IHeftConfigurationJsonTaskSpecifier, IHeftConfigurationJsonPluginSpecifier @@ -18,10 +18,20 @@ import type { IScopedLogger } from './logging/ScopedLogger'; const RESERVED_TASK_NAMES: Set = new Set(['clean']); +/** + * @public + */ +export interface IHeftTask { + readonly parentPhase: IHeftPhase; + readonly taskName: string; + readonly consumingTasks: ReadonlySet; + readonly dependencyTasks: ReadonlySet; +} + /** * @internal */ -export class HeftTask { +export class HeftTask implements IHeftTask { private _parentPhase: HeftPhase; private _taskName: string; private _taskSpecifier: IHeftConfigurationJsonTaskSpecifier; diff --git a/apps/heft/src/pluginFramework/HeftTaskSession.ts b/apps/heft/src/pluginFramework/HeftTaskSession.ts index 152e6967b9b..9898b11a492 100644 --- a/apps/heft/src/pluginFramework/HeftTaskSession.ts +++ b/apps/heft/src/pluginFramework/HeftTaskSession.ts @@ -3,6 +3,8 @@ import { AsyncParallelHook, AsyncSeriesWaterfallHook } from 'tapable'; +import { InternalError } from '@rushstack/node-core-library'; + import type { MetricsCollector } from '../metrics/MetricsCollector'; import type { IScopedLogger } from './logging/ScopedLogger'; import type { HeftTask } from './HeftTask'; @@ -12,7 +14,6 @@ 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 { InternalError } from '@rushstack/node-core-library'; import type { IWatchFileSystem } from '../utilities/WatchFileSystemAdapter'; /** diff --git a/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts index 56eb74ed6b9..3c30d07cec5 100644 --- a/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts +++ b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem, Path } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts index 7d62f0ad803..89129078af2 100644 --- a/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts +++ b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; -import * as path from 'path'; +import type * as fs from 'node:fs'; +import * as path from 'node:path'; + import type { FileSystemAdapter } from 'fast-glob'; + import { Path } from '@rushstack/node-core-library'; interface IVirtualFileSystemEntry { @@ -45,7 +47,7 @@ export class StaticFileSystemAdapter implements FileSystemAdapter { callback(e, {} as fs.Stats); return; } - // eslint-disable-next-line @rushstack/no-new-null + callback(null, result); }); }) as FileSystemAdapter['lstat']; @@ -115,10 +117,8 @@ export class StaticFileSystemAdapter implements FileSystemAdapter { // When "withFileTypes" is false or undefined, the callback is expected to return a string array. // Otherwise, we return a fs.Dirent array. if (options?.withFileTypes) { - // eslint-disable-next-line @rushstack/no-new-null (callback as ReaddirDirentCallback)(null, result as fs.Dirent[]); } else { - // eslint-disable-next-line @rushstack/no-new-null (callback as ReaddirStringCallback)(null, result as string[]); } }); diff --git a/apps/heft/src/pluginFramework/logging/LoggingManager.ts b/apps/heft/src/pluginFramework/logging/LoggingManager.ts index c3601902870..36c243a8084 100644 --- a/apps/heft/src/pluginFramework/logging/LoggingManager.ts +++ b/apps/heft/src/pluginFramework/logging/LoggingManager.ts @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { ScopedLogger } from './ScopedLogger'; import { FileError, type FileLocationStyle, type IFileErrorFormattingOptions } from '@rushstack/node-core-library'; import type { ITerminalProvider } from '@rushstack/terminal'; + +import { ScopedLogger } from './ScopedLogger'; export interface ILoggingManagerOptions { terminalProvider: ITerminalProvider; } diff --git a/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts index e2921fb22e3..0a5d3be7f65 100644 --- a/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts +++ b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; import { Path } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap index 390725566a9..1803097905b 100644 --- a/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap +++ b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`serializeBuildInfo Has expected serialized format: posix 1`] = ` Object { diff --git a/apps/heft/src/plugins/DeleteFilesPlugin.ts b/apps/heft/src/plugins/DeleteFilesPlugin.ts index e85047a6597..73976dad8f4 100644 --- a/apps/heft/src/plugins/DeleteFilesPlugin.ts +++ b/apps/heft/src/plugins/DeleteFilesPlugin.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; +import type * as fs from 'node:fs'; + import { FileSystem, Async } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; diff --git a/apps/heft/src/plugins/FileGlobSpecifier.ts b/apps/heft/src/plugins/FileGlobSpecifier.ts index 8f147cb148b..96d3223dd5a 100644 --- a/apps/heft/src/plugins/FileGlobSpecifier.ts +++ b/apps/heft/src/plugins/FileGlobSpecifier.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; -import * as path from 'path'; +import type * as fs from 'node:fs'; +import * as path from 'node:path'; + import glob, { type FileSystemAdapter, type Entry } from 'fast-glob'; import { Async } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/plugins/NodeServicePlugin.ts b/apps/heft/src/plugins/NodeServicePlugin.ts index 86a954a747b..dfb8e42760f 100644 --- a/apps/heft/src/plugins/NodeServicePlugin.ts +++ b/apps/heft/src/plugins/NodeServicePlugin.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as child_process from 'child_process'; -import * as process from 'process'; +import * as child_process from 'node:child_process'; +import * as process from 'node:process'; + import { InternalError, SubprocessTerminator } from '@rushstack/node-core-library'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; diff --git a/apps/heft/src/plugins/RunScriptPlugin.ts b/apps/heft/src/plugins/RunScriptPlugin.ts index 62188ec1134..6c74d9dfd56 100644 --- a/apps/heft/src/plugins/RunScriptPlugin.ts +++ b/apps/heft/src/plugins/RunScriptPlugin.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type { HeftConfiguration } from '../configuration/HeftConfiguration'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; import type { IHeftTaskSession, IHeftTaskRunHookOptions } from '../pluginFramework/HeftTaskSession'; diff --git a/apps/heft/src/start.ts b/apps/heft/src/start.ts index b6c5f1e9391..0fa5a60c557 100644 --- a/apps/heft/src/start.ts +++ b/apps/heft/src/start.ts @@ -3,7 +3,7 @@ import { HeftCommandLineParser } from './cli/HeftCommandLineParser'; -// Launching via lib/start.js bypasses the version selector. Use that for debugging Heft. +// Launching via lib-commonjs/start.js bypasses the version selector. Use that for debugging Heft. const parser: HeftCommandLineParser = new HeftCommandLineParser(); diff --git a/apps/heft/src/startWithVersionSelector.ts b/apps/heft/src/startWithVersionSelector.ts index d78da294bbe..e9cc3b950f6 100644 --- a/apps/heft/src/startWithVersionSelector.ts +++ b/apps/heft/src/startWithVersionSelector.ts @@ -5,9 +5,11 @@ // NOTE: Since startWithVersionSelector.ts is loaded in the same process as start.ts, any dependencies that // we import here may become side-by-side versions. We want to minimize any dependencies. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; + import type { IPackageJson } from '@rushstack/node-core-library'; + import { getToolParameterNamesFromArgs } from './utilities/CliUtilities'; import { Constants } from './utilities/Constants'; @@ -91,9 +93,19 @@ function tryStartLocalHeft(): boolean { // installed as "/node_modules/@rushstack/heft". const heftFolder: string = path.join(projectFolder, 'node_modules', Constants.heftPackageName); - heftEntryPoint = path.join(heftFolder, 'lib', 'start.js'); - if (!fs.existsSync(heftEntryPoint)) { - throw new Error('Unable to find Heft entry point: ' + heftEntryPoint); + // Try the new output layout first, then fall back to the legacy layout + const commonJsHeftEntryPoint: string = path.join(heftFolder, 'lib-commonjs', 'start.js'); + if (!fs.existsSync(commonJsHeftEntryPoint)) { + const legacyHeftEntryPoint: string = path.join(heftFolder, 'lib', 'start.js'); + if (!fs.existsSync(legacyHeftEntryPoint)) { + throw new Error( + `Unable to find Heft entry point: ${commonJsHeftEntryPoint} or ${legacyHeftEntryPoint}` + ); + } else { + heftEntryPoint = legacyHeftEntryPoint; + } + } else { + heftEntryPoint = commonJsHeftEntryPoint; } } catch (error) { throw new Error('Error probing for local Heft version: ' + (error as Error).message); diff --git a/apps/heft/src/utilities/CoreConfigFiles.ts b/apps/heft/src/utilities/CoreConfigFiles.ts index 8ca28874cae..3ad45c6fda9 100644 --- a/apps/heft/src/utilities/CoreConfigFiles.ts +++ b/apps/heft/src/utilities/CoreConfigFiles.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { ProjectConfigurationFile, InheritanceType, diff --git a/apps/heft/src/utilities/GitUtilities.ts b/apps/heft/src/utilities/GitUtilities.ts index 937beddd5db..a0f918b1242 100644 --- a/apps/heft/src/utilities/GitUtilities.ts +++ b/apps/heft/src/utilities/GitUtilities.ts @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type { ChildProcess, SpawnSyncReturns } from 'child_process'; +import * as path from 'node:path'; +import type { ChildProcess, SpawnSyncReturns } from 'node:child_process'; + import { default as getGitRepoInfo, type GitRepoInfo as IGitRepoInfo } from 'git-repo-info'; -import { Executable, FileSystem, InternalError, Path, Text } from '@rushstack/node-core-library'; import { default as ignore, type Ignore as IIgnoreMatcher } from 'ignore'; -// Matches lines starting with "#" and whitepace lines +import { Executable, FileSystem, InternalError, Path, Text } from '@rushstack/node-core-library'; + +// Matches lines starting with "#" and whitespace lines const GITIGNORE_IGNORABLE_LINE_REGEX: RegExp = /^(?:(?:#.*)|(?:\s+))$/; const UNINITIALIZED: 'UNINITIALIZED' = 'UNINITIALIZED'; diff --git a/apps/heft/src/utilities/WatchFileSystemAdapter.ts b/apps/heft/src/utilities/WatchFileSystemAdapter.ts index 0380c6db56a..97c1ae5bdd3 100644 --- a/apps/heft/src/utilities/WatchFileSystemAdapter.ts +++ b/apps/heft/src/utilities/WatchFileSystemAdapter.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import Watchpack from 'watchpack'; diff --git a/apps/heft/src/utilities/test/GitUtilities.test.ts b/apps/heft/src/utilities/test/GitUtilities.test.ts index 100156c3590..9b51b6d1f1d 100644 --- a/apps/heft/src/utilities/test/GitUtilities.test.ts +++ b/apps/heft/src/utilities/test/GitUtilities.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { GitUtilities, type GitignoreFilterFn } from '../GitUtilities'; import { PackageJsonLookup } from '@rushstack/node-core-library'; diff --git a/apps/lockfile-explorer-web/.eslintrc.js b/apps/lockfile-explorer-web/.eslintrc.js deleted file mode 100644 index cf9ccc5e37e..00000000000 --- a/apps/lockfile-explorer-web/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-web-rig/profiles/app/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-web-rig/profiles/app/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-web-rig/profiles/app/includes/eslint/profile/web-app', - 'local-web-rig/profiles/app/includes/eslint/mixins/react' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/apps/lockfile-explorer-web/eslint.config.js b/apps/lockfile-explorer-web/eslint.config.js new file mode 100644 index 00000000000..9765c392aa3 --- /dev/null +++ b/apps/lockfile-explorer-web/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-web-rig/profiles/app/includes/eslint/flat/profile/web-app'); +const reactMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/react'); +const packletsMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + packletsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/lockfile-explorer-web/package.json b/apps/lockfile-explorer-web/package.json index 58198d94123..bb22f5bd43f 100644 --- a/apps/lockfile-explorer-web/package.json +++ b/apps/lockfile-explorer-web/package.json @@ -12,18 +12,22 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "react": "~17.0.2", - "react-dom": "~17.0.2", - "@lifaon/path": "~2.1.0", - "@reduxjs/toolkit": "~1.8.6", - "react-redux": "~8.0.4", - "redux": "~4.2.0", - "@rushstack/rush-themed-ui": "workspace:*" + "@reduxjs/toolkit": "~2.11.2", + "@rushstack/rush-themed-ui": "workspace:*", + "prism-react-renderer": "~2.4.1", + "react-dom": "~19.2.3", + "react-redux": "~9.2.0", + "react": "~19.2.3", + "redux": "~5.0.1", + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "local-web-rig": "workspace:*" - } + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*", + "typescript": "5.8.2" + }, + "sideEffects": false } diff --git a/apps/lockfile-explorer-web/src/App.tsx b/apps/lockfile-explorer-web/src/App.tsx index a83f7831908..243b65c52db 100644 --- a/apps/lockfile-explorer-web/src/App.tsx +++ b/apps/lockfile-explorer-web/src/App.tsx @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import React, { useEffect } from 'react'; + import styles from './App.scss'; import { readLockfileAsync } from './parsing/readLockfile'; import { LockfileViewer } from './containers/LockfileViewer'; @@ -17,7 +18,7 @@ import { ConnectionModal } from './components/ConnectionModal'; /** * This React component renders the application page. */ -export const App = (): JSX.Element => { +export const App = (): React.ReactElement => { const dispatch = useAppDispatch(); useEffect(() => { diff --git a/apps/lockfile-explorer-web/src/AppContext.ts b/apps/lockfile-explorer-web/src/AppContext.ts deleted file mode 100644 index 098a8432e53..00000000000 --- a/apps/lockfile-explorer-web/src/AppContext.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Describes the `window.appContext` object that the Node.js service uses - * to communicate runtime configuration to the web app. - * - * @remarks - * The `dist/index.html` page loads a script `initappcontext.js` to initialize - * this object before the web app starts. - * - * When the app is hosted by Webpack dev server, this is implemented by - * `lockfile-explorer-web/src/stub/initappcontext.ts`. - * - * When the app is hosted by the CLI front end, the `initappcontext.js` content - * is generated by an Express route. - */ -export interface IAppContext { - /** - * The service URL, without the trailing slash. - * - * @example - * Example: `http://localhost:8091` - */ - serviceUrl: string; - - /** - * The `package.json` version for the app. - */ - appVersion: string; - - /** - * Whether the CLI was invoked with the `--debug` parameter. - */ - debugMode: boolean; -} - -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - appContext: IAppContext; - } -} diff --git a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx index d7e1d963bdf..afc205df90d 100644 --- a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx +++ b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx @@ -2,13 +2,15 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; + import { Button, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { checkAliveAsync } from '../../parsing/getPackageFiles'; +import { checkAliveAsync } from '../../helpers/lfxApiClient'; import type { ReactNull } from '../../types/ReactNull'; -export const ConnectionModal = (): JSX.Element | ReactNull => { +export const ConnectionModal = (): React.ReactElement | ReactNull => { const [isAlive, setIsAlive] = useState(true); const [checking, setChecking] = useState(false); const [manualChecked, setManualChecked] = useState(false); diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx index 28a2ac8eaff..79e7bd3a3fc 100644 --- a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx @@ -2,25 +2,27 @@ // See LICENSE in the project root for license information. import React, { useCallback } from 'react'; + +import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import appStyles from '../../App.scss'; import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; +import type { LfxGraphEntry } from '../../packlets/lfx-shared'; import { clearStackAndPush, removeBookmark } from '../../store/slices/entrySlice'; -import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; -export const BookmarksSidebar = (): JSX.Element => { +export const BookmarksSidebar = (): React.ReactElement => { const bookmarks = useAppSelector((state) => state.entry.bookmarkedEntries); const dispatch = useAppDispatch(); const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(clearStackAndPush(entry)); }, [dispatch] ); const deleteEntry = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(removeBookmark(entry)); }, [dispatch] diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx index 277edde9e61..66bc2f2fc03 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx @@ -2,15 +2,16 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; + import { ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { IDependencyType, type LockfileDependency } from '../../parsing/LockfileDependency'; -import { readPackageJsonAsync } from '../../parsing/getPackageFiles'; +import { LfxDependencyKind, type LfxGraphDependency, type LfxGraphEntry } from '../../packlets/lfx-shared'; +import { readPackageJsonAsync } from '../../helpers/lfxApiClient'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { pushToStack, selectCurrentEntry } from '../../store/slices/entrySlice'; import { ReactNull } from '../../types/ReactNull'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; import { logDiagnosticInfo } from '../../helpers/logDiagnosticInfo'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -27,23 +28,23 @@ enum DependencyKey { } interface IInfluencerType { - entry: LockfileEntry; + entry: LfxGraphEntry; type: DependencyType; } -export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { +export const LockfileEntryDetailsView = (): React.ReactElement | ReactNull => { const selectedEntry = useAppSelector(selectCurrentEntry); const specChanges = useAppSelector((state) => state.workspace.specChanges); const dispatch = useAppDispatch(); - const [inspectDependency, setInspectDependency] = useState(null); + const [inspectDependency, setInspectDependency] = useState(null); const [influencers, setInfluencers] = useState([]); const [directRefsPackageJSON, setDirectRefsPackageJSON] = useState>( new Map() ); useEffect(() => { - async function loadPackageJson(referrers: LockfileEntry[]): Promise { + async function loadPackageJson(referrers: LfxGraphEntry[]): Promise { const referrersJsonMap = new Map(); await Promise.all( referrers.map(async (ref) => { @@ -66,12 +67,12 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { }, [selectedEntry]); const selectResolvedEntry = useCallback( - (dependencyToTrace) => () => { + (dependencyToTrace: LfxGraphDependency) => () => { if (inspectDependency && inspectDependency.entryId === dependencyToTrace.entryId) { if (dependencyToTrace.resolvedEntry) { dispatch(pushToStack(dependencyToTrace.resolvedEntry)); } else { - logDiagnosticInfo('No resolved entry for dependency:', dependencyToTrace); + logDiagnosticInfo('No resolved entry for dependency:', dependencyToTrace.entryId); } } else if (selectedEntry) { // eslint-disable-next-line no-console @@ -80,15 +81,15 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { // Check if we need to calculate influencers. // If the current dependencyToTrace is a peer dependency then we do - if (dependencyToTrace.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (dependencyToTrace.dependencyKind !== LfxDependencyKind.Peer) { return; } // calculate influencers const stack = [selectedEntry]; - const determinants = new Set(); - const transitiveReferrers = new Set(); - const visitedNodes = new Set(); + const determinants = new Set(); + const transitiveReferrers = new Set(); + const visitedNodes = new Set(); visitedNodes.add(selectedEntry); while (stack.length) { const currEntry = stack.pop(); @@ -152,14 +153,14 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { ); const selectResolvedReferencer = useCallback( - (referrer) => () => { + (referrer: LfxGraphEntry) => () => { dispatch(pushToStack(referrer)); }, // eslint-disable-next-line react-hooks/exhaustive-deps [selectedEntry] ); - const renderDependencyMetadata = (): JSX.Element | ReactNull => { + const renderDependencyMetadata = (): React.ReactElement | ReactNull => { if (!inspectDependency) { return ReactNull; } @@ -171,7 +172,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { Selected Dependency:{' '} - {inspectDependency.name}: {inspectDependency.version} + {inspectDependency.name}: {inspectDependency.versionPath}
@@ -179,11 +180,11 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { package.json spec:{' '} - {inspectDependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {inspectDependency.dependencyKind === LfxDependencyKind.Peer ? `"${inspectDependency.peerDependencyMeta.version}" ${ inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required' } Peer` - : inspectDependency.version} + : inspectDependency.versionPath}
@@ -201,11 +202,9 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { ); }; - const renderPeerDependencies = (): JSX.Element | ReactNull => { + const renderPeerDependencies = (): React.ReactElement | ReactNull => { if (!selectedEntry) return ReactNull; - const peerDeps = selectedEntry.dependencies.filter( - (d) => d.dependencyType === IDependencyType.PEER_DEPENDENCY - ); + const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyKind === LfxDependencyKind.Peer); if (!peerDeps.length) { return (
@@ -213,7 +212,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
); } - if (!inspectDependency || inspectDependency.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (!inspectDependency || inspectDependency.dependencyKind !== LfxDependencyKind.Peer) { return (
Select a peer dependency to view its influencers @@ -301,7 +300,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
- {selectedEntry.referrers?.map((referrer: LockfileEntry) => ( + {selectedEntry.referrers?.map((referrer: LfxGraphEntry) => (
{
- {selectedEntry.dependencies?.map((dependency: LockfileDependency) => ( + {selectedEntry.dependencies?.map((dependency: LfxGraphDependency) => (
{ > Name: {dependency.name}{' '} - {dependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {dependency.dependencyKind === LfxDependencyKind.Peer ? `${ dependency.peerDependencyMeta.optional ? '(Optional)' : '(Non-optional)' } Peer Dependency` : ''}
- Version: {dependency.version} + Version: {dependency.versionPath} Entry ID: {dependency.entryId}
diff --git a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx index 05bc7b2ce8d..6467ae37f12 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx @@ -2,8 +2,11 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useRef, useState } from 'react'; + +import { Tabs, Checkbox, ScrollArea, Input, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; -import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { type LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; import { ReactNull } from '../../types/ReactNull'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -13,20 +16,19 @@ import { setFilter as selectFilter } from '../../store/slices/entrySlice'; import { getFilterFromLocalStorage, saveFilterToLocalStorage } from '../../helpers/localStorage'; -import { Tabs, Checkbox, ScrollArea, Input, Text } from '@rushstack/rush-themed-ui'; interface ILockfileEntryGroup { entryName: string; - versions: LockfileEntry[]; + versions: LfxGraphEntry[]; } -const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element => { +const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): React.ReactElement => { const selectedEntry = useAppSelector(selectCurrentEntry); const activeFilters = useAppSelector((state) => state.entry.filters); const dispatch = useAppDispatch(); - const fieldRef = useRef() as React.MutableRefObject; + const fieldRef = useRef(null); const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(pushToStack(entry)); }, [dispatch] @@ -34,13 +36,13 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element useEffect(() => { if (selectedEntry && selectedEntry.entryPackageName === group.entryName) { - fieldRef.current.scrollIntoView({ + fieldRef.current?.scrollIntoView({ behavior: 'smooth' }); } }, [selectedEntry, group]); - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { return (
{group.versions.map((entry) => ( @@ -80,7 +82,7 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element ); }; -const multipleVersions = (entries: LockfileEntry[]): boolean => { +const multipleVersions = (entries: LfxGraphEntry[]): boolean => { const set = new Set(); for (const entry of entries) { if (set.has(entry.entryPackageVersion)) return true; @@ -89,15 +91,15 @@ const multipleVersions = (entries: LockfileEntry[]): boolean => { return false; }; -export const LockfileViewer = (): JSX.Element | ReactNull => { +export const LockfileViewer = (): React.ReactElement | ReactNull => { const dispatch = useAppDispatch(); const [projectFilter, setProjectFilter] = useState(''); const [packageFilter, setPackageFilter] = useState(''); const entries = useAppSelector(selectFilteredEntries); const activeFilters = useAppSelector((state) => state.entry.filters); const updateFilter = useCallback( - (type: LockfileEntryFilter) => (e: React.ChangeEvent) => { - if (type === LockfileEntryFilter.Project) { + (type: LfxGraphEntryKind) => (e: React.ChangeEvent) => { + if (type === LfxGraphEntryKind.Project) { setProjectFilter(e.target.value); } else { setPackageFilter(e.target.value); @@ -108,19 +110,19 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ); useEffect(() => { - setProjectFilter(getFilterFromLocalStorage(LockfileEntryFilter.Project)); - setPackageFilter(getFilterFromLocalStorage(LockfileEntryFilter.Package)); + setProjectFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Project)); + setPackageFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Package)); }, []); const getEntriesToShow = (): ILockfileEntryGroup[] => { - let filteredEntries: LockfileEntry[] = entries; - if (projectFilter && activeFilters[LockfileEntryFilter.Project]) { + let filteredEntries: LfxGraphEntry[] = entries; + if (projectFilter && activeFilters[LfxGraphEntryKind.Project]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(projectFilter) !== -1); - } else if (packageFilter && activeFilters[LockfileEntryFilter.Package]) { + } else if (packageFilter && activeFilters[LfxGraphEntryKind.Package]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(packageFilter) !== -1); } - const reducedEntries = filteredEntries.reduce((groups: { [key in string]: LockfileEntry[] }, item) => { + const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LfxGraphEntry[] }, item) => { const group = groups[item.entryPackageName] || []; group.push(item); groups[item.entryPackageName] = group; @@ -134,14 +136,14 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }); } - if (activeFilters[LockfileEntryFilter.SideBySide]) { + if (activeFilters[LfxGraphEntryKind.SideBySide]) { groupedEntries = groupedEntries.filter((entry) => entry.versions.length > 1); } - if (activeFilters[LockfileEntryFilter.Doppelganger]) { + if (activeFilters[LfxGraphEntryKind.Doppelganger]) { groupedEntries = groupedEntries.filter((entry) => multipleVersions(entry.versions)); } - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { groupedEntries = groupedEntries.sort((a, b) => a.entryName > b.entryName ? 1 : b.entryName > a.entryName ? -1 : 0 ); @@ -151,7 +153,7 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }; const changeFilter = useCallback( - (filter: LockfileEntryFilter, enabled: boolean) => (): void => { + (filter: LfxGraphEntryKind, enabled: boolean) => (): void => { dispatch(selectFilter({ filter, state: enabled })); }, [dispatch] @@ -160,11 +162,11 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { const togglePackageView = useCallback( (selected: string) => { if (selected === 'Projects') { - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: false })); } else { - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: false })); } }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -186,17 +188,15 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { header: 'Packages' } ]} - value={activeFilters[LockfileEntryFilter.Project] ? 'Projects' : 'Packages'} + value={activeFilters[LfxGraphEntryKind.Project] ? 'Projects' : 'Packages'} onChange={togglePackageView} /> @@ -204,25 +204,25 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ))} - {activeFilters[LockfileEntryFilter.Package] ? ( + {activeFilters[LfxGraphEntryKind.Package] ? (
Filters
diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx index 45313bac8da..2c9ab618525 100644 --- a/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx @@ -2,9 +2,10 @@ // See LICENSE in the project root for license information. import React from 'react'; + import styles from './styles.scss'; -export const LogoPanel = (): JSX.Element => { +export const LogoPanel = (): React.ReactElement => { // TODO: Add a mechanism to keep this in sync with the @rushstack/lockfile-explorer // package version. const appPackageVersion: string = window.appContext.appVersion; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx new file mode 100644 index 00000000000..be941756ca6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import React from 'react'; +import { Highlight, themes } from 'prism-react-renderer'; + +// Generate this list by doing console.log(Object.keys(Prism.languages)) +// BUT THEN DELETE the APIs that are bizarrely mixed into this namespace: +// "extend", "insertBefore", "DFS" +export type PrismLanguage = + | 'plain' + | 'plaintext' + | 'text' + | 'txt' + | 'markup' + | 'html' + | 'mathml' + | 'svg' + | 'xml' + | 'ssml' + | 'atom' + | 'rss' + | 'regex' + | 'clike' + | 'javascript' + | 'js' + | 'actionscript' + | 'coffeescript' + | 'coffee' + | 'javadoclike' + | 'css' + | 'yaml' + | 'yml' + | 'markdown' + | 'md' + | 'graphql' + | 'sql' + | 'typescript' + | 'ts' + | 'jsdoc' + | 'flow' + | 'n4js' + | 'n4jsd' + | 'jsx' + | 'tsx' + | 'swift' + | 'kotlin' + | 'kt' + | 'kts' + | 'c' + | 'objectivec' + | 'objc' + | 'reason' + | 'rust' + | 'go' + | 'cpp' + | 'python' + | 'py' + | 'json' + | 'webmanifest'; + +export const CodeBox = (props: { code: string; language: PrismLanguage }): React.ReactElement => { + return ( + + {({ className, style, tokens, getLineProps, getTokenProps }) => ( +
+          {tokens.map((line, i) => (
+            
+ {line.map((token, key) => ( + + ))} +
+ ))} +
+ )} +
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx index d7bdd1ad267..906c58fd0af 100644 --- a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; -import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../parsing/getPackageFiles'; -import styles from './styles.scss'; + +import { ScrollArea, Tabs, Text } from '@rushstack/rush-themed-ui'; + +import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../helpers/lfxApiClient'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { selectCurrentEntry } from '../../store/slices/entrySlice'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -11,16 +13,17 @@ import { compareSpec } from '../../parsing/compareSpec'; import { loadSpecChanges } from '../../store/slices/workspaceSlice'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import { isEntryModified } from '../../helpers/isEntryModified'; -import { ScrollArea, Tabs, Text } from '@rushstack/rush-themed-ui'; -import { LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { LfxGraphEntryKind } from '../../packlets/lfx-shared'; +import { CodeBox } from './CodeBox'; +import styles from './styles.scss'; -const PackageView: { [key in string]: string } = { +const PackageView: { [key: string]: string } = { PACKAGE_JSON: 'PACKAGE_JSON', PACKAGE_SPEC: 'PACKAGE_SPEC', PARSED_PACKAGE_JSON: 'PARSED_PACKAGE_JSON' }; -export const PackageJsonViewer = (): JSX.Element => { +export const PackageJsonViewer = (): React.ReactElement => { const dispatch = useAppDispatch(); const [packageJSON, setPackageJSON] = useState(undefined); const [parsedPackageJSON, setParsedPackageJSON] = useState(undefined); @@ -48,9 +51,9 @@ export const PackageJsonViewer = (): JSX.Element => { useEffect(() => { async function loadPackageDetailsAsync(packageName: string): Promise { - const packageJSONFile = await readPackageJsonAsync(packageName); + const packageJSONFile: IPackageJson | undefined = await readPackageJsonAsync(packageName); setPackageJSON(packageJSONFile); - const parsedJSON = await readPackageSpecAsync(packageName); + const parsedJSON: IPackageJson | undefined = await readPackageSpecAsync(packageName); setParsedPackageJSON(parsedJSON); if (packageJSONFile && parsedJSON) { @@ -73,7 +76,7 @@ export const PackageJsonViewer = (): JSX.Element => { }, [dispatch, selectedEntry]); const renderDep = - (name: boolean): ((dependencyDetails: [string, string]) => JSX.Element) => + (name: boolean): ((dependencyDetails: [string, string]) => React.ReactElement) => (dependencyDetails) => { const [dep, version] = dependencyDetails; if (specChanges.has(dep)) { @@ -152,7 +155,7 @@ export const PackageJsonViewer = (): JSX.Element => { } }; - const renderFile = (): JSX.Element | null => { + const renderFile = (): React.ReactElement | null => { switch (selection) { case PackageView.PACKAGE_JSON: if (!packageJSON) @@ -161,7 +164,7 @@ export const PackageJsonViewer = (): JSX.Element => { Please select a Project or Package to view it's package.json ); - return
{JSON.stringify(packageJSON, null, 2)}
; + return ; case PackageView.PACKAGE_SPEC: if (!pnpmfile) { return ( @@ -171,7 +174,7 @@ export const PackageJsonViewer = (): JSX.Element => { ); } - return
{pnpmfile}
; + return ; case PackageView.PARSED_PACKAGE_JSON: if (!parsedPackageJSON) return ( @@ -186,7 +189,7 @@ export const PackageJsonViewer = (): JSX.Element => { Package Name: - {selectedEntry?.kind === LockfileEntryFilter.Project + {selectedEntry?.kind === LfxGraphEntryKind.Project ? parsedPackageJSON.name : selectedEntry?.displayText} diff --git a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx index 0745c0f39c2..310b7e3cf7d 100644 --- a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx @@ -2,6 +2,9 @@ // See LICENSE in the project root for license information. import React, { useCallback } from 'react'; + +import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -11,9 +14,8 @@ import { removeBookmark, selectCurrentEntry } from '../../store/slices/entrySlice'; -import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; -export const SelectedEntryPreview = (): JSX.Element => { +export const SelectedEntryPreview = (): React.ReactElement => { const selectedEntry = useAppSelector(selectCurrentEntry); const isBookmarked = useAppSelector((state) => selectedEntry ? state.entry.bookmarkedEntries.includes(selectedEntry) : false @@ -37,7 +39,7 @@ export const SelectedEntryPreview = (): JSX.Element => { dispatch(forwardStack()); }, [dispatch]); - const renderButtonRow = (): JSX.Element => { + const renderButtonRow = (): React.ReactElement => { return (