Skip to content

Commit 20a1f52

Browse files
authored
no-array-reduce: More explicit check (#1822)
1 parent 56df468 commit 20a1f52

File tree

1 file changed

+52
-37
lines changed

1 file changed

+52
-37
lines changed

rules/no-array-reduce.js

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22
const {methodCallSelector} = require('./selectors/index.js');
3-
const {arrayPrototypeMethodSelector, notFunctionSelector, matches} = require('./selectors/index.js');
3+
const {arrayPrototypeMethodSelector, notFunctionSelector} = require('./selectors/index.js');
44

55
const MESSAGE_ID = 'no-reduce';
66
const messages = {
@@ -14,25 +14,49 @@ const prototypeSelector = method => [
1414
methods: ['reduce', 'reduceRight'],
1515
}),
1616
].join('');
17-
const selector = matches([
17+
const cases = [
1818
// `array.{reduce,reduceRight}()`
19-
[
20-
methodCallSelector({methods: ['reduce', 'reduceRight'], minimumArguments: 1, maximumArguments: 2}),
21-
notFunctionSelector('arguments.0'),
22-
' > .callee > .property',
23-
].join(''),
19+
{
20+
selector: [
21+
methodCallSelector({methods: ['reduce', 'reduceRight'], minimumArguments: 1, maximumArguments: 2}),
22+
notFunctionSelector('arguments.0'),
23+
].join(''),
24+
getMethodNode: callExpression => callExpression.callee.property,
25+
isSimpleOperation(callExpression) {
26+
const [callback] = callExpression.arguments;
27+
28+
return (
29+
callback
30+
&& (
31+
// `array.reduce((accumulator, element) => accumulator + element)`
32+
(callback.type === 'ArrowFunctionExpression' && callback.body.type === 'BinaryExpression')
33+
// `array.reduce((accumulator, element) => {return accumulator + element;})`
34+
// `array.reduce(function (accumulator, element){return accumulator + element;})`
35+
|| (
36+
(callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression')
37+
&& callback.body.type === 'BlockStatement'
38+
&& callback.body.body.length === 1
39+
&& callback.body.body[0].type === 'ReturnStatement'
40+
&& callback.body.body[0].argument.type === 'BinaryExpression'
41+
)
42+
)
43+
);
44+
},
45+
},
2446
// `[].{reduce,reduceRight}.call()` and `Array.{reduce,reduceRight}.call()`
25-
[
26-
prototypeSelector('call'),
27-
notFunctionSelector('arguments.1'),
28-
' > .callee > .object > .property',
29-
].join(''),
47+
{
48+
selector: [
49+
prototypeSelector('call'),
50+
notFunctionSelector('arguments.1'),
51+
].join(''),
52+
getMethodNode: callExpression => callExpression.callee.object.property,
53+
},
3054
// `[].{reduce,reduceRight}.apply()` and `Array.{reduce,reduceRight}.apply()`
31-
[
32-
prototypeSelector('apply'),
33-
' > .callee > .object > .property',
34-
].join(''),
35-
]);
55+
{
56+
selector: prototypeSelector('apply'),
57+
getMethodNode: callExpression => callExpression.callee.object.property,
58+
},
59+
];
3660

3761
const schema = [
3862
{
@@ -50,35 +74,26 @@ const schema = [
5074
/** @param {import('eslint').Rule.RuleContext} context */
5175
const create = context => {
5276
const {allowSimpleOperations} = {allowSimpleOperations: true, ...context.options[0]};
77+
const listeners = {};
5378

54-
return {
55-
[selector](node) {
56-
const callback = node.parent.parent?.arguments?.[0] ?? {};
79+
for (const {selector, getMethodNode, isSimpleOperation} of cases) {
80+
listeners[selector] = callExpression => {
81+
const methodNode = getMethodNode(callExpression);
5782
const problem = {
58-
node,
83+
node: methodNode,
5984
messageId: MESSAGE_ID,
60-
data: {method: node.name},
85+
data: {method: methodNode.name},
6186
};
6287

63-
if (!allowSimpleOperations) {
64-
return problem;
65-
}
66-
67-
if (callback.type === 'ArrowFunctionExpression' && callback.body.type === 'BinaryExpression') {
68-
return;
69-
}
70-
71-
if ((callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression')
72-
&& callback.body.type === 'BlockStatement'
73-
&& callback.body.body.length === 1
74-
&& callback.body.body[0].type === 'ReturnStatement'
75-
&& callback.body.body[0].argument.type === 'BinaryExpression') {
88+
if (allowSimpleOperations && isSimpleOperation?.(callExpression)) {
7689
return;
7790
}
7891

7992
return problem;
80-
},
81-
};
93+
};
94+
}
95+
96+
return listeners;
8297
};
8398

8499
/** @type {import('eslint').Rule.RuleModule} */

0 commit comments

Comments
 (0)