diff --git a/common/autoinstallers/command-plugins/package.json b/common/autoinstallers/command-plugins/package.json index 43f204ca..d65d85da 100644 --- a/common/autoinstallers/command-plugins/package.json +++ b/common/autoinstallers/command-plugins/package.json @@ -9,6 +9,7 @@ "rush-lint-staged-plugin": "0.1.6", "rush-sort-package-json": "0.0.3", "rush-upgrade-self-plugin": "1.0.6", + "rush-metadata-plugin": "link:../../../rush-plugins/rush-metadata-plugin", "typescript": "4.4.2" } } diff --git a/common/autoinstallers/command-plugins/pnpm-lock.yaml b/common/autoinstallers/command-plugins/pnpm-lock.yaml index 2ff6a010..8499c710 100644 --- a/common/autoinstallers/command-plugins/pnpm-lock.yaml +++ b/common/autoinstallers/command-plugins/pnpm-lock.yaml @@ -5,6 +5,7 @@ specifiers: rush-audit-cache-plugin: 0.0.2 rush-init-project-plugin: 0.6.0 rush-lint-staged-plugin: 0.1.6 + rush-metadata-plugin: link:../../../rush-plugins/rush-metadata-plugin rush-sort-package-json: 0.0.3 rush-upgrade-self-plugin: 1.0.6 typescript: 4.4.2 @@ -14,6 +15,7 @@ dependencies: rush-audit-cache-plugin: 0.0.2 rush-init-project-plugin: 0.6.0_typescript@4.4.2 rush-lint-staged-plugin: 0.1.6 + rush-metadata-plugin: link:../../../rush-plugins/rush-metadata-plugin rush-sort-package-json: 0.0.3 rush-upgrade-self-plugin: 1.0.6 typescript: 4.4.2 @@ -719,7 +721,7 @@ packages: '@npmcli/move-file': 2.0.1 chownr: 2.0.0 fs-minipass: 2.1.0 - glob: 8.1.0 + glob: 8.0.3 infer-owner: 1.0.4 lru-cache: 7.14.1 minipass: 3.3.6 @@ -907,6 +909,13 @@ packages: engines: {node: ^12.20.0 || >=14} dev: false + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + requiresBuild: true + dev: false + optional: true + /component-emitter/1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} dev: false @@ -1380,14 +1389,14 @@ packages: path-is-absolute: 1.0.1 dev: false - /glob/8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + /glob/8.0.3: + resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} engines: {node: '>=12'} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.1.2 once: 1.4.0 dev: false @@ -2314,8 +2323,8 @@ packages: brace-expansion: 1.1.11 dev: false - /minimatch/5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + /minimatch/5.1.2: + resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 @@ -3729,5 +3738,5 @@ packages: lodash.isequal: 4.5.0 validator: 13.7.0 optionalDependencies: - commander: 9.4.1 + commander: 9.5.0 dev: false diff --git a/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-metadata-plugin/command-line.json b/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-metadata-plugin/command-line.json new file mode 100644 index 00000000..94e066c6 --- /dev/null +++ b/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-metadata-plugin/command-line.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "name": "meta-init", + "commandKind": "global", + "summary": "Initialize a metadata file for a project", + "shellCommand": "node /lib/index.js init", + "safeForSimultaneousRushProcesses": false + }, + { + "name": "meta-sync", + "commandKind": "global", + "summary": "Sync the metadata files in the monorepo", + "shellCommand": "node /lib/index.js sync", + "safeForSimultaneousRushProcesses": false + } + ], + "parameters": [ + { + "parameterKind": "string", + "description": "The package name of the project", + "longName": "--project", + "shortName": "-p", + "argumentName": "PACKAGE_NAME", + "associatedCommands": ["meta-init"], + "required": false + }, + { + "parameterKind": "flag", + "description": "Generate a metadata JSON for each project in the monorepo", + "longName": "--all", + "associatedCommands": ["meta-init"], + "required": false + } + ] +} diff --git a/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json b/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000..616133b0 --- /dev/null +++ b/common/autoinstallers/command-plugins/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", + "plugins": [ + { + "pluginName": "rush-metadata-plugin", + "description": "A tool for managing metadata files", + "commandLineJsonFilePath": "command-line.json", + "optionsSchema": "lib/schemas/plugin-options.schema.json" + } + ] +} diff --git a/common/changes/rush-metadata-plugin/will-rush-metadata-plugin_2023-05-30-20-19.json b/common/changes/rush-metadata-plugin/will-rush-metadata-plugin_2023-05-30-20-19.json new file mode 100644 index 00000000..c6500b6e --- /dev/null +++ b/common/changes/rush-metadata-plugin/will-rush-metadata-plugin_2023-05-30-20-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "rush-metadata-plugin", + "comment": "Add the basic functionality to generate and update metadata files in rush projects", + "type": "minor" + } + ], + "packageName": "rush-metadata-plugin" +} \ No newline at end of file diff --git a/common/config/rush-plugins/rush-metadata-plugin.json b/common/config/rush-plugins/rush-metadata-plugin.json new file mode 100644 index 00000000..4d20b5b2 --- /dev/null +++ b/common/config/rush-plugins/rush-metadata-plugin.json @@ -0,0 +1,57 @@ +/** + +Custom field parameters: + +field: name +desc: name of the metadata field +type: string + +field: description +desc: description of the metdata field +type: string + +field: type +desc: what kind of data is it +types: +- string +- number +- string[] +- number[] + +field: isSelect +desc: whether this field will be a rush selector or not (passed into "--to" parameter, etc) +type: boolean +(note that this cannot be used for any type other than string) + +field: required +desc: whether or not this field is required +type: boolean + +*/ + +{ + "$schema": "../../../rush-plugins/rush-metadata-plugin/customMetaSchema.json", + // "metadataFileName": "config/project-metadata.json", + "fields": [ + { + "name": "productLine", + "description": "Which product line this project belongs to", + "prompt": "Which product line does this project belong to?", + "type": "string", + "required": true + }, + { + "name": "environmentVars", + "description": "A list of environment variables used in this package", + "prompt": "What environment variables are required for this package?", + "type": "string", + "required": false + } + // { + // "name": "testField", + // "description": "test", + // "type": "string", + // "required": true + // } + ] +} diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index de6dfbed..2503ddd0 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -212,6 +212,49 @@ importers: eslint: 7.32.0 typescript: 4.4.2 + ../../rush-plugins/rush-metadata-plugin: + specifiers: + '@rushstack/eslint-config': 2.4.5 + '@rushstack/heft': 0.43.2 + '@rushstack/heft-jest-plugin': ~0.1.53 + '@rushstack/heft-node-rig': 1.2.31 + '@rushstack/node-core-library': 3.44.1 + '@rushstack/rush-sdk': 5.62.4 + '@types/heft-jest': 1.0.1 + '@types/inquirer': ~8.1.3 + '@types/json2md': ~1.5.1 + '@types/node': 12.20.24 + '@types/yargs': ~17.0.7 + chalk: 4.1.2 + commander: ~9.4.0 + eslint: 7.32.0 + ignore: 5.1.9 + inquirer: ~8.2.0 + json2md: ~2.0.0 + typescript: 4.4.2 + yargs: ~17.3.0 + dependencies: + '@rushstack/node-core-library': 3.44.1 + '@rushstack/rush-sdk': 5.62.4 + chalk: 4.1.2 + commander: 9.4.0 + ignore: 5.1.9 + inquirer: 8.2.0 + json2md: 2.0.0 + yargs: 17.3.0 + devDependencies: + '@rushstack/eslint-config': 2.4.5_eslint@7.32.0+typescript@4.4.2 + '@rushstack/heft': 0.43.2 + '@rushstack/heft-jest-plugin': 0.1.53_@rushstack+heft@0.43.2 + '@rushstack/heft-node-rig': 1.2.31_@rushstack+heft@0.43.2 + '@types/heft-jest': 1.0.1 + '@types/inquirer': 8.1.3 + '@types/json2md': 1.5.1 + '@types/node': 12.20.24 + '@types/yargs': 17.0.7 + eslint: 7.32.0 + typescript: 4.4.2 + ../../rush-plugins/rush-print-log-if-error-plugin: specifiers: '@rushstack/eslint-config': 2.4.5 @@ -4343,7 +4386,7 @@ packages: mute-stream: 0.0.8 ora: 5.4.1 run-async: 2.4.1 - rxjs: 7.4.0 + rxjs: 7.5.2 string-width: 4.2.3 strip-ansi: 6.0.1 through: 2.3.8 @@ -6167,7 +6210,7 @@ packages: dev: false /os-tmpdir/1.0.2: - resolution: {integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=} + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} dev: false @@ -6750,6 +6793,7 @@ packages: resolution: {integrity: sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==} dependencies: tslib: 2.1.0 + dev: true /rxjs/7.5.2: resolution: {integrity: sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==} @@ -7332,7 +7376,7 @@ packages: dev: true /through/2.3.8: - resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=} + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: false /through2/2.0.5: @@ -7468,6 +7512,7 @@ packages: /tslib/2.1.0: resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} + dev: true /tslib/2.3.1: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} diff --git a/common/config/rush/rush-plugins.json b/common/config/rush/rush-plugins.json index b4d5c7e9..063b84eb 100644 --- a/common/config/rush/rush-plugins.json +++ b/common/config/rush/rush-plugins.json @@ -50,6 +50,11 @@ "packageName": "rush-upgrade-self-plugin", "pluginName": "rush-upgrade-self-plugin", "autoinstallerName": "command-plugins" // the name of autoinstaller you created before + }, + { + "packageName": "rush-metadata-plugin", + "pluginName": "rush-metadata-plugin", + "autoinstallerName": "command-plugins" // the name of autoinstaller you created before } ] } diff --git a/rush-plugins/rush-metadata-plugin/.eslintrc.js b/rush-plugins/rush-metadata-plugin/.eslintrc.js new file mode 100644 index 00000000..925d67c4 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/.eslintrc.js @@ -0,0 +1,14 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require("@rushstack/eslint-config/patch/modern-module-resolution"); + +module.exports = { + extends: [ + "@rushstack/eslint-config/profile/node-trusted-tool", + "@rushstack/eslint-config/mixins/friendly-locals", + ], + parserOptions: { tsconfigRootDir: __dirname }, + ignorePatterns: ["node_modules/", "lib/"], + rules: { + "@typescript-eslint/no-explicit-any": "off", + }, +}; diff --git a/rush-plugins/rush-metadata-plugin/.gitignore b/rush-plugins/rush-metadata-plugin/.gitignore new file mode 100644 index 00000000..f1ff06d6 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/.gitignore @@ -0,0 +1 @@ +lib/ \ No newline at end of file diff --git a/rush-plugins/rush-metadata-plugin/README.md b/rush-plugins/rush-metadata-plugin/README.md new file mode 100644 index 00000000..e1f92a56 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/README.md @@ -0,0 +1,42 @@ +========== This section is auto-generated by the rush metadata plugin. ========== + + +This section is auto-generated and will be auto-updated. Anything added manually outside this section will be preserved. + +## purpose + +#### The purpose of the package. + + +This package initializes and syncs metadata files in a monorepo. + +## pointOfContact + +#### The list of package owners. + + +william2958 + +## projectGroup + +#### Which project group does this package belong to? + + +rush-plugins + +## targetRuntime + +#### The environment in which the project will run. + + +node + +## productLine + +#### Which product line this project belongs to + + +libs + + +========== End of auto-generated section. ========== \ No newline at end of file diff --git a/rush-plugins/rush-metadata-plugin/command-line.json b/rush-plugins/rush-metadata-plugin/command-line.json new file mode 100644 index 00000000..94e066c6 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/command-line.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "name": "meta-init", + "commandKind": "global", + "summary": "Initialize a metadata file for a project", + "shellCommand": "node /lib/index.js init", + "safeForSimultaneousRushProcesses": false + }, + { + "name": "meta-sync", + "commandKind": "global", + "summary": "Sync the metadata files in the monorepo", + "shellCommand": "node /lib/index.js sync", + "safeForSimultaneousRushProcesses": false + } + ], + "parameters": [ + { + "parameterKind": "string", + "description": "The package name of the project", + "longName": "--project", + "shortName": "-p", + "argumentName": "PACKAGE_NAME", + "associatedCommands": ["meta-init"], + "required": false + }, + { + "parameterKind": "flag", + "description": "Generate a metadata JSON for each project in the monorepo", + "longName": "--all", + "associatedCommands": ["meta-init"], + "required": false + } + ] +} diff --git a/rush-plugins/rush-metadata-plugin/config/project-metadata.json b/rush-plugins/rush-metadata-plugin/config/project-metadata.json new file mode 100644 index 00000000..103e5e00 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/config/project-metadata.json @@ -0,0 +1,7 @@ +{ + "purpose": "This package initializes and syncs metadata files in a monorepo.", + "pointOfContact": ["william2958"], + "projectGroup": "rush-plugins", + "targetRuntime": "node", + "productLine": "libs" +} diff --git a/rush-plugins/rush-metadata-plugin/customMetaSchema.json b/rush-plugins/rush-metadata-plugin/customMetaSchema.json new file mode 100644 index 00000000..3277fa2a --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/customMetaSchema.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "CustomMetadata", + "properties": { + "metadataFileName": { + "type": "string", + "description": "The metadata file name to be saved and edited." + }, + "fields": { + "type": "array", + "description": "" + } + }, + "required": ["metadataFileName", "fields"] +} diff --git a/rush-plugins/rush-metadata-plugin/package.json b/rush-plugins/rush-metadata-plugin/package.json new file mode 100644 index 00000000..29ea0592 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/package.json @@ -0,0 +1,50 @@ +{ + "name": "rush-metadata-plugin", + "version": "0.0.1", + "description": "A tool for managing metadata files", + "keywords": [ + "rush", + "plugin", + "command", + "metadata" + ], + "homepage": "https://github.com/bytemate/rush-plugins#readme", + "repository": { + "type": "git", + "url": "https://github.com/bytemate/rush-plugins", + "directory": "rush-plugins/rush-audit-cache-plugin" + }, + "license": "MIT", + "author": "william2958", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "scripts": { + "build": "heft build --clean", + "build:watch": "heft build --watch", + "prepublishOnly": "npm run build", + "test": "heft test" + }, + "dependencies": { + "@rushstack/node-core-library": "3.44.1", + "@rushstack/rush-sdk": "5.62.4", + "chalk": "4.1.2", + "commander": "~9.4.0", + "ignore": "5.1.9", + "inquirer": "~8.2.0", + "json2md": "~2.0.0", + "yargs": "~17.3.0" + }, + "devDependencies": { + "@rushstack/eslint-config": "2.4.5", + "@rushstack/heft": "0.43.2", + "@rushstack/heft-jest-plugin": "~0.1.53", + "@rushstack/heft-node-rig": "1.2.31", + "@types/heft-jest": "1.0.1", + "@types/inquirer": "~8.1.3", + "@types/json2md": "~1.5.1", + "@types/node": "12.20.24", + "@types/yargs": "~17.0.7", + "eslint": "7.32.0", + "typescript": "4.4.2" + } +} diff --git a/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json b/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000..616133b0 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/rush-plugin-manifest.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", + "plugins": [ + { + "pluginName": "rush-metadata-plugin", + "description": "A tool for managing metadata files", + "commandLineJsonFilePath": "command-line.json", + "optionsSchema": "lib/schemas/plugin-options.schema.json" + } + ] +} diff --git a/rush-plugins/rush-metadata-plugin/src/defaultMetadataFields.json b/rush-plugins/rush-metadata-plugin/src/defaultMetadataFields.json new file mode 100644 index 00000000..76b11536 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/defaultMetadataFields.json @@ -0,0 +1,47 @@ +{ + "metadataFileName": "config/project-metadata.json", + "codeownersFileName": "config/CODEOWNERS", + "fields": [ + { + "name": "purpose", + "description": "The purpose of the package.", + "prompt": "What is the purpose of this package?", + "fieldType": "string", + "required": true + }, + { + "name": "pointOfContact", + "description": "The list of package owners.", + "prompt": "Who are the POCs of this package? (Separated by ',')", + "fieldType": "string", + "required": true + }, + { + "name": "projectGroup", + "description": "Which project group does this package belong to?", + "prompt": "What is the project group for this package?", + "fieldType": "string", + "required": false + }, + { + "name": "targetRuntime", + "description": "The environment in which the project will run.", + "prompt": "What is the target runtime?", + "fieldType": "list", + "choices": ["node", "browser", "cli"], + "required": false + }, + { + "name": "riskLevel", + "description": "The risk level assigned to this package.", + "prompt": "What is the risk level of this package?", + "fieldType": "list", + "choices": [ + { "name": "0 - Low Risk (Internal Library)", "value": 0 }, + { "name": "1 - Medium Risk (External Library)", "value": 1 }, + { "name": "2 - High Risk (Production Application)", "value": 2 } + ], + "required": false + } + ] +} diff --git a/rush-plugins/rush-metadata-plugin/src/index.ts b/rush-plugins/rush-metadata-plugin/src/index.ts new file mode 100644 index 00000000..65937ccf --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/index.ts @@ -0,0 +1,55 @@ +#!/usr/bin/env node +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +main(); + +async function main(): Promise { + await yargs(hideBin(process.argv)) + .command( + 'init', + 'Add metadata to a project', + (yargs) => { + return yargs + .option('project', { + type: 'string', + describe: 'The name of the package to archive' + }) + .option('all', { + type: 'boolean', + describe: 'Whether to initialize a basic metadata file for each project in the monorepo' + }); + }, + async (argv) => { + const { initMeta } = await import('./initMeta'); + try { + await initMeta(argv); + } catch (e: any) { + console.error('error: ', e); + process.exit(1); + } + } + ) + .command( + 'sync', + 'Sync the metadata in the monorepo.', + (yargs) => { + return yargs.option('codeowners', { + type: 'boolean', + describe: 'option to generate codeowners file' + }); + }, + async () => { + const { syncMeta } = await import('./syncMeta'); + try { + await syncMeta(); + } catch (e: any) { + console.error('error: ', e); + process.exit(1); + } + } + ) + .demandCommand(1, 'You need at least one command before moving on') + .parse(); +} diff --git a/rush-plugins/rush-metadata-plugin/src/initMeta/index.ts b/rush-plugins/rush-metadata-plugin/src/initMeta/index.ts new file mode 100644 index 00000000..ab9d6560 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/initMeta/index.ts @@ -0,0 +1,39 @@ +import { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import { loadRushConfiguration } from '../logic/rushConfiguration'; +import { initMetaForProject } from './initMetaForProject'; +import chalk from 'chalk'; +import path from 'path'; +import fs from 'fs'; +import { getCustomMetadataInfo } from '../logic/customMeta'; + +// Used to initialize a metadata file for a package +export const initMeta = async ({ project, all }: { project?: string; all?: boolean }): Promise => { + const rushConfiguration: RushConfiguration = loadRushConfiguration(); + + if (project) { + const rushProject: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(project); + if (!rushProject) { + throw new Error(`Could not find project with package name ${project}`); + } + await initMetaForProject(rushProject, true); + } else if (all) { + const allRushProjects: RushConfigurationProject[] = rushConfiguration.projects; + // Look for custom plugin configurations + const { metadataFileName } = getCustomMetadataInfo(); + for (const rushProject of allRushProjects) { + // Check if metadata file exists already + const { projectFolder } = rushProject; + const metaFilePath: string = path.join(projectFolder, metadataFileName); + if (!fs.existsSync(metaFilePath)) { + // Only initialize for projects that don't already have a metadata file + await initMetaForProject(rushProject, false); + } + } + } else { + console.log( + chalk.red( + 'Please specify a project with the --project parameter, or --all to initialize metadata for all packages.' + ) + ); + } +}; diff --git a/rush-plugins/rush-metadata-plugin/src/initMeta/initMetaForProject.ts b/rush-plugins/rush-metadata-plugin/src/initMeta/initMetaForProject.ts new file mode 100644 index 00000000..680e218a --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/initMeta/initMetaForProject.ts @@ -0,0 +1,50 @@ +import fs from 'fs'; +import path from 'path'; +import chalk from 'chalk'; + +import { RushConfigurationProject } from '@rushstack/rush-sdk'; +import { getAllMetadataFields, getCustomMetadataInfo } from '../logic/customMeta'; +import { IMetadataField } from '../types/metadataField'; +import { queryFields } from './queryFields'; +import { JsonFile } from '@rushstack/node-core-library'; +import { outputToReadme } from '../transformers/outputToReadme'; + +export const initMetaForProject = async ( + rushProject: RushConfigurationProject, + queryForAnswers: boolean +): Promise => { + const { projectFolder } = rushProject; + + // Look for custom plugin configurations + const { metadataFileName } = getCustomMetadataInfo(); + + // Check if metadata file exists already + const metaFilePath: string = path.join(projectFolder, metadataFileName); + + if (fs.existsSync(metaFilePath)) { + console.log(chalk.red('Please run rush meta update or edit the metadata file directly to make updates')); + return; + } + + const allFields: IMetadataField[] = getAllMetadataFields(); + + let answers: Record; + if (queryForAnswers) { + answers = await queryFields(allFields); + + if (answers.pointOfContact) { + const enteredPointsOfContact: string = answers.pointOfContact as string; + answers.pointOfContact = enteredPointsOfContact.split(',').map((s) => s.trim()); + } + } else { + answers = {}; + for (const field of allFields) { + answers[field.name] = ''; + } + } + + JsonFile.save(answers, metaFilePath, { ensureFolderExists: true }); + + const readmeAbsoluteFilePath: string = path.join(rushProject.projectFolder, 'README.md'); + outputToReadme(answers, readmeAbsoluteFilePath); +}; diff --git a/rush-plugins/rush-metadata-plugin/src/initMeta/queryFields.ts b/rush-plugins/rush-metadata-plugin/src/initMeta/queryFields.ts new file mode 100644 index 00000000..8bce23d9 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/initMeta/queryFields.ts @@ -0,0 +1,41 @@ +import inquirer from 'inquirer'; +import { IMetadataField } from '../types/metadataField'; + +export const queryFields = async (fields: IMetadataField[]): Promise> => { + const inquirerQuestions: any = []; + + for (const field of fields) { + const question: any = { + name: field.name, + message: field.prompt, + type: 'input' + }; + switch (field.fieldType) { + case 'string': + case 'number': + question.type = 'input'; + break; + case 'list': + question.type = 'list'; + question.choices = field.choices || []; + break; + } + inquirerQuestions.push(question); + } + + const answers: any = await inquirer.prompt(inquirerQuestions); + + const { confirmAnswers }: any = await inquirer.prompt([ + { + type: 'confirm', + name: 'confirmAnswers', + message: 'Do you want to save the above answers to the metadata file?' + } + ]); + + if (!confirmAnswers) { + return {}; + } + + return answers; +}; diff --git a/rush-plugins/rush-metadata-plugin/src/logic/convertFieldValue.ts b/rush-plugins/rush-metadata-plugin/src/logic/convertFieldValue.ts new file mode 100644 index 00000000..8137f078 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/logic/convertFieldValue.ts @@ -0,0 +1,26 @@ +import { IMetadataField } from '../types/metadataField'; + +export const convertFieldValue = (field: IMetadataField, value: string | number | string[]): string => { + if (Array.isArray(value)) { + return value.join(','); + } + + if (field.fieldType === 'list') { + if (field.choices && typeof field.choices[0] === 'string') { + return value as string; + } + // Try to decode the field value into it's label + if (field.choices && field.choices.length) { + for (const choice of field.choices as { + name: string; + value: string | number; + }[]) { + if (choice?.value === value) { + return choice.name; + } + } + } + return ''; + } + return value as string; +}; diff --git a/rush-plugins/rush-metadata-plugin/src/logic/customMeta.ts b/rush-plugins/rush-metadata-plugin/src/logic/customMeta.ts new file mode 100644 index 00000000..fe59aa70 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/logic/customMeta.ts @@ -0,0 +1,80 @@ +import { RushConfiguration } from '@rushstack/rush-sdk'; +import path from 'path'; + +import { loadRushConfiguration } from './rushConfiguration'; +import { JsonFile, FileSystem } from '@rushstack/node-core-library'; +import { IMetadataField } from '../types/metadataField'; +import { IPluginConfig } from '../types/pluginConfig'; +import DefaultFields from '../defaultMetadataFields.json'; + +export const getDefaultMetadataFileName = (): string => { + // Load default fields + const { metadataFileName }: { metadataFileName: string } = DefaultFields; + + return metadataFileName; +}; + +export const getDefaultCodeownersFileName = (): string => { + const { codeownersFileName }: { codeownersFileName: string } = DefaultFields; + return codeownersFileName; +}; + +export interface ICustomMetadataInfo { + metadataFileName: string; + codeownersFileName: string; + fields: IMetadataField[]; +} +export const getCustomMetadataInfo = (): ICustomMetadataInfo => { + const rushConfiguration: RushConfiguration = loadRushConfiguration(); + + const pluginOptionsJsonFilePath: string = path.join( + rushConfiguration.rushPluginOptionsFolder, + 'rush-metadata-plugin.json' + ); + + // Custom configurations for plugin + let metadataRelativeFolder: string = getDefaultMetadataFileName(); + let codeownersFileName: string = getDefaultCodeownersFileName(); + let customFields: IMetadataField[] = []; + + let metaConfigs: IPluginConfig | undefined; + try { + metaConfigs = JsonFile.load(pluginOptionsJsonFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + } + if (metaConfigs) { + if (metaConfigs.metadataFileName) { + metadataRelativeFolder = metaConfigs.metadataFileName; + } + if (metaConfigs.codeownersFileName) { + codeownersFileName = metaConfigs.codeownersFileName; + } + if (metaConfigs.fields) { + customFields = metaConfigs.fields; + } + } + + return { + metadataFileName: metadataRelativeFolder, + codeownersFileName, + fields: customFields + }; +}; + +export const getAllMetadataFields = (): IMetadataField[] => { + // Look for custom plugin configurations + const { fields } = getCustomMetadataInfo(); + + // Load default fields + const { fields: defaultFields }: { fields: IMetadataField[] } = DefaultFields as { + fields: IMetadataField[]; + }; + + // join the custom and default fields + const allFields: IMetadataField[] = [...defaultFields, ...fields]; + + return allFields; +}; diff --git a/rush-plugins/rush-metadata-plugin/src/logic/projectMetadata.ts b/rush-plugins/rush-metadata-plugin/src/logic/projectMetadata.ts new file mode 100644 index 00000000..4d6f927d --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/logic/projectMetadata.ts @@ -0,0 +1,36 @@ +import { JsonObject, JsonFile } from "@rushstack/node-core-library"; +export class ProjectMetadata { + private _projectConfig: JsonObject; + public static FILENAME: string = "rush-project-metadata.json"; + + public constructor(projectConfig: JsonObject) { + this._projectConfig = projectConfig; + } + + public static load(filePath: string): ProjectMetadata { + const { projectConfig } = JsonFile.load(filePath); + return new ProjectMetadata(projectConfig); + } + + public save(filePath: string): void { + JsonFile.save( + { + projectConfig: this._projectConfig, + }, + filePath, + { + ensureFolderExists: true, + } + ); + } + + public get projectConfig(): JsonObject { + return this._projectConfig; + } +} + +export interface IProjectCheckpointMetadata { + checkpointBranch: string; + archivedOn: string; + description: string; +} \ No newline at end of file diff --git a/rush-plugins/rush-metadata-plugin/src/logic/rushConfiguration.ts b/rush-plugins/rush-metadata-plugin/src/logic/rushConfiguration.ts new file mode 100644 index 00000000..f8e86e12 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/logic/rushConfiguration.ts @@ -0,0 +1,24 @@ +import { RushConfiguration } from "@rushstack/rush-sdk"; + +const cwd2rushConfiguration: Record = {}; + +export const loadRushConfiguration = ( + cwd: string = process.cwd() +): RushConfiguration => { + let rushConfiguration: RushConfiguration | undefined = + cwd2rushConfiguration[cwd]; + if (!rushConfiguration) { + try { + rushConfiguration = RushConfiguration.loadFromDefaultLocation({ + startingFolder: cwd, + }); + } catch { + // no-catch + } + if (!rushConfiguration) { + throw new Error("Could not load rush configuration"); + } + cwd2rushConfiguration[cwd] = rushConfiguration; + } + return rushConfiguration; +}; diff --git a/rush-plugins/rush-metadata-plugin/src/syncMeta/index.ts b/rush-plugins/rush-metadata-plugin/src/syncMeta/index.ts new file mode 100644 index 00000000..8074b4f6 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/syncMeta/index.ts @@ -0,0 +1,40 @@ +import { RushConfiguration } from '@rushstack/rush-sdk'; +import { JsonFile } from '@rushstack/node-core-library'; +import { log } from 'console'; +import chalk from 'chalk'; +import path from 'path'; +import fs from 'fs'; + +import { loadRushConfiguration } from '../logic/rushConfiguration'; +import { getCustomMetadataInfo } from '../logic/customMeta'; +import { ICoreMetadata } from '../template'; +import { syncMetadataFile } from './syncMetadataFile'; +import { outputToReadme } from '../transformers/outputToReadme'; + +// Used to sync all the metadata files in the monorepo according to the metadata spec +export const syncMeta = async (): Promise => { + const rushConfiguration: RushConfiguration = loadRushConfiguration(); + for (const rushProject of rushConfiguration.projects) { + log('rush project: ', rushProject.projectFolder); + + // Look for custom plugin configurations + const { metadataFileName } = getCustomMetadataInfo(); + + // Check if metadata file exists already + const metaFilePath: string = path.join(rushProject.projectFolder, metadataFileName); + let newMetadataFile: any; + if (fs.existsSync(metaFilePath)) { + // Read and parse the file + const loadedJsonFile: ICoreMetadata = JsonFile.load(metaFilePath); + + log(chalk.green(`Updating metadata file at: ${metaFilePath}`)); + + newMetadataFile = syncMetadataFile(loadedJsonFile); + + JsonFile.save(newMetadataFile, metaFilePath, { updateExistingFile: true }); + + const readmeAbsoluteFilePath: string = path.join(rushProject.projectFolder, 'README.md'); + outputToReadme(loadedJsonFile, readmeAbsoluteFilePath); + } + } +}; diff --git a/rush-plugins/rush-metadata-plugin/src/syncMeta/syncMetadataFile.ts b/rush-plugins/rush-metadata-plugin/src/syncMeta/syncMetadataFile.ts new file mode 100644 index 00000000..ec0f5d06 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/syncMeta/syncMetadataFile.ts @@ -0,0 +1,22 @@ +import { getAllMetadataFields } from '../logic/customMeta'; +import { ICoreMetadata } from '../template'; +import { IMetadataField } from '../types/metadataField'; + +export const syncMetadataFile = (currMetadata: any): ICoreMetadata => { + const allFields: IMetadataField[] = getAllMetadataFields(); + const newMetadata: any = {}; + + for (const field of allFields) { + // @ts-ignore + if (field.required && !currMetadata[field.name]) { + // Fill in the field with a default value + newMetadata[field.name] = ''; + } else if (!field.required && !currMetadata[field.name]) { + // Don't care if the field doesn't exist on a field that is not required + } else { + newMetadata[field.name] = currMetadata[field.name]; + } + } + + return newMetadata; +}; diff --git a/rush-plugins/rush-metadata-plugin/src/template.ts b/rush-plugins/rush-metadata-plugin/src/template.ts new file mode 100644 index 00000000..9586664a --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/template.ts @@ -0,0 +1,7 @@ +export interface ICoreMetadata { + pointOfContact: string[] | string; + purpose: string; + projectGroup: string; + targetRuntime: string; + riskLevel: number; +} \ No newline at end of file diff --git a/rush-plugins/rush-metadata-plugin/src/transformers/outputToReadme.ts b/rush-plugins/rush-metadata-plugin/src/transformers/outputToReadme.ts new file mode 100644 index 00000000..7e19cfe9 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/transformers/outputToReadme.ts @@ -0,0 +1,59 @@ +import json2md from 'json2md'; +import fs from 'fs'; +import { IMetadataField } from '../types/metadataField'; +import { getAllMetadataFields } from '../logic/customMeta'; +import { convertFieldValue } from '../logic/convertFieldValue'; + +export const MDStartKey: string = + '========== This section is auto-generated by the rush metadata plugin. =========='; +export const MDEndKey: string = '========== End of auto-generated section. =========='; + +export const outputToReadme = (currentValues: any, outputFileLocation: string): void => { + let prevMDContents: string = ''; + let postMDContents: string = ''; + + // Check if readme file already exists + if (fs.existsSync(outputFileLocation)) { + const readmeContents: string = fs.readFileSync(outputFileLocation, 'utf8'); + // Check if the start and end key exist + if (readmeContents.indexOf(MDStartKey) !== -1 && readmeContents.indexOf(MDEndKey)) { + prevMDContents = readmeContents.slice(0, readmeContents.indexOf(MDStartKey)); + postMDContents = readmeContents.slice(readmeContents.indexOf(MDEndKey) + MDEndKey.length); + } else { + // Preserve previous content in prevMDContents + prevMDContents = readmeContents + '\n'; + } + } + + const allFields: IMetadataField[] = getAllMetadataFields(); + // Generate md file + const mdFileContents: any = [ + { p: MDStartKey }, + { + p: 'This section is auto-generated and will be auto-updated. Anything added manually outside this section will be preserved.' + } + ]; + + for (const field of allFields) { + let fieldValue: string = ''; + if (!currentValues[field.name]) { + continue; + } + fieldValue = convertFieldValue(field, currentValues[field.name]); + mdFileContents.push( + ...[ + { h2: field.name }, + { h4: `${field.description}` }, + { p: fieldValue } + ] + ); + } + + mdFileContents.push({ p: MDEndKey }); + + const mdContents: string = json2md(mdFileContents); + + const mdToOutput: string = prevMDContents + mdContents.trim() + postMDContents; + + fs.writeFileSync(outputFileLocation, mdToOutput); +}; diff --git a/rush-plugins/rush-metadata-plugin/src/types/metadataField.ts b/rush-plugins/rush-metadata-plugin/src/types/metadataField.ts new file mode 100644 index 00000000..b39570a0 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/types/metadataField.ts @@ -0,0 +1,17 @@ +export enum FieldTypes { + STRING = 'string', + NUMBER = 'number', + LIST = 'list', + CHOICE = 'choice', + SELECTOR = 'selector' +} + +export interface IMetadataField { + name: string; + description: string; + prompt: string; + fieldType: FieldTypes; + required: boolean; + choices?: string[] | { name: string; value: string | number }[]; + defaultValue?: string; +} diff --git a/rush-plugins/rush-metadata-plugin/src/types/pluginConfig.ts b/rush-plugins/rush-metadata-plugin/src/types/pluginConfig.ts new file mode 100644 index 00000000..36a69574 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/src/types/pluginConfig.ts @@ -0,0 +1,9 @@ +import { IMetadataField } from './metadataField'; + +export interface IPluginConfig { + metadataFileName?: string; + codeownersFileName?: string; + // Link to the custom schema for this metadata object (generated by this plugin) + metadataSchema?: string; + fields: IMetadataField[]; +} diff --git a/rush-plugins/rush-metadata-plugin/tsconfig.json b/rush-plugins/rush-metadata-plugin/tsconfig.json new file mode 100644 index 00000000..5f5cea08 --- /dev/null +++ b/rush-plugins/rush-metadata-plugin/tsconfig.json @@ -0,0 +1,97 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [ + // "ES2015" + // ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + "types": [ + "heft-jest", + "node" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + /* Emit */ + "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + "declarationMap": true /* Create sourcemaps for d.ts files. */, + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./lib" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + "downlevelIteration": true /* Emit more compliant, but verbose and less performant JavaScript for iteration. */, + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/rush.json b/rush.json index 3b674985..11f86c92 100644 --- a/rush.json +++ b/rush.json @@ -496,6 +496,11 @@ "packageName": "rush-git-lfs-plugin", "projectFolder": "rush-plugins/rush-git-lfs-plugin", "shouldPublish": true + }, + { + "packageName": "rush-metadata-plugin", + "projectFolder": "rush-plugins/rush-metadata-plugin", + "shouldPublish": true } ] }