1
+ import { ASTUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
1
2
import {
2
- ESLintUtils ,
3
- TSESTree ,
4
- ASTUtils ,
5
- } from '@typescript-eslint/experimental-utils' ;
6
- import { getDocsUrl } from '../utils' ;
7
- import {
3
+ getDeepestIdentifierNode ,
4
+ getFunctionName ,
5
+ getInnermostReturningFunction ,
8
6
isMemberExpression ,
9
7
isObjectPattern ,
10
8
isProperty ,
11
- isRenderVariableDeclarator ,
12
9
} from '../node-utils' ;
10
+ import { createTestingLibraryRule } from '../create-testing-library-rule' ;
13
11
14
12
export const RULE_NAME = 'no-container' ;
15
13
export type MessageIds = 'noContainer' ;
16
- type Options = [ { renderFunctions ?: string [ ] } ] ;
14
+ type Options = [ ] ;
17
15
18
- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
16
+ export default createTestingLibraryRule < Options , MessageIds > ( {
19
17
name : RULE_NAME ,
20
18
meta : {
21
19
type : 'problem' ,
@@ -29,48 +27,52 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
29
27
'Avoid using container methods. Prefer using the methods from Testing Library, such as "getByRole()"' ,
30
28
} ,
31
29
fixable : null ,
32
- schema : [
33
- {
34
- type : 'object' ,
35
- properties : {
36
- renderFunctions : {
37
- type : 'array' ,
38
- } ,
39
- } ,
40
- } ,
41
- ] ,
30
+ schema : [ ] ,
42
31
} ,
43
- defaultOptions : [
44
- {
45
- renderFunctions : [ ] ,
46
- } ,
47
- ] ,
32
+ defaultOptions : [ ] ,
48
33
49
- create ( context , [ options ] ) {
50
- const { renderFunctions } = options ;
34
+ create ( context , [ ] , helpers ) {
51
35
const destructuredContainerPropNames : string [ ] = [ ] ;
52
- let renderWrapperName : string = null ;
36
+ const renderWrapperNames : string [ ] = [ ] ;
37
+ let renderResultVarName : string = null ;
53
38
let containerName : string = null ;
54
39
let containerCallsMethod = false ;
55
40
41
+ function detectRenderWrapper ( node : TSESTree . Identifier ) : void {
42
+ const innerFunction = getInnermostReturningFunction ( context , node ) ;
43
+
44
+ if ( innerFunction ) {
45
+ renderWrapperNames . push ( getFunctionName ( innerFunction ) ) ;
46
+ }
47
+ }
48
+
56
49
function showErrorIfChainedContainerMethod (
57
50
innerNode : TSESTree . MemberExpression
58
51
) {
59
52
if ( isMemberExpression ( innerNode ) ) {
60
53
if ( ASTUtils . isIdentifier ( innerNode . object ) ) {
61
54
const isContainerName = innerNode . object . name === containerName ;
62
- const isRenderWrapper = innerNode . object . name === renderWrapperName ;
63
55
56
+ if ( isContainerName ) {
57
+ context . report ( {
58
+ node : innerNode ,
59
+ messageId : 'noContainer' ,
60
+ } ) ;
61
+ return ;
62
+ }
63
+
64
+ const isRenderWrapper = innerNode . object . name === renderResultVarName ;
64
65
containerCallsMethod =
65
66
ASTUtils . isIdentifier ( innerNode . property ) &&
66
67
innerNode . property . name === 'container' &&
67
68
isRenderWrapper ;
68
69
69
- if ( isContainerName || containerCallsMethod ) {
70
+ if ( containerCallsMethod ) {
70
71
context . report ( {
71
- node : innerNode ,
72
+ node : innerNode . property ,
72
73
messageId : 'noContainer' ,
73
74
} ) ;
75
+ return ;
74
76
}
75
77
}
76
78
showErrorIfChainedContainerMethod (
@@ -80,35 +82,12 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
80
82
}
81
83
82
84
return {
83
- VariableDeclarator ( node ) {
84
- if ( isRenderVariableDeclarator ( node , [ 'render' , ...renderFunctions ] ) ) {
85
- if ( isObjectPattern ( node . id ) ) {
86
- const containerIndex = node . id . properties . findIndex (
87
- ( property ) =>
88
- isProperty ( property ) &&
89
- ASTUtils . isIdentifier ( property . key ) &&
90
- property . key . name === 'container'
91
- ) ;
92
- const nodeValue =
93
- containerIndex !== - 1 && node . id . properties [ containerIndex ] . value ;
94
- if ( ASTUtils . isIdentifier ( nodeValue ) ) {
95
- containerName = nodeValue . name ;
96
- } else {
97
- isObjectPattern ( nodeValue ) &&
98
- nodeValue . properties . forEach (
99
- ( property ) =>
100
- isProperty ( property ) &&
101
- ASTUtils . isIdentifier ( property . key ) &&
102
- destructuredContainerPropNames . push ( property . key . name )
103
- ) ;
104
- }
105
- } else {
106
- renderWrapperName = ASTUtils . isIdentifier ( node . id ) && node . id . name ;
107
- }
85
+ CallExpression ( node ) {
86
+ const callExpressionIdentifier = getDeepestIdentifierNode ( node ) ;
87
+ if ( helpers . isRenderUtil ( callExpressionIdentifier ) ) {
88
+ detectRenderWrapper ( callExpressionIdentifier ) ;
108
89
}
109
- } ,
110
90
111
- CallExpression ( node ) {
112
91
if ( isMemberExpression ( node . callee ) ) {
113
92
showErrorIfChainedContainerMethod ( node . callee ) ;
114
93
} else {
@@ -120,6 +99,47 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
120
99
} ) ;
121
100
}
122
101
} ,
102
+
103
+ VariableDeclarator ( node ) {
104
+ const initIdentifierNode = getDeepestIdentifierNode ( node . init ) ;
105
+
106
+ const isRenderWrapperVariableDeclarator = initIdentifierNode
107
+ ? renderWrapperNames . includes ( initIdentifierNode . name )
108
+ : false ;
109
+
110
+ if (
111
+ ! helpers . isRenderVariableDeclarator ( node ) &&
112
+ ! isRenderWrapperVariableDeclarator
113
+ ) {
114
+ return ;
115
+ }
116
+
117
+ if ( isObjectPattern ( node . id ) ) {
118
+ const containerIndex = node . id . properties . findIndex (
119
+ ( property ) =>
120
+ isProperty ( property ) &&
121
+ ASTUtils . isIdentifier ( property . key ) &&
122
+ property . key . name === 'container'
123
+ ) ;
124
+
125
+ const nodeValue =
126
+ containerIndex !== - 1 && node . id . properties [ containerIndex ] . value ;
127
+
128
+ if ( ASTUtils . isIdentifier ( nodeValue ) ) {
129
+ containerName = nodeValue . name ;
130
+ } else {
131
+ isObjectPattern ( nodeValue ) &&
132
+ nodeValue . properties . forEach (
133
+ ( property ) =>
134
+ isProperty ( property ) &&
135
+ ASTUtils . isIdentifier ( property . key ) &&
136
+ destructuredContainerPropNames . push ( property . key . name )
137
+ ) ;
138
+ }
139
+ } else {
140
+ renderResultVarName = ASTUtils . isIdentifier ( node . id ) && node . id . name ;
141
+ }
142
+ } ,
123
143
} ;
124
144
} ,
125
145
} ) ;
0 commit comments