-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathbabel-plugin-inline-const-enum.mts
More file actions
150 lines (131 loc) · 3.96 KB
/
babel-plugin-inline-const-enum.mts
File metadata and controls
150 lines (131 loc) · 3.96 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* @file Babel plugin to inline TypeScript const enum member access. Replaces
* enum member access with literal values when enum definition is available.
* Note: TypeScript normally handles this during compilation. This plugin is
* useful for post-processing compiled code or handling external modules.
*/
/**
* Get the value from a literal node.
*/
function getLiteralValue(t, node) {
if (t.isNullLiteral(node)) {
return undefined
}
return node.value
}
/**
* Check if a node is a literal value.
*/
function isLiteralValue(t, node) {
return (
t.isNumericLiteral(node) ||
t.isStringLiteral(node) ||
t.isBooleanLiteral(node) ||
t.isNullLiteral(node)
)
}
/**
* Convert a value to a Babel AST literal node.
*/
export function valueToLiteral(t, value) {
if (value === null) {
return t.nullLiteral()
}
if (value === undefined) {
return t.identifier('undefined')
}
if (typeof value === 'string') {
return t.stringLiteral(value)
}
if (typeof value === 'number') {
return t.numericLiteral(value)
}
if (typeof value === 'boolean') {
return t.booleanLiteral(value)
}
throw new Error(`Unsupported enum value type: ${typeof value}`)
}
/**
* Babel plugin to inline const enum values.
*
* Transforms: MyEnum.Value → 42 (if MyEnum.Value = 42 in the enum definition)
*
* Usage: Pass enum definitions via options.enums: { enums: { MyEnum: { Value1:
* 0, Value2: 1 } } }
*
* Or let the plugin scan the code for enum declarations (limited support).
*
* @param {object} babel - Babel API object.
* @param {object} options - Plugin options.
* @param {Record<string, Record<string, any>>} [options.enums] - Enum
* definitions.
* @param {boolean} [options.scanDeclarations=false] - Auto-detect enum
* declarations.
*
* @returns {object} Babel plugin object
*/
export default function inlineConstEnum(babel, options = {}) {
const { types: t } = babel
const { enums = {}, scanDeclarations = false } = options
// Map of enum name to member values.
const enumMap = new Map(Object.entries(enums))
return {
name: 'inline-const-enum',
visitor: {
// Scan for enum declarations if enabled.
// Note: This has limited support and may not catch all cases.
VariableDeclaration(path) {
if (!scanDeclarations) {
return
}
// Look for: const MyEnum = { Value: 0, ... }
const { declarations } = path.node
for (let i = 0, { length } = declarations; i < length; i += 1) {
const decl = declarations[i]
if (
!t.isVariableDeclarator(decl) ||
!t.isIdentifier(decl.id) ||
!t.isObjectExpression(decl.init)
) {
continue
}
const enumName = decl.id.name
const enumValues = {}
// Extract property values.
for (const prop of decl.init.properties) {
if (
!t.isObjectProperty(prop) ||
!t.isIdentifier(prop.key) ||
!isLiteralValue(t, prop.value)
) {
continue
}
enumValues[prop.key.name] = getLiteralValue(t, prop.value)
}
if (Object.keys(enumValues).length > 0) {
enumMap.set(enumName, enumValues)
}
}
},
// Inline enum member access: MyEnum.Value
MemberExpression(path) {
const { object, property } = path.node
// Match: EnumName.MemberName
if (!t.isIdentifier(object) || !t.isIdentifier(property)) {
return
}
const enumName = object.name
const memberName = property.name
// Check if we have this enum.
const enumDef = enumMap.get(enumName)
if (!enumDef || !(memberName in enumDef)) {
return
}
const value = enumDef[memberName]
// Replace with literal value.
const replacement = valueToLiteral(t, value)
path.replaceWith(replacement)
},
},
}
}