@@ -13,75 +13,138 @@ const create = context => {
13
13
'falsy'
14
14
] ;
15
15
16
+ const equalityTests = [ 'is' , 'deepEqual' ] ;
17
+
16
18
const findReference = name => {
17
19
const reference = context . getScope ( ) . references . find ( reference => reference . identifier . name === name ) ;
18
20
const definitions = reference . resolved . defs ;
21
+
22
+ // Many integration tests have identifiers that match zero definitions
23
+ if ( definitions . length === 0 ) {
24
+ return undefined ;
25
+ }
26
+
19
27
return definitions [ definitions . length - 1 ] . node ;
20
28
} ;
21
29
30
+ const isRegExp = lookup => {
31
+ let isRegex = lookup . regex ;
32
+
33
+ // It's not a regexp but an identifier
34
+ if ( ! isRegex && lookup . type === 'Identifier' ) {
35
+ const reference = findReference ( lookup . name ) ;
36
+
37
+ // Not all possible references have an init field§
38
+ if ( reference && reference . init ) {
39
+ isRegex = reference . init . regex ;
40
+ }
41
+ }
42
+
43
+ return isRegex ;
44
+ } ;
45
+
46
+ const booleanHandler = node => {
47
+ const firstArg = node . arguments [ 0 ] ;
48
+
49
+ // First argument is a call expression
50
+ const isFunctionCall = firstArg . type === 'CallExpression' ;
51
+ if ( ! isFunctionCall || ! firstArg . callee . property ) {
52
+ return ;
53
+ }
54
+
55
+ const { name} = firstArg . callee . property ;
56
+ let lookup = { } ;
57
+ let variable = { } ;
58
+
59
+ if ( name === 'test' ) {
60
+ // `lookup.test(variable)`
61
+ lookup = firstArg . callee . object ;
62
+ variable = firstArg . arguments [ 0 ] ;
63
+ } else if ( [ 'search' , 'match' ] . includes ( name ) ) {
64
+ // `variable.match(lookup)`
65
+ lookup = firstArg . arguments [ 0 ] ;
66
+ variable = firstArg . callee . object ;
67
+ }
68
+
69
+ if ( ! isRegExp ( lookup ) ) {
70
+ return ;
71
+ }
72
+
73
+ const assertion = [ 'true' , 'truthy' ] . includes ( node . callee . property . name ) ? 'regex' : 'notRegex' ;
74
+
75
+ const fix = fixer => {
76
+ const source = context . getSourceCode ( ) ;
77
+ return [
78
+ fixer . replaceText ( node . callee . property , assertion ) ,
79
+ fixer . replaceText ( firstArg , `${ source . getText ( variable ) } , ${ source . getText ( lookup ) } ` )
80
+ ] ;
81
+ } ;
82
+
83
+ context . report ( {
84
+ node,
85
+ message : `Prefer using the \`t.${ assertion } ()\` assertion.` ,
86
+ fix
87
+ } ) ;
88
+ } ;
89
+
90
+ const equalityHandler = node => {
91
+ const firstArg = node . arguments [ 0 ] ;
92
+ const secondArg = node . arguments [ 1 ] ;
93
+
94
+ if ( ! firstArg || ! secondArg ) {
95
+ return ;
96
+ }
97
+
98
+ const firstIsRx = isRegExp ( firstArg ) ;
99
+ const secondIsRx = isRegExp ( secondArg ) ;
100
+
101
+ // If both are regex, or neither are, the expression is ok
102
+ if ( firstIsRx === secondIsRx ) {
103
+ return ;
104
+ }
105
+
106
+ const matchee = secondIsRx ? firstArg : secondArg ;
107
+ const regex = secondIsRx ? secondArg : firstArg ;
108
+
109
+ const assertion = 'regex' ;
110
+
111
+ const fix = fixer => {
112
+ const source = context . getSourceCode ( ) ;
113
+ return [
114
+ fixer . replaceText ( node . callee . property , 'regex' ) ,
115
+ fixer . replaceText ( firstArg , `${ source . getText ( matchee ) } ` ) ,
116
+ fixer . replaceText ( secondArg , `${ source . getText ( regex ) } ` )
117
+ ] ;
118
+ } ;
119
+
120
+ context . report ( {
121
+ node,
122
+ message : `Prefer using the \`t.${ assertion } ()\` assertion.` ,
123
+ fix
124
+ } ) ;
125
+ } ;
126
+
22
127
return ava . merge ( {
23
128
CallExpression : visitIf ( [
24
129
ava . isInTestFile ,
25
130
ava . isInTestNode
26
131
] ) ( node => {
27
- // Call a boolean assertion, for example, `t.true`, `t.false`, …
28
- const isBooleanAssertion = node . callee . type === 'MemberExpression' &&
29
- booleanTests . includes ( node . callee . property . name ) &&
132
+ const isAssertion = node . callee . type === 'MemberExpression' &&
30
133
util . getNameOfRootNodeObject ( node . callee ) === 't' ;
31
134
32
- if ( ! isBooleanAssertion ) {
33
- return ;
34
- }
35
-
36
- const firstArg = node . arguments [ 0 ] ;
37
-
38
- // First argument is a call expression
39
- const isFunctionCall = firstArg . type === 'CallExpression' ;
40
- if ( ! isFunctionCall || ! firstArg . callee . property ) {
41
- return ;
42
- }
43
-
44
- const { name} = firstArg . callee . property ;
45
- let lookup = { } ;
46
- let variable = { } ;
47
-
48
- if ( name === 'test' ) {
49
- // `lookup.test(variable)`
50
- lookup = firstArg . callee . object ;
51
- variable = firstArg . arguments [ 0 ] ;
52
- } else if ( [ 'search' , 'match' ] . includes ( name ) ) {
53
- // `variable.match(lookup)`
54
- lookup = firstArg . arguments [ 0 ] ;
55
- variable = firstArg . callee . object ;
56
- }
57
-
58
- let isRegExp = lookup . regex ;
135
+ // Call a boolean assertion, for example, `t.true`, `t.false`, …
136
+ const isBooleanAssertion = isAssertion &&
137
+ booleanTests . includes ( node . callee . property . name ) ;
59
138
60
- // It's not a regexp but an identifier
61
- if ( ! isRegExp && lookup . type === 'Identifier' ) {
62
- const reference = findReference ( lookup . name ) ;
63
- isRegExp = reference . init . regex ;
64
- }
139
+ // Call an equality assertion, ie. 't.is', 't.deepEqual'
140
+ const isEqualityAssertion = isAssertion &&
141
+ equalityTests . includes ( node . callee . property . name ) ;
65
142
66
- if ( ! isRegExp ) {
67
- return ;
143
+ if ( isBooleanAssertion ) {
144
+ booleanHandler ( node ) ;
145
+ } else if ( isEqualityAssertion ) {
146
+ equalityHandler ( node ) ;
68
147
}
69
-
70
- const assertion = [ 'true' , 'truthy' ] . includes ( node . callee . property . name ) ? 'regex' : 'notRegex' ;
71
-
72
- const fix = fixer => {
73
- const source = context . getSourceCode ( ) ;
74
- return [
75
- fixer . replaceText ( node . callee . property , assertion ) ,
76
- fixer . replaceText ( firstArg , `${ source . getText ( variable ) } , ${ source . getText ( lookup ) } ` )
77
- ] ;
78
- } ;
79
-
80
- context . report ( {
81
- node,
82
- message : `Prefer using the \`t.${ assertion } ()\` assertion.` ,
83
- fix
84
- } ) ;
85
148
} )
86
149
} ) ;
87
150
} ;
0 commit comments