diff --git a/packages/babel-generator/src/generators/methods.ts b/packages/babel-generator/src/generators/methods.ts index af4eb6236584..2f5f947ee3a0 100644 --- a/packages/babel-generator/src/generators/methods.ts +++ b/packages/babel-generator/src/generators/methods.ts @@ -112,32 +112,18 @@ export function ArrowFunctionExpression( const firstParam = node.params[0]; + // Try to avoid printing parens in simple cases, but only if we're pretty + // sure that they aren't needed by type annotations or potential newlines. if ( + !this.format.retainLines && + // Auxiliary comments can introduce unexpected newlines + !this.format.auxiliaryCommentBefore && + !this.format.auxiliaryCommentAfter && node.params.length === 1 && t.isIdentifier(firstParam) && - !hasTypes(node, firstParam) + !hasTypesOrComments(node, firstParam) ) { - if ( - (this.format.retainLines || node.async) && - ((node.loc && - node.body.loc && - node.loc.start.line < node.body.loc.start.line) || - firstParam.leadingComments?.length || - firstParam.trailingComments?.length) - ) { - this.token("("); - if (firstParam.loc && firstParam.loc.start.line > node.loc.start.line) { - this.indent(); - this.print(firstParam, node); - this.dedent(); - this._catchUp("start", node.body.loc); - } else { - this.print(firstParam, node); - } - this.token(")"); - } else { - this.print(firstParam, node); - } + this.print(firstParam, node); } else { this._params(node); } @@ -151,12 +137,18 @@ export function ArrowFunctionExpression( this.print(node.body, node); } -function hasTypes(node, param) { - return ( +function hasTypesOrComments( + node: t.ArrowFunctionExpression, + param: t.Identifier, +): boolean { + return !!( node.typeParameters || node.returnType || + // @ts-expect-error + node.predicate || param.typeAnnotation || param.optional || - param.trailingComments + param.leadingComments?.length || + param.trailingComments?.length ); } diff --git a/packages/babel-generator/test/arrow-functions.js b/packages/babel-generator/test/arrow-functions.js new file mode 100644 index 000000000000..f17bb0ef8747 --- /dev/null +++ b/packages/babel-generator/test/arrow-functions.js @@ -0,0 +1,119 @@ +import generate from "../lib"; +import { parse } from "@babel/parser"; + +describe("parameter parentheses", () => { + // Common source text for several snapshot tests + const source = ` + () => {}; + a => {}; + (a, b) => {}; + async () => {}; + async a => {}; + async (a, b) => {}; + `; + // Apply a callback function to each parameter in the AST of the above source + function forEachParam(ast, callbackFn) { + ast.program.body.forEach(s => { + s.expression.params.forEach(p => { + callbackFn(p); + }); + }); + } + + it("auxiliaryCommentBefore", () => { + const ast = parse(source); + forEachParam(ast, p => (p.loc = null)); + const output = generate(ast, { auxiliaryCommentBefore: "BEFORE" }).code; + expect(output).toMatchInlineSnapshot(` + "() => {}; + + ( + /*BEFORE*/ + a) => {}; + + ( + /*BEFORE*/ + a, + /*BEFORE*/ + b) => {}; + + async () => {}; + + async ( + /*BEFORE*/ + a) => {}; + + async ( + /*BEFORE*/ + a, + /*BEFORE*/ + b) => {};" + `); + }); + it("auxiliaryCommentAfter", () => { + const ast = parse(source); + forEachParam(ast, p => (p.loc = null)); + const output = generate(ast, { auxiliaryCommentAfter: "AFTER" }).code; + expect(output).toMatchInlineSnapshot(` + "() => {}; + + (a + /*AFTER*/ + ) => {}; + + (a + /*AFTER*/ + , b + /*AFTER*/ + ) => {}; + + async () => {}; + + async (a + /*AFTER*/ + ) => {}; + + async (a + /*AFTER*/ + , b + /*AFTER*/ + ) => {};" + `); + }); + it("empty leadingComments array", () => { + const ast = parse(source); + forEachParam(ast, p => (p.leadingComments = [])); + const output = generate(ast).code; + expect(output).toMatchInlineSnapshot(` + "() => {}; + + a => {}; + + (a, b) => {}; + + async () => {}; + + async a => {}; + + async (a, b) => {};" + `); + }); + it("empty trailingComments array", () => { + const ast = parse(source); + forEachParam(ast, p => (p.trailingComments = [])); + const output = generate(ast).code; + expect(output).toMatchInlineSnapshot(` + "() => {}; + + a => {}; + + (a, b) => {}; + + async () => {}; + + async a => {}; + + async (a, b) => {};" + `); + }); +}); diff --git a/packages/babel-generator/test/fixtures/edgecase/single-arg-async-arrow-with-retainlines/output.js b/packages/babel-generator/test/fixtures/edgecase/single-arg-async-arrow-with-retainlines/output.js index 6bb2ce5093e8..d7c8ba8571e8 100644 --- a/packages/babel-generator/test/fixtures/edgecase/single-arg-async-arrow-with-retainlines/output.js +++ b/packages/babel-generator/test/fixtures/edgecase/single-arg-async-arrow-with-retainlines/output.js @@ -1,11 +1,11 @@ var fn = async ( - arg -) => {}; +arg) => +{}; async (x) => {}; -async x => {}; +async (x) => {}; async (x) => {}; \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/flow/predicates/output.js b/packages/babel-generator/test/fixtures/flow/predicates/output.js index bc1ac228aaa1..f78e494bce29 100644 --- a/packages/babel-generator/test/fixtures/flow/predicates/output.js +++ b/packages/babel-generator/test/fixtures/flow/predicates/output.js @@ -14,4 +14,4 @@ var f = (x: mixed): %checks => typeof x === "string"; const foo2 = (x: mixed): boolean %checks => typeof x === "string"; -x: %checks => x !== null; \ No newline at end of file +(x): %checks => x !== null; \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/parentheses/async-arrow-function/output.js b/packages/babel-generator/test/fixtures/parentheses/async-arrow-function/output.js index eaf8a9076d5a..9dd55c5ad596 100644 --- a/packages/babel-generator/test/fixtures/parentheses/async-arrow-function/output.js +++ b/packages/babel-generator/test/fixtures/parentheses/async-arrow-function/output.js @@ -1,8 +1,8 @@ const x = async ( // some comment - a) => { +a) => { return foo(await a); }; function foo(a) { return a; -} +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-computed-key/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-computed-key/output.js index fd457cfdc663..fd1cb2742b4f 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-computed-key/output.js +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-computed-key/output.js @@ -1,7 +1,7 @@ var _ref2; const { - [(_ref) => { + [_ref => { let rest = babelHelpers.extends({}, _ref); let b = babelHelpers.extends({}, {}); }]: a, diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-default-value/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-default-value/output.js index f1ad422c4de0..cc5c24aa43d0 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-default-value/output.js +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-default-value/output.js @@ -1,7 +1,7 @@ var _ref2; const { - a = (_ref) => { + a = _ref => { let rest = babelHelpers.extends({}, _ref); let b = babelHelpers.extends({}, {}); }, diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js index 8033a4d76105..0d4466933614 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js @@ -1,4 +1,4 @@ -(_ref) => { +_ref => { let R = babelHelpers.extends({}, _ref); let a = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : R; }; @@ -32,7 +32,7 @@ }(); }; -(_ref6) => { +_ref6 => { let R = babelHelpers.extends({}, _ref6); let a = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : f(R); }; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-4904/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-4904/output.js index 1d9133c7c626..4f44bbb1ef68 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-4904/output.js +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-4904/output.js @@ -15,7 +15,7 @@ const _bar = bar(), const { a -} = foo((_ref) => { +} = foo(_ref => { let { b } = _ref, diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-8323/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-8323/output.js index b2596090f6ec..cc84cec34a16 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-8323/output.js +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/regression/gh-8323/output.js @@ -3,7 +3,7 @@ const get = () => { return 3; }; -const f = (_ref) => { +const f = _ref => { let { a = get(), b diff --git a/packages/babel-preset-env/test/fixtures/bugfixes/_esmodules-no-bugfixes/output.js b/packages/babel-preset-env/test/fixtures/bugfixes/_esmodules-no-bugfixes/output.js index 06783423c900..74848f95a68c 100644 --- a/packages/babel-preset-env/test/fixtures/bugfixes/_esmodules-no-bugfixes/output.js +++ b/packages/babel-preset-env/test/fixtures/bugfixes/_esmodules-no-bugfixes/output.js @@ -1,5 +1,5 @@ // Edge -(_ref) => { +_ref => { var { x = 2 } = _ref; diff --git a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-40/output.js b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-40/output.js index 889201c488e6..6e14edf5b712 100644 --- a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-40/output.js +++ b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-40/output.js @@ -1,4 +1,4 @@ -(_ref) => { +_ref => { var { x = 2 } = _ref; diff --git a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-14/output.js b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-14/output.js index e93f11f57a97..6659cf75adbf 100644 --- a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-14/output.js +++ b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-14/output.js @@ -1,4 +1,4 @@ -(_ref) => { +_ref => { let _ref$x = _ref.x, x = _ref$x === void 0 ? 2 : _ref$x; }; diff --git a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-17-no-bugfixes/output.js b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-17-no-bugfixes/output.js index 4b87aa152fb2..dd102fbc348e 100644 --- a/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-17-no-bugfixes/output.js +++ b/packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-17-no-bugfixes/output.js @@ -1,4 +1,4 @@ -(_ref) => { +_ref => { let { x = 2 } = _ref;