From 857c55bd61ff943bc4fe92549aa15b48ef40ef9f Mon Sep 17 00:00:00 2001 From: Brian Ng Date: Tue, 15 May 2018 11:41:17 -0500 Subject: [PATCH] Keep parens around do-expressions inside ExpressionStatement (#4479) --- src/common/util.js | 37 ++++++--- src/language-js/needs-parens.js | 7 +- src/language-js/printer-estree.js | 4 +- tests/do/__snapshots__/jsfmt.spec.js.snap | 98 +++++++++++++++++++++++ tests/do/do.js | 47 +++++++++++ 5 files changed, 177 insertions(+), 16 deletions(-) diff --git a/src/common/util.js b/src/common/util.js index 4baf93597..88b69993a 100644 --- a/src/common/util.js +++ b/src/common/util.js @@ -369,54 +369,65 @@ function isBitwiseOperator(operator) { ); } -// Tests if an expression starts with `{`, or (if forbidFunctionAndClass holds) `function` or `class`. -// Will be overzealous if there's already necessary grouping parentheses. -function startsWithNoLookaheadToken(node, forbidFunctionAndClass) { +// Tests if an expression starts with `{`, or (if forbidFunctionClassAndDoExpr +// holds) `function`, `class`, or `do {}`. Will be overzealous if there's +// already necessary grouping parentheses. +function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { node = getLeftMost(node); switch (node.type) { // Hack. Remove after https://github.com/eslint/typescript-eslint-parser/issues/331 case "ObjectPattern": - return !forbidFunctionAndClass; + return !forbidFunctionClassAndDoExpr; case "FunctionExpression": case "ClassExpression": - return forbidFunctionAndClass; + case "DoExpression": + return forbidFunctionClassAndDoExpr; case "ObjectExpression": return true; case "MemberExpression": - return startsWithNoLookaheadToken(node.object, forbidFunctionAndClass); + return startsWithNoLookaheadToken( + node.object, + forbidFunctionClassAndDoExpr + ); case "TaggedTemplateExpression": if (node.tag.type === "FunctionExpression") { // IIFEs are always already parenthesized return false; } - return startsWithNoLookaheadToken(node.tag, forbidFunctionAndClass); + return startsWithNoLookaheadToken(node.tag, forbidFunctionClassAndDoExpr); case "CallExpression": if (node.callee.type === "FunctionExpression") { // IIFEs are always already parenthesized return false; } - return startsWithNoLookaheadToken(node.callee, forbidFunctionAndClass); + return startsWithNoLookaheadToken( + node.callee, + forbidFunctionClassAndDoExpr + ); case "ConditionalExpression": - return startsWithNoLookaheadToken(node.test, forbidFunctionAndClass); + return startsWithNoLookaheadToken( + node.test, + forbidFunctionClassAndDoExpr + ); case "UpdateExpression": return ( !node.prefix && - startsWithNoLookaheadToken(node.argument, forbidFunctionAndClass) + startsWithNoLookaheadToken(node.argument, forbidFunctionClassAndDoExpr) ); case "BindExpression": return ( node.object && - startsWithNoLookaheadToken(node.object, forbidFunctionAndClass) + startsWithNoLookaheadToken(node.object, forbidFunctionClassAndDoExpr) ); case "SequenceExpression": return startsWithNoLookaheadToken( node.expressions[0], - forbidFunctionAndClass + forbidFunctionClassAndDoExpr ); case "TSAsExpression": return startsWithNoLookaheadToken( node.expression, - forbidFunctionAndClass + forbidFunctionClassAndDoExpr ); default: return false; diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 360209840..451985f54 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -91,10 +91,13 @@ function needsParens(path, options) { node.type !== "SequenceExpression" && // these have parens added anyway util.startsWithNoLookaheadToken( node, - /* forbidFunctionAndClass */ false + /* forbidFunctionClassAndDoExpr */ false )) || (parent.type === "ExpressionStatement" && - util.startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ true)) + util.startsWithNoLookaheadToken( + node, + /* forbidFunctionClassAndDoExpr */ true + )) ) { return true; } diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 3edf537f5..f5928738a 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -661,7 +661,8 @@ function printPathNoParens(path, options, print, args) { n.body.type === "BlockStatement" || isJSXNode(n.body) || isTemplateOnItsOwnLine(n.body, options.originalText, options) || - n.body.type === "ArrowFunctionExpression") + n.body.type === "ArrowFunctionExpression" || + n.body.type === "DoExpression") ) { return group(concat([concat(parts), " ", body])); } @@ -912,6 +913,7 @@ function printPathNoParens(path, options, print, args) { parent.type === "ForStatement" || parent.type === "WhileStatement" || parent.type === "DoWhileStatement" || + parent.type === "DoExpression" || (parent.type === "CatchClause" && !parentParent.finalizer)) ) { return "{}"; diff --git a/tests/do/__snapshots__/jsfmt.spec.js.snap b/tests/do/__snapshots__/jsfmt.spec.js.snap index 8c2116e96..7953a42f5 100644 --- a/tests/do/__snapshots__/jsfmt.spec.js.snap +++ b/tests/do/__snapshots__/jsfmt.spec.js.snap @@ -8,6 +8,53 @@ const envSpecific = { else if(env === 'development') 'http://localhost:4000'; } }; + +let x = do { + let tmp = f(); + tmp * tmp + 1 +}; + +let x = do { + if (foo()) { f() } + else if (bar()) { g() } + else { h() } +}; + +function foo() { + return ( + + ); +} + +(do {}); +(do {} + 1); +(1 + do {}); +() => do {}; + +(do { + switch(0) { + case 0: "foo"; + case 1: break; + } +}); + +() => do { + var obj = { foo: "bar", bar: "foo" }; + for (var key in obj) { + obj[key]; + } +}; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const envSpecific = { domain: do { @@ -16,4 +63,55 @@ const envSpecific = { } }; +let x = do { + let tmp = f(); + tmp * tmp + 1; +}; + +let x = do { + if (foo()) { + f(); + } else if (bar()) { + g(); + } else { + h(); + } +}; + +function foo() { + return ( + + ); +} + +(do {}); +(do {} + 1); +1 + do {}; +() => do {}; + +(do { + switch (0) { + case 0: + "foo"; + case 1: + break; + } +}); + +() => do { + var obj = { foo: "bar", bar: "foo" }; + for (var key in obj) { + obj[key]; + } +}; + `; diff --git a/tests/do/do.js b/tests/do/do.js index 654b4fc4a..ae98feeaf 100644 --- a/tests/do/do.js +++ b/tests/do/do.js @@ -5,3 +5,50 @@ const envSpecific = { else if(env === 'development') 'http://localhost:4000'; } }; + +let x = do { + let tmp = f(); + tmp * tmp + 1 +}; + +let x = do { + if (foo()) { f() } + else if (bar()) { g() } + else { h() } +}; + +function foo() { + return ( + + ); +} + +(do {}); +(do {} + 1); +(1 + do {}); +() => do {}; + +(do { + switch(0) { + case 0: "foo"; + case 1: break; + } +}); + +() => do { + var obj = { foo: "bar", bar: "foo" }; + for (var key in obj) { + obj[key]; + } +};