From 5bf578935ccad043da106af3bbcc523f87c83dd5 Mon Sep 17 00:00:00 2001 From: Joe Hildebrand Date: Sat, 17 Feb 2024 06:20:10 -0700 Subject: [PATCH] Add no-unused-rule processing for imports --- lib/rules/no-unused-rules.js | 39 +++++++++++++++++++++ src/rules/no-unused-rules.ts | 44 ++++++++++++++++++++++++ test/rules/no-unused-rules.test.js | 55 ++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/lib/rules/no-unused-rules.js b/lib/rules/no-unused-rules.js index 25bd188..bca9b69 100644 --- a/lib/rules/no-unused-rules.js +++ b/lib/rules/no-unused-rules.js @@ -11,13 +11,36 @@ const rule = { }, messages: { unused: "Rule '{{ name }}' is never used.", + unusedImport: "Library import '{{ name }}' is never used.", }, schema: [], }, create(context) { + const imports = new Map(); const rules = new Map(); const refs = new Set(); + const importRefs = new Set(); return (0, utils_1.makeListener)({ + import_binding(node) { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_all(node) { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_default(node) { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_rename(node) { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, rule(node) { if (rules.size === 0) { // Default start rule counts as a reference. @@ -28,9 +51,13 @@ const rule = { rule_ref(node) { refs.add(node.name.value); }, + library_ref(node) { + importRefs.add(node.library.value); + }, "Program:exit": () => { for (const name of refs) { rules.delete(name); + imports.delete(name); } for (const [name, r] of rules) { context.report({ @@ -41,6 +68,18 @@ const rule = { }, }); } + for (const name of importRefs) { + imports.delete(name); + } + for (const [name, r] of imports) { + context.report({ + node: (0, utils_1.n)(r), + messageId: "unusedImport", + data: { + name, + }, + }); + } }, }); }, diff --git a/src/rules/no-unused-rules.ts b/src/rules/no-unused-rules.ts index f85a313..fa16e18 100644 --- a/src/rules/no-unused-rules.ts +++ b/src/rules/no-unused-rules.ts @@ -12,13 +12,41 @@ const rule: Rule.RuleModule = { }, messages: { unused: "Rule '{{ name }}' is never used.", + unusedImport: "Library import '{{ name }}' is never used.", }, schema: [], }, create(context: Rule.RuleContext): Rule.RuleListener { + const imports = new Map(); const rules = new Map(); const refs = new Set(); + const importRefs = new Set(); return makeListener({ + import_binding(node: visitor.AST.ImportBinding): void { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_all(node: visitor.AST.ImportBindingAll): void { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_default(node: visitor.AST.ImportBindingDefault): void { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, + import_binding_rename(node: visitor.AST.ImportBindingRename) { + if (node.binding.id) { + imports.set(node.binding.id.value, node); + } + }, rule(node: visitor.AST.Rule): void { if (rules.size === 0) { // Default start rule counts as a reference. @@ -29,9 +57,13 @@ const rule: Rule.RuleModule = { rule_ref(node: visitor.AST.RuleReferenceExpression): void { refs.add(node.name.value); }, + library_ref(node: visitor.AST.LibraryReferenceExpression): void { + importRefs.add(node.library.value); + }, "Program:exit": (): void => { for (const name of refs) { rules.delete(name); + imports.delete(name); } for (const [name, r] of rules) { context.report({ @@ -42,6 +74,18 @@ const rule: Rule.RuleModule = { }, }); } + for (const name of importRefs) { + imports.delete(name); + } + for (const [name, r] of imports) { + context.report({ + node: n(r), + messageId: "unusedImport", + data: { + name, + }, + }); + } }, }); }, diff --git a/test/rules/no-unused-rules.test.js b/test/rules/no-unused-rules.test.js index 75a582c..41a7026 100644 --- a/test/rules/no-unused-rules.test.js +++ b/test/rules/no-unused-rules.test.js @@ -15,11 +15,66 @@ foo = bar bar = "1" `, }, + { + code: ` +import * as bar from "bar" +foo = bar.foo`, + }, + { + code: ` +import bar from 'bar' +foo = bar`, + }, + { + code: ` +import {bar} from 'bar' +foo = bar`, + }, + { + code: ` +import {foo as bar} from 'bar' +foo = bar`, + }, + { + code: ` +import {"foo" as bar} from 'bar' +foo = bar`, + }, ], invalid: [ { code: "foo = '1'\nbar = '2'", errors: [{ messageId: "unused" }], }, + { + code: ` + import * as bar from "bar" + foo = bart.foo`, + errors: [{ messageId: "unusedImport" }], + }, + { + code: ` + import bar from "bar" + foo = "1"`, + errors: [{ messageId: "unusedImport" }], + }, + { + code: ` + import {bar} from "bar" + foo = "1"`, + errors: [{ messageId: "unusedImport" }], + }, + { + code: ` + import {foo as bar} from "bar" + foo = "1"`, + errors: [{ messageId: "unusedImport" }], + }, + { + code: ` + import {"foo" as bar} from "bar" + foo = "1"`, + errors: [{ messageId: "unusedImport" }], + }, ], });