2 * @fileoverview Rule to flag statements that use != and == instead of !== and ===
3 * @author Nicholas C. Zakas
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
18 /** @type {import('../shared/types').Rule} */
24 description
: "require the use of `===` and `!==`",
26 url
: "https://eslint.org/docs/rules/eqeqeq"
41 enum: ["always", "never", "ignore"]
44 additionalProperties
: false
47 additionalItems
: false
53 enum: ["smart", "allow-null"]
56 additionalItems
: false
64 unexpected
: "Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'."
69 const config
= context
.options
[0] || "always";
70 const options
= context
.options
[1] || {};
71 const sourceCode
= context
.getSourceCode();
73 const nullOption
= (config
=== "always")
74 ? options
.null || "always"
76 const enforceRuleForNull
= (nullOption
=== "always");
77 const enforceInverseRuleForNull
= (nullOption
=== "never");
80 * Checks if an expression is a typeof expression
81 * @param {ASTNode} node The node to check
82 * @returns {boolean} if the node is a typeof expression
84 function isTypeOf(node
) {
85 return node
.type
=== "UnaryExpression" && node
.operator
=== "typeof";
89 * Checks if either operand of a binary expression is a typeof operation
90 * @param {ASTNode} node The node to check
91 * @returns {boolean} if one of the operands is typeof
94 function isTypeOfBinary(node
) {
95 return isTypeOf(node
.left
) || isTypeOf(node
.right
);
99 * Checks if operands are literals of the same type (via typeof)
100 * @param {ASTNode} node The node to check
101 * @returns {boolean} if operands are of same type
104 function areLiteralsAndSameType(node
) {
105 return node
.left
.type
=== "Literal" && node
.right
.type
=== "Literal" &&
106 typeof node
.left
.value
=== typeof node
.right
.value
;
110 * Checks if one of the operands is a literal null
111 * @param {ASTNode} node The node to check
112 * @returns {boolean} if operands are null
115 function isNullCheck(node
) {
116 return astUtils
.isNullLiteral(node
.right
) || astUtils
.isNullLiteral(node
.left
);
120 * Reports a message for this rule.
121 * @param {ASTNode} node The binary expression node that was checked
122 * @param {string} expectedOperator The operator that was expected (either '==', '!=', '===', or '!==')
126 function report(node
, expectedOperator
) {
127 const operatorToken
= sourceCode
.getFirstTokenBetween(
130 token
=> token
.value
=== node
.operator
135 loc
: operatorToken
.loc
,
136 messageId
: "unexpected",
137 data
: { expectedOperator
, actualOperator
: node
.operator
},
140 // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
141 if (isTypeOfBinary(node
) || areLiteralsAndSameType(node
)) {
142 return fixer
.replaceText(operatorToken
, expectedOperator
);
150 BinaryExpression(node
) {
151 const isNull
= isNullCheck(node
);
153 if (node
.operator
!== "==" && node
.operator
!== "!=") {
154 if (enforceInverseRuleForNull
&& isNull
) {
155 report(node
, node
.operator
.slice(0, -1));
160 if (config
=== "smart" && (isTypeOfBinary(node
) ||
161 areLiteralsAndSameType(node
) || isNull
)) {
165 if (!enforceRuleForNull
&& isNull
) {
169 report(node
, `${node.operator}=`);