From 1c173dc1f3d36a28cb2543e93675c2fbdb6fa9f1 Mon Sep 17 00:00:00 2001 From: Tanuj Kanti <86398394+Tanujkanti4441@users.noreply.github.com> Date: Thu, 7 Mar 2024 18:05:22 +0530 Subject: [PATCH] feat: add `ignoreClassWithStaticInitBlock` option to `no-unused-vars` (#18170) * feat: add option to ignore SIB-classes * add docs and tests * add test * update docs --- docs/src/rules/no-unused-vars.md | 45 ++++++++++++++++++++++++++ lib/rules/no-unused-vars.js | 15 ++++++++- tests/lib/rules/no-unused-vars.js | 54 +++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/docs/src/rules/no-unused-vars.md b/docs/src/rules/no-unused-vars.md index d924f02d657..cc361e955e4 100644 --- a/docs/src/rules/no-unused-vars.md +++ b/docs/src/rules/no-unused-vars.md @@ -410,6 +410,51 @@ var bar; ::: +### ignoreClassWithStaticInitBlock + +The `ignoreClassWithStaticInitBlock` option is a boolean (default: `false`). Static initialization blocks allow you to initialize static variables and execute code during the evaluation of a class definition, meaning the static block code is executed without creating a new instance of the class. When set to `true`, this option ignores classes containing static initialization blocks. + +Examples of **incorrect** code for the `{ "ignoreClassWithStaticInitBlock": true }` option + +::: incorrect + +```js +/*eslint no-unused-vars: ["error", { "ignoreClassWithStaticInitBlock": true }]*/ + +class Foo { + static myProperty = "some string"; + static mymethod() { + return "some string"; + } +} + +class Bar { + static { + let baz; // unused variable + } +} +``` + +::: + +Examples of **correct** code for the `{ "ignoreClassWithStaticInitBlock": true }` option + +::: correct + +```js +/*eslint no-unused-vars: ["error", { "ignoreClassWithStaticInitBlock": true }]*/ + +class Foo { + static { + let bar = "some string"; + + console.log(bar); + } +} +``` + +::: + ## When Not To Use It If you don't want to be notified about unused variables or function arguments, you can safely turn this rule off. diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 74a664089ed..90b76e6f2d1 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -70,6 +70,9 @@ module.exports = { }, destructuredArrayIgnorePattern: { type: "string" + }, + ignoreClassWithStaticInitBlock: { + type: "boolean" } }, additionalProperties: false @@ -92,7 +95,8 @@ module.exports = { vars: "all", args: "after-used", ignoreRestSiblings: false, - caughtErrors: "all" + caughtErrors: "all", + ignoreClassWithStaticInitBlock: false }; const firstOption = context.options[0]; @@ -105,6 +109,7 @@ module.exports = { config.args = firstOption.args || config.args; config.ignoreRestSiblings = firstOption.ignoreRestSiblings || config.ignoreRestSiblings; config.caughtErrors = firstOption.caughtErrors || config.caughtErrors; + config.ignoreClassWithStaticInitBlock = firstOption.ignoreClassWithStaticInitBlock || config.ignoreClassWithStaticInitBlock; if (firstOption.varsIgnorePattern) { config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern, "u"); @@ -613,6 +618,14 @@ module.exports = { continue; } + if (type === "ClassName") { + const hasStaticBlock = def.node.body.body.some(node => node.type === "StaticBlock"); + + if (config.ignoreClassWithStaticInitBlock && hasStaticBlock) { + continue; + } + } + // skip catch variables if (type === "CatchClause") { if (config.caughtErrors === "none") { diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index 0d8e7c33b89..de85050248f 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -445,6 +445,23 @@ ruleTester.run("no-unused-vars", rule, { { code: "var a; a ??= 1;", languageOptions: { ecmaVersion: 2021 } + }, + + // ignore class with static initialization block https://github.com/eslint/eslint/issues/17772 + { + code: "class Foo { static {} }", + options: [{ ignoreClassWithStaticInitBlock: true }], + languageOptions: { ecmaVersion: 2022 } + }, + { + code: "class Foo { static {} }", + options: [{ ignoreClassWithStaticInitBlock: true, varsIgnorePattern: "^_" }], + languageOptions: { ecmaVersion: 2022 } + }, + { + code: "class Foo { static {} }", + options: [{ ignoreClassWithStaticInitBlock: false, varsIgnorePattern: "^Foo" }], + languageOptions: { ecmaVersion: 2022 } } ], invalid: [ @@ -1557,6 +1574,43 @@ function foo1() { c = foo1`, languageOptions: { ecmaVersion: 2020 }, errors: [{ ...assignedError("c"), line: 10, column: 1 }] + }, + + // ignore class with static initialization block https://github.com/eslint/eslint/issues/17772 + { + code: "class Foo { static {} }", + options: [{ ignoreClassWithStaticInitBlock: false }], + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + }, + { + code: "class Foo { static {} }", + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + }, + { + code: "class Foo { static { var bar; } }", + options: [{ ignoreClassWithStaticInitBlock: true }], + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("bar"), line: 1, column: 26 }] + }, + { + code: "class Foo {}", + options: [{ ignoreClassWithStaticInitBlock: true }], + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + }, + { + code: "class Foo { static bar; }", + options: [{ ignoreClassWithStaticInitBlock: true }], + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + }, + { + code: "class Foo { static bar() {} }", + options: [{ ignoreClassWithStaticInitBlock: true }], + languageOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError("Foo"), line: 1, column: 7 }] } ] });