ai-linter
v1.0.6
Published
A linter tool to analyze JavaScript, TypeScript, and Vue code, with a focus on AI-generated code, unused imports, alias resolution, and potential hazards.
Downloads
41
Maintainers
Readme
Advanced Linter for AI-Generated Code
ai-linter is a powerful static analysis tool designed specifically to validate and enhance JavaScript, TypeScript, and Vue code, particularly code generated by AI. It helps ensure code quality, maintainability, and security by identifying potential issues, unused code, and inconsistencies.
Key Features
- AI-Generated Code Validation: Tailored to scrutinize code produced by AI tools, catching common pitfalls and ensuring adherence to best practices.
- Unused Import Detection & Cleaning: Identifies and helps remove unused import statements, keeping your codebase clean and optimized.
- Alias Resolution Verification: Checks and resolves path aliases (e.g.,
@/components,~/utils) defined injsconfig.json,tsconfig.json, Babel, Webpack, Vite, or Next.js configurations, ensuring imports are correctly mapped. - Potential Hazard Detection: Flags potentially problematic code constructs such as:
eval()usageconsole.logand otherconsolemethod callsdebuggerstatementsTODOandFIXMEcomments, prompting for review and action.
- Import Syntax Error Identification: Detects and reports errors in import statements, including unresolved modules and incorrect named/default imports.
- Export Validation: Verifies named exports and re-exports, ensuring that what's imported is actually available from the source module.
- Undeclared Identifier Detection: Finds variables or functions used without prior declaration.
- Support for Multiple File Types: Analyzes
.js,.jsx,.ts,.tsx, and.vuefiles. - Configurable Analysis: Use a
.analyzerconfig.jsonfile or command-line options to customize target directories/files, ignored patterns, output format, and more.
Why ai-linter?
As AI-assisted development becomes more prevalent, ensuring the quality and reliability of generated code is crucial. ai-linter provides a focused solution to:
- Improve Code Quality: By catching errors and bad practices early.
- Enhance Maintainability: By promoting cleaner, more understandable code.
- Reduce Bundle Sizes: By helping eliminate unused code.
- Streamline Code Reviews: By automating the detection of common issues.
Getting Started
Prerequisites
- Node.js (version 14 or higher recommended)
Installation
Currently, ai-linter can be run directly from its source or integrated as a module.
# Clone the repository (if you haven't already)
git clone <repository-url>
cd ai-linter
# Install dependencies
yarn install # or npm installUsage
ai-linter offers two primary ways to use its analysis capabilities:
1. Command Line Interface (CLI)
For quick analysis and integration into build scripts, the CLI is the recommended approach. After installation, you might need to make index.js executable or call it via node.
If you've set up the bin field in package.json and installed the package globally or linked it (npm link), you can run:
ai-linter <file|directory> [options]Otherwise, run from the project root:
node index.js <file|directory> [options]Examples:
Analyze all supported files in the
srcdirectory:node index.js src/Analyze a specific file:
node index.js src/components/MyComponent.vueAnalyze the current directory, output results in JSON format to
report.json:node index.js . --format json --output report.jsonAnalyze
srcbut ignore test files:node index.js src --ignore "**/*.test.js,**/*.spec.js"
Options:
--recursive,-r: Scan subdirectories (default: true, configurable via.analyzerconfig.json).--extensions,-e: File extensions to analyze (default:.js,.jsx,.ts,.tsx,.vue, configurable).--ignore,-i: Glob patterns to ignore (configurable).--format,-f: Output format (json|table|summary) (default:table, configurable).--output,-o: File to write output to (configurable).--help,-h: Display help message.
2. Programmatic Usage (Analyzer Module)
For more complex integrations or custom analysis workflows, you can use the Analyzer module directly in your Node.js projects.
The Analyzer constructor accepts an optional cwd (current working directory) parameter. If not provided, it defaults to process.cwd(). This cwd is used as the base for resolving relative paths for configuration files (like jsconfig.json, babel.config.js), analysis target files/directories, and path aliases.
const { Analyzer } = require('ai-linter'); // Or adjust path if used locally
// Example 1: Default behavior (uses process.cwd())
const analyzer1 = new Analyzer();
// Analyzes './src/someFile.js' relative to process.cwd()
const report1 = analyzer1.analyzeFile('./src/someFile.js');
console.log(JSON.stringify(report1, null, 2));
// Example 2: Specifying a custom current working directory
const projectRoot = '/path/to/your/project'; // Replace with actual path
const analyzer2 = new Analyzer(projectRoot);
// Analyze a single file relative to 'projectRoot'
// e.g., resolves to '/path/to/your/project/src/components/MyComponent.js'
const fileReport = analyzer2.analyzeFile('./src/components/MyComponent.js');
console.log(JSON.stringify(fileReport, null, 2));
/* Example fileReport output:
{
"file": "/path/to/your/project/src/components/MyComponent.js",
"status": "ok", // or "error", "warning"
"syntaxError": null, // or { message: "...", line: X, column: Y }
"imports": [
{
"path": "react",
"specifiers": [{ "name": "default", "alias": "React", "type": "ImportDefaultSpecifier" }],
"line": 1,
"resolvedPath": "react", // Path to the module in node_modules or core module name
"status": "resolved",
"isExternal": true
}
],
"dynamicImports": [],
"exports": [
{ "type": "default", "line": 5 }
],
"unusedImports": [], // e.g., ["unusedIdentifier"]
"issues": [] // e.g., [{ "type": "console-usage", "message": "Usage of 'console.log'.", "line": 10 }]
}
*/
// Analyze a directory relative to 'projectRoot'
// e.g., analyzes files within '/path/to/your/project/src'
const directoryReport = analyzer2.analyzeDirectory('./src', {
recursive: true,
extensions: ['.js', '.ts'],
ignore: ['node_modules/**'] // Paths in ignore are also relative to the analyzer's cwd or absolute
});
console.log(JSON.stringify(directoryReport, null, 2));
/* Example directoryReport output:
{
"totalFiles": 5,
"filesWithErrors": 1,
"filesWithWarnings": 0,
"totalImports": 12,
"unresolvedImports": 1,
"unusedImports": 2,
"totalUndeclaredIdentifiers": 0,
"details": [
// Array of fileReport objects, one for each analyzed file
{
"file": "/path/to/your/project/src/file1.js",
"status": "ok",
// ... other properties as in fileReport ...
},
{
"file": "/path/to/your/project/src/fileWithError.js",
"status": "error",
"syntaxError": { "message": "Unexpected token", "line": 3, "column": 10 },
// ... other properties ...
}
// ... more file reports ...
]
}
*/This approach gives you direct access to the analysis results as JavaScript objects, allowing for deeper integration with other tools or custom reporting mechanisms.
Configuration File
You can configure ai-linter using a .analyzerconfig.json file in your project root (or the current working directory from which the tool is run):
{
"target": "src",
"recursive": true,
"extensions": [".js", ".jsx", ".ts", ".tsx", ".vue"],
"ignore": [
"node_modules/**",
"dist/**",
"**/*.test.js"
],
"format": "summary",
"output": "analysis-report.txt"
}Command-line arguments will override settings in the configuration file when using the CLI. The target and output paths in the configuration file are resolved relative to the location of the configuration file itself (which is typically the project root or cwd).
How It Works
ai-linter parses your code into an Abstract Syntax Tree (AST) using Babel parser. It then traverses this tree to:
- Identify Imports & Exports: Collects all import and export statements.
- Resolve Aliases: Uses configurations from common tools (
jsconfig.json,tsconfig.json, Webpack, Vite, etc.)—searched relative to the current working directory (or thecwdprovided to theAnalyzerinstance)—to map aliased paths to their actual file locations. - Validate Imports: Checks if imported modules exist and if named/default imports are correctly specified based on the exports of the source file.
- Detect Unused Imports: Compares imported identifiers against their usage within the file.
- Scan for Code Issues: Looks for patterns like
eval(),console.*,debugger,TODO/FIXMEcomments, undeclared variables, and duplicate object keys.
Detected Issue Types and Examples
ai-linter can detect a variety of issues in your codebase. Here's a list of common issue types, their meanings, and examples of code that would trigger them.
Import/Export Issues
unresolved-import- Description: The linter could not find or resolve the module specified in an import statement.
- Example:
import something from './non-existent-module';
error-in-imported-file- Description: An imported file contains a syntax error, preventing it from being parsed.
- Example:
// main.js import config from './broken-config'; // broken-config.js export default { setting: true // Missing semicolon or comma, causing syntax error }
unresolved-named-import- Description: A named import (e.g.,
import { specificThing } from 'module';) could not be found among the exports of the target module. - Example:
// utils.js export const helper = () => {}; // main.js import { nonExistentHelper } from './utils'; // 'nonExistentHelper' is not exported
- Description: A named import (e.g.,
unresolved-default-import- Description: A default import (e.g.,
import myModule from 'module';) was used, but the target module does not have a default export. - Example:
// config.js export const setting = true; // No default export // main.js import appConfig from './config'; // './config' has no default export
- Description: A default import (e.g.,
unresolved-dynamic-import- Description: The linter could not find or resolve the module specified in a dynamic
import()call. - Example:
async function loadFeature() { const feature = await import('./non-existent-feature'); // ... }
- Description: The linter could not find or resolve the module specified in a dynamic
unresolved-re-export-source- Description: The source module specified in a re-export statement (e.g.,
export { name } from './source';) could not be found. - Example:
// index.js export { utility } from './missing-utils'; // './missing-utils' does not exist
- Description: The source module specified in a re-export statement (e.g.,
error-in-re-exported-file- Description: A file being re-exported from contains a syntax error.
- Example:
// index.js export { configValue } from './broken-module'; // broken-module.js export const configValue = "test" // Syntax error here
missing-re-exported-name- Description: A named entity being re-exported (e.g.,
export { specificName } from './source';) is not actually exported by the source module. - Example:
// source.js export const oneThing = 1; // index.js export { anotherThing } from './source'; // 'anotherThing' is not in 'source.js'
- Description: A named entity being re-exported (e.g.,
unresolved-re-export-all-source- Description: The source module in an
export * from './source';statement could not be found. - Example:
// aggregator.js export * from './non-existent-lib';
- Description: The source module in an
error-in-re-exported-all-source- Description: The source module in an
export * from './source';statement contains a syntax error. - Example:
// aggregator.js export * from './faulty-lib'; // faulty-lib.js export const item = 1 // Syntax error
- Description: The source module in an
unused-imports- Description: An imported module or identifier is not used anywhere in the file.
- Example:
import { usefulFunction, unusedFunction } from './lib'; usefulFunction(); // 'unusedFunction' is imported but not called or referenced
Code Quality & Potential Hazards
eval-usage- Description: Use of the
eval()function, which can be a security risk and hinder performance. - Example:
const result = eval('1 + 1');
- Description: Use of the
console-usage- Description: Presence of
console.log(),console.warn(), etc., which are often left over from debugging. - Example:
function myFunc(data) { console.log('Debugging data:', data); return data; }
- Description: Presence of
debugger-statement- Description: A
debugger;statement found, which can halt execution if developer tools are open. - Example:
if (criticalCondition) { debugger; // Pauses execution here }
- Description: A
duplicate-object-key- Description: An object literal contains duplicate keys, where later keys will overwrite earlier ones.
- Example:
const config = { url: 'http://example.com', timeout: 5000, url: 'http://test.com' // 'url' key is duplicated };
Variable & Identifier Issues
undeclared-identifier- Description: A variable or function is used without being declared in the current scope or imported.
- Example:
function process() { const result = myUndeclaredVariable * 10; // 'myUndeclaredVariable' is not defined return result; }
undeclared-jsx-component- Description: A JSX component (typically starting with an uppercase letter) is used without being declared or imported.
- Example:
// MyComponent.jsx (assuming MyButton is not imported or defined) function MyComponent() { return <MyButton label="Click Me" />; }
File System Issues
file-not-found(when analyzing a single file directly or an import resolves to a non-existent file)- Description: The target file specified for analysis or an imported file path does not exist.
- Example (CLI):
ai-linter ./path/to/non-existent-file.js - Example (Import):
import settings from './missing-settings'; // if './missing-settings.js' doesn't exist
Comment-Based Issues
todo-comment- Description: A
// TODO:or/* TODO: */comment is found, indicating pending work. - Example:
// TODO: Refactor this function for better performance function oldFunction() { /* ... */ }
- Description: A
fixme-comment- Description: A
// FIXME:or/* FIXME: */comment is found, indicating a known bug or issue that needs fixing. - Example:
// FIXME: This calculation is sometimes incorrect under X condition const value = complexCalculation();
- Description: A
Contributing
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
License
This project is open-source and available under the MIT License.
