1- import { Rule } from "eslint" ;
1+ import {
2+ CallExpression ,
3+ ClassDeclaration ,
4+ Decorator ,
5+ MethodDefinition ,
6+ ObjectExpression ,
7+ Property ,
8+ } from "@typescript-eslint/types/dist/generated/ast-spec" ;
9+ import { ESLintUtils } from "@typescript-eslint/utils" ;
10+ import { repositoryUrl } from "../utils" ;
211
3- const rule : Rule . RuleModule = {
4- create : context => {
12+ export const ruleName = "destroy-service-provider" ;
13+
14+ type MessageIds = "missing" ;
15+
16+ type Options = [
17+ {
18+ /**
19+ * @default DestroyService
20+ */
21+ destroyServiceName ?: string ;
22+ } ,
23+ ] ;
24+
25+ const createRule = ESLintUtils . RuleCreator ( name => `${ repositoryUrl } #${ name } ` ) ;
26+
27+ export const rule = createRule < Options , MessageIds > ( {
28+ create ( context , [ options ] ) {
529 return {
630 "ClassDeclaration > Decorator[expression.callee.name=/^(Component|Directive)$/]" :
7- ( node : any ) => {
31+ ( node : Decorator ) => {
32+ const nodeExpression = node . expression as CallExpression ;
833 const isDecoratorEmpty =
9- ! node . expression . arguments . length ||
10- ! node . expression . arguments [ 0 ] . properties . length ;
34+ ! nodeExpression . arguments . length ||
35+ ! ( nodeExpression . arguments [ 0 ] as ObjectExpression ) . properties
36+ . length ;
1137
1238 if ( isDecoratorEmpty ) {
1339 return ;
1440 }
1541
1642 // whether component has providers decorator property
17- const providersProperty =
18- node . expression . arguments [ 0 ] . properties . find ( ( property : any ) => {
19- return (
20- property . key . type === "Identifier" &&
21- property . key . name === "providers"
22- ) ;
23- } ) ;
43+ const providersProperty = (
44+ nodeExpression . arguments [ 0 ] as ObjectExpression
45+ ) . properties . find ( ( property : any ) => {
46+ return (
47+ property . key . type === "Identifier" &&
48+ property . key . name === "providers"
49+ ) ;
50+ } ) as Property ;
2451
2552 let providerValuesHasDestroyService : boolean = false ;
2653
@@ -31,7 +58,10 @@ const rule: Rule.RuleModule = {
3158 ) {
3259 providerValuesHasDestroyService =
3360 ! ! providersProperty . value . elements . find ( ( e : any ) => {
34- return e . type === "Identifier" && e . name === "DestroyService" ;
61+ return (
62+ e . type === "Identifier" &&
63+ e . name === options . destroyServiceName
64+ ) ;
3565 } ) ;
3666 }
3767
@@ -40,17 +70,18 @@ const rule: Rule.RuleModule = {
4070 ( providersProperty && ! providerValuesHasDestroyService )
4171 ) {
4272 // get constructor
43- const classDeclaration = node . parent ;
73+ const classDeclaration = ( node as any ) . parent as ClassDeclaration ;
4474 const classElements = classDeclaration . body . body ;
45- const classConstructor = classElements . find ( ( e : any ) => {
75+ const classConstructor = classElements . find ( e => {
4676 return e . type === "MethodDefinition" && e . kind === "constructor" ;
4777 } ) ;
4878
4979 let hasDestroy ;
5080
5181 if ( classConstructor ) {
5282 // find DestroyService
53- const params : any [ ] = classConstructor . value . params ;
83+ const params : any [ ] = ( classConstructor as MethodDefinition ) . value
84+ . params ;
5485 hasDestroy = params . find ( param => {
5586 return (
5687 param . type === "TSParameterProperty" &&
@@ -60,21 +91,48 @@ const rule: Rule.RuleModule = {
6091 param . parameter . typeAnnotation . typeAnnotation . typeName
6192 . type === "Identifier" &&
6293 param . parameter . typeAnnotation . typeAnnotation . typeName
63- . name === "DestroyService"
94+ . name === options . destroyServiceName
6495 ) ;
6596 } ) ;
6697 }
6798
6899 if ( hasDestroy ) {
69100 context . report ( {
70101 loc : hasDestroy . loc ,
71- message : `Please provide DestroyService in ${ node . expression . callee . name } class providers.` ,
102+ messageId : "missing" ,
103+ data : {
104+ className : ( nodeExpression as any ) . callee . name ,
105+ } ,
72106 } ) ;
73107 }
74108 }
75109 } ,
76110 } ;
77111 } ,
78- } ;
79-
80- export = rule ;
112+ name : ruleName ,
113+ meta : {
114+ type : "problem" ,
115+ docs : {
116+ description :
117+ "Destroy service should be provided in Component/Directive providers/viewProviders array." ,
118+ recommended : "error" ,
119+ } ,
120+ messages : {
121+ missing :
122+ "Please provide DestroyService in {{className}} class providers." ,
123+ } ,
124+ schema : [
125+ {
126+ type : "object" ,
127+ properties : {
128+ destroyServiceName : {
129+ type : "string" ,
130+ default : "DestroyService" ,
131+ } ,
132+ } ,
133+ additionalProperties : false ,
134+ } ,
135+ ] ,
136+ } ,
137+ defaultOptions : [ { destroyServiceName : "DestroyService" } ] ,
138+ } ) ;
0 commit comments