1
1
'use strict' ;
2
- const { isParenthesized} = require ( '@eslint-community/eslint-utils' ) ;
3
2
const { isMethodCall} = require ( './ast/index.js' ) ;
4
- const { isNodeMatches, isNodeValueNotFunction} = require ( './utils/index.js' ) ;
3
+ const {
4
+ isNodeMatches,
5
+ isNodeValueNotFunction,
6
+ isParenthesized,
7
+ getParenthesizedRange,
8
+ getParenthesizedText,
9
+ shouldAddParenthesesToCallExpressionCallee,
10
+ } = require ( './utils/index.js' ) ;
5
11
6
12
const ERROR_WITH_NAME_MESSAGE_ID = 'error-with-name' ;
7
13
const ERROR_WITHOUT_NAME_MESSAGE_ID = 'error-without-name' ;
@@ -25,7 +31,7 @@ const iteratorMethods = new Map([
25
31
} ,
26
32
{
27
33
method : 'filter' ,
28
- test : node => ! ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'Vue' ) ,
34
+ shouldIgnoreCallExpression : node => ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'Vue' ) ,
29
35
ignore : [
30
36
'Boolean' ,
31
37
] ,
@@ -63,7 +69,7 @@ const iteratorMethods = new Map([
63
69
} ,
64
70
{
65
71
method : 'map' ,
66
- test : node => ! ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'types' ) ,
72
+ shouldIgnoreCallExpression : node => ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'types' ) ,
67
73
ignore : [
68
74
'String' ,
69
75
'Number' ,
@@ -104,35 +110,39 @@ const iteratorMethods = new Map([
104
110
ignore = [ ] ,
105
111
minParameters = 1 ,
106
112
returnsUndefined = false ,
107
- test ,
113
+ shouldIgnoreCallExpression ,
108
114
} ) => [ method , {
109
115
minParameters,
110
116
parameters,
111
117
returnsUndefined,
112
- test ( node ) {
118
+ shouldIgnoreCallExpression ( callExpression ) {
113
119
if (
114
120
method !== 'reduce'
115
121
&& method !== 'reduceRight'
116
- && isAwaitExpressionArgument ( node )
122
+ && isAwaitExpressionArgument ( callExpression )
117
123
) {
118
- return false ;
124
+ return true ;
119
125
}
120
126
121
- if ( isNodeMatches ( node . callee . object , ignoredCallee ) ) {
122
- return false ;
127
+ if ( isNodeMatches ( callExpression . callee . object , ignoredCallee ) ) {
128
+ return true ;
123
129
}
124
130
125
- if ( node . callee . object . type === 'CallExpression' && isNodeMatches ( node . callee . object . callee , ignoredCallee ) ) {
126
- return false ;
131
+ if (
132
+ callExpression . callee . object . type === 'CallExpression'
133
+ && isNodeMatches ( callExpression . callee . object . callee , ignoredCallee )
134
+ ) {
135
+ return true ;
127
136
}
128
137
129
- const [ callback ] = node . arguments ;
130
-
138
+ return shouldIgnoreCallExpression ?. ( callExpression ) ?? false ;
139
+ } ,
140
+ shouldIgnoreCallback ( callback ) {
131
141
if ( callback . type === 'Identifier' && ignore . includes ( callback . name ) ) {
132
- return false ;
142
+ return true ;
133
143
}
134
144
135
- return ! test || test ( node ) ;
145
+ return false ;
136
146
} ,
137
147
} ] ) ) ;
138
148
@@ -163,9 +173,14 @@ function getProblem(context, node, method, options) {
163
173
name,
164
174
method,
165
175
} ,
166
- suggest : [ ] ,
167
176
} ;
168
177
178
+ if ( node . type === 'YieldExpression' || node . type === 'AwaitExpression' ) {
179
+ return problem ;
180
+ }
181
+
182
+ problem . suggest = [ ] ;
183
+
169
184
const { parameters, minParameters, returnsUndefined} = options ;
170
185
for ( let parameterLength = minParameters ; parameterLength <= parameters . length ; parameterLength ++ ) {
171
186
const suggestionParameters = parameters . slice ( 0 , parameterLength ) . join ( ', ' ) ;
@@ -178,16 +193,20 @@ function getProblem(context, node, method, options) {
178
193
} ,
179
194
fix ( fixer ) {
180
195
const { sourceCode} = context ;
181
- let nodeText = sourceCode . getText ( node ) ;
182
- if ( isParenthesized ( node , sourceCode ) || type === 'ConditionalExpression' ) {
183
- nodeText = `(${ nodeText } )` ;
196
+ let text = getParenthesizedText ( node , sourceCode ) ;
197
+
198
+ if (
199
+ ! isParenthesized ( node , sourceCode )
200
+ && shouldAddParenthesesToCallExpressionCallee ( node )
201
+ ) {
202
+ text = `(${ text } )` ;
184
203
}
185
204
186
- return fixer . replaceText (
187
- node ,
205
+ return fixer . replaceTextRange (
206
+ getParenthesizedRange ( node , sourceCode ) ,
188
207
returnsUndefined
189
- ? `(${ suggestionParameters } ) => { ${ nodeText } (${ suggestionParameters } ); }`
190
- : `(${ suggestionParameters } ) => ${ nodeText } (${ suggestionParameters } )` ,
208
+ ? `(${ suggestionParameters } ) => { ${ text } (${ suggestionParameters } ); }`
209
+ : `(${ suggestionParameters } ) => ${ text } (${ suggestionParameters } )` ,
191
210
) ;
192
211
} ,
193
212
} ;
@@ -198,47 +217,57 @@ function getProblem(context, node, method, options) {
198
217
return problem ;
199
218
}
200
219
220
+ function * getTernaryConsequentAndALternate ( node ) {
221
+ if ( node . type === 'ConditionalExpression' ) {
222
+ yield * getTernaryConsequentAndALternate ( node . consequent ) ;
223
+ yield * getTernaryConsequentAndALternate ( node . alternate ) ;
224
+ return ;
225
+ }
226
+
227
+ yield node ;
228
+ }
229
+
201
230
/** @param {import('eslint').Rule.RuleContext } context */
202
231
const create = context => ( {
203
- CallExpression ( node ) {
232
+ * CallExpression ( callExpression ) {
204
233
if (
205
- ! isMethodCall ( node , {
234
+ ! isMethodCall ( callExpression , {
206
235
minimumArguments : 1 ,
207
236
maximumArguments : 2 ,
208
237
optionalCall : false ,
209
238
optionalMember : false ,
210
239
computed : false ,
211
240
} )
212
- || node . callee . property . type !== 'Identifier'
241
+ || callExpression . callee . property . type !== 'Identifier'
213
242
) {
214
243
return ;
215
244
}
216
245
217
- const methodNode = node . callee . property ;
246
+ const methodNode = callExpression . callee . property ;
218
247
const methodName = methodNode . name ;
219
248
if ( ! iteratorMethods . has ( methodName ) ) {
220
249
return ;
221
250
}
222
251
223
- const [ callback ] = node . arguments ;
224
-
225
- if (
226
- callback . type === 'FunctionExpression'
227
- || callback . type === 'ArrowFunctionExpression'
228
- // Ignore all `CallExpression`s include `function.bind()`
229
- || callback . type === 'CallExpression'
230
- || isNodeValueNotFunction ( callback )
231
- ) {
252
+ const options = iteratorMethods . get ( methodName ) ;
253
+ if ( options . shouldIgnoreCallExpression ( callExpression ) ) {
232
254
return ;
233
255
}
234
256
235
- const options = iteratorMethods . get ( methodName ) ;
257
+ for ( const callback of getTernaryConsequentAndALternate ( callExpression . arguments [ 0 ] ) ) {
258
+ if (
259
+ callback . type === 'FunctionExpression'
260
+ || callback . type === 'ArrowFunctionExpression'
261
+ // Ignore all `CallExpression`s include `function.bind()`
262
+ || callback . type === 'CallExpression'
263
+ || options . shouldIgnoreCallback ( callback )
264
+ || isNodeValueNotFunction ( callback )
265
+ ) {
266
+ continue ;
267
+ }
236
268
237
- if ( ! options . test ( node ) ) {
238
- return ;
269
+ yield getProblem ( context , callback , methodName , options ) ;
239
270
}
240
-
241
- return getProblem ( context , callback , methodName , options ) ;
242
271
} ,
243
272
} ) ;
244
273
0 commit comments