From 7a8ca357533c559d5eaab8a63ab2e702db0c4be5 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Tue, 11 Jun 2024 12:06:19 +0930 Subject: [PATCH] feat(eslint-plugin): [no-unused-vars] support `ignoreClassWithStaticInitBlock` --- .../eslint-plugin/src/rules/no-unused-vars.ts | 19 ++++ .../no-unused-vars-eslint.test.ts | 92 +++++++++++++++++++ .../schema-snapshots/no-unused-vars.shot | 4 + 3 files changed, 115 insertions(+) diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index cf1c6378a39f..f2a6f972408a 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -29,6 +29,7 @@ export type Options = [ caughtErrors?: 'all' | 'none'; caughtErrorsIgnorePattern?: string; destructuredArrayIgnorePattern?: string; + ignoreClassWithStaticInitBlock?: boolean; reportUsedIgnorePattern?: boolean; }, ]; @@ -42,6 +43,7 @@ interface TranslatedOptions { caughtErrors: 'all' | 'none'; caughtErrorsIgnorePattern?: RegExp; destructuredArrayIgnorePattern?: RegExp; + ignoreClassWithStaticInitBlock: boolean; reportUsedIgnorePattern: boolean; } @@ -97,6 +99,9 @@ export default createRule({ destructuredArrayIgnorePattern: { type: 'string', }, + ignoreClassWithStaticInitBlock: { + type: 'boolean', + }, reportUsedIgnorePattern: { type: 'boolean', }, @@ -122,6 +127,7 @@ export default createRule({ args: 'after-used', ignoreRestSiblings: false, caughtErrors: 'all', + ignoreClassWithStaticInitBlock: false, reportUsedIgnorePattern: false, }; @@ -133,6 +139,9 @@ export default createRule({ options.ignoreRestSiblings = firstOption.ignoreRestSiblings ?? options.ignoreRestSiblings; options.caughtErrors = firstOption.caughtErrors ?? options.caughtErrors; + options.ignoreClassWithStaticInitBlock = + firstOption.ignoreClassWithStaticInitBlock ?? + options.ignoreClassWithStaticInitBlock; options.reportUsedIgnorePattern = firstOption.reportUsedIgnorePattern ?? options.reportUsedIgnorePattern; @@ -423,6 +432,16 @@ export default createRule({ continue; } + if (def.type === TSESLint.Scope.DefinitionType.ClassName) { + const hasStaticBlock = def.node.body.body.some( + node => node.type === AST_NODE_TYPES.StaticBlock, + ); + + if (options.ignoreClassWithStaticInitBlock && hasStaticBlock) { + continue; + } + } + // skip catch variables if (def.type === TSESLint.Scope.DefinitionType.CatchClause) { if (options.caughtErrors === 'none') { diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts index 9d2866a079d8..1b6e27d606be 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts @@ -1261,6 +1261,39 @@ console.log(a + c); ], parserOptions: { ecmaVersion: 6 }, }, + + // ignore class with static initialization block https://github.com/eslint/eslint/issues/17772 + { + code: ` +class Foo { + static {} +} + `, + options: [{ ignoreClassWithStaticInitBlock: true }], + parserOptions: { ecmaVersion: 2022 }, + }, + { + code: ` +class Foo { + static {} +} + `, + options: [ + { ignoreClassWithStaticInitBlock: true, varsIgnorePattern: '^_' }, + ], + parserOptions: { ecmaVersion: 2022 }, + }, + { + code: ` +class Foo { + static {} +} + `, + options: [ + { ignoreClassWithStaticInitBlock: false, varsIgnorePattern: '^Foo' }, + ], + parserOptions: { ecmaVersion: 2022 }, + }, ], invalid: [ { @@ -2965,5 +2998,64 @@ try { ], errors: [usedIgnoredError('_err', '. Used args must not match /^_/u')], }, + + // ignore class with static initialization block https://github.com/eslint/eslint/issues/17772 + { + code: ` +class Foo { + static {} +} + `, + options: [{ ignoreClassWithStaticInitBlock: false }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('Foo'), line: 2, column: 7 }], + }, + { + code: ` +class Foo { + static {} +} + `, + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('Foo'), line: 2, column: 7 }], + }, + { + code: ` +class Foo { + static { + var bar; + } +} + `, + options: [{ ignoreClassWithStaticInitBlock: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('bar'), line: 4, column: 9 }], + }, + { + code: 'class Foo {}', + options: [{ ignoreClassWithStaticInitBlock: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('Foo'), line: 1, column: 7 }], + }, + { + code: ` +class Foo { + static bar; +} + `, + options: [{ ignoreClassWithStaticInitBlock: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('Foo'), line: 2, column: 7 }], + }, + { + code: ` +class Foo { + static bar() {} +} + `, + options: [{ ignoreClassWithStaticInitBlock: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ ...definedError('Foo'), line: 2, column: 7 }], + }, ], }); diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot b/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot index 7717d324d3db..f7a81d300694 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot @@ -31,6 +31,9 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "destructuredArrayIgnorePattern": { "type": "string" }, + "ignoreClassWithStaticInitBlock": { + "type": "boolean" + }, "ignoreRestSiblings": { "type": "boolean" }, @@ -63,6 +66,7 @@ type Options = [ caughtErrors?: 'all' | 'none'; caughtErrorsIgnorePattern?: string; destructuredArrayIgnorePattern?: string; + ignoreClassWithStaticInitBlock?: boolean; ignoreRestSiblings?: boolean; reportUsedIgnorePattern?: boolean; vars?: 'all' | 'local';