diff --git a/build-tests/eslint-bulk-suppressions-test/build.js b/build-tests/eslint-bulk-suppressions-test/build.js new file mode 100644 index 00000000000..2e1cb54fc77 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/build.js @@ -0,0 +1,88 @@ +const { FileSystem, Executable, Text, Import } = require('@rushstack/node-core-library'); +const { + ESLINT_PACKAGE_NAME_ENV_VAR_NAME +} = require('@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants'); + +const eslintBulkStartPath = Import.resolveModule({ + modulePath: '@rushstack/eslint-bulk/lib/start', + baseFolderPath: __dirname +}); + +function tryLoadSuppressions(suppressionsJsonPath) { + try { + return Text.convertToLf(FileSystem.readFile(suppressionsJsonPath)).trim(); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return ''; + } else { + throw e; + } + } +} + +const RUN_FOLDER_PATHS = ['client', 'server']; +const ESLINT_PACKAGE_NAMES = ['eslint', 'eslint-newest', 'eslint-oldest']; + +const updateFilePaths = new Set(); + +for (const runFolderPath of RUN_FOLDER_PATHS) { + const folderPath = `${__dirname}/${runFolderPath}`; + const suppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions.json`; + + const folderItems = FileSystem.readFolderItems(folderPath); + for (const folderItem of folderItems) { + if (folderItem.isFile() && folderItem.name.match(/^\.eslint\-bulk\-suppressions\-[\d.]+\.json$/)) { + const fullPath = `${folderPath}/${folderItem.name}`; + updateFilePaths.add(fullPath); + } + } + + for (const eslintPackageName of ESLINT_PACKAGE_NAMES) { + const { version: eslintVersion } = require(`${eslintPackageName}/package.json`); + + const startLoggingMessage = `-- Running eslint-bulk-suppressions for eslint@${eslintVersion} in ${runFolderPath} --`; + const endLoggingMessage = '-'.repeat(startLoggingMessage.length); + console.log(startLoggingMessage); + const referenceSuppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions-${eslintVersion}.json`; + const existingSuppressions = tryLoadSuppressions(referenceSuppressionsJsonPath); + + const executableResult = Executable.spawnSync( + process.argv0, + [eslintBulkStartPath, 'suppress', '--all', 'src'], + { + currentWorkingDirectory: folderPath, + environment: { + ...process.env, + [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName + } + } + ); + + console.log('STDOUT:'); + console.log(executableResult.stdout.toString()); + + console.log('STDERR:'); + console.log(executableResult.stderr.toString()); + + const newSuppressions = tryLoadSuppressions(suppressionsJsonPath); + if (newSuppressions === existingSuppressions) { + updateFilePaths.delete(referenceSuppressionsJsonPath); + } else { + updateFilePaths.add(referenceSuppressionsJsonPath); + FileSystem.writeFile(referenceSuppressionsJsonPath, newSuppressions); + } + + FileSystem.deleteFile(suppressionsJsonPath); + + console.log(endLoggingMessage); + console.log(); + } +} + +if (updateFilePaths.size > 0) { + for (const updateFilePath of updateFilePaths) { + console.log(`The suppressions file "${updateFilePath}" was updated and must be committed to git.`); + } + + process.exit(1); +} diff --git a/build-tests/eslint-bulk-suppressions-test/package.json b/build-tests/eslint-bulk-suppressions-test/package.json index e7826a03fcb..a52b1d8bb72 100644 --- a/build-tests/eslint-bulk-suppressions-test/package.json +++ b/build-tests/eslint-bulk-suppressions-test/package.json @@ -4,13 +4,18 @@ "version": "1.0.0", "private": true, "scripts": { - "_phase:build": "eslint ." + "_phase:build": "node build.js" }, "devDependencies": { + "@rushstack/eslint-bulk": "workspace:*", + "@rushstack/eslint-patch": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", + "@rushstack/node-core-library": "workspace:*", "@typescript-eslint/parser": "~6.19.0", "eslint": "~8.7.0", + "eslint-newest": "npm:eslint@~8.23.1", + "eslint-oldest": "npm:eslint@8.6.0", + "local-node-rig": "workspace:*", "typescript": "~5.4.2" } } diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 11d8bfb0860..b20320fe938 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -98,6 +98,10 @@ "name": "@rushstack/debug-certificate-manager", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/eslint-bulk", + "allowedCategories": [ "tests" ] + }, { "name": "@rushstack/eslint-config", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 8a09e22a634..6da61ed964f 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -918,10 +918,10 @@ importers: version: file:../../apps/heft '@rushstack/heft-lint-plugin': specifier: workspace:* - version: file:../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.66.1) + version: file:../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.66.2) '@rushstack/heft-typescript-plugin': specifier: workspace:* - version: file:../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.66.1) + version: file:../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.66.2) eslint: specifier: ~8.7.0 version: 8.7.0(supports-color@8.1.1) @@ -1322,15 +1322,30 @@ importers: ../../build-tests/eslint-bulk-suppressions-test: devDependencies: + '@rushstack/eslint-bulk': + specifier: workspace:* + version: link:../../eslint/eslint-bulk + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../../eslint/eslint-patch '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library '@typescript-eslint/parser': specifier: ~6.19.0 version: 6.19.1(eslint@8.7.0)(typescript@5.4.2) eslint: specifier: ~8.7.0 version: 8.7.0(supports-color@8.1.1) + eslint-newest: + specifier: npm:eslint@~8.23.1 + version: /eslint@8.23.1 + eslint-oldest: + specifier: npm:eslint@8.6.0 + version: /eslint@8.6.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -1943,7 +1958,7 @@ importers: version: 29.5.12 '@types/node': specifier: ts4.9 - version: 20.11.29 + version: 20.11.30 eslint: specifier: ~8.7.0 version: 8.7.0(supports-color@8.1.1) @@ -8497,6 +8512,17 @@ packages: csstype: 3.1.3 dev: false + /@humanwhocodes/config-array@0.10.7: + resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4(supports-color@8.1.1) + minimatch: 3.0.8 + transitivePeerDependencies: + - supports-color + dev: true + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -8529,6 +8555,10 @@ packages: transitivePeerDependencies: - supports-color + /@humanwhocodes/gitignore-to-minimatch@1.0.2: + resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} + dev: true + /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -12026,8 +12056,8 @@ packages: /@types/node@18.17.15: resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} - /@types/node@20.11.29: - resolution: {integrity: sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==} + /@types/node@20.11.30: + resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} dependencies: undici-types: 5.26.5 dev: true @@ -17095,6 +17125,54 @@ packages: - supports-color dev: true + /eslint@8.23.1: + resolution: {integrity: sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1(supports-color@8.1.1) + '@humanwhocodes/config-array': 0.10.7 + '@humanwhocodes/gitignore-to-minimatch': 1.0.2 + '@humanwhocodes/module-importer': 1.0.1 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-utils: 3.0.0(eslint@8.7.0) + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + globby: 11.1.0 + grapheme-splitter: 1.0.4 + ignore: 5.3.1 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-sdsl: 4.4.2 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -17142,6 +17220,53 @@ packages: - supports-color dev: true + /eslint@8.6.0: + resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1(supports-color@8.1.1) + '@humanwhocodes/config-array': 0.9.5(supports-color@8.1.1) + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + doctrine: 3.0.0 + enquirer: 2.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-utils: 3.0.0(eslint@8.7.0) + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.24.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.0.8 + natural-compare: 1.4.0 + optionator: 0.9.3 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.5.4 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + v8-compile-cache: 2.4.0 + transitivePeerDependencies: + - supports-color + dev: true + /eslint@8.7.0(supports-color@8.1.1): resolution: {integrity: sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -18350,6 +18475,10 @@ packages: /graceful-fs@4.2.4: resolution: {integrity: sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==} + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -20201,6 +20330,10 @@ packages: engines: {node: '>= 0.6.0'} dev: true + /js-sdsl@4.4.2: + resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} + dev: true + /js-string-escape@1.0.1: resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} engines: {node: '>= 0.8'} @@ -27460,7 +27593,7 @@ packages: - supports-color dev: true - file:../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.66.1): + file:../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.66.2): resolution: {directory: ../../heft-plugins/heft-lint-plugin, type: directory} id: file:../../heft-plugins/heft-lint-plugin name: '@rushstack/heft-lint-plugin' @@ -27472,7 +27605,7 @@ packages: semver: 7.5.4 dev: true - file:../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.66.1): + file:../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.66.2): resolution: {directory: ../../heft-plugins/heft-typescript-plugin, type: directory} id: file:../../heft-plugins/heft-typescript-plugin name: '@rushstack/heft-typescript-plugin' diff --git a/common/config/rush/repo-state.json b/common/config/rush/repo-state.json index 17bee58b6b7..d25d3d76b24 100644 --- a/common/config/rush/repo-state.json +++ b/common/config/rush/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": "552257b9ed51e893210d6bba3f0c10fcddf6a9aa", + "pnpmShrinkwrapHash": "1da0835844b2dddb8f340063ceb13ccf02a65dea", "preferredVersionsHash": "c3ce06bc821dea3e1fe5dbc73da35b305908795a" } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts index cd89709bfca..2fb9f55bb34 100755 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import path from 'path'; +import { BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME } from '../../constants'; // When this list is updated, update the `eslint-bulk-suppressions-newest-test` // and/or the `eslint-bulk-suppressions-newest-test` projects' eslint dependencies. @@ -11,7 +12,9 @@ export function getEslintPath(packagePath: string): string { // Try to find a local ESLint installation, the one that should be listed as a dev dependency in package.json // and installed in node_modules try { - const localEslintApiPath: string = require.resolve('eslint', { paths: [packagePath] }); + const localEslintApiPath: string = require.resolve(BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME, { + paths: [packagePath] + }); const localEslintPath: string = path.dirname(path.dirname(localEslintApiPath)); const { version: localEslintVersion } = require(`${localEslintPath}/package.json`); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts index 84518d5e3cc..0d505df08ab 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts @@ -12,3 +12,9 @@ export const ESLINT_BULK_DETECT_ENV_VAR_NAME: '_RUSHSTACK_ESLINT_BULK_DETECT' = export const ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME: 'RUSHSTACK_ESLINT_BULK_FORCE_REGENERATE_PATCH' = 'RUSHSTACK_ESLINT_BULK_FORCE_REGENERATE_PATCH'; export const VSCODE_PID_ENV_VAR_NAME: 'VSCODE_PID' = 'VSCODE_PID'; + +export const ESLINT_PACKAGE_NAME_ENV_VAR_NAME: '_RUSHSTACK_ESLINT_PACKAGE_NAME' = + '_RUSHSTACK_ESLINT_PACKAGE_NAME'; + +export const BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME: string = + process.env[ESLINT_PACKAGE_NAME_ENV_VAR_NAME] ?? 'eslint';