2 * @fileoverview Rule to disallow negating the left operand of relational operators
3 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
19 * Checks whether the given operator is `in` or `instanceof`
20 * @param {string} op The operator type to check.
21 * @returns {boolean} `true` if the operator is `in` or `instanceof`
23 function isInOrInstanceOfOperator(op
) {
24 return op
=== "in" || op
=== "instanceof";
28 * Checks whether the given operator is an ordering relational operator or not.
29 * @param {string} op The operator type to check.
30 * @returns {boolean} `true` if the operator is an ordering relational operator.
32 function isOrderingRelationalOperator(op
) {
33 return op
=== "<" || op
=== ">" || op
=== ">=" || op
=== "<=";
37 * Checks whether the given node is a logical negation expression or not.
38 * @param {ASTNode} node The node to check.
39 * @returns {boolean} `true` if the node is a logical negation expression.
41 function isNegation(node
) {
42 return node
.type
=== "UnaryExpression" && node
.operator
=== "!";
45 //------------------------------------------------------------------------------
47 //------------------------------------------------------------------------------
54 description
: "disallow negating the left operand of relational operators",
56 url
: "https://eslint.org/docs/rules/no-unsafe-negation"
65 enforceForOrderingRelations
: {
70 additionalProperties
: false
77 unexpected
: "Unexpected negating the left operand of '{{operator}}' operator.",
78 suggestNegatedExpression
: "Negate '{{operator}}' expression instead of its left operand. This changes the current behavior.",
79 suggestParenthesisedNegation
: "Wrap negation in '()' to make the intention explicit. This preserves the current behavior."
84 const sourceCode
= context
.getSourceCode();
85 const options
= context
.options
[0] || {};
86 const enforceForOrderingRelations
= options
.enforceForOrderingRelations
=== true;
89 BinaryExpression(node
) {
90 const operator
= node
.operator
;
91 const orderingRelationRuleApplies
= enforceForOrderingRelations
&& isOrderingRelationalOperator(operator
);
94 (isInOrInstanceOfOperator(operator
) || orderingRelationRuleApplies
) &&
95 isNegation(node
.left
) &&
96 !astUtils
.isParenthesised(sourceCode
, node
.left
)
101 messageId
: "unexpected",
105 messageId
: "suggestNegatedExpression",
108 const negationToken
= sourceCode
.getFirstToken(node
.left
);
109 const fixRange
= [negationToken
.range
[1], node
.range
[1]];
110 const text
= sourceCode
.text
.slice(fixRange
[0], fixRange
[1]);
112 return fixer
.replaceTextRange(fixRange
, `(${text})`);
116 messageId
: "suggestParenthesisedNegation",
118 return fixer
.replaceText(node
.left
, `(${sourceCode.getText(node.left)})`);