From 8f141bfafedec3096ca9f08707e50cdd431f1102 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Thu, 24 May 2018 13:06:33 -0700 Subject: [PATCH] Update babylon & flow (#4536) * Support new node types for optionals * Update babylon * Fix decorator tests * fix manual errors * Update flow * pretty print * enable option for flow to support ?? * fix AST_COMPARE=1 * fix lint and explicitly test 1_2_3 syntax for flow --- package.json | 4 +- src/language-js/clean.js | 14 ++- src/language-js/parser-babylon.js | 2 +- src/language-js/parser-flow.js | 3 +- src/language-js/printer-estree.js | 88 ++++++++++++++----- tests/literal-numeric-separator/jsfmt.spec.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 6 -- tests/nullish_coalescing/jsfmt.spec.js | 2 +- .../nullish_coalesing_operator.js | 3 - .../__snapshots__/jsfmt.spec.js.snap | 6 ++ tests/pipeline_operator/pipeline_operator.js | 3 + yarn.lock | 12 +-- 12 files changed, 99 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index bc51e6db..97bbe027 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@babel/code-frame": "7.0.0-beta.40", "@glimmer/syntax": "0.30.3", - "babylon": "7.0.0-beta.34", + "babylon": "7.0.0-beta.47", "camelcase": "4.1.0", "chalk": "2.1.0", "cjk-regex": "1.0.2", @@ -31,7 +31,7 @@ "esutils": "2.0.2", "find-parent-dir": "0.3.0", "find-project-root": "1.1.1", - "flow-parser": "0.70", + "flow-parser": "0.72.0", "get-stream": "3.0.0", "globby": "6.1.0", "graphql": "0.13.2", diff --git a/src/language-js/clean.js b/src/language-js/clean.js index 73b4bd19..7680fe73 100644 --- a/src/language-js/clean.js +++ b/src/language-js/clean.js @@ -89,6 +89,11 @@ function clean(ast, newObj, parent) { delete newObj.key; } + if (ast.type === "OptionalMemberExpression" && ast.optional === false) { + newObj.type = "MemberExpression"; + delete newObj.optional; + } + // Remove raw and cooked values from TemplateElement when it's CSS // styled-jsx if ( @@ -123,12 +128,13 @@ function clean(ast, newObj, parent) { } // CSS template literals in Angular Component decorator + const expression = ast.expression || ast.callee; if ( ast.type === "Decorator" && - ast.expression.type === "CallExpression" && - ast.expression.callee.name === "Component" && - ast.expression.arguments.length === 1 && - ast.expression.arguments[0].properties.some( + expression.type === "CallExpression" && + expression.callee.name === "Component" && + expression.arguments.length === 1 && + expression.arguments[0].properties.some( prop => prop.key.name === "styles" && prop.value.type === "ArrayExpression" ) diff --git a/src/language-js/parser-babylon.js b/src/language-js/parser-babylon.js index 15ab25cb..a4cd3743 100644 --- a/src/language-js/parser-babylon.js +++ b/src/language-js/parser-babylon.js @@ -17,7 +17,7 @@ function parse(text, parsers, opts) { "flow", "doExpressions", "objectRestSpread", - "decorators", + "decorators-legacy", "classProperties", "exportDefaultFrom", "exportNamespaceFrom", diff --git a/src/language-js/parser-flow.js b/src/language-js/parser-flow.js index e5a07878..d913d064 100644 --- a/src/language-js/parser-flow.js +++ b/src/language-js/parser-flow.js @@ -15,7 +15,8 @@ function parse(text /*, parsers, opts*/) { esproposal_class_instance_fields: true, esproposal_class_static_fields: true, esproposal_export_star_as: true, - esproposal_optional_chaining: true + esproposal_optional_chaining: true, + esproposal_nullish_coalescing: true }); if (ast.errors.length > 0) { diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 09a78b2f..164d54ed 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -76,11 +76,11 @@ function genericPrint(path, options, printPath, args) { ) { let separator = hardline; path.each(decoratorPath => { - let prefix = "@"; let decorator = decoratorPath.getValue(); if (decorator.expression) { decorator = decorator.expression; - prefix = ""; + } else { + decorator = decorator.callee; } if ( @@ -90,17 +90,21 @@ function genericPrint(path, options, printPath, args) { node.type !== "ClassMethod" && (decorator.type === "Identifier" || decorator.type === "MemberExpression" || - (decorator.type === "CallExpression" && + decorator.type === "OptionalMemberExpression" || + ((decorator.type === "CallExpression" || + decorator.type === "OptionalCallExpression") && (decorator.arguments.length === 0 || (decorator.arguments.length === 1 && (isStringLiteral(decorator.arguments[0]) || decorator.arguments[0].type === "Identifier" || - decorator.arguments[0].type === "MemberExpression"))))) + decorator.arguments[0].type === "MemberExpression" || + decorator.arguments[0].type === + "OptionalMemberExpression"))))) ) { separator = line; } - decorators.push(prefix, printPath(decoratorPath), separator); + decorators.push(printPath(decoratorPath), separator); }, "decorators"); } else if ( privateUtil.isExportDeclaration(node) && @@ -294,7 +298,10 @@ function formatTernaryOperator(path, options, print, operatorOptions) { // : c // ).call() const breakClosingParen = - !jsxMode && parent.type === "MemberExpression" && !parent.computed; + !jsxMode && + (parent.type === "MemberExpression" || + parent.type === "OptionalMemberExpression") && + !parent.computed; return maybeGroup( concat( @@ -430,7 +437,9 @@ function printPathNoParens(path, options, print, args) { // ).call() if ( parent.type === "UnaryExpression" || - (parent.type === "MemberExpression" && !parent.computed) + ((parent.type === "MemberExpression" || + parent.type === "OptionalMemberExpression") && + !parent.computed) ) { return group( concat([indent(concat([softline, concat(parts)])), softline]) @@ -518,6 +527,7 @@ function printPathNoParens(path, options, print, args) { } return group(concat([castGroup, path.call(print, "expression")])); } + case "OptionalMemberExpression": case "MemberExpression": { const parent = path.getParentNode(); let firstNonMemberParent; @@ -528,6 +538,7 @@ function printPathNoParens(path, options, print, args) { } while ( firstNonMemberParent && (firstNonMemberParent.type === "MemberExpression" || + firstNonMemberParent.type === "OptionalMemberExpression" || firstNonMemberParent.type === "TSNonNullExpression") ); @@ -542,7 +553,8 @@ function printPathNoParens(path, options, print, args) { n.computed || (n.object.type === "Identifier" && n.property.type === "Identifier" && - parent.type !== "MemberExpression"); + parent.type !== "MemberExpression" && + parent.type !== "OptionalMemberExpression"); return concat([ path.call(print, "object"), @@ -990,6 +1002,7 @@ function printPathNoParens(path, options, print, args) { return concat(parts); case "NewExpression": + case "OptionalCallExpression": case "CallExpression": { const isNew = n.type === "NewExpression"; @@ -1262,7 +1275,11 @@ function printPathNoParens(path, options, print, args) { case "ObjectMethod": return printObjectMethod(path, options, print); case "Decorator": - return concat(["@", path.call(print, "expression")]); + return concat([ + "@", + path.call(print, "expression"), + path.call(print, "callee") + ]); case "ArrayExpression": case "ArrayPattern": if (n.elements.length === 0) { @@ -1837,6 +1854,7 @@ function printPathNoParens(path, options, print, args) { n.expression.type === "ObjectExpression" || n.expression.type === "ArrowFunctionExpression" || n.expression.type === "CallExpression" || + n.expression.type === "OptionalCallExpression" || n.expression.type === "FunctionExpression" || n.expression.type === "JSXEmptyExpression" || n.expression.type === "TemplateLiteral" || @@ -2235,6 +2253,7 @@ function printPathNoParens(path, options, print, args) { if ( (n.expressions[i].comments && n.expressions[i].comments.length) || n.expressions[i].type === "MemberExpression" || + n.expressions[i].type === "OptionalMemberExpression" || n.expressions[i].type === "ConditionalExpression" ) { printed = concat([indent(concat([softline, printed])), softline]); @@ -3331,6 +3350,7 @@ function couldGroupArg(arg) { arg.body.type === "ObjectExpression" || arg.body.type === "ArrayExpression" || arg.body.type === "CallExpression" || + arg.body.type === "OptionalCallExpression" || isJSXNode(arg.body))) ); } @@ -3378,6 +3398,7 @@ const functionCompositionFunctionNames = { }; function isFunctionCompositionFunction(node) { switch (node.type) { + case "OptionalMemberExpression": case "MemberExpression": { return isFunctionCompositionFunction(node.property); } @@ -4126,8 +4147,8 @@ function printOptionalToken(path) { return ""; } if ( - node.type === "CallExpression" || - (node.type === "MemberExpression" && node.computed) + node.type === "OptionalCallExpression" || + (node.type === "OptionalMemberExpression" && node.computed) ) { return "?."; } @@ -4204,8 +4225,11 @@ function printMemberChain(path, options, print) { function rec(path) { const node = path.getValue(); if ( - node.type === "CallExpression" && - (isMemberish(node.callee) || node.callee.type === "CallExpression") + (node.type === "CallExpression" || + node.type === "OptionalCallExpression") && + (isMemberish(node.callee) || + node.callee.type === "CallExpression" || + node.callee.type === "OptionalCallExpression") ) { printedNodes.unshift({ node: node, @@ -4230,6 +4254,7 @@ function printMemberChain(path, options, print) { printed: comments.printComments( path, () => + node.type === "OptionalMemberExpression" || node.type === "MemberExpression" ? printMemberLookup(path, options, print) : printBindExpressionCallee(path, options, print), @@ -4294,8 +4319,10 @@ function printMemberChain(path, options, print) { for (; i < printedNodes.length; ++i) { if ( printedNodes[i].node.type === "TSNonNullExpression" || + printedNodes[i].node.type === "OptionalCallExpression" || printedNodes[i].node.type === "CallExpression" || - (printedNodes[i].node.type === "MemberExpression" && + ((printedNodes[i].node.type === "MemberExpression" || + printedNodes[i].node.type === "OptionalMemberExpression") && printedNodes[i].node.computed && isNumericLiteral(printedNodes[i].node.property)) ) { @@ -4304,7 +4331,10 @@ function printMemberChain(path, options, print) { break; } } - if (printedNodes[0].node.type !== "CallExpression") { + if ( + printedNodes[0].node.type !== "CallExpression" && + printedNodes[0].node.type !== "OptionalCallExpression" + ) { for (; i + 1 < printedNodes.length; ++i) { if ( isMemberish(printedNodes[i].node) && @@ -4341,7 +4371,10 @@ function printMemberChain(path, options, print) { hasSeenCallExpression = false; } - if (printedNodes[i].node.type === "CallExpression") { + if ( + printedNodes[i].node.type === "CallExpression" || + printedNodes[i].node.type === "OptionalCallExpression" + ) { hasSeenCallExpression = true; } currentGroup.push(printedNodes[i]); @@ -4403,7 +4436,8 @@ function printMemberChain(path, options, print) { const lastNode = privateUtil.getLast(groups[0]).node; return ( - lastNode.type === "MemberExpression" && + (lastNode.type === "MemberExpression" || + lastNode.type === "OptionalMemberExpression") && lastNode.property.type === "Identifier" && (isFactory(lastNode.property.name) || (isExpression && isShort(lastNode.property.name)) || @@ -4453,6 +4487,7 @@ function printMemberChain(path, options, print) { ).node; const shouldHaveEmptyLineBeforeIndent = lastNodeBeforeIndent.type !== "CallExpression" && + lastNodeBeforeIndent.type !== "OptionalCallExpression" && shouldInsertEmptyLineAfter(lastNodeBeforeIndent); const expanded = concat([ @@ -4463,7 +4498,9 @@ function printMemberChain(path, options, print) { ]); const callExpressionCount = printedNodes.filter( - tuple => tuple.node.type === "CallExpression" + tuple => + tuple.node.type === "CallExpression" || + tuple.node.type === "OptionalCallExpression" ).length; // We don't want to print in one line if there's: @@ -4952,6 +4989,7 @@ function maybeWrapJSXElementInParens(path, elem) { TSJsxFragment: true, ExpressionStatement: true, CallExpression: true, + OptionalCallExpression: true, ConditionalExpression: true }; if (NO_WRAP_PARENTS[parent.type]) { @@ -4975,6 +5013,7 @@ function isBinaryish(node) { function isMemberish(node) { return ( node.type === "MemberExpression" || + node.type === "OptionalMemberExpression" || (node.type === "BindExpression" && node.object) ); } @@ -5203,7 +5242,9 @@ function hasNakedLeftSide(node) { node.type === "LogicalExpression" || node.type === "ConditionalExpression" || node.type === "CallExpression" || + node.type === "OptionalCallExpression" || node.type === "MemberExpression" || + node.type === "OptionalMemberExpression" || node.type === "SequenceExpression" || node.type === "TaggedTemplateExpression" || (node.type === "BindExpression" && !node.object) || @@ -5396,7 +5437,10 @@ function returnArgumentHasLeadingComment(options, argument) { } function isMemberExpressionChain(node) { - if (node.type !== "MemberExpression") { + if ( + node.type !== "MemberExpression" && + node.type !== "OptionalMemberExpression" + ) { return false; } if (node.object.type === "Identifier") { @@ -5640,7 +5684,8 @@ function isTestCall(n, parent) { function isSkipOrOnlyBlock(node) { return ( - node.callee.type === "MemberExpression" && + (node.callee.type === "MemberExpression" || + node.callee.type === "OptionalMemberExpression") && node.callee.object.type === "Identifier" && node.callee.property.type === "Identifier" && unitTestRe.test(node.callee.object.name) && @@ -5657,7 +5702,8 @@ function isTemplateLiteral(node) { // example: https://docs.angularjs.org/guide/unit-testing#using-beforeall- function isAngularTestWrapper(node) { return ( - node.type === "CallExpression" && + (node.type === "CallExpression" || + node.type === "OptionalCallExpression") && node.callee.type === "Identifier" && (node.callee.name === "async" || node.callee.name === "inject") ); diff --git a/tests/literal-numeric-separator/jsfmt.spec.js b/tests/literal-numeric-separator/jsfmt.spec.js index 4ef9b45f..c0e8f2eb 100644 --- a/tests/literal-numeric-separator/jsfmt.spec.js +++ b/tests/literal-numeric-separator/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["babylon", "typescript"]); +run_spec(__dirname, ["babylon", "flow", "typescript"]); diff --git a/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap b/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap index e11e17b0..46c3faab 100644 --- a/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap +++ b/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap @@ -13,9 +13,6 @@ foo ?? baz || baz; (foo && baz) ?? baz; foo && (baz ?? baz); - -foo |> (bar ?? baz); -(foo |> bar) ?? baz; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ obj.foo ?? "default"; @@ -30,7 +27,4 @@ foo ?? baz || baz; (foo && baz) ?? baz; foo && (baz ?? baz); -foo |> bar ?? baz; -(foo |> bar) ?? baz; - `; diff --git a/tests/nullish_coalescing/jsfmt.spec.js b/tests/nullish_coalescing/jsfmt.spec.js index 968651cd..bffb7a54 100644 --- a/tests/nullish_coalescing/jsfmt.spec.js +++ b/tests/nullish_coalescing/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["babylon"]); +run_spec(__dirname, ["babylon", "flow"]); diff --git a/tests/nullish_coalescing/nullish_coalesing_operator.js b/tests/nullish_coalescing/nullish_coalesing_operator.js index d56e001f..49261d78 100644 --- a/tests/nullish_coalescing/nullish_coalesing_operator.js +++ b/tests/nullish_coalescing/nullish_coalesing_operator.js @@ -10,6 +10,3 @@ foo ?? baz || baz; (foo && baz) ?? baz; foo && (baz ?? baz); - -foo |> (bar ?? baz); -(foo |> bar) ?? baz; diff --git a/tests/pipeline_operator/__snapshots__/jsfmt.spec.js.snap b/tests/pipeline_operator/__snapshots__/jsfmt.spec.js.snap index a2af7f4e..07d40a83 100644 --- a/tests/pipeline_operator/__snapshots__/jsfmt.spec.js.snap +++ b/tests/pipeline_operator/__snapshots__/jsfmt.spec.js.snap @@ -25,6 +25,9 @@ function createPerson (attrs) { |> format('name', /^[a-z]$/i) |> Person.insertIntoDatabase; } + +foo |> (bar ?? baz); +(foo |> bar) ?? baz; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a |> b |> c; @@ -49,4 +52,7 @@ function createPerson(attrs) { |> Person.insertIntoDatabase; } +foo |> bar ?? baz; +(foo |> bar) ?? baz; + `; diff --git a/tests/pipeline_operator/pipeline_operator.js b/tests/pipeline_operator/pipeline_operator.js index 57ccee0f..a262b23e 100644 --- a/tests/pipeline_operator/pipeline_operator.js +++ b/tests/pipeline_operator/pipeline_operator.js @@ -22,3 +22,6 @@ function createPerson (attrs) { |> format('name', /^[a-z]$/i) |> Person.insertIntoDatabase; } + +foo |> (bar ?? baz); +(foo |> bar) ?? baz; diff --git a/yarn.lock b/yarn.lock index 7a25adc8..6b6ffb8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -962,9 +962,9 @@ babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@7.0.0-beta.34: - version "7.0.0-beta.34" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.34.tgz#2ccdf97bb4fbc1617619a030a6c0390b2c8f16d6" +babylon@7.0.0-beta.47: + version "7.0.0-beta.47" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80" babylon@7.0.0-beta.40: version "7.0.0-beta.40" @@ -2094,9 +2094,9 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -flow-parser@0.70: - version "0.70.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.70.0.tgz#9c310187efe4380ba9a251284e9b83b95c49e857" +flow-parser@0.72.0: + version "0.72.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.72.0.tgz#6c8041e76ac7d0be1a71ce29c00cd1435fb6013c" for-in@^1.0.1: version "1.0.2"