Simplify the special-case printing of single-param arrow functions (#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
This commit is contained in:
Stuart Cook 2021-04-27 00:26:45 +10:00 committed by GitHub
parent 10f4d08efb
commit 3d4b801bb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 152 additions and 41 deletions

View File

@ -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
);
}

View File

@ -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) => {};"
`);
});
});

View File

@ -1,11 +1,11 @@
var fn = async (
arg
) => {};
arg) =>
{};
async (x) =>
{};
async x => {};
async (x) => {};
async (x) =>
{};

View File

@ -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;

View File

@ -1,8 +1,8 @@
const x = async ( // some comment
a) => {
a) => {
return foo(await a);
};
function foo(a) {
return a;
}
}

View File

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

View File

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

View File

@ -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);
};

View File

@ -15,7 +15,7 @@ const _bar = bar(),
const {
a
} = foo((_ref) => {
} = foo(_ref => {
let {
b
} = _ref,

View File

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

View File

@ -1,5 +1,5 @@
// Edge
(_ref) => {
_ref => {
var {
x = 2
} = _ref;

View File

@ -1,4 +1,4 @@
(_ref) => {
_ref => {
var {
x = 2
} = _ref;

View File

@ -1,4 +1,4 @@
(_ref) => {
_ref => {
let _ref$x = _ref.x,
x = _ref$x === void 0 ? 2 : _ref$x;
};

View File

@ -1,4 +1,4 @@
(_ref) => {
_ref => {
let {
x = 2
} = _ref;