diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md
index 9063affc6..803bffabd 100644
--- a/packages/eslint-plugin/README.md
+++ b/packages/eslint-plugin/README.md
@@ -70,7 +70,7 @@
| [`use-component-selector`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-component-selector.md) | Component selector must be declared | | | |
| [`use-component-view-encapsulation`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-component-view-encapsulation.md) | Disallows using `ViewEncapsulation.None` | | | :bulb: |
| [`use-injectable-provided-in`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-injectable-provided-in.md) | Using the `providedIn` property makes `Injectables` tree-shakable | | | :bulb: |
-| [`use-lifecycle-interface`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md) | Ensures that classes implement lifecycle interfaces corresponding to the declared lifecycle methods. See more at https://angular.io/styleguide#style-09-01 | | | |
+| [`use-lifecycle-interface`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md) | Ensures that classes implement lifecycle interfaces corresponding to the declared lifecycle methods. See more at https://angular.io/styleguide#style-09-01 | | :wrench: | |
| [`use-pipe-transform-interface`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-pipe-transform-interface.md) | Ensures that `Pipes` implement `PipeTransform` interface | :white_check_mark: | :wrench: | |
diff --git a/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md b/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md
index 819e205fd..c957f7250 100644
--- a/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md
+++ b/packages/eslint-plugin/docs/rules/use-lifecycle-interface.md
@@ -18,6 +18,7 @@
Ensures that classes implement lifecycle interfaces corresponding to the declared lifecycle methods. See more at https://angular.io/styleguide#style-09-01
- Type: suggestion
+- 🔧 Supports autofix (`--fix`)
diff --git a/packages/eslint-plugin/src/rules/use-lifecycle-interface.ts b/packages/eslint-plugin/src/rules/use-lifecycle-interface.ts
index 7b71b4215..27349449f 100644
--- a/packages/eslint-plugin/src/rules/use-lifecycle-interface.ts
+++ b/packages/eslint-plugin/src/rules/use-lifecycle-interface.ts
@@ -1,4 +1,9 @@
-import { ASTUtils, toPattern } from '@angular-eslint/utils';
+import {
+ ASTUtils,
+ toPattern,
+ RuleFixes,
+ isNotNullOrUndefined,
+} from '@angular-eslint/utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { createESLintRule } from '../utils/create-eslint-rule';
@@ -18,6 +23,7 @@ export default createESLintRule({
messages: {
useLifecycleInterface: `Lifecycle interface '{{interfaceName}}' should be implemented for method '{{methodName}}'. (${STYLE_GUIDE_LINK})`,
},
+ fixable: 'code',
},
defaultOptions: [],
create(context) {
@@ -50,6 +56,16 @@ export default createESLintRule({
node: key,
messageId: 'useLifecycleInterface',
data: { interfaceName, methodName },
+ fix: (fixer) => {
+ const { implementsNodeReplace, implementsTextReplace } =
+ RuleFixes.getImplementsSchemaFixer(parent, interfaceName);
+ return [
+ fixer.insertTextAfter(
+ implementsNodeReplace,
+ implementsTextReplace,
+ ),
+ ].filter(isNotNullOrUndefined);
+ },
});
},
};
diff --git a/packages/eslint-plugin/tests/rules/use-lifecycle-interface/cases.ts b/packages/eslint-plugin/tests/rules/use-lifecycle-interface/cases.ts
index 17c8b3ed9..8b5630d27 100644
--- a/packages/eslint-plugin/tests/rules/use-lifecycle-interface/cases.ts
+++ b/packages/eslint-plugin/tests/rules/use-lifecycle-interface/cases.ts
@@ -58,6 +58,14 @@ export const invalid = [
interfaceName: ASTUtils.AngularLifecycleInterfaces.OnInit,
methodName: ASTUtils.AngularLifecycleMethods.ngOnInit,
},
+ annotatedOutput: `
+ @Component()
+ class Test implements OnInit {
+ ngOnInit() {
+
+ }
+ }
+ `,
}),
convertAnnotatedSourceToFailureCase({
description:
@@ -77,6 +85,16 @@ export const invalid = [
interfaceName: ASTUtils.AngularLifecycleInterfaces.OnDestroy,
methodName: ASTUtils.AngularLifecycleMethods.ngOnDestroy,
},
+ annotatedOutput: `
+ @Directive()
+ class Test extends Component implements OnInit, OnDestroy {
+ ngOnInit() {}
+
+ ngOnDestroy() {
+
+ }
+ }
+ `,
}),
convertAnnotatedSourceToFailureCase({
description:
@@ -120,6 +138,19 @@ export const invalid = [
},
},
],
+ annotatedOutput: `
+ @Injectable()
+ class Test implements DoBootstrap {
+ ngDoBootstrap() {}
+
+
+ ngOnInit() {}
+
+
+ ngOnDestroy() {}
+
+ }
+ `,
}),
convertAnnotatedSourceToFailureCase({
description:
@@ -139,5 +170,15 @@ export const invalid = [
interfaceName: ASTUtils.AngularLifecycleInterfaces.OnDestroy,
methodName: ASTUtils.AngularLifecycleMethods.ngOnDestroy,
},
+ annotatedOutput: `
+ @NgModule()
+ class Test extends Component implements ng.OnInit, OnDestroy {
+ ngOnInit() {}
+
+ ngOnDestroy() {
+
+ }
+ }
+ `,
}),
];