/
index.ts
96 lines (81 loc) 路 2.29 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/* @noflow */
import type { NodePath } from "@babel/traverse";
import wrapFunction from "@babel/helper-wrap-function";
import annotateAsPure from "@babel/helper-annotate-as-pure";
import {
callExpression,
cloneNode,
isIdentifier,
isThisExpression,
yieldExpression,
} from "@babel/types";
const awaitVisitor = {
Function(path) {
path.skip();
},
AwaitExpression(path, { wrapAwait }) {
const argument = path.get("argument");
path.replaceWith(
yieldExpression(
wrapAwait
? callExpression(cloneNode(wrapAwait), [argument.node])
: argument.node,
),
);
},
};
export default function (
path: NodePath<any>,
helpers: {
wrapAsync: any;
wrapAwait?: any;
},
noNewArrows?: boolean,
ignoreFunctionLength?: boolean,
) {
path.traverse(awaitVisitor, {
wrapAwait: helpers.wrapAwait,
});
const isIIFE = checkIsIIFE(path);
path.node.async = false;
path.node.generator = true;
wrapFunction(
path,
cloneNode(helpers.wrapAsync),
noNewArrows,
ignoreFunctionLength,
);
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() &&
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 &&
isThisExpression(bindCall.node.arguments[0]) &&
// and whether the result of the .bind(this) is being called
bindCall.parentPath.isCallExpression({ callee: bindCall.node })
);
}
return false;
}
}