-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathunwrapIIFEs.js
57 lines (56 loc) · 1.96 KB
/
unwrapIIFEs.js
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
/**
* Replace IIFEs that are unwrapping a function with the unwraped function.
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function unwrapIIFEs(arb, candidateFilter = () => true) {
const relevantNodes = [
...(arb.ast[0].typeMap.CallExpression || []),
];
candidatesLoop: for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (!n.arguments.length &&
['ArrowFunctionExpression', 'FunctionExpression'].includes(n.callee.type) &&
!n.callee.id &&
// IIFEs with a single return statement
(((
n.callee.body.type !== 'BlockStatement' ||
(
n.callee.body.body.length === 1 &&
n.callee.body.body[0].type === 'ReturnStatement')
) &&
n.parentKey === 'init') ||
// Generic IIFE wrappers
(n.parentKey === 'ExpressionStatement' ||
n.parentKey === 'argument' &&
n.parentNode.type === 'UnaryExpression')) &&
candidateFilter(n)) {
let targetNode = n;
let replacementNode = n.callee.body;
if (replacementNode.type === 'BlockStatement') {
let targetChild = replacementNode;
// IIFEs with a single return statement
if (replacementNode.body?.[0]?.argument) replacementNode = replacementNode.body[0].argument;
// IIFEs with multiple statements or expressions
else while (targetNode && !targetNode.body) {
// Skip cases where IIFE is used to initialize or set a value
if (targetNode.parentKey === 'init' || targetNode.type === 'AssignmentExpression' ) continue candidatesLoop;
targetChild = targetNode;
targetNode = targetNode.parentNode;
}
if (!targetNode?.body?.filter) targetNode = n;
else {
// Place the wrapped code instead of the wrapper node
replacementNode = {
...targetNode,
body: [...targetNode.body.filter(t => t !== targetChild), ...replacementNode.body],
};
}
}
arb.markNode(targetNode, replacementNode);
}
}
return arb;
}
export default unwrapIIFEs;