]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-dupe-else-if.js
2 * @fileoverview Rule to disallow duplicate conditions in if-else-if chains
3 * @author Milos Djermanovic
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
19 * Determines whether the first given array is a subset of the second given array.
20 * @param {Function} comparator A function to compare two elements, should return `true` if they are equal.
21 * @param {Array} arrA The array to compare from.
22 * @param {Array} arrB The array to compare against.
23 * @returns {boolean} `true` if the array `arrA` is a subset of the array `arrB`.
25 function isSubsetByComparator(comparator
, arrA
, arrB
) {
26 return arrA
.every(a
=> arrB
.some(b
=> comparator(a
, b
)));
30 * Splits the given node by the given logical operator.
31 * @param {string} operator Logical operator `||` or `&&`.
32 * @param {ASTNode} node The node to split.
33 * @returns {ASTNode[]} Array of conditions that makes the node when joined by the operator.
35 function splitByLogicalOperator(operator
, node
) {
36 if (node
.type
=== "LogicalExpression" && node
.operator
=== operator
) {
37 return [...splitByLogicalOperator(operator
, node
.left
), ...splitByLogicalOperator(operator
, node
.right
)];
42 const splitByOr
= splitByLogicalOperator
.bind(null, "||");
43 const splitByAnd
= splitByLogicalOperator
.bind(null, "&&");
45 //------------------------------------------------------------------------------
47 //------------------------------------------------------------------------------
49 /** @type {import('../shared/types').Rule} */
55 description
: "Disallow duplicate conditions in if-else-if chains",
57 url
: "https://eslint.org/docs/latest/rules/no-dupe-else-if"
63 unexpected
: "This branch can never execute. Its condition is a duplicate or covered by previous conditions in the if-else-if chain."
68 const sourceCode
= context
.sourceCode
;
71 * Determines whether the two given nodes are considered to be equal. In particular, given that the nodes
72 * represent expressions in a boolean context, `||` and `&&` can be considered as commutative operators.
73 * @param {ASTNode} a First node.
74 * @param {ASTNode} b Second node.
75 * @returns {boolean} `true` if the nodes are considered to be equal.
77 function equal(a
, b
) {
78 if (a
.type
!== b
.type
) {
83 a
.type
=== "LogicalExpression" &&
84 (a
.operator
=== "||" || a
.operator
=== "&&") &&
85 a
.operator
=== b
.operator
87 return equal(a
.left
, b
.left
) && equal(a
.right
, b
.right
) ||
88 equal(a
.left
, b
.right
) && equal(a
.right
, b
.left
);
91 return astUtils
.equalTokens(a
, b
, sourceCode
);
94 const isSubset
= isSubsetByComparator
.bind(null, equal
);
98 const test
= node
.test
,
99 conditionsToCheck
= test
.type
=== "LogicalExpression" && test
.operator
=== "&&"
100 ? [test
, ...splitByAnd(test
)]
103 listToCheck
= conditionsToCheck
.map(c
=> splitByOr(c
).map(splitByAnd
));
105 while (current
.parent
&& current
.parent
.type
=== "IfStatement" && current
.parent
.alternate
=== current
) {
106 current
= current
.parent
;
108 const currentOrOperands
= splitByOr(current
.test
).map(splitByAnd
);
110 listToCheck
= listToCheck
.map(orOperands
=> orOperands
.filter(
111 orOperand
=> !currentOrOperands
.some(currentOrOperand
=> isSubset(currentOrOperand
, orOperand
))
114 if (listToCheck
.some(orOperands
=> orOperands
.length
=== 0)) {
115 context
.report({ node
: test
, messageId
: "unexpected" });