From bfdb0c97003fc0e045aa6ed10b177c35305a6e46 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Tue, 13 Aug 2019 22:57:51 +0200 Subject: [PATCH] Fix: no-extra-boolean-cast invalid autofix for Boolean() without args (#12076) * Fix: no-extra-boolean-cast invalid autofix for Boolean() without args * Add test cases * Prevent removal of comments --- lib/rules/no-extra-boolean-cast.js | 49 +++- tests/lib/rules/no-extra-boolean-cast.js | 308 +++++++++++++++++++++++ 2 files changed, 352 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-extra-boolean-cast.js b/lib/rules/no-extra-boolean-cast.js index 8dd526477d4..9ae9b5be61f 100644 --- a/lib/rules/no-extra-boolean-cast.js +++ b/lib/rules/no-extra-boolean-cast.js @@ -50,8 +50,8 @@ module.exports = { /** * 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 + * @param {ASTNode} node The node + * @param {ASTNode} parent Its parent * @returns {boolean} If it is in a boolean context */ function isInBooleanContext(node, parent) { @@ -65,6 +65,15 @@ module.exports = { ); } + /** + * Check if a node has comments inside. + * + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if it has comments inside. + */ + function hasCommentsInside(node) { + return Boolean(sourceCode.getCommentsInside(node).length); + } return { UnaryExpression(node) { @@ -89,7 +98,12 @@ module.exports = { context.report({ node, messageId: "unexpectedNegation", - fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument)) + fix: fixer => { + if (hasCommentsInside(parent)) { + return null; + } + return fixer.replaceText(parent, sourceCode.getText(node.argument)); + } }); } }, @@ -106,10 +120,35 @@ module.exports = { messageId: "unexpectedCall", fix: fixer => { if (!node.arguments.length) { - return fixer.replaceText(parent, "true"); + if (parent.type === "UnaryExpression" && parent.operator === "!") { + + // !Boolean() -> true + + if (hasCommentsInside(parent)) { + return null; + } + + const replacement = "true"; + let prefix = ""; + const tokenBefore = sourceCode.getTokenBefore(parent); + + if (tokenBefore && tokenBefore.range[1] === parent.range[0] && + !astUtils.canTokensBeAdjacent(tokenBefore, replacement)) { + prefix = " "; + } + + return fixer.replaceText(parent, prefix + replacement); + } + + // Boolean() -> false + if (hasCommentsInside(node)) { + return null; + } + return fixer.replaceText(node, "false"); } - if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") { + if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement" || + hasCommentsInside(node)) { return null; } diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js index 4d2890e8476..129329ff0a3 100644 --- a/tests/lib/rules/no-extra-boolean-cast.js +++ b/tests/lib/rules/no-extra-boolean-cast.js @@ -227,6 +227,314 @@ ruleTester.run("no-extra-boolean-cast", rule, { messageId: "unexpectedCall", type: "CallExpression" }] + }, + { + code: "if (!Boolean()) { foo() }", + output: "if (true) { foo() }", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "while (!Boolean()) { foo() }", + output: "while (true) { foo() }", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "var foo = Boolean() ? bar() : baz()", + output: "var foo = false ? bar() : baz()", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if (Boolean()) { foo() }", + output: "if (false) { foo() }", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "while (Boolean()) { foo() }", + output: "while (false) { foo() }", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + + // Adjacent tokens tests + { + code: "void!Boolean()", + output: "void true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void! Boolean()", + output: "void true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "typeof!Boolean()", + output: "typeof true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(!Boolean())", + output: "(true)", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "+!Boolean()", + output: "+true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void !Boolean()", + output: "void true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void(!Boolean())", + output: "void(true)", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "void/**/!Boolean()", + output: "void/**/true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + + // Comments tests + { + code: "!/**/!!foo", + output: "!/**/foo", + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!!/**/!foo", + output: null, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!!!/**/foo", + output: null, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!!!foo/**/", + output: "!foo/**/", + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "if(!/**/!foo);", + output: null, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "(!!/**/foo ? 1 : 2)", + output: null, + errors: [{ + messageId: "unexpectedNegation", + type: "UnaryExpression" + }] + }, + { + code: "!/**/Boolean(foo)", + output: "!/**/foo", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean/**/(foo)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(/**/foo)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo/**/)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(foo)/**/", + output: "!foo/**/", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean/**/(foo));", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(Boolean(foo/**/) ? 1 : 2)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "/**/!Boolean()", + output: "/**/true", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!/**/Boolean()", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean/**/()", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean(/**/)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "!Boolean()/**/", + output: "true/**/", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(!/**/Boolean());", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(!Boolean(/**/) ? 1 : 2)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(/**/Boolean());", + output: "if(/**/false);", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean/**/());", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean(/**/));", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "if(Boolean()/**/);", + output: "if(false/**/);", + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] + }, + { + code: "(Boolean/**/() ? 1 : 2)", + output: null, + errors: [{ + messageId: "unexpectedCall", + type: "CallExpression" + }] } ] });