1
1
'use strict' ;
2
2
const { isParenthesized} = require ( '@eslint-community/eslint-utils' ) ;
3
- const { methodCallSelector} = require ( './selectors/index.js' ) ;
4
- const { isNodeMatches} = require ( './utils/is-node-matches.js' ) ;
5
- const { isNodeValueNotFunction} = require ( './utils/index.js' ) ;
3
+ const { isMethodCall} = require ( './ast/index.js' ) ;
4
+ const { isNodeMatches, isNodeValueNotFunction} = require ( './utils/index.js' ) ;
6
5
7
6
const ERROR_WITH_NAME_MESSAGE_ID = 'error-with-name' ;
8
7
const ERROR_WITHOUT_NAME_MESSAGE_ID = 'error-without-name' ;
@@ -15,120 +14,127 @@ const messages = {
15
14
[ REPLACE_WITHOUT_NAME_MESSAGE_ID ] : 'Replace function with `… => …({{parameters}})`.' ,
16
15
} ;
17
16
18
- const iteratorMethods = [
19
- [
20
- 'every' ,
21
- {
22
- ignore : [
23
- 'Boolean' ,
24
- ] ,
25
- } ,
26
- ] ,
27
- [
28
- 'filter' , {
29
- extraSelector : '[callee.object.name!="Vue"]' ,
30
- ignore : [
31
- 'Boolean' ,
32
- ] ,
33
- } ,
34
- ] ,
35
- [
36
- 'find' ,
37
- {
38
- ignore : [
39
- 'Boolean' ,
40
- ] ,
41
- } ,
42
- ] ,
43
- [
44
- 'findLast' ,
45
- {
46
- ignore : [
47
- 'Boolean' ,
48
- ] ,
49
- } ,
50
- ] ,
51
- [
52
- 'findIndex' ,
53
- {
54
- ignore : [
55
- 'Boolean' ,
56
- ] ,
57
- } ,
58
- ] ,
59
- [
60
- 'findLastIndex' ,
61
- {
62
- ignore : [
63
- 'Boolean' ,
64
- ] ,
65
- } ,
66
- ] ,
67
- [
68
- 'flatMap' ,
69
- ] ,
70
- [
71
- 'forEach' ,
72
- {
73
- returnsUndefined : true ,
74
- } ,
75
- ] ,
76
- [
77
- 'map' ,
78
- {
79
- extraSelector : '[callee.object.name!="types"]' ,
80
- ignore : [
81
- 'String' ,
82
- 'Number' ,
83
- 'BigInt' ,
84
- 'Boolean' ,
85
- 'Symbol' ,
86
- ] ,
87
- } ,
88
- ] ,
89
- [
90
- 'reduce' ,
91
- {
92
- parameters : [
93
- 'accumulator' ,
94
- 'element' ,
95
- 'index' ,
96
- 'array' ,
97
- ] ,
98
- minParameters : 2 ,
99
- } ,
100
- ] ,
101
- [
102
- 'reduceRight' ,
103
- {
104
- parameters : [
105
- 'accumulator' ,
106
- 'element' ,
107
- 'index' ,
108
- 'array' ,
109
- ] ,
110
- minParameters : 2 ,
111
- } ,
112
- ] ,
113
- [
114
- 'some' ,
115
- {
116
- ignore : [
117
- 'Boolean' ,
118
- ] ,
119
- } ,
120
- ] ,
121
- ] . map ( ( [ method , options ] ) => {
122
- options = {
123
- parameters : [ 'element' , 'index' , 'array' ] ,
124
- ignore : [ ] ,
125
- minParameters : 1 ,
126
- extraSelector : '' ,
127
- returnsUndefined : false ,
128
- ...options ,
129
- } ;
130
- return [ method , options ] ;
131
- } ) ;
17
+ const isAwaitExpressionArgument = node => node . parent . type === 'AwaitExpression' && node . parent . argument === node ;
18
+
19
+ const iteratorMethods = new Map ( [
20
+ {
21
+ method : 'every' ,
22
+ ignore : [
23
+ 'Boolean' ,
24
+ ] ,
25
+ } ,
26
+ {
27
+ method : 'filter' ,
28
+ test : node => ! ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'Vue' ) ,
29
+ ignore : [
30
+ 'Boolean' ,
31
+ ] ,
32
+ } ,
33
+ {
34
+ method : 'find' ,
35
+ ignore : [
36
+ 'Boolean' ,
37
+ ] ,
38
+ } ,
39
+ {
40
+ method : 'findLast' ,
41
+ ignore : [
42
+ 'Boolean' ,
43
+ ] ,
44
+ } ,
45
+ {
46
+ method : 'findIndex' ,
47
+ ignore : [
48
+ 'Boolean' ,
49
+ ] ,
50
+ } ,
51
+ {
52
+ method : 'findLastIndex' ,
53
+ ignore : [
54
+ 'Boolean' ,
55
+ ] ,
56
+ } ,
57
+ {
58
+ method : 'flatMap' ,
59
+ } ,
60
+ {
61
+ method : 'forEach' ,
62
+ returnsUndefined : true ,
63
+ } ,
64
+ {
65
+ method : 'map' ,
66
+ test : node => ! ( node . callee . object . type === 'Identifier' && node . callee . object . name === 'types' ) ,
67
+ ignore : [
68
+ 'String' ,
69
+ 'Number' ,
70
+ 'BigInt' ,
71
+ 'Boolean' ,
72
+ 'Symbol' ,
73
+ ] ,
74
+ } ,
75
+ {
76
+ method : 'reduce' ,
77
+ parameters : [
78
+ 'accumulator' ,
79
+ 'element' ,
80
+ 'index' ,
81
+ 'array' ,
82
+ ] ,
83
+ minParameters : 2 ,
84
+ } ,
85
+ {
86
+ method : 'reduceRight' ,
87
+ parameters : [
88
+ 'accumulator' ,
89
+ 'element' ,
90
+ 'index' ,
91
+ 'array' ,
92
+ ] ,
93
+ minParameters : 2 ,
94
+ } ,
95
+ {
96
+ method : 'some' ,
97
+ ignore : [
98
+ 'Boolean' ,
99
+ ] ,
100
+ } ,
101
+ ] . map ( ( {
102
+ method,
103
+ parameters = [ 'element' , 'index' , 'array' ] ,
104
+ ignore = [ ] ,
105
+ minParameters = 1 ,
106
+ returnsUndefined = false ,
107
+ test,
108
+ } ) => [ method , {
109
+ minParameters,
110
+ parameters,
111
+ returnsUndefined,
112
+ test ( node ) {
113
+ if (
114
+ method !== 'reduce'
115
+ && method !== 'reduceRight'
116
+ && isAwaitExpressionArgument ( node )
117
+ ) {
118
+ return false ;
119
+ }
120
+
121
+ if ( isNodeMatches ( node . callee . object , ignoredCallee ) ) {
122
+ return false ;
123
+ }
124
+
125
+ if ( node . callee . object . type === 'CallExpression' && isNodeMatches ( node . callee . object . callee , ignoredCallee ) ) {
126
+ return false ;
127
+ }
128
+
129
+ const [ callback ] = node . arguments ;
130
+
131
+ if ( callback . type === 'Identifier' && ignore . includes ( callback . name ) ) {
132
+ return false ;
133
+ }
134
+
135
+ return ! test || test ( node ) ;
136
+ } ,
137
+ } ] ) ) ;
132
138
133
139
const ignoredCallee = [
134
140
// http://bluebirdjs.com/docs/api/promise.map.html
@@ -150,10 +156,6 @@ function getProblem(context, node, method, options) {
150
156
151
157
const name = type === 'Identifier' ? node . name : '' ;
152
158
153
- if ( type === 'Identifier' && options . ignore . includes ( name ) ) {
154
- return ;
155
- }
156
-
157
159
const problem = {
158
160
node,
159
161
messageId : name ? ERROR_WITH_NAME_MESSAGE_ID : ERROR_WITHOUT_NAME_MESSAGE_ID ,
@@ -197,47 +199,48 @@ function getProblem(context, node, method, options) {
197
199
}
198
200
199
201
/** @param {import('eslint').Rule.RuleContext } context */
200
- const create = context => {
201
- const rules = { } ;
202
-
203
- for ( const [ method , options ] of iteratorMethods ) {
204
- const selector = [
205
- method === 'reduce' || method === 'reduceRight' ? '' : ':not(AwaitExpression) > ' ,
206
- methodCallSelector ( {
207
- method,
202
+ const create = context => ( {
203
+ CallExpression ( node ) {
204
+ if (
205
+ ! isMethodCall ( node , {
208
206
minimumArguments : 1 ,
209
207
maximumArguments : 2 ,
210
- } ) ,
211
- options . extraSelector ,
212
- ] . join ( '' ) ;
213
-
214
- rules [ selector ] = node => {
215
- if ( isNodeMatches ( node . callee . object , ignoredCallee ) ) {
216
- return ;
217
- }
218
-
219
- if ( node . callee . object . type === 'CallExpression' && isNodeMatches ( node . callee . object . callee , ignoredCallee ) ) {
220
- return ;
221
- }
222
-
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
- ) {
232
- return ;
233
- }
234
-
235
- return getProblem ( context , callback , method , options ) ;
236
- } ;
237
- }
208
+ optionalCall : false ,
209
+ optionalMember : false ,
210
+ computed : false ,
211
+ } )
212
+ || node . callee . property . type !== 'Identifier'
213
+ ) {
214
+ return ;
215
+ }
238
216
239
- return rules ;
240
- } ;
217
+ const methodNode = node . callee . property ;
218
+ const methodName = methodNode . name ;
219
+ if ( ! iteratorMethods . has ( methodName ) ) {
220
+ return ;
221
+ }
222
+
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
+ ) {
232
+ return ;
233
+ }
234
+
235
+ const options = iteratorMethods . get ( methodName ) ;
236
+
237
+ if ( ! options . test ( node ) ) {
238
+ return ;
239
+ }
240
+
241
+ return getProblem ( context , callback , methodName , options ) ;
242
+ } ,
243
+ } ) ;
241
244
242
245
/** @type {import('eslint').Rule.RuleModule } */
243
246
module . exports = {
0 commit comments