A custom ESLint plugin that extends @angular-eslint/eslint-plugin@19.3.0
with additional fixes, and suggestions for Angular applications.
-
Enhanced Angular Rules: Custom rules built on top of
@angular-eslint
- Automatic Fixes: Many rules include automatic code fixes
- Smart Suggestions: Intelligent suggestions for code improvements
- TypeScript Support: Full TypeScript support with proper type checking
npm install eslint-plugin-custom-angular --save-dev
Add the plugin to your ESLint configuration:
// eslint.config.js
const eslint = require("@eslint/js");
const tseslint = require("typescript-eslint");
const custom = require("eslint-plugin-custom-angular");
module.exports = tseslint.config({
files: [ "**/*.ts" ],
plugins: { "custom-angular": custom },
extends: [ eslint.configs.recommended, ...tseslint.configs.recommended ],
rules: {
// Enable all rules
"custom-angular/component-max-inline-declarations": "error",
"custom-angular/no-duplicates-in-metadata-arrays": "error",
"custom-angular/relative-url-prefix": "error",
"custom-angular/sort-lifecycle-methods": "error"
}
});
Enforces a maximum number of lines in inline animations. Automatically extracts long inline declarations to separate variables. If reuse the array destructuring it into inline animations array will have suggestions.
Options:
-
animations
(number): Maximum lines allowed for animations (default: 15)
Example:
// ❌ Too many lines
@Component({
animations: [
trigger('dialogContainer', [
transition('* => void', query('@transformPanel', [animateChild()], {optional: true}))
]),
// ... more animations
]
})
// ✅ Automatically fixed to
const myAnimations: unknown[] = [
trigger('dialogContainer', [
transition('* => void', query('@transformPanel', [animateChild()], {optional: true}))
]),
// ... more animations
];
@Component({
animations: myAnimations
})
Ensures that metadata arrays do not contain duplicate entries. Automatically removes duplicates.
Example:
// ❌ Duplicate entries
@NgModule({
imports: [CommonModule, CommonModule, RouterModule],
declarations: [AppComponent, AppComponent]
})
// ✅ Automatically fixed to
@NgModule({
imports: [CommonModule, RouterModule],
declarations: [AppComponent]
})
Enforces the use of ./
and ../
prefixes for relative URLs in Angular components.
Example:
// ❌ Missing relative prefix
@Component({
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
// ✅ Automatically fixed to
@Component({
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
Ensures that lifecycle methods are declared in order of execution. Automatically reorders methods.
Example:
// ❌ Incorrect order
export class AppComponent {
ngOnInit() { }
constructor() { }
ngOnDestroy() { }
}
// ✅ Automatically fixed to
export class AppComponent {
constructor() { }
ngOnInit() { }
ngOnDestroy() { }
}
-
npm run build
- Build the plugin -
npm run tests
- Run all tests with coverage -
npm run serve-coverage
- Serve coverage report locally -
npm run deploy
- Build and publish to npm
Run tests for all rules:
npm run tests
[!warning] python3 is required
View coverage report:
npm run serve-coverage
Then open http://localhost:8000
in your browser.
- Built on top of @angular-eslint
- Inspired by Angular's official style guide
- Developed as part of a Final Degree Project (TFG)