Skip to content

[eslint-config] Update TypeScript/ESLint Utilities and Refactor Linting #4883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ jobs:
strategy:
matrix:
include:
- NodeVersion: 16.20.x
NodeVersionDisplayName: 16
OS: ubuntu-latest
- NodeVersion: 18.18.x
NodeVersionDisplayName: 18
OS: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ These GitHub repositories provide supplementary resources for Rush Stack:
| [/build-tests/eslint-7-test](./build-tests/eslint-7-test/) | This project contains a build test to validate ESLint 7 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) |
| [/build-tests/eslint-8-test](./build-tests/eslint-8-test/) | This project contains a build test to validate ESLint 8 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) |
| [/build-tests/eslint-bulk-suppressions-test](./build-tests/eslint-bulk-suppressions-test/) | Sample code to test eslint bulk suppressions |
| [/build-tests/eslint-bulk-suppressions-test-legacy](./build-tests/eslint-bulk-suppressions-test-legacy/) | Sample code to test eslint bulk suppressions for versions of eslint < 8.57.0 |
| [/build-tests/hashed-folder-copy-plugin-webpack5-test](./build-tests/hashed-folder-copy-plugin-webpack5-test/) | Building this project exercises @rushstack/hashed-folder-copy-plugin with Webpack 5. NOTE - THIS TEST IS CURRENTLY EXPECTED TO BE BROKEN |
| [/build-tests/heft-copy-files-test](./build-tests/heft-copy-files-test/) | Building this project tests copying files with Heft |
| [/build-tests/heft-example-plugin-01](./build-tests/heft-example-plugin-01/) | This is an example heft plugin that exposes hooks for other plugins |
Expand Down
4 changes: 2 additions & 2 deletions build-tests/eslint-7-11-test/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-pac

module.exports = {
extends: [
'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool',
'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals'
'@rushstack/eslint-config/profile/node-trusted-tool',
'@rushstack/eslint-config/mixins/friendly-locals'
],
parserOptions: { tsconfigRootDir: __dirname },

Expand Down
3 changes: 2 additions & 1 deletion build-tests/eslint-7-11-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
"_phase:build": "heft run --only build -- --clean"
},
"devDependencies": {
"@rushstack/eslint-config": "3.7.0",
"@rushstack/heft": "workspace:*",
"local-node-rig": "workspace:*",
"@types/node": "18.17.15",
"@typescript-eslint/parser": "~6.19.0",
"eslint": "7.11.0",
"local-node-rig": "workspace:*",
"typescript": "~5.4.2"
}
}
4 changes: 2 additions & 2 deletions build-tests/eslint-7-7-test/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-pac

module.exports = {
extends: [
'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool',
'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals'
'@rushstack/eslint-config/profile/node-trusted-tool',
'@rushstack/eslint-config/mixins/friendly-locals'
],
parserOptions: { tsconfigRootDir: __dirname },

Expand Down
3 changes: 2 additions & 1 deletion build-tests/eslint-7-7-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
"_phase:build": "heft run --only build -- --clean"
},
"devDependencies": {
"@rushstack/eslint-config": "3.7.0",
"@rushstack/heft": "workspace:*",
"local-node-rig": "workspace:*",
"@types/node": "18.17.15",
"@typescript-eslint/parser": "~6.19.0",
"eslint": "7.7.0",
"local-node-rig": "workspace:*",
"typescript": "~5.4.2"
}
}
4 changes: 2 additions & 2 deletions build-tests/eslint-7-test/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-pac

module.exports = {
extends: [
'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool',
'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals'
'@rushstack/eslint-config/profile/node-trusted-tool',
'@rushstack/eslint-config/mixins/friendly-locals'
],
parserOptions: { tsconfigRootDir: __dirname },

Expand Down
3 changes: 2 additions & 1 deletion build-tests/eslint-7-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
"_phase:build": "heft run --only build -- --clean"
},
"devDependencies": {
"@rushstack/eslint-config": "3.7.0",
"@rushstack/heft": "workspace:*",
"local-node-rig": "workspace:*",
"@types/node": "18.17.15",
"@typescript-eslint/parser": "~6.19.0",
"eslint": "~7.30.0",
"local-node-rig": "workspace:*",
"typescript": "~5.4.2"
}
}
2 changes: 1 addition & 1 deletion build-tests/eslint-8-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@rushstack/heft": "workspace:*",
"local-node-rig": "workspace:*",
"@types/node": "18.17.15",
"@typescript-eslint/parser": "~6.19.0",
"@typescript-eslint/parser": "~8.1.0",
"eslint": "~8.57.0",
"typescript": "~5.4.2"
}
Expand Down
108 changes: 108 additions & 0 deletions build-tests/eslint-bulk-suppressions-test-legacy/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// This project is a duplicate of "eslint-bulk-suppressions-test" intended to test eslint
// against the older version of the TypeScript parser. Any modifications made to this project
// should be reflected in "eslint-bulk-suppressions-test" as well.

const { FileSystem, Executable, Text, Import } = require('@rushstack/node-core-library');
const path = require('path');
const {
ESLINT_PACKAGE_NAME_ENV_VAR_NAME
} = require('@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants');

const eslintBulkStartPath = Import.resolveModule({
modulePath: '@rushstack/eslint-bulk/lib/start',
baseFolderPath: __dirname
});

function tryLoadSuppressions(suppressionsJsonPath) {
try {
return Text.convertToLf(FileSystem.readFile(suppressionsJsonPath)).trim();
} catch (e) {
if (FileSystem.isNotExistError(e)) {
return '';
} else {
throw e;
}
}
}

const RUN_FOLDER_PATHS = ['client', 'server'];
const ESLINT_PACKAGE_NAMES = ['eslint', 'eslint-8.23', 'eslint-oldest'];

const updateFilePaths = new Set();

for (const runFolderPath of RUN_FOLDER_PATHS) {
const folderPath = `${__dirname}/${runFolderPath}`;
const suppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions.json`;

const folderItems = FileSystem.readFolderItems(folderPath);
for (const folderItem of folderItems) {
if (folderItem.isFile() && folderItem.name.match(/^\.eslint\-bulk\-suppressions\-[\d.]+\.json$/)) {
const fullPath = `${folderPath}/${folderItem.name}`;
updateFilePaths.add(fullPath);
}
}

for (const eslintPackageName of ESLINT_PACKAGE_NAMES) {
const { version: eslintVersion } = require(`${eslintPackageName}/package.json`);

const startLoggingMessage = `-- Running eslint-bulk-suppressions for eslint@${eslintVersion} in ${runFolderPath} --`;
console.log(startLoggingMessage);
const referenceSuppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions-${eslintVersion}.json`;
const existingSuppressions = tryLoadSuppressions(referenceSuppressionsJsonPath);

// The eslint-bulk-suppressions patch expects to find "eslint" in the shell PATH. To ensure deterministic
// test behavior, we need to designate an explicit "node_modules/.bin" folder.
//
// Use the ".bin" folder from @rushstack/eslint-patch as a workaround for this PNPM bug:
// https://github.com/pnpm/pnpm/issues/7833
const dependencyBinFolder = path.join(
__dirname,
'node_modules',
'@rushstack',
'eslint-patch',
'node_modules',
'.bin'
);
const shellPathWithEslint = `${dependencyBinFolder}${path.delimiter}${process.env['PATH']}`;

const executableResult = Executable.spawnSync(
process.argv0,
[eslintBulkStartPath, 'suppress', '--all', 'src'],
{
currentWorkingDirectory: folderPath,
environment: {
...process.env,
PATH: shellPathWithEslint,
[ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName
}
}
);

if (executableResult.status !== 0) {
console.error('The eslint-bulk-suppressions command failed.');
console.error('STDOUT:');
console.error(executableResult.stdout.toString());
console.error('STDERR:');
console.error(executableResult.stderr.toString());
process.exit(1);
}

const newSuppressions = tryLoadSuppressions(suppressionsJsonPath);
if (newSuppressions === existingSuppressions) {
updateFilePaths.delete(referenceSuppressionsJsonPath);
} else {
updateFilePaths.add(referenceSuppressionsJsonPath);
FileSystem.writeFile(referenceSuppressionsJsonPath, newSuppressions);
}

FileSystem.deleteFile(suppressionsJsonPath);
}
}

if (updateFilePaths.size > 0) {
for (const updateFilePath of updateFilePaths) {
console.log(`The suppressions file "${updateFilePath}" was updated and must be committed to git.`);
}

process.exit(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
{
"suppressions": [
{
"file": "src/index.ts",
"scopeId": ".",
"rule": "prefer-const"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass",
"rule": "@typescript-eslint/ban-types"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass",
"rule": "@typescript-eslint/explicit-member-accessibility"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass.exampleMethod",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass.exampleMethod",
"rule": "@typescript-eslint/explicit-member-accessibility"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass.exampleMethod",
"rule": "@typescript-eslint/typedef"
},
{
"file": "src/index.ts",
"scopeId": ".ExampleClass.exampleMethod",
"rule": "no-var"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass",
"rule": "@typescript-eslint/explicit-member-accessibility"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass",
"rule": "@typescript-eslint/typedef"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass",
"rule": "no-useless-concat"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass.constructor",
"rule": "@typescript-eslint/explicit-member-accessibility"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass.exampleSetGet",
"rule": "@typescript-eslint/ban-types"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass.exampleSetGet",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".exampleAnonymousClass.exampleSetGet",
"rule": "@typescript-eslint/explicit-member-accessibility"
},
{
"file": "src/index.ts",
"scopeId": ".exampleArrowFunction",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".exampleArrowFunction",
"rule": "@typescript-eslint/typedef"
},
{
"file": "src/index.ts",
"scopeId": ".exampleArrowFunction",
"rule": "dot-notation"
},
{
"file": "src/index.ts",
"scopeId": ".exampleArrowFunction",
"rule": "no-empty"
},
{
"file": "src/index.ts",
"scopeId": ".exampleArrowFunction",
"rule": "no-unused-expressions"
},
{
"file": "src/index.ts",
"scopeId": ".exampleFunction",
"rule": "@typescript-eslint/ban-types"
},
{
"file": "src/index.ts",
"scopeId": ".exampleFunction",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".exampleFunction",
"rule": "no-empty-pattern"
},
{
"file": "src/index.ts",
"scopeId": ".exampleFunction",
"rule": "no-extra-boolean-cast"
},
{
"file": "src/index.ts",
"scopeId": ".exampleObject",
"rule": "@typescript-eslint/typedef"
},
{
"file": "src/index.ts",
"scopeId": ".x",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".y",
"rule": "@typescript-eslint/explicit-function-return-type"
},
{
"file": "src/index.ts",
"scopeId": ".z",
"rule": "@typescript-eslint/explicit-function-return-type"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

// This is a workaround for https://github.com/eslint/eslint/issues/3458
require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution');
// This is a workaround for https://github.com/microsoft/rushstack/issues/3021
require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names');
require('local-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions');

module.exports = {
extends: [
'@rushstack/eslint-config/profile/node-trusted-tool',
'@rushstack/eslint-config/mixins/friendly-locals'
],
ignorePatterns: ['.eslintrc.js'],

overrides: [
/**
* Override the parser from @rushstack/eslint-config. Since the config is coming
* from the workspace instead of the external NPM package, the versions of ESLint
* and TypeScript that the config consumes will be resolved from the devDependencies
* of the config instead of from the eslint-8-test package. Overriding the parser
* ensures that the these dependencies come from the eslint-8-test package. See:
* https://github.com/microsoft/rushstack/issues/3021
*/
{
files: ['**/*.ts', '**/*.tsx'],
parser: '@typescript-eslint/parser',
parserOptions: { project: '../tsconfig.json', tsconfigRootDir: __dirname }
}
]
};
Loading
Loading