This commit introduces 4 changes:
1) Function declarations are wrapped using function declarations.
This has two advantages:
- We can rely on native hoisting, instead of using _blockHoist
- The function isn't wrapped until it is called. This avoids
problems where `regeneratorRuntime.wrap` was called before
that `babel-polyfill` was imported.
Example:
function fn() {}
// becomes
function fn() { return _fn.apply(this, arguments); }
function _fn() {
_fn = _wrapper(/* Original function ... */);
return _fn.apply(this, arguments);
}
2) Use a single template for both named and anonymous function
expressions. They already had the same behavior, but the one
used for named functions was a bit longer.
3) Use normal functions instead of arrow functions to wrap
function expressions.
4) Generate a name based on the original one for wrapped
functions (e.g. `foo` becomes `_foo` instead of `_ref`).
88 lines
2.1 KiB
JavaScript
88 lines
2.1 KiB
JavaScript
/* @noflow */
|
|
|
|
import type { NodePath } from "@babel/traverse";
|
|
import wrapFunction from "@babel/helper-wrap-function";
|
|
import annotateAsPure from "@babel/helper-annotate-as-pure";
|
|
import * as t from "@babel/types";
|
|
import rewriteForAwait from "./for-await";
|
|
|
|
const awaitVisitor = {
|
|
Function(path) {
|
|
path.skip();
|
|
},
|
|
|
|
AwaitExpression(path, { wrapAwait }) {
|
|
const argument = path.get("argument");
|
|
|
|
if (path.parentPath.isYieldExpression()) {
|
|
path.replaceWith(argument.node);
|
|
return;
|
|
}
|
|
|
|
path.replaceWith(
|
|
t.yieldExpression(
|
|
wrapAwait
|
|
? t.callExpression(wrapAwait, [argument.node])
|
|
: argument.node,
|
|
),
|
|
);
|
|
},
|
|
|
|
ForOfStatement(path, { file, wrapAwait }) {
|
|
const { node } = path;
|
|
if (!node.await) return;
|
|
|
|
const build = rewriteForAwait(path, {
|
|
getAsyncIterator: file.addHelper("asyncIterator"),
|
|
wrapAwait,
|
|
});
|
|
|
|
const { declar, loop } = build;
|
|
const block = loop.body;
|
|
|
|
// ensure that it's a block so we can take all its statements
|
|
path.ensureBlock();
|
|
|
|
// add the value declaration to the new loop body
|
|
if (declar) {
|
|
block.body.push(declar);
|
|
}
|
|
|
|
// push the rest of the original loop body onto our new body
|
|
block.body = block.body.concat(node.body.body);
|
|
|
|
t.inherits(loop, node);
|
|
t.inherits(loop.body, node.body);
|
|
|
|
if (build.replaceParent) {
|
|
path.parentPath.replaceWithMultiple(build.node);
|
|
} else {
|
|
path.replaceWithMultiple(build.node);
|
|
}
|
|
},
|
|
};
|
|
|
|
export default function(path: NodePath, file: Object, helpers: Object) {
|
|
path.traverse(awaitVisitor, {
|
|
file,
|
|
wrapAwait: helpers.wrapAwait,
|
|
});
|
|
|
|
const isIIFE = path.parentPath.isCallExpression({ callee: path.node });
|
|
|
|
path.node.async = false;
|
|
path.node.generator = true;
|
|
|
|
wrapFunction(path, helpers.wrapAsync);
|
|
|
|
const isProperty =
|
|
path.isObjectMethod() ||
|
|
path.isClassMethod() ||
|
|
path.parentPath.isObjectProperty() ||
|
|
path.parentPath.isClassProperty();
|
|
|
|
if (!isProperty && !isIIFE && path.isExpression()) {
|
|
annotateAsPure(path);
|
|
}
|
|
}
|