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" ;
2
11
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 ] ) {
5
29
return {
6
30
"ClassDeclaration > Decorator[expression.callee.name=/^(Component|Directive)$/]" :
7
- ( node : any ) => {
31
+ ( node : Decorator ) => {
32
+ const nodeExpression = node . expression as CallExpression ;
8
33
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 ;
11
37
12
38
if ( isDecoratorEmpty ) {
13
39
return ;
14
40
}
15
41
16
42
// 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 ;
24
51
25
52
let providerValuesHasDestroyService : boolean = false ;
26
53
@@ -31,7 +58,10 @@ const rule: Rule.RuleModule = {
31
58
) {
32
59
providerValuesHasDestroyService =
33
60
! ! 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
+ ) ;
35
65
} ) ;
36
66
}
37
67
@@ -40,17 +70,18 @@ const rule: Rule.RuleModule = {
40
70
( providersProperty && ! providerValuesHasDestroyService )
41
71
) {
42
72
// get constructor
43
- const classDeclaration = node . parent ;
73
+ const classDeclaration = ( node as any ) . parent as ClassDeclaration ;
44
74
const classElements = classDeclaration . body . body ;
45
- const classConstructor = classElements . find ( ( e : any ) => {
75
+ const classConstructor = classElements . find ( e => {
46
76
return e . type === "MethodDefinition" && e . kind === "constructor" ;
47
77
} ) ;
48
78
49
79
let hasDestroy ;
50
80
51
81
if ( classConstructor ) {
52
82
// find DestroyService
53
- const params : any [ ] = classConstructor . value . params ;
83
+ const params : any [ ] = ( classConstructor as MethodDefinition ) . value
84
+ . params ;
54
85
hasDestroy = params . find ( param => {
55
86
return (
56
87
param . type === "TSParameterProperty" &&
@@ -60,21 +91,48 @@ const rule: Rule.RuleModule = {
60
91
param . parameter . typeAnnotation . typeAnnotation . typeName
61
92
. type === "Identifier" &&
62
93
param . parameter . typeAnnotation . typeAnnotation . typeName
63
- . name === "DestroyService"
94
+ . name === options . destroyServiceName
64
95
) ;
65
96
} ) ;
66
97
}
67
98
68
99
if ( hasDestroy ) {
69
100
context . report ( {
70
101
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
+ } ,
72
106
} ) ;
73
107
}
74
108
}
75
109
} ,
76
110
} ;
77
111
} ,
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