From 41de9df41a30a4300243bfe4ca26f716a787b2fc Mon Sep 17 00:00:00 2001 From: jmoore914 <30698083+jmoore914@users.noreply.github.com> Date: Fri, 14 Feb 2020 18:36:53 -0500 Subject: [PATCH] Update: enforceForLogicalOperands no-extra-boolean-cast (fixes #12137) (#12734) * Working rule, updated documentation * New: Added enforceForLogicalOperands option to no-extra-boolean-cast (fixes #12137) * Add default for schema option; renamed functions for clarity; pass fewer parameters to functions; check precedence in fixer * Removed extra variable from function; fixed function name; fixed precedence check; added additional example * Updated documentation * Removed outdated legacy code method * Added additional tests * Renamed function * Added additional test; updated documentation * Switched docs examples order; fixed comments in rule; added test for inserting space * Fixed accidentally edited lines --- docs/rules/no-extra-boolean-cast.md | 54 ++ lib/rules/no-extra-boolean-cast.js | 89 ++- tests/lib/rules/no-extra-boolean-cast.js | 768 ++++++++++++++++++++++- 3 files changed, 891 insertions(+), 20 deletions(-) diff --git a/docs/rules/no-extra-boolean-cast.md b/docs/rules/no-extra-boolean-cast.md index baf795a4faa..5c7d2007fe8 100644 --- a/docs/rules/no-extra-boolean-cast.md +++ b/docs/rules/no-extra-boolean-cast.md @@ -68,3 +68,57 @@ function foo() { var foo = bar ? !!baz : !!bat; ``` + +## Options + +This rule has an object option: + +* `"enforceForLogicalOperands"` when set to `true`, in addition to checking default contexts, checks whether the extra boolean cast is contained within a logical expression. Default is `false`, meaning that this rule by default does not warn about extra booleans cast inside logical expression. + +### enforceForLogicalOperands + +Examples of **incorrect** code for this rule with `"enforceForLogicalOperands"` option set to `true`: + +```js +/*eslint no-extra-boolean-cast: ["error", {"enforceForLogicalOperands": true}]*/ + +if (!!foo || bar) { + //... +} + +while (!!foo && bar) { + //... +} + +if ((!!foo || bar) && baz) { + //... +} + +foo && Boolean(bar) ? baz : bat + +var foo = new Boolean(!!bar || baz) +``` + +Examples of **correct** code for this rule with `"enforceForLogicalOperands"` option set to `true`: + +```js +/*eslint no-extra-boolean-cast: ["error", {"enforceForLogicalOperands": true}]*/ + +if (foo || bar) { + //... +} + +while (foo && bar) { + //... +} + +if ((foo || bar) && baz) { + //... +} + +foo && bar ? baz : bat + +var foo = new Boolean(bar || baz) + +var foo = !!bar || baz; +``` diff --git a/lib/rules/no-extra-boolean-cast.js b/lib/rules/no-extra-boolean-cast.js index 336f601d165..8ccd0bce906 100644 --- a/lib/rules/no-extra-boolean-cast.js +++ b/lib/rules/no-extra-boolean-cast.js @@ -26,7 +26,16 @@ module.exports = { url: "https://eslint.org/docs/rules/no-extra-boolean-cast" }, - schema: [], + schema: [{ + type: "object", + properties: { + enforceForLogicalOperands: { + type: "boolean", + default: false + } + }, + additionalProperties: false + }], fixable: "code", messages: { @@ -47,23 +56,67 @@ module.exports = { "ForStatement" ]; + /** + * Check if a node is a Boolean function or constructor. + * @param {ASTNode} node the node + * @returns {boolean} If the node is Boolean function or constructor + */ + function isBooleanFunctionOrConstructorCall(node) { + + // Boolean() and new Boolean() + return (node.type === "CallExpression" || node.type === "NewExpression") && + node.callee.type === "Identifier" && + node.callee.name === "Boolean"; + } + + /** + * Checks whether the node is a logical expression and that the option is enabled + * @param {ASTNode} node the node + * @returns {boolean} if the node is a logical expression and option is enabled + */ + function isLogicalContext(node) { + return node.type === "LogicalExpression" && + (node.operator === "||" || node.operator === "&&") && + (context.options.length && context.options[0].enforceForLogicalOperands === true); + + } + + /** * Check if a node is in a context where its value would be coerced to a boolean at runtime. * @param {ASTNode} node The node - * @param {ASTNode} parent Its parent * @returns {boolean} If it is in a boolean context */ - function isInBooleanContext(node, parent) { + function isInBooleanContext(node) { return ( - (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 && - node === parent.test) || + (isBooleanFunctionOrConstructorCall(node.parent) && + node === node.parent.arguments[0]) || + + (BOOLEAN_NODE_TYPES.indexOf(node.parent.type) !== -1 && + node === node.parent.test) || // ! - (parent.type === "UnaryExpression" && - parent.operator === "!") + (node.parent.type === "UnaryExpression" && + node.parent.operator === "!") + ); + } + + /** + * Checks whether the node is a context that should report an error + * Acts recursively if it is in a logical context + * @param {ASTNode} node the node + * @returns {boolean} If the node is in one of the flagged contexts + */ + function isInFlaggedContext(node) { + return isInBooleanContext(node) || + (isLogicalContext(node.parent) && + + // For nested logical statements + isInFlaggedContext(node.parent) ); } + /** * Check if a node has comments inside. * @param {ASTNode} node The node to check. @@ -75,24 +128,18 @@ module.exports = { return { UnaryExpression(node) { - const ancestors = context.getAncestors(), - parent = ancestors.pop(), - grandparent = ancestors.pop(); + const parent = node.parent; + // Exit early if it's guaranteed not to match if (node.operator !== "!" || - parent.type !== "UnaryExpression" || - parent.operator !== "!") { + parent.type !== "UnaryExpression" || + parent.operator !== "!") { return; } - if (isInBooleanContext(parent, grandparent) || - // Boolean() and new Boolean() - ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") && - grandparent.callee.type === "Identifier" && - grandparent.callee.name === "Boolean") - ) { + if (isInFlaggedContext(parent)) { context.report({ node: parent, messageId: "unexpectedNegation", @@ -110,6 +157,10 @@ module.exports = { prefix = " "; } + if (astUtils.getPrecedence(node.argument) < astUtils.getPrecedence(parent.parent)) { + return fixer.replaceText(parent, `(${sourceCode.getText(node.argument)})`); + } + return fixer.replaceText(parent, prefix + sourceCode.getText(node.argument)); } }); @@ -122,7 +173,7 @@ module.exports = { return; } - if (isInBooleanContext(node, parent)) { + if (isInFlaggedContext(node)) { context.report({ node, messageId: "unexpectedCall", diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js index a530f81f603..08605d15aa1 100644 --- a/tests/lib/rules/no-extra-boolean-cast.js +++ b/tests/lib/rules/no-extra-boolean-cast.js @@ -21,6 +21,7 @@ const ruleTester = new RuleTester(); ruleTester.run("no-extra-boolean-cast", rule, { valid: [ + "Boolean(bar, !!baz);", "var foo = !!bar;", "function foo() { return !!bar; }", "var foo = bar() ? !!baz : !!bat", @@ -31,7 +32,80 @@ ruleTester.run("no-extra-boolean-cast", rule, { "var foo = bar() ? Boolean(baz) : Boolean(bat)", "for(Boolean(foo);;) {}", "for(;; Boolean(foo)) {}", - "if (new Boolean(foo)) {}" + "if (new Boolean(foo)) {}", + { + code: "var foo = bar || !!baz", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = bar && !!baz", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = bar || (baz && !!bat)", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "function foo() { return (!!bar || baz); }", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = bar() ? (!!baz && bat) : (!!bat && qux)", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "for(!!(foo && bar);;) {}", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "for(;; !!(foo || bar)) {}", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = Boolean(bar) || baz;", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = bar || Boolean(baz);", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = Boolean(bar) || Boolean(baz);", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "function foo() { return (Boolean(bar) || baz); }", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "var foo = bar() ? Boolean(baz) || bat : Boolean(bat)", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "for(Boolean(foo) || bar;;) {}", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "for(;; Boolean(foo) || bar) {}", + options: [{ enforceForLogicalOperands: true }] + }, + { + code: "if (new Boolean(foo) || bar) {}", + options: [{ enforceForLogicalOperands: true }] + }, + "if (!!foo || bar) {}", + { + code: "if (!!foo || bar) {}", + options: [{}] + }, + { + code: "if (!!foo || bar) {}", + options: [{ enforceForLogicalOperands: false }] + }, + { + code: "if ((!!foo || bar) === baz) {}", + options: [{ enforceForLogicalOperands: true }] + } ], invalid: [ @@ -277,6 +351,23 @@ ruleTester.run("no-extra-boolean-cast", rule, { type: "CallExpression" }] }, + { + code: "Boolean(Boolean(foo))", + output: "Boolean(foo)", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "Boolean(!!foo, bar)", + output: "Boolean(foo, bar)", + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + // Adjacent tokens tests { @@ -606,6 +697,681 @@ ruleTester.run("no-extra-boolean-cast", rule, { messageId: "unexpectedCall", type: "CallExpression" }] + }, + + + // In Logical context + { + code: "if (!!foo || bar) {}", + output: "if (foo || bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 5, + endColumn: 10 + }] + }, + { + code: "if (!!foo && bar) {}", + output: "if (foo && bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 5, + endColumn: 10 + }] + }, + + { + code: "if ((!!foo || bar) && bat) {}", + output: "if ((foo || bar) && bat) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 6, + endColumn: 11 + }] + }, + { + code: "if (foo && !!bar) {}", + output: "if (foo && bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 12, + endColumn: 17 + }] + }, + { + code: "do {} while (!!foo || bar)", + output: "do {} while (foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 14 + }] + }, + { + code: "while (!!foo || bar) {}", + output: "while (foo || bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 8 + }] + }, + { + code: "!!foo && bat ? bar : baz", + output: "foo && bat ? bar : baz", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 1 + }] + }, + { + code: "for (; !!foo || bar;) {}", + output: "for (; foo || bar;) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 8 + }] + }, + { + code: "!!!foo || bar", + output: "!foo || bar", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 2 + }] + }, + { + code: "Boolean(!!foo || bar)", + output: "Boolean(foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 9 + }] + }, + { + code: "new Boolean(!!foo || bar)", + output: "new Boolean(foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 13 + }] + }, + { + code: "if (Boolean(foo) || bar) {}", + output: "if (foo || bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "do {} while (Boolean(foo) || bar)", + output: "do {} while (foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "while (Boolean(foo) || bar) {}", + output: "while (foo || bar) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "Boolean(foo) || bat ? bar : baz", + output: "foo || bat ? bar : baz", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "for (; Boolean(foo) || bar;) {}", + output: "for (; foo || bar;) {}", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo) || bar", + output: "!foo || bar", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo && bar) || bat", + output: "!(foo && bar) || bat", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo + bar) || bat", + output: "!(foo + bar) || bat", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(+foo) || bar", + output: "!+foo || bar", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo()) || bar", + output: "!foo() || bar", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo() || bar)", + output: "!(foo() || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo = bar) || bat", + output: "!(foo = bar) || bat", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(...foo) || bar;", + output: null, + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo, bar()) || bar;", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean((foo, bar()) || bat);", + output: "!((foo, bar()) || bat);", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean() || bar;", + output: "true || bar;", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!(Boolean()) || bar;", + output: "true || bar;", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if (!Boolean() || bar) { foo() }", + output: "if (true || bar) { foo() }", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "while (!Boolean() || bar) { foo() }", + output: "while (true || bar) { foo() }", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "var foo = Boolean() || bar ? bar() : baz()", + output: "var foo = false || bar ? bar() : baz()", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if (Boolean() || bar) { foo() }", + output: "if (false || bar) { foo() }", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "while (Boolean() || bar) { foo() }", + output: "while (false || bar) { foo() }", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + + + // Adjacent tokens tests + { + code: "function *foo() { yield(!!a || d) ? b : c }", + output: "function *foo() { yield(a || d) ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "function *foo() { yield(!! a || d) ? b : c }", + output: "function *foo() { yield(a || d) ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "function *foo() { yield(! !a || d) ? b : c }", + output: "function *foo() { yield(a || d) ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "function *foo() { yield (!!a || d) ? b : c }", + output: "function *foo() { yield (a || d) ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "function *foo() { yield/**/(!!a || d) ? b : c }", + output: "function *foo() { yield/**/(a || d) ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "x=!!a || d ? b : c ", + output: "x=a || d ? b : c ", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "void(!Boolean() || bar)", + output: "void(true || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void(! Boolean() || bar)", + output: "void(true || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "typeof(!Boolean() || bar)", + output: "typeof(true || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(!Boolean() || bar)", + output: "(true || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void/**/(!Boolean() || bar)", + output: "void/**/(true || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + + // Comments tests + { + code: "!/**/(!!foo || bar)", + output: "!/**/(foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!!/**/!foo || bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!!!/**/foo || bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!(!!foo || bar)/**/", + output: "!(foo || bar)/**/", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "if(!/**/!foo || bar);", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "(!!/**/foo || bar ? 1 : 2)", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!/**/(Boolean(foo) || bar)", + output: "!/**/(foo || bar)", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean/**/(foo) || bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(/**/foo) || bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo/**/) || bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!(Boolean(foo)|| bar)/**/", + output: "!(foo|| bar)/**/", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean/**/(foo) || bar);", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(Boolean(foo/**/)|| bar ? 1 : 2)", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "/**/!Boolean()|| bar", + output: "/**/true|| bar", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!/**/Boolean()|| bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean/**/()|| bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(/**/)|| bar", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(!Boolean()|| bar)/**/", + output: "(true|| bar)/**/", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(!/**/Boolean()|| bar);", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(!Boolean(/**/) || bar ? 1 : 2)", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(/**/Boolean()|| bar);", + output: "if(/**/false|| bar);", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean/**/()|| bar);", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean(/**/)|| bar);", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean()|| bar/**/);", + output: "if(false|| bar/**/);", + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(Boolean/**/()|| bar ? 1 : 2)", + output: null, + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if (a && !!(b ? c : d)){}", + output: "if (a && (b ? c : d)){}", + + options: [{ enforceForLogicalOperands: true }], + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 10, + endColumn: 23 + }] + }, + { + code: "function *foo() { yield!!a || d ? b : c }", + output: "function *foo() { yield a || d ? b : c }", + options: [{ enforceForLogicalOperands: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression", + column: 24, + endColumn: 27 + }] } ] });