ESLint plugin that identifies and automatically removes unused ES6 module imports
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
ESLint Plugin Unused Imports identifies and automatically removes unused ES6 module imports from JavaScript and TypeScript codebases. It extends the standard no-unused-vars rule to specifically handle import statements in the Abstract Syntax Tree (AST), providing autofix capabilities to clean up unnecessary imports.
npm install eslint-plugin-unused-imports --save-devimport unusedImports from "eslint-plugin-unused-imports";For CommonJS:
const unusedImports = require("eslint-plugin-unused-imports");import unusedImports from "eslint-plugin-unused-imports";
export default [{
plugins: {
"unused-imports": unusedImports,
},
rules: {
"no-unused-vars": "off", // or "@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_",
},
]
}
}];The plugin uses a composable architecture built around several key components:
Main ESLint plugin export containing the two rules.
interface ESLintPlugin {
meta: {
name: string;
};
rules: {
"no-unused-vars": Rule.RuleModule;
"no-unused-imports": Rule.RuleModule;
};
}
const plugin: ESLintPlugin;
export default plugin;Detects and autofixes unused import statements with comprehensive autofix support.
/**
* ESLint rule that identifies unused import statements and provides autofix
* Handles various import scenarios including single imports, multiple imports,
* default + named combinations, and proper formatting preservation
*/
const noUnusedImportsRule: Rule.RuleModule;Rule Configuration:
"unused-imports/no-unused-imports": "error" to enable with autofixAutofix Examples:
// Single unused import - entire statement removed
import { unused } from 'module'; // ❌ Removed completely
// Multiple imports with some unused - only unused ones removed
import { used, unused1, unused2 } from 'module';
// ⬇️ Becomes:
import { used } from 'module';
// Default + named imports with unused named import
import React, { useState, unused } from 'react';
// ⬇️ Becomes:
import React, { useState } from 'react';
// All imports unused - entire statement removed with proper newline handling
import { unused1, unused2 } from 'module';
console.log('next line');
// ⬇️ Becomes:
console.log('next line'); // Proper spacing preservedEnhanced version of standard no-unused-vars rule that excludes imports to prevent duplicate reporting.
/**
* Enhanced no-unused-vars rule that filters out import-related problems
* Prevents duplicate reporting when used with no-unused-imports rule
* Supports all standard no-unused-vars configuration options
*/
const noUnusedVarsRule: Rule.RuleModule;Core system for creating filtered rules with predicate-based problem filtering.
/**
* Predicate function type for filtering rule problems
* Returns the problem to report or false to suppress it
*/
type Predicate = (
problem: Rule.ReportDescriptor,
context: Rule.RuleContext,
) => Rule.ReportDescriptor | false;
/**
* Creates a new rule by applying a predicate filter to a base rule
* Used to create both no-unused-imports and no-unused-vars rules
*/
function createRuleWithPredicate(
name: string,
baseRule: Rule.RuleModule,
predicate: Predicate,
): Rule.RuleModule;
/**
* Predicate that filters for unused import statements (includes autofix)
*/
const unusedImportsPredicate: Predicate;
/**
* Predicate that filters out import statements (excludes imports)
*/
const unusedVarsPredicate: Predicate;Predicate System Example:
// How predicates filter problems from the base no-unused-vars rule
const problem = {
node: someASTNode,
message: "someVariable is defined but never used",
// ... other problem properties
};
// unusedImportsPredicate: Returns problem ONLY if it's an import
// - Checks if problem.node.parent matches /^Import(|Default|Namespace)Specifier$/
// - If import: adds autofix logic and returns enhanced problem
// - If not import: returns false (suppresses the problem)
// unusedVarsPredicate: Returns problem ONLY if it's NOT an import
// - Checks if problem.node.parent matches /^Import(|Default|Namespace)Specifier$/
// - If import: returns false (suppresses the problem)
// - If not import: returns problem unchangedDynamic rule loading system that selects the appropriate no-unused-vars implementation.
/**
* Gets the appropriate base no-unused-vars rule using fallback strategy:
* 1. @typescript-eslint/eslint-plugin (if available)
* 2. typescript-eslint unified plugin (if available)
* 3. ESLint core no-unused-vars rule (fallback)
*/
function getBaseRule(): Rule.RuleModule;
/**
* Attempts to load no-unused-vars from @typescript-eslint/eslint-plugin
* Returns null if package is not available
*/
function getRuleFromTSLintPlugin(): Rule.RuleModule | null;
/**
* Attempts to load no-unused-vars from typescript-eslint unified package
* Returns null if package is not available
*/
function getRuleFromTSLint(): Rule.RuleModule | null;
/**
* Loads the core ESLint no-unused-vars rule as fallback
* Always succeeds as ESLint is a required dependency
*/
function getESLintBaseRule(): Rule.RuleModule;Rule Configuration: Standard ESLint no-unused-vars options:
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all" | "local",
"varsIgnorePattern": string, // regex pattern
"args": "after-used" | "all" | "none",
"argsIgnorePattern": string, // regex pattern
"caughtErrors": "none" | "all",
"caughtErrorsIgnorePattern": string, // regex pattern
"destructuredArrayIgnorePattern": string, // regex pattern
"ignoreRestSiblings": boolean
}
]/**
* ESLint Rule Module interface for both plugin rules
*/
interface Rule.RuleModule {
meta: {
type?: "problem" | "suggestion" | "layout";
docs?: {
description?: string;
category?: string;
recommended?: boolean;
url?: string;
};
fixable?: "code" | "whitespace";
schema: any[];
messages: Record<string, string>;
};
create(context: Rule.RuleContext): Rule.RuleListener;
}
/**
* ESLint Rule Context provided to rule implementations
*/
interface Rule.RuleContext {
id: string;
options: any[];
settings: any;
parserPath: string;
parserOptions: any;
sourceCode: SourceCode;
report(descriptor: Rule.ReportDescriptor): void;
}
/**
* ESLint Report Descriptor for rule violations
*/
interface Rule.ReportDescriptor {
node?: any;
loc?: any;
message: string;
data?: any;
fix?: (fixer: Rule.RuleFixer) => Rule.Fix | Rule.Fix[];
}Peer Dependencies:
eslint: ^8.0.0 || ^9.0.0@typescript-eslint/eslint-plugin: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 (optional)Version Compatibility:
Framework Integration:
eslint-plugin-react with react/jsx-uses-react and react/jsx-uses-vars rules enabled@typescript-eslint/eslint-plugin and @typescript-eslint/parser for TypeScript projects