Optimize transform-async-to-generator output (#14122)

* Optimize `transform-async-to-generator` output

- remove wrapper if the function length is zero.
- remove wrapper if the `assumptions.ignoreFunctionLength` is `true`.

* chore: update test case and code style

* chore: add test
This commit is contained in:
magic-akari 2022-01-09 04:01:20 +08:00 committed by GitHub
parent 213397be99
commit 910ece5e2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 102 additions and 21 deletions

View File

@ -36,6 +36,7 @@ export default function (
wrapAwait?: any; wrapAwait?: any;
}, },
noNewArrows?: boolean, noNewArrows?: boolean,
ignoreFunctionLength?: boolean,
) { ) {
path.traverse(awaitVisitor, { path.traverse(awaitVisitor, {
wrapAwait: helpers.wrapAwait, wrapAwait: helpers.wrapAwait,
@ -46,7 +47,12 @@ export default function (
path.node.async = false; path.node.async = false;
path.node.generator = true; path.node.generator = true;
wrapFunction(path, cloneNode(helpers.wrapAsync), noNewArrows); wrapFunction(
path,
cloneNode(helpers.wrapAsync),
noNewArrows,
ignoreFunctionLength,
);
const isProperty = const isProperty =
path.isObjectMethod() || path.isObjectMethod() ||

View File

@ -66,7 +66,12 @@ function classOrObjectMethod(
).unwrapFunctionEnvironment(); ).unwrapFunctionEnvironment();
} }
function plainFunction(path: NodePath<any>, callId: any, noNewArrows: boolean) { function plainFunction(
path: NodePath<any>,
callId: any,
noNewArrows: boolean,
ignoreFunctionLength: boolean,
) {
const node = path.node; const node = path.node;
const isDeclaration = path.isFunctionDeclaration(); const isDeclaration = path.isFunctionDeclaration();
const functionId = node.id; const functionId = node.id;
@ -87,26 +92,20 @@ function plainFunction(path: NodePath<any>, callId: any, noNewArrows: boolean) {
} }
const built = callExpression(callId, [node]); const built = callExpression(callId, [node]);
const params: t.Identifier[] = [];
for (const param of node.params) {
if (isAssignmentPattern(param) || isRestElement(param)) {
break;
}
params.push(path.scope.generateUidIdentifier("x"));
}
const container = wrapper({ const container = wrapper({
NAME: functionId || null, NAME: functionId || null,
REF: path.scope.generateUidIdentifier(functionId ? functionId.name : "ref"), REF: path.scope.generateUidIdentifier(functionId ? functionId.name : "ref"),
FUNCTION: built, FUNCTION: built,
PARAMS: node.params.reduce( PARAMS: params,
(acc, param) => {
acc.done =
acc.done || isAssignmentPattern(param) || isRestElement(param);
if (!acc.done) {
acc.params.push(path.scope.generateUidIdentifier("x"));
}
return acc;
},
{
params: [],
done: false,
},
).params,
}); });
if (isDeclaration) { if (isDeclaration) {
@ -123,7 +122,11 @@ function plainFunction(path: NodePath<any>, callId: any, noNewArrows: boolean) {
}); });
} }
if (!retFunction || retFunction.id || node.params.length) { if (
!retFunction ||
retFunction.id ||
(!ignoreFunctionLength && params.length)
) {
// we have an inferred function id or params so we need this wrapper // we have an inferred function id or params so we need this wrapper
// @ts-expect-error todo(flow->ts) separate `wrapper` for `isDeclaration` and `else` branches // @ts-expect-error todo(flow->ts) separate `wrapper` for `isDeclaration` and `else` branches
path.replaceWith(container); path.replaceWith(container);
@ -139,10 +142,11 @@ export default function wrapFunction(
callId: any, callId: any,
// TODO(Babel 8): Consider defaulting to false for spec compliancy // TODO(Babel 8): Consider defaulting to false for spec compliancy
noNewArrows: boolean = true, noNewArrows: boolean = true,
ignoreFunctionLength: boolean = false,
) { ) {
if (path.isMethod()) { if (path.isMethod()) {
classOrObjectMethod(path, callId); classOrObjectMethod(path, callId);
} else { } else {
plainFunction(path, callId, noNewArrows); plainFunction(path, callId, noNewArrows, ignoreFunctionLength);
} }
} }

View File

@ -8,6 +8,7 @@ export default declare((api, options) => {
const { method, module } = options; const { method, module } = options;
const noNewArrows = api.assumption("noNewArrows"); const noNewArrows = api.assumption("noNewArrows");
const ignoreFunctionLength = api.assumption("ignoreFunctionLength");
if (method && module) { if (method && module) {
return { return {
@ -24,7 +25,12 @@ export default declare((api, options) => {
wrapAsync = state.methodWrapper = addNamed(path, method, module); wrapAsync = state.methodWrapper = addNamed(path, method, module);
} }
remapAsyncToGenerator(path, { wrapAsync }, noNewArrows); remapAsyncToGenerator(
path,
{ wrapAsync },
noNewArrows,
ignoreFunctionLength,
);
}, },
}, },
}; };
@ -41,6 +47,7 @@ export default declare((api, options) => {
path, path,
{ wrapAsync: state.addHelper("asyncToGenerator") }, { wrapAsync: state.addHelper("asyncToGenerator") },
noNewArrows, noNewArrows,
ignoreFunctionLength,
); );
}, },
}, },

View File

@ -0,0 +1,16 @@
foo(async (x) => {});
foo(async ([x]) => {});
foo(async ({ x }) => {});
foo(async function (x) {});
foo(async function ([x]) {});
foo(async function ({ x }) {});
foo(async ([]) => {});
foo(async ({}) => {});
foo(async function ([]) {});
foo(async function ({}) {});
export default async ([...x]) => {};

View File

@ -0,0 +1,6 @@
{
"plugins": ["transform-async-to-generator"],
"assumptions": {
"ignoreFunctionLength": true
}
}

View File

@ -0,0 +1,15 @@
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* (x) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ([x]) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ({
x
}) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* (x) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ([x]) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ({
x
}) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ([]) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ({}) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ([]) {}));
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* ({}) {}));
export default /*#__PURE__*/babelHelpers.asyncToGenerator(function* ([...x]) {});

View File

@ -0,0 +1,6 @@
{
"plugins": ["transform-async-to-generator"],
"assumptions": {
"ignoreFunctionLength": true
}
}

View File

@ -0,0 +1,8 @@
export default function (_x) {
return _ref.apply(this, arguments);
}
function _ref() {
_ref = babelHelpers.asyncToGenerator(function* (x) {});
return _ref.apply(this, arguments);
}

View File

@ -1,3 +1,11 @@
foo(async function () { foo(async function () {
}); });
bar(async function (x = 1) {
});
baz(async function (...y) {
});

View File

@ -1 +1,5 @@
foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {})); foo( /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {}));
bar( /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {
let x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
}));
baz( /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {}));