forked from babel/babel
-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.ts
85 lines (77 loc) · 2.63 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
import { declare } from "@babel/helper-plugin-utils";
import syntaxClassStaticBlock from "@babel/plugin-syntax-class-static-block";
import {
enableFeature,
FEATURES,
} from "@babel/helper-create-class-features-plugin";
import type * as t from "@babel/types";
import type { NodePath } from "@babel/traverse";
/**
* Generate a uid that is not in `denyList`
*
* @param {*} scope
* @param {Set<string>} denyList a deny list that the generated uid should avoid
* @returns
*/
function generateUid(scope, denyList: Set<string>) {
const name = "";
let uid;
let i = 1;
do {
uid = scope._generateUid(name, i);
i++;
} while (denyList.has(uid));
return uid;
}
export default declare(({ types: t, template, assertVersion }) => {
assertVersion("^7.12.0");
return {
name: "proposal-class-static-block",
inherits: syntaxClassStaticBlock.default,
pre() {
// Enable this in @babel/helper-create-class-features-plugin, so that it
// can be handled by the private fields and methods transform.
enableFeature(this.file, FEATURES.staticBlocks, /* loose */ false);
},
visitor: {
// Run on ClassBody and not on class so that if @babel/helper-create-class-features-plugin
// is enabled it can generte optimized output without passing from the intermediate
// private fields representation.
ClassBody(classBody: NodePath<t.ClassBody>) {
const { scope } = classBody;
const privateNames = new Set<string>();
const body = classBody.get("body");
for (const path of body) {
if (path.isPrivate()) {
privateNames.add(path.get("key.id").node.name);
}
}
for (const path of body) {
if (!path.isStaticBlock()) continue;
const staticBlockPrivateId = generateUid(scope, privateNames);
privateNames.add(staticBlockPrivateId);
const staticBlockRef = t.privateName(
t.identifier(staticBlockPrivateId),
);
let replacement;
const blockBody = path.node.body;
// We special-case the single expression case to avoid the iife, since
// it's common.
if (blockBody.length === 1 && t.isExpressionStatement(blockBody[0])) {
replacement = (blockBody[0] as t.ExpressionStatement).expression;
} else {
replacement = template.expression.ast`(() => { ${blockBody} })()`;
}
path.replaceWith(
t.classPrivateProperty(
staticBlockRef,
replacement,
[],
/* static */ true,
),
);
}
},
},
};
});