webfuscator 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/DISCLOSURE +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +83 -0
  4. package/dist/analysis/constant.d.ts +11 -0
  5. package/dist/analysis/constant.d.ts.map +1 -0
  6. package/dist/analysis/constant.js +261 -0
  7. package/dist/analysis/constant.js.map +1 -0
  8. package/dist/analysis/document-order.d.ts +5 -0
  9. package/dist/analysis/document-order.d.ts.map +1 -0
  10. package/dist/analysis/document-order.js +124 -0
  11. package/dist/analysis/document-order.js.map +1 -0
  12. package/dist/analysis/inlineability.d.ts +13 -0
  13. package/dist/analysis/inlineability.d.ts.map +1 -0
  14. package/dist/analysis/inlineability.js +270 -0
  15. package/dist/analysis/inlineability.js.map +1 -0
  16. package/dist/analysis/purity.d.ts +5 -0
  17. package/dist/analysis/purity.d.ts.map +1 -0
  18. package/dist/analysis/purity.js +281 -0
  19. package/dist/analysis/purity.js.map +1 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/obfuscator.d.ts +4 -0
  25. package/dist/obfuscator.d.ts.map +1 -0
  26. package/dist/obfuscator.js +222 -0
  27. package/dist/obfuscator.js.map +1 -0
  28. package/dist/options.d.ts +73 -0
  29. package/dist/options.d.ts.map +1 -0
  30. package/dist/options.js +2 -0
  31. package/dist/options.js.map +1 -0
  32. package/dist/preparation/dot-to-bracket.d.ts +16 -0
  33. package/dist/preparation/dot-to-bracket.d.ts.map +1 -0
  34. package/dist/preparation/dot-to-bracket.js +36 -0
  35. package/dist/preparation/dot-to-bracket.js.map +1 -0
  36. package/dist/preparation/expand-destructuring.d.ts +26 -0
  37. package/dist/preparation/expand-destructuring.d.ts.map +1 -0
  38. package/dist/preparation/expand-destructuring.js +154 -0
  39. package/dist/preparation/expand-destructuring.js.map +1 -0
  40. package/dist/preparation/expand-template-literals.d.ts +23 -0
  41. package/dist/preparation/expand-template-literals.d.ts.map +1 -0
  42. package/dist/preparation/expand-template-literals.js +78 -0
  43. package/dist/preparation/expand-template-literals.js.map +1 -0
  44. package/dist/preparation/rewrite-class-fields.d.ts +43 -0
  45. package/dist/preparation/rewrite-class-fields.d.ts.map +1 -0
  46. package/dist/preparation/rewrite-class-fields.js +270 -0
  47. package/dist/preparation/rewrite-class-fields.js.map +1 -0
  48. package/dist/preparation/split-sequence-expressions.d.ts +15 -0
  49. package/dist/preparation/split-sequence-expressions.d.ts.map +1 -0
  50. package/dist/preparation/split-sequence-expressions.js +36 -0
  51. package/dist/preparation/split-sequence-expressions.js.map +1 -0
  52. package/dist/preparation/split-variable-declarations.d.ts +20 -0
  53. package/dist/preparation/split-variable-declarations.d.ts.map +1 -0
  54. package/dist/preparation/split-variable-declarations.js +36 -0
  55. package/dist/preparation/split-variable-declarations.js.map +1 -0
  56. package/dist/preparation/stringify-object-keys.d.ts +21 -0
  57. package/dist/preparation/stringify-object-keys.d.ts.map +1 -0
  58. package/dist/preparation/stringify-object-keys.js +96 -0
  59. package/dist/preparation/stringify-object-keys.js.map +1 -0
  60. package/dist/preparation/wrap-single-statements.d.ts +24 -0
  61. package/dist/preparation/wrap-single-statements.d.ts.map +1 -0
  62. package/dist/preparation/wrap-single-statements.js +53 -0
  63. package/dist/preparation/wrap-single-statements.js.map +1 -0
  64. package/dist/transforms/arguments-to-parameters.d.ts +20 -0
  65. package/dist/transforms/arguments-to-parameters.d.ts.map +1 -0
  66. package/dist/transforms/arguments-to-parameters.js +162 -0
  67. package/dist/transforms/arguments-to-parameters.js.map +1 -0
  68. package/dist/transforms/arrow-to-function.d.ts +46 -0
  69. package/dist/transforms/arrow-to-function.d.ts.map +1 -0
  70. package/dist/transforms/arrow-to-function.js +203 -0
  71. package/dist/transforms/arrow-to-function.js.map +1 -0
  72. package/dist/transforms/collapse-single-use-temps.d.ts +16 -0
  73. package/dist/transforms/collapse-single-use-temps.d.ts.map +1 -0
  74. package/dist/transforms/collapse-single-use-temps.js +805 -0
  75. package/dist/transforms/collapse-single-use-temps.js.map +1 -0
  76. package/dist/transforms/const-let-to-var.d.ts +21 -0
  77. package/dist/transforms/const-let-to-var.d.ts.map +1 -0
  78. package/dist/transforms/const-let-to-var.js +217 -0
  79. package/dist/transforms/const-let-to-var.js.map +1 -0
  80. package/dist/transforms/const-to-let.d.ts +17 -0
  81. package/dist/transforms/const-to-let.d.ts.map +1 -0
  82. package/dist/transforms/const-to-let.js +33 -0
  83. package/dist/transforms/const-to-let.js.map +1 -0
  84. package/dist/transforms/do-while-to-while.d.ts +26 -0
  85. package/dist/transforms/do-while-to-while.d.ts.map +1 -0
  86. package/dist/transforms/do-while-to-while.js +54 -0
  87. package/dist/transforms/do-while-to-while.js.map +1 -0
  88. package/dist/transforms/drop-console.d.ts +27 -0
  89. package/dist/transforms/drop-console.d.ts.map +1 -0
  90. package/dist/transforms/drop-console.js +107 -0
  91. package/dist/transforms/drop-console.js.map +1 -0
  92. package/dist/transforms/drop-debugger.d.ts +18 -0
  93. package/dist/transforms/drop-debugger.d.ts.map +1 -0
  94. package/dist/transforms/drop-debugger.js +34 -0
  95. package/dist/transforms/drop-debugger.js.map +1 -0
  96. package/dist/transforms/expand-binary-assignment.d.ts +26 -0
  97. package/dist/transforms/expand-binary-assignment.d.ts.map +1 -0
  98. package/dist/transforms/expand-binary-assignment.js +78 -0
  99. package/dist/transforms/expand-binary-assignment.js.map +1 -0
  100. package/dist/transforms/expand-logical-assignment.d.ts +22 -0
  101. package/dist/transforms/expand-logical-assignment.d.ts.map +1 -0
  102. package/dist/transforms/expand-logical-assignment.js +73 -0
  103. package/dist/transforms/expand-logical-assignment.js.map +1 -0
  104. package/dist/transforms/extract-object-properties.d.ts +21 -0
  105. package/dist/transforms/extract-object-properties.d.ts.map +1 -0
  106. package/dist/transforms/extract-object-properties.js +340 -0
  107. package/dist/transforms/extract-object-properties.js.map +1 -0
  108. package/dist/transforms/fold-builtin-methods.d.ts +23 -0
  109. package/dist/transforms/fold-builtin-methods.d.ts.map +1 -0
  110. package/dist/transforms/fold-builtin-methods.js +839 -0
  111. package/dist/transforms/fold-builtin-methods.js.map +1 -0
  112. package/dist/transforms/fold-constants.d.ts +16 -0
  113. package/dist/transforms/fold-constants.d.ts.map +1 -0
  114. package/dist/transforms/fold-constants.js +421 -0
  115. package/dist/transforms/fold-constants.js.map +1 -0
  116. package/dist/transforms/for-to-while.d.ts +29 -0
  117. package/dist/transforms/for-to-while.d.ts.map +1 -0
  118. package/dist/transforms/for-to-while.js +91 -0
  119. package/dist/transforms/for-to-while.js.map +1 -0
  120. package/dist/transforms/function-declaration-to-expression.d.ts +28 -0
  121. package/dist/transforms/function-declaration-to-expression.d.ts.map +1 -0
  122. package/dist/transforms/function-declaration-to-expression.js +95 -0
  123. package/dist/transforms/function-declaration-to-expression.js.map +1 -0
  124. package/dist/transforms/inline-functions.d.ts +16 -0
  125. package/dist/transforms/inline-functions.d.ts.map +1 -0
  126. package/dist/transforms/inline-functions.js +896 -0
  127. package/dist/transforms/inline-functions.js.map +1 -0
  128. package/dist/transforms/logical-to-ternary.d.ts +20 -0
  129. package/dist/transforms/logical-to-ternary.d.ts.map +1 -0
  130. package/dist/transforms/logical-to-ternary.js +78 -0
  131. package/dist/transforms/logical-to-ternary.js.map +1 -0
  132. package/dist/transforms/mangle-properties.d.ts +27 -0
  133. package/dist/transforms/mangle-properties.d.ts.map +1 -0
  134. package/dist/transforms/mangle-properties.js +703 -0
  135. package/dist/transforms/mangle-properties.js.map +1 -0
  136. package/dist/transforms/nullish-coalescing-to-ternary.d.ts +18 -0
  137. package/dist/transforms/nullish-coalescing-to-ternary.d.ts.map +1 -0
  138. package/dist/transforms/nullish-coalescing-to-ternary.js +61 -0
  139. package/dist/transforms/nullish-coalescing-to-ternary.js.map +1 -0
  140. package/dist/transforms/numbers-to-strings.d.ts +19 -0
  141. package/dist/transforms/numbers-to-strings.d.ts.map +1 -0
  142. package/dist/transforms/numbers-to-strings.js +51 -0
  143. package/dist/transforms/numbers-to-strings.js.map +1 -0
  144. package/dist/transforms/object-method-to-property.d.ts +34 -0
  145. package/dist/transforms/object-method-to-property.d.ts.map +1 -0
  146. package/dist/transforms/object-method-to-property.js +78 -0
  147. package/dist/transforms/object-method-to-property.js.map +1 -0
  148. package/dist/transforms/optional-chaining-to-ternary.d.ts +19 -0
  149. package/dist/transforms/optional-chaining-to-ternary.d.ts.map +1 -0
  150. package/dist/transforms/optional-chaining-to-ternary.js +206 -0
  151. package/dist/transforms/optional-chaining-to-ternary.js.map +1 -0
  152. package/dist/transforms/pack-declarations-into-parameters.d.ts +22 -0
  153. package/dist/transforms/pack-declarations-into-parameters.d.ts.map +1 -0
  154. package/dist/transforms/pack-declarations-into-parameters.js +208 -0
  155. package/dist/transforms/pack-declarations-into-parameters.js.map +1 -0
  156. package/dist/transforms/remove-anonymous-function-names.d.ts +17 -0
  157. package/dist/transforms/remove-anonymous-function-names.d.ts.map +1 -0
  158. package/dist/transforms/remove-anonymous-function-names.js +72 -0
  159. package/dist/transforms/remove-anonymous-function-names.js.map +1 -0
  160. package/dist/transforms/remove-unreachable-code.d.ts +21 -0
  161. package/dist/transforms/remove-unreachable-code.d.ts.map +1 -0
  162. package/dist/transforms/remove-unreachable-code.js +103 -0
  163. package/dist/transforms/remove-unreachable-code.js.map +1 -0
  164. package/dist/transforms/remove-unused-code.d.ts +18 -0
  165. package/dist/transforms/remove-unused-code.d.ts.map +1 -0
  166. package/dist/transforms/remove-unused-code.js +249 -0
  167. package/dist/transforms/remove-unused-code.js.map +1 -0
  168. package/dist/transforms/rename-identifiers.d.ts +24 -0
  169. package/dist/transforms/rename-identifiers.d.ts.map +1 -0
  170. package/dist/transforms/rename-identifiers.js +264 -0
  171. package/dist/transforms/rename-identifiers.js.map +1 -0
  172. package/dist/transforms/specials-to-strings.d.ts +30 -0
  173. package/dist/transforms/specials-to-strings.d.ts.map +1 -0
  174. package/dist/transforms/specials-to-strings.js +101 -0
  175. package/dist/transforms/specials-to-strings.js.map +1 -0
  176. package/dist/transforms/switch-to-if.d.ts +28 -0
  177. package/dist/transforms/switch-to-if.d.ts.map +1 -0
  178. package/dist/transforms/switch-to-if.js +279 -0
  179. package/dist/transforms/switch-to-if.js.map +1 -0
  180. package/dist/transforms/ternary-to-if.d.ts +20 -0
  181. package/dist/transforms/ternary-to-if.d.ts.map +1 -0
  182. package/dist/transforms/ternary-to-if.js +315 -0
  183. package/dist/transforms/ternary-to-if.js.map +1 -0
  184. package/dist/transforms/update-to-assignment.d.ts +26 -0
  185. package/dist/transforms/update-to-assignment.d.ts.map +1 -0
  186. package/dist/transforms/update-to-assignment.js +120 -0
  187. package/dist/transforms/update-to-assignment.js.map +1 -0
  188. package/dist/transforms/yodify-conditions.d.ts +22 -0
  189. package/dist/transforms/yodify-conditions.d.ts.map +1 -0
  190. package/dist/transforms/yodify-conditions.js +91 -0
  191. package/dist/transforms/yodify-conditions.js.map +1 -0
  192. package/dist/utils/ast.d.ts +10 -0
  193. package/dist/utils/ast.d.ts.map +1 -0
  194. package/dist/utils/ast.js +112 -0
  195. package/dist/utils/ast.js.map +1 -0
  196. package/dist/utils/change-tracking.d.ts +8 -0
  197. package/dist/utils/change-tracking.d.ts.map +1 -0
  198. package/dist/utils/change-tracking.js +8 -0
  199. package/dist/utils/change-tracking.js.map +1 -0
  200. package/dist/utils/dom-properties.d.ts +2 -0
  201. package/dist/utils/dom-properties.d.ts.map +1 -0
  202. package/dist/utils/dom-properties.js +9252 -0
  203. package/dist/utils/dom-properties.js.map +1 -0
  204. package/dist/utils/evaluation-order.d.ts +4 -0
  205. package/dist/utils/evaluation-order.d.ts.map +1 -0
  206. package/dist/utils/evaluation-order.js +152 -0
  207. package/dist/utils/evaluation-order.js.map +1 -0
  208. package/dist/utils/literal.d.ts +5 -0
  209. package/dist/utils/literal.d.ts.map +1 -0
  210. package/dist/utils/literal.js +90 -0
  211. package/dist/utils/literal.js.map +1 -0
  212. package/dist/utils/logical-lowering.d.ts +4 -0
  213. package/dist/utils/logical-lowering.d.ts.map +1 -0
  214. package/dist/utils/logical-lowering.js +104 -0
  215. package/dist/utils/logical-lowering.js.map +1 -0
  216. package/dist/utils/loop-lowering.d.ts +23 -0
  217. package/dist/utils/loop-lowering.d.ts.map +1 -0
  218. package/dist/utils/loop-lowering.js +88 -0
  219. package/dist/utils/loop-lowering.js.map +1 -0
  220. package/dist/utils/paths.d.ts +9 -0
  221. package/dist/utils/paths.d.ts.map +1 -0
  222. package/dist/utils/paths.js +90 -0
  223. package/dist/utils/paths.js.map +1 -0
  224. package/dist/utils/random.d.ts +3 -0
  225. package/dist/utils/random.d.ts.map +1 -0
  226. package/dist/utils/random.js +22 -0
  227. package/dist/utils/random.js.map +1 -0
  228. package/dist/utils/string-generator.d.ts +37 -0
  229. package/dist/utils/string-generator.d.ts.map +1 -0
  230. package/dist/utils/string-generator.js +175 -0
  231. package/dist/utils/string-generator.js.map +1 -0
  232. package/package.json +76 -0
  233. package/src/analysis/constant.ts +310 -0
  234. package/src/analysis/document-order.ts +141 -0
  235. package/src/analysis/inlineability.ts +336 -0
  236. package/src/analysis/purity.ts +315 -0
  237. package/src/index.ts +2 -0
  238. package/src/obfuscator.ts +271 -0
  239. package/src/options.ts +114 -0
  240. package/src/preparation/dot-to-bracket.ts +41 -0
  241. package/src/preparation/expand-destructuring.ts +211 -0
  242. package/src/preparation/expand-template-literals.ts +92 -0
  243. package/src/preparation/rewrite-class-fields.ts +320 -0
  244. package/src/preparation/split-sequence-expressions.ts +40 -0
  245. package/src/preparation/split-variable-declarations.ts +39 -0
  246. package/src/preparation/stringify-object-keys.ts +107 -0
  247. package/src/preparation/wrap-single-statements.ts +63 -0
  248. package/src/transforms/arguments-to-parameters.ts +187 -0
  249. package/src/transforms/arrow-to-function.ts +225 -0
  250. package/src/transforms/collapse-single-use-temps.ts +957 -0
  251. package/src/transforms/const-let-to-var.ts +246 -0
  252. package/src/transforms/const-to-let.ts +38 -0
  253. package/src/transforms/do-while-to-while.ts +69 -0
  254. package/src/transforms/drop-console.ts +119 -0
  255. package/src/transforms/drop-debugger.ts +38 -0
  256. package/src/transforms/expand-binary-assignment.ts +94 -0
  257. package/src/transforms/expand-logical-assignment.ts +84 -0
  258. package/src/transforms/extract-object-properties.ts +404 -0
  259. package/src/transforms/fold-builtin-methods.ts +949 -0
  260. package/src/transforms/fold-constants.ts +462 -0
  261. package/src/transforms/for-to-while.ts +109 -0
  262. package/src/transforms/function-declaration-to-expression.ts +108 -0
  263. package/src/transforms/inline-functions.ts +1074 -0
  264. package/src/transforms/logical-to-ternary.ts +92 -0
  265. package/src/transforms/mangle-properties.ts +819 -0
  266. package/src/transforms/nullish-coalescing-to-ternary.ts +77 -0
  267. package/src/transforms/numbers-to-strings.ts +61 -0
  268. package/src/transforms/object-method-to-property.ts +86 -0
  269. package/src/transforms/optional-chaining-to-ternary.ts +225 -0
  270. package/src/transforms/pack-declarations-into-parameters.ts +233 -0
  271. package/src/transforms/remove-anonymous-function-names.ts +84 -0
  272. package/src/transforms/remove-unreachable-code.ts +115 -0
  273. package/src/transforms/remove-unused-code.ts +296 -0
  274. package/src/transforms/rename-identifiers.ts +289 -0
  275. package/src/transforms/specials-to-strings.ts +116 -0
  276. package/src/transforms/switch-to-if.ts +339 -0
  277. package/src/transforms/ternary-to-if.ts +387 -0
  278. package/src/transforms/update-to-assignment.ts +132 -0
  279. package/src/transforms/yodify-conditions.ts +103 -0
  280. package/src/utils/ast.ts +129 -0
  281. package/src/utils/change-tracking.ts +15 -0
  282. package/src/utils/dom-properties.ts +9252 -0
  283. package/src/utils/evaluation-order.ts +178 -0
  284. package/src/utils/literal.ts +96 -0
  285. package/src/utils/logical-lowering.ts +132 -0
  286. package/src/utils/loop-lowering.ts +109 -0
  287. package/src/utils/paths.ts +103 -0
  288. package/src/utils/random.ts +22 -0
  289. package/src/utils/string-generator.ts +206 -0
@@ -0,0 +1,819 @@
1
+ import traverse from '@babel/traverse'
2
+ import type { NodePath, Scope, Visitor } from '@babel/traverse'
3
+ import * as t from '@babel/types'
4
+ import type { File } from '@babel/types'
5
+
6
+ import { evaluateConstant, isOpaque } from 'src/analysis/constant'
7
+ import type { ManglePropertiesOptions, PropertyNameGenerator, TransformContext } from 'src/options'
8
+ import { isProtoKey } from 'src/utils/ast'
9
+ import type { ChangeState } from 'src/utils/change-tracking'
10
+ import { DOM_PROPERTIES } from 'src/utils/dom-properties'
11
+ import { mulberry32 } from 'src/utils/random'
12
+ import { StringGenerator } from 'src/utils/string-generator'
13
+
14
+ /**
15
+ * Renames statically known public properties through one program-wide mapping.
16
+ * Property selection follows Terser, with extra collision checks for names
17
+ * that this pipeline must leave unchanged.
18
+ *
19
+ * This pass runs before shape preparation, while Babel still distinguishes
20
+ * `obj.name` from `obj["name"]` and class fields still carry their source keys.
21
+ *
22
+ * @example
23
+ * // ◀️ before
24
+ * var counter = {
25
+ * current_: 1,
26
+ * increment_() { return ++this.current_; }
27
+ * };
28
+ * log(counter.increment_());
29
+ *
30
+ * // ▶️ after
31
+ * var counter = {
32
+ * a: 1,
33
+ * b() { return ++this.a; }
34
+ * };
35
+ * log(counter.b());
36
+ */
37
+ export function mangleProperties(ast: File, ctx: TransformContext): boolean {
38
+ const state = new PropertyManglerState(ctx)
39
+ traverse(ast, prepareVisitor, undefined, state)
40
+ traverse(ast, collectVisitor, undefined, state)
41
+ state.finalizeCandidates()
42
+ traverse(ast, rewriteVisitor, undefined, state)
43
+ return state.changed
44
+ }
45
+
46
+ const MANGLE_PROPERTY_ANNOTATION = '__MANGLE_PROP__'
47
+ const PROPERTY_KEY_ANNOTATION = '__KEY__'
48
+ const NUMERIC_PROPERTY_RE = /^-?[0-9]+(?:\.[0-9]+)?(?:e[+-][0-9]+)?$/u
49
+ const SYNTAX_SENSITIVE_GENERATED_NAMES = new Set(['__proto__', 'constructor', 'prototype'])
50
+ const MAX_GENERATOR_ATTEMPTS = 100_000
51
+
52
+ type KeyedProperty =
53
+ | t.ClassAccessorProperty
54
+ | t.ClassMethod
55
+ | t.ClassProperty
56
+ | t.ObjectMethod
57
+ | t.ObjectProperty
58
+
59
+ type Member = t.MemberExpression | t.OptionalMemberExpression
60
+ type Call = t.CallExpression | t.OptionalCallExpression
61
+
62
+ class PropertyManglerState implements ChangeState {
63
+ changed = false
64
+ readonly annotated = new Set<string>()
65
+ readonly candidates = new Set<string>()
66
+ readonly cache: Map<string, string>
67
+ readonly keepQuoted: boolean | 'strict'
68
+ readonly onlyAnnotated: boolean
69
+ readonly onlyCache: boolean
70
+ readonly reserved: Set<string>
71
+ readonly rewrittenKeyAnnotations = new WeakSet<t.StringLiteral>()
72
+ readonly undeclared: boolean
73
+
74
+ private readonly blockedCacheSources = new Set<string>()
75
+ private readonly debugSuffix: string | null
76
+ private readonly emittedNames = new Set<string>()
77
+ private readonly nameGenerator: PropertyNameGenerator
78
+ private readonly regex: RegExp | null
79
+ private readonly skippedUndeclaredNames = new Set<string>()
80
+ private readonly unavailableOutputs = new Set<string>()
81
+ private nameIndex = 0
82
+
83
+ constructor(ctx: TransformContext) {
84
+ const options = ctx.mangleProperties ?? {}
85
+ this.cache = options.cache ?? new Map()
86
+ this.keepQuoted = options.keepQuoted ?? false
87
+ this.onlyAnnotated = options.onlyAnnotated ?? false
88
+ this.onlyCache = options.onlyCache ?? false
89
+ this.reserved = new Set(options.reserved)
90
+ this.undeclared = options.undeclared ?? false
91
+ this.debugSuffix = debugSuffix(options.debug)
92
+ this.regex = compileRegex(options.regex)
93
+
94
+ if (!options.builtins) {
95
+ for (const name of builtinProperties()) {
96
+ this.reserved.add(name)
97
+ }
98
+ }
99
+
100
+ const cachedNames = new Set<string>()
101
+ for (const [name, mangled] of this.cache) {
102
+ if (typeof name !== 'string' || typeof mangled !== 'string') {
103
+ throw new TypeError('mangleProperties.cache must map strings to strings')
104
+ }
105
+ if (SYNTAX_SENSITIVE_GENERATED_NAMES.has(mangled)) {
106
+ throw new TypeError(`mangleProperties.cache cannot emit ${JSON.stringify(mangled)}`)
107
+ }
108
+ if (cachedNames.has(mangled)) {
109
+ throw new TypeError(
110
+ `mangleProperties.cache contains duplicate output ${JSON.stringify(mangled)}`,
111
+ )
112
+ }
113
+ cachedNames.add(mangled)
114
+ this.emittedNames.add(mangled)
115
+ }
116
+
117
+ if (options.nameGenerator) {
118
+ this.nameGenerator = options.nameGenerator
119
+ } else {
120
+ const generator = new StringGenerator(ctx.stringGeneratorMode, mulberry32(ctx.seed))
121
+ this.nameGenerator = (index) => generator.at(index)
122
+ }
123
+ }
124
+
125
+ addCandidate(name: string): void {
126
+ if (this.canSelect(name)) {
127
+ this.candidates.add(name)
128
+ }
129
+ if (!this.shouldMangle(name)) {
130
+ this.unavailableOutputs.add(name)
131
+ }
132
+ }
133
+
134
+ retainName(name: string): void {
135
+ this.unavailableOutputs.add(name)
136
+ }
137
+
138
+ reserveName(name: string): void {
139
+ this.reserved.add(name)
140
+ this.unavailableOutputs.add(name)
141
+ }
142
+
143
+ skipUndeclaredName(name: string): void {
144
+ this.skippedUndeclaredNames.add(name)
145
+ }
146
+
147
+ finalizeCandidates(): void {
148
+ for (const name of this.skippedUndeclaredNames) {
149
+ if (!this.shouldMangle(name)) {
150
+ this.unavailableOutputs.add(name)
151
+ }
152
+ }
153
+
154
+ const sourceByOutput = new Map<string, string>()
155
+ for (const [source, output] of this.cache) {
156
+ if (source === output || !this.shouldMangle(source)) {
157
+ continue
158
+ }
159
+ sourceByOutput.set(output, source)
160
+ }
161
+
162
+ // A blocked endpoint in a cached rename chain makes every predecessor
163
+ // unsafe too, since its output would collide with the retained source.
164
+ const pending = [...this.unavailableOutputs]
165
+ for (const output of pending) {
166
+ const source = sourceByOutput.get(output)
167
+ if (source === undefined || this.blockedCacheSources.has(source)) {
168
+ continue
169
+ }
170
+ this.blockedCacheSources.add(source)
171
+ if (!this.unavailableOutputs.has(source)) {
172
+ this.unavailableOutputs.add(source)
173
+ pending.push(source)
174
+ }
175
+ }
176
+ }
177
+
178
+ mangle(name: string): string {
179
+ if (!this.shouldMangle(name)) {
180
+ return name
181
+ }
182
+
183
+ const cached = this.cache.get(name)
184
+ if (cached !== undefined || this.cache.has(name)) {
185
+ return cached!
186
+ }
187
+
188
+ let mangled = this.debugName(name)
189
+ if (mangled === null) {
190
+ mangled = this.nextGeneratedName()
191
+ }
192
+ this.cache.set(name, mangled)
193
+ this.emittedNames.add(mangled)
194
+ return mangled
195
+ }
196
+
197
+ private canSelect(name: string): boolean {
198
+ if (this.reserved.has(name)) {
199
+ return false
200
+ }
201
+ if (this.onlyCache) {
202
+ return this.cache.has(name)
203
+ }
204
+ return !NUMERIC_PROPERTY_RE.test(name)
205
+ }
206
+
207
+ private debugName(name: string): string | null {
208
+ if (this.debugSuffix === null) {
209
+ return null
210
+ }
211
+ const candidate = `_$${name}$${this.debugSuffix}_`
212
+ return this.isAvailableOutput(candidate) ? candidate : null
213
+ }
214
+
215
+ private matchesRegex(name: string): boolean {
216
+ if (this.regex === null) {
217
+ return true
218
+ }
219
+ this.regex.lastIndex = 0
220
+ return this.regex.test(name)
221
+ }
222
+
223
+ private nextGeneratedName(): string {
224
+ for (let attempt = 0; attempt < MAX_GENERATOR_ATTEMPTS; attempt++) {
225
+ const candidate = this.nameGenerator(this.nameIndex++)
226
+ if (typeof candidate !== 'string') {
227
+ throw new TypeError('mangleProperties.nameGenerator must return a string')
228
+ }
229
+ if (this.isAvailableOutput(candidate)) {
230
+ return candidate
231
+ }
232
+ }
233
+ throw new Error('mangleProperties.nameGenerator did not produce an available name')
234
+ }
235
+
236
+ private shouldMangle(name: string): boolean {
237
+ if (this.blockedCacheSources.has(name)) {
238
+ return false
239
+ }
240
+ if (this.onlyAnnotated && !this.annotated.has(name)) {
241
+ return false
242
+ }
243
+ if (!this.matchesRegex(name) && !this.annotated.has(name)) {
244
+ return false
245
+ }
246
+ if (this.reserved.has(name)) {
247
+ return false
248
+ }
249
+ return this.cache.has(name) || this.candidates.has(name)
250
+ }
251
+
252
+ private isAvailableOutput(name: string): boolean {
253
+ return (
254
+ !SYNTAX_SENSITIVE_GENERATED_NAMES.has(name) &&
255
+ !NUMERIC_PROPERTY_RE.test(name) &&
256
+ !this.emittedNames.has(name) &&
257
+ !this.reserved.has(name) &&
258
+ !this.unavailableOutputs.has(name)
259
+ )
260
+ }
261
+ }
262
+
263
+ const prepareVisitor: Visitor<PropertyManglerState> = {
264
+ enter(path, state) {
265
+ if (isKeyedProperty(path.node)) {
266
+ prepareKeyedProperty(path as NodePath<KeyedProperty>, state)
267
+ return
268
+ }
269
+ if (t.isMemberExpression(path.node) || t.isOptionalMemberExpression(path.node)) {
270
+ prepareMember(path as NodePath<Member>, state)
271
+ }
272
+ },
273
+ }
274
+
275
+ const collectVisitor: Visitor<PropertyManglerState> = {
276
+ enter(path, state) {
277
+ if (isKeyedProperty(path.node)) {
278
+ collectKeyedProperty(path as NodePath<KeyedProperty>, state)
279
+ return
280
+ }
281
+ if (t.isMemberExpression(path.node) || t.isOptionalMemberExpression(path.node)) {
282
+ collectMember(path as NodePath<Member>, state)
283
+ return
284
+ }
285
+ if (t.isBinaryExpression(path.node) && path.node.operator === 'in') {
286
+ if (t.isExpression(path.node.left)) {
287
+ collectTerminalNames(path.node.left, path.scope, path, state)
288
+ }
289
+ return
290
+ }
291
+ if (
292
+ (t.isCallExpression(path.node) || t.isOptionalCallExpression(path.node)) &&
293
+ isObjectDefinePropertyCall(path as NodePath<Call>)
294
+ ) {
295
+ const [, key] = path.node.arguments
296
+ if (key && t.isExpression(key)) {
297
+ collectTerminalNames(key, path.scope, path, state)
298
+ }
299
+ return
300
+ }
301
+ if (t.isStringLiteral(path.node) && hasAnnotation(path.node, PROPERTY_KEY_ANNOTATION)) {
302
+ state.addCandidate(path.node.value)
303
+ }
304
+ },
305
+ }
306
+
307
+ const rewriteVisitor: Visitor<PropertyManglerState> = {
308
+ enter(path, state) {
309
+ if (isKeyedProperty(path.node)) {
310
+ rewriteKeyedProperty(path as NodePath<KeyedProperty>, state)
311
+ return
312
+ }
313
+ if (t.isMemberExpression(path.node) || t.isOptionalMemberExpression(path.node)) {
314
+ rewriteMember(path as NodePath<Member>, state)
315
+ return
316
+ }
317
+ if (t.isBinaryExpression(path.node) && path.node.operator === 'in') {
318
+ if (t.isExpression(path.node.left)) {
319
+ path.node.left = rewriteTerminalNames(path.node.left, path.scope, path, state)
320
+ }
321
+ return
322
+ }
323
+ if (
324
+ (t.isCallExpression(path.node) || t.isOptionalCallExpression(path.node)) &&
325
+ isObjectDefinePropertyCall(path as NodePath<Call>)
326
+ ) {
327
+ const [, key] = path.node.arguments
328
+ if (key && t.isExpression(key)) {
329
+ path.node.arguments[1] = rewriteTerminalNames(key, path.scope, path, state)
330
+ }
331
+ return
332
+ }
333
+ if (
334
+ t.isStringLiteral(path.node) &&
335
+ hasAnnotation(path.node, PROPERTY_KEY_ANNOTATION) &&
336
+ !state.rewrittenKeyAnnotations.has(path.node)
337
+ ) {
338
+ rewriteString(path.node, state)
339
+ }
340
+ },
341
+ }
342
+
343
+ function prepareKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
344
+ const { node } = path
345
+ if (isSemanticKey(node)) {
346
+ const name = plainKeyName(node.key)
347
+ if (name !== null) {
348
+ state.reserveName(name)
349
+ }
350
+ }
351
+ if (state.keepQuoted) {
352
+ protectQuotedKey(path, state)
353
+ }
354
+ if (
355
+ hasAnnotation(node, MANGLE_PROPERTY_ANNOTATION) ||
356
+ hasAnnotation(node.key, MANGLE_PROPERTY_ANNOTATION)
357
+ ) {
358
+ addAnnotatedKey(path, state)
359
+ }
360
+ }
361
+
362
+ function prepareMember(path: NodePath<Member>, state: PropertyManglerState): void {
363
+ const { node } = path
364
+ if (state.keepQuoted && node.computed && t.isExpression(node.property)) {
365
+ protectTerminalNames(node.property, path.scope, path, state)
366
+ }
367
+ if (memberHasMangleAnnotation(path)) {
368
+ addAnnotatedMember(path, state)
369
+ }
370
+ }
371
+
372
+ function protectQuotedKey(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
373
+ const { node } = path
374
+ if (node.computed) {
375
+ if (t.isExpression(node.key)) {
376
+ protectTerminalNames(node.key, path.scope, path, state)
377
+ }
378
+ } else if (t.isStringLiteral(node.key)) {
379
+ protectName(node.key.value, state)
380
+ }
381
+ }
382
+
383
+ function protectTerminalNames(
384
+ node: t.Expression,
385
+ scope: Scope,
386
+ referencePath: NodePath,
387
+ state: PropertyManglerState,
388
+ ): void {
389
+ forEachTerminalName(node, scope, referencePath, (name) => protectName(name, state))
390
+ }
391
+
392
+ function protectName(name: string, state: PropertyManglerState): void {
393
+ if (state.keepQuoted === true) {
394
+ state.reserveName(name)
395
+ } else {
396
+ state.retainName(name)
397
+ }
398
+ }
399
+
400
+ function addAnnotatedKey(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
401
+ const { node } = path
402
+ if (node.computed) {
403
+ if (t.isExpression(node.key)) {
404
+ forEachTerminalName(node.key, path.scope, path, (name) => state.annotated.add(name))
405
+ }
406
+ return
407
+ }
408
+ const name = plainKeyName(node.key)
409
+ if (name !== null) {
410
+ state.annotated.add(name)
411
+ }
412
+ }
413
+
414
+ function addAnnotatedMember(path: NodePath<Member>, state: PropertyManglerState): void {
415
+ const { node } = path
416
+ if (node.computed) {
417
+ if (t.isExpression(node.property)) {
418
+ forEachTerminalName(node.property, path.scope, path, (name) => state.annotated.add(name))
419
+ }
420
+ } else if (t.isIdentifier(node.property)) {
421
+ state.annotated.add(node.property.name)
422
+ }
423
+ }
424
+
425
+ function collectKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
426
+ const { node } = path
427
+ if (node.computed) {
428
+ if (!state.keepQuoted && t.isExpression(node.key)) {
429
+ collectTerminalNames(node.key, path.scope, path, state)
430
+ }
431
+ return
432
+ }
433
+ if (state.keepQuoted && t.isStringLiteral(node.key)) {
434
+ return
435
+ }
436
+ const name = plainKeyName(node.key)
437
+ if (name !== null) {
438
+ state.addCandidate(name)
439
+ }
440
+ }
441
+
442
+ function collectMember(path: NodePath<Member>, state: PropertyManglerState): void {
443
+ const { node } = path
444
+ if (node.computed) {
445
+ if (!state.keepQuoted && t.isExpression(node.property)) {
446
+ collectTerminalNames(node.property, path.scope, path, state)
447
+ }
448
+ return
449
+ }
450
+ if (!state.undeclared && memberRootIsUndeclared(path)) {
451
+ if (t.isIdentifier(node.property)) {
452
+ state.skipUndeclaredName(node.property.name)
453
+ }
454
+ return
455
+ }
456
+ if (t.isIdentifier(node.property)) {
457
+ state.addCandidate(node.property.name)
458
+ }
459
+ }
460
+
461
+ function collectTerminalNames(
462
+ node: t.Expression,
463
+ scope: Scope,
464
+ referencePath: NodePath,
465
+ state: PropertyManglerState,
466
+ ): void {
467
+ forEachTerminalName(node, scope, referencePath, (name) => state.addCandidate(name))
468
+ }
469
+
470
+ function rewriteKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
471
+ const { node } = path
472
+ if (node.computed) {
473
+ if (!state.keepQuoted && t.isExpression(node.key)) {
474
+ node.key = rewriteTerminalNames(node.key, path.scope, path, state)
475
+ }
476
+ return
477
+ }
478
+ if (state.keepQuoted && t.isStringLiteral(node.key)) {
479
+ return
480
+ }
481
+ const name = plainKeyName(node.key)
482
+ if (name === null) {
483
+ return
484
+ }
485
+ const mangled = state.mangle(name)
486
+ if (mangled === name) {
487
+ return
488
+ }
489
+ node.key = t.inheritsComments(t.stringLiteral(mangled), node.key)
490
+ node.computed = false
491
+ if (t.isObjectProperty(node)) {
492
+ node.shorthand = false
493
+ }
494
+ state.changed = true
495
+ }
496
+
497
+ function rewriteMember(path: NodePath<Member>, state: PropertyManglerState): void {
498
+ const { node } = path
499
+ if (node.computed) {
500
+ if (!state.keepQuoted && t.isExpression(node.property)) {
501
+ node.property = rewriteTerminalNames(node.property, path.scope, path, state)
502
+ }
503
+ return
504
+ }
505
+ if (!t.isIdentifier(node.property)) {
506
+ return
507
+ }
508
+ const mangled = state.mangle(node.property.name)
509
+ if (mangled === node.property.name) {
510
+ return
511
+ }
512
+ // Babel narrows members by `computed`, so both fields need widening.
513
+ const computed = node as Member & { computed: boolean; property: t.Expression }
514
+ computed.property = t.inheritsComments(t.stringLiteral(mangled), node.property)
515
+ computed.computed = true
516
+ state.changed = true
517
+ }
518
+
519
+ function rewriteString(node: t.StringLiteral, state: PropertyManglerState): void {
520
+ const mangled = state.mangle(node.value)
521
+ if (mangled !== node.value) {
522
+ node.value = mangled
523
+ state.changed = true
524
+ }
525
+ }
526
+
527
+ function forEachTerminalName(
528
+ node: t.Expression,
529
+ scope: Scope,
530
+ referencePath: NodePath,
531
+ visit: (name: string) => void,
532
+ ): void {
533
+ const name = evaluatedPropertyName(node, scope, referencePath)
534
+ if (name !== null) {
535
+ visit(name)
536
+ return
537
+ }
538
+ if (t.isSequenceExpression(node)) {
539
+ forEachTerminalName(node.expressions.at(-1)!, scope, referencePath, visit)
540
+ } else if (t.isConditionalExpression(node)) {
541
+ forEachTerminalName(node.consequent, scope, referencePath, visit)
542
+ forEachTerminalName(node.alternate, scope, referencePath, visit)
543
+ } else if (t.isLogicalExpression(node)) {
544
+ forEachTerminalName(node.right, scope, referencePath, visit)
545
+ } else if (t.isParenthesizedExpression(node)) {
546
+ forEachTerminalName(node.expression, scope, referencePath, visit)
547
+ }
548
+ }
549
+
550
+ function rewriteTerminalNames(
551
+ node: t.Expression,
552
+ scope: Scope,
553
+ referencePath: NodePath,
554
+ state: PropertyManglerState,
555
+ ): t.Expression {
556
+ const name = evaluatedPropertyName(node, scope, referencePath)
557
+ if (name !== null) {
558
+ const mangled = state.mangle(name)
559
+ if (mangled === name) {
560
+ return node
561
+ }
562
+ state.changed = true
563
+ if (t.isStringLiteral(node)) {
564
+ state.rewrittenKeyAnnotations.add(node)
565
+ node.value = mangled
566
+ return node
567
+ }
568
+ return t.inheritsComments(t.stringLiteral(mangled), node)
569
+ }
570
+ if (t.isSequenceExpression(node)) {
571
+ const last = node.expressions.length - 1
572
+ node.expressions[last] = rewriteTerminalNames(
573
+ node.expressions[last]!,
574
+ scope,
575
+ referencePath,
576
+ state,
577
+ )
578
+ } else if (t.isConditionalExpression(node)) {
579
+ node.consequent = rewriteTerminalNames(node.consequent, scope, referencePath, state)
580
+ node.alternate = rewriteTerminalNames(node.alternate, scope, referencePath, state)
581
+ } else if (t.isLogicalExpression(node)) {
582
+ node.right = rewriteTerminalNames(node.right, scope, referencePath, state)
583
+ } else if (t.isParenthesizedExpression(node)) {
584
+ node.expression = rewriteTerminalNames(node.expression, scope, referencePath, state)
585
+ }
586
+ return node
587
+ }
588
+
589
+ function evaluatedPropertyName(
590
+ node: t.Expression,
591
+ scope: Scope,
592
+ referencePath: NodePath,
593
+ ): string | null {
594
+ const result = evaluateConstant(node, scope, referencePath)
595
+ if (!result.known || isOpaque(result.value) || typeof result.value === 'symbol') {
596
+ return null
597
+ }
598
+ return String(result.value)
599
+ }
600
+
601
+ function memberRootIsUndeclared(path: NodePath<Member>): boolean {
602
+ const root = memberRootIdentifier(path.node)
603
+ return root !== null && path.scope.getBinding(root.name) === undefined
604
+ }
605
+
606
+ function memberRootIdentifier(node: Member): t.Identifier | null {
607
+ let root: t.Node = node.object
608
+ while (true) {
609
+ if (t.isMemberExpression(root) || t.isOptionalMemberExpression(root)) {
610
+ root = root.object
611
+ } else if (t.isCallExpression(root) || t.isOptionalCallExpression(root)) {
612
+ root = root.callee
613
+ } else if (t.isNewExpression(root)) {
614
+ root = root.callee
615
+ } else if (t.isTaggedTemplateExpression(root)) {
616
+ root = root.tag
617
+ } else if (t.isParenthesizedExpression(root)) {
618
+ root = root.expression
619
+ } else {
620
+ break
621
+ }
622
+ }
623
+ return t.isIdentifier(root) ? root : null
624
+ }
625
+
626
+ function memberHasMangleAnnotation(path: NodePath<Member>): boolean {
627
+ if (
628
+ hasAnnotation(path.node, MANGLE_PROPERTY_ANNOTATION) ||
629
+ hasAnnotation(path.node.object, MANGLE_PROPERTY_ANNOTATION) ||
630
+ hasAnnotation(path.node.property, MANGLE_PROPERTY_ANNOTATION)
631
+ ) {
632
+ return true
633
+ }
634
+
635
+ let current: NodePath = path
636
+ while (current.parentPath) {
637
+ const parent: NodePath = current.parentPath
638
+ if (parent.isMemberExpression() || parent.isOptionalMemberExpression()) {
639
+ return false
640
+ }
641
+ if (parent.isExpressionStatement() && parent.node.expression === current.node) {
642
+ return hasAnnotation(parent.node, MANGLE_PROPERTY_ANNOTATION)
643
+ }
644
+ if (!isTransparentAnnotationParent(parent, current.node)) {
645
+ return false
646
+ }
647
+ current = parent
648
+ }
649
+ return false
650
+ }
651
+
652
+ function isTransparentAnnotationParent(path: NodePath, child: t.Node): boolean {
653
+ const { node } = path
654
+ return (
655
+ (t.isAssignmentExpression(node) && node.left === child) ||
656
+ (t.isCallExpression(node) && node.callee === child) ||
657
+ (t.isOptionalCallExpression(node) && node.callee === child) ||
658
+ (t.isParenthesizedExpression(node) && node.expression === child) ||
659
+ (t.isUnaryExpression(node) && node.argument === child) ||
660
+ (t.isUpdateExpression(node) && node.argument === child)
661
+ )
662
+ }
663
+
664
+ function hasAnnotation(node: t.Node, annotation: string): boolean {
665
+ return (
666
+ node.leadingComments?.some(
667
+ (comment) =>
668
+ comment.value.includes(`@${annotation}`) || comment.value.includes(`#${annotation}`),
669
+ ) ?? false
670
+ )
671
+ }
672
+
673
+ function isObjectDefinePropertyCall(path: NodePath<Call>): boolean {
674
+ const { node } = path
675
+ const { callee } = node
676
+ if (
677
+ (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) ||
678
+ !t.isIdentifier(callee.object, { name: 'Object' })
679
+ ) {
680
+ return false
681
+ }
682
+ if (!callee.computed) {
683
+ return t.isIdentifier(callee.property, { name: 'defineProperty' })
684
+ }
685
+ return (
686
+ t.isExpression(callee.property) &&
687
+ evaluatedPropertyName(callee.property, path.scope, path) === 'defineProperty'
688
+ )
689
+ }
690
+
691
+ function isSemanticKey(node: KeyedProperty): boolean {
692
+ return (
693
+ (t.isClassMethod(node) && node.kind === 'constructor') ||
694
+ (t.isObjectProperty(node) && !node.computed && !node.shorthand && isProtoKey(node.key))
695
+ )
696
+ }
697
+
698
+ function isKeyedProperty(node: t.Node): node is KeyedProperty {
699
+ return (
700
+ t.isClassAccessorProperty(node) ||
701
+ t.isClassMethod(node) ||
702
+ t.isClassProperty(node) ||
703
+ t.isObjectMethod(node) ||
704
+ t.isObjectProperty(node)
705
+ )
706
+ }
707
+
708
+ function plainKeyName(key: t.Node): string | null {
709
+ if (t.isIdentifier(key)) {
710
+ return key.name
711
+ }
712
+ if (t.isStringLiteral(key)) {
713
+ return key.value
714
+ }
715
+ if (t.isBooleanLiteral(key)) {
716
+ return String(key.value)
717
+ }
718
+ if (t.isNullLiteral(key)) {
719
+ return 'null'
720
+ }
721
+ if (t.isNumericLiteral(key) || t.isBigIntLiteral(key)) {
722
+ return String(key.value)
723
+ }
724
+ return null
725
+ }
726
+
727
+ function debugSuffix(debug: ManglePropertiesOptions['debug']): string | null {
728
+ if (debug === undefined || debug === false) {
729
+ return null
730
+ }
731
+ return debug === true ? '' : debug
732
+ }
733
+
734
+ function compileRegex(regex: ManglePropertiesOptions['regex']): RegExp | null {
735
+ if (regex === undefined) {
736
+ return null
737
+ }
738
+ if (typeof regex === 'string') {
739
+ // Terser accepts legacy-mode pattern strings; forcing `u` changes their grammar.
740
+ // oxlint-disable-next-line require-unicode-regexp
741
+ return new RegExp(regex)
742
+ }
743
+ return new RegExp(regex.source, regex.flags)
744
+ }
745
+
746
+ const BUILTIN_OBJECTS: readonly object[] = [
747
+ Object,
748
+ Array,
749
+ Function,
750
+ Number,
751
+ String,
752
+ Boolean,
753
+ BigInt,
754
+ Symbol,
755
+ Error,
756
+ AggregateError,
757
+ EvalError,
758
+ RangeError,
759
+ ReferenceError,
760
+ SyntaxError,
761
+ TypeError,
762
+ URIError,
763
+ Math,
764
+ Date,
765
+ RegExp,
766
+ JSON,
767
+ ArrayBuffer,
768
+ SharedArrayBuffer,
769
+ DataView,
770
+ Atomics,
771
+ Float32Array,
772
+ Float64Array,
773
+ Int8Array,
774
+ Int16Array,
775
+ Int32Array,
776
+ BigInt64Array,
777
+ Uint8Array,
778
+ Uint8ClampedArray,
779
+ Uint16Array,
780
+ Uint32Array,
781
+ BigUint64Array,
782
+ Map,
783
+ Set,
784
+ WeakMap,
785
+ WeakSet,
786
+ WeakRef,
787
+ FinalizationRegistry,
788
+ Promise,
789
+ Proxy,
790
+ Reflect,
791
+ Intl,
792
+ WebAssembly,
793
+ ]
794
+
795
+ let cachedBuiltinProperties: ReadonlySet<string> | undefined
796
+
797
+ function builtinProperties(): ReadonlySet<string> {
798
+ cachedBuiltinProperties ??= collectBuiltinProperties()
799
+ return cachedBuiltinProperties
800
+ }
801
+
802
+ function collectBuiltinProperties(): ReadonlySet<string> {
803
+ const names = new Set(DOM_PROPERTIES)
804
+ for (const name of ['null', 'true', 'false', 'NaN', 'Infinity', '-Infinity', 'undefined']) {
805
+ names.add(name)
806
+ }
807
+ for (const object of BUILTIN_OBJECTS) {
808
+ for (const name of Object.getOwnPropertyNames(object)) {
809
+ names.add(name)
810
+ }
811
+ const prototype = 'prototype' in object ? object.prototype : null
812
+ if (prototype && (typeof prototype === 'object' || typeof prototype === 'function')) {
813
+ for (const name of Object.getOwnPropertyNames(prototype)) {
814
+ names.add(name)
815
+ }
816
+ }
817
+ }
818
+ return names
819
+ }