Nicolò Ribaudo 6ef7b51a11 Implement assumptions defined in the babel/rfcs#5 RFC
- `mutableTemplateObject` and `ignoreToPrimitiveHint` (#12408)
- `setClassMethods` (#12407)
- `setComputedProperties` (#12490)
- `ignoreFunctionLength` (#12491)
- `noDocumentAll` (#12481)
- `iterableIsArray` and `arrayLikeIsIterable` (#12489)
- `pureGetters` (#12504)
- `skipForOfIteratorClosing` (#12496)
- `objectRestNoSymbols`, `setSpreadProperties` and `pureGetters` (#12505)
- `noNewArrows` (#12613, #12793)
- `setPublicClassFields` and `privateFieldsAsProperties` (#12497)
- `constantReexports` and `enumerableModuleMeta` (#12618)
- `constantSuper`, `superIsCallableConstructor` and `noClassCalls` (#12726)

Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
Co-authored-by: Huáng Jùnliàng <JLHwung@users.noreply.github.com>
2021-02-21 17:09:45 +01:00

87 lines
2.2 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";
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(t.cloneNode(wrapAwait), [argument.node])
: argument.node,
),
);
},
};
export default function (
path: NodePath,
helpers: { wrapAsync: Object, wrapAwait: Object },
noNewArrows?: boolean,
) {
path.traverse(awaitVisitor, {
wrapAwait: helpers.wrapAwait,
});
const isIIFE = checkIsIIFE(path);
path.node.async = false;
path.node.generator = true;
wrapFunction(path, t.cloneNode(helpers.wrapAsync), noNewArrows);
const isProperty =
path.isObjectMethod() ||
path.isClassMethod() ||
path.parentPath.isObjectProperty() ||
path.parentPath.isClassProperty();
if (!isProperty && !isIIFE && path.isExpression()) {
annotateAsPure(path);
}
function checkIsIIFE(path: NodePath) {
if (path.parentPath.isCallExpression({ callee: path.node })) {
return true;
}
// try to catch calls to Function#bind, as emitted by arrowFunctionToExpression in spec mode
// this may also catch .bind(this) written by users, but does it matter? 🤔
const { parentPath } = path;
if (
parentPath.isMemberExpression() &&
t.isIdentifier(parentPath.node.property, { name: "bind" })
) {
const { parentPath: bindCall } = parentPath;
// (function () { ... }).bind(this)()
return (
// first, check if the .bind is actually being called
bindCall.isCallExpression() &&
// and whether its sole argument is 'this'
bindCall.node.arguments.length === 1 &&
t.isThisExpression(bindCall.node.arguments[0]) &&
// and whether the result of the .bind(this) is being called
bindCall.parentPath.isCallExpression({ callee: bindCall.node })
);
}
return false;
}
}