From db909b8afb04c9b1f8d1063d09362aaf35c84f82 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 7 Jul 2025 17:52:17 -0700 Subject: [PATCH 01/40] Use "decoupled-local-node-rig" in heft-heft-json-schema-typings-plugin and typings-generator. --- .../heft-json-schema-typings-plugin/config/jest.config.json | 2 +- heft-plugins/heft-json-schema-typings-plugin/config/rig.json | 2 +- heft-plugins/heft-json-schema-typings-plugin/eslint.config.js | 4 ++-- heft-plugins/heft-json-schema-typings-plugin/package.json | 2 +- heft-plugins/heft-json-schema-typings-plugin/tsconfig.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json b/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json index 7b2eb73199f..4b94b1ba368 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json +++ b/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json @@ -1,5 +1,5 @@ { - "extends": "local-node-rig/profiles/default/config/jest.config.json", + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json", "moduleNameMapper": { "^prettier$": "/jestMocks/prettier.js" } diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/rig.json b/heft-plugins/heft-json-schema-typings-plugin/config/rig.json index 165ffb001f5..cc98dea43dd 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/config/rig.json +++ b/heft-plugins/heft-json-schema-typings-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "local-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js b/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js index c15e6077310..e54effd122a 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js +++ b/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js @@ -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. -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'); +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, diff --git a/heft-plugins/heft-json-schema-typings-plugin/package.json b/heft-plugins/heft-json-schema-typings-plugin/package.json index 0ea0582db8d..62edfb7e8a1 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/package.json +++ b/heft-plugins/heft-json-schema-typings-plugin/package.json @@ -27,7 +27,7 @@ "@rushstack/heft": "workspace:*", "@rushstack/terminal": "workspace:*", "eslint": "~9.37.0", - "local-node-rig": "workspace:*" + "decoupled-local-node-rig": "workspace:*" }, "exports": { "./lib/*.schema.json": "./lib-commonjs/*.schema.json", diff --git a/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json b/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json index dac21d04081..1a33d17b873 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json +++ b/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } From dba78a9d6244a5fad6dc3692c2f5cacb78f9ce61 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 7 Jul 2025 17:58:25 -0700 Subject: [PATCH 02/40] Use the JSON schema plugin in local-node-rig and local-web-rig. --- common/config/rush/nonbrowser-approved-packages.json | 2 +- rigs/local-node-rig/package.json | 3 ++- .../local-node-rig/profiles/default/config/heft.json | 12 +++++++++++- .../profiles/default/tsconfig-base.json | 1 + rigs/local-web-rig/package.json | 2 +- rigs/local-web-rig/profiles/app/config/heft.json | 12 +++++++++++- rigs/local-web-rig/profiles/app/tsconfig-base.json | 2 +- rigs/local-web-rig/profiles/library/config/heft.json | 12 +++++++++++- .../profiles/library/tsconfig-base.json | 2 +- 9 files changed, 40 insertions(+), 8 deletions(-) diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 3f6756df1a8..335c7ea116a 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -208,7 +208,7 @@ }, { "name": "@rushstack/heft-json-schema-typings-plugin", - "allowedCategories": [ "tests" ] + "allowedCategories": [ "libraries", "tests" ] }, { "name": "@rushstack/heft-lint-plugin", diff --git a/rigs/local-node-rig/package.json b/rigs/local-node-rig/package.json index 9a8256b7c26..b401b2f87b8 100644 --- a/rigs/local-node-rig/package.json +++ b/rigs/local-node-rig/package.json @@ -11,13 +11,14 @@ "dependencies": { "@microsoft/api-extractor": "workspace:*", "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft-json-schema-typings-plugin": "workspace:*", "@rushstack/heft-node-rig": "workspace:*", "@rushstack/heft": "workspace:*", "@types/heft-jest": "1.0.1", "@types/node": "20.17.19", - "local-eslint-config": "workspace:*", "eslint": "~9.37.0", "jest-junit": "12.3.0", + "local-eslint-config": "workspace:*", "typescript": "~5.8.2" } } diff --git a/rigs/local-node-rig/profiles/default/config/heft.json b/rigs/local-node-rig/profiles/default/config/heft.json index 77fe092ba04..c25581d099b 100644 --- a/rigs/local-node-rig/profiles/default/config/heft.json +++ b/rigs/local-node-rig/profiles/default/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-esnext"] }], + "cleanFiles": [{ "includeGlobs": ["lib-esnext", "temp/schema-ts"] }], "tasksByName": { "lint": { @@ -14,6 +14,16 @@ "sarifLogPath": "temp/build/lint/lint.sarif" } } + }, + + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "generatedTsFolders": ["temp/schema-ts", "lib"] + } + } } } }, diff --git a/rigs/local-node-rig/profiles/default/tsconfig-base.json b/rigs/local-node-rig/profiles/default/tsconfig-base.json index a70f8605252..025cbf19728 100644 --- a/rigs/local-node-rig/profiles/default/tsconfig-base.json +++ b/rigs/local-node-rig/profiles/default/tsconfig-base.json @@ -11,6 +11,7 @@ "outDir": "${configDir}/lib-commonjs", "declarationDir": "${configDir}/lib-dts", "rootDir": "${configDir}/src", + "rootDirs": ["${configDir}/src", "${configDir}/temp/schema-ts"], "types": ["heft-jest", "node"], "typeRoots": ["${configDir}/node_modules/@types", "../../node_modules/@types"] diff --git a/rigs/local-web-rig/package.json b/rigs/local-web-rig/package.json index 32af5b941d0..b8b752f9fe7 100644 --- a/rigs/local-web-rig/package.json +++ b/rigs/local-web-rig/package.json @@ -15,9 +15,9 @@ "@rushstack/heft": "workspace:*", "@types/heft-jest": "1.0.1", "@types/webpack-env": "1.18.8", - "local-eslint-config": "workspace:*", "eslint": "~9.37.0", "jest-junit": "12.3.0", + "local-eslint-config": "workspace:*", "typescript": "~5.8.2" } } diff --git a/rigs/local-web-rig/profiles/app/config/heft.json b/rigs/local-web-rig/profiles/app/config/heft.json index 1888d38a36f..236c653056d 100644 --- a/rigs/local-web-rig/profiles/app/config/heft.json +++ b/rigs/local-web-rig/profiles/app/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-dts", "lib-esm"] }], + "cleanFiles": [{ "includeGlobs": ["lib-dts", "lib-esm", "temp/schema-ts"] }], "tasksByName": { "lint": { @@ -14,6 +14,16 @@ "sarifLogPath": "temp/build/lint/lint.sarif" } } + }, + + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "generatedTsFolders": ["temp/schema-ts", "lib"] + } + } } } }, diff --git a/rigs/local-web-rig/profiles/app/tsconfig-base.json b/rigs/local-web-rig/profiles/app/tsconfig-base.json index e609adca759..f61d1820f6d 100644 --- a/rigs/local-web-rig/profiles/app/tsconfig-base.json +++ b/rigs/local-web-rig/profiles/app/tsconfig-base.json @@ -13,7 +13,7 @@ "outDir": "${configDir}/lib-esm", "declarationDir": "${configDir}/lib-dts", "rootDir": "${configDir}/src", - "rootDirs": ["${configDir}/src", "${configDir}/temp/sass-ts"], + "rootDirs": ["${configDir}/src", "${configDir}/temp/sass-ts", "${configDir}/temp/schema-ts"], "types": ["heft-jest", "webpack-env"], "typeRoots": ["${configDir}/node_modules/@types", "../../node_modules/@types"] diff --git a/rigs/local-web-rig/profiles/library/config/heft.json b/rigs/local-web-rig/profiles/library/config/heft.json index 541a146a9c8..f4f7d1dd03f 100644 --- a/rigs/local-web-rig/profiles/library/config/heft.json +++ b/rigs/local-web-rig/profiles/library/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-dts", "lib-esm"] }], + "cleanFiles": [{ "includeGlobs": ["lib-dts", "lib-esm", "temp/schema-ts"] }], "tasksByName": { "lint": { @@ -14,6 +14,16 @@ "sarifLogPath": "temp/build/lint/lint.sarif" } } + }, + + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "generatedTsFolders": ["temp/schema-ts", "lib"] + } + } } } }, diff --git a/rigs/local-web-rig/profiles/library/tsconfig-base.json b/rigs/local-web-rig/profiles/library/tsconfig-base.json index eec41564e0e..de5406f3052 100644 --- a/rigs/local-web-rig/profiles/library/tsconfig-base.json +++ b/rigs/local-web-rig/profiles/library/tsconfig-base.json @@ -10,7 +10,7 @@ "outDir": "${configDir}/lib-esm", "declarationDir": "${configDir}/lib-dts", "rootDir": "${configDir}/src", - "rootDirs": ["${configDir}/src", "${configDir}/temp/sass-ts"], + "rootDirs": ["${configDir}/src", "${configDir}/temp/sass-ts", "${configDir}/temp/schema-ts"], "types": ["heft-jest", "webpack-env"], "typeRoots": ["${configDir}/node_modules/@types", "../../node_modules/@types"] From 430ec0d9f92960733f391e5744de3affde2f1672 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 7 Jul 2025 18:23:10 -0700 Subject: [PATCH 03/40] fixup! Use the JSON schema plugin in local-node-rig and local-web-rig. --- rigs/local-node-rig/profiles/default/config/heft.json | 4 ++++ rigs/local-web-rig/profiles/app/config/heft.json | 4 ++++ rigs/local-web-rig/profiles/library/config/heft.json | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/rigs/local-node-rig/profiles/default/config/heft.json b/rigs/local-node-rig/profiles/default/config/heft.json index c25581d099b..049789bee4b 100644 --- a/rigs/local-node-rig/profiles/default/config/heft.json +++ b/rigs/local-node-rig/profiles/default/config/heft.json @@ -24,6 +24,10 @@ "generatedTsFolders": ["temp/schema-ts", "lib"] } } + }, + + "typescript": { + "taskDependencies": ["json-schema-typings"] } } }, diff --git a/rigs/local-web-rig/profiles/app/config/heft.json b/rigs/local-web-rig/profiles/app/config/heft.json index 236c653056d..39cce434bd5 100644 --- a/rigs/local-web-rig/profiles/app/config/heft.json +++ b/rigs/local-web-rig/profiles/app/config/heft.json @@ -24,6 +24,10 @@ "generatedTsFolders": ["temp/schema-ts", "lib"] } } + }, + + "typescript": { + "taskDependencies": ["json-schema-typings"] } } }, diff --git a/rigs/local-web-rig/profiles/library/config/heft.json b/rigs/local-web-rig/profiles/library/config/heft.json index f4f7d1dd03f..648b8daa61c 100644 --- a/rigs/local-web-rig/profiles/library/config/heft.json +++ b/rigs/local-web-rig/profiles/library/config/heft.json @@ -24,6 +24,10 @@ "generatedTsFolders": ["temp/schema-ts", "lib"] } } + }, + + "typescript": { + "taskDependencies": ["json-schema-typings"] } } }, From 8cce05505740e3f27458fc8fa07b59eae606728f Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 7 Jul 2025 17:54:15 -0700 Subject: [PATCH 04/40] Use decoupled-local-node-rig in typings-generator. --- libraries/typings-generator/config/rig.json | 2 +- libraries/typings-generator/eslint.config.js | 4 ++-- libraries/typings-generator/package.json | 4 ++-- libraries/typings-generator/tsconfig.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/typings-generator/config/rig.json b/libraries/typings-generator/config/rig.json index 165ffb001f5..cc98dea43dd 100644 --- a/libraries/typings-generator/config/rig.json +++ b/libraries/typings-generator/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "local-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/typings-generator/eslint.config.js b/libraries/typings-generator/eslint.config.js index c15e6077310..e54effd122a 100644 --- a/libraries/typings-generator/eslint.config.js +++ b/libraries/typings-generator/eslint.config.js @@ -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. -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'); +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, diff --git a/libraries/typings-generator/package.json b/libraries/typings-generator/package.json index 5e438eecb6d..fc0e9bf0518 100644 --- a/libraries/typings-generator/package.json +++ b/libraries/typings-generator/package.json @@ -51,8 +51,8 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", - "eslint": "~9.37.0", - "local-node-rig": "workspace:*" + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" }, "peerDependencies": { "@types/node": "*" diff --git a/libraries/typings-generator/tsconfig.json b/libraries/typings-generator/tsconfig.json index dac21d04081..1a33d17b873 100644 --- a/libraries/typings-generator/tsconfig.json +++ b/libraries/typings-generator/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } From 2ed45ceda869b2b74a3b346b4e7b39912fd4b5b3 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Wed, 9 Jul 2025 15:24:32 -0700 Subject: [PATCH 05/40] Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- rigs/decoupled-local-node-rig/package.json | 4 ++-- .../profiles/default/config/heft.json | 12 +++++++++++- rush.json | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rigs/decoupled-local-node-rig/package.json b/rigs/decoupled-local-node-rig/package.json index 3d9f26bee4f..540a3d32b45 100644 --- a/rigs/decoupled-local-node-rig/package.json +++ b/rigs/decoupled-local-node-rig/package.json @@ -13,6 +13,7 @@ "@rushstack/eslint-config": "4.6.2", "@rushstack/eslint-patch": "1.16.0", "@rushstack/eslint-plugin": "0.23.0", + "@rushstack/heft-json-schema-typings-plugin": "1.2.0", "@rushstack/heft-node-rig": "2.11.20", "@rushstack/heft": "1.2.0", "@types/heft-jest": "1.0.1", @@ -26,7 +27,6 @@ "eslint-plugin-react-hooks": "5.2.0", "eslint": "~9.37.0", "jest-junit": "12.3.0", - "typescript": "~5.8.2", - "eslint-import-resolver-node": "0.3.9" + "typescript": "~5.8.2" } } diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json index 77fe092ba04..c25581d099b 100644 --- a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json +++ b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-esnext"] }], + "cleanFiles": [{ "includeGlobs": ["lib-esnext", "temp/schema-ts"] }], "tasksByName": { "lint": { @@ -14,6 +14,16 @@ "sarifLogPath": "temp/build/lint/lint.sarif" } } + }, + + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "generatedTsFolders": ["temp/schema-ts", "lib"] + } + } } } }, diff --git a/rush.json b/rush.json index 8d2151e9cc1..d13407943b8 100644 --- a/rush.json +++ b/rush.json @@ -1373,6 +1373,7 @@ "@rushstack/eslint-config", "@rushstack/eslint-patch", "@rushstack/eslint-plugin", + "@rushstack/heft-json-schema-typings-plugin", "@rushstack/heft-node-rig", "@rushstack/heft" ] From 350ecc4a94e5b0c6149c9454f0b655f22c5271b1 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Thu, 10 Jul 2025 18:44:01 -0700 Subject: [PATCH 06/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- .../profiles/default/tsconfig-base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json index a70f8605252..a16e53d7ca4 100644 --- a/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json +++ b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json @@ -10,7 +10,7 @@ "outDir": "${configDir}/lib-commonjs", "declarationDir": "${configDir}/lib-dts", - "rootDir": "${configDir}/src", + "rootDirs": ["${configDir}/src", "${configDir}/temp/schema-ts"], "types": ["heft-jest", "node"], "typeRoots": ["${configDir}/node_modules/@types", "../../node_modules/@types"] From 03efd2f5ffbf9b7301a5f5def0c7a6decfbe4c45 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Thu, 10 Jul 2025 18:46:48 -0700 Subject: [PATCH 07/40] Use schemas for typings in the heft plugins. --- .../reviews/api/heft-typescript-plugin.api.md | 59 +++++------ .../src/ApiExtractorPlugin.ts | 31 +----- .../heft-plugin.json | 2 +- .../src/SwcIsolatedTranspilePlugin.ts | 19 ++-- ...lated-transpile-plugin-options.schema.json | 77 ++++++++++++++ .../swc-isolated-transpile-plugin.schema.json | 32 ------ .../src/types.ts | 13 --- .../heft-jest-plugin/heft-plugin.json | 2 +- .../heft-jest-plugin/src/JestPlugin.ts | 6 +- ...n => heft-jest-plugin-options.schema.json} | 0 .../src/JsonSchemaTypingsPlugin.ts | 8 +- .../heft-lint-plugin/heft-plugin.json | 2 +- .../heft-lint-plugin/src/LintPlugin.ts | 17 ++- ...n => heft-lint-plugin-options.schema.json} | 0 .../src/LocalizationTypingsPlugin.ts | 35 +----- .../heft-sass-plugin/src/SassPlugin.ts | 19 +--- ...n => heft-sass-plugin-options.schema.json} | 0 .../heft-storybook-plugin/heft-plugin.json | 2 +- .../src/StorybookPlugin.ts | 100 ++---------------- ...n => storybook-plugin-options.schema.json} | 0 .../src/TypeScriptBuilder.ts | 4 +- .../src/TypeScriptPlugin.ts | 84 ++------------- .../heft-typescript-plugin/src/index.ts | 7 +- .../src/schemas/typescript.schema.json | 2 +- .../heft-webpack4-plugin/heft-plugin.json | 2 +- .../src/Webpack4Plugin.ts | 16 ++- .../src/WebpackConfigurationLoader.ts | 6 +- ... heft-webpack4-plugin-options.schema.json} | 0 .../heft-webpack5-plugin/heft-plugin.json | 2 +- .../src/Webpack5Plugin.ts | 15 ++- .../src/WebpackConfigurationLoader.ts | 6 +- ... heft-webpack5-plugin-options.schema.json} | 0 32 files changed, 176 insertions(+), 392 deletions(-) create mode 100644 heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin-options.schema.json delete mode 100644 heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json rename heft-plugins/heft-jest-plugin/src/schemas/{heft-jest-plugin.schema.json => heft-jest-plugin-options.schema.json} (100%) rename heft-plugins/heft-lint-plugin/src/schemas/{heft-lint-plugin.schema.json => heft-lint-plugin-options.schema.json} (100%) rename heft-plugins/heft-sass-plugin/src/schemas/{heft-sass-plugin.schema.json => heft-sass-plugin-options.schema.json} (100%) rename heft-plugins/heft-storybook-plugin/src/schemas/{storybook.schema.json => storybook-plugin-options.schema.json} (100%) rename heft-plugins/heft-webpack4-plugin/src/schemas/{heft-webpack4-plugin.schema.json => heft-webpack4-plugin-options.schema.json} (100%) rename heft-plugins/heft-webpack5-plugin/src/schemas/{heft-webpack5-plugin.schema.json => heft-webpack5-plugin-options.schema.json} (100%) diff --git a/common/reviews/api/heft-typescript-plugin.api.md b/common/reviews/api/heft-typescript-plugin.api.md index 2e42af718cc..3e841c7104b 100644 --- a/common/reviews/api/heft-typescript-plugin.api.md +++ b/common/reviews/api/heft-typescript-plugin.api.md @@ -39,16 +39,6 @@ export interface _ICompilerCapabilities { solutionBuilder: boolean; } -// @beta (undocumented) -export interface IEmitModuleKind { - // (undocumented) - jsExtensionOverride?: string; - // (undocumented) - moduleKind: 'commonjs' | 'amd' | 'umd' | 'system' | 'es2015' | 'esnext'; - // (undocumented) - outFolderName: string; -} - // @internal (undocumented) export interface _ILoadedTypeScriptTool { // (undocumented) @@ -95,29 +85,6 @@ export interface IPartialTsconfigCompilerOptions { outDir?: string; } -// @beta (undocumented) -export interface IStaticAssetsCopyConfiguration { - // (undocumented) - excludeGlobs: string[]; - // (undocumented) - fileExtensions: string[]; - // (undocumented) - includeGlobs: string[]; -} - -// @beta (undocumented) -export interface ITypeScriptConfigurationJson { - additionalModuleKindsToEmit?: IEmitModuleKind[] | undefined; - buildProjectReferences?: boolean; - emitCjsExtensionForCommonJS?: boolean | undefined; - emitMjsExtensionForESModule?: boolean | undefined; - onlyResolveSymlinksInNodeModules?: boolean; - // (undocumented) - project?: string; - staticAssetsToCopy?: IStaticAssetsCopyConfiguration; - useTranspilerWorker?: boolean; -} - // @beta (undocumented) export interface ITypeScriptPluginAccessor { // (undocumented) @@ -125,19 +92,41 @@ export interface ITypeScriptPluginAccessor { } // @beta (undocumented) -export function loadPartialTsconfigFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal, typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined): Promise; +export function loadPartialTsconfigFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal, typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined): Promise; // @internal (undocumented) export function _loadTsconfig(options: _ILoadTsconfigOptions): _TTypeScript.ParsedCommandLine; // @beta (undocumented) -export function loadTypeScriptConfigurationFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal): Promise; +export function loadTypeScriptConfigurationFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal): Promise; // @internal (undocumented) export function _loadTypeScriptToolAsync(options: _ILoadTypeScriptToolOptions): Promise<_ILoadedTypeScriptTool>; export { _TTypeScript } +// @beta +export interface TypeScriptBuildConfiguration { + $schema?: string; + additionalModuleKindsToEmit?: { + moduleKind: "commonjs" | "amd" | "umd" | "system" | "es2015" | "esnext"; + outFolderName: string; + [k: string]: unknown; + }[]; + buildProjectReferences?: boolean; + emitCjsExtensionForCommonJS?: boolean; + emitMjsExtensionForESModule?: boolean; + extends?: string; + onlyResolveSymlinksInNodeModules?: boolean; + project?: string; + staticAssetsToCopy?: { + fileExtensions?: string[]; + excludeGlobs?: string[]; + includeGlobs?: string[]; + }; + useTranspilerWorker?: boolean; +} + // @public export const TypeScriptPluginName: 'typescript-plugin'; diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts index 8ab77d46808..b78c23b69a5 100644 --- a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts @@ -13,6 +13,7 @@ import type { import { invokeApiExtractorAsync } from './ApiExtractorRunner'; import apiExtractorConfigSchema from './schemas/api-extractor-task.schema.json'; +import type { APIExtractorTaskConfiguration } from './schemas/api-extractor-task.schema.json.d.ts'; // eslint-disable-next-line @rushstack/no-new-null const UNINITIALIZED: null = null; @@ -23,7 +24,7 @@ const EXTRACTOR_CONFIG_FILENAME: typeof TApiExtractor.ExtractorConfig.FILENAME = const LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH: string = `./${EXTRACTOR_CONFIG_FILENAME}`; const EXTRACTOR_CONFIG_RELATIVE_PATH: string = `./config/${EXTRACTOR_CONFIG_FILENAME}`; -const API_EXTRACTOR_CONFIG_SPECIFICATION: ConfigurationFile.IProjectConfigurationFileSpecification = +const API_EXTRACTOR_CONFIG_SPECIFICATION: ConfigurationFile.IProjectConfigurationFileSpecification = { projectRelativeFilePath: TASK_CONFIG_RELATIVE_PATH, jsonSchemaObject: apiExtractorConfigSchema @@ -34,34 +35,6 @@ export interface IApiExtractorConfigurationResult { apiExtractorConfiguration: TApiExtractor.ExtractorConfig; } -export interface IApiExtractorTaskConfiguration { - /** - * If set to true, use the project's TypeScript compiler version for API Extractor's - * analysis. API Extractor's included TypeScript compiler can generally correctly - * analyze typings generated by older compilers, and referencing the project's compiler - * can cause issues. If issues are encountered with API Extractor's included compiler, - * set this option to true. - * - * This corresponds to API Extractor's `--typescript-compiler-folder` CLI option and - * `IExtractorInvokeOptions.typescriptCompilerFolder` API option. This option defaults to false. - */ - useProjectTypescriptVersion?: boolean; - - /** - * If set to true, do a full run of api-extractor on every build. - */ - runInWatchMode?: boolean; - - /** - * Controls whether API Extractor prints a diff of the API report file if it's changed. - * If set to `"production"`, this will only be printed if Heft is run in `--production` - * mode, and if set to `"always"`, this will always be printed if the API report is changed. - * This corresponds to API Extractor's `IExtractorInvokeOptions.printApiReportDiff` API option. - * This option defaults to `"never"`. - */ - printApiReportDiff?: 'production' | 'always' | 'never'; -} - export default class ApiExtractorPlugin implements IHeftTaskPlugin { private _apiExtractor: typeof TApiExtractor | undefined; private _apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED; diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json index e94bf9c0815..1ada2fe4d39 100644 --- a/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "swc-isolated-transpile-plugin", "entryPoint": "./lib-commonjs/SwcIsolatedTranspilePlugin", - "optionsSchema": "./lib-commonjs/schemas/swc-isolated-transpile-plugin.schema.json" + "optionsSchema": "./lib-commonjs/schemas/swc-isolated-transpile-plugin-options.schema.json" } ] } diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts index 2dd940fc342..987bce82d95 100644 --- a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts @@ -33,19 +33,16 @@ import { _getTsconfigFilePath as getTsconfigFilePath } from '@rushstack/heft-typescript-plugin'; -import type { - ISwcIsolatedTranspileOptions, - IWorkerResult, - ITransformTask, - IEmitKind, - ITransformModulesRequestMessage -} from './types'; +import type { SwcIsolatedTranspilePluginOptions } from './schemas/swc-isolated-transpile-plugin-options.schema.json.d.ts'; +import type { IWorkerResult, ITransformTask, ITransformModulesRequestMessage } from './types'; /** * @public */ export type ModuleKind = keyof typeof TTypeScript.ModuleKind; +type IEmitKind = Required['emitKinds'][number]; + const TSC_TO_SWC_MODULE_MAP: Record = { CommonJS: 'commonjs', ES2015: 'es6', @@ -105,7 +102,9 @@ export interface ISwcIsolatedTranspilePluginAccessor { /** * @public */ -export default class SwcIsolatedTranspilePlugin implements IHeftTaskPlugin { +export default class SwcIsolatedTranspilePlugin + implements IHeftTaskPlugin +{ /** * @beta */ @@ -122,7 +121,7 @@ export default class SwcIsolatedTranspilePlugin implements IHeftTaskPlugin { const { logger } = heftSession; @@ -146,7 +145,7 @@ export default class SwcIsolatedTranspilePlugin implements IHeftTaskPlugin IWatchFileSystem) | undefined diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin-options.schema.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin-options.schema.json new file mode 100644 index 00000000000..01042dab791 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin-options.schema.json @@ -0,0 +1,77 @@ +{ + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + + "extends": { + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "type": "string" + }, + + "tsConfigPath": { + "type": "string", + "description": "The path to the tsconfig.json file" + }, + + "emitKinds": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["outDir", "formatOverride", "targetOverride"], + "properties": { + "outDir": { + "type": "string", + "description": "The output directory for the transpiled files" + }, + + "formatOverride": { + "type": "string", + "description": "The output format for transpiled files. See type ModuleKind in TypeScript for valid values.", + "enum": [ + "None", + "CommonJS", + "AMD", + "UMD", + "System", + "ES2015", + "ES2020", + "ES2022", + "ESNext", + "Node16", + "Node18", + "NodeNext", + "Preserve" + ] + }, + + "targetOverride": { + "type": "string", + "description": "The target for transpiled files. See type ScriptTarget in TypeScript for valid values.", + "enum": [ + "ES2015", + "ES2020", + "ES2022", + "ESNext", + "ES3", + "ES5", + "ES2016", + "ES2017", + "ES2018", + "ES2019", + "ES2021", + "ES2023", + "ES2024", + "JSON", + "Latest" + ] + } + } + } + } + } +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json deleted file mode 100644 index f87ab47a031..00000000000 --- a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "properties": { - "tsConfigPath": { - "type": "string", - "description": "The path to the tsconfig.json file" - }, - "emitKinds": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "required": ["outDir", "formatOverride", "targetOverride"], - "properties": { - "outDir": { - "type": "string", - "description": "The output directory for the transpiled files" - }, - "formatOverride": { - "type": "string", - "description": "The output format for transpiled files. See type ModuleKind in TypeScript for valid values." - }, - "targetOverride": { - "type": "string", - "description": "The target for transpiled files. See type ScriptTarget in TypeScript for valid values." - } - } - } - } - } -} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts index 0926fba7f7e..2ae4eba9155 100644 --- a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts @@ -1,23 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { ModuleKind, ScriptTarget } from './SwcIsolatedTranspilePlugin'; - export interface IProjectOptions { buildFolder: string; } -export interface IEmitKind { - outDir: string; - formatOverride: ModuleKind; - targetOverride: ScriptTarget; -} - -export interface ISwcIsolatedTranspileOptions { - tsConfigPath?: string; - emitKinds?: IEmitKind[]; -} - export interface IWorkerData { buildFolderPath: string; concurrency: number; diff --git a/heft-plugins/heft-jest-plugin/heft-plugin.json b/heft-plugins/heft-jest-plugin/heft-plugin.json index 52c65540566..ae446f1f008 100644 --- a/heft-plugins/heft-jest-plugin/heft-plugin.json +++ b/heft-plugins/heft-jest-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "jest-plugin", "entryPoint": "./lib-commonjs/JestPlugin", - "optionsSchema": "./lib-commonjs/schemas/heft-jest-plugin.schema.json", + "optionsSchema": "./lib-commonjs/schemas/heft-jest-plugin-options.schema.json", "parameterScope": "jest", "parameters": [ diff --git a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts index 5bf31ed257e..4935be7046f 100644 --- a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts +++ b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts @@ -37,6 +37,7 @@ import type { ITerminal } from '@rushstack/terminal'; import type { IHeftJestReporterOptions } from './HeftJestReporter'; import { jestResolve } from './JestUtils'; import { TerminalWritableStream } from './TerminalWritableStream'; +import type { HeftJestPluginOptionsConfiguration } from './schemas/heft-jest-plugin-options.schema.json.d.ts'; import anythingSchema from './schemas/anything.schema.json'; const jestPluginSymbol: unique symbol = Symbol('heft-jest-plugin'); @@ -90,13 +91,10 @@ interface IJestResolutionOptions { /** * Options that can be provided to the plugin. */ -export interface IJestPluginOptions { - configurationPath?: string; +export interface IJestPluginOptions extends HeftJestPluginOptionsConfiguration { debugHeftReporter?: boolean; detectOpenHandles?: boolean; disableCodeCoverage?: boolean; - disableConfigurationModuleResolution?: boolean; - enableNodeEnvManagement?: boolean; findRelatedTests?: string[]; maxWorkers?: string; passWithNoTests?: boolean; diff --git a/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json rename to heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts index 877cd041b26..53be89d56fd 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts @@ -11,16 +11,10 @@ import type { import type { ITerminal } from '@rushstack/terminal'; import { JsonSchemaTypingsGenerator } from './JsonSchemaTypingsGenerator'; +import type { Options as IJsonSchemaTypingsPluginOptions } from './schemas/options.schema.json.d.ts'; const PLUGIN_NAME: 'json-schema-typings-plugin' = 'json-schema-typings-plugin'; -// TODO: Replace this with usage of this plugin after this plugin is published -export interface IJsonSchemaTypingsPluginOptions { - srcFolder?: string; - generatedTsFolders?: string[]; - formatWithPrettier?: boolean; -} - export default class JsonSchemaTypingsPlugin implements IHeftTaskPlugin { /** * Generate typings for JSON Schemas. diff --git a/heft-plugins/heft-lint-plugin/heft-plugin.json b/heft-plugins/heft-lint-plugin/heft-plugin.json index 13c0b3f3656..cc2330a6103 100644 --- a/heft-plugins/heft-lint-plugin/heft-plugin.json +++ b/heft-plugins/heft-lint-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "lint-plugin", "entryPoint": "./lib-commonjs/LintPlugin", - "optionsSchema": "./lib-commonjs/schemas/heft-lint-plugin.schema.json", + "optionsSchema": "./lib-commonjs/schemas/heft-lint-plugin-options.schema.json", "parameterScope": "lint", "parameters": [ diff --git a/heft-plugins/heft-lint-plugin/src/LintPlugin.ts b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts index 74a4e384d97..be6aa73b0a4 100644 --- a/heft-plugins/heft-lint-plugin/src/LintPlugin.ts +++ b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts @@ -23,6 +23,7 @@ import type { LinterBase } from './LinterBase'; import { Eslint } from './Eslint'; import { Tslint } from './Tslint'; import type { IExtendedProgram, IExtendedSourceFile } from './internalTypings/TypeScriptInternals'; +import type { HeftLintPluginOptionsConfiguration } from './schemas/heft-lint-plugin-options.schema.json.d.ts'; const PLUGIN_NAME: 'lint-plugin' = 'lint-plugin'; const TYPESCRIPT_PLUGIN_PACKAGE_NAME: '@rushstack/heft-typescript-plugin' = @@ -30,11 +31,6 @@ const TYPESCRIPT_PLUGIN_PACKAGE_NAME: '@rushstack/heft-typescript-plugin' = const TYPESCRIPT_PLUGIN_NAME: typeof TypeScriptPluginName = 'typescript-plugin'; const FIX_PARAMETER_NAME: string = '--fix'; -interface ILintPluginOptions { - alwaysFix?: boolean; - sarifLogPath?: string; -} - interface ILintOptions { taskSession: IHeftTaskSession; heftConfiguration: HeftConfiguration; @@ -44,7 +40,10 @@ interface ILintOptions { changedFiles?: ReadonlySet; } -function checkFix(taskSession: IHeftTaskSession, pluginOptions?: ILintPluginOptions): boolean { +function checkFix( + taskSession: IHeftTaskSession, + pluginOptions?: HeftLintPluginOptionsConfiguration +): boolean { let fix: boolean = pluginOptions?.alwaysFix || taskSession.parameters.getFlagParameter(FIX_PARAMETER_NAME).value; if (fix && taskSession.parameters.production) { @@ -60,7 +59,7 @@ function checkFix(taskSession: IHeftTaskSession, pluginOptions?: ILintPluginOpti function getSarifLogPath( heftConfiguration: HeftConfiguration, - pluginOptions?: ILintPluginOptions + pluginOptions?: HeftLintPluginOptionsConfiguration ): string | undefined { const relativeSarifLogPath: string | undefined = pluginOptions?.sarifLogPath; const sarifLogPath: string | undefined = @@ -68,7 +67,7 @@ function getSarifLogPath( return sarifLogPath; } -export default class LintPlugin implements IHeftTaskPlugin { +export default class LintPlugin implements IHeftTaskPlugin { // These are initliazed by _initAsync private _initPromise!: Promise; private _eslintToolPath: string | undefined; @@ -79,7 +78,7 @@ export default class LintPlugin implements IHeftTaskPlugin { public apply( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, - pluginOptions?: ILintPluginOptions + pluginOptions?: HeftLintPluginOptionsConfiguration ): void { // Disable linting in watch mode. Some lint rules require the context of multiple files, which // may not be available in watch mode. diff --git a/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin.schema.json b/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin.schema.json rename to heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json diff --git a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts index 5d71f8da9a7..ac29a4db12c 100644 --- a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts +++ b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts @@ -9,40 +9,9 @@ import type { IScopedLogger, IWatchedFileState } from '@rushstack/heft'; -import { type ITypingsGeneratorOptions, TypingsGenerator } from '@rushstack/localization-utilities'; +import { TypingsGenerator } from '@rushstack/localization-utilities'; -export interface ILocalizationTypingsPluginOptions { - /** - * Source code root directory. - * Defaults to "src/". - */ - srcFolder?: string; - - /** - * Output directory for generated typings. - * Defaults to "temp/loc-ts/". - */ - generatedTsFolder?: string; - - /** - * Folders, relative to the project root, where JSON files containing only the key/string pairs should be emitted to. - * These files will be emitted as `.resx.json`, `.loc.json`, or `.resjson`, depending on the input file extension. - * The intent is that bundlers can find these files and load them to receive the original untranslated strings. - */ - trimmedJsonOutputFolders?: string[]; - - /** - * Additional folders, relative to the project root, where the generated typings should be emitted to. - */ - secondaryGeneratedTsFolders?: string[]; - - exportAsDefault?: ITypingsGeneratorOptions['exportAsDefault']; - - /** - * An array of string names to ignore when generating typings. - */ - stringNamesToIgnore?: string[]; -} +import type { Options as ILocalizationTypingsPluginOptions } from './schemas/options.schema.json.d.ts'; const PLUGIN_NAME: 'localization-typings-plugin' = 'localization-typings-plugin'; diff --git a/heft-plugins/heft-sass-plugin/src/SassPlugin.ts b/heft-plugins/heft-sass-plugin/src/SassPlugin.ts index 3525cbfa817..01589da4515 100644 --- a/heft-plugins/heft-sass-plugin/src/SassPlugin.ts +++ b/heft-plugins/heft-sass-plugin/src/SassPlugin.ts @@ -16,20 +16,9 @@ import type { } from '@rushstack/heft'; import { PLUGIN_NAME } from './constants'; -import { type ICssOutputFolder, type ISassProcessorOptions, SassProcessor } from './SassProcessor'; -import sassConfigSchema from './schemas/heft-sass-plugin.schema.json'; - -export interface ISassConfigurationJson { - srcFolder?: string; - generatedTsFolder?: string; - cssOutputFolders?: (string | ICssOutputFolder)[]; - secondaryGeneratedTsFolders?: string[]; - exportAsDefault?: boolean; - fileExtensions?: string[]; - nonModuleFileExtensions?: string[]; - silenceDeprecations?: string[]; - excludeFiles?: string[]; -} +import { type ISassProcessorOptions, SassProcessor } from './SassProcessor'; +import type { SassConfiguration as ISassConfigurationJson } from './schemas/heft-sass-plugin-options.schema.json.d.ts'; +import sassConfigSchema from './schemas/heft-sass-plugin-options.schema.json'; const SASS_CONFIGURATION_LOCATION: string = 'config/sass.json'; @@ -113,7 +102,7 @@ export default class SassPlugin implements IHeftPlugin { excludeFiles, fileExtensions, nonModuleFileExtensions, - cssOutputFolders: cssOutputFolders?.map((folder: string | ICssOutputFolder) => { + cssOutputFolders: cssOutputFolders?.map((folder) => { const folderPath: string = typeof folder === 'string' ? folder : folder.folder; const shimModuleFormat: 'commonjs' | 'esnext' | undefined = typeof folder === 'string' ? undefined : folder.shimModuleFormat; diff --git a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json rename to heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json diff --git a/heft-plugins/heft-storybook-plugin/heft-plugin.json b/heft-plugins/heft-storybook-plugin/heft-plugin.json index 107eca91df2..84aea41444f 100644 --- a/heft-plugins/heft-storybook-plugin/heft-plugin.json +++ b/heft-plugins/heft-storybook-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "storybook-plugin", "entryPoint": "./lib-commonjs/StorybookPlugin", - "optionsSchema": "./lib-commonjs/schemas/storybook.schema.json", + "optionsSchema": "./lib-commonjs/schemas/storybook-plugin-options.schema.json", "parameterScope": "storybook", "parameters": [ diff --git a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts index 4b3939ac429..8000cf53c7c 100644 --- a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts +++ b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts @@ -35,6 +35,8 @@ import type { } from '@rushstack/heft-webpack5-plugin'; import type { IRspackPluginAccessor, PluginName as RspackPluginName } from '@rushstack/heft-rspack-plugin'; +import type { HeftStorybookPluginOptionsConfiguration } from './schemas/storybook-plugin-options.schema.json.d.ts'; + const PLUGIN_NAME: 'storybook-plugin' = 'storybook-plugin'; const WEBPACK4_PLUGIN_NAME: typeof Webpack4PluginName = 'webpack4-plugin'; const WEBPACK5_PLUGIN_NAME: typeof Webpack5PluginName = 'webpack5-plugin'; @@ -72,94 +74,6 @@ interface IStorybookCliCallingConfig { packageName: string; } -/** - * Options for `StorybookPlugin`. - * - * @public - */ -export interface IStorybookPluginOptions { - /** - * Specifies an NPM package that will provide the Storybook dependencies for the project. - * - * @example - * `"storykitPackageName": "my-react-storykit"` - * - * @remarks - * - * Storybook's conventional approach is for your app project to have direct dependencies - * on NPM packages such as `@storybook/react` and `@storybook/addon-essentials`. These packages have - * heavyweight dependencies such as Babel, Webpack, and the associated loaders and plugins needed to - * build the Storybook app (which is bundled completely independently from Heft). Naively adding these - * dependencies to your app's package.json muddies the waters of two radically different toolchains, - * and is likely to lead to dependency conflicts, for example if Heft installs Webpack 5 but - * `@storybook/react` installs Webpack 4. - * - * To solve this problem, `heft-storybook-plugin` introduces the concept of a separate - * "storykit package". All of your Storybook NPM packages are moved to be dependencies of the - * storykit. Storybook's browser API unfortunately isn't separated into dedicated NPM packages, - * but instead is exported by the Node.js toolchain packages such as `@storybook/react`. For - * an even cleaner separation the storykit package can simply reexport such APIs. - */ - storykitPackageName: string; - - /** - * Specify how the Storybook CLI should be invoked. Possible values: - * - * - "storybook6": For a static build, Heft will expect the cliPackageName package - * to define a binary command named "build-storybook". For the dev server mode, - * Heft will expect to find a binary command named "start-storybook". These commands - * must be declared in the "bin" section of package.json since Heft invokes the script directly. - * The output folder will be specified using the "--output-dir" CLI parameter. - * - * - "storybook7": Heft looks for a single binary command named "sb". It will be invoked as - * "sb build" for static builds, or "sb dev" for dev server mode. - * The output folder will be specified using the "--output-dir" CLI parameter. - * - * @defaultValue `storybook7` - */ - cliCallingConvention?: `${StorybookCliVersion}`; - - /** - * Specify the NPM package that provides the CLI binary to run. - * It will be resolved from the folder of your storykit package. - * - * @defaultValue - * The default is `@storybook/cli` when `cliCallingConvention` is `storybook7` - * and `@storybook/react` when `cliCallingConvention` is `storybook6` - */ - cliPackageName?: string; - - /** - * The customized output dir for storybook static build. - * If this is empty, then it will use the storybook default output dir. - * - * @example - * If you want to change the static build output dir to staticBuildDir, then the static build output dir would be: - * - * `"staticBuildOutputFolder": "newStaticBuildDir"` - */ - staticBuildOutputFolder?: string; - - /** - * Specifies an NPM dependency name that is used as the (cwd) target for the storybook commands - * By default the plugin executes the storybook commands in the local package context, - * but for distribution purposes it can be useful to split the TS library and storybook exports into two packages. - * - * @example - * If you create a storybook app project "my-ui-storybook-library-app" for the storybook preview distribution, - * and your main UI component library is my-ui-storybook-library. - * - * Your 'app' project is able to compile the 'library' storybook preview using the CWD target: - * - * `"cwdPackageName": "my-storybook-ui-library"` - */ - cwdPackageName?: string; - /** - * Specifies whether to capture the webpack stats for the storybook build by adding the `--webpack-stats-json` CLI flag. - */ - captureWebpackStats?: boolean; -} - interface IRunStorybookOptions extends IPrepareStorybookOptions { logger: IScopedLogger; isServeMode: boolean; @@ -170,7 +84,7 @@ interface IRunStorybookOptions extends IPrepareStorybookOptions { verbose: boolean; } -interface IPrepareStorybookOptions extends IStorybookPluginOptions { +interface IPrepareStorybookOptions extends HeftStorybookPluginOptionsConfiguration { logger: IScopedLogger; taskSession: IHeftTaskSession; heftConfiguration: HeftConfiguration; @@ -216,14 +130,14 @@ const STORYBOOK_TEST_FLAG_NAME: '--storybook-test' = '--storybook-test'; const DOCS_FLAG_NAME: '--docs' = '--docs'; /** @public */ -export default class StorybookPlugin implements IHeftTaskPlugin { +export default class StorybookPlugin implements IHeftTaskPlugin { /** * Generate typings for Sass files before TypeScript compilation. */ public apply( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, - options: IStorybookPluginOptions + options: HeftStorybookPluginOptionsConfiguration ): void { const logger: IScopedLogger = taskSession.logger; const storybookParameter: CommandLineFlagParameter = @@ -450,7 +364,7 @@ export default class StorybookPlugin implements IHeftTaskPlugin { const { logger, resolvedModulePath, verbose, isServeMode, isTestMode, isDocsMode } = runStorybookOptions; let { workingDirectory, outputFolder } = runStorybookOptions; @@ -617,7 +531,7 @@ export default class StorybookPlugin implements IHeftTaskPlugin; } -const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpecification = +type IStaticAssetsCopyConfiguration = TypeScriptBuildConfiguration['staticAssetsToCopy']; + +const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpecification = { projectRelativeFilePath: 'config/typescript.json', jsonSchemaObject: typescriptConfigSchema, @@ -159,8 +93,8 @@ const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpeci export async function loadTypeScriptConfigurationFileAsync( heftConfiguration: HeftConfiguration, terminal: ITerminal -): Promise { - return await heftConfiguration.tryLoadProjectConfigurationFileAsync( +): Promise { + return await heftConfiguration.tryLoadProjectConfigurationFileAsync( TYPESCRIPT_LOADER_CONFIG, terminal ); @@ -175,7 +109,7 @@ const _partialTsconfigFilePromiseCache: Map { const buildFolderPath: string = heftConfiguration.buildFolderPath; @@ -241,7 +175,7 @@ export async function loadPartialTsconfigFileAsync( } interface ITypeScriptConfigurationJsonAndPartialTsconfigFile { - typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined; + typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined; partialTsconfigFile: IPartialTsconfig | undefined; } @@ -396,7 +330,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { ): Promise { const terminal: ITerminal = taskSession.logger.terminal; - const typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined = + const typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined = await loadTypeScriptConfigurationFileAsync(heftConfiguration, terminal); const partialTsconfigFile: IPartialTsconfig | undefined = await loadPartialTsconfigFileAsync( diff --git a/heft-plugins/heft-typescript-plugin/src/index.ts b/heft-plugins/heft-typescript-plugin/src/index.ts index 4b727d4baa1..dcf65151e67 100644 --- a/heft-plugins/heft-typescript-plugin/src/index.ts +++ b/heft-plugins/heft-typescript-plugin/src/index.ts @@ -8,14 +8,15 @@ */ export type { - IEmitModuleKind, - IStaticAssetsCopyConfiguration, - ITypeScriptConfigurationJson, IPartialTsconfigCompilerOptions, IPartialTsconfig, IChangedFilesHookOptions, ITypeScriptPluginAccessor } from './TypeScriptPlugin'; +/** + * @beta + */ +export type { TypeScriptBuildConfiguration } from './schemas/typescript.schema.json.d.ts'; export { PLUGIN_NAME as TypeScriptPluginName, diff --git a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json index d42ff1f0476..6b7f99a2eb4 100644 --- a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json +++ b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "TypeScript Build Configuration", - "description": "Defines optional options for TypeScript build.", + "description": "Defines optional options for TypeScript build.\n\n@beta", "type": "object", "additionalProperties": false, diff --git a/heft-plugins/heft-webpack4-plugin/heft-plugin.json b/heft-plugins/heft-webpack4-plugin/heft-plugin.json index 32f5ce328d0..ca101b5e92d 100644 --- a/heft-plugins/heft-webpack4-plugin/heft-plugin.json +++ b/heft-plugins/heft-webpack4-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "webpack4-plugin", "entryPoint": "./lib-commonjs/Webpack4Plugin", - "optionsSchema": "./lib-commonjs/schemas/heft-webpack4-plugin.schema.json", + "optionsSchema": "./lib-commonjs/schemas/heft-webpack4-plugin-options.schema.json", "parameterScope": "webpack4", "parameters": [ diff --git a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts index 644f585c8e8..5ff4d499b52 100644 --- a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts +++ b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts @@ -30,6 +30,7 @@ import { type IWatchFileSystem, OverrideNodeWatchFSPlugin } from './DeferredWatchFileSystem'; +import type { Webpack4PluginConfiguration } from './schemas/heft-webpack4-plugin-options.schema.json.d.ts'; type ExtendedWatching = TWebpack.Watching & { resume: () => void; @@ -59,11 +60,6 @@ type ExtendedMultiCompiler = TWebpack.MultiCompiler & { watching: ExtendedMultiWatching; }; -export interface IWebpackPluginOptions { - devConfigurationPath?: string | undefined; - configurationPath?: string | undefined; -} - const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; const WEBPACK_PACKAGE_NAME: 'webpack' = 'webpack'; const WEBPACK_DEV_SERVER_PACKAGE_NAME: 'webpack-dev-server' = 'webpack-dev-server'; @@ -73,7 +69,7 @@ const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-d /** * @internal */ -export default class Webpack4Plugin implements IHeftTaskPlugin { +export default class Webpack4Plugin implements IHeftTaskPlugin { private _accessor: IWebpackPluginAccessor | undefined; private _isServeMode: boolean = false; private _webpack: typeof TWebpack | undefined; @@ -101,7 +97,7 @@ export default class Webpack4Plugin implements IHeftTaskPlugin void ): Promise { if (this._webpackConfiguration === false) { @@ -189,7 +185,7 @@ export default class Webpack4Plugin implements IHeftTaskPlugin { this._validateEnvironmentVariable(taskSession); if (taskSession.parameters.watch || this._isServeMode) { @@ -235,7 +231,7 @@ export default class Webpack4Plugin implements IHeftTaskPlugin void ): Promise { // Save a handle to the original promise, since the this-scoped promise will be replaced whenever diff --git a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts index cd1b0c36052..7e5a6ecda94 100644 --- a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts +++ b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts @@ -8,7 +8,7 @@ import type * as TWebpack from 'webpack'; import { FileSystem } from '@rushstack/node-core-library'; import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; -import type { IWebpackPluginOptions } from './Webpack4Plugin'; +import type { Webpack4PluginConfiguration } from './schemas/heft-webpack4-plugin-options.schema.json.d.ts'; import { PLUGIN_NAME, STAGE_LOAD_LOCAL_CONFIG, @@ -47,7 +47,7 @@ const DEFAULT_WEBPACK_DEV_CONFIG_PATH: './webpack.dev.config.js' = './webpack.de */ export async function tryLoadWebpackConfigurationAsync( options: ILoadWebpackConfigurationOptions, - pluginOptions: IWebpackPluginOptions + pluginOptions: Webpack4PluginConfiguration ): Promise { const { taskSession, hooks, _tryLoadConfigFileAsync = tryLoadWebpackConfigurationFileAsync } = options; const { logger } = taskSession; @@ -108,7 +108,7 @@ export async function tryLoadWebpackConfigurationAsync( */ export async function tryLoadWebpackConfigurationFileAsync( options: ILoadWebpackConfigurationOptions, - pluginOptions: IWebpackPluginOptions + pluginOptions: Webpack4PluginConfiguration ): Promise { // TODO: Eventually replace this custom logic with a call to this utility in in webpack-cli: // https://github.com/webpack/webpack-cli/blob/next/packages/webpack-cli/lib/groups/ConfigGroup.js diff --git a/heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin.schema.json b/heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin.schema.json rename to heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin-options.schema.json diff --git a/heft-plugins/heft-webpack5-plugin/heft-plugin.json b/heft-plugins/heft-webpack5-plugin/heft-plugin.json index 165299e71d3..cbaa3c47d4c 100644 --- a/heft-plugins/heft-webpack5-plugin/heft-plugin.json +++ b/heft-plugins/heft-webpack5-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "webpack5-plugin", "entryPoint": "./lib-commonjs/Webpack5Plugin", - "optionsSchema": "./lib-commonjs/schemas/heft-webpack5-plugin.schema.json", + "optionsSchema": "./lib-commonjs/schemas/heft-webpack5-plugin-options.schema.json", "parameterScope": "webpack5", "parameters": [ diff --git a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts index 59bf0c4b725..87a8b622aa4 100644 --- a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts +++ b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts @@ -26,11 +26,8 @@ import { } from './shared'; import { tryLoadWebpackConfigurationAsync } from './WebpackConfigurationLoader'; import { type DeferredWatchFileSystem, OverrideNodeWatchFSPlugin } from './DeferredWatchFileSystem'; +import type { Webpack5PluginConfiguration } from './schemas/heft-webpack5-plugin-options.schema.json.d.ts'; -export interface IWebpackPluginOptions { - devConfigurationPath?: string | undefined; - configurationPath?: string | undefined; -} const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; const WEBPACK_PACKAGE_NAME: 'webpack' = 'webpack'; const WEBPACK_DEV_SERVER_PACKAGE_NAME: 'webpack-dev-server' = 'webpack-dev-server'; @@ -40,7 +37,7 @@ const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-d /** * @internal */ -export default class Webpack5Plugin implements IHeftTaskPlugin { +export default class Webpack5Plugin implements IHeftTaskPlugin { private _accessor: IWebpackPluginAccessor | undefined; private _isServeMode: boolean = false; private _webpack: typeof TWebpack | undefined; @@ -68,7 +65,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin void ): Promise { if (this._webpackConfiguration === false) { @@ -170,7 +167,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { this._validateEnvironmentVariable(taskSession); if (taskSession.parameters.watch || this._isServeMode) { @@ -218,7 +215,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin void ): Promise { // Save a handle to the original promise, since the this-scoped promise will be replaced whenever diff --git a/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts index c8516cfbe1f..2193d0adb50 100644 --- a/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts +++ b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts @@ -8,7 +8,7 @@ import type * as TWebpack from 'webpack'; import { FileSystem } from '@rushstack/node-core-library'; import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; -import type { IWebpackPluginOptions } from './Webpack5Plugin'; +import type { Webpack5PluginConfiguration } from './schemas/heft-webpack5-plugin-options.schema.json.d.ts'; import { PLUGIN_NAME, STAGE_LOAD_LOCAL_CONFIG, @@ -47,7 +47,7 @@ const DEFAULT_WEBPACK_DEV_CONFIG_PATH: './webpack.dev.config.js' = './webpack.de */ export async function tryLoadWebpackConfigurationAsync( options: ILoadWebpackConfigurationOptions, - pluginOptions: IWebpackPluginOptions + pluginOptions: Webpack5PluginConfiguration ): Promise { const { taskSession, hooks, _tryLoadConfigFileAsync = tryLoadWebpackConfigurationFileAsync } = options; const { logger } = taskSession; @@ -108,7 +108,7 @@ export async function tryLoadWebpackConfigurationAsync( */ export async function tryLoadWebpackConfigurationFileAsync( options: ILoadWebpackConfigurationOptions, - pluginOptions: IWebpackPluginOptions + pluginOptions: Webpack5PluginConfiguration ): Promise { // TODO: Eventually replace this custom logic with a call to this utility in in webpack-cli: // https://github.com/webpack/webpack-cli/blob/next/packages/webpack-cli/lib/groups/ConfigGroup.js diff --git a/heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin.schema.json b/heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin.schema.json rename to heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin-options.schema.json From 3d11432bb2dd83255068abaee1de6b08600ac232 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Wed, 18 Feb 2026 12:54:15 -0800 Subject: [PATCH 08/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- heft-plugins/heft-json-schema-typings-plugin/config/heft.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/heft.json b/heft-plugins/heft-json-schema-typings-plugin/config/heft.json index 0e52387039a..8d1359f022f 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/config/heft.json +++ b/heft-plugins/heft-json-schema-typings-plugin/config/heft.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - "extends": "local-node-rig/profiles/default/config/heft.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", "phasesByName": { "build": { From 2a021eb4872a7fd1a3eee80ba09e7337fecc0def Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Wed, 18 Feb 2026 18:52:25 -0800 Subject: [PATCH 09/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- rigs/decoupled-local-node-rig/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rigs/decoupled-local-node-rig/package.json b/rigs/decoupled-local-node-rig/package.json index 540a3d32b45..aff7b2d86f4 100644 --- a/rigs/decoupled-local-node-rig/package.json +++ b/rigs/decoupled-local-node-rig/package.json @@ -27,6 +27,7 @@ "eslint-plugin-react-hooks": "5.2.0", "eslint": "~9.37.0", "jest-junit": "12.3.0", - "typescript": "~5.8.2" + "typescript": "~5.8.2", + "eslint-import-resolver-node": "0.3.9" } } From a9c47a0279aac1ad11bd345a0ad000bc52e71abc Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Thu, 19 Feb 2026 20:08:23 -0800 Subject: [PATCH 10/40] fixup! Use schemas for typings in the heft plugins. --- .../src/LocalizationTypingsPlugin.ts | 2 +- ...ft-localization-typings-plugin.schema.json | 1 + .../heft-rspack-plugin/heft-plugin.json | 2 +- .../src/RspackConfigurationLoader.ts | 2 +- .../heft-rspack-plugin/src/RspackPlugin.ts | 9 ++---- ...=> heft-rspack-plugin-options.schema.json} | 0 .../src/TypeScriptBuilder.ts | 7 ++-- .../src/schemas/typescript.schema.json | 32 +++++++++++-------- 8 files changed, 30 insertions(+), 25 deletions(-) rename heft-plugins/heft-rspack-plugin/src/schemas/{heft-rspack-plugin.schema.json => heft-rspack-plugin-options.schema.json} (100%) diff --git a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts index ac29a4db12c..2e9d80e2a4e 100644 --- a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts +++ b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts @@ -11,7 +11,7 @@ import type { } from '@rushstack/heft'; import { TypingsGenerator } from '@rushstack/localization-utilities'; -import type { Options as ILocalizationTypingsPluginOptions } from './schemas/options.schema.json.d.ts'; +import type { HeftLocalizationTypingsPluginOptions as ILocalizationTypingsPluginOptions } from './schemas/heft-localization-typings-plugin.schema.json.d.ts'; const PLUGIN_NAME: 'localization-typings-plugin' = 'localization-typings-plugin'; diff --git a/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json b/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json index ae9cf8f52c3..05d3f1f0afe 100644 --- a/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json +++ b/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json @@ -1,5 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Localization Typings Plugin Options", "type": "object", "additionalProperties": false, diff --git a/heft-plugins/heft-rspack-plugin/heft-plugin.json b/heft-plugins/heft-rspack-plugin/heft-plugin.json index cec21c0dfc3..f230ed4f925 100644 --- a/heft-plugins/heft-rspack-plugin/heft-plugin.json +++ b/heft-plugins/heft-rspack-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "rspack-plugin", "entryPoint": "./lib-commonjs/RspackPlugin", - "optionsSchema": "./lib-commonjs/schemas/heft-rspack-plugin.schema.json", + "optionsSchema": "./lib-commonjs/schemas/heft-rspack-plugin-options.schema.json", "parameterScope": "rspack", "parameters": [ diff --git a/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts b/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts index 98a6d37fdcf..bc8ad12a344 100644 --- a/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts +++ b/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts @@ -9,7 +9,7 @@ import type * as TRspack from '@rspack/core'; import type { HeftConfiguration, IHeftTaskSession } from '@rushstack/heft'; import { FileSystem } from '@rushstack/node-core-library'; -import type { IRspackPluginOptions } from './RspackPlugin'; +import type { RspackPluginConfiguration as IRspackPluginOptions } from './schemas/heft-rspack-plugin-options.schema.json.d.ts'; import { type IRspackConfiguration, type IRspackConfigurationFnEnvironment, diff --git a/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts index 67546a3e345..0a8682e9b20 100644 --- a/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts +++ b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts @@ -27,11 +27,8 @@ import { } from './shared'; import { tryLoadRspackConfigurationAsync } from './RspackConfigurationLoader'; import { type DeferredWatchFileSystem, OverrideNodeWatchFSPlugin } from './DeferredWatchFileSystem'; +import type { RspackPluginConfiguration as IRspackPluginOptions } from './schemas/heft-rspack-plugin-options.schema.json.d.ts'; -export interface IRspackPluginOptions { - devConfigurationPath?: string | undefined; - configurationPath?: string | undefined; -} const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; const RSPACK_PACKAGE_NAME: '@rspack/core' = '@rspack/core'; const RSPACK_DEV_SERVER_PACKAGE_NAME: '@rspack/dev-server' = '@rspack/dev-server'; @@ -426,9 +423,7 @@ export default class RspackPlugin implements IHeftTaskPlugin ({ ...emitKind, outFolderName: Path.convertToSlashes( diff --git a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json index 6b7f99a2eb4..64b8d25aad1 100644 --- a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json +++ b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json @@ -6,6 +6,24 @@ "additionalProperties": false, + "definitions": { + "additionalModuleKindToEmit": { + "type": "object", + "properties": { + "moduleKind": { + "type": "string", + "enum": ["commonjs", "amd", "umd", "system", "es2015", "esnext"] + }, + + "outFolderName": { + "type": "string", + "pattern": "[^\\\\\\/]" + } + }, + "required": ["moduleKind", "outFolderName"] + } + }, + "properties": { "$schema": { "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", @@ -21,19 +39,7 @@ "type": "array", "description": "If provided, emit these module kinds in addition to the modules specified in the tsconfig. Note that this option only applies to the main tsconfig.json configuration.", "items": { - "type": "object", - "properties": { - "moduleKind": { - "type": "string", - "enum": ["commonjs", "amd", "umd", "system", "es2015", "esnext"] - }, - - "outFolderName": { - "type": "string", - "pattern": "[^\\\\\\/]" - } - }, - "required": ["moduleKind", "outFolderName"] + "$ref": "#/definitions/additionalModuleKindToEmit" } }, From 862edc14733805357adb9535541615baf6bf8876 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Thu, 19 Feb 2026 20:31:20 -0800 Subject: [PATCH 11/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- .../decoupled-local-node-rig/profiles/default/tsconfig-base.json | 1 + 1 file changed, 1 insertion(+) diff --git a/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json index a16e53d7ca4..025cbf19728 100644 --- a/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json +++ b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json @@ -10,6 +10,7 @@ "outDir": "${configDir}/lib-commonjs", "declarationDir": "${configDir}/lib-dts", + "rootDir": "${configDir}/src", "rootDirs": ["${configDir}/src", "${configDir}/temp/schema-ts"], "types": ["heft-jest", "node"], From cd9781c0d085b19c1be7d9543fb5a11fe0f5d2a8 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Thu, 19 Feb 2026 20:43:00 -0800 Subject: [PATCH 12/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- rigs/decoupled-local-node-rig/profiles/default/config/heft.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json index c25581d099b..2d38bdac879 100644 --- a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json +++ b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json @@ -21,7 +21,7 @@ "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", "options": { - "generatedTsFolders": ["temp/schema-ts", "lib"] + "generatedTsFolders": ["temp/schema-ts", "lib", "lib-dts"] } } } From 70ccbfdc99ad87aaa05efc840cca639075c868e4 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 12:34:27 -0800 Subject: [PATCH 13/40] Rename heft-json-schema-typings-plugin.schema.json to heft-json-schema-typings-plugin-options.schema.json. --- heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json | 2 +- .../src/JsonSchemaTypingsPlugin.ts | 2 +- ...json => heft-json-schema-typings-plugin-options.schema.json} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename heft-plugins/heft-json-schema-typings-plugin/src/schemas/{heft-json-schema-typings-plugin.schema.json => heft-json-schema-typings-plugin-options.schema.json} (100%) diff --git a/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json b/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json index 9d40b9828d2..69601f333cb 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json +++ b/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json @@ -5,7 +5,7 @@ { "pluginName": "json-schema-typings-plugin", "entryPoint": "./lib-commonjs/JsonSchemaTypingsPlugin", - "optionsSchema": "./lib-commonjs/schemas/heft-json-schema-typings-plugin.schema.json" + "optionsSchema": "./lib-commonjs/schemas/heft-json-schema-typings-plugin-options.schema.json" } ] } diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts index 53be89d56fd..3d43b06e638 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts @@ -11,7 +11,7 @@ import type { import type { ITerminal } from '@rushstack/terminal'; import { JsonSchemaTypingsGenerator } from './JsonSchemaTypingsGenerator'; -import type { Options as IJsonSchemaTypingsPluginOptions } from './schemas/options.schema.json.d.ts'; +import type { HeftJsonSchemaTypingsPluginOptions as IJsonSchemaTypingsPluginOptions } from './schemas/heft-json-schema-typings-plugin-options.schema.json'; const PLUGIN_NAME: 'json-schema-typings-plugin' = 'json-schema-typings-plugin'; diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin-options.schema.json similarity index 100% rename from heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin.schema.json rename to heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin-options.schema.json From 7846150aacd9ec0ff3c1b28853b80bad4b293310 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 12:40:42 -0800 Subject: [PATCH 14/40] Rush update. --- .../build-tests-subspace/pnpm-lock.yaml | 168 +++++++++++++++--- .../build-tests-subspace/repo-state.json | 4 +- .../config/subspaces/default/pnpm-lock.yaml | 51 +++++- .../config/subspaces/default/repo-state.json | 2 +- 4 files changed, 188 insertions(+), 37 deletions(-) diff --git a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml index cf41ad60f8c..334ce2cdea8 100644 --- a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml +++ b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml @@ -166,6 +166,10 @@ importers: packages: + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} @@ -422,14 +426,6 @@ packages: '@types/node': optional: true - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -555,6 +551,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} @@ -844,7 +843,7 @@ packages: '@rushstack/heft-api-extractor-plugin@file:../../../heft-plugins/heft-api-extractor-plugin': resolution: {directory: ../../../heft-plugins/heft-api-extractor-plugin, type: directory} peerDependencies: - '@rushstack/heft': 1.2.0 + '@rushstack/heft': 1.2.2 '@rushstack/heft-config-file@file:../../../libraries/heft-config-file': resolution: {directory: ../../../libraries/heft-config-file, type: directory} @@ -853,7 +852,7 @@ packages: '@rushstack/heft-jest-plugin@file:../../../heft-plugins/heft-jest-plugin': resolution: {directory: ../../../heft-plugins/heft-jest-plugin, type: directory} peerDependencies: - '@rushstack/heft': ^1.2.0 + '@rushstack/heft': ^1.2.2 jest-environment-jsdom: ^29.5.0 jest-environment-node: ^29.5.0 peerDependenciesMeta: @@ -862,20 +861,25 @@ packages: jest-environment-node: optional: true + '@rushstack/heft-json-schema-typings-plugin@file:../../../heft-plugins/heft-json-schema-typings-plugin': + resolution: {directory: ../../../heft-plugins/heft-json-schema-typings-plugin, type: directory} + peerDependencies: + '@rushstack/heft': 1.2.2 + '@rushstack/heft-lint-plugin@file:../../../heft-plugins/heft-lint-plugin': resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} peerDependencies: - '@rushstack/heft': 1.2.0 + '@rushstack/heft': 1.2.2 '@rushstack/heft-node-rig@file:../../../rigs/heft-node-rig': resolution: {directory: ../../../rigs/heft-node-rig, type: directory} peerDependencies: - '@rushstack/heft': ^1.2.0 + '@rushstack/heft': ^1.2.2 '@rushstack/heft-typescript-plugin@file:../../../heft-plugins/heft-typescript-plugin': resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} peerDependencies: - '@rushstack/heft': 1.2.0 + '@rushstack/heft': 1.2.2 '@rushstack/heft@file:../../../apps/heft': resolution: {directory: ../../../apps/heft, type: directory} @@ -955,6 +959,14 @@ packages: '@rushstack/ts-command-line@file:../../../libraries/ts-command-line': resolution: {directory: ../../../libraries/ts-command-line, type: directory} + '@rushstack/typings-generator@file:../../../libraries/typings-generator': + resolution: {directory: ../../../libraries/typings-generator, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -1021,6 +1033,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/lodash@4.17.23': + resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} + '@types/node@20.17.19': resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} @@ -1363,6 +1378,10 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -1456,6 +1475,10 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -1917,6 +1940,15 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + figures@3.0.0: resolution: {integrity: sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==} engines: {node: '>=8'} @@ -2193,6 +2225,10 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-boolean-object@1.2.2: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} @@ -2535,6 +2571,11 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -2683,10 +2724,6 @@ packages: resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} engines: {node: '>=8'} - minimatch@10.1.2: - resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} - engines: {node: 20 || >=22} - minimatch@10.2.1: resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} engines: {node: 20 || >=22} @@ -2958,6 +2995,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + pretty-error@4.0.0: resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} @@ -3020,6 +3062,10 @@ packages: resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} deprecated: This functionality has been moved to @npmcli/fs + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -3381,6 +3427,10 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -3607,6 +3657,12 @@ packages: snapshots: + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -3896,12 +3952,6 @@ snapshots: optionalDependencies: '@types/node': 20.17.19 - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 @@ -4156,6 +4206,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jsdevtools/ono@7.1.3': {} + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 @@ -4672,6 +4724,15 @@ snapshots: - supports-color - ts-node + '@rushstack/heft-json-schema-typings-plugin@file:../../../heft-plugins/heft-json-schema-typings-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/typings-generator': file:../../../libraries/typings-generator(@types/node@20.17.19) + json-schema-to-typescript: 15.0.4 + transitivePeerDependencies: + - '@types/node' + '@rushstack/heft-lint-plugin@file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': dependencies: '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) @@ -4849,6 +4910,15 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@rushstack/typings-generator@file:../../../libraries/typings-generator(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + chokidar: 3.6.0 + fast-glob: 3.3.3 + optionalDependencies: + '@types/node': 20.17.19 + '@sinclair/typebox@0.27.8': {} '@sinclair/typebox@0.34.48': {} @@ -4927,6 +4997,8 @@ snapshots: '@types/json5@0.0.29': {} + '@types/lodash@4.17.23': {} + '@types/node@20.17.19': dependencies: undici-types: 6.19.8 @@ -5487,6 +5559,8 @@ snapshots: dependencies: is-windows: 1.0.2 + binary-extensions@2.3.0: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -5587,6 +5661,18 @@ snapshots: chardet@2.1.1: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chownr@3.0.0: {} chrome-trace-event@1.0.4: {} @@ -6222,6 +6308,10 @@ snapshots: dependencies: bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + figures@3.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -6512,6 +6602,10 @@ snapshots: dependencies: has-bigints: 1.1.0 + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-boolean-object@1.2.2: dependencies: call-bound: 1.0.4 @@ -7077,6 +7171,18 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.23 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.23 + minimist: 1.2.8 + prettier: 3.8.1 + tinyglobby: 0.2.15 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -7166,6 +7272,7 @@ snapshots: '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@20.17.19) '@rushstack/eslint-patch': file:../../../eslint/eslint-patch '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-json-schema-typings-plugin': file:../../../heft-plugins/heft-json-schema-typings-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) '@types/heft-jest': 1.0.1 '@types/node': 20.17.19 @@ -7252,10 +7359,6 @@ snapshots: mimic-fn@3.1.0: {} - minimatch@10.1.2: - dependencies: - '@isaacs/brace-expansion': 5.0.1 - minimatch@10.2.1: dependencies: brace-expansion: 5.0.2 @@ -7542,6 +7645,8 @@ snapshots: prelude-ls@1.2.1: {} + prettier@3.8.1: {} + pretty-error@4.0.0: dependencies: lodash: 4.17.23 @@ -7626,6 +7731,10 @@ snapshots: graceful-fs: 4.2.11 once: 1.4.0 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -8026,6 +8135,11 @@ snapshots: through@2.3.8: {} + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tmpl@1.0.5: {} to-regex-range@5.0.1: diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json index 63190118101..4c6bad01b93 100644 --- a/common/config/subspaces/build-tests-subspace/repo-state.json +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -1,6 +1,6 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "970749d264e69bf8ff6a9fb6007b379832c9ac09", + "pnpmShrinkwrapHash": "6972816c9d6f6511a8df09c9ad08d647c6c16ff1", "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9", - "packageJsonInjectedDependenciesHash": "0124c511e290517bf309935112b2dbab981575bb" + "packageJsonInjectedDependenciesHash": "57a16de99cf9519f84d13159d3a087d48ae710d7" } diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index b992ec346ba..4968bf8004e 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -3280,12 +3280,12 @@ importers: '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: specifier: ~9.37.0 version: 9.37.0 - local-node-rig: - specifier: workspace:* - version: link:../../rigs/local-node-rig ../../../heft-plugins/heft-lint-plugin: dependencies: @@ -4481,12 +4481,12 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: specifier: ~9.37.0 version: 9.37.0 - local-node-rig: - specifier: workspace:* - version: link:../../rigs/local-node-rig ../../../libraries/worker-pool: devDependencies: @@ -4585,6 +4585,9 @@ importers: '@rushstack/heft': specifier: 1.2.0 version: 1.2.0(@types/node@20.17.19) + '@rushstack/heft-json-schema-typings-plugin': + specifier: 1.2.0 + version: 1.2.0(@rushstack/heft@1.2.0(@types/node@20.17.19))(@types/node@20.17.19) '@rushstack/heft-node-rig': specifier: 2.11.20 version: 2.11.20(@rushstack/heft@1.2.0(@types/node@20.17.19))(@types/node@20.17.19)(jest-environment-jsdom@29.5.0) @@ -4801,6 +4804,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@rushstack/heft-json-schema-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-json-schema-typings-plugin '@rushstack/heft-node-rig': specifier: workspace:* version: link:../heft-node-rig @@ -9021,6 +9027,11 @@ packages: jest-environment-node: optional: true + '@rushstack/heft-json-schema-typings-plugin@1.2.0': + resolution: {integrity: sha512-mIJplAzTnhq4Z5TND/ZRMElrGP+8MtlACwvFBL4WfXjnbf96O5LH3m+HtEKpTGun9xuai8YWM2MY0etlcsDSPQ==} + peerDependencies: + '@rushstack/heft': 1.2.0 + '@rushstack/heft-lint-plugin@1.2.0': resolution: {integrity: sha512-Z7AxUTUHBH+MNmNAdBGTn7TawMLP5tU50hi+E9g/s0WaoHm6TD7CqrI1kPwELGZl4fnqPQHQsgkXC4P94FDDWQ==} peerDependencies: @@ -9101,6 +9112,14 @@ packages: '@rushstack/ts-command-line@5.3.0': resolution: {integrity: sha512-4hneaVxA5zPC8cwUGZtdvCUzGbW8A+b+qrBK3hYs/xO7TyWkgAMKxq/6FJY91fPG8awgmJ+s1w8GuqNXgxsTyw==} + '@rushstack/typings-generator@0.16.0': + resolution: {integrity: sha512-YH1IAbmi/XVEc/R8LwdZ2THhjzb0mdQjQVdaiH22alSryWNU6/vP6KAI5XY98iCnFyHd/tmZkIbj1StFf7pHhQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + '@rushstack/webpack-plugin-utilities@0.3.16': resolution: {integrity: sha512-0Xb0GESYEyv6Q7hzANZ8RIWa3seiJiCKBNNG83znQwMZ9l0bfnoJzZ3cYODkofoK0E8/nr4hTsn/pWKommf6Mw==} peerDependencies: @@ -24041,6 +24060,15 @@ snapshots: - supports-color - ts-node + '@rushstack/heft-json-schema-typings-plugin@1.2.0(@rushstack/heft@1.2.0(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@rushstack/heft': 1.2.0(@types/node@20.17.19) + '@rushstack/node-core-library': 5.20.0(@types/node@20.17.19) + '@rushstack/typings-generator': 0.16.0(@types/node@20.17.19) + json-schema-to-typescript: 15.0.4 + transitivePeerDependencies: + - '@types/node' + '@rushstack/heft-lint-plugin@1.2.0(@rushstack/heft@1.2.0(@types/node@20.17.19))(@types/node@20.17.19)': dependencies: '@rushstack/heft': 1.2.0(@types/node@20.17.19) @@ -24252,6 +24280,15 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@rushstack/typings-generator@0.16.0(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': 5.20.0(@types/node@20.17.19) + '@rushstack/terminal': 0.22.0(@types/node@20.17.19) + chokidar: 3.6.0 + fast-glob: 3.3.3 + optionalDependencies: + '@types/node': 20.17.19 + '@rushstack/webpack-plugin-utilities@0.3.16(@types/webpack@4.41.32)(webpack@4.47.0)': dependencies: memfs: 3.4.3 @@ -30145,7 +30182,7 @@ snapshots: eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) '@eslint-community/regexpp': 4.12.2 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.1 diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index 9b13d6b9d1a..25970caf43b 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "425296840bc63395649600913e66041583bdc287", + "pnpmShrinkwrapHash": "07d9d2f7d978e6063fed9d72f4b58218ffdff71d", "preferredVersionsHash": "93bf435032db8da4a18734f1eaa359c12ad147c1" } From b0fb05ef3c4dbd92a30f0f4efa5a05417c337d93 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 12:56:28 -0800 Subject: [PATCH 15/40] fixup! Rush update. --- common/config/subspaces/default/pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index 4968bf8004e..2f446ba1698 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -4840,6 +4840,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@rushstack/heft-json-schema-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-json-schema-typings-plugin '@rushstack/heft-web-rig': specifier: workspace:* version: link:../heft-web-rig From cf4fbed5a098d1ec69c1e848688d16a1e7cb5698 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 12:56:26 -0800 Subject: [PATCH 16/40] fixup! Use the JSON schema plugin in local-node-rig and local-web-rig. --- rigs/local-web-rig/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/rigs/local-web-rig/package.json b/rigs/local-web-rig/package.json index b8b752f9fe7..58d5230980c 100644 --- a/rigs/local-web-rig/package.json +++ b/rigs/local-web-rig/package.json @@ -11,6 +11,7 @@ "dependencies": { "@microsoft/api-extractor": "workspace:*", "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft-json-schema-typings-plugin": "workspace:*", "@rushstack/heft-web-rig": "workspace:*", "@rushstack/heft": "workspace:*", "@types/heft-jest": "1.0.1", From fb924e47fef73ca139a10fb905b1429acac4847c Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:21:23 -0800 Subject: [PATCH 17/40] Wrap things that look like TSDoc tags in backtick quotes in schemas. --- .../src/schemas/api-extractor.schema.json | 12 ++++++------ .../src/schemas/heft-jest-plugin-options.schema.json | 2 +- .../src/schemas/heft-lint-plugin-options.schema.json | 2 +- .../src/schemas/heft-sass-plugin-options.schema.json | 2 +- .../src/schemas/storybook-plugin-options.schema.json | 2 +- .../src/schemas/approved-packages.schema.json | 2 +- .../rush-lib/src/schemas/pnpm-config.schema.json | 4 ++-- libraries/rush-lib/src/schemas/rush.schema.json | 12 ++++++------ 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/api-extractor/src/schemas/api-extractor.schema.json b/apps/api-extractor/src/schemas/api-extractor.schema.json index 20773498c59..8bd8fdaef13 100644 --- a/apps/api-extractor/src/schemas/api-extractor.schema.json +++ b/apps/api-extractor/src/schemas/api-extractor.schema.json @@ -14,7 +14,7 @@ }, "projectFolder": { - "description": "Determines the \"\" token that can be used with other config file settings. The project folder typically contains the tsconfig.json and package.json config files, but the path is user-defined. The path is resolved relative to the folder of the config file that contains the setting. The default value for \"projectFolder\" is the token \"\", which means the folder is determined using the following heuristics:\n\nIf the config/rig.json system is used (as defined by @rushstack/rig-package), then the \"\" value will be the package folder that referenced the rig.\n\nOtherwise, the \"\" value is determined by traversing parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error will be reported.", + "description": "Determines the \"\" token that can be used with other config file settings. The project folder typically contains the tsconfig.json and package.json config files, but the path is user-defined. The path is resolved relative to the folder of the config file that contains the setting. The default value for \"projectFolder\" is the token \"\", which means the folder is determined using the following heuristics:\n\nIf the config/rig.json system is used (as defined by `@rushstack/rig-package`), then the \"\" value will be the package folder that referenced the rig.\n\nOtherwise, the \"\" value is determined by traversing parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error will be reported.", "type": "string" }, @@ -85,7 +85,7 @@ }, "reportVariants": { - "description": "To support different approval requirements for different API levels, multiple \"variants\" of the API report can be generated. The \"reportVariants\" setting specifies a list of variants to be generated. If omitted, by default only the \"complete\" variant will be generated, which includes all @internal, @alpha, @beta, and @public items. Other possible variants are \"alpha\" (@alpha + @beta + @public), \"beta\" (@beta + @public), and \"public\" (@public only).", + "description": "To support different approval requirements for different API levels, multiple \"variants\" of the API report can be generated. The \"reportVariants\" setting specifies a list of variants to be generated. If omitted, by default only the \"complete\" variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, and `@public` items. Other possible variants are \"alpha\" (`@alpha` + `@beta` + `@public`), \"beta\" (`@beta` + `@public`), and \"public\" (`@public` only).", "type": "array", "items": { "type": "string", @@ -109,7 +109,7 @@ }, "tagsToReport": { - "description": "Specifies a list of TSDoc tags that should be reported in the API report file for items whose documentation contains them. This can be used to include standard TSDoc tags or custom ones. Specified tag names must begin with \"@\". By default, the following tags are reported: [@sealed, @virtual, @override, @eventProperty, @deprecated]. Tags will appear in the order they are specified in this list. Note that an item's release tag will always reported; this behavior cannot be overridden.", + "description": "Specifies a list of TSDoc tags that should be reported in the API report file for items whose documentation contains them. This can be used to include standard TSDoc tags or custom ones. Specified tag names must begin with `@`. By default, the following tags are reported: [`@sealed`, `@virtual`, `@override`, `@eventProperty`, `@deprecated`]. Tags will appear in the order they are specified in this list. Note that an item's release tag will always reported; this behavior cannot be overridden.", "type": "object", "patternProperties": { "^@[^\\s]*$": { @@ -169,15 +169,15 @@ "type": "string" }, "alphaTrimmedFilePath": { - "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for an \"alpha\" release. This file will include only declarations that are marked as \"@public\", \"@beta\", or \"@alpha\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", + "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for an \"alpha\" release. This file will include only declarations that are marked as `@public`, `@beta`, or `@alpha`. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", "type": "string" }, "betaTrimmedFilePath": { - "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release. This file will include only declarations that are marked as \"@public\" or \"@beta\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", + "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release. This file will include only declarations that are marked as `@public` or `@beta`. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", "type": "string" }, "publicTrimmedFilePath": { - "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release. This file will include only declarations that are marked as \"@public\". If the path is an empty string, then this file will not be written. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", + "description": "Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release. This file will include only declarations that are marked as `@public`. If the path is an empty string, then this file will not be written. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \"\".", "type": "string" }, "omitTrimmingComments": { diff --git a/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json index af5a94ddccd..b6b8ba1e307 100644 --- a/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json +++ b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin-options.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Heft Jest Plugin Options Configuration", - "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-jest-plugin\".", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading `@rushstack/heft-jest-plugin`.", "type": "object", "additionalProperties": false, diff --git a/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json b/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json index 072d2c70df6..ea8d04020a2 100644 --- a/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json +++ b/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin-options.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Heft Lint Plugin Options Configuration", - "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-lint-plugin\".", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading `@rushstack/heft-lint-plugin`.", "type": "object", "additionalProperties": false, diff --git a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json index 0ff5b533c91..1aa5ebdf3ac 100644 --- a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json +++ b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin-options.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Sass Configuration", - "description": "This schema describes the \"config/sass.json\" config file used to configure \"@rushstack/heft-jest-plugin\", and also the \"options\" field that can be specified in heft.json when loading the plugin.", + "description": "This schema describes the \"config/sass.json\" config file used to configure `@rushstack/heft-jest-plugin`, and also the \"options\" field that can be specified in heft.json when loading the plugin.", "type": "object", "additionalProperties": false, diff --git a/heft-plugins/heft-storybook-plugin/src/schemas/storybook-plugin-options.schema.json b/heft-plugins/heft-storybook-plugin/src/schemas/storybook-plugin-options.schema.json index 0af3cda0e68..86195c623fa 100644 --- a/heft-plugins/heft-storybook-plugin/src/schemas/storybook-plugin-options.schema.json +++ b/heft-plugins/heft-storybook-plugin/src/schemas/storybook-plugin-options.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Heft Storybook Plugin Options Configuration", - "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-storybook-plugin\".", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading `@rushstack/heft-storybook-plugin`.", "type": "object", "additionalProperties": false, "required": ["storykitPackageName"], diff --git a/libraries/rush-lib/src/schemas/approved-packages.schema.json b/libraries/rush-lib/src/schemas/approved-packages.schema.json index 0bced3cfed0..4b41f5cab57 100644 --- a/libraries/rush-lib/src/schemas/approved-packages.schema.json +++ b/libraries/rush-lib/src/schemas/approved-packages.schema.json @@ -8,7 +8,7 @@ "type": "object", "properties": { "name": { - "description": "The name of the NPM package, e.g. \"@scope/example\"", + "description": "The name of the NPM package, e.g. `@scope/example`", "type": "string" }, "allowedCategories": { diff --git a/libraries/rush-lib/src/schemas/pnpm-config.schema.json b/libraries/rush-lib/src/schemas/pnpm-config.schema.json index 4646fe2398e..5d218eae909 100644 --- a/libraries/rush-lib/src/schemas/pnpm-config.schema.json +++ b/libraries/rush-lib/src/schemas/pnpm-config.schema.json @@ -62,7 +62,7 @@ "description": "The \"globalOverrides\" setting provides a simple mechanism for overriding version selections for all dependencies of all projects in the monorepo workspace. The settings are copied into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated by Rush during installation.\n\nOrder of precedence: `.pnpmfile.cjs` has the highest precedence, followed by `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, and `globalOverrides` has lowest precedence.\n\nPNPM documentation: https://pnpm.io/package_json#pnpmoverrides", "type": "object", "additionalProperties": { - "description": "You may specify the package the overridden dependency belongs to by separating the package selector from the dependency selector with a \">\", for example qar@1>zoo will only override the zoo dependency of qar@1, not for any other dependencies.", + "description": "You may specify the package the overridden dependency belongs to by separating the package selector from the dependency selector with a \">\", for example `qar@1>zoo` will only override the `zoo` dependency of `qar@1`, not for any other dependencies.", "type": "string" } }, @@ -206,7 +206,7 @@ }, "minimumReleaseAgeExclude": { - "description": "List of package names or patterns that are excluded from the minimumReleaseAge check. These packages will always install the newest version immediately, even if minimumReleaseAge is set. Supports glob patterns (e.g., \"@myorg/*\").\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude\n\nExample: [\"webpack\", \"react\", \"@myorg/*\"]", + "description": "List of package names or patterns that are excluded from the minimumReleaseAge check. These packages will always install the newest version immediately, even if minimumReleaseAge is set. Supports glob patterns (e.g., `@myorg/*`).\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude\n\nExample: [\"webpack\", \"react\", `@myorg/*`]", "type": "array", "items": { "description": "Package name or pattern", diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json index dce5fcaae37..50778d45495 100644 --- a/libraries/rush-lib/src/schemas/rush.schema.json +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -104,7 +104,7 @@ "type": "boolean" }, "resolutionStrategy": { - "description": "(Deprecated) Configures the strategy used to select versions during installation. This feature requires PNPM version 3.1 or newer. It corresponds to the \"--resolution-strategy\" command-line option for PNPM. Possible values are \"fast\" and \"fewer-dependencies\". PNPM's default is \"fast\", but this may be incompatible with certain packages, for example the \"@types\" packages from DefinitelyTyped. Rush's default is \"fewer-dependencies\", which causes PNPM to avoid installing a newer version if an already installed version can be reused; this is more similar to NPM's algorithm.", + "description": "(Deprecated) Configures the strategy used to select versions during installation. This feature requires PNPM version 3.1 or newer. It corresponds to the \"--resolution-strategy\" command-line option for PNPM. Possible values are \"fast\" and \"fewer-dependencies\". PNPM's default is \"fast\", but this may be incompatible with certain packages, for example the `@types` packages from DefinitelyTyped. Rush's default is \"fewer-dependencies\", which causes PNPM to avoid installing a newer version if an already installed version can be reused; this is more similar to NPM's algorithm.", "type": "string", "enum": ["fewer-dependencies", "fast"] }, @@ -156,7 +156,7 @@ } }, "ignoredNpmScopes": { - "description": "A list of NPM package scopes that will be excluded from review (e.g. \"@types\")", + "description": "A list of NPM package scopes that will be excluded from review (e.g. `@types`)", "type": "array", "items": { "type": "string", @@ -171,14 +171,14 @@ "type": "object", "properties": { "allowedEmailRegExps": { - "description": "A list of regular expressions describing allowable e-mail patterns for Git commits. They are case-insensitive anchored JavaScript RegExps. Example: \".*@example\\.com\"", + "description": "A list of regular expressions describing allowable e-mail patterns for Git commits. They are case-insensitive anchored JavaScript RegExps. Example: `.*@example\\.com`", "type": "array", "items": { "type": "string" } }, "sampleEmail": { - "description": "An example valid e-mail address for \"Mr. Example\" that conforms to one of the allowedEmailRegExps. Example: \"mr-example@contoso\\.com\"", + "description": "An example valid e-mail address for \"Mr. Example\" that conforms to one of the allowedEmailRegExps. Example: `mr-example@contoso\\.com`", "type": "string" }, "versionBumpCommitMessage": { @@ -249,7 +249,7 @@ "type": "boolean" }, "allowedProjectTags": { - "description": "This is an optional, but recommended, list of allowed tags that can be applied to Rush projects using the \"tags\" setting in this file. This list is useful for preventing mistakes such as misspelling, and it also provides a centralized place to document your tags. If \"allowedProjectTags\" list is not specified, then any valid tag is allowed. A tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "description": "This is an optional, but recommended, list of allowed tags that can be applied to Rush projects using the \"tags\" setting in this file. This list is useful for preventing mistakes such as misspelling, and it also provides a centralized place to document your tags. If \"allowedProjectTags\" list is not specified, then any valid tag is allowed. A tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and `@` characters.", "type": "array", "items": { "type": "string", @@ -305,7 +305,7 @@ "type": "string" }, "tags": { - "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and `@` characters.", "type": "array", "items": { "type": "string", From d0918223fe7cf54b0022dac93190e3dca89f56b6 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:28:44 -0800 Subject: [PATCH 18/40] fixup! Use the JSON schema plugin in local-node-rig and local-web-rig. --- rigs/local-node-rig/profiles/default/config/heft.json | 3 ++- rigs/local-web-rig/profiles/app/config/heft.json | 3 ++- rigs/local-web-rig/profiles/library/config/heft.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/rigs/local-node-rig/profiles/default/config/heft.json b/rigs/local-node-rig/profiles/default/config/heft.json index 049789bee4b..c3f6c74be99 100644 --- a/rigs/local-node-rig/profiles/default/config/heft.json +++ b/rigs/local-node-rig/profiles/default/config/heft.json @@ -21,7 +21,8 @@ "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", "options": { - "generatedTsFolders": ["temp/schema-ts", "lib"] + "generatedTsFolders": ["temp/schema-ts", "lib-dts"], + "formatWithPrettier": true } } }, diff --git a/rigs/local-web-rig/profiles/app/config/heft.json b/rigs/local-web-rig/profiles/app/config/heft.json index 39cce434bd5..18b5e9c5913 100644 --- a/rigs/local-web-rig/profiles/app/config/heft.json +++ b/rigs/local-web-rig/profiles/app/config/heft.json @@ -21,7 +21,8 @@ "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", "options": { - "generatedTsFolders": ["temp/schema-ts", "lib"] + "generatedTsFolders": ["temp/schema-ts", "lib-dts"], + "formatWithPrettier": true } } }, diff --git a/rigs/local-web-rig/profiles/library/config/heft.json b/rigs/local-web-rig/profiles/library/config/heft.json index 648b8daa61c..91d18f13ef5 100644 --- a/rigs/local-web-rig/profiles/library/config/heft.json +++ b/rigs/local-web-rig/profiles/library/config/heft.json @@ -21,7 +21,8 @@ "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", "options": { - "generatedTsFolders": ["temp/schema-ts", "lib"] + "generatedTsFolders": ["temp/schema-ts", "lib-dts"], + "formatWithPrettier": true } } }, From cc63aa64e6071e417addc20c494d9f9ae6085856 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:38:49 -0800 Subject: [PATCH 19/40] fixup! Make @rushstack/heft-json-schema-typings-plugin a decoupled dependency. --- .../decoupled-local-node-rig/profiles/default/config/heft.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json index 2d38bdac879..f97687a9621 100644 --- a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json +++ b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json @@ -21,7 +21,8 @@ "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", "options": { - "generatedTsFolders": ["temp/schema-ts", "lib", "lib-dts"] + "generatedTsFolders": ["temp/schema-ts", "lib-dts"], + "formatWithPrettier": true } } } From 3d113b508d5167287600d54c49a3d3637aa0cb93 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:40:44 -0800 Subject: [PATCH 20/40] Include the formatted schema output folder in the json schema typings generator test project's clean globs. --- .../heft-json-schema-typings-plugin-test/config/heft.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json index f74df35f8af..e542c488937 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json +++ b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["temp/schema-dts"] }], + "cleanFiles": [{ "includeGlobs": ["temp/schema-dts", "temp/schema-dts-formatted"] }], "tasksByName": { "json-schema-typings": { From af1c2a18d7c77bba291c1d4658e8b0d4d46300b8 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 17:05:53 -0800 Subject: [PATCH 21/40] Use the generated types in credential-cache. --- common/reviews/api/credential-cache.api.md | 15 ++++--- .../credential-cache/src/CredentialCache.ts | 35 +++++++---------- libraries/credential-cache/src/index.ts | 1 + .../src/schemas/credentials.schema.json | 39 ++++++++++++------- .../src/test/CredentialCache.test.ts | 6 +-- 5 files changed, 53 insertions(+), 43 deletions(-) diff --git a/common/reviews/api/credential-cache.api.md b/common/reviews/api/credential-cache.api.md index f6563cc246a..01e18b11f54 100644 --- a/common/reviews/api/credential-cache.api.md +++ b/common/reviews/api/credential-cache.api.md @@ -27,15 +27,20 @@ export class CredentialCache implements Disposable { } // @public (undocumented) -export interface ICredentialCacheEntry { - // (undocumented) - credential: string; - // (undocumented) - credentialMetadata?: object; +export interface ICredentialCacheEntry extends Omit { // (undocumented) expires?: Date; } +// @public +export interface ICredentialCacheEntryJson { + credential: string; + credentialMetadata?: { + [k: string]: unknown; + }; + expires: number; +} + // @public (undocumented) export interface ICredentialCacheOptions { // (undocumented) diff --git a/libraries/credential-cache/src/CredentialCache.ts b/libraries/credential-cache/src/CredentialCache.ts index bac9378e7a9..255b4e5292e 100644 --- a/libraries/credential-cache/src/CredentialCache.ts +++ b/libraries/credential-cache/src/CredentialCache.ts @@ -14,6 +14,12 @@ import { } from '@rushstack/node-core-library'; import schemaJson from './schemas/credentials.schema.json'; +import type { + CredentialCache as ICredentialCacheJson, + CredentialCacheEntry as ICredentialCacheEntryJson +} from './schemas/credentials.schema.json.d.ts'; + +export type { ICredentialCacheEntryJson }; // Polyfill for node 18 Disposables.polyfillDisposeSymbols(); @@ -27,26 +33,11 @@ export const RUSH_USER_FOLDER_NAME: '.rush-user' = '.rush-user'; const DEFAULT_CACHE_FILENAME: 'credentials.json' = 'credentials.json'; const LATEST_CREDENTIALS_JSON_VERSION: string = '0.1.0'; -interface ICredentialCacheJson { - version: string; - cacheEntries: { - [credentialCacheId: string]: ICacheEntryJson; - }; -} - -interface ICacheEntryJson { - expires: number; - credential: string; - credentialMetadata?: object; -} - /** * @public */ -export interface ICredentialCacheEntry { +export interface ICredentialCacheEntry extends Omit { expires?: Date; - credential: string; - credentialMetadata?: object; } /** @@ -62,7 +53,7 @@ export interface ICredentialCacheOptions { */ export class CredentialCache implements Disposable { private readonly _cacheFilePath: string; - private readonly _cacheEntries: Map; + private readonly _cacheEntries: Map; private _modified: boolean = false; private _disposed: boolean = false; private readonly _supportsEditing: boolean; @@ -78,7 +69,9 @@ export class CredentialCache implements Disposable { } this._cacheFilePath = cacheFilePath; - this._cacheEntries = new Map(Object.entries(loadedJson?.cacheEntries || {})); + this._cacheEntries = new Map( + Object.entries(loadedJson?.cacheEntries || {}) + ); this._supportsEditing = !!lockfile; this._lockfile = lockfile; } @@ -132,7 +125,7 @@ export class CredentialCache implements Disposable { const { expires, credential, credentialMetadata } = entry; const expiresMilliseconds: number = expires?.getTime() || 0; - const existingCacheEntry: ICacheEntryJson | undefined = this._cacheEntries.get(cacheId); + const existingCacheEntry: ICredentialCacheEntryJson | undefined = this._cacheEntries.get(cacheId); if ( existingCacheEntry?.credential !== credential || existingCacheEntry?.expires !== expiresMilliseconds || @@ -150,7 +143,7 @@ export class CredentialCache implements Disposable { public tryGetCacheEntry(cacheId: string): ICredentialCacheEntry | undefined { this._validate(false); - const cacheEntry: ICacheEntryJson | undefined = this._cacheEntries.get(cacheId); + const cacheEntry: ICredentialCacheEntryJson | undefined = this._cacheEntries.get(cacheId); if (cacheEntry) { const result: ICredentialCacheEntry = { expires: cacheEntry.expires ? new Date(cacheEntry.expires) : undefined, @@ -189,7 +182,7 @@ export class CredentialCache implements Disposable { this._validate(true); if (this._modified) { - const cacheEntriesJson: { [cacheId: string]: ICacheEntryJson } = {}; + const cacheEntriesJson: { [cacheId: string]: ICredentialCacheEntryJson } = {}; for (const [cacheId, cacheEntry] of this._cacheEntries.entries()) { cacheEntriesJson[cacheId] = cacheEntry; } diff --git a/libraries/credential-cache/src/index.ts b/libraries/credential-cache/src/index.ts index 00ce0172b53..47377bdba7b 100644 --- a/libraries/credential-cache/src/index.ts +++ b/libraries/credential-cache/src/index.ts @@ -10,6 +10,7 @@ export { CredentialCache, type ICredentialCacheEntry, + type ICredentialCacheEntryJson, type ICredentialCacheOptions, RUSH_USER_FOLDER_NAME } from './CredentialCache'; diff --git a/libraries/credential-cache/src/schemas/credentials.schema.json b/libraries/credential-cache/src/schemas/credentials.schema.json index 9800b511877..d95287d4b86 100644 --- a/libraries/credential-cache/src/schemas/credentials.schema.json +++ b/libraries/credential-cache/src/schemas/credentials.schema.json @@ -1,7 +1,8 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Cache for credentials used with the Rush tool.", + "title": "Credential Cache", "description": "For use with the Rush tool, this file acts as a cache for the credentials. See http://rushjs.io for details.", + "x-tsdoc-release-tag": "@public", "type": "object", @@ -15,20 +16,30 @@ "type": "object", "patternProperties": { ".+": { - "type": "object", - "required": ["expires", "credential"], + "$ref": "#/definitions/credentialCacheEntry" + } + } + } + }, + + "definitions": { + "credentialCacheEntry": { + "type": "object", + "required": ["expires", "credential"], + "additionalProperties": false, - "properties": { - "expires": { - "type": "number" - }, - "credential": { - "type": "string" - }, - "credentialMetadata": { - "type": "object" - } - } + "properties": { + "expires": { + "description": "The expiration time of the credential, in milliseconds since the epoch.", + "type": "number" + }, + "credential": { + "description": "The credential string.", + "type": "string" + }, + "credentialMetadata": { + "description": "Additional metadata associated with the credential.", + "type": "object" } } } diff --git a/libraries/credential-cache/src/test/CredentialCache.test.ts b/libraries/credential-cache/src/test/CredentialCache.test.ts index 5bdb13c49e6..b474f184d28 100644 --- a/libraries/credential-cache/src/test/CredentialCache.test.ts +++ b/libraries/credential-cache/src/test/CredentialCache.test.ts @@ -274,7 +274,7 @@ describe(CredentialCache.name, () => { it('correctly sets credentialMetadata', async () => { const credentialId: string = 'test-credential'; const credentialValue: string = 'test-value'; - const credentialMetadata: object = { + const credentialMetadata: { [k: string]: unknown } = { a: 1, b: true }; @@ -307,11 +307,11 @@ describe(CredentialCache.name, () => { it('correctly updates credentialMetadata', async () => { const credentialId: string = 'test-credential'; const credentialValue: string = 'test-value'; - const oldCredentialMetadata: object = { + const oldCredentialMetadata: { [k: string]: unknown } = { a: 1, b: true }; - const newCredentialMetadata: object = { + const newCredentialMetadata: { [k: string]: unknown } = { c: ['a', 'b', 'c'] }; From 5b4d1163649b7b61ae2ade961f5205a045245685 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 17:06:37 -0800 Subject: [PATCH 22/40] Use the generated types in rig-package. --- common/reviews/api/rig-package.api.md | 1 + libraries/rig-package/src/RigConfig.ts | 24 ++----------------- .../rig-package/src/schemas/rig.schema.json | 3 ++- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/common/reviews/api/rig-package.api.md b/common/reviews/api/rig-package.api.md index d79f609abb6..7071fe549dd 100644 --- a/common/reviews/api/rig-package.api.md +++ b/common/reviews/api/rig-package.api.md @@ -28,6 +28,7 @@ export interface IRigConfig { // @public export interface IRigConfigJson { + $schema?: string; rigPackageName: string; rigProfile?: string; } diff --git a/libraries/rig-package/src/RigConfig.ts b/libraries/rig-package/src/RigConfig.ts index 31ab62e2d76..fab7a44864e 100644 --- a/libraries/rig-package/src/RigConfig.ts +++ b/libraries/rig-package/src/RigConfig.ts @@ -8,34 +8,14 @@ import * as nodeResolve from 'resolve'; import stripJsonComments from 'strip-json-comments'; import { Helpers } from './Helpers'; +import type { RigConfiguration as IRigConfigJson } from './schemas/rig.schema.json.d.ts'; /** * Represents the literal contents of the `config/rig.json` file. * * @public */ -export interface IRigConfigJson { - /** - * The name of the rig package to use. - * - * @remarks - * The name must be a valid NPM package name, and must end with the `-rig` suffix. - * - * Example: `example-rig` - */ - rigPackageName: string; - - /** - * Specify which rig profile to use from the rig package. - * - * @remarks - * The name must consist of lowercase alphanumeric words separated by hyphens, for example `"sample-profile"`. - * If the `"rigProfile"` is not specified, then the profile name `"default"` will be used. - * - * Example: `example-profile` - */ - rigProfile?: string; -} +export type { IRigConfigJson }; interface IRigConfigOptions { projectFolderPath: string; diff --git a/libraries/rig-package/src/schemas/rig.schema.json b/libraries/rig-package/src/schemas/rig.schema.json index 9707e71e3da..f97246fd9a7 100644 --- a/libraries/rig-package/src/schemas/rig.schema.json +++ b/libraries/rig-package/src/schemas/rig.schema.json @@ -1,7 +1,8 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Describes the config/rig.json file", + "title": "Rig Configuration", "description": "The rig.json file is a standard for sharing project configuration in a monorepo without duplicating files", + "x-tsdoc-release-tag": "@public", "type": "object", "additionalProperties": false, From fc477372f957cc81ff6635544fa972bd0105142f Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 18:07:22 -0800 Subject: [PATCH 23/40] Use the generated types in rush. --- common/reviews/api/rush-lib.api.md | 11 +- .../src/api/ApprovedPackagesConfiguration.ts | 22 +-- .../rush-lib/src/api/CobuildConfiguration.ts | 6 +- .../src/api/CommonVersionsConfiguration.ts | 16 +-- .../src/api/ExperimentsConfiguration.ts | 128 +----------------- .../src/api/RushPluginsConfiguration.ts | 5 +- .../rush-lib/src/api/RushUserConfiguration.ts | 5 +- .../src/api/SubspacesConfiguration.ts | 8 +- .../src/schemas/approved-packages.schema.json | 2 +- .../rush-lib/src/schemas/cobuild.schema.json | 3 +- .../src/schemas/common-versions.schema.json | 2 +- .../src/schemas/custom-tips.schema.json | 2 +- .../src/schemas/experiments.schema.json | 5 +- .../src/schemas/rush-plugins.schema.json | 2 +- .../schemas/rush-user-settings.schema.json | 2 +- .../src/schemas/subspaces.schema.json | 4 +- .../src/AzureAuthenticationBase.ts | 2 +- 17 files changed, 34 insertions(+), 191 deletions(-) diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 1f8def84f93..c7e5aa1bc02 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -369,13 +369,12 @@ export interface ICobuildContext { runnerId: string; } -// @beta (undocumented) -export interface ICobuildJson { - // (undocumented) +// @beta +export type ICobuildJson = { + $schema?: string; cobuildFeatureEnabled: boolean; - // (undocumented) cobuildLockProvider: string; -} +}; // @beta (undocumented) export interface ICobuildLockProvider { @@ -462,6 +461,7 @@ export interface IExecutionResult { // @beta export interface IExperimentsJson { + $schema?: string; allowCobuildWithoutCache?: boolean; buildCacheWithAllowWarningsInSuccessfulBuild?: boolean; buildSkipWithAllowWarningsInSuccessfulBuild?: boolean; @@ -473,6 +473,7 @@ export interface IExperimentsJson { noChmodFieldInTarHeaderNormalization?: boolean; omitAppleDoubleFilesFromBuildCache?: boolean; omitImportersFromPreventManualShrinkwrapChanges?: boolean; + phasedCommands?: boolean; printEventHooksOutputToConsole?: boolean; rushAlerts?: boolean; useIPCScriptsInWatchMode?: boolean; diff --git a/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts index e7b48f2c842..0c672b568e7 100644 --- a/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts +++ b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts @@ -8,24 +8,10 @@ import { JsonFile, JsonSchema, FileSystem, NewlineKind, InternalError } from '@r import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; import schemaJson from '../schemas/approved-packages.schema.json'; import { RushConstants } from '../logic/RushConstants'; - -/** - * Part of IApprovedPackagesJson. - */ -export interface IApprovedPackagesItemJson { - name: string; - allowedCategories: string[]; -} - -/** - * This represents the JSON data structure for the "browser-approved-packages.json" - * and "nonbrowser-approved-packages.json" configuration files. See "approved-packages.schema.json" - * for documentation. - */ -export interface IApprovedPackagesJson { - $schema?: string; - packages: IApprovedPackagesItemJson[]; -} +import type { + RushApprovedPackagesConfiguration as IApprovedPackagesJson, + PackageInfo as IApprovedPackagesItemJson +} from '../schemas/approved-packages.schema.json.d.ts'; /** * An item returned by ApprovedPackagesConfiguration diff --git a/libraries/rush-lib/src/api/CobuildConfiguration.ts b/libraries/rush-lib/src/api/CobuildConfiguration.ts index d96cfc96dc2..e3228022a31 100644 --- a/libraries/rush-lib/src/api/CobuildConfiguration.ts +++ b/libraries/rush-lib/src/api/CobuildConfiguration.ts @@ -12,14 +12,12 @@ import { RushConstants } from '../logic/RushConstants'; import type { ICobuildLockProvider } from '../logic/cobuild/ICobuildLockProvider'; import type { RushConfiguration } from './RushConfiguration'; import schemaJson from '../schemas/cobuild.schema.json'; +import type { RushCobuildConfiguration as ICobuildJson } from '../schemas/cobuild.schema.json.d.ts'; /** * @beta */ -export interface ICobuildJson { - cobuildFeatureEnabled: boolean; - cobuildLockProvider: string; -} +export type { ICobuildJson }; /** * @beta diff --git a/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts index 0996bbc5a0f..b3839a172f9 100644 --- a/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts +++ b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -19,6 +19,7 @@ import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; import type { RushConfiguration } from './RushConfiguration'; import { RushConstants } from '../logic/RushConstants'; import schemaJson from '../schemas/common-versions.schema.json'; +import type { RushCommonVersionsConfiguration as ICommonVersionsJson } from '../schemas/common-versions.schema.json.d.ts'; /** * Part of the ICommonVersionsJson structure. @@ -42,21 +43,6 @@ export declare interface ICommonVersionsJsonVersionsMap { [dependencyName: string]: string[]; } -/** - * Describes the file structure for the "common/config/rush/common-versions.json" config file. - */ -interface ICommonVersionsJson { - $schema?: string; - - preferredVersions?: ICommonVersionsJsonVersionMap; - - implicitlyPreferredVersions?: boolean; - - allowedAlternativeVersions?: ICommonVersionsJsonVersionsMap; - - ensureConsistentVersions?: boolean; -} - /** * Use this class to load and save the "common/config/rush/common-versions.json" config file. * This config file stores dependency version information that affects all projects in the repo. diff --git a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts index f8a9ae66e34..e9976b2de08 100644 --- a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts +++ b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts @@ -5,138 +5,16 @@ import { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; import schemaJson from '../schemas/experiments.schema.json'; - -const GRADUATED_EXPERIMENTS: Set = new Set(['phasedCommands']); +import type { RushExperimentsConfiguration as IExperimentsJson } from '../schemas/experiments.schema.json.d.ts'; /** * This interface represents the raw experiments.json file which allows repo * maintainers to enable and disable experimental Rush features. * @beta */ -export interface IExperimentsJson { - /** - * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. - * Set this option to true to pass '--frozen-lockfile' instead for faster installs. - */ - usePnpmFrozenLockfileForRushInstall?: boolean; - - /** - * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. - * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. - */ - usePnpmPreferFrozenLockfileForRushUpdate?: boolean; - - /** - * By default, 'rush update' runs as a single operation. - * Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. - * Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs. - */ - usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate?: boolean; - - /** - * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. - * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not - * cause hash changes. - */ - omitImportersFromPreventManualShrinkwrapChanges?: boolean; - - /** - * If true, the chmod field in temporary project tar headers will not be normalized. - * This normalization can help ensure consistent tarball integrity across platforms. - */ - noChmodFieldInTarHeaderNormalization?: boolean; - - /** - * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. - * This will not replay warnings from the cached build. - */ - buildCacheWithAllowWarningsInSuccessfulBuild?: boolean; - - /** - * If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. - * This will not replay warnings from the skipped build. - */ - buildSkipWithAllowWarningsInSuccessfulBuild?: boolean; - - /** - * If true, perform a clean install after when running `rush install` or `rush update` if the - * `.npmrc` file has changed since the last install. - */ - cleanInstallAfterNpmrcChanges?: boolean; - - /** - * If true, print the outputs of shell commands defined in event hooks to the console. - */ - printEventHooksOutputToConsole?: boolean; +export type { IExperimentsJson }; - /** - * If true, Rush will not allow node_modules in the repo folder or in parent folders. - */ - forbidPhantomResolvableNodeModulesFolders?: boolean; - - /** - * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot - * correctly satisfy versioning requirements without installing duplicate copies of a package inside the - * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally - * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" - * feature provides a model for copying the local project folder into node_modules, however copying - * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. - * The "pnpm-sync" tool manages this operation; see its documentation for details. - * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies - * by invoking "pnpm-sync" during the build. - */ - usePnpmSyncForInjectedDependencies?: boolean; - - /** - * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. - */ - generateProjectImpactGraphDuringRushUpdate?: boolean; - - /** - * If true, when running in watch mode, Rush will check for phase scripts named `_phase::ipc` and run them instead - * of `_phase:` if they exist. The created child process will be provided with an IPC channel and expected to persist - * across invocations. - */ - useIPCScriptsInWatchMode?: boolean; - - /** - * (UNDER DEVELOPMENT) The Rush alerts feature provides a way to send announcements to engineers - * working in the monorepo, by printing directly in the user's shell window when they invoke Rush commands. - * This ensures that important notices will be seen by anyone doing active development, since people often - * ignore normal discussion group messages or don't know to subscribe. - */ - rushAlerts?: boolean; - - /** - * Allow cobuilds without using the build cache to store previous execution info. When setting up - * distributed builds, Rush will allow uncacheable projects to still leverage the cobuild feature. - * This is useful when you want to speed up operations that can't (or shouldn't) be cached. - */ - allowCobuildWithoutCache?: boolean; - - /** - * By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes. - * When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations. - */ - enableSubpathScan?: boolean; - - /** - * Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending - * on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies` - * in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different - * subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume - * each other's packages via the NPM registry. - */ - exemptDecoupledDependenciesBetweenSubspaces?: boolean; - - /** - * If true, when running on macOS, Rush will omit AppleDouble files (`._*`) from build cache archives - * when a companion file exists in the same directory. AppleDouble files are automatically created by - * macOS to store extended attributes on filesystems that don't support them, and should generally not - * be included in the shared build cache. - */ - omitAppleDoubleFilesFromBuildCache?: boolean; -} +const GRADUATED_EXPERIMENTS: Set = new Set(['phasedCommands']); const _EXPERIMENTS_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); diff --git a/libraries/rush-lib/src/api/RushPluginsConfiguration.ts b/libraries/rush-lib/src/api/RushPluginsConfiguration.ts index f8d194d0ab1..47277082e08 100644 --- a/libraries/rush-lib/src/api/RushPluginsConfiguration.ts +++ b/libraries/rush-lib/src/api/RushPluginsConfiguration.ts @@ -4,6 +4,7 @@ import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; import schemaJson from '../schemas/rush-plugins.schema.json'; +import type { RushPluginsConfiguration as IRushPluginsConfigurationJson } from '../schemas/rush-plugins.schema.json.d.ts'; /** * @internal @@ -17,10 +18,6 @@ export interface IRushPluginConfiguration extends IRushPluginConfigurationBase { autoinstallerName: string; } -interface IRushPluginsConfigurationJson { - plugins: IRushPluginConfiguration[]; -} - export class RushPluginsConfiguration { private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); diff --git a/libraries/rush-lib/src/api/RushUserConfiguration.ts b/libraries/rush-lib/src/api/RushUserConfiguration.ts index cdf767363bb..c92f81c02d2 100644 --- a/libraries/rush-lib/src/api/RushUserConfiguration.ts +++ b/libraries/rush-lib/src/api/RushUserConfiguration.ts @@ -7,10 +7,7 @@ import { FileSystem, JsonFile, JsonSchema, User } from '@rushstack/node-core-lib import { RushConstants } from '../logic/RushConstants'; import schemaJson from '../schemas/rush-user-settings.schema.json'; - -interface IRushUserSettingsJson { - buildCacheFolder?: string; -} +import type { RushUserSettings as IRushUserSettingsJson } from '../schemas/rush-user-settings.schema.json.d.ts'; /** * Rush per-user configuration data. diff --git a/libraries/rush-lib/src/api/SubspacesConfiguration.ts b/libraries/rush-lib/src/api/SubspacesConfiguration.ts index 91dbe477be3..fa7a9cfdb20 100644 --- a/libraries/rush-lib/src/api/SubspacesConfiguration.ts +++ b/libraries/rush-lib/src/api/SubspacesConfiguration.ts @@ -6,6 +6,7 @@ import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; import type { RushConfiguration } from './RushConfiguration'; import schemaJson from '../schemas/subspaces.schema.json'; import { RushConstants } from '../logic/RushConstants'; +import type { RushSubspacesConfiguration as ISubspacesConfigurationJson } from '../schemas/subspaces.schema.json.d.ts'; /** * The allowed naming convention for subspace names. @@ -20,12 +21,7 @@ export const SPLIT_WORKSPACE_SUBSPACE_NAME_REGEXP: RegExp = /^[a-z0-9][+_\-a-z0- * This represents the JSON data structure for the "subspaces.json" configuration file. * See subspace.schema.json for documentation. */ -export interface ISubspacesConfigurationJson { - subspacesEnabled: boolean; - splitWorkspaceCompatibility?: boolean; - preventSelectingAllSubspaces?: boolean; - subspaceNames: string[]; -} +export type { ISubspacesConfigurationJson }; /** * This represents the subspace configurations for a repository, based on the "subspaces.json" diff --git a/libraries/rush-lib/src/schemas/approved-packages.schema.json b/libraries/rush-lib/src/schemas/approved-packages.schema.json index 4b41f5cab57..e12c276169b 100644 --- a/libraries/rush-lib/src/schemas/approved-packages.schema.json +++ b/libraries/rush-lib/src/schemas/approved-packages.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush approved packages config file", + "title": "Rush Approved Packages Configuration", "description": "For use with the Rush tool, this file tracks a list of NPM packages that have been approved for usage. This schema is used by two config files browser-approved-packages.json and nonbrowser-approved-packages.jsons. See http://rushjs.io for details.", "definitions": { diff --git a/libraries/rush-lib/src/schemas/cobuild.schema.json b/libraries/rush-lib/src/schemas/cobuild.schema.json index 6fe630b89d8..33f405786df 100644 --- a/libraries/rush-lib/src/schemas/cobuild.schema.json +++ b/libraries/rush-lib/src/schemas/cobuild.schema.json @@ -1,7 +1,8 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Configuration for Rush's cobuild.", + "title": "Rush Cobuild Configuration", "description": "For use with the Rush tool, this file provides configuration options for cobuild feature. See http://rushjs.io for details.", + "x-tsdoc-release-tag": "@beta", "definitions": { "anything": { "type": ["array", "boolean", "integer", "number", "object", "string"], diff --git a/libraries/rush-lib/src/schemas/common-versions.schema.json b/libraries/rush-lib/src/schemas/common-versions.schema.json index 35e3de17634..bb4426197a6 100644 --- a/libraries/rush-lib/src/schemas/common-versions.schema.json +++ b/libraries/rush-lib/src/schemas/common-versions.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush common-versions.json config file", + "title": "Rush Common Versions Configuration", "description": "For use with the Rush tool, this file manages dependency versions that affect all projects in the repo. See http://rushjs.io for details.", "type": "object", "properties": { diff --git a/libraries/rush-lib/src/schemas/custom-tips.schema.json b/libraries/rush-lib/src/schemas/custom-tips.schema.json index faa274fe091..2f9586d3015 100644 --- a/libraries/rush-lib/src/schemas/custom-tips.schema.json +++ b/libraries/rush-lib/src/schemas/custom-tips.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush custom-tips.json config file", + "title": "Rush Custom Tips Configuration", "description": "The config file for adding tips to specific messages.", "type": "object", diff --git a/libraries/rush-lib/src/schemas/experiments.schema.json b/libraries/rush-lib/src/schemas/experiments.schema.json index 8a92fa9ee67..6a79b944f1a 100644 --- a/libraries/rush-lib/src/schemas/experiments.schema.json +++ b/libraries/rush-lib/src/schemas/experiments.schema.json @@ -1,7 +1,8 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush experiments.json config file", + "title": "Rush Experiments Configuration", "description": "For use with the Rush tool, this file allows repo maintainers to enable and disable experimental Rush features.", + "x-tsdoc-release-tag": "@beta", "type": "object", "properties": { @@ -79,7 +80,7 @@ "type": "boolean" }, "exemptDecoupledDependenciesBetweenSubspaces": { - "description": "Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume each other's packages via the NPM registry.", + "description": "Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies` in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume each other's packages via the NPM registry.", "type": "boolean" }, "omitAppleDoubleFilesFromBuildCache": { diff --git a/libraries/rush-lib/src/schemas/rush-plugins.schema.json b/libraries/rush-lib/src/schemas/rush-plugins.schema.json index caa4e0784ea..720f0dda7e3 100644 --- a/libraries/rush-lib/src/schemas/rush-plugins.schema.json +++ b/libraries/rush-lib/src/schemas/rush-plugins.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema", - "title": "Rush rush-plugins.json config file", + "title": "Rush Plugins Configuration", "description": "This file defines plugins used by Rush", "type": "object", "required": ["plugins"], diff --git a/libraries/rush-lib/src/schemas/rush-user-settings.schema.json b/libraries/rush-lib/src/schemas/rush-user-settings.schema.json index dde6f7e06f3..a113ffed643 100644 --- a/libraries/rush-lib/src/schemas/rush-user-settings.schema.json +++ b/libraries/rush-lib/src/schemas/rush-user-settings.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush per-user settings file", + "title": "Rush User Settings", "description": "For use with the Rush tool, this file stores user-specific settings options. See http://rushjs.io for details.", "type": "object", diff --git a/libraries/rush-lib/src/schemas/subspaces.schema.json b/libraries/rush-lib/src/schemas/subspaces.schema.json index 5322a806a7b..de9bdcbae09 100644 --- a/libraries/rush-lib/src/schemas/subspaces.schema.json +++ b/libraries/rush-lib/src/schemas/subspaces.schema.json @@ -1,9 +1,11 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush subspace config file.", + "title": "Rush Subspaces Configuration", "description": "The configuration file for enabling the subspaces feature in rush. This is an EXPERIMENTAL feature which is not yet fully implemented. To opt into the experiment, simply toggle the 'enabled' property in this file.", "type": "object", + "required": ["subspacesEnabled", "subspaceNames"], + "properties": { "$schema": { "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", diff --git a/rush-plugins/rush-azure-storage-build-cache-plugin/src/AzureAuthenticationBase.ts b/rush-plugins/rush-azure-storage-build-cache-plugin/src/AzureAuthenticationBase.ts index 2be93baa713..e85409d6bd1 100644 --- a/rush-plugins/rush-azure-storage-build-cache-plugin/src/AzureAuthenticationBase.ts +++ b/rush-plugins/rush-azure-storage-build-cache-plugin/src/AzureAuthenticationBase.ts @@ -137,7 +137,7 @@ export interface IAzureAuthenticationBaseOptions { */ export interface ICredentialResult { credentialString: string; expiresOn?: Date; - credentialMetadata?: object; + credentialMetadata?: { [k: string]: unknown }; } /** From 55d801d4095d0c0be143bc20ec83f7bb1de4b891 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 18:54:37 -0800 Subject: [PATCH 24/40] Add support for draft-2019-09 schemas. --- ...e-json-schema-plugin_2026-02-22-02-50.json | 10 +++ common/reviews/api/node-core-library.api.md | 2 +- libraries/node-core-library/src/JsonSchema.ts | 11 ++- .../src/test/JsonSchema.test.ts | 29 +++++++ .../test-schema-draft-2019-09.schema.json | 75 +++++++++++++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 common/changes/@rushstack/node-core-library/use-json-schema-plugin_2026-02-22-02-50.json create mode 100644 libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-2019-09.schema.json diff --git a/common/changes/@rushstack/node-core-library/use-json-schema-plugin_2026-02-22-02-50.json b/common/changes/@rushstack/node-core-library/use-json-schema-plugin_2026-02-22-02-50.json new file mode 100644 index 00000000000..30f25144f66 --- /dev/null +++ b/common/changes/@rushstack/node-core-library/use-json-schema-plugin_2026-02-22-02-50.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/node-core-library", + "comment": "Add support for `draft-2019-09` JSON schemas in `JsonSchema`.", + "type": "minor" + } + ], + "packageName": "@rushstack/node-core-library" +} \ No newline at end of file diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index c5b2ebe4f9b..8bee22d8cd6 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -743,7 +743,7 @@ export class JsonSchema { } // @public -export type JsonSchemaVersion = 'draft-04' | 'draft-07'; +export type JsonSchemaVersion = 'draft-04' | 'draft-07' | 'draft-2019-09'; // @public export enum JsonSyntax { diff --git a/libraries/node-core-library/src/JsonSchema.ts b/libraries/node-core-library/src/JsonSchema.ts index a1ffdf13dfb..76590da9f62 100644 --- a/libraries/node-core-library/src/JsonSchema.ts +++ b/libraries/node-core-library/src/JsonSchema.ts @@ -5,6 +5,7 @@ import * as os from 'node:os'; import * as path from 'node:path'; import Ajv, { type Options as AjvOptions, type ErrorObject, type ValidateFunction } from 'ajv'; +import Ajv2019 from 'ajv/dist/2019'; import AjvDraft04 from 'ajv-draft-04'; import addFormats from 'ajv-formats'; @@ -44,7 +45,7 @@ interface ISchemaWithId { * https://json-schema.org/specification * @public */ -export type JsonSchemaVersion = 'draft-04' | 'draft-07'; +export type JsonSchemaVersion = 'draft-04' | 'draft-07' | 'draft-2019-09'; /** * A definition for a custom format to consider during validation. @@ -175,7 +176,8 @@ export type IJsonSchemaFromObjectOptions = IJsonSchemaLoadOptions; const JSON_SCHEMA_URL_PREFIX_BY_JSON_SCHEMA_VERSION: Map = new Map([ ['draft-04', 'http://json-schema.org/draft-04/schema'], - ['draft-07', 'http://json-schema.org/draft-07/schema'] + ['draft-07', 'http://json-schema.org/draft-07/schema'], + ['draft-2019-09', 'https://json-schema.org/draft/2019-09/schema'] ]); /** @@ -371,6 +373,11 @@ export class JsonSchema { break; } + case 'draft-2019-09': { + validator = new Ajv2019(validatorOptions); + break; + } + case 'draft-07': default: { validator = new Ajv(validatorOptions); diff --git a/libraries/node-core-library/src/test/JsonSchema.test.ts b/libraries/node-core-library/src/test/JsonSchema.test.ts index 44a482d9398..7d265a1ddde 100644 --- a/libraries/node-core-library/src/test/JsonSchema.test.ts +++ b/libraries/node-core-library/src/test/JsonSchema.test.ts @@ -7,6 +7,7 @@ import { JsonSchema, type IJsonSchemaErrorInfo } from '../JsonSchema'; const SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema.schema.json`; const DRAFT_04_SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema-draft-04.schema.json`; const DRAFT_07_SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema-draft-07.schema.json`; +const DRAFT_2019_09_SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema-draft-2019-09.schema.json`; describe(JsonSchema.name, () => { const schema: JsonSchema = JsonSchema.fromFile(SCHEMA_PATH, { @@ -57,6 +58,18 @@ describe(JsonSchema.name, () => { }); }); + test('validates a JSON file against a draft-2019-09 schema', () => { + const schemaDraft2019: JsonSchema = JsonSchema.fromFile(DRAFT_2019_09_SCHEMA_PATH); + + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; + const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaDraft2019); + + expect(jsonObject).toMatchObject({ + exampleString: 'This is a string', + exampleArray: ['apple', 'banana', 'coconut'] + }); + }); + test('validates a JSON file using nested schemas', () => { const schemaPathChild: string = `${__dirname}/test-data/test-schemas/test-schema-nested-child.schema.json`; const schemaChild: JsonSchema = JsonSchema.fromFile(schemaPathChild); @@ -120,6 +133,22 @@ describe(JsonSchema.name, () => { }); }); + test('validates objects against a draft-2019-09 schema', () => { + const schemaDraft2019: JsonSchema = JsonSchema.fromLoadedObject({ + $schema: 'https://json-schema.org/draft/2019-09/schema#', + title: 'Test draft-2019-09 schema', + type: 'object', + properties: { + exampleString: { type: 'string' } + }, + additionalProperties: false, + required: ['exampleString'] + }); + + expect(() => schemaDraft2019.validateObject({ exampleString: 'This is a string' }, '')).not.toThrow(); + expect(() => schemaDraft2019.validateObject({} as JsonObject, '')).toThrow(); + }); + test('accepts vendor extension keywords by default', () => { const schemaWithVendorExtensions: JsonSchema = JsonSchema.fromLoadedObject( { diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-2019-09.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-2019-09.schema.json new file mode 100644 index 00000000000..699cc7ac185 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-2019-09.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema#", + "title": "Test Schema File", + "type": "object", + + "definitions": { + "type1": { + "description": "Description for type1", + "type": "object", + "properties": { + "field1": { + "description": "Description for field1", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["field1"] + }, + "type2": { + "description": "Description for type2", + "type": "object", + "properties": { + "field2": { + "description": "Description for field2", + "type": "string" + }, + "field3": { + "description": "Description for field3", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["field2", "field3"] + } + }, + + "properties": { + "exampleString": { + "type": "string" + }, + "exampleLink": { + "type": "string", + "format": "uri" + }, + "exampleArray": { + "type": "array", + "items": { + "type": "string" + } + }, + "exampleOneOf": { + "description": "Description for exampleOneOf - this is a very long description to show in an error message", + "type": "object", + "oneOf": [{ "$ref": "#/definitions/type1" }, { "$ref": "#/definitions/type2" }] + }, + "exampleUniqueObjectArray": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field2": { + "type": "string" + }, + "field3": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false, + "required": ["exampleString", "exampleArray"] +} From f953801ff736ec939b2928a40b4cdaf59890a781 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 18:55:50 -0800 Subject: [PATCH 25/40] fixup! Use the generated types in rush. --- .../reviews/api/rush-azure-storage-build-cache-plugin.api.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md b/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md index 26f39c4993a..3d53aed9cc5 100644 --- a/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md +++ b/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md @@ -103,7 +103,9 @@ export interface IAzureStorageAuthenticationOptions extends IAzureAuthentication // @public (undocumented) export interface ICredentialResult { // (undocumented) - credentialMetadata?: object; + credentialMetadata?: { + [k: string]: unknown; + }; // (undocumented) credentialString: string; // (undocumented) From 6f5db39e42355f84c5d8ccd1b05a1456ba916771 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 19:05:21 -0800 Subject: [PATCH 26/40] Use the generated types in heft. --- apps/heft/src/index.ts | 8 +- apps/heft/src/plugins/CopyFilesPlugin.ts | 35 +- apps/heft/src/plugins/DeleteFilesPlugin.ts | 15 +- apps/heft/src/plugins/FileGlobSpecifier.ts | 33 +- apps/heft/src/plugins/RunScriptPlugin.ts | 8 +- .../plugins/SetEnvironmentVariablesPlugin.ts | 8 +- .../schemas/copy-files-options.schema.json | 121 +++--- .../schemas/delete-files-options.schema.json | 82 ++-- .../src/schemas/file-selection.schema.json | 42 ++ apps/heft/src/schemas/heft-plugin.schema.json | 394 ++++++------------ apps/heft/src/schemas/heft.schema.json | 40 +- ...t-environment-variables-plugin.schema.json | 4 +- common/reviews/api/heft.api.md | 22 +- 13 files changed, 349 insertions(+), 463 deletions(-) create mode 100644 apps/heft/src/schemas/file-selection.schema.json diff --git a/apps/heft/src/index.ts b/apps/heft/src/index.ts index 0c6006dfc8c..c45d9e5b9e5 100644 --- a/apps/heft/src/index.ts +++ b/apps/heft/src/index.ts @@ -46,9 +46,13 @@ export type { IHeftTaskRunIncrementalHookOptions } from './pluginFramework/HeftTaskSession'; -export type { ICopyOperation, IIncrementalCopyOperation } from './plugins/CopyFilesPlugin'; +export type { + ICopyOperation, + IIncrementalCopyOperation, + ICopyOperationBase +} from './plugins/CopyFilesPlugin'; -export type { IDeleteOperation } from './plugins/DeleteFilesPlugin'; +export type { IDeleteOperation, IDeleteOperationBase } from './plugins/DeleteFilesPlugin'; export type { IRunScript, IRunScriptOptions } from './plugins/RunScriptPlugin'; diff --git a/apps/heft/src/plugins/CopyFilesPlugin.ts b/apps/heft/src/plugins/CopyFilesPlugin.ts index 2c9d47347a1..a635782100f 100644 --- a/apps/heft/src/plugins/CopyFilesPlugin.ts +++ b/apps/heft/src/plugins/CopyFilesPlugin.ts @@ -24,6 +24,12 @@ import { tryReadBuildInfoAsync, writeBuildInfoAsync } from '../pluginFramework/IncrementalBuildInfo'; +import type { + CopyFilesHeftTaskEventOptions as ICopyFilesPluginOptions, + CopyOperationBase as ICopyOperationBase +} from '../schemas/copy-files-options.schema.json.d.ts'; + +export type { ICopyOperationBase }; /** * Used to specify a selection of files to copy from a specific source folder to one @@ -31,30 +37,7 @@ import { * * @public */ -export interface ICopyOperation extends IFileSelectionSpecifier { - /** - * Absolute paths to folders which files or folders should be copied to. - */ - destinationFolders: string[]; - - /** - * Copy only the file and discard the relative path from the source folder. - */ - flatten?: boolean; - - /** - * Hardlink files instead of copying. - * - * @remarks - * If the sourcePath is a folder, the contained directory structure will be re-created - * and all files will be individually hardlinked. This means that folders will be new - * filesystem entities and will have separate folder metadata, while the contained files - * will maintain normal hardlink behavior. This is done since folders do not have a - * cross-platform equivalent of a hardlink, and since file symlinks provide fundamentally - * different functionality in comparison to hardlinks. - */ - hardlink?: boolean; -} +export interface ICopyOperation extends IFileSelectionSpecifier, ICopyOperationBase {} /** * Used to specify a selection of files to copy from a specific source folder to one @@ -70,10 +53,6 @@ export interface IIncrementalCopyOperation extends ICopyOperation { onlyIfChanged?: boolean; } -interface ICopyFilesPluginOptions { - copyOperations: ICopyOperation[]; -} - interface ICopyDescriptor { sourcePath: string; destinationPath: string; diff --git a/apps/heft/src/plugins/DeleteFilesPlugin.ts b/apps/heft/src/plugins/DeleteFilesPlugin.ts index 73976dad8f4..bc200884d9d 100644 --- a/apps/heft/src/plugins/DeleteFilesPlugin.ts +++ b/apps/heft/src/plugins/DeleteFilesPlugin.ts @@ -15,17 +15,22 @@ import { import type { HeftConfiguration } from '../configuration/HeftConfiguration'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; import type { IHeftTaskSession, IHeftTaskFileOperations } from '../pluginFramework/HeftTaskSession'; +import type { + DeleteFilesHeftTaskEventOptions as IDeleteFilesPluginOptions, + DeleteOperationBase as IDeleteOperationBase +} from '../schemas/delete-files-options.schema.json.d.ts'; + +/** + * @internal + */ +export type { IDeleteOperationBase }; /** * Used to specify a selection of source files to delete from the specified source folder. * * @public */ -export interface IDeleteOperation extends IFileSelectionSpecifier {} - -interface IDeleteFilesPluginOptions { - deleteOperations: IDeleteOperation[]; -} +export interface IDeleteOperation extends IFileSelectionSpecifier, IDeleteOperationBase {} interface IGetPathsToDeleteResult { filesToDelete: Set; diff --git a/apps/heft/src/plugins/FileGlobSpecifier.ts b/apps/heft/src/plugins/FileGlobSpecifier.ts index 96d3223dd5a..da09c50e1a8 100644 --- a/apps/heft/src/plugins/FileGlobSpecifier.ts +++ b/apps/heft/src/plugins/FileGlobSpecifier.ts @@ -9,38 +9,9 @@ import glob, { type FileSystemAdapter, type Entry } from 'fast-glob'; import { Async } from '@rushstack/node-core-library'; import type { IWatchFileSystemAdapter, IWatchedFileState } from '../utilities/WatchFileSystemAdapter'; +import type { FileSelectionSpecifierBase as IFileSelectionSpecifier } from '../schemas/file-selection.schema.json.d.ts'; -/** - * Used to specify a selection of one or more files. - * - * @public - */ -export interface IFileSelectionSpecifier { - /** - * Absolute path to the target. The provided sourcePath can be to a file or a folder. If - * fileExtensions, excludeGlobs, or includeGlobs are specified, the sourcePath is assumed - * to be a folder. If it is not a folder, an error will be thrown. - */ - sourcePath?: string; - - /** - * File extensions that should be included from the source folder. Only supported when the sourcePath - * is a folder. - */ - fileExtensions?: string[]; - - /** - * Globs that should be explicitly excluded. This takes precedence over globs listed in "includeGlobs" and - * files that match the file extensions provided in "fileExtensions". Only supported when the sourcePath - * is a folder. - */ - excludeGlobs?: string[]; - - /** - * Globs that should be explicitly included. Only supported when the sourcePath is a folder. - */ - includeGlobs?: string[]; -} +export type { IFileSelectionSpecifier }; /** * A supported subset of options used when globbing files. diff --git a/apps/heft/src/plugins/RunScriptPlugin.ts b/apps/heft/src/plugins/RunScriptPlugin.ts index 6c74d9dfd56..1f8d3dfe2ee 100644 --- a/apps/heft/src/plugins/RunScriptPlugin.ts +++ b/apps/heft/src/plugins/RunScriptPlugin.ts @@ -6,11 +6,7 @@ import * as path from 'node:path'; import type { HeftConfiguration } from '../configuration/HeftConfiguration'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; import type { IHeftTaskSession, IHeftTaskRunHookOptions } from '../pluginFramework/HeftTaskSession'; - -interface IRunScriptPluginOptions { - scriptPath: string; - scriptOptions: Record; -} +import type { RunScriptHeftTaskEventOptions as IRunScriptPluginOptions } from '../schemas/run-script-options.schema.json.d.ts'; /** * Options provided to scripts that are run using the RunScriptPlugin. @@ -21,7 +17,7 @@ export interface IRunScriptOptions { heftTaskSession: IHeftTaskSession; heftConfiguration: HeftConfiguration; runOptions: IHeftTaskRunHookOptions; - scriptOptions: Record; + scriptOptions: Record | undefined; } /** diff --git a/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts b/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts index fb83903b83b..4a75e526521 100644 --- a/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts +++ b/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts @@ -4,12 +4,14 @@ import type { HeftConfiguration } from '../configuration/HeftConfiguration'; import type { IHeftTaskSession } from '../pluginFramework/HeftTaskSession'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; +import type { SetEnvironmentVariablesHeftTaskEventOptions as ISetEnvironmentVariablesPluginOptions } from '../schemas/set-environment-variables-plugin.schema.json.d.ts'; export const PLUGIN_NAME: string = 'set-environment-variables-plugin'; -export interface ISetEnvironmentVariablesPluginOptions { - environmentVariablesToSet: Record; -} +/** + * @public + */ +export type { ISetEnvironmentVariablesPluginOptions }; export default class SetEnvironmentVariablesPlugin implements IHeftTaskPlugin diff --git a/apps/heft/src/schemas/copy-files-options.schema.json b/apps/heft/src/schemas/copy-files-options.schema.json index f42d46af61c..e56ffc05517 100644 --- a/apps/heft/src/schemas/copy-files-options.schema.json +++ b/apps/heft/src/schemas/copy-files-options.schema.json @@ -1,7 +1,8 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "CopyFiles Heft Task Event Options", "description": "Defines configuration used by the \"copyFiles\" Heft task event.", + "x-tsdoc-release-tag": "@public", "type": "object", "additionalProperties": false, @@ -13,74 +14,68 @@ "description": "An array of copy operations to perform during the specified Heft event.", "items": { - "type": "object", - "additionalProperties": false, - "required": ["destinationFolders"], - "anyOf": [ - { "required": ["sourcePath"] }, - { "required": ["fileExtensions"] }, - { "required": ["includeGlobs"] }, - { "required": ["excludeGlobs"] } - ], - "properties": { - "sourcePath": { - "title": "Source Path", - "type": "string", - "description": "The target folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be copied. To copy a single file, set \"includeGlobs\" to an array containing the exact name of the file. If this parameter is not provided, defaults to the project root.", - "pattern": "[^\\\\]" - }, - - "destinationFolders": { - "title": "Destination Folders", - "type": "array", - "description": "One or more folders that files and folders will be copied into, relative to the project root.", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } - }, + "$ref": "#/$defs/copyOperationBase" + } + } + }, - "fileExtensions": { - "title": "File Extensions", - "type": "array", - "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", - "items": { - "type": "string", - "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" - } - }, + "$defs": { + "copyOperationBase": { + "description": "Configures a copy operation for the \"copyFiles\" task event.", + "type": "object", + "additionalProperties": false, + "required": ["destinationFolders"], + "properties": { + "sourcePath": { + "type": "string", + "description": "The target folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be copied. To copy a single file, set \"includeGlobs\" to an array containing the exact name of the file. If this parameter is not provided, defaults to the project root.", + "pattern": "[^\\\\]" + }, - "excludeGlobs": { - "title": "Exclude Globs", - "type": "array", - "description": "A list of glob patterns that exclude files or folders from being copied. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } - }, + "fileExtensions": { + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, - "includeGlobs": { - "title": "Include Globs", - "type": "array", - "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourcePath\".", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } - }, + "excludeGlobs": { + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being copied. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, - "flatten": { - "title": "Flatten", - "type": "boolean", - "description": "Normally, copying will preserve the path relative to \"sourcePath\" under the destination folder (e.g. if \"sourcePath\" is \"src/test\" and \"destinationFolders\" is [\"out\"], \"src/test/a/b/c.txt\" will be copied to \"out/a/b/c.txt\"). Specify \"flatten=true\" to discard path information and keep only the filename (e.g. \"out/c.txt\". If two files have the same name an error will be reported. The default value is false." - }, + "includeGlobs": { + "type": "array", + "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, - "hardlink": { - "title": "Hardlink", - "type": "boolean", - "description": "If true, filesystem hard links will be created instead of copying the file. Depending on the operating system, this may be faster. The default value is false. NOTE: This may cause unexpected behavior if a tool modifies the link. The contained directory structure will be re-created and all files will be individually hardlinked. This means that folders will be new filesystem entities and will have separate folder metadata, while the contained files will maintain normal hardlink behavior. This is done since folders do not have a cross-platform equivalent of a hardlink, and since file symlinks provide fundamentally different functionality in comparison to hardlinks." + "destinationFolders": { + "type": "array", + "description": "One or more folders that files and folders will be copied into, relative to the project root.", + "items": { + "type": "string", + "pattern": "[^\\\\]" } + }, + + "flatten": { + "type": "boolean", + "description": "Normally, copying will preserve the path relative to \"sourcePath\" under the destination folder (e.g. if \"sourcePath\" is \"src/test\" and \"destinationFolders\" is [\"out\"], \"src/test/a/b/c.txt\" will be copied to \"out/a/b/c.txt\"). Specify \"flatten=true\" to discard path information and keep only the filename (e.g. \"out/c.txt\"). If two files have the same name an error will be reported. The default value is false." + }, + + "hardlink": { + "type": "boolean", + "description": "If true, filesystem hard links will be created instead of copying the file. Depending on the operating system, this may be faster. The default value is false. NOTE: This may cause unexpected behavior if a tool modifies the link. The contained directory structure will be re-created and all files will be individually hardlinked. This means that folders will be new filesystem entities and will have separate folder metadata, while the contained files will maintain normal hardlink behavior. This is done since folders do not have a cross-platform equivalent of a hardlink, and since file symlinks provide fundamentally different functionality in comparison to hardlinks." } } } diff --git a/apps/heft/src/schemas/delete-files-options.schema.json b/apps/heft/src/schemas/delete-files-options.schema.json index 0e6c0a9ccae..d076e7ae8bc 100644 --- a/apps/heft/src/schemas/delete-files-options.schema.json +++ b/apps/heft/src/schemas/delete-files-options.schema.json @@ -1,7 +1,8 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "DeleteFiles Heft Task Event Options", "description": "Defines configuration used by the \"deleteFiles\" Heft task event.", + "x-tsdoc-release-tag": "@public", "type": "object", "additionalProperties": false, @@ -13,50 +14,47 @@ "description": "An array of delete operations to perform during the specified Heft event.", "items": { - "type": "object", - "additionalProperties": false, - "anyOf": [ - { "required": ["sourcePath"] }, - { "required": ["fileExtensions"] }, - { "required": ["includeGlobs"] }, - { "required": ["excludeGlobs"] } - ], - "properties": { - "sourcePath": { - "title": "Source Path", - "type": "string", - "description": "The base folder that files will be deleted from, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be deleted.", - "pattern": "[^\\\\]" - }, + "$ref": "#/$defs/deleteOperationBase" + } + } + }, + + "$defs": { + "deleteOperationBase": { + "description": "Configures a delete operation for the \"deleteFiles\" task event.", + "type": "object", + "additionalProperties": false, + "properties": { + "sourcePath": { + "type": "string", + "description": "The base folder that files will be deleted from, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be deleted.", + "pattern": "[^\\\\]" + }, - "fileExtensions": { - "title": "File Extensions", - "type": "array", - "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", - "items": { - "type": "string", - "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" - } - }, + "fileExtensions": { + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, - "excludeGlobs": { - "title": "Exclude Globs", - "type": "array", - "description": "A list of glob patterns that exclude files or folders from being deleted. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } - }, + "excludeGlobs": { + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being deleted. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, - "includeGlobs": { - "title": "Include Globs", - "type": "array", - "description": "A list of glob patterns that select files to be deleted. The paths are resolved relative to \"sourcePath\".", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } + "includeGlobs": { + "type": "array", + "description": "A list of glob patterns that select files to be deleted. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" } } } diff --git a/apps/heft/src/schemas/file-selection.schema.json b/apps/heft/src/schemas/file-selection.schema.json new file mode 100644 index 00000000000..1b3b2a652d2 --- /dev/null +++ b/apps/heft/src/schemas/file-selection.schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "File Selection Specifier Base", + "description": "Used to specify a selection of one or more files.", + "x-tsdoc-release-tag": "@public", + "type": "object", + "additionalProperties": false, + "properties": { + "sourcePath": { + "type": "string", + "description": "The target folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be used as-is. If this parameter is not provided, defaults to the project root.", + "pattern": "[^\\\\]" + }, + + "fileExtensions": { + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + + "excludeGlobs": { + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being selected. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "includeGlobs": { + "type": "array", + "description": "A list of glob patterns that select files to be included. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + } + } +} diff --git a/apps/heft/src/schemas/heft-plugin.schema.json b/apps/heft/src/schemas/heft-plugin.schema.json index 37dd45012d7..5a73c1b66b5 100644 --- a/apps/heft/src/schemas/heft-plugin.schema.json +++ b/apps/heft/src/schemas/heft-plugin.schema.json @@ -1,18 +1,17 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Heft Configuration", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Heft Plugin Configuration", "description": "Defines configuration used by core Heft.", "type": "object", - "definitions": { + "$defs": { "anything": { "type": ["array", "boolean", "integer", "number", "object", "string"], - "items": { "$ref": "#/definitions/anything" } + "items": { "$ref": "#/$defs/anything" } }, "baseParameter": { "type": "object", - "additionalProperties": true, "required": ["parameterKind", "longName", "description"], "properties": { "parameterKind": { @@ -50,305 +49,178 @@ "title": "Choice Parameter", "description": "A command-line parameter whose argument must be chosen from a list of allowable alternatives", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["alternatives"], - "properties": { - "parameterKind": { - "enum": ["choice"] - }, - "alternatives": { - "title": "Alternatives", - "description": "A list of alternative argument values that can be chosen for this parameter.", - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["name", "description"], - "properties": { - "name": { - "title": "Name of Alternative", - "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", - "type": "string" - }, - "description": { - "title": "Description of Alternative", - "description": "A detailed description for the alternative that will be shown in the command-line help.", - "type": "string" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choice"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" } - }, - "defaultValue": { - "title": "Default Value", - "description": "If the parameter is omitted from the command line, this value will be inserted by default", - "type": "string" } } }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "alternatives": { "$ref": "#/definitions/anything" }, - "defaultValue": { "$ref": "#/definitions/anything" } - } + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" } - ] + } }, "choiceListParameter": { "title": "Choice List Parameter", "description": "A command-line parameter whose arguments must be chosen from a list of allowable alternatives", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["alternatives"], - "properties": { - "parameterKind": { - "enum": ["choiceList"] - }, - "alternatives": { - "title": "Alternatives", - "description": "A list of alternative argument values that can be chosen for this parameter.", - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["name", "description"], - "properties": { - "name": { - "title": "Name of Alternative", - "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", - "type": "string" - }, - "description": { - "title": "Description of Alternative", - "description": "A detailed description for the alternative that will be shown in the command-line help.", - "type": "string" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choiceList"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" } } } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "alternatives": { "$ref": "#/definitions/anything" } - } } - ] + } }, "flagParameter": { "title": "Flag Parameter", "description": "A command-line parameter whose presence acts as an on/off switch", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "properties": { - "parameterKind": { - "enum": ["flag"] - } - } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "properties": { + "parameterKind": { + "enum": ["flag"] } - ] + } }, "integerParameter": { "title": "Integer Parameter", "description": "A command-line parameter whose value is interpreted as an integer", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["argumentName"], - "properties": { - "parameterKind": { - "enum": ["integer"] - }, - "argumentName": { - "title": "Argument Name", - "description": "The name of the argument for this parameter.", - "type": "string" - }, - "defaultValue": { - "title": "Default Value", - "description": "If the parameter is omitted from the command line, this value will be inserted by default", - "type": "integer" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integer"] }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "argumentName": { "$ref": "#/definitions/anything" }, - "defaultValue": { "$ref": "#/definitions/anything" } - } + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "integer" } - ] + } }, "integerListParameter": { "title": "Integer List Parameter", "description": "A command-line parameter whose value is interpreted as a list of integers", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["argumentName"], - "properties": { - "parameterKind": { - "enum": ["integerList"] - }, - "argumentName": { - "title": "Argument Name", - "description": "The name of the argument for this parameter.", - "type": "string" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integerList"] }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "argumentName": { "$ref": "#/definitions/anything" } - } + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" } - ] + } }, "stringParameter": { "title": "String Parameter", "description": "A command-line parameter whose value is interpreted as a string", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["argumentName"], - "properties": { - "parameterKind": { - "enum": ["string"] - }, - "argumentName": { - "title": "Argument Name", - "description": "The name of the argument for this parameter.", - "type": "string" - }, - "defaultValue": { - "title": "Default Value", - "description": "If the parameter is omitted from the command line, this value will be inserted by default", - "type": "string" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["string"] }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "argumentName": { "$ref": "#/definitions/anything" }, - "defaultValue": { "$ref": "#/definitions/anything" } - } + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" } - ] + } }, "stringListParameter": { "title": "String List Parameter", "description": "A command-line parameter whose value is interpreted as a string list", "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["argumentName"], - "properties": { - "parameterKind": { - "enum": ["stringList"] - }, - "argumentName": { - "title": "Argument Name", - "description": "The name of the argument for this parameter.", - "type": "string" - } - } + "unevaluatedProperties": false, + "allOf": [{ "$ref": "#/$defs/baseParameter" }], + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["stringList"] }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "argumentName": { "$ref": "#/definitions/anything" } - } + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" } - ] + } }, "heft-plugin-base": { @@ -391,13 +263,13 @@ "items": { "type": "object", "oneOf": [ - { "$ref": "#/definitions/flagParameter" }, - { "$ref": "#/definitions/integerParameter" }, - { "$ref": "#/definitions/integerListParameter" }, - { "$ref": "#/definitions/choiceParameter" }, - { "$ref": "#/definitions/choiceListParameter" }, - { "$ref": "#/definitions/stringParameter" }, - { "$ref": "#/definitions/stringListParameter" } + { "$ref": "#/$defs/flagParameter" }, + { "$ref": "#/$defs/integerParameter" }, + { "$ref": "#/$defs/integerListParameter" }, + { "$ref": "#/$defs/choiceParameter" }, + { "$ref": "#/$defs/choiceListParameter" }, + { "$ref": "#/$defs/stringParameter" }, + { "$ref": "#/$defs/stringListParameter" } ] } } @@ -405,11 +277,11 @@ }, "heft-lifecycle-plugin": { - "$ref": "#/definitions/heft-plugin-base" + "$ref": "#/$defs/heft-plugin-base" }, "heft-task-plugin": { - "$ref": "#/definitions/heft-plugin-base" + "$ref": "#/$defs/heft-plugin-base" } }, @@ -425,14 +297,14 @@ "title": "Lifecycle Plugins", "description": "A list of plugins that will be loaded and used for Heft lifecycle hooks.", "type": "array", - "items": { "$ref": "#/definitions/heft-lifecycle-plugin" } + "items": { "$ref": "#/$defs/heft-lifecycle-plugin" } }, "taskPlugins": { "title": "Task Plugins", "description": "A list of plugins that will be loaded and used for Heft task hooks.", "type": "array", - "items": { "$ref": "#/definitions/heft-task-plugin" } + "items": { "$ref": "#/$defs/heft-task-plugin" } } } } diff --git a/apps/heft/src/schemas/heft.schema.json b/apps/heft/src/schemas/heft.schema.json index cba91630724..26df02a6c65 100644 --- a/apps/heft/src/schemas/heft.schema.json +++ b/apps/heft/src/schemas/heft.schema.json @@ -1,13 +1,13 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Heft Configuration", "description": "Defines configuration used by core Heft.", "type": "object", - "definitions": { + "$defs": { "anything": { "type": ["array", "boolean", "integer", "number", "object", "string"], - "items": { "$ref": "#/definitions/anything" } + "items": { "$ref": "#/$defs/anything" } }, "heft-plugin": { @@ -51,18 +51,11 @@ } }, - "delete-operation": { + "fileSelectionSpecifierBase": { + "description": "Used to specify a selection of one or more files.", "type": "object", - "additionalProperties": false, - "anyOf": [ - { "required": ["sourcePath"] }, - { "required": ["fileExtensions"] }, - { "required": ["includeGlobs"] }, - { "required": ["excludeGlobs"] } - ], "properties": { "sourcePath": { - "title": "Source Path", "type": "string", "description": "The target file or folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the file or folder will be deleted.", "pattern": "[^\\\\]" @@ -77,7 +70,7 @@ }, "excludeGlobs": { "type": "array", - "description": "A list of glob patterns that exclude files or folders from being copied. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "description": "A list of glob patterns that exclude files or folders from being deleted. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", "items": { "type": "string", "pattern": "[^\\\\]" @@ -85,13 +78,26 @@ }, "includeGlobs": { "type": "array", - "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourcePath\".", + "description": "A list of glob patterns that select files to be deleted. The paths are resolved relative to \"sourcePath\".", "items": { "type": "string", "pattern": "[^\\\\]" } } } + }, + + "delete-operation": { + "type": "object", + "unevaluatedProperties": false, + "anyOf": [ + { "required": ["sourcePath"] }, + { "required": ["fileExtensions"] }, + { "required": ["includeGlobs"] }, + { "required": ["excludeGlobs"] } + ], + "allOf": [{ "$ref": "#/$defs/fileSelectionSpecifierBase" }], + "properties": {} } }, @@ -111,7 +117,7 @@ "heftPlugins": { "type": "array", "description": "List of Heft plugins that are used by a project.", - "items": { "$ref": "#/definitions/heft-plugin" } + "items": { "$ref": "#/$defs/heft-plugin" } }, "aliasesByName": { @@ -169,7 +175,7 @@ "cleanFiles": { "description": "List of delete operations to perform when cleaning at the beginning of phase execution.", "type": "array", - "items": { "$ref": "#/definitions/delete-operation" } + "items": { "$ref": "#/$defs/delete-operation" } }, "tasksByName": { @@ -183,7 +189,7 @@ "additionalProperties": false, "required": ["taskPlugin"], "properties": { - "taskPlugin": { "$ref": "#/definitions/heft-plugin" }, + "taskPlugin": { "$ref": "#/$defs/heft-plugin" }, "taskDependencies": { "type": "array", diff --git a/apps/heft/src/schemas/set-environment-variables-plugin.schema.json b/apps/heft/src/schemas/set-environment-variables-plugin.schema.json index 7ffa21d2967..9f5b3aeac8f 100644 --- a/apps/heft/src/schemas/set-environment-variables-plugin.schema.json +++ b/apps/heft/src/schemas/set-environment-variables-plugin.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "CopyFiles Heft Task Event Options", - "description": "Defines configuration used by the \"copyFiles\" Heft task event.", + "title": "SetEnvironmentVariables Heft Task Event Options", + "description": "Defines configuration used by the \"setEnvironmentVariables\" Heft task event.", "type": "object", "additionalProperties": false, diff --git a/common/reviews/api/heft.api.md b/common/reviews/api/heft.api.md index 96f4281126f..702d957fd6b 100644 --- a/common/reviews/api/heft.api.md +++ b/common/reviews/api/heft.api.md @@ -102,14 +102,30 @@ export class HeftConfiguration { } // @public -export interface ICopyOperation extends IFileSelectionSpecifier { +export interface ICopyOperation extends IFileSelectionSpecifier, ICopyOperationBase { +} + +// @public +export interface ICopyOperationBase { destinationFolders: string[]; + excludeGlobs?: string[]; + fileExtensions?: string[]; flatten?: boolean; hardlink?: boolean; + includeGlobs?: string[]; + sourcePath?: string; } // @public -export interface IDeleteOperation extends IFileSelectionSpecifier { +export interface IDeleteOperation extends IFileSelectionSpecifier, IDeleteOperationBase { +} + +// @public +export interface IDeleteOperationBase { + excludeGlobs?: string[]; + fileExtensions?: string[]; + includeGlobs?: string[]; + sourcePath?: string; } // @public @@ -377,7 +393,7 @@ export interface IRunScriptOptions { // (undocumented) runOptions: IHeftTaskRunHookOptions; // (undocumented) - scriptOptions: Record; + scriptOptions: Record | undefined; } // @public From fbba8deb9a450383e1ffc82634bd9a0e279e0654 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 19:13:30 -0800 Subject: [PATCH 27/40] fixup! Use schemas for typings in the heft plugins. --- common/reviews/api/heft-typescript-plugin.api.md | 12 +++++++----- heft-plugins/heft-typescript-plugin/src/index.ts | 5 ++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/reviews/api/heft-typescript-plugin.api.md b/common/reviews/api/heft-typescript-plugin.api.md index 3e841c7104b..5c0292cf421 100644 --- a/common/reviews/api/heft-typescript-plugin.api.md +++ b/common/reviews/api/heft-typescript-plugin.api.md @@ -10,6 +10,12 @@ import semver from 'semver'; import { SyncHook } from 'tapable'; import type * as _TTypeScript from 'typescript'; +// @beta (undocumented) +export interface AdditionalModuleKindToEmit { + moduleKind: "commonjs" | "amd" | "umd" | "system" | "es2015" | "esnext"; + outFolderName: string; +} + // @internal (undocumented) export function _getTsconfigFilePath(heftConfiguration: HeftConfiguration, tsconfigRelativePath: string | undefined): string; @@ -108,11 +114,7 @@ export { _TTypeScript } // @beta export interface TypeScriptBuildConfiguration { $schema?: string; - additionalModuleKindsToEmit?: { - moduleKind: "commonjs" | "amd" | "umd" | "system" | "es2015" | "esnext"; - outFolderName: string; - [k: string]: unknown; - }[]; + additionalModuleKindsToEmit?: AdditionalModuleKindToEmit[]; buildProjectReferences?: boolean; emitCjsExtensionForCommonJS?: boolean; emitMjsExtensionForESModule?: boolean; diff --git a/heft-plugins/heft-typescript-plugin/src/index.ts b/heft-plugins/heft-typescript-plugin/src/index.ts index dcf65151e67..462a12698e2 100644 --- a/heft-plugins/heft-typescript-plugin/src/index.ts +++ b/heft-plugins/heft-typescript-plugin/src/index.ts @@ -16,7 +16,10 @@ export type { /** * @beta */ -export type { TypeScriptBuildConfiguration } from './schemas/typescript.schema.json.d.ts'; +export type { + TypeScriptBuildConfiguration, + AdditionalModuleKindToEmit +} from './schemas/typescript.schema.json.d.ts'; export { PLUGIN_NAME as TypeScriptPluginName, From 34c721ca1698864cd74e6bf222af56cbb44d6413 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 19:24:40 -0800 Subject: [PATCH 28/40] fixup! Use schemas for typings in the heft plugins. --- .../reviews/api/heft-typescript-plugin.api.md | 55 ++++++++++--------- .../src/TypeScriptPlugin.ts | 26 ++++++--- .../heft-typescript-plugin/src/index.ts | 10 +--- .../src/schemas/typescript.schema.json | 6 +- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/common/reviews/api/heft-typescript-plugin.api.md b/common/reviews/api/heft-typescript-plugin.api.md index 5c0292cf421..436c37e2d66 100644 --- a/common/reviews/api/heft-typescript-plugin.api.md +++ b/common/reviews/api/heft-typescript-plugin.api.md @@ -10,12 +10,6 @@ import semver from 'semver'; import { SyncHook } from 'tapable'; import type * as _TTypeScript from 'typescript'; -// @beta (undocumented) -export interface AdditionalModuleKindToEmit { - moduleKind: "commonjs" | "amd" | "umd" | "system" | "es2015" | "esnext"; - outFolderName: string; -} - // @internal (undocumented) export function _getTsconfigFilePath(heftConfiguration: HeftConfiguration, tsconfigRelativePath: string | undefined): string; @@ -45,6 +39,12 @@ export interface _ICompilerCapabilities { solutionBuilder: boolean; } +// @beta (undocumented) +export interface IEmitModuleKind { + moduleKind: "commonjs" | "amd" | "umd" | "system" | "es2015" | "esnext"; + outFolderName: string; +} + // @internal (undocumented) export interface _ILoadedTypeScriptTool { // (undocumented) @@ -92,29 +92,12 @@ export interface IPartialTsconfigCompilerOptions { } // @beta (undocumented) -export interface ITypeScriptPluginAccessor { - // (undocumented) - readonly onChangedFilesHook: SyncHook; -} - -// @beta (undocumented) -export function loadPartialTsconfigFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal, typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined): Promise; - -// @internal (undocumented) -export function _loadTsconfig(options: _ILoadTsconfigOptions): _TTypeScript.ParsedCommandLine; - -// @beta (undocumented) -export function loadTypeScriptConfigurationFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal): Promise; - -// @internal (undocumented) -export function _loadTypeScriptToolAsync(options: _ILoadTypeScriptToolOptions): Promise<_ILoadedTypeScriptTool>; - -export { _TTypeScript } +export type IStaticAssetsCopyConfiguration = ITypeScriptConfigurationJson['staticAssetsToCopy']; // @beta -export interface TypeScriptBuildConfiguration { +export interface ITypeScriptConfigurationJson { $schema?: string; - additionalModuleKindsToEmit?: AdditionalModuleKindToEmit[]; + additionalModuleKindsToEmit?: IEmitModuleKind[]; buildProjectReferences?: boolean; emitCjsExtensionForCommonJS?: boolean; emitMjsExtensionForESModule?: boolean; @@ -129,6 +112,26 @@ export interface TypeScriptBuildConfiguration { useTranspilerWorker?: boolean; } +// @beta (undocumented) +export interface ITypeScriptPluginAccessor { + // (undocumented) + readonly onChangedFilesHook: SyncHook; +} + +// @beta (undocumented) +export function loadPartialTsconfigFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal, typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined): Promise; + +// @internal (undocumented) +export function _loadTsconfig(options: _ILoadTsconfigOptions): _TTypeScript.ParsedCommandLine; + +// @beta (undocumented) +export function loadTypeScriptConfigurationFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal): Promise; + +// @internal (undocumented) +export function _loadTypeScriptToolAsync(options: _ILoadTypeScriptToolOptions): Promise<_ILoadedTypeScriptTool>; + +export { _TTypeScript } + // @public export const TypeScriptPluginName: 'typescript-plugin'; diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts index f3bb2c61ac7..8065e151d41 100644 --- a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts @@ -23,9 +23,19 @@ import type { import { TypeScriptBuilder, type ITypeScriptBuilderConfiguration } from './TypeScriptBuilder'; import anythingSchema from './schemas/anything.schema.json'; import typescriptConfigSchema from './schemas/typescript.schema.json'; -import type { TypeScriptBuildConfiguration } from './schemas/typescript.schema.json.d.ts'; +import type { + TypeScriptBuildConfiguration as ITypeScriptConfigurationJson, + AdditionalModuleKindToEmit as IEmitModuleKind +} from './schemas/typescript.schema.json.d.ts'; import { getTsconfigFilePath } from './tsconfigLoader'; +/** + * @beta + */ +export type IStaticAssetsCopyConfiguration = ITypeScriptConfigurationJson['staticAssetsToCopy']; + +export { IEmitModuleKind, ITypeScriptConfigurationJson }; + /** * The name of the plugin, as specified in heft-plugin.json * @@ -68,9 +78,7 @@ export interface ITypeScriptPluginAccessor { readonly onChangedFilesHook: SyncHook; } -type IStaticAssetsCopyConfiguration = TypeScriptBuildConfiguration['staticAssetsToCopy']; - -const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpecification = +const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpecification = { projectRelativeFilePath: 'config/typescript.json', jsonSchemaObject: typescriptConfigSchema, @@ -93,8 +101,8 @@ const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpeci export async function loadTypeScriptConfigurationFileAsync( heftConfiguration: HeftConfiguration, terminal: ITerminal -): Promise { - return await heftConfiguration.tryLoadProjectConfigurationFileAsync( +): Promise { + return await heftConfiguration.tryLoadProjectConfigurationFileAsync( TYPESCRIPT_LOADER_CONFIG, terminal ); @@ -109,7 +117,7 @@ const _partialTsconfigFilePromiseCache: Map { const buildFolderPath: string = heftConfiguration.buildFolderPath; @@ -175,7 +183,7 @@ export async function loadPartialTsconfigFileAsync( } interface ITypeScriptConfigurationJsonAndPartialTsconfigFile { - typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined; + typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined; partialTsconfigFile: IPartialTsconfig | undefined; } @@ -330,7 +338,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { ): Promise { const terminal: ITerminal = taskSession.logger.terminal; - const typeScriptConfigurationJson: TypeScriptBuildConfiguration | undefined = + const typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined = await loadTypeScriptConfigurationFileAsync(heftConfiguration, terminal); const partialTsconfigFile: IPartialTsconfig | undefined = await loadPartialTsconfigFileAsync( diff --git a/heft-plugins/heft-typescript-plugin/src/index.ts b/heft-plugins/heft-typescript-plugin/src/index.ts index 462a12698e2..4b727d4baa1 100644 --- a/heft-plugins/heft-typescript-plugin/src/index.ts +++ b/heft-plugins/heft-typescript-plugin/src/index.ts @@ -8,18 +8,14 @@ */ export type { + IEmitModuleKind, + IStaticAssetsCopyConfiguration, + ITypeScriptConfigurationJson, IPartialTsconfigCompilerOptions, IPartialTsconfig, IChangedFilesHookOptions, ITypeScriptPluginAccessor } from './TypeScriptPlugin'; -/** - * @beta - */ -export type { - TypeScriptBuildConfiguration, - AdditionalModuleKindToEmit -} from './schemas/typescript.schema.json.d.ts'; export { PLUGIN_NAME as TypeScriptPluginName, diff --git a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json index 64b8d25aad1..056dc522d66 100644 --- a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json +++ b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json @@ -1,7 +1,8 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "title": "TypeScript Build Configuration", - "description": "Defines optional options for TypeScript build.\n\n@beta", + "description": "Defines optional options for TypeScript build.", + "x-tsdoc-release-tag": "@beta", "type": "object", "additionalProperties": false, @@ -9,13 +10,16 @@ "definitions": { "additionalModuleKindToEmit": { "type": "object", + "additionalProperties": false, "properties": { "moduleKind": { + "description": "Specifies the module format to emit. The value must be one of the module formats supported by the TypeScript compiler.", "type": "string", "enum": ["commonjs", "amd", "umd", "system", "es2015", "esnext"] }, "outFolderName": { + "description": "Specifies the output folder name where the compiler will emit the module format. This folder name is resolved relative to the project root.", "type": "string", "pattern": "[^\\\\\\/]" } From 624be0a4dc217847ee5f5d69dffc23a5d7b80ac1 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 19:29:27 -0800 Subject: [PATCH 29/40] fixup! Add support for draft-2019-09 schemas. --- .../JsonSchemaTypingsGenerator.test.ts.snap | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap index e65a7d9d88a..7b73aa261af 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap @@ -54,6 +54,44 @@ export interface Type2 { ", "./test-schema-draft-07.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior +export interface TestSchemaFile { + exampleString: string; + exampleLink?: string; + exampleArray: string[]; + /** + * Description for exampleOneOf - this is a very long description to show in an error message + */ + exampleOneOf?: Type1 | Type2; + exampleUniqueObjectArray?: { + field2?: string; + field3?: string; + }[]; +} +/** + * Description for type1 + */ +export interface Type1 { + /** + * Description for field1 + */ + field1: string; +} +/** + * Description for type2 + */ +export interface Type2 { + /** + * Description for field2 + */ + field2: string; + /** + * Description for field3 + */ + field3: string; +} +", + "./test-schema-draft-2019-09.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + export interface TestSchemaFile { exampleString: string; exampleLink?: string; @@ -238,6 +276,44 @@ field3: string ", "./test-schema-draft-07.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior +export interface TestSchemaFile { +exampleString: string +exampleLink?: string +exampleArray: string[] +/** + * Description for exampleOneOf - this is a very long description to show in an error message + */ +exampleOneOf?: (Type1 | Type2) +exampleUniqueObjectArray?: { +field2?: string +field3?: string +}[] +} +/** + * Description for type1 + */ +export interface Type1 { +/** + * Description for field1 + */ +field1: string +} +/** + * Description for type2 + */ +export interface Type2 { +/** + * Description for field2 + */ +field2: string +/** + * Description for field3 + */ +field3: string +} +", + "./test-schema-draft-2019-09.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + export interface TestSchemaFile { exampleString: string exampleLink?: string From dd3682503a742fe5c970921b3ee30732caaa06fc Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 20:03:02 -0800 Subject: [PATCH 30/40] Use the generated types in api-extractor. --- apps/api-extractor/src/api/ExtractorConfig.ts | 3 +- apps/api-extractor/src/api/IConfigFile.ts | 477 +----------------- .../src/collector/MessageRouter.ts | 2 +- .../src/schemas/api-extractor.schema.json | 110 ++-- common/reviews/api/api-extractor.api.md | 26 +- 5 files changed, 120 insertions(+), 498 deletions(-) diff --git a/apps/api-extractor/src/api/ExtractorConfig.ts b/apps/api-extractor/src/api/ExtractorConfig.ts index 47f16e6c020..4f74843dc75 100644 --- a/apps/api-extractor/src/api/ExtractorConfig.ts +++ b/apps/api-extractor/src/api/ExtractorConfig.ts @@ -1208,7 +1208,8 @@ export class ExtractorConfig { break; } - const enumMemberOrder: EnumMemberOrder = configObject.enumMemberOrder ?? EnumMemberOrder.ByName; + const enumMemberOrder: EnumMemberOrder = + (configObject.enumMemberOrder as EnumMemberOrder) ?? EnumMemberOrder.ByName; extractorConfigParameters = { projectFolder: projectFolder, diff --git a/apps/api-extractor/src/api/IConfigFile.ts b/apps/api-extractor/src/api/IConfigFile.ts index f05b943f796..917928a1ac4 100644 --- a/apps/api-extractor/src/api/IConfigFile.ts +++ b/apps/api-extractor/src/api/IConfigFile.ts @@ -1,9 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { EnumMemberOrder } from '@microsoft/api-extractor-model'; - -import type { ExtractorLogLevel } from './ExtractorLogLevel'; +import type { + APIExtractorConfiguration as IConfigFile, + ApiReportVariant, + ConfigApiReport as IConfigApiReport, + ConfigCompiler as IConfigCompiler, + ConfigDocModel as IConfigDocModel, + ConfigDtsRollup as IConfigDtsRollup, + ConfigMessageReportingRule as IConfigMessageReportingRule, + ConfigTsdocMetadata as IConfigTsdocMetadata, + ExtractorMessageReportingTable as IConfigMessageReportingTable, + ExtractorMessagesConfig as IExtractorMessagesConfig, + ReleaseTagForTrim +} from '../schemas/api-extractor.schema.json.d.ts'; /** * Determines how the TypeScript compiler engine will be invoked by API Extractor. @@ -13,48 +23,14 @@ import type { ExtractorLogLevel } from './ExtractorLogLevel'; * * @public */ -export interface IConfigCompiler { - /** - * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. - * - * @remarks - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - * - * Note: This setting will be ignored if `overrideTsconfig` is used. - */ - tsconfigFilePath?: string; - - /** - * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. - * - * @remarks - * The value must conform to the TypeScript tsconfig schema: - * - * http://json.schemastore.org/tsconfig - * - * If omitted, then the tsconfig.json file will instead be read from the projectFolder. - */ - overrideTsconfig?: {}; - - /** - * This option causes the compiler to be invoked with the `--skipLibCheck` option. - * - * @remarks - * This option is not recommended and may cause API Extractor to produce incomplete or incorrect declarations, - * but it may be required when dependencies contain declarations that are incompatible with the TypeScript engine - * that API Extractor uses for its analysis. Where possible, the underlying issue should be fixed rather than - * relying on skipLibCheck. - */ - skipLibCheck?: boolean; -} +export type { IConfigCompiler }; /** * The allowed variations of API reports. * * @public */ -export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; +export type { ApiReportVariant }; /** * Configures how the API report files (*.api.md) will be generated. @@ -64,124 +40,13 @@ export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; * * @public */ -export interface IConfigApiReport { - /** - * Whether to generate an API report. - */ - enabled: boolean; - - /** - * The base filename for the API report files, to be combined with {@link IConfigApiReport.reportFolder} or - * {@link IConfigApiReport.reportTempFolder} to produce the full file path. - * - * @remarks - * The `reportFileName` should not include any path separators such as `\` or `/`. The `reportFileName` should - * not include a file extension, since API Extractor will automatically append an appropriate file extension such - * as `.api.md`. If the {@link IConfigApiReport.reportVariants} setting is used, then the file extension includes - * the variant name, for example `my-report.public.api.md` or `my-report.beta.api.md`. The `complete` variant always - * uses the simple extension `my-report.api.md`. - * - * Previous versions of API Extractor required `reportFileName` to include the `.api.md` extension explicitly; - * for backwards compatibility, that is still accepted but will be discarded before applying the above rules. - * - * @defaultValue `` - */ - reportFileName?: string; - - /** - * The set of report variants to generate. - * - * @remarks - * To support different approval requirements for different API levels, multiple "variants" of the API report can - * be generated. The `reportVariants` setting specifies a list of variants to be generated. If omitted, - * by default only the `complete` variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, - * and `@public` items. Other possible variants are `alpha` (`@alpha` + `@beta` + `@public`), - * `beta` (`@beta` + `@public`), and `public` (`@public only`). - * - * The resulting API report file names will be derived from the {@link IConfigApiReport.reportFileName}. - * - * @defaultValue `[ "complete" ]` - */ - reportVariants?: ApiReportVariant[]; - - /** - * Specifies the folder where the API report file is written. The file name portion is determined by - * the `reportFileName` setting. - * - * @remarks - * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, - * e.g. for an API review. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - reportFolder?: string; - - /** - * Specifies the folder where the temporary report file is written. The file name portion is determined by - * the `reportFileName` setting. - * - * @remarks - * After the temporary file is written to disk, it is compared with the file in the `reportFolder`. - * If they are different, a production build will fail. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - reportTempFolder?: string; - - /** - * Whether "forgotten exports" should be included in the API report file. - * - * @remarks - * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See - * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. - * - * @defaultValue `false` - */ - includeForgottenExports?: boolean; - - /** - * Specifies a list of {@link https://tsdoc.org/ | TSDoc} tags that should be reported in the API report file for - * items whose documentation contains them. - * - * @remarks - * Tag names must begin with `@`. - * - * This list may include standard TSDoc tags as well as custom ones. - * For more information on defining custom TSDoc tags, see - * {@link https://api-extractor.com/pages/configs/tsdoc_json/#defining-your-own-tsdoc-tags | here}. - * - * Note that an item's release tag will always reported; this behavior cannot be overridden. - * - * @defaultValue `@sealed`, `@virtual`, `@override`, `@eventProperty`, and `@deprecated` - * - * @example Omitting default tags - * To omit the `@sealed` and `@virtual` tags from API reports, you would specify `tagsToReport` as follows: - * ```json - * "tagsToReport": { - * "@sealed": false, - * "@virtual": false - * } - * ``` - * - * @example Including additional tags - * To include additional tags to the set included in API reports, you could specify `tagsToReport` like this: - * ```json - * "tagsToReport": { - * "@customTag": true - * } - * ``` - * This will result in `@customTag` being included in addition to the default tags. - */ - tagsToReport?: Readonly>; -} +export type { IConfigApiReport }; /** * The allowed release tags that can be used to mark API items. * @public */ -export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; +export type { ReleaseTagForTrim }; /** * Configures how the doc model file (*.api.json) will be generated. @@ -191,53 +56,7 @@ export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; * * @public */ -export interface IConfigDocModel { - /** - * Whether to generate a doc model file. - */ - enabled: boolean; - - /** - * The output path for the doc model file. The file extension should be ".api.json". - * - * @remarks - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - apiJsonFilePath?: string; - - /** - * Whether "forgotten exports" should be included in the doc model file. - * - * @remarks - * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See - * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. - * - * @defaultValue `false` - */ - includeForgottenExports?: boolean; - - /** - * The base URL where the project's source code can be viewed on a website such as GitHub or - * Azure DevOps. This URL path corresponds to the `` path on disk. - * - * @remarks - * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. - * For example, if the `projectFolderUrl` is "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor" and an API - * item's file path is "api/ExtractorConfig.ts", the full URL file path would be - * "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js". - * - * Can be omitted if you don't need source code links in your API documentation reference. - */ - projectFolderUrl?: string; - - /** - * Specifies a list of release tags that will be trimmed from the doc model. - * - * @defaultValue `["@internal"]` - */ - releaseTagsToTrim?: ReleaseTagForTrim[]; -} +export type { IConfigDocModel }; /** * Configures how the .d.ts rollup file will be generated. @@ -247,67 +66,7 @@ export interface IConfigDocModel { * * @public */ -export interface IConfigDtsRollup { - /** - * Whether to generate the .d.ts rollup file. - */ - enabled: boolean; - - /** - * Specifies the output path for a .d.ts rollup file to be generated without any trimming. - * - * @remarks - * This file will include all declarations that are exported by the main entry point. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - untrimmedFilePath?: string; - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. - * - * @remarks - * This file will include only declarations that are marked as `@public`, `@beta`, or `@alpha`. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - alphaTrimmedFilePath?: string; - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. - * - * @remarks - * This file will include only declarations that are marked as `@public` or `@beta`. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - betaTrimmedFilePath?: string; - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. - * - * @remarks - * This file will include only declarations that are marked as `@public`. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - */ - publicTrimmedFilePath?: string; - - /** - * When a declaration is trimmed, by default it will be replaced by a code comment such as - * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the - * declaration completely. - */ - omitTrimmingComments?: boolean; -} +export type { IConfigDtsRollup }; /** * Configures how the tsdoc-metadata.json file will be generated. @@ -317,25 +76,7 @@ export interface IConfigDtsRollup { * * @public */ -export interface IConfigTsdocMetadata { - /** - * Whether to generate the tsdoc-metadata.json file. - */ - enabled: boolean; - - /** - * Specifies where the TSDoc metadata file should be written. - * - * @remarks - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as ``. - * - * The default value is ``, which causes the path to be automatically inferred from the `tsdocMetadata`, - * `typings` or `main` fields of the project's package.json. If none of these fields are set, the lookup - * falls back to `tsdoc-metadata.json` in the package folder. - */ - tsdocMetadataFilePath?: string; -} +export type { IConfigTsdocMetadata }; /** * Configures reporting for a given message identifier. @@ -345,22 +86,7 @@ export interface IConfigTsdocMetadata { * * @public */ -export interface IConfigMessageReportingRule { - /** - * Specifies whether the message should be written to the the tool's output log. - * - * @remarks - * Note that the `addToApiReportFile` property may supersede this option. - */ - logLevel: ExtractorLogLevel; - - /** - * When `addToApiReportFile` is true: If API Extractor is configured to write an API report file (.api.md), - * then the message will be written inside that file; otherwise, the message is instead logged according to - * the `logLevel` option. - */ - addToApiReportFile?: boolean; -} +export type { IConfigMessageReportingRule }; /** * Specifies a table of reporting rules for different message identifiers, and also the default rule used for @@ -371,14 +97,7 @@ export interface IConfigMessageReportingRule { * * @public */ -export interface IConfigMessageReportingTable { - /** - * The key is a message identifier for the associated type of message, or "default" to specify the default policy. - * For example, the key might be `TS2551` (a compiler message), `tsdoc-link-tag-unescaped-text` (a TSDOc message), - * or `ae-extra-release-tag` (a message related to the API Extractor analysis). - */ - [messageId: string]: IConfigMessageReportingRule; -} +export type { IConfigMessageReportingTable }; /** * Configures how API Extractor reports error and warning messages produced during analysis. @@ -388,159 +107,11 @@ export interface IConfigMessageReportingTable { * * @public */ -export interface IExtractorMessagesConfig { - /** - * Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the - * input .d.ts files. - */ - compilerMessageReporting?: IConfigMessageReportingTable; - - /** - * Configures handling of messages reported by API Extractor during its analysis. - */ - extractorMessageReporting?: IConfigMessageReportingTable; - - /** - * Configures handling of messages reported by the TSDoc parser when analyzing code comments. - */ - tsdocMessageReporting?: IConfigMessageReportingTable; -} - +export type { IExtractorMessagesConfig }; /** * Configuration options for the API Extractor tool. These options can be constructed programmatically * or loaded from the api-extractor.json config file using the {@link ExtractorConfig} class. * * @public */ -export interface IConfigFile { - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for - * standard settings to be shared across multiple projects. - * - * @remarks - * If the path starts with `./` or `../`, the path is resolved relative to the folder of the file that contains - * the `extends` field. Otherwise, the first path segment is interpreted as an NPM package name, and will be - * resolved using NodeJS `require()`. - */ - extends?: string; - - /** - * Determines the `` token that can be used with other config file settings. The project folder - * typically contains the tsconfig.json and package.json config files, but the path is user-defined. - * - * @remarks - * - * The path is resolved relative to the folder of the config file that contains the setting. - * - * The default value for `projectFolder` is the token ``, which means the folder is determined using - * the following heuristics: - * - * If the config/rig.json system is used (as defined by {@link https://www.npmjs.com/package/@rushstack/rig-package - * | @rushstack/rig-package}), then the `` value will be the package folder that referenced the rig. - * - * Otherwise, the `` value is determined by traversing parent folders, starting from the folder containing - * api-extractor.json, and stopping at the first folder that contains a tsconfig.json file. If a tsconfig.json file - * cannot be found in this way, then an error will be reported. - */ - projectFolder?: string; - - /** - * Specifies the .d.ts file to be used as the starting point for analysis. API Extractor - * analyzes the symbols exported by this module. - * - * @remarks - * - * The file extension must be ".d.ts" and not ".ts". - * The path is resolved relative to the "projectFolder" location. - */ - mainEntryPointFilePath: string; - - /** - * A list of NPM package names whose exports should be treated as part of this package. - * - * @remarks - * Also supports glob patterns. - * Note: glob patterns will **only** be resolved against dependencies listed in the project's package.json file. - * - * * This is both a safety and a performance precaution. - * - * Exact package names will be applied against any dependency encountered while walking the type graph, regardless of - * dependencies listed in the package.json. - * - * @example - * - * Suppose that Webpack is used to generate a distributed bundle for the project `library1`, - * and another NPM package `library2` is embedded in this bundle. Some types from `library2` may become part - * of the exported API for `library1`, but by default API Extractor would generate a .d.ts rollup that explicitly - * imports `library2`. To avoid this, we can specify: - * - * ```js - * "bundledPackages": [ "library2" ], - * ``` - * - * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been - * local files for `library1`. - */ - bundledPackages?: string[]; - - /** - * Specifies what type of newlines API Extractor should use when writing output files. - * - * @remarks - * By default, the output files will be written with Windows-style newlines. - * To use POSIX-style newlines, specify "lf" instead. - * To use the OS's default newline kind, specify "os". - */ - newlineKind?: 'crlf' | 'lf' | 'os'; - - /** - * Set to true when invoking API Extractor's test harness. - * @remarks - * When `testMode` is true, the `toolVersion` field in the .api.json file is assigned an empty string - * to prevent spurious diffs in output files tracked for tests. - */ - testMode?: boolean; - - /** - * Specifies how API Extractor sorts members of an enum when generating the .api.json file. - * - * @remarks - * By default, the output files will be sorted alphabetically, which is "by-name". - * To keep the ordering in the source code, specify "preserve". - * - * @defaultValue `by-name` - */ - enumMemberOrder?: EnumMemberOrder; - - /** - * {@inheritDoc IConfigCompiler} - */ - compiler?: IConfigCompiler; - - /** - * {@inheritDoc IConfigApiReport} - */ - apiReport?: IConfigApiReport; - - /** - * {@inheritDoc IConfigDocModel} - */ - docModel?: IConfigDocModel; - - /** - * {@inheritDoc IConfigDtsRollup} - * @beta - */ - dtsRollup?: IConfigDtsRollup; - - /** - * {@inheritDoc IConfigTsdocMetadata} - * @beta - */ - tsdocMetadata?: IConfigTsdocMetadata; - - /** - * {@inheritDoc IExtractorMessagesConfig} - */ - messages?: IExtractorMessagesConfig; -} +export type { IConfigFile }; diff --git a/apps/api-extractor/src/collector/MessageRouter.ts b/apps/api-extractor/src/collector/MessageRouter.ts index bc09397c084..984ca710931 100644 --- a/apps/api-extractor/src/collector/MessageRouter.ts +++ b/apps/api-extractor/src/collector/MessageRouter.ts @@ -175,7 +175,7 @@ export class MessageRouter { private static _getNormalizedRule(rule: IConfigMessageReportingRule): IReportingRule { return { - logLevel: rule.logLevel || 'none', + logLevel: (rule.logLevel || 'none') as ExtractorLogLevel, addToApiReportFile: rule.addToApiReportFile || false }; } diff --git a/apps/api-extractor/src/schemas/api-extractor.schema.json b/apps/api-extractor/src/schemas/api-extractor.schema.json index 8bd8fdaef13..0b40686313d 100644 --- a/apps/api-extractor/src/schemas/api-extractor.schema.json +++ b/apps/api-extractor/src/schemas/api-extractor.schema.json @@ -1,6 +1,7 @@ { "title": "API Extractor Configuration", "description": "Describes how the API Extractor tool will process a project.", + "x-tsdoc-release-tag": "@public", "type": "object", "properties": { "$schema": { @@ -51,6 +52,40 @@ }, "compiler": { + "description": "Determines how the TypeScript compiler engine will be invoked by API Extractor.", + "allOf": [{ "$ref": "#/definitions/configCompiler" }] + }, + + "apiReport": { + "description": "Configures how the API report file (*.api.md) will be generated.", + "allOf": [{ "$ref": "#/definitions/configApiReport" }] + }, + + "docModel": { + "description": "Configures how the doc model file (*.api.json) will be generated.", + "allOf": [{ "$ref": "#/definitions/configDocModel" }] + }, + + "dtsRollup": { + "description": "Configures how the .d.ts rollup file will be generated.", + "allOf": [{ "$ref": "#/definitions/configDtsRollup" }] + }, + + "tsdocMetadata": { + "description": "Configures how the tsdoc-metadata.json file will be generated.", + "allOf": [{ "$ref": "#/definitions/configTsdocMetadata" }] + }, + + "messages": { + "description": "Configures how API Extractor reports error and warning messages produced during analysis.", + "allOf": [{ "$ref": "#/definitions/extractorMessagesConfig" }] + } + }, + "required": ["mainEntryPointFilePath"], + "additionalProperties": false, + + "definitions": { + "configCompiler": { "description": "Determines how the TypeScript compiler engine will be invoked by API Extractor.", "type": "object", "properties": { @@ -70,8 +105,14 @@ "additionalProperties": false }, - "apiReport": { - "description": "Configures how the API report file (*.api.md) will be generated.", + "apiReportVariant": { + "description": "The allowed variations of API reports.", + "type": "string", + "enum": ["public", "beta", "alpha", "complete"] + }, + + "configApiReport": { + "description": "Configures how the API report files (*.api.md) will be generated.", "type": "object", "properties": { "enabled": { @@ -88,8 +129,7 @@ "description": "To support different approval requirements for different API levels, multiple \"variants\" of the API report can be generated. The \"reportVariants\" setting specifies a list of variants to be generated. If omitted, by default only the \"complete\" variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, and `@public` items. Other possible variants are \"alpha\" (`@alpha` + `@beta` + `@public`), \"beta\" (`@beta` + `@public`), and \"public\" (`@public` only).", "type": "array", "items": { - "type": "string", - "enum": ["public", "beta", "alpha", "complete"] + "$ref": "#/definitions/apiReportVariant" } }, @@ -123,7 +163,13 @@ "additionalProperties": false }, - "docModel": { + "releaseTagForTrim": { + "description": "The allowed release tags that can be used to trim API items.", + "type": "string", + "enum": ["@internal", "@alpha", "@beta", "@public"] + }, + + "configDocModel": { "description": "Configures how the doc model file (*.api.json) will be generated.", "type": "object", "properties": { @@ -147,7 +193,7 @@ "description": "Specifies a list of release tags that will be trimmed from the doc model. The default value is `[\"@internal\"]`.", "type": "array", "items": { - "enum": ["@internal", "@alpha", "@beta", "@public"] + "$ref": "#/definitions/releaseTagForTrim" }, "uniqueItems": true } @@ -156,7 +202,7 @@ "additionalProperties": false }, - "dtsRollup": { + "configDtsRollup": { "description": "Configures how the .d.ts rollup file will be generated.", "type": "object", "properties": { @@ -189,7 +235,7 @@ "additionalProperties": false }, - "tsdocMetadata": { + "configTsdocMetadata": { "description": "Configures how the tsdoc-metadata.json file will be generated.", "type": "object", "properties": { @@ -205,53 +251,53 @@ "additionalProperties": false }, - "messages": { + "extractorMessagesConfig": { "description": "Configures how API Extractor reports error and warning messages produced during analysis.", "type": "object", "properties": { "compilerMessageReporting": { "description": "Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the input .d.ts files.", - "$ref": "#/definitions/extractorMessageReportingTable" + "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] }, "extractorMessageReporting": { "description": "Configures handling of messages reported by API Extractor during its analysis.", - "$ref": "#/definitions/extractorMessageReportingTable" + "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] }, "tsdocMessageReporting": { "description": "Configures handling of messages reported by the TSDoc parser when analyzing code comments.", - "$ref": "#/definitions/extractorMessageReportingTable" + "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] } }, "additionalProperties": false - } - }, - "required": ["mainEntryPointFilePath"], - "additionalProperties": false, + }, - "definitions": { "extractorMessageReportingTable": { "type": "object", "description": "Specifies a table of reporting rules for different message identifiers, and also the default rule used for identifiers that do not appear in the table. The key is a message identifier for the associated type of message, or \"default\" to specify the default policy. For example, the key might be \"TS2551\" (a compiler message), \"tsdoc-link-tag-unescaped-text\" (a TSDOc message), or \"ae-extra-release-tag\" (a message related to the API Extractor analysis).", "patternProperties": { ".+": { - "type": "object", - "description": "Configures reporting for a given message identifier.", - "properties": { - "logLevel": { - "type": "string", - "description": "Specifies whether the message should be written to the the tool's output log. Note that the \"addToApiReportFile\" property may supersede this option.", - "enum": ["error", "warning", "none"] - }, - "addToApiReportFile": { - "type": "boolean", - "description": "If API Extractor is configured to write an API review file (.api.md), then the message will be written inside that file. If the API review file is NOT being written, then the message is instead logged according to the \"logLevel\" option." - } - }, - "additionalProperties": false, - "required": ["logLevel"] + "$ref": "#/definitions/configMessageReportingRule" } }, "additionalProperties": false + }, + + "configMessageReportingRule": { + "type": "object", + "description": "Configures reporting for a given message identifier.", + "properties": { + "logLevel": { + "type": "string", + "description": "Specifies whether the message should be written to the the tool's output log. Note that the \"addToApiReportFile\" property may supersede this option.", + "enum": ["error", "warning", "none"] + }, + "addToApiReportFile": { + "type": "boolean", + "description": "If API Extractor is configured to write an API review file (.api.md), then the message will be written inside that file. If the API review file is NOT being written, then the message is instead logged according to the \"logLevel\" option." + } + }, + "additionalProperties": false, + "required": ["logLevel"] } } } diff --git a/common/reviews/api/api-extractor.api.md b/common/reviews/api/api-extractor.api.md index f44ecd8e92b..83f2baa8e49 100644 --- a/common/reviews/api/api-extractor.api.md +++ b/common/reviews/api/api-extractor.api.md @@ -16,7 +16,7 @@ import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { TSDocConfiguration } from '@microsoft/tsdoc'; // @public -export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; +export type ApiReportVariant = "public" | "beta" | "alpha" | "complete"; // @public export class CompilerState { @@ -195,12 +195,16 @@ export interface IConfigApiReport { reportFolder?: string; reportTempFolder?: string; reportVariants?: ApiReportVariant[]; - tagsToReport?: Readonly>; + tagsToReport?: { + [k: string]: boolean; + }; } // @public export interface IConfigCompiler { - overrideTsconfig?: {}; + overrideTsconfig?: { + [k: string]: unknown; + }; skipLibCheck?: boolean; tsconfigFilePath?: string; } @@ -226,37 +230,37 @@ export interface IConfigDtsRollup { // @public export interface IConfigFile { + $schema?: string; apiReport?: IConfigApiReport; bundledPackages?: string[]; compiler?: IConfigCompiler; docModel?: IConfigDocModel; - // @beta dtsRollup?: IConfigDtsRollup; - enumMemberOrder?: EnumMemberOrder; + enumMemberOrder?: "by-name" | "preserve"; extends?: string; mainEntryPointFilePath: string; messages?: IExtractorMessagesConfig; - newlineKind?: 'crlf' | 'lf' | 'os'; + newlineKind?: "crlf" | "lf" | "os"; projectFolder?: string; testMode?: boolean; - // @beta tsdocMetadata?: IConfigTsdocMetadata; } // @public export interface IConfigMessageReportingRule { addToApiReportFile?: boolean; - logLevel: ExtractorLogLevel; + logLevel: "error" | "warning" | "none"; } // @public export interface IConfigMessageReportingTable { - [messageId: string]: IConfigMessageReportingRule; + // (undocumented) + [k: string]: IConfigMessageReportingRule; } // @public export interface IConfigTsdocMetadata { - enabled: boolean; + enabled?: boolean; tsdocMetadataFilePath?: string; } @@ -308,6 +312,6 @@ export interface IExtractorMessagesConfig { } // @public -export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; +export type ReleaseTagForTrim = "@internal" | "@alpha" | "@beta" | "@public"; ``` From 85300f519dd4e5c9404e0560087b14e904e06dd0 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 20:07:50 -0800 Subject: [PATCH 31/40] Wrap the generated patternProperties comments in code quotes to fix TSDoc issues. --- .../use-json-schema-plugin_2026-02-22-04-05.json | 10 ++++++++++ .../src/JsonSchemaTypingsGenerator.ts | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 common/changes/@rushstack/heft-json-schema-typings-plugin/use-json-schema-plugin_2026-02-22-04-05.json diff --git a/common/changes/@rushstack/heft-json-schema-typings-plugin/use-json-schema-plugin_2026-02-22-04-05.json b/common/changes/@rushstack/heft-json-schema-typings-plugin/use-json-schema-plugin_2026-02-22-04-05.json new file mode 100644 index 00000000000..e25851c29ff --- /dev/null +++ b/common/changes/@rushstack/heft-json-schema-typings-plugin/use-json-schema-plugin_2026-02-22-04-05.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-json-schema-typings-plugin", + "comment": "Fix TSDoc parse warnings caused by `@` characters in generated type definitions. The `json-schema-to-typescript` library emits JSDoc comments containing raw JSON Schema pattern values (e.g. `\"^@[^\\s]*$\"`), which TSDoc interprets as tag indicators. These values are now wrapped in backtick code spans to prevent the warnings.", + "type": "minor" + } + ], + "packageName": "@rushstack/heft-json-schema-typings-plugin" +} \ No newline at end of file diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts index deb30f2742b..59f10ace9ac 100644 --- a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts @@ -60,6 +60,15 @@ export class JsonSchemaTypingsGenerator extends TypingsGenerator { format: formatWithPrettier }); + // The json-schema-to-typescript library generates JSDoc comments containing + // inline values that may include "@" characters, such as: + // via the `patternProperty` "^@[^\s]*$". + // TSDoc interprets "@" as a tag indicator, causing parse warnings. + // Wrap double-quoted values in backtick code spans to prevent this issue. + // Use " +" for the leading whitespace so this matches at any JSDoc indentation + // level (e.g. top-level " * ..." or nested " * ..."). + typings = typings.replace(/^( +\* .+`(?:patternProperty|definition)`) "([^"]+)"/gm, '$1 `"$2"`'); + // Check for an "x-tsdoc-release-tag" property in the schema (e.g. "@public" or "@beta"). // If present, inject the tag into JSDoc comments for all exported declarations. if (tsdocReleaseTag) { From 88bcfbb98a5badde74480e01bc5fc9534cbf7cd1 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 21:18:59 -0800 Subject: [PATCH 32/40] Update the checked-in tsdoc-metadata.json file --- build-tests/api-extractor-test-05/dist/tsdoc-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json index 35d93708271..610567002e0 100644 --- a/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json +++ b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json @@ -5,7 +5,7 @@ "toolPackages": [ { "packageName": "@microsoft/api-extractor", - "packageVersion": "7.57.0" + "packageVersion": "7.57.2" } ] } From 4a7bb3a1d69d3d6e2f77d2ad39ecd895c95552cb Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 21:19:51 -0800 Subject: [PATCH 33/40] Move .d.ts files from lib-commonjs to lib-dts in rush-lib and rush-sdk - Remove dTsFilesInputFolderName from DeepImportsPlugin config in rush-lib webpack - Update copyEmptyModules.js to only generate JS stubs without .d.ts copying - Refactor rush-sdk generate-stubs.ts to only create JS stubs - Add copy-files-plugin task to copy .d.ts files from rush-lib/lib-dts to rush-sdk/lib-dts - Declarations now live only in lib-dts, not duplicated in lib-commonjs --- .../rush-lib/scripts/copyEmptyModules.js | 20 +-- libraries/rush-lib/webpack.config.js | 3 +- libraries/rush-sdk/config/heft.json | 12 +- libraries/rush-sdk/src/generate-stubs.ts | 132 ++++++++---------- 4 files changed, 67 insertions(+), 100 deletions(-) diff --git a/libraries/rush-lib/scripts/copyEmptyModules.js b/libraries/rush-lib/scripts/copyEmptyModules.js index 061a03d699e..c3cc77f0337 100644 --- a/libraries/rush-lib/scripts/copyEmptyModules.js +++ b/libraries/rush-lib/scripts/copyEmptyModules.js @@ -3,7 +3,6 @@ const { FileSystem, Async, AsyncQueue } = require('@rushstack/node-core-library'); const JS_FILE_EXTENSION = '.js'; -const DTS_FILE_EXTENSION = '.d.ts'; module.exports = { runAsync: async ({ @@ -15,17 +14,16 @@ module.exports = { // We're using a Webpack plugin called `@rushstack/webpack-deep-imports-plugin` to // examine all of the modules that are imported by the entrypoints (index, and the start* scripts) // to `rush-lib` and generate stub JS files in the `lib` folder that reference the original modules - // in the webpack bundle. The plugin also copies the `.d.ts` files for those modules to the `lib` folder. + // in the webpack bundle. // // A limitation of this approach is that only modules that contain runtime code end up in the Webpack - // bundle, so only modules that contain runtime code get stubs and have their `.d.ts` files copied. This + // bundle, so only modules that contain runtime code get stubs. This // creates a problem when a `.d.ts` file references a module that doesn't have runtime code (i.e. - - // a `.d.ts` file that only contains types). + // a `.ts` file that only contains types). // // This script looks through the `lib-intermediate-esm` folder for `.js` files that were produced by the TypeScript // compiler from `.ts` files that contain no runtime code and generates stub `.js` files for them in the - // `lib` folder and copies the corresponding `.d.ts` files to the `lib`. This ensures that the `.d.ts` - // files that end up in the `lib` folder don't have any unresolved imports. This is tested by the + // `lib-commonjs` folder. This ensures that all modules have corresponding JS stubs. This is tested by the // `rush-lib-declaration-paths-test` project in the `build-tests` function stripCommentsFromJsFile(jsFileText) { @@ -44,7 +42,6 @@ module.exports = { } const jsInFolderPath = `${buildFolderPath}/lib-intermediate-esm`; - const dtsInFolderPath = `${buildFolderPath}/lib-dts`; const outCjsFolderPath = `${buildFolderPath}/lib-commonjs`; const emptyModuleBuffer = Buffer.from('module.exports = {};', 'utf8'); const folderPathQueue = new AsyncQueue([undefined]); @@ -70,15 +67,6 @@ module.exports = { await FileSystem.writeFileAsync(outJsPath, emptyModuleBuffer, { ensureFolderExists: true }); - - const relativeDtsPath = - relativeItemPath.slice(0, -JS_FILE_EXTENSION.length) + DTS_FILE_EXTENSION; - const inDtsPath = `${dtsInFolderPath}/${relativeDtsPath}`; - const outDtsPath = `${outCjsFolderPath}/${relativeDtsPath}`; - terminal.writeVerboseLine(`Copying ${inDtsPath} to ${outDtsPath}`); - // We know this is a file, don't need the redundant checks in FileSystem.copyFileAsync - const buffer = await FileSystem.readFileToBufferAsync(inDtsPath); - await FileSystem.writeFileAsync(outDtsPath, buffer, { ensureFolderExists: true }); } } } diff --git a/libraries/rush-lib/webpack.config.js b/libraries/rush-lib/webpack.config.js index 6952beba9dc..df64833e2b8 100644 --- a/libraries/rush-lib/webpack.config.js +++ b/libraries/rush-lib/webpack.config.js @@ -100,8 +100,7 @@ module.exports = () => { path: `${__dirname}/temp/build/webpack-dll/[name].json`, inFolderName: 'lib-intermediate-esm', outFolderName: 'lib-commonjs', - pathsToIgnore: ['utilities/prompts/SearchListPrompt.js'], - dTsFilesInputFolderName: 'lib-dts' + pathsToIgnore: ['utilities/prompts/SearchListPrompt.js'] }) ], { diff --git a/libraries/rush-sdk/config/heft.json b/libraries/rush-sdk/config/heft.json index 21b0acb80a3..3072d84888c 100644 --- a/libraries/rush-sdk/config/heft.json +++ b/libraries/rush-sdk/config/heft.json @@ -31,16 +31,18 @@ "sourcePath": "./node_modules/@microsoft/rush-lib/dist", "includeGlobs": ["rush-lib.d.ts"], "destinationFolders": ["dist"] + }, + { + "sourcePath": "./node_modules/@microsoft/rush-lib/lib-dts", + "destinationFolders": ["lib-dts"], + "fileExtensions": [".d.ts"], + "hardlink": true } ] } } }, - "typescript": { - "taskDependencies": ["copy-rush-lib-types"] - }, - "webpack": { "taskDependencies": ["typescript"], "taskPlugin": { @@ -49,7 +51,7 @@ }, "generate-stubs": { - "taskDependencies": ["typescript"], + "taskDependencies": ["typescript", "copy-rush-lib-types"], "taskPlugin": { "pluginPackage": "@rushstack/heft", "pluginName": "run-script-plugin", diff --git a/libraries/rush-sdk/src/generate-stubs.ts b/libraries/rush-sdk/src/generate-stubs.ts index d43b5502fec..8f110769f63 100644 --- a/libraries/rush-sdk/src/generate-stubs.ts +++ b/libraries/rush-sdk/src/generate-stubs.ts @@ -6,64 +6,52 @@ import * as path from 'node:path'; import type { IRunScriptOptions } from '@rushstack/heft'; import { Async, FileSystem, type FolderItem, Import, JsonFile, Path } from '@rushstack/node-core-library'; -interface IGenerateOptions { +interface IGenerateJsStubsOptions { parentSourcePath: string; - parentCjsTargetPath: string; - parentDtsTargetPath: string; + parentTargetPath: string; parentSrcImportPathWithSlash: string; libShimIndexPath: string; } -interface IFileTask { - type: 'dts' | 'js'; - sourcePath: string; +interface IJsStubTask { + jsSourcePath: string; targetPath: string; - srcImportPath?: string; - shimPathLiteral?: string; + srcImportPath: string; + shimPathLiteral: string; } -async function* collectFileTasksAsync(options: IGenerateOptions): AsyncGenerator { - const { - parentSourcePath, - parentCjsTargetPath, - parentDtsTargetPath, - parentSrcImportPathWithSlash, - libShimIndexPath - } = options; - const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(options.parentSourcePath); +/** + * Walks rush-lib/lib-commonjs to collect JS stub tasks. These stubs redirect + * require() calls through the rush-sdk shim so that the actual rush-lib module + * is loaded at runtime. + */ +async function* collectJsStubTasksAsync(options: IGenerateJsStubsOptions): AsyncGenerator { + const { parentSourcePath, parentTargetPath, parentSrcImportPathWithSlash, libShimIndexPath } = options; + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(parentSourcePath); for (const folderItem of folderItems) { const itemName: string = folderItem.name; const sourcePath: string = `${parentSourcePath}/${itemName}`; - const cjsTargetPath: string = `${parentCjsTargetPath}/${itemName}`; - const dtsTargetPath: string = `${parentDtsTargetPath}/${itemName}`; + const targetPath: string = `${parentTargetPath}/${itemName}`; if (folderItem.isDirectory()) { // Ensure destination folder exists - await FileSystem.ensureFolderAsync(cjsTargetPath); + await FileSystem.ensureFolderAsync(targetPath); // Recursively yield tasks from subdirectory - yield* collectFileTasksAsync({ + yield* collectJsStubTasksAsync({ parentSourcePath: sourcePath, - parentCjsTargetPath: cjsTargetPath, - parentDtsTargetPath: dtsTargetPath, + parentTargetPath: targetPath, parentSrcImportPathWithSlash: parentSrcImportPathWithSlash + itemName + '/', libShimIndexPath }); - } else if (folderItem.name.endsWith('.d.ts')) { - yield { - type: 'dts', - sourcePath, - targetPath: dtsTargetPath - }; } else if (folderItem.name.endsWith('.js')) { const srcImportPath: string = parentSrcImportPathWithSlash + path.parse(folderItem.name).name; - const shimPath: string = path.relative(parentCjsTargetPath, libShimIndexPath); + const shimPath: string = path.relative(parentTargetPath, libShimIndexPath); const shimPathLiteral: string = JSON.stringify(Path.convertToSlashes(shimPath)); yield { - type: 'js', - sourcePath, - targetPath: cjsTargetPath, + jsSourcePath: sourcePath, + targetPath, srcImportPath, shimPathLiteral }; @@ -71,43 +59,36 @@ async function* collectFileTasksAsync(options: IGenerateOptions): AsyncGenerator } } -async function processFileTaskAsync(task: IFileTask): Promise { - const { type, sourcePath, targetPath, srcImportPath, shimPathLiteral } = task; - if (type === 'dts') { - await FileSystem.copyFileAsync({ - sourcePath, - destinationPath: targetPath - }); - } else { - const srcImportPathLiteral: string = JSON.stringify(srcImportPath); - - let namedExportsAssignment: string = ''; - try { - // Read the sidecar .exports.json file generated by DeepImportsPlugin to get module exports - const exportsJsonPath: string = sourcePath.slice(0, -'.js'.length) + '.exports.json'; - const { moduleExports }: { moduleExports: string[] } = await JsonFile.loadAsync(exportsJsonPath); - if (moduleExports.length > 0) { - // Assign named exports after module.exports to ensure they're properly exposed for ESM imports - namedExportsAssignment = - '\n' + moduleExports.map((exportName) => `exports.${exportName} = _m.${exportName};`).join('\n'); - } - } catch (e) { - if (!FileSystem.isNotExistError(e)) { - throw e; - } +async function processJsStubTaskAsync(task: IJsStubTask): Promise { + const { jsSourcePath, targetPath, srcImportPath, shimPathLiteral } = task; + const srcImportPathLiteral: string = JSON.stringify(srcImportPath); + + let namedExportsAssignment: string = ''; + try { + // Read the sidecar .exports.json file generated by DeepImportsPlugin to get module exports + const exportsJsonPath: string = jsSourcePath.slice(0, -'.js'.length) + '.exports.json'; + const { moduleExports }: { moduleExports: string[] } = await JsonFile.loadAsync(exportsJsonPath); + if (moduleExports.length > 0) { + // Assign named exports after module.exports to ensure they're properly exposed for ESM imports + namedExportsAssignment = + '\n' + moduleExports.map((exportName) => `exports.${exportName} = _m.${exportName};`).join('\n'); + } + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; } - - await FileSystem.writeFileAsync( - targetPath, - // Example: - // ``` - // const _m = require("../../../lib-shim/index")._rushSdk_loadInternalModule("logic/policy/GitEmailPolicy"); - // module.exports = _m; - // exports.GitEmailPolicy = _m.GitEmailPolicy; - // ``` - `const _m = require(${shimPathLiteral})._rushSdk_loadInternalModule(${srcImportPathLiteral});\nmodule.exports = _m;${namedExportsAssignment}\n` - ); } + + await FileSystem.writeFileAsync( + targetPath, + // Example: + // ``` + // const _m = require("../../../lib-shim/index")._rushSdk_loadInternalModule("logic/policy/GitEmailPolicy"); + // module.exports = _m; + // exports.GitEmailPolicy = _m.GitEmailPolicy; + // ``` + `const _m = require(${shimPathLiteral})._rushSdk_loadInternalModule(${srcImportPathLiteral});\nmodule.exports = _m;${namedExportsAssignment}\n` + ); } // Entry point invoked by "runScript" action from config/heft.json @@ -126,23 +107,20 @@ export async function runAsync(options: IRunScriptOptions): Promise { }); const cjsStubsTargetPath: string = `${buildFolderPath}/lib-commonjs`; - const dtsStubsTargetPath: string = `${buildFolderPath}/lib-dts`; - terminal.writeLine( - `generate-stubs: Generating stub files under ${cjsStubsTargetPath} and ${dtsStubsTargetPath}` - ); + terminal.writeLine(`generate-stubs: Generating stub files under ${cjsStubsTargetPath}`); // Ensure the target folder exists await FileSystem.ensureFolderAsync(cjsStubsTargetPath); - // Collect and process file tasks in parallel with controlled concurrency - const tasks: AsyncGenerator = collectFileTasksAsync({ + // Generate JS stubs from rush-lib/lib-commonjs (these redirect require() through the shim) + // Note: .d.ts files are copied separately by the copy-rush-lib-types heft task from rush-lib/lib-dts + const jsTasks: AsyncGenerator = collectJsStubTasksAsync({ parentSourcePath: `${rushLibFolder}/lib-commonjs`, - parentCjsTargetPath: cjsStubsTargetPath, - parentDtsTargetPath: dtsStubsTargetPath, + parentTargetPath: cjsStubsTargetPath, parentSrcImportPathWithSlash: '', libShimIndexPath: `${buildFolderPath}/lib-shim/index.js` }); - await Async.forEachAsync(tasks, processFileTaskAsync, { concurrency: 50 }); + await Async.forEachAsync(jsTasks, processJsStubTaskAsync, { concurrency: 50 }); terminal.writeLine('generate-stubs: Completed successfully.'); } From afa1c55f4d41a964879ee8176916c7bac6a8ee64 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 21:25:07 -0800 Subject: [PATCH 34/40] Revert "Use the generated types in api-extractor." This reverts commit f8f628ae9c3034805f17e052ff287064ad2f2dfb. --- apps/api-extractor/src/api/ExtractorConfig.ts | 3 +- apps/api-extractor/src/api/IConfigFile.ts | 477 +++++++++++++++++- .../src/collector/MessageRouter.ts | 2 +- .../src/schemas/api-extractor.schema.json | 110 ++-- common/reviews/api/api-extractor.api.md | 26 +- 5 files changed, 498 insertions(+), 120 deletions(-) diff --git a/apps/api-extractor/src/api/ExtractorConfig.ts b/apps/api-extractor/src/api/ExtractorConfig.ts index 4f74843dc75..47f16e6c020 100644 --- a/apps/api-extractor/src/api/ExtractorConfig.ts +++ b/apps/api-extractor/src/api/ExtractorConfig.ts @@ -1208,8 +1208,7 @@ export class ExtractorConfig { break; } - const enumMemberOrder: EnumMemberOrder = - (configObject.enumMemberOrder as EnumMemberOrder) ?? EnumMemberOrder.ByName; + const enumMemberOrder: EnumMemberOrder = configObject.enumMemberOrder ?? EnumMemberOrder.ByName; extractorConfigParameters = { projectFolder: projectFolder, diff --git a/apps/api-extractor/src/api/IConfigFile.ts b/apps/api-extractor/src/api/IConfigFile.ts index 917928a1ac4..f05b943f796 100644 --- a/apps/api-extractor/src/api/IConfigFile.ts +++ b/apps/api-extractor/src/api/IConfigFile.ts @@ -1,19 +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 { - APIExtractorConfiguration as IConfigFile, - ApiReportVariant, - ConfigApiReport as IConfigApiReport, - ConfigCompiler as IConfigCompiler, - ConfigDocModel as IConfigDocModel, - ConfigDtsRollup as IConfigDtsRollup, - ConfigMessageReportingRule as IConfigMessageReportingRule, - ConfigTsdocMetadata as IConfigTsdocMetadata, - ExtractorMessageReportingTable as IConfigMessageReportingTable, - ExtractorMessagesConfig as IExtractorMessagesConfig, - ReleaseTagForTrim -} from '../schemas/api-extractor.schema.json.d.ts'; +import type { EnumMemberOrder } from '@microsoft/api-extractor-model'; + +import type { ExtractorLogLevel } from './ExtractorLogLevel'; /** * Determines how the TypeScript compiler engine will be invoked by API Extractor. @@ -23,14 +13,48 @@ import type { * * @public */ -export type { IConfigCompiler }; +export interface IConfigCompiler { + /** + * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. + * + * @remarks + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + * + * Note: This setting will be ignored if `overrideTsconfig` is used. + */ + tsconfigFilePath?: string; + + /** + * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. + * + * @remarks + * The value must conform to the TypeScript tsconfig schema: + * + * http://json.schemastore.org/tsconfig + * + * If omitted, then the tsconfig.json file will instead be read from the projectFolder. + */ + overrideTsconfig?: {}; + + /** + * This option causes the compiler to be invoked with the `--skipLibCheck` option. + * + * @remarks + * This option is not recommended and may cause API Extractor to produce incomplete or incorrect declarations, + * but it may be required when dependencies contain declarations that are incompatible with the TypeScript engine + * that API Extractor uses for its analysis. Where possible, the underlying issue should be fixed rather than + * relying on skipLibCheck. + */ + skipLibCheck?: boolean; +} /** * The allowed variations of API reports. * * @public */ -export type { ApiReportVariant }; +export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; /** * Configures how the API report files (*.api.md) will be generated. @@ -40,13 +64,124 @@ export type { ApiReportVariant }; * * @public */ -export type { IConfigApiReport }; +export interface IConfigApiReport { + /** + * Whether to generate an API report. + */ + enabled: boolean; + + /** + * The base filename for the API report files, to be combined with {@link IConfigApiReport.reportFolder} or + * {@link IConfigApiReport.reportTempFolder} to produce the full file path. + * + * @remarks + * The `reportFileName` should not include any path separators such as `\` or `/`. The `reportFileName` should + * not include a file extension, since API Extractor will automatically append an appropriate file extension such + * as `.api.md`. If the {@link IConfigApiReport.reportVariants} setting is used, then the file extension includes + * the variant name, for example `my-report.public.api.md` or `my-report.beta.api.md`. The `complete` variant always + * uses the simple extension `my-report.api.md`. + * + * Previous versions of API Extractor required `reportFileName` to include the `.api.md` extension explicitly; + * for backwards compatibility, that is still accepted but will be discarded before applying the above rules. + * + * @defaultValue `` + */ + reportFileName?: string; + + /** + * The set of report variants to generate. + * + * @remarks + * To support different approval requirements for different API levels, multiple "variants" of the API report can + * be generated. The `reportVariants` setting specifies a list of variants to be generated. If omitted, + * by default only the `complete` variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, + * and `@public` items. Other possible variants are `alpha` (`@alpha` + `@beta` + `@public`), + * `beta` (`@beta` + `@public`), and `public` (`@public only`). + * + * The resulting API report file names will be derived from the {@link IConfigApiReport.reportFileName}. + * + * @defaultValue `[ "complete" ]` + */ + reportVariants?: ApiReportVariant[]; + + /** + * Specifies the folder where the API report file is written. The file name portion is determined by + * the `reportFileName` setting. + * + * @remarks + * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, + * e.g. for an API review. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + reportFolder?: string; + + /** + * Specifies the folder where the temporary report file is written. The file name portion is determined by + * the `reportFileName` setting. + * + * @remarks + * After the temporary file is written to disk, it is compared with the file in the `reportFolder`. + * If they are different, a production build will fail. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + reportTempFolder?: string; + + /** + * Whether "forgotten exports" should be included in the API report file. + * + * @remarks + * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See + * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. + * + * @defaultValue `false` + */ + includeForgottenExports?: boolean; + + /** + * Specifies a list of {@link https://tsdoc.org/ | TSDoc} tags that should be reported in the API report file for + * items whose documentation contains them. + * + * @remarks + * Tag names must begin with `@`. + * + * This list may include standard TSDoc tags as well as custom ones. + * For more information on defining custom TSDoc tags, see + * {@link https://api-extractor.com/pages/configs/tsdoc_json/#defining-your-own-tsdoc-tags | here}. + * + * Note that an item's release tag will always reported; this behavior cannot be overridden. + * + * @defaultValue `@sealed`, `@virtual`, `@override`, `@eventProperty`, and `@deprecated` + * + * @example Omitting default tags + * To omit the `@sealed` and `@virtual` tags from API reports, you would specify `tagsToReport` as follows: + * ```json + * "tagsToReport": { + * "@sealed": false, + * "@virtual": false + * } + * ``` + * + * @example Including additional tags + * To include additional tags to the set included in API reports, you could specify `tagsToReport` like this: + * ```json + * "tagsToReport": { + * "@customTag": true + * } + * ``` + * This will result in `@customTag` being included in addition to the default tags. + */ + tagsToReport?: Readonly>; +} /** * The allowed release tags that can be used to mark API items. * @public */ -export type { ReleaseTagForTrim }; +export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; /** * Configures how the doc model file (*.api.json) will be generated. @@ -56,7 +191,53 @@ export type { ReleaseTagForTrim }; * * @public */ -export type { IConfigDocModel }; +export interface IConfigDocModel { + /** + * Whether to generate a doc model file. + */ + enabled: boolean; + + /** + * The output path for the doc model file. The file extension should be ".api.json". + * + * @remarks + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + apiJsonFilePath?: string; + + /** + * Whether "forgotten exports" should be included in the doc model file. + * + * @remarks + * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See + * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. + * + * @defaultValue `false` + */ + includeForgottenExports?: boolean; + + /** + * The base URL where the project's source code can be viewed on a website such as GitHub or + * Azure DevOps. This URL path corresponds to the `` path on disk. + * + * @remarks + * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. + * For example, if the `projectFolderUrl` is "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor" and an API + * item's file path is "api/ExtractorConfig.ts", the full URL file path would be + * "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js". + * + * Can be omitted if you don't need source code links in your API documentation reference. + */ + projectFolderUrl?: string; + + /** + * Specifies a list of release tags that will be trimmed from the doc model. + * + * @defaultValue `["@internal"]` + */ + releaseTagsToTrim?: ReleaseTagForTrim[]; +} /** * Configures how the .d.ts rollup file will be generated. @@ -66,7 +247,67 @@ export type { IConfigDocModel }; * * @public */ -export type { IConfigDtsRollup }; +export interface IConfigDtsRollup { + /** + * Whether to generate the .d.ts rollup file. + */ + enabled: boolean; + + /** + * Specifies the output path for a .d.ts rollup file to be generated without any trimming. + * + * @remarks + * This file will include all declarations that are exported by the main entry point. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + untrimmedFilePath?: string; + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. + * + * @remarks + * This file will include only declarations that are marked as `@public`, `@beta`, or `@alpha`. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + alphaTrimmedFilePath?: string; + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. + * + * @remarks + * This file will include only declarations that are marked as `@public` or `@beta`. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + betaTrimmedFilePath?: string; + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. + * + * @remarks + * This file will include only declarations that are marked as `@public`. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + */ + publicTrimmedFilePath?: string; + + /** + * When a declaration is trimmed, by default it will be replaced by a code comment such as + * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the + * declaration completely. + */ + omitTrimmingComments?: boolean; +} /** * Configures how the tsdoc-metadata.json file will be generated. @@ -76,7 +317,25 @@ export type { IConfigDtsRollup }; * * @public */ -export type { IConfigTsdocMetadata }; +export interface IConfigTsdocMetadata { + /** + * Whether to generate the tsdoc-metadata.json file. + */ + enabled: boolean; + + /** + * Specifies where the TSDoc metadata file should be written. + * + * @remarks + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as ``. + * + * The default value is ``, which causes the path to be automatically inferred from the `tsdocMetadata`, + * `typings` or `main` fields of the project's package.json. If none of these fields are set, the lookup + * falls back to `tsdoc-metadata.json` in the package folder. + */ + tsdocMetadataFilePath?: string; +} /** * Configures reporting for a given message identifier. @@ -86,7 +345,22 @@ export type { IConfigTsdocMetadata }; * * @public */ -export type { IConfigMessageReportingRule }; +export interface IConfigMessageReportingRule { + /** + * Specifies whether the message should be written to the the tool's output log. + * + * @remarks + * Note that the `addToApiReportFile` property may supersede this option. + */ + logLevel: ExtractorLogLevel; + + /** + * When `addToApiReportFile` is true: If API Extractor is configured to write an API report file (.api.md), + * then the message will be written inside that file; otherwise, the message is instead logged according to + * the `logLevel` option. + */ + addToApiReportFile?: boolean; +} /** * Specifies a table of reporting rules for different message identifiers, and also the default rule used for @@ -97,7 +371,14 @@ export type { IConfigMessageReportingRule }; * * @public */ -export type { IConfigMessageReportingTable }; +export interface IConfigMessageReportingTable { + /** + * The key is a message identifier for the associated type of message, or "default" to specify the default policy. + * For example, the key might be `TS2551` (a compiler message), `tsdoc-link-tag-unescaped-text` (a TSDOc message), + * or `ae-extra-release-tag` (a message related to the API Extractor analysis). + */ + [messageId: string]: IConfigMessageReportingRule; +} /** * Configures how API Extractor reports error and warning messages produced during analysis. @@ -107,11 +388,159 @@ export type { IConfigMessageReportingTable }; * * @public */ -export type { IExtractorMessagesConfig }; +export interface IExtractorMessagesConfig { + /** + * Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the + * input .d.ts files. + */ + compilerMessageReporting?: IConfigMessageReportingTable; + + /** + * Configures handling of messages reported by API Extractor during its analysis. + */ + extractorMessageReporting?: IConfigMessageReportingTable; + + /** + * Configures handling of messages reported by the TSDoc parser when analyzing code comments. + */ + tsdocMessageReporting?: IConfigMessageReportingTable; +} + /** * Configuration options for the API Extractor tool. These options can be constructed programmatically * or loaded from the api-extractor.json config file using the {@link ExtractorConfig} class. * * @public */ -export type { IConfigFile }; +export interface IConfigFile { + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for + * standard settings to be shared across multiple projects. + * + * @remarks + * If the path starts with `./` or `../`, the path is resolved relative to the folder of the file that contains + * the `extends` field. Otherwise, the first path segment is interpreted as an NPM package name, and will be + * resolved using NodeJS `require()`. + */ + extends?: string; + + /** + * Determines the `` token that can be used with other config file settings. The project folder + * typically contains the tsconfig.json and package.json config files, but the path is user-defined. + * + * @remarks + * + * The path is resolved relative to the folder of the config file that contains the setting. + * + * The default value for `projectFolder` is the token ``, which means the folder is determined using + * the following heuristics: + * + * If the config/rig.json system is used (as defined by {@link https://www.npmjs.com/package/@rushstack/rig-package + * | @rushstack/rig-package}), then the `` value will be the package folder that referenced the rig. + * + * Otherwise, the `` value is determined by traversing parent folders, starting from the folder containing + * api-extractor.json, and stopping at the first folder that contains a tsconfig.json file. If a tsconfig.json file + * cannot be found in this way, then an error will be reported. + */ + projectFolder?: string; + + /** + * Specifies the .d.ts file to be used as the starting point for analysis. API Extractor + * analyzes the symbols exported by this module. + * + * @remarks + * + * The file extension must be ".d.ts" and not ".ts". + * The path is resolved relative to the "projectFolder" location. + */ + mainEntryPointFilePath: string; + + /** + * A list of NPM package names whose exports should be treated as part of this package. + * + * @remarks + * Also supports glob patterns. + * Note: glob patterns will **only** be resolved against dependencies listed in the project's package.json file. + * + * * This is both a safety and a performance precaution. + * + * Exact package names will be applied against any dependency encountered while walking the type graph, regardless of + * dependencies listed in the package.json. + * + * @example + * + * Suppose that Webpack is used to generate a distributed bundle for the project `library1`, + * and another NPM package `library2` is embedded in this bundle. Some types from `library2` may become part + * of the exported API for `library1`, but by default API Extractor would generate a .d.ts rollup that explicitly + * imports `library2`. To avoid this, we can specify: + * + * ```js + * "bundledPackages": [ "library2" ], + * ``` + * + * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been + * local files for `library1`. + */ + bundledPackages?: string[]; + + /** + * Specifies what type of newlines API Extractor should use when writing output files. + * + * @remarks + * By default, the output files will be written with Windows-style newlines. + * To use POSIX-style newlines, specify "lf" instead. + * To use the OS's default newline kind, specify "os". + */ + newlineKind?: 'crlf' | 'lf' | 'os'; + + /** + * Set to true when invoking API Extractor's test harness. + * @remarks + * When `testMode` is true, the `toolVersion` field in the .api.json file is assigned an empty string + * to prevent spurious diffs in output files tracked for tests. + */ + testMode?: boolean; + + /** + * Specifies how API Extractor sorts members of an enum when generating the .api.json file. + * + * @remarks + * By default, the output files will be sorted alphabetically, which is "by-name". + * To keep the ordering in the source code, specify "preserve". + * + * @defaultValue `by-name` + */ + enumMemberOrder?: EnumMemberOrder; + + /** + * {@inheritDoc IConfigCompiler} + */ + compiler?: IConfigCompiler; + + /** + * {@inheritDoc IConfigApiReport} + */ + apiReport?: IConfigApiReport; + + /** + * {@inheritDoc IConfigDocModel} + */ + docModel?: IConfigDocModel; + + /** + * {@inheritDoc IConfigDtsRollup} + * @beta + */ + dtsRollup?: IConfigDtsRollup; + + /** + * {@inheritDoc IConfigTsdocMetadata} + * @beta + */ + tsdocMetadata?: IConfigTsdocMetadata; + + /** + * {@inheritDoc IExtractorMessagesConfig} + */ + messages?: IExtractorMessagesConfig; +} diff --git a/apps/api-extractor/src/collector/MessageRouter.ts b/apps/api-extractor/src/collector/MessageRouter.ts index 984ca710931..bc09397c084 100644 --- a/apps/api-extractor/src/collector/MessageRouter.ts +++ b/apps/api-extractor/src/collector/MessageRouter.ts @@ -175,7 +175,7 @@ export class MessageRouter { private static _getNormalizedRule(rule: IConfigMessageReportingRule): IReportingRule { return { - logLevel: (rule.logLevel || 'none') as ExtractorLogLevel, + logLevel: rule.logLevel || 'none', addToApiReportFile: rule.addToApiReportFile || false }; } diff --git a/apps/api-extractor/src/schemas/api-extractor.schema.json b/apps/api-extractor/src/schemas/api-extractor.schema.json index 0b40686313d..8bd8fdaef13 100644 --- a/apps/api-extractor/src/schemas/api-extractor.schema.json +++ b/apps/api-extractor/src/schemas/api-extractor.schema.json @@ -1,7 +1,6 @@ { "title": "API Extractor Configuration", "description": "Describes how the API Extractor tool will process a project.", - "x-tsdoc-release-tag": "@public", "type": "object", "properties": { "$schema": { @@ -52,40 +51,6 @@ }, "compiler": { - "description": "Determines how the TypeScript compiler engine will be invoked by API Extractor.", - "allOf": [{ "$ref": "#/definitions/configCompiler" }] - }, - - "apiReport": { - "description": "Configures how the API report file (*.api.md) will be generated.", - "allOf": [{ "$ref": "#/definitions/configApiReport" }] - }, - - "docModel": { - "description": "Configures how the doc model file (*.api.json) will be generated.", - "allOf": [{ "$ref": "#/definitions/configDocModel" }] - }, - - "dtsRollup": { - "description": "Configures how the .d.ts rollup file will be generated.", - "allOf": [{ "$ref": "#/definitions/configDtsRollup" }] - }, - - "tsdocMetadata": { - "description": "Configures how the tsdoc-metadata.json file will be generated.", - "allOf": [{ "$ref": "#/definitions/configTsdocMetadata" }] - }, - - "messages": { - "description": "Configures how API Extractor reports error and warning messages produced during analysis.", - "allOf": [{ "$ref": "#/definitions/extractorMessagesConfig" }] - } - }, - "required": ["mainEntryPointFilePath"], - "additionalProperties": false, - - "definitions": { - "configCompiler": { "description": "Determines how the TypeScript compiler engine will be invoked by API Extractor.", "type": "object", "properties": { @@ -105,14 +70,8 @@ "additionalProperties": false }, - "apiReportVariant": { - "description": "The allowed variations of API reports.", - "type": "string", - "enum": ["public", "beta", "alpha", "complete"] - }, - - "configApiReport": { - "description": "Configures how the API report files (*.api.md) will be generated.", + "apiReport": { + "description": "Configures how the API report file (*.api.md) will be generated.", "type": "object", "properties": { "enabled": { @@ -129,7 +88,8 @@ "description": "To support different approval requirements for different API levels, multiple \"variants\" of the API report can be generated. The \"reportVariants\" setting specifies a list of variants to be generated. If omitted, by default only the \"complete\" variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, and `@public` items. Other possible variants are \"alpha\" (`@alpha` + `@beta` + `@public`), \"beta\" (`@beta` + `@public`), and \"public\" (`@public` only).", "type": "array", "items": { - "$ref": "#/definitions/apiReportVariant" + "type": "string", + "enum": ["public", "beta", "alpha", "complete"] } }, @@ -163,13 +123,7 @@ "additionalProperties": false }, - "releaseTagForTrim": { - "description": "The allowed release tags that can be used to trim API items.", - "type": "string", - "enum": ["@internal", "@alpha", "@beta", "@public"] - }, - - "configDocModel": { + "docModel": { "description": "Configures how the doc model file (*.api.json) will be generated.", "type": "object", "properties": { @@ -193,7 +147,7 @@ "description": "Specifies a list of release tags that will be trimmed from the doc model. The default value is `[\"@internal\"]`.", "type": "array", "items": { - "$ref": "#/definitions/releaseTagForTrim" + "enum": ["@internal", "@alpha", "@beta", "@public"] }, "uniqueItems": true } @@ -202,7 +156,7 @@ "additionalProperties": false }, - "configDtsRollup": { + "dtsRollup": { "description": "Configures how the .d.ts rollup file will be generated.", "type": "object", "properties": { @@ -235,7 +189,7 @@ "additionalProperties": false }, - "configTsdocMetadata": { + "tsdocMetadata": { "description": "Configures how the tsdoc-metadata.json file will be generated.", "type": "object", "properties": { @@ -251,53 +205,53 @@ "additionalProperties": false }, - "extractorMessagesConfig": { + "messages": { "description": "Configures how API Extractor reports error and warning messages produced during analysis.", "type": "object", "properties": { "compilerMessageReporting": { "description": "Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the input .d.ts files.", - "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] + "$ref": "#/definitions/extractorMessageReportingTable" }, "extractorMessageReporting": { "description": "Configures handling of messages reported by API Extractor during its analysis.", - "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] + "$ref": "#/definitions/extractorMessageReportingTable" }, "tsdocMessageReporting": { "description": "Configures handling of messages reported by the TSDoc parser when analyzing code comments.", - "allOf": [{ "$ref": "#/definitions/extractorMessageReportingTable" }] + "$ref": "#/definitions/extractorMessageReportingTable" } }, "additionalProperties": false - }, + } + }, + "required": ["mainEntryPointFilePath"], + "additionalProperties": false, + "definitions": { "extractorMessageReportingTable": { "type": "object", "description": "Specifies a table of reporting rules for different message identifiers, and also the default rule used for identifiers that do not appear in the table. The key is a message identifier for the associated type of message, or \"default\" to specify the default policy. For example, the key might be \"TS2551\" (a compiler message), \"tsdoc-link-tag-unescaped-text\" (a TSDOc message), or \"ae-extra-release-tag\" (a message related to the API Extractor analysis).", "patternProperties": { ".+": { - "$ref": "#/definitions/configMessageReportingRule" + "type": "object", + "description": "Configures reporting for a given message identifier.", + "properties": { + "logLevel": { + "type": "string", + "description": "Specifies whether the message should be written to the the tool's output log. Note that the \"addToApiReportFile\" property may supersede this option.", + "enum": ["error", "warning", "none"] + }, + "addToApiReportFile": { + "type": "boolean", + "description": "If API Extractor is configured to write an API review file (.api.md), then the message will be written inside that file. If the API review file is NOT being written, then the message is instead logged according to the \"logLevel\" option." + } + }, + "additionalProperties": false, + "required": ["logLevel"] } }, "additionalProperties": false - }, - - "configMessageReportingRule": { - "type": "object", - "description": "Configures reporting for a given message identifier.", - "properties": { - "logLevel": { - "type": "string", - "description": "Specifies whether the message should be written to the the tool's output log. Note that the \"addToApiReportFile\" property may supersede this option.", - "enum": ["error", "warning", "none"] - }, - "addToApiReportFile": { - "type": "boolean", - "description": "If API Extractor is configured to write an API review file (.api.md), then the message will be written inside that file. If the API review file is NOT being written, then the message is instead logged according to the \"logLevel\" option." - } - }, - "additionalProperties": false, - "required": ["logLevel"] } } } diff --git a/common/reviews/api/api-extractor.api.md b/common/reviews/api/api-extractor.api.md index 83f2baa8e49..f44ecd8e92b 100644 --- a/common/reviews/api/api-extractor.api.md +++ b/common/reviews/api/api-extractor.api.md @@ -16,7 +16,7 @@ import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { TSDocConfiguration } from '@microsoft/tsdoc'; // @public -export type ApiReportVariant = "public" | "beta" | "alpha" | "complete"; +export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; // @public export class CompilerState { @@ -195,16 +195,12 @@ export interface IConfigApiReport { reportFolder?: string; reportTempFolder?: string; reportVariants?: ApiReportVariant[]; - tagsToReport?: { - [k: string]: boolean; - }; + tagsToReport?: Readonly>; } // @public export interface IConfigCompiler { - overrideTsconfig?: { - [k: string]: unknown; - }; + overrideTsconfig?: {}; skipLibCheck?: boolean; tsconfigFilePath?: string; } @@ -230,37 +226,37 @@ export interface IConfigDtsRollup { // @public export interface IConfigFile { - $schema?: string; apiReport?: IConfigApiReport; bundledPackages?: string[]; compiler?: IConfigCompiler; docModel?: IConfigDocModel; + // @beta dtsRollup?: IConfigDtsRollup; - enumMemberOrder?: "by-name" | "preserve"; + enumMemberOrder?: EnumMemberOrder; extends?: string; mainEntryPointFilePath: string; messages?: IExtractorMessagesConfig; - newlineKind?: "crlf" | "lf" | "os"; + newlineKind?: 'crlf' | 'lf' | 'os'; projectFolder?: string; testMode?: boolean; + // @beta tsdocMetadata?: IConfigTsdocMetadata; } // @public export interface IConfigMessageReportingRule { addToApiReportFile?: boolean; - logLevel: "error" | "warning" | "none"; + logLevel: ExtractorLogLevel; } // @public export interface IConfigMessageReportingTable { - // (undocumented) - [k: string]: IConfigMessageReportingRule; + [messageId: string]: IConfigMessageReportingRule; } // @public export interface IConfigTsdocMetadata { - enabled?: boolean; + enabled: boolean; tsdocMetadataFilePath?: string; } @@ -312,6 +308,6 @@ export interface IExtractorMessagesConfig { } // @public -export type ReleaseTagForTrim = "@internal" | "@alpha" | "@beta" | "@public"; +export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; ``` From aa46a62f3b3d8cb5a5c948ad96ee100e49b0b8de Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 21:48:58 -0800 Subject: [PATCH 35/40] Fix some issues with heft-json-schema-typings-plugin-test. --- .../heft-json-schema-typings-plugin-test/config/heft.json | 2 +- .../src/test/JsonSchemaTypingsGenerator.test.ts | 6 +++--- .../__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json index e542c488937..c44c50824a1 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json +++ b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json @@ -8,7 +8,7 @@ "cleanFiles": [{ "includeGlobs": ["temp/schema-dts", "temp/schema-dts-formatted"] }], "tasksByName": { - "json-schema-typings": { + "json-schema-typings-unformatted": { "taskPlugin": { "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", "pluginName": "json-schema-typings-plugin", diff --git a/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts b/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts index 20a46ffc077..e56c8119d73 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts @@ -40,15 +40,15 @@ describe('json-schema-typings-plugin', () => { rootFolder = foundRootFolder; }); - it('should generate typings for JSON Schemas', async () => { + it('should generate typings for JSON Schemas (unformatted)', async () => { const folderItems: Record = await getFolderItemsAsync( - `${rootFolder}/temp/schema-dts`, + `${rootFolder}/temp/schema-dts-unformatted`, '.' ); expect(folderItems).toMatchSnapshot(); }); - it('should generate formatted typings for JSON Schemas', async () => { + it('should generate typings for JSON Schemas (formatted)', async () => { const folderItems: Record = await getFolderItemsAsync( `${rootFolder}/temp/schema-dts-formatted`, '.' diff --git a/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap index 7b73aa261af..50ea7bb1cae 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`json-schema-typings-plugin should generate formatted typings for JSON Schemas 1`] = ` +exports[`json-schema-typings-plugin should generate typings for JSON Schemas (formatted) 1`] = ` Object { "./test-invalid-additional.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior @@ -222,7 +222,7 @@ export interface TestValid { } `; -exports[`json-schema-typings-plugin should generate typings for JSON Schemas 1`] = ` +exports[`json-schema-typings-plugin should generate typings for JSON Schemas (unformatted) 1`] = ` Object { "./test-invalid-additional.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior From b4bbace4c56c13a0d8c867872d585599b5548fe9 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 22:11:48 -0800 Subject: [PATCH 36/40] Include empty changelogs. --- .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../rush/use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../heft/use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ .../use-json-schema-plugin_2026-02-22-06-11.json | 10 ++++++++++ 17 files changed, 170 insertions(+) create mode 100644 common/changes/@microsoft/api-extractor/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@microsoft/rush/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/credential-cache/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-api-extractor-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-isolated-typescript-transpile-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-jest-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-lint-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-localization-typings-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-rspack-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-sass-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-storybook-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-typescript-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-webpack4-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft-webpack5-plugin/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/heft/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/rig-package/use-json-schema-plugin_2026-02-22-06-11.json create mode 100644 common/changes/@rushstack/typings-generator/use-json-schema-plugin_2026-02-22-06-11.json diff --git a/common/changes/@microsoft/api-extractor/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@microsoft/api-extractor/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..752ad7dd46f --- /dev/null +++ b/common/changes/@microsoft/api-extractor/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/api-extractor" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@microsoft/rush/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..bd7ff97cb34 --- /dev/null +++ b/common/changes/@microsoft/rush/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@rushstack/credential-cache/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/credential-cache/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..bce1619cc7e --- /dev/null +++ b/common/changes/@rushstack/credential-cache/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/credential-cache", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/credential-cache" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-api-extractor-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-api-extractor-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..95128aed453 --- /dev/null +++ b/common/changes/@rushstack/heft-api-extractor-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-api-extractor-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-api-extractor-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-isolated-typescript-transpile-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-isolated-typescript-transpile-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..fbd4c12b6b9 --- /dev/null +++ b/common/changes/@rushstack/heft-isolated-typescript-transpile-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-isolated-typescript-transpile-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-isolated-typescript-transpile-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-jest-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-jest-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..8453696f39b --- /dev/null +++ b/common/changes/@rushstack/heft-jest-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-jest-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-jest-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-lint-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-lint-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..a259901b76f --- /dev/null +++ b/common/changes/@rushstack/heft-lint-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-lint-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-lint-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-localization-typings-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-localization-typings-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..e3dd3971b44 --- /dev/null +++ b/common/changes/@rushstack/heft-localization-typings-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-localization-typings-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-localization-typings-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-rspack-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-rspack-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..c002a6dc429 --- /dev/null +++ b/common/changes/@rushstack/heft-rspack-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-rspack-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-rspack-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-sass-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-sass-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..501a07dfec7 --- /dev/null +++ b/common/changes/@rushstack/heft-sass-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-sass-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-sass-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-storybook-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-storybook-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..a46619d0a73 --- /dev/null +++ b/common/changes/@rushstack/heft-storybook-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-storybook-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-storybook-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-typescript-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-typescript-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..cb6f98ca14f --- /dev/null +++ b/common/changes/@rushstack/heft-typescript-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-typescript-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-typescript-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-webpack4-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-webpack4-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..e6a91323381 --- /dev/null +++ b/common/changes/@rushstack/heft-webpack4-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-webpack4-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-webpack4-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-webpack5-plugin/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft-webpack5-plugin/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..e62ded6bf1b --- /dev/null +++ b/common/changes/@rushstack/heft-webpack5-plugin/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-webpack5-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft-webpack5-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/heft/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..4da3f257a2d --- /dev/null +++ b/common/changes/@rushstack/heft/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/heft" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/rig-package/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..1c1df562afb --- /dev/null +++ b/common/changes/@rushstack/rig-package/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/rig-package", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/rig-package" +} \ No newline at end of file diff --git a/common/changes/@rushstack/typings-generator/use-json-schema-plugin_2026-02-22-06-11.json b/common/changes/@rushstack/typings-generator/use-json-schema-plugin_2026-02-22-06-11.json new file mode 100644 index 00000000000..8f04a7afc26 --- /dev/null +++ b/common/changes/@rushstack/typings-generator/use-json-schema-plugin_2026-02-22-06-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/typings-generator", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/typings-generator" +} \ No newline at end of file From 710d6950355a9435748b7a7ee0f53febd665bc28 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 22:26:10 -0800 Subject: [PATCH 37/40] Fix rig-package test failure caused by x-tsdoc-release-tag custom keyword in strict mode AJV. --- libraries/rig-package/src/test/RigConfig.test.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/rig-package/src/test/RigConfig.test.ts b/libraries/rig-package/src/test/RigConfig.test.ts index 743c5ddd05a..778cb2096ae 100644 --- a/libraries/rig-package/src/test/RigConfig.test.ts +++ b/libraries/rig-package/src/test/RigConfig.test.ts @@ -187,19 +187,23 @@ describe(RigConfig.name, () => { ); }); }); + it('validates a rig.json file using the schema', () => { const rigConfigFilePath: string = path.join(testProjectFolder, 'config', 'rig.json'); + // Remove fields that AJV strict mode doesn't recognize + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { 'x-tsdoc-release-tag': _releaseTag, ...schemaObject } = RigConfig.jsonSchemaObject as Record< + string, + unknown + >; + const ajv = new Ajv({ verbose: true }); - // Delete our older "draft-04/schema" and use AJV's built-in schema - // eslint-disable-next-line - delete (RigConfig.jsonSchemaObject as any)['$schema']; - // Compile our schema - const validateRigFile: ValidateFunction = ajv.compile(RigConfig.jsonSchemaObject); + const validateRigFile: ValidateFunction = ajv.compile(schemaObject); // Load the rig.json file const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); From 9d92020f031dc9325d933837d1284f2e2275b3b4 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 22:34:47 -0800 Subject: [PATCH 38/40] fixup! Fix rig-package test failure caused by x-tsdoc-release-tag custom keyword in strict mode AJV. --- libraries/rig-package/src/RigConfig.ts | 7 ++++++- libraries/rig-package/src/test/RigConfig.test.ts | 9 +-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/rig-package/src/RigConfig.ts b/libraries/rig-package/src/RigConfig.ts index fab7a44864e..51db167974a 100644 --- a/libraries/rig-package/src/RigConfig.ts +++ b/libraries/rig-package/src/RigConfig.ts @@ -258,8 +258,12 @@ export class RigConfig implements IRigConfig { public static get jsonSchemaObject(): object { if (RigConfig._jsonSchemaObject === undefined) { const jsonSchemaContent: string = fs.readFileSync(RigConfig.jsonSchemaPath).toString(); - RigConfig._jsonSchemaObject = JSON.parse(jsonSchemaContent); + // Remove nonstandard fields that are not part of the JSON Schema specification + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { 'x-tsdoc-release-tag': _, ...schemaObject } = JSON.parse(jsonSchemaContent); + RigConfig._jsonSchemaObject = schemaObject; } + return RigConfig._jsonSchemaObject!; } @@ -500,6 +504,7 @@ export class RigConfig implements IRigConfig { throw new Error(`Unsupported field ${JSON.stringify(key)}`); } } + if (!json.rigPackageName) { throw new Error('Missing required field "rigPackageName"'); } diff --git a/libraries/rig-package/src/test/RigConfig.test.ts b/libraries/rig-package/src/test/RigConfig.test.ts index 778cb2096ae..b81d360ca26 100644 --- a/libraries/rig-package/src/test/RigConfig.test.ts +++ b/libraries/rig-package/src/test/RigConfig.test.ts @@ -191,19 +191,12 @@ describe(RigConfig.name, () => { it('validates a rig.json file using the schema', () => { const rigConfigFilePath: string = path.join(testProjectFolder, 'config', 'rig.json'); - // Remove fields that AJV strict mode doesn't recognize - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { 'x-tsdoc-release-tag': _releaseTag, ...schemaObject } = RigConfig.jsonSchemaObject as Record< - string, - unknown - >; - const ajv = new Ajv({ verbose: true }); // Compile our schema - const validateRigFile: ValidateFunction = ajv.compile(schemaObject); + const validateRigFile: ValidateFunction = ajv.compile(RigConfig.jsonSchemaObject); // Load the rig.json file const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); From b4ceb04c4b3135f0e15f67a2d2d38afa57a3b2a5 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 22:37:07 -0800 Subject: [PATCH 39/40] fixup! Fix rig-package test failure caused by x-tsdoc-release-tag custom keyword in strict mode AJV. --- libraries/rig-package/src/test/RigConfig.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/rig-package/src/test/RigConfig.test.ts b/libraries/rig-package/src/test/RigConfig.test.ts index b81d360ca26..743c5ddd05a 100644 --- a/libraries/rig-package/src/test/RigConfig.test.ts +++ b/libraries/rig-package/src/test/RigConfig.test.ts @@ -187,7 +187,6 @@ describe(RigConfig.name, () => { ); }); }); - it('validates a rig.json file using the schema', () => { const rigConfigFilePath: string = path.join(testProjectFolder, 'config', 'rig.json'); @@ -195,6 +194,10 @@ describe(RigConfig.name, () => { verbose: true }); + // Delete our older "draft-04/schema" and use AJV's built-in schema + // eslint-disable-next-line + delete (RigConfig.jsonSchemaObject as any)['$schema']; + // Compile our schema const validateRigFile: ValidateFunction = ajv.compile(RigConfig.jsonSchemaObject); From 1506ce0d91c12d9f8c3dd539b7f75277f9b7dbc0 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 23:00:03 -0800 Subject: [PATCH 40/40] fixup! Fix some issues with heft-json-schema-typings-plugin-test. --- .../heft-json-schema-typings-plugin-test/config/heft.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json index c44c50824a1..67eab084ea8 100644 --- a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json +++ b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json @@ -5,7 +5,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["temp/schema-dts", "temp/schema-dts-formatted"] }], + "cleanFiles": [{ "includeGlobs": ["temp/schema-dts-unformatted", "temp/schema-dts-formatted"] }], "tasksByName": { "json-schema-typings-unformatted": { @@ -14,7 +14,7 @@ "pluginName": "json-schema-typings-plugin", "options": { "srcFolder": "node_modules/@rushstack/node-core-library/src/test/test-data/test-schemas", - "generatedTsFolders": ["temp/schema-dts"] + "generatedTsFolders": ["temp/schema-dts-unformatted"] } } },