123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- /**
- * @fileoverview Rule to flag unnecessary double negation in Boolean contexts
- * @author Brandon Mills
- */
-
- "use strict";
-
- //------------------------------------------------------------------------------
- // Requirements
- //------------------------------------------------------------------------------
-
- const astUtils = require("../util/ast-utils");
-
- //------------------------------------------------------------------------------
- // Rule Definition
- //------------------------------------------------------------------------------
-
- module.exports = {
- meta: {
- type: "suggestion",
-
- docs: {
- description: "disallow unnecessary boolean casts",
- category: "Possible Errors",
- recommended: true,
- url: "https://eslint.org/docs/rules/no-extra-boolean-cast"
- },
-
- schema: [],
- fixable: "code",
-
- messages: {
- unexpectedCall: "Redundant Boolean call.",
- unexpectedNegation: "Redundant double negation."
- }
- },
-
- create(context) {
- const sourceCode = context.getSourceCode();
-
- // Node types which have a test which will coerce values to booleans.
- const BOOLEAN_NODE_TYPES = [
- "IfStatement",
- "DoWhileStatement",
- "WhileStatement",
- "ConditionalExpression",
- "ForStatement"
- ];
-
- /**
- * Check if a node is in a context where its value would be coerced to a boolean at runtime.
- *
- * @param {Object} node The node
- * @param {Object} parent Its parent
- * @returns {boolean} If it is in a boolean context
- */
- function isInBooleanContext(node, parent) {
- return (
- (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 &&
- node === parent.test) ||
-
- // !<bool>
- (parent.type === "UnaryExpression" &&
- parent.operator === "!")
- );
- }
-
-
- return {
- UnaryExpression(node) {
- const ancestors = context.getAncestors(),
- parent = ancestors.pop(),
- grandparent = ancestors.pop();
-
- // Exit early if it's guaranteed not to match
- if (node.operator !== "!" ||
- parent.type !== "UnaryExpression" ||
- parent.operator !== "!") {
- return;
- }
-
- if (isInBooleanContext(parent, grandparent) ||
-
- // Boolean(<bool>) and new Boolean(<bool>)
- ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") &&
- grandparent.callee.type === "Identifier" &&
- grandparent.callee.name === "Boolean")
- ) {
- context.report({
- node,
- messageId: "unexpectedNegation",
- fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument))
- });
- }
- },
- CallExpression(node) {
- const parent = node.parent;
-
- if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") {
- return;
- }
-
- if (isInBooleanContext(node, parent)) {
- context.report({
- node,
- messageId: "unexpectedCall",
- fix: fixer => {
- if (!node.arguments.length) {
- return fixer.replaceText(parent, "true");
- }
-
- if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") {
- return null;
- }
-
- const argument = node.arguments[0];
-
- if (astUtils.getPrecedence(argument) < astUtils.getPrecedence(node.parent)) {
- return fixer.replaceText(node, `(${sourceCode.getText(argument)})`);
- }
- return fixer.replaceText(node, sourceCode.getText(argument));
- }
- });
- }
- }
- };
-
- }
- };
|