Skip to content

Commit e1b25d6

Browse files
authored
no-array-callback-reference: Use simple selector (#2118)
1 parent f9ed3e1 commit e1b25d6

File tree

1 file changed

+162
-159
lines changed

1 file changed

+162
-159
lines changed

rules/no-array-callback-reference.js

Lines changed: 162 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
'use strict';
22
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');
65

76
const ERROR_WITH_NAME_MESSAGE_ID = 'error-with-name';
87
const ERROR_WITHOUT_NAME_MESSAGE_ID = 'error-without-name';
@@ -15,120 +14,127 @@ const messages = {
1514
[REPLACE_WITHOUT_NAME_MESSAGE_ID]: 'Replace function with `… => …({{parameters}})`.',
1615
};
1716

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+
}]));
132138

133139
const ignoredCallee = [
134140
// http://bluebirdjs.com/docs/api/promise.map.html
@@ -150,10 +156,6 @@ function getProblem(context, node, method, options) {
150156

151157
const name = type === 'Identifier' ? node.name : '';
152158

153-
if (type === 'Identifier' && options.ignore.includes(name)) {
154-
return;
155-
}
156-
157159
const problem = {
158160
node,
159161
messageId: name ? ERROR_WITH_NAME_MESSAGE_ID : ERROR_WITHOUT_NAME_MESSAGE_ID,
@@ -197,47 +199,48 @@ function getProblem(context, node, method, options) {
197199
}
198200

199201
/** @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, {
208206
minimumArguments: 1,
209207
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+
}
238216

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+
});
241244

242245
/** @type {import('eslint').Rule.RuleModule} */
243246
module.exports = {

0 commit comments

Comments
 (0)