Skip to content

Commit

Permalink
Simplify the special-case printing of single-param arrow functions (#…
Browse files Browse the repository at this point in the history
…13204)

* Simplify the special-case printing of single-param arrow functions

* Update test fixtures with single-param arrow functions

* Add some explicit snapshot tests for known edge-cases
  • Loading branch information
Zalathar committed Apr 26, 2021
1 parent 10f4d08 commit 3d4b801
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 41 deletions.
42 changes: 17 additions & 25 deletions packages/babel-generator/src/generators/methods.ts
Expand Up @@ -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);
}
Expand All @@ -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
);
}
119 changes: 119 additions & 0 deletions 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) => {};"
`);
});
});
@@ -1,11 +1,11 @@
var fn = async (
arg
) => {};
arg) =>
{};

async (x) =>
{};

async x => {};
async (x) => {};

async (x) =>
{};
Expand Up @@ -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;
(x): %checks => x !== null;
@@ -1,8 +1,8 @@
const x = async ( // some comment
a) => {
a) => {
return foo(await a);
};

function foo(a) {
return a;
}
}
@@ -1,7 +1,7 @@
var _ref2;

const {
[(_ref) => {
[_ref => {
let rest = babelHelpers.extends({}, _ref);
let b = babelHelpers.extends({}, {});
}]: a,
Expand Down
@@ -1,7 +1,7 @@
var _ref2;

const {
a = (_ref) => {
a = _ref => {
let rest = babelHelpers.extends({}, _ref);
let b = babelHelpers.extends({}, {});
},
Expand Down
@@ -1,4 +1,4 @@
(_ref) => {
_ref => {
let R = babelHelpers.extends({}, _ref);
let a = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : R;
};
Expand Down Expand Up @@ -32,7 +32,7 @@
}();
};

(_ref6) => {
_ref6 => {
let R = babelHelpers.extends({}, _ref6);
let a = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : f(R);
};
Expand Down
Expand Up @@ -15,7 +15,7 @@ const _bar = bar(),

const {
a
} = foo((_ref) => {
} = foo(_ref => {
let {
b
} = _ref,
Expand Down
Expand Up @@ -3,7 +3,7 @@ const get = () => {
return 3;
};

const f = (_ref) => {
const f = _ref => {
let {
a = get(),
b
Expand Down
@@ -1,5 +1,5 @@
// Edge
(_ref) => {
_ref => {
var {
x = 2
} = _ref;
Expand Down
@@ -1,4 +1,4 @@
(_ref) => {
_ref => {
var {
x = 2
} = _ref;
Expand Down
@@ -1,4 +1,4 @@
(_ref) => {
_ref => {
let _ref$x = _ref.x,
x = _ref$x === void 0 ? 2 : _ref$x;
};
@@ -1,4 +1,4 @@
(_ref) => {
_ref => {
let {
x = 2
} = _ref;
Expand Down

0 comments on commit 3d4b801

Please sign in to comment.