|
|
|
|
|
|
|
|
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
|
|
const astUtils = require("./utils/ast-utils"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = { |
|
meta: { |
|
type: "suggestion", |
|
|
|
docs: { |
|
description: "Require the use of `===` and `!==`", |
|
recommended: false, |
|
url: "https://eslint.org/docs/latest/rules/eqeqeq" |
|
}, |
|
|
|
schema: { |
|
anyOf: [ |
|
{ |
|
type: "array", |
|
items: [ |
|
{ |
|
enum: ["always"] |
|
}, |
|
{ |
|
type: "object", |
|
properties: { |
|
null: { |
|
enum: ["always", "never", "ignore"] |
|
} |
|
}, |
|
additionalProperties: false |
|
} |
|
], |
|
additionalItems: false |
|
}, |
|
{ |
|
type: "array", |
|
items: [ |
|
{ |
|
enum: ["smart", "allow-null"] |
|
} |
|
], |
|
additionalItems: false |
|
} |
|
] |
|
}, |
|
|
|
fixable: "code", |
|
|
|
messages: { |
|
unexpected: "Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'." |
|
} |
|
}, |
|
|
|
create(context) { |
|
const config = context.options[0] || "always"; |
|
const options = context.options[1] || {}; |
|
const sourceCode = context.sourceCode; |
|
|
|
const nullOption = (config === "always") |
|
? options.null || "always" |
|
: "ignore"; |
|
const enforceRuleForNull = (nullOption === "always"); |
|
const enforceInverseRuleForNull = (nullOption === "never"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
function isTypeOf(node) { |
|
return node.type === "UnaryExpression" && node.operator === "typeof"; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isTypeOfBinary(node) { |
|
return isTypeOf(node.left) || isTypeOf(node.right); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function areLiteralsAndSameType(node) { |
|
return node.left.type === "Literal" && node.right.type === "Literal" && |
|
typeof node.left.value === typeof node.right.value; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isNullCheck(node) { |
|
return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function report(node, expectedOperator) { |
|
const operatorToken = sourceCode.getFirstTokenBetween( |
|
node.left, |
|
node.right, |
|
token => token.value === node.operator |
|
); |
|
|
|
context.report({ |
|
node, |
|
loc: operatorToken.loc, |
|
messageId: "unexpected", |
|
data: { expectedOperator, actualOperator: node.operator }, |
|
fix(fixer) { |
|
|
|
|
|
if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) { |
|
return fixer.replaceText(operatorToken, expectedOperator); |
|
} |
|
return null; |
|
} |
|
}); |
|
} |
|
|
|
return { |
|
BinaryExpression(node) { |
|
const isNull = isNullCheck(node); |
|
|
|
if (node.operator !== "==" && node.operator !== "!=") { |
|
if (enforceInverseRuleForNull && isNull) { |
|
report(node, node.operator.slice(0, -1)); |
|
} |
|
return; |
|
} |
|
|
|
if (config === "smart" && (isTypeOfBinary(node) || |
|
areLiteralsAndSameType(node) || isNull)) { |
|
return; |
|
} |
|
|
|
if (!enforceRuleForNull && isNull) { |
|
return; |
|
} |
|
|
|
report(node, `${node.operator}=`); |
|
} |
|
}; |
|
|
|
} |
|
}; |
|
|