From 994596b07f5ff20a615a4be1ea03e5fd59cdb84b Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Sun, 22 Oct 2023 18:56:52 +0200 Subject: [PATCH 01/91] ci: run tests in Node.js 21 (#17673) Run CI tests in Node 21 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7602b8380378..7bf368fdac75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node: [20.x, 19.x, 18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"] + node: [21.x, 20.x, 19.x, 18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"] include: - os: windows-latest node: "lts/*" From b329ea748dff45f11c7e218208244dc24fcb5c8f Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Tue, 24 Oct 2023 08:58:43 +0200 Subject: [PATCH 02/91] fix: add `;` after JSX nodes in `no-object-constructor` autofix (#17672) Fix `no-object-constructor` autofix after JSX nodes --- lib/rules/no-object-constructor.js | 4 ++-- tests/lib/rules/no-object-constructor.js | 28 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/rules/no-object-constructor.js b/lib/rules/no-object-constructor.js index 0659d1633816..e3ac20957348 100644 --- a/lib/rules/no-object-constructor.js +++ b/lib/rules/no-object-constructor.js @@ -35,10 +35,10 @@ const NODE_TYPES_BY_KEYWORD = { }; /* - * Before an opening parenthesis, `>` (for JSX), and postfix `++` and `--` always trigger ASI; + * Before an opening parenthesis, postfix `++` and `--` always trigger ASI; * the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement. */ -const PUNCTUATORS = new Set([":", ";", ">", "{", "=>", "++", "--"]); +const PUNCTUATORS = new Set([":", ";", "{", "=>", "++", "--"]); /* * Statements that can contain an `ExpressionStatement` after a closing parenthesis. diff --git a/tests/lib/rules/no-object-constructor.js b/tests/lib/rules/no-object-constructor.js index 4d51f2a21d69..464a0779bc70 100644 --- a/tests/lib/rules/no-object-constructor.js +++ b/tests/lib/rules/no-object-constructor.js @@ -168,6 +168,20 @@ ruleTester.run("no-object-constructor", rule, { var foo = { bar: baz } Object() ` + }, + { + code: ` + + Object() + `, + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: ` + + Object() + `, + parserOptions: { ecmaFeatures: { jsx: true } } } ].map(props => ({ ...props, @@ -296,20 +310,6 @@ ruleTester.run("no-object-constructor", rule, { Object() ` }, - { - code: ` - - Object() - `, - parserOptions: { ecmaFeatures: { jsx: true } } - }, - { - code: ` - - Object() - `, - parserOptions: { ecmaFeatures: { jsx: true } } - }, { code: ` const foo = bar From db06a7ff7992a74368f03d1f21beb00df0407021 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 09:26:08 +0200 Subject: [PATCH 03/91] ci: bump actions/setup-node from 3 to 4 (#17676) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- .github/workflows/update-readme.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7bf368fdac75..c2ee74329c5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 'lts/*' - name: Install Packages @@ -54,7 +54,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - name: Install Packages @@ -69,7 +69,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '16' - name: Install Packages diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml index 43b783d3fcad..5e3fb97c48d3 100644 --- a/.github/workflows/update-readme.yml +++ b/.github/workflows/update-readme.yml @@ -14,7 +14,7 @@ jobs: token: ${{ secrets.WORKFLOW_PUSH_BOT_TOKEN }} - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 - name: Install npm packages run: npm install From 3aec1c55ba2c6d2833e1c0afe0a58f0cc6bbc0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Tue, 24 Oct 2023 11:31:34 -0400 Subject: [PATCH 04/91] docs: explained rule fixers and suggestions (#17657) * docs: explained report fixers and suggestions * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas * Post-suggestion fix: rule-categories.macro.html link --------- Co-authored-by: Nicholas C. Zakas --- .../components/rule-categories.macro.html | 2 +- docs/src/use/core-concepts.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/src/_includes/components/rule-categories.macro.html b/docs/src/_includes/components/rule-categories.macro.html index 193f6def64eb..f38d371049eb 100644 --- a/docs/src/_includes/components/rule-categories.macro.html +++ b/docs/src/_includes/components/rule-categories.macro.html @@ -21,7 +21,7 @@
💡 hasSuggestions

- Some problems reported by this rule are manually fixable by editor suggestions + Some problems reported by this rule are manually fixable by editor suggestions

{%- endif -%} diff --git a/docs/src/use/core-concepts.md b/docs/src/use/core-concepts.md index b9dfbbbfa1c0..b60ad3b0b0ed 100644 --- a/docs/src/use/core-concepts.md +++ b/docs/src/use/core-concepts.md @@ -23,6 +23,23 @@ ESLint contains hundreds of built-in rules that you can use. You can also create For more information, refer to [Rules](../rules/). +### Rule Fixes + +Rules may optionally provide fixes for violations that they find. Fixes safely correct the violation without changing application logic. + +Fixes may be applied automatically with the [`--fix` command line option](https://eslint.org/docs/latest/use/command-line-interface#--fix) and via editor extensions. + +Rules that may provide fixes are marked with 🔧 in [Rules](../rules/). + +### Rule Suggestions + +Rules may optionally provide suggestions in addition to or instead of providing fixes. Suggestions differ from fixes in two ways: + +1. Suggestions may change application logic and so cannot be automatically applied. +1. Suggestions cannot be applied through the ESLint CLI and are only available through editor integrations. + +Rules that may provide suggestions are marked with 💡 in [Rules](../rules/). + ## Configuration Files An ESLint configuration file is a place where you put the configuration for ESLint in your project. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more. From 8651895ca7ae15e13d74c8be67d9eebd63a7ce1f Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Thu, 26 Oct 2023 22:50:36 +0200 Subject: [PATCH 05/91] docs: Fix tabs in rule examples (#17653) * Different ways to handle tabs * Option to remove Playground links * use tabs with `markdownlint-disable` comments * add missing `eslint` comments * Apply review suggestions * Remove comments from `no-mixed-spaces-and-tabs` --- docs/src/rules/indent-legacy.md | 11 +++++--- docs/src/rules/indent.md | 11 +++++--- docs/src/rules/max-len.md | 19 +++++++++----- docs/src/rules/no-mixed-spaces-and-tabs.md | 30 +++++++++++----------- docs/src/rules/no-tabs.md | 20 +++++++++++---- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/docs/src/rules/indent-legacy.md b/docs/src/rules/indent-legacy.md index c3543133be4c..a8097b229324 100644 --- a/docs/src/rules/indent-legacy.md +++ b/docs/src/rules/indent-legacy.md @@ -140,20 +140,23 @@ function foo(d) { Examples of **correct** code for this rule with the `"tab"` option: + + ::: correct ```js /*eslint indent-legacy: ["error", "tab"]*/ if (a) { -/*tab*/b=c; -/*tab*/function foo(d) { -/*tab*//*tab*/e=f; -/*tab*/} + b=c; + function foo(d) { + e=f; + } } ``` ::: + ### SwitchCase diff --git a/docs/src/rules/indent.md b/docs/src/rules/indent.md index 72efad265683..ea700b240bb1 100644 --- a/docs/src/rules/indent.md +++ b/docs/src/rules/indent.md @@ -141,20 +141,23 @@ function foo(d) { Examples of **correct** code for this rule with the `"tab"` option: + + ::: correct ```js /*eslint indent: ["error", "tab"]*/ if (a) { -/*tab*/b=c; -/*tab*/function foo(d) { -/*tab*//*tab*/e=f; -/*tab*/} + b=c; + function foo(d) { + e=f; + } } ``` ::: + ### ignoredNodes diff --git a/docs/src/rules/max-len.md b/docs/src/rules/max-len.md index eabd3efc4c6c..fb3310269e37 100644 --- a/docs/src/rules/max-len.md +++ b/docs/src/rules/max-len.md @@ -69,30 +69,36 @@ var foo = { Examples of **incorrect** code for this rule with the default `{ "tabWidth": 4 }` option: + + ::: incorrect ```js /*eslint max-len: ["error", { "code": 80, "tabWidth": 4 }]*/ -\t \t var foo = { "bar": "This is a bar.", "baz": { "qux": "This is a qux" } }; + var foo = { "bar": "This is a bar.", "baz": { "qux": "This is a qux" } }; ``` ::: + Examples of **correct** code for this rule with the default `{ "tabWidth": 4 }` option: + + ::: correct ```js /*eslint max-len: ["error", { "code": 80, "tabWidth": 4 }]*/ -\t \t var foo = { -\t \t \t \t "bar": "This is a bar.", -\t \t \t \t "baz": { "qux": "This is a qux" } -\t \t }; + var foo = { + "bar": "This is a bar.", + "baz": { "qux": "This is a qux" } + }; ``` ::: + ### comments @@ -203,7 +209,8 @@ Examples of **correct** code for this rule with the `ignorePattern` option: ::: correct ```js -/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\\(" }]*/ +/*eslint max-len: +["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\\(" }]*/ var dep = require('really/really/really/really/really/really/really/really/long/module'); ``` diff --git a/docs/src/rules/no-mixed-spaces-and-tabs.md b/docs/src/rules/no-mixed-spaces-and-tabs.md index 29f82e2191f7..39c230b2dcaf 100644 --- a/docs/src/rules/no-mixed-spaces-and-tabs.md +++ b/docs/src/rules/no-mixed-spaces-and-tabs.md @@ -15,42 +15,42 @@ This rule disallows mixed spaces and tabs for indentation. Examples of **incorrect** code for this rule: + + ::: incorrect ```js /*eslint no-mixed-spaces-and-tabs: "error"*/ function add(x, y) { -// --->..return x + y; - - return x + y; + return x + y; } function main() { -// --->var x = 5, -// --->....y = 7; - - var x = 5, - y = 7; + var x = 5, + y = 7; } ``` ::: + Examples of **correct** code for this rule: + + ::: correct ```js /*eslint no-mixed-spaces-and-tabs: "error"*/ function add(x, y) { -// --->return x + y; - return x + y; + return x + y; } ``` ::: + ## Options @@ -62,18 +62,18 @@ This rule has a string option. Examples of **correct** code for this rule with the `"smart-tabs"` option: + + ::: correct ```js /*eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/ function main() { -// --->var x = 5, -// --->....y = 7; - - var x = 5, - y = 7; + var x = 5, + y = 7; } ``` ::: + diff --git a/docs/src/rules/no-tabs.md b/docs/src/rules/no-tabs.md index 316db6203f3d..c105b6a8193b 100644 --- a/docs/src/rules/no-tabs.md +++ b/docs/src/rules/no-tabs.md @@ -12,26 +12,33 @@ This rule looks for tabs anywhere inside a file: code, comments or anything else Examples of **incorrect** code for this rule: + + ::: incorrect ```js -var a \t= 2; +/* eslint no-tabs: "error" */ + +var a = 2; /** -* \t\t it's a test function +* it's a test function */ function test(){} -var x = 1; // \t test +var x = 1; // test ``` ::: + Examples of **correct** code for this rule: ::: correct ```js +/* eslint no-tabs: "error" */ + var a = 2; /** @@ -54,19 +61,22 @@ This rule has an optional object option with the following properties: Examples of **correct** code for this rule with the `allowIndentationTabs: true` option: + + ::: correct ```js /* eslint no-tabs: ["error", { allowIndentationTabs: true }] */ function test() { -\tdoSomething(); + doSomething(); } -\t// comment with leading indentation tab + // comment with leading indentation tab ``` ::: + ## When Not To Use It From 4164b2ceec89726b18ea0b0e34fab05735d55a09 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Fri, 27 Oct 2023 08:06:57 +0000 Subject: [PATCH 06/91] docs: Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c910134a6f41..5379c319491c 100644 --- a/README.md +++ b/README.md @@ -294,7 +294,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Chrome Frameworks Fund Automattic

Gold Sponsors

Salesforce Airbnb

Silver Sponsors

Liftoff American Express

Bronze Sponsors

-

ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

+

ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders

## Technology Sponsors From 1ad6257744d63281235fcc33288394b1d69b34ce Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 27 Oct 2023 13:36:58 +0200 Subject: [PATCH 07/91] fix: ensure that exit code for fatal errors is not overwritten (#17683) * fix: ensure that exit code for fatal errors is not overwritten * Add comments * update test --- bin/eslint.js | 26 +++++++++++++++++-- tests/bin/eslint.js | 18 +++++++++++++ tests/fixtures/bin/empty.js | 0 .../bin/eslint.config-promise-tick-throws.js | 22 ++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/bin/empty.js create mode 100644 tests/fixtures/bin/eslint.config-promise-tick-throws.js diff --git a/bin/eslint.js b/bin/eslint.js index 5c7972cc086e..eeb4647e70b1 100755 --- a/bin/eslint.js +++ b/bin/eslint.js @@ -97,9 +97,14 @@ function getErrorMessage(error) { * same message once. * @type {Set} */ - const displayedErrors = new Set(); +/** + * Tracks whether an unexpected error was caught + * @type {boolean} + */ +let hadFatalError = false; + /** * Catch and report unexpected error. * @param {any} error The thrown error object. @@ -107,6 +112,7 @@ const displayedErrors = new Set(); */ function onFatalError(error) { process.exitCode = 2; + hadFatalError = true; const { version } = require("../package.json"); const message = ` @@ -143,9 +149,25 @@ ${getErrorMessage(error)}`; } // Otherwise, call the CLI. - process.exitCode = await require("../lib/cli").execute( + const exitCode = await require("../lib/cli").execute( process.argv, process.argv.includes("--stdin") ? await readStdin() : null, true ); + + /* + * If an uncaught exception or unhandled rejection was detected in the meantime, + * keep the fatal exit code 2 that is already assigned to `process.exitCode`. + * Without this condition, exit code 2 (unsuccessful execution) could be overwritten with + * 1 (successful execution, lint problems found) or even 0 (successful execution, no lint problems found). + * This ensures that unexpected errors that seemingly don't affect the success + * of the execution will still cause a non-zero exit code, as it's a common + * practice and the default behavior of Node.js to exit with non-zero + * in case of an uncaught exception or unhandled rejection. + * + * Otherwise, assign the exit code returned from CLI. + */ + if (!hadFatalError) { + process.exitCode = exitCode; + } }()).catch(onFatalError); diff --git a/tests/bin/eslint.js b/tests/bin/eslint.js index dca8955d0386..430f7112e962 100644 --- a/tests/bin/eslint.js +++ b/tests/bin/eslint.js @@ -387,6 +387,24 @@ describe("bin/eslint.js", () => { return Promise.all([exitCodeAssertion, outputAssertion]); }); + it("does not exit with zero when there is an error in the next tick", () => { + const config = path.join(__dirname, "../fixtures/bin/eslint.config-promise-tick-throws.js"); + const file = path.join(__dirname, "../fixtures/bin/empty.js"); + const child = runESLint(["--config", config, file]); + const exitCodeAssertion = assertExitCode(child, 2); + const outputAssertion = getOutput(child).then(output => { + + // ensure the expected error was printed + assert.include(output.stderr, "test_error_stack"); + + // ensure that linting the file did not cause an error + assert.notInclude(output.stderr, "empty.js"); + assert.notInclude(output.stdout, "empty.js"); + }); + + return Promise.all([exitCodeAssertion, outputAssertion]); + }); + // https://github.com/eslint/eslint/issues/17560 describe("does not print duplicate errors in the event of a crash", () => { diff --git a/tests/fixtures/bin/empty.js b/tests/fixtures/bin/empty.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/fixtures/bin/eslint.config-promise-tick-throws.js b/tests/fixtures/bin/eslint.config-promise-tick-throws.js new file mode 100644 index 000000000000..6ea53d253863 --- /dev/null +++ b/tests/fixtures/bin/eslint.config-promise-tick-throws.js @@ -0,0 +1,22 @@ +function throwError() { + const error = new Error(); + error.stack = "test_error_stack"; + throw error; +} + +process.nextTick(throwError); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function getConfig() { + await delay(100); + return []; +} + +/* + * Exporting the config as an initially unsettled Promise should ensure that + * the error in next tick will be thrown before any linting is done + */ +module.exports = getConfig(); From 4fc44c0b8c5dca466bffdfe01dfd80794d7762b7 Mon Sep 17 00:00:00 2001 From: Tanuj Kanti <86398394+Tanujkanti4441@users.noreply.github.com> Date: Fri, 27 Oct 2023 20:30:34 +0530 Subject: [PATCH 08/91] docs: update twitter icon to new X icon (#17687) --- docs/src/_includes/components/social-icons.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/src/_includes/components/social-icons.html b/docs/src/_includes/components/social-icons.html index bb025af5b134..6f2b887e9490 100644 --- a/docs/src/_includes/components/social-icons.html +++ b/docs/src/_includes/components/social-icons.html @@ -3,11 +3,8 @@