@generaltranslation/vue-extractor 0.0.0

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 (62) hide show
  1. package/LICENSE.md +105 -0
  2. package/dist/config.d.ts +2 -0
  3. package/dist/config.js +2 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +2 -0
  6. package/dist/internal/compilerAst.d.ts +43 -0
  7. package/dist/internal/compilerAst.js +77 -0
  8. package/dist/internal/compilerAst.js.map +1 -0
  9. package/dist/internal/config/resolveVueCompilerOptions.d.ts +23 -0
  10. package/dist/internal/config/resolveVueCompilerOptions.js +987 -0
  11. package/dist/internal/config/resolveVueCompilerOptions.js.map +1 -0
  12. package/dist/internal/extractFromVueSource.d.ts +9 -0
  13. package/dist/internal/extractFromVueSource.js +332 -0
  14. package/dist/internal/extractFromVueSource.js.map +1 -0
  15. package/dist/internal/script/analyze.d.ts +13 -0
  16. package/dist/internal/script/analyze.js +4761 -0
  17. package/dist/internal/script/analyze.js.map +1 -0
  18. package/dist/internal/script/jsx.d.ts +36 -0
  19. package/dist/internal/script/jsx.js +667 -0
  20. package/dist/internal/script/jsx.js.map +1 -0
  21. package/dist/internal/script/knownValues.d.ts +14 -0
  22. package/dist/internal/script/knownValues.js +148 -0
  23. package/dist/internal/script/knownValues.js.map +1 -0
  24. package/dist/internal/script/localModules.d.ts +80 -0
  25. package/dist/internal/script/localModules.js +364 -0
  26. package/dist/internal/script/localModules.js.map +1 -0
  27. package/dist/internal/script/model.d.ts +317 -0
  28. package/dist/internal/script/model.js +1 -0
  29. package/dist/internal/script/parser.d.ts +3 -0
  30. package/dist/internal/script/parser.js +21 -0
  31. package/dist/internal/script/parser.js.map +1 -0
  32. package/dist/internal/script/replay.d.ts +53 -0
  33. package/dist/internal/script/replay.js +1611 -0
  34. package/dist/internal/script/replay.js.map +1 -0
  35. package/dist/internal/script/snapshot.d.ts +25 -0
  36. package/dist/internal/script/snapshot.js +293 -0
  37. package/dist/internal/script/snapshot.js.map +1 -0
  38. package/dist/internal/script/syntax.d.ts +21 -0
  39. package/dist/internal/script/syntax.js +46 -0
  40. package/dist/internal/script/syntax.js.map +1 -0
  41. package/dist/internal/script.d.ts +2 -0
  42. package/dist/internal/script.js +2 -0
  43. package/dist/internal/stringCalls.d.ts +7 -0
  44. package/dist/internal/stringCalls.js +82 -0
  45. package/dist/internal/stringCalls.js.map +1 -0
  46. package/dist/internal/template.d.ts +4 -0
  47. package/dist/internal/template.js +2198 -0
  48. package/dist/internal/template.js.map +1 -0
  49. package/dist/internal/templatePath.d.ts +12 -0
  50. package/dist/internal/templatePath.js +23 -0
  51. package/dist/internal/templatePath.js.map +1 -0
  52. package/dist/internal/types.d.ts +69 -0
  53. package/dist/internal/types.js +1 -0
  54. package/dist/internal/utils.d.ts +19 -0
  55. package/dist/internal/utils.js +149 -0
  56. package/dist/internal/utils.js.map +1 -0
  57. package/dist/internal/vueCompiler.d.ts +35 -0
  58. package/dist/internal/vueCompiler.js +320 -0
  59. package/dist/internal/vueCompiler.js.map +1 -0
  60. package/dist/types.d.ts +80 -0
  61. package/dist/types.js +1 -0
  62. package/package.json +78 -0
@@ -0,0 +1,1611 @@
1
+ import { unwrapExpression } from "../utils.js";
2
+ import { appendTemplatePath, recursiveTemplatePathSegment, unknownTemplatePathSegment } from "../templatePath.js";
3
+ //#region src/internal/script/replay.ts
4
+ /**
5
+ * Creates the finite source-ordered identity analyzer used by script analysis.
6
+ * Dependencies are injected so the replay evaluator remains one cohesive SCC
7
+ * without creating a runtime import cycle back to the script orchestrator.
8
+ */
9
+ function createReplayAnalysis({ ordinaryGlobalValues: ORDINARY_GLOBAL_VALUES, readonlyArrayTransforms: READONLY_ARRAY_TRANSFORMS, bindingReadsUnsafeMutableImport, collectFunctionReturnExpressions, collectPatternBindingNames, composeContainerWritePolicy, knownValueKey, readDefiniteArrayInteger, readResolvedMemberPath, readResolvedMemberProperty, readResolvedPropertyKey, readStaticFromScope, resolveCalledFunction, resolveComputedGetter, resolveKnownExpression }) {
10
+ const replayUnsafe = { type: "unsafe" };
11
+ /** Creates one fresh runtime container identity for source-ordered replay. */
12
+ function createReplayContainer(snapshot) {
13
+ return {
14
+ type: "container",
15
+ identity: {
16
+ escaped: false,
17
+ snapshot
18
+ },
19
+ writePolicy: "forward"
20
+ };
21
+ }
22
+ /** Returns a reference with the write behavior Vue applies to one wrapper. */
23
+ function wrapReplayContainer(value, wrapper) {
24
+ return {
25
+ type: "container",
26
+ identity: value.identity,
27
+ writePolicy: composeContainerWritePolicy(wrapper, value.writePolicy)
28
+ };
29
+ }
30
+ /** Applies a Vue proxy wrapper to a container, ref, or computed reference. */
31
+ function wrapReplayReference(value, wrapper) {
32
+ if (value.type === "container") return wrapReplayContainer(value, wrapper);
33
+ return {
34
+ ...value,
35
+ writePolicy: composeContainerWritePolicy(wrapper, value.writePolicy)
36
+ };
37
+ }
38
+ /** Marks an escaped identity and every nested identity reachable through it. */
39
+ function markReplayContainerEscaped(value, seen = /* @__PURE__ */ new Set()) {
40
+ if (seen.has(value.identity)) return;
41
+ seen.add(value.identity);
42
+ value.identity.escaped = true;
43
+ const entries = value.identity.snapshot.kind === "array" ? value.identity.snapshot.entries : value.identity.snapshot.entries.values();
44
+ for (const entry of entries) {
45
+ if (entry?.type === "container") markReplayContainerEscaped(entry, seen);
46
+ if (entry?.type === "ref") markReplayRefEscaped(entry, seen);
47
+ if (entry?.type === "collection") markReplayCollectionEscaped(entry, seen);
48
+ }
49
+ if (value.identity.snapshot.kind === "object") {
50
+ const prototype = value.identity.snapshot.prototype;
51
+ if (prototype) markReplayContainerEscaped(prototype, seen);
52
+ }
53
+ }
54
+ /** Marks a ref and every container reachable through its current value unsafe. */
55
+ function markReplayRefEscaped(value, seen = /* @__PURE__ */ new Set()) {
56
+ if (seen.has(value.identity)) return;
57
+ seen.add(value.identity);
58
+ value.identity.escaped = true;
59
+ const current = value.identity.value;
60
+ if (current?.type === "container") markReplayContainerEscaped(current, seen);
61
+ if (current?.type === "ref") markReplayRefEscaped(current, seen);
62
+ if (current?.type === "collection") markReplayCollectionEscaped(current, seen);
63
+ }
64
+ /** Marks a Map or Set abstraction unsafe after an unmodelled escape. */
65
+ function markReplayCollectionEscaped(value, seen = /* @__PURE__ */ new Set()) {
66
+ if (seen.has(value.identity)) return;
67
+ seen.add(value.identity);
68
+ value.identity.escaped = true;
69
+ for (const entry of value.identity.entries.values()) {
70
+ if (entry.type === "container") markReplayContainerEscaped(entry, seen);
71
+ if (entry.type === "ref") markReplayRefEscaped(entry, seen);
72
+ if (entry.type === "collection") markReplayCollectionEscaped(entry, seen);
73
+ }
74
+ }
75
+ /** Marks any mutable replay value unsafe after an unsupported operation. */
76
+ function markReplayValueEscaped(value) {
77
+ if (value?.type === "container") markReplayContainerEscaped(value);
78
+ if (value?.type === "ref") markReplayRefEscaped(value);
79
+ if (value?.type === "collection") markReplayCollectionEscaped(value);
80
+ if (value?.type === "function") {
81
+ for (const captured of value.substitutions.values()) markReplayValueEscaped(captured);
82
+ for (const captured of value.boundArguments) markReplayValueEscaped(captured);
83
+ }
84
+ }
85
+ /** Reads a ref value through the proxy policy currently wrapping the ref. */
86
+ function readReplayRefValue(value) {
87
+ if (value.identity.escaped) return replayUnsafe;
88
+ const current = value.identity.value;
89
+ if (current?.type === "collection" || current?.type === "container" || current?.type === "ref" || current?.type === "computed") {
90
+ if (value.writePolicy === "readonly-deep") return wrapReplayReference(current, "readonly");
91
+ }
92
+ return current?.type === "leaf" ? {
93
+ ...current,
94
+ exactSelection: true,
95
+ selectionKind: "ref"
96
+ } : current;
97
+ }
98
+ /** Applies Vue's deep readonly conversion to a value read through a proxy. */
99
+ function wrapReplayReadValue(value, policy) {
100
+ if (value && policy === "readonly-deep" && (value.type === "collection" || value.type === "computed" || value.type === "container" || value.type === "ref")) return wrapReplayReference(value, "readonly");
101
+ return value;
102
+ }
103
+ /** Evaluates a supported property getter against the current replay state. */
104
+ function evaluateReplayGetter(value, receiver, state, context) {
105
+ if (!context.allowGetterEffects) {
106
+ const body = value.getter.node.body;
107
+ if (body.type === "BlockStatement" && (body.body.length !== 1 || body.body[0]?.type !== "ReturnStatement")) return;
108
+ const returns = collectFunctionReturnExpressions(value.getter.node, value.getter.scope, state);
109
+ return returns.length === 1 ? evaluateReplayExpression(returns[0].node, returns[0].scope, state, {
110
+ ...context,
111
+ substitutions: new Map(value.substitutions),
112
+ thisValue: receiver
113
+ }) : void 0;
114
+ }
115
+ const result = executeReplayFunction(value.getter, [], state, {
116
+ ...context,
117
+ substitutions: new Map(value.substitutions),
118
+ thisValue: receiver
119
+ }, receiver);
120
+ return result.executed ? result.value : void 0;
121
+ }
122
+ /** Reads a child using prototype lookup and Vue proxy conversion rules. */
123
+ function readReplayContainerEntry(value, property, state, context, seen = /* @__PURE__ */ new Set(), receiver = value) {
124
+ if (value.identity.escaped || seen.has(value.identity)) return replayUnsafe;
125
+ const snapshot = value.identity.snapshot;
126
+ let entry;
127
+ if (snapshot.kind === "array") entry = /^(0|[1-9]\d*)$/.test(property) ? snapshot.entries[Number(property)] : void 0;
128
+ else if (snapshot.entries.has(property)) entry = snapshot.entries.get(property);
129
+ else if (snapshot.prototype) entry = readReplayContainerEntry(snapshot.prototype, property, state, context, new Set(seen).add(value.identity), receiver);
130
+ let fromGetter = false;
131
+ if (entry?.type === "getter") {
132
+ fromGetter = true;
133
+ entry = evaluateReplayGetter(entry, receiver, state, context);
134
+ }
135
+ if (entry?.type === "method") entry = {
136
+ ...entry,
137
+ receiver
138
+ };
139
+ if (entry?.type === "leaf") entry = {
140
+ ...entry,
141
+ exactSelection: true,
142
+ selectionKind: fromGetter ? "getter" : "member"
143
+ };
144
+ return wrapReplayReadValue(entry, value.writePolicy);
145
+ }
146
+ /** Lists the property names visible through a finite object prototype chain. */
147
+ function readReplayVisibleObjectKeys(value, seen = /* @__PURE__ */ new Set()) {
148
+ if (value.identity.escaped || value.identity.snapshot.kind !== "object" || seen.has(value.identity)) return;
149
+ const keys = value.identity.snapshot.prototype ? readReplayVisibleObjectKeys(value.identity.snapshot.prototype, new Set(seen).add(value.identity)) : /* @__PURE__ */ new Set();
150
+ if (!keys) return void 0;
151
+ for (const key of value.identity.snapshot.entries.keys()) keys.add(key);
152
+ return keys;
153
+ }
154
+ /** Lists every value a template can select from one finite container. */
155
+ function readReplayVisibleContainerEntries(value, state, context) {
156
+ if (value.identity.escaped) return void 0;
157
+ const snapshot = value.identity.snapshot;
158
+ if (snapshot.kind === "array") return snapshot.entries.map((entry, index) => [String(index), entry]);
159
+ const keys = readReplayVisibleObjectKeys(value);
160
+ if (!keys) return void 0;
161
+ const entries = [];
162
+ for (const key of keys) {
163
+ const entry = readReplayContainerEntry(value, key, state, context);
164
+ if (!entry) return void 0;
165
+ entries.push([key, entry]);
166
+ }
167
+ return entries;
168
+ }
169
+ /** Resolves whether a non-container value is definitely `<T>` at this point. */
170
+ function createReplayLeaf(node, scope, state) {
171
+ const expression = unwrapExpression(node) ?? node;
172
+ const known = resolveKnownExpression(expression, scope, state, /* @__PURE__ */ new Set());
173
+ const knownValue = known?.type === "component" || known?.type === "string" || known?.type === "vue-builtin" ? known : void 0;
174
+ if (known) return {
175
+ type: "leaf",
176
+ expression: {
177
+ node: expression,
178
+ scope
179
+ },
180
+ hasGT: known.type === "component" && known.name === "T",
181
+ knownValue
182
+ };
183
+ const primitive = readStaticFromScope(expression, scope, /* @__PURE__ */ new Set(), expression.end ?? Number.POSITIVE_INFINITY, state.analysis);
184
+ const ordinaryGlobal = expression.type === "Identifier" && !scope.getBinding(expression.name) && ORDINARY_GLOBAL_VALUES.has(expression.name);
185
+ return {
186
+ type: "leaf",
187
+ expression: {
188
+ node: expression,
189
+ scope
190
+ },
191
+ hasGT: primitive.ok || ordinaryGlobal ? false : void 0,
192
+ knownValue
193
+ };
194
+ }
195
+ /** Reads a statically named member chain from a replayed container. */
196
+ function evaluateReplayMember(node, scope, state, context) {
197
+ const object = evaluateReplayExpression(node.object, scope, state, context);
198
+ const property = readResolvedMemberProperty(node, scope, state);
199
+ if (property === void 0) return void 0;
200
+ if (object?.type === "unsafe") return object;
201
+ if (object?.type === "container") return readReplayContainerEntry(object, property, state, context);
202
+ if (property !== "value") return void 0;
203
+ if (object?.type === "ref") return readReplayRefValue(object);
204
+ if (object?.type === "computed") return evaluateReplayComputed(object, state, context);
205
+ }
206
+ /** Shallow-copies the enumerable own entries of one container reference. */
207
+ function copyReplayContainerEntries(value, state, context) {
208
+ if (value.identity.escaped) return void 0;
209
+ const snapshot = value.identity.snapshot;
210
+ if (snapshot.kind === "array") return {
211
+ kind: "array",
212
+ entries: snapshot.entries.map((_entry, index) => readReplayContainerEntry(value, String(index), state, context))
213
+ };
214
+ return {
215
+ kind: "object",
216
+ entries: new Map([...snapshot.entries.keys()].flatMap((key) => {
217
+ const entry = readReplayContainerEntry(value, key, state, context);
218
+ return entry ? [[key, entry]] : [];
219
+ }))
220
+ };
221
+ }
222
+ /** Evaluates one finite array literal without losing nested object identity. */
223
+ function evaluateReplayArray(node, scope, state, context) {
224
+ const entries = [];
225
+ for (const element of node.elements) {
226
+ if (!element) {
227
+ entries.push(void 0);
228
+ continue;
229
+ }
230
+ if (element.type === "SpreadElement") {
231
+ const spread = evaluateReplayExpression(element.argument, scope, state, context);
232
+ if (spread?.type === "unsafe") return spread;
233
+ if (spread?.type === "container" && spread.identity.escaped) return replayUnsafe;
234
+ if (spread?.type !== "container" || spread.identity.snapshot.kind !== "array") return;
235
+ const copied = copyReplayContainerEntries(spread, state, context);
236
+ if (!copied || copied.kind !== "array") return void 0;
237
+ entries.push(...copied.entries);
238
+ continue;
239
+ }
240
+ entries.push(evaluateReplayExpression(element, scope, state, context));
241
+ }
242
+ return createReplayContainer({
243
+ kind: "array",
244
+ entries
245
+ });
246
+ }
247
+ /** Evaluates one finite object literal with JavaScript shallow-spread semantics. */
248
+ function evaluateReplayObject(node, scope, state, context) {
249
+ const entries = /* @__PURE__ */ new Map();
250
+ const setters = /* @__PURE__ */ new Map();
251
+ for (const property of node.properties) {
252
+ if (property.type === "SpreadElement") {
253
+ const spread = evaluateReplayExpression(property.argument, scope, state, context);
254
+ if (spread?.type === "unsafe") return spread;
255
+ if (spread?.type === "container" && spread.identity.escaped) return replayUnsafe;
256
+ if (spread?.type !== "container" || spread.identity.snapshot.kind !== "object") return;
257
+ const copied = copyReplayContainerEntries(spread, state, context);
258
+ if (!copied || copied.kind !== "object") return void 0;
259
+ for (const [key, value] of copied.entries) entries.set(key, value);
260
+ continue;
261
+ }
262
+ if (property.type === "ObjectMethod" && property.kind === "get") {
263
+ const key = readResolvedPropertyKey(property, scope, state);
264
+ if (key === void 0) return void 0;
265
+ entries.set(key, {
266
+ type: "getter",
267
+ getter: {
268
+ node: property,
269
+ scope: state.scopes.get(property) ?? scope
270
+ },
271
+ substitutions: new Map(context.substitutions)
272
+ });
273
+ continue;
274
+ }
275
+ if (property.type === "ObjectMethod" && property.kind === "method") {
276
+ const key = readResolvedPropertyKey(property, scope, state);
277
+ if (key === void 0) return void 0;
278
+ entries.set(key, {
279
+ type: "method",
280
+ callable: {
281
+ node: property,
282
+ scope: state.scopes.get(property) ?? scope
283
+ },
284
+ substitutions: new Map(context.substitutions)
285
+ });
286
+ continue;
287
+ }
288
+ if (property.type === "ObjectMethod" && property.kind === "set") {
289
+ const key = readResolvedPropertyKey(property, scope, state);
290
+ if (key === void 0) return void 0;
291
+ setters.set(key, {
292
+ type: "method",
293
+ callable: {
294
+ node: property,
295
+ scope: state.scopes.get(property) ?? scope
296
+ },
297
+ substitutions: new Map(context.substitutions)
298
+ });
299
+ continue;
300
+ }
301
+ if (property.type !== "ObjectProperty") return void 0;
302
+ const key = readResolvedPropertyKey(property, scope, state);
303
+ if (key === void 0) return void 0;
304
+ const value = evaluateReplayExpression(property.value, scope, state, context);
305
+ if (!value) return void 0;
306
+ entries.set(key, value);
307
+ }
308
+ return createReplayContainer({
309
+ kind: "object",
310
+ entries,
311
+ setters
312
+ });
313
+ }
314
+ /** Evaluates a computed getter against the current, not captured, bindings. */
315
+ function evaluateReplayComputed(value, state, context) {
316
+ const returns = collectFunctionReturnExpressions(value.getter.node, value.getter.scope, state);
317
+ if (returns.length !== 1) return void 0;
318
+ const result = evaluateReplayExpression(returns[0].node, returns[0].scope, state, context);
319
+ return result && (result.type === "collection" || result.type === "container" || result.type === "ref" || result.type === "computed") ? wrapReplayReference(result, value.writePolicy === "readonly-deep" ? "readonly" : value.writePolicy === "readonly-shallow" ? "shallow-readonly" : "unref") : result;
320
+ }
321
+ /** Evaluates an expression while applying its supported direct side effects. */
322
+ function executeReplayExpression(node, scope, state, context) {
323
+ const expression = unwrapExpression(node);
324
+ if (expression?.type === "UnaryExpression" && expression.operator === "delete" && (expression.argument.type === "MemberExpression" || expression.argument.type === "OptionalMemberExpression")) return applyReplayMemberDelete(expression.argument, scope, state, context) ? createReplayLeaf(expression, scope, state) : void 0;
325
+ if (expression?.type !== "AssignmentExpression") return evaluateReplayExpression(node, scope, state, context);
326
+ if (expression.operator !== "=") return void 0;
327
+ const replacement = evaluateReplayExpression(expression.right, scope, state, context);
328
+ if (expression.left.type === "Identifier") {
329
+ const binding = scope.getBinding(expression.left.name);
330
+ if (binding) {
331
+ if (replacement?.type === "unsafe") context.unsafeBindings.add(binding);
332
+ else context.unsafeBindings.delete(binding);
333
+ context.values.set(binding, replacement);
334
+ }
335
+ return replacement;
336
+ }
337
+ if (expression.left.type === "MemberExpression" || expression.left.type === "OptionalMemberExpression") return applyReplayMemberAssignment(expression.left, expression.right, scope, state, context) ? replacement : void 0;
338
+ }
339
+ /** Executes one finite local function body with captured identities intact. */
340
+ function executeReplayFunction(callable, arguments_, state, context, thisValue = context.thisValue) {
341
+ if (state.activeReplayFunctions.has(callable.node)) return {
342
+ executed: false,
343
+ value: void 0
344
+ };
345
+ const functionScope = state.scopes.get(callable.node) ?? callable.scope;
346
+ const substitutions = new Map(context.substitutions);
347
+ for (const [index, parameter] of callable.node.params.entries()) {
348
+ const name = parameter.type === "Identifier" ? parameter.name : parameter.type === "RestElement" && parameter.argument.type === "Identifier" ? parameter.argument.name : void 0;
349
+ if (!name) return {
350
+ executed: false,
351
+ value: void 0
352
+ };
353
+ const binding = functionScope.getBinding(name);
354
+ if (!binding) return {
355
+ executed: false,
356
+ value: void 0
357
+ };
358
+ if (parameter.type === "RestElement") {
359
+ substitutions.set(binding, createReplayContainer({
360
+ kind: "array",
361
+ entries: arguments_.slice(index)
362
+ }));
363
+ break;
364
+ }
365
+ const argument = arguments_[index];
366
+ if (!argument) return {
367
+ executed: false,
368
+ value: void 0
369
+ };
370
+ substitutions.set(binding, argument);
371
+ }
372
+ const localContext = {
373
+ ...context,
374
+ substitutions,
375
+ thisValue
376
+ };
377
+ state.activeReplayFunctions.add(callable.node);
378
+ try {
379
+ if (callable.node.body.type !== "BlockStatement") return {
380
+ executed: true,
381
+ value: executeReplayExpression(callable.node.body, functionScope, state, localContext)
382
+ };
383
+ const bodyPath = state.paths.get(callable.node.body);
384
+ const statements = bodyPath?.isBlockStatement() ? bodyPath.get("body") : void 0;
385
+ if (!statements || !Array.isArray(statements)) return {
386
+ executed: false,
387
+ value: void 0
388
+ };
389
+ for (const statement of statements) {
390
+ if (statement.isReturnStatement()) return {
391
+ executed: true,
392
+ value: statement.node.argument ? executeReplayExpression(statement.node.argument, statement.scope, state, localContext) : void 0
393
+ };
394
+ if (!statement.isVariableDeclaration() && !statement.isExpressionStatement()) return {
395
+ executed: false,
396
+ value: void 0
397
+ };
398
+ replayContainerStatement(statement, state, localContext);
399
+ }
400
+ return {
401
+ executed: true,
402
+ value: void 0
403
+ };
404
+ } finally {
405
+ state.activeReplayFunctions.delete(callable.node);
406
+ }
407
+ }
408
+ /** Reads one exact callback return for array transform replay. */
409
+ function evaluateReplayCallback(callback, argument, source, state, context) {
410
+ const result = executeReplayFunction(callback, [argument], state, context);
411
+ if (!result.executed) {
412
+ invalidateReplayFunctionCaptures(callback.node, state, context);
413
+ markReplayContainerEscaped(source);
414
+ return;
415
+ }
416
+ return result.value;
417
+ }
418
+ /** Detects writes hidden inside an expression-bodied callback. */
419
+ function replayExpressionHasWrites(node, state) {
420
+ const path = state.paths.get(node);
421
+ if (!path) return true;
422
+ let writes = false;
423
+ const mark = (candidate) => {
424
+ writes = true;
425
+ candidate.stop();
426
+ };
427
+ path.traverse({
428
+ AssignmentExpression: mark,
429
+ UpdateExpression: mark,
430
+ UnaryExpression(candidate) {
431
+ if (candidate.node.operator === "delete") mark(candidate);
432
+ }
433
+ });
434
+ return writes;
435
+ }
436
+ /** Applies a finite array copy transform at the exact call position. */
437
+ function evaluateReplayArrayTransform(value, method, call, scope, state, context) {
438
+ if (value.identity.escaped) return replayUnsafe;
439
+ if (value.identity.snapshot.kind !== "array") return void 0;
440
+ if (call.arguments.some((argument) => argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement")) return;
441
+ const copied = copyReplayContainerEntries(value, state, context);
442
+ if (!copied || copied.kind !== "array") return void 0;
443
+ const entries = copied.entries;
444
+ const argumentNode = (index) => {
445
+ const argument = call.arguments[index];
446
+ return argument && argument.type !== "ArgumentPlaceholder" ? argument : void 0;
447
+ };
448
+ if (method === "slice") {
449
+ const start = readDefiniteArrayInteger(argumentNode(0), 0, scope, state);
450
+ const end = readDefiniteArrayInteger(argumentNode(1), entries.length, scope, state);
451
+ return start === void 0 || end === void 0 ? void 0 : createReplayContainer({
452
+ kind: "array",
453
+ entries: entries.slice(start, end)
454
+ });
455
+ }
456
+ if (method === "concat") {
457
+ for (const argument of call.arguments) {
458
+ const item = evaluateReplayExpression(argument, scope, state, context);
459
+ if (!item) return void 0;
460
+ if (item.type === "container" && item.identity.snapshot.kind === "array") {
461
+ const flattened = copyReplayContainerEntries(item, state, context);
462
+ if (!flattened || flattened.kind !== "array") return void 0;
463
+ entries.push(...flattened.entries);
464
+ } else entries.push(item);
465
+ }
466
+ return createReplayContainer({
467
+ kind: "array",
468
+ entries
469
+ });
470
+ }
471
+ if (method === "map") {
472
+ const callbackNode = argumentNode(0);
473
+ const callback = callbackNode ? resolveCalledFunction(callbackNode, scope, state, /* @__PURE__ */ new Set()) : void 0;
474
+ if (!callback) return void 0;
475
+ const mapped = [];
476
+ for (const entry of entries) {
477
+ if (!entry) {
478
+ mapped.push(void 0);
479
+ continue;
480
+ }
481
+ const result = evaluateReplayCallback(callback, entry, value, state, context);
482
+ if (!result) return void 0;
483
+ mapped.push(result);
484
+ }
485
+ return createReplayContainer({
486
+ kind: "array",
487
+ entries: mapped
488
+ });
489
+ }
490
+ if (method === "toSpliced") {
491
+ const start = readDefiniteArrayInteger(argumentNode(0), 0, scope, state);
492
+ const deleteCount = readDefiniteArrayInteger(argumentNode(1), call.arguments.length === 0 ? 0 : call.arguments.length === 1 ? entries.length : 0, scope, state);
493
+ if (start === void 0 || deleteCount === void 0) return void 0;
494
+ const inserted = [];
495
+ for (const argument of call.arguments.slice(2)) {
496
+ const item = evaluateReplayExpression(argument, scope, state, context);
497
+ if (!item) return void 0;
498
+ inserted.push(item);
499
+ }
500
+ entries.splice(start, Math.max(0, deleteCount), ...inserted);
501
+ return createReplayContainer({
502
+ kind: "array",
503
+ entries
504
+ });
505
+ }
506
+ if (method === "toReversed") return createReplayContainer({
507
+ kind: "array",
508
+ entries: entries.reverse()
509
+ });
510
+ if (method === "toSorted") return entries.length <= 1 ? createReplayContainer({
511
+ kind: "array",
512
+ entries
513
+ }) : void 0;
514
+ if (method === "with") {
515
+ const index = readDefiniteArrayInteger(argumentNode(0), 0, scope, state);
516
+ const replacement = argumentNode(1);
517
+ if (index === void 0 || !replacement) return void 0;
518
+ const normalized = index < 0 ? entries.length + index : index;
519
+ if (normalized < 0 || normalized >= entries.length) return void 0;
520
+ const item = evaluateReplayExpression(replacement, scope, state, context);
521
+ if (!item) return void 0;
522
+ entries[normalized] = item;
523
+ return createReplayContainer({
524
+ kind: "array",
525
+ entries
526
+ });
527
+ }
528
+ }
529
+ /** Mutates one replayed array when the built-in operation is deterministic. */
530
+ function applyReplayArrayMutation(value, method, call, scope, state, context) {
531
+ if (value.identity.snapshot.kind !== "array") return false;
532
+ if (value.writePolicy !== "forward") return true;
533
+ if (call.arguments.some((argument) => argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement")) {
534
+ markReplayContainerEscaped(value);
535
+ return false;
536
+ }
537
+ const entries = value.identity.snapshot.entries;
538
+ const evaluated = call.arguments.map((argument) => evaluateReplayExpression(argument, scope, state, context));
539
+ if (evaluated.some((entry) => !entry)) {
540
+ markReplayContainerEscaped(value);
541
+ return false;
542
+ }
543
+ const items = evaluated;
544
+ if (method === "pop") entries.pop();
545
+ else if (method === "shift") entries.shift();
546
+ else if (method === "push") entries.push(...items);
547
+ else if (method === "unshift") entries.unshift(...items);
548
+ else if (method === "splice") {
549
+ const first = call.arguments[0];
550
+ const second = call.arguments[1];
551
+ const start = readDefiniteArrayInteger(first, 0, scope, state);
552
+ const deleteCount = readDefiniteArrayInteger(second, call.arguments.length === 0 ? 0 : call.arguments.length === 1 ? entries.length : 0, scope, state);
553
+ if (start === void 0 || deleteCount === void 0) {
554
+ markReplayContainerEscaped(value);
555
+ return false;
556
+ }
557
+ entries.splice(start, Math.max(0, deleteCount), ...items.slice(2));
558
+ } else return false;
559
+ return true;
560
+ }
561
+ /** Evaluates known wrappers, transforms, and mutators in source order. */
562
+ function evaluateReplayCall(node, scope, state, context) {
563
+ const wrapper = resolveKnownExpression(node.callee, scope, state, /* @__PURE__ */ new Set());
564
+ const first = node.arguments[0];
565
+ if (wrapper?.type === "container-wrapper" && first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement") {
566
+ const value = evaluateReplayExpression(first, scope, state, context);
567
+ if (value?.type === "unsafe") return value;
568
+ if (wrapper.kind === "unref") {
569
+ if (value?.type === "ref") return readReplayRefValue(value);
570
+ if (value?.type === "computed") return evaluateReplayComputed(value, state, context);
571
+ return value;
572
+ }
573
+ return value && (value.type === "container" || value.type === "collection" || value.type === "ref" || value.type === "computed") ? wrapReplayReference(value, wrapper.kind) : void 0;
574
+ }
575
+ if (wrapper?.type === "identity" && first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement") return evaluateReplayExpression(first, scope, state, context);
576
+ if (wrapper?.type === "vue-wrapper" && wrapper.kind === "ref") return {
577
+ type: "ref",
578
+ identity: {
579
+ escaped: false,
580
+ value: first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement" ? evaluateReplayExpression(first, scope, state, context) : createReplayLeaf(node, scope, state)
581
+ },
582
+ writePolicy: "forward"
583
+ };
584
+ if (wrapper?.type === "vue-wrapper" && wrapper.kind === "computed") {
585
+ const getter = first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement" ? resolveComputedGetter(first, scope, state) : void 0;
586
+ return getter ? {
587
+ type: "computed",
588
+ getter,
589
+ writePolicy: "forward"
590
+ } : void 0;
591
+ }
592
+ if (wrapper?.type === "hook") return createReplayLeaf(node, scope, state);
593
+ const calleePath = readResolvedMemberPath(node.callee, scope, state);
594
+ if (calleePath === "Array.from" && !scope.getBinding("Array")) {
595
+ if (node.arguments.length > 1 || !first || first.type === "ArgumentPlaceholder" || first.type === "SpreadElement") return;
596
+ const source = evaluateReplayExpression(first, scope, state, context);
597
+ if (source?.type === "unsafe") return source;
598
+ if (source?.type === "collection") {
599
+ if (source.identity.escaped) return replayUnsafe;
600
+ if (source.identity.kind === "map" && source.iteration === "entries") return;
601
+ return createReplayContainer({
602
+ kind: "array",
603
+ entries: [...source.identity.entries.values()]
604
+ });
605
+ }
606
+ if (source?.type !== "container" || source.identity.snapshot.kind !== "array") return;
607
+ if (source.identity.escaped) return replayUnsafe;
608
+ const copied = copyReplayContainerEntries(source, state, context);
609
+ return copied?.kind === "array" ? createReplayContainer(copied) : void 0;
610
+ }
611
+ if (calleePath === "Object.assign" && !scope.getBinding("Object")) {
612
+ if (!first || first.type === "ArgumentPlaceholder" || first.type === "SpreadElement") return;
613
+ const target = evaluateReplayExpression(first, scope, state, context);
614
+ if (target?.type !== "container" || target.identity.snapshot.kind !== "object") return;
615
+ if (target.writePolicy !== "forward") return target;
616
+ for (const argument of node.arguments.slice(1)) {
617
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") {
618
+ markReplayContainerEscaped(target);
619
+ return;
620
+ }
621
+ const source = evaluateReplayExpression(argument, scope, state, context);
622
+ if (source?.type === "unsafe") {
623
+ markReplayContainerEscaped(target);
624
+ return target;
625
+ }
626
+ if (source?.type !== "container" || source.identity.snapshot.kind !== "object") {
627
+ markReplayContainerEscaped(target);
628
+ return;
629
+ }
630
+ if (source.identity.escaped) {
631
+ markReplayContainerEscaped(target);
632
+ return target;
633
+ }
634
+ const copied = copyReplayContainerEntries(source, state, context);
635
+ if (!copied || copied.kind !== "object") return void 0;
636
+ for (const [key, value] of copied.entries) target.identity.snapshot.entries.set(key, value);
637
+ }
638
+ return target;
639
+ }
640
+ if (calleePath === "Object.create" && !scope.getBinding("Object")) {
641
+ if (!first || first.type === "ArgumentPlaceholder" || first.type === "SpreadElement") return;
642
+ const prototype = evaluateReplayExpression(first, scope, state, context);
643
+ if (prototype?.type !== "container" || prototype.identity.snapshot.kind !== "object") return;
644
+ return createReplayContainer({
645
+ kind: "object",
646
+ entries: /* @__PURE__ */ new Map(),
647
+ prototype
648
+ });
649
+ }
650
+ if (calleePath === "Object.setPrototypeOf" && !scope.getBinding("Object")) {
651
+ const prototypeNode = node.arguments[1];
652
+ if (!first || first.type === "ArgumentPlaceholder" || first.type === "SpreadElement" || !prototypeNode || prototypeNode.type === "ArgumentPlaceholder" || prototypeNode.type === "SpreadElement") return;
653
+ const target = evaluateReplayExpression(first, scope, state, context);
654
+ const prototype = evaluateReplayExpression(prototypeNode, scope, state, context);
655
+ if (target?.type !== "container" || target.identity.snapshot.kind !== "object" || target.writePolicy !== "forward" || prototype?.type !== "container" || prototype.identity.snapshot.kind !== "object") return;
656
+ target.identity.snapshot.prototype = prototype;
657
+ return target;
658
+ }
659
+ const replayCallee = evaluateReplayExpression(node.callee, scope, state, context);
660
+ if (replayCallee?.type === "leaf" && (replayCallee.knownValue?.type === "string" || replayCallee.expression.node.type === "Identifier" && !replayCallee.expression.scope.getBinding(replayCallee.expression.node.name) && ORDINARY_GLOBAL_VALUES.has(replayCallee.expression.node.name))) return {
661
+ type: "leaf",
662
+ expression: {
663
+ node,
664
+ scope
665
+ },
666
+ hasGT: false
667
+ };
668
+ if (replayCallee?.type === "function") {
669
+ const arguments_ = [];
670
+ for (const argument of node.arguments) {
671
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") {
672
+ markReplayValueEscaped(replayCallee);
673
+ return;
674
+ }
675
+ const value = evaluateReplayExpression(argument, scope, state, context);
676
+ if (!value) {
677
+ markReplayValueEscaped(replayCallee);
678
+ return;
679
+ }
680
+ arguments_.push(value);
681
+ }
682
+ const result = executeReplayFunction(replayCallee.callable, [...replayCallee.boundArguments, ...arguments_], state, {
683
+ ...context,
684
+ substitutions: new Map(replayCallee.substitutions)
685
+ }, replayCallee.thisValue);
686
+ if (!result.executed) {
687
+ markReplayValueEscaped(replayCallee);
688
+ for (const argument of arguments_) markReplayValueEscaped(argument);
689
+ return;
690
+ }
691
+ return result.value ?? createReplayLeaf(node, scope, state);
692
+ }
693
+ if (replayCallee?.type === "method" && replayCallee.receiver) {
694
+ const arguments_ = [];
695
+ for (const argument of node.arguments) {
696
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") {
697
+ markReplayContainerEscaped(replayCallee.receiver);
698
+ return;
699
+ }
700
+ const value = evaluateReplayExpression(argument, scope, state, context);
701
+ if (!value) {
702
+ markReplayContainerEscaped(replayCallee.receiver);
703
+ return;
704
+ }
705
+ arguments_.push(value);
706
+ }
707
+ const result = executeReplayFunction(replayCallee.callable, arguments_, state, {
708
+ ...context,
709
+ substitutions: new Map(replayCallee.substitutions)
710
+ }, replayCallee.receiver);
711
+ if (!result.executed) {
712
+ markReplayContainerEscaped(replayCallee.receiver);
713
+ return;
714
+ }
715
+ return result.value ?? createReplayLeaf(node, scope, state);
716
+ }
717
+ const localFunction = resolveCalledFunction(node.callee, scope, state, /* @__PURE__ */ new Set());
718
+ if (localFunction) {
719
+ const arguments_ = [];
720
+ for (const argument of node.arguments) {
721
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") {
722
+ invalidateReplayFunctionCaptures(localFunction.node, state, context);
723
+ return;
724
+ }
725
+ const value = evaluateReplayExpression(argument, scope, state, context);
726
+ if (!value) {
727
+ invalidateReplayFunctionCaptures(localFunction.node, state, context);
728
+ return;
729
+ }
730
+ arguments_.push(value);
731
+ }
732
+ const result = executeReplayFunction(localFunction, arguments_, state, context);
733
+ if (result.executed) return result.value ?? createReplayLeaf(node, scope, state);
734
+ for (const argument of arguments_) markReplayValueEscaped(argument);
735
+ invalidateReplayFunctionCaptures(localFunction.node, state, context);
736
+ return;
737
+ }
738
+ const callee = unwrapExpression(node.callee);
739
+ if (callee?.type === "MemberExpression" || callee?.type === "OptionalMemberExpression") {
740
+ const value = evaluateReplayExpression(callee.object, scope, state, context);
741
+ const method = readResolvedMemberProperty(callee, scope, state);
742
+ if (value?.type === "collection" && method) {
743
+ if (value.identity.escaped) return replayUnsafe;
744
+ if (method === "values") return {
745
+ ...value,
746
+ iteration: "values"
747
+ };
748
+ const firstArgument = node.arguments[0];
749
+ const keyValue = firstArgument && firstArgument.type !== "ArgumentPlaceholder" && firstArgument.type !== "SpreadElement" ? evaluateReplayExpression(firstArgument, scope, state, context) : void 0;
750
+ const key = keyValue ? replayCollectionKey(keyValue, state) : void 0;
751
+ if (method === "get" && value.identity.kind === "map") {
752
+ const entry = key === void 0 ? void 0 : value.identity.entries.get(key);
753
+ return entry?.type === "leaf" ? {
754
+ ...entry,
755
+ exactSelection: true,
756
+ selectionKind: "collection"
757
+ } : entry;
758
+ }
759
+ if (method === "set" && value.identity.kind === "map") {
760
+ if (value.writePolicy !== "forward") return value;
761
+ const next = node.arguments[1];
762
+ const entry = next && next.type !== "ArgumentPlaceholder" && next.type !== "SpreadElement" ? evaluateReplayExpression(next, scope, state, context) : void 0;
763
+ if (key === void 0 || !entry) {
764
+ markReplayCollectionEscaped(value);
765
+ return;
766
+ }
767
+ value.identity.entries.set(key, entry);
768
+ const templateKey = keyValue ? replayCollectionTemplateKey(keyValue, context, state) : void 0;
769
+ if (templateKey !== void 0) value.identity.templateKeys.set(key, templateKey);
770
+ return value;
771
+ }
772
+ if (method === "add" && value.identity.kind === "set" && keyValue) {
773
+ if (value.writePolicy !== "forward") return value;
774
+ value.identity.entries.set(key ?? `entry:${value.identity.entries.size}`, keyValue);
775
+ return value;
776
+ }
777
+ if (method === "delete" && key !== void 0) {
778
+ if (value.writePolicy !== "forward") return createReplayLeaf(node, scope, state);
779
+ value.identity.entries.delete(key);
780
+ value.identity.templateKeys.delete(key);
781
+ return createReplayLeaf(node, scope, state);
782
+ }
783
+ markReplayCollectionEscaped(value);
784
+ return;
785
+ }
786
+ if (value?.type === "container" && method) {
787
+ const transformed = evaluateReplayArrayTransform(value, method, node, scope, state, context);
788
+ if (transformed) return transformed;
789
+ const callbackNode = node.arguments[0];
790
+ const callback = callbackNode && callbackNode.type !== "ArgumentPlaceholder" && callbackNode.type !== "SpreadElement" ? resolveCalledFunction(callbackNode, scope, state, /* @__PURE__ */ new Set()) : void 0;
791
+ if (callback && method === "forEach" && value.identity.snapshot.kind === "array") {
792
+ for (const entry of value.identity.snapshot.entries) {
793
+ if (!entry) continue;
794
+ if (!executeReplayFunction(callback, [entry], state, context).executed) {
795
+ invalidateReplayFunctionCaptures(callback.node, state, context);
796
+ markReplayContainerEscaped(value);
797
+ return;
798
+ }
799
+ }
800
+ return createReplayLeaf(node, scope, state);
801
+ }
802
+ if (callback && [
803
+ "every",
804
+ "filter",
805
+ "find",
806
+ "findIndex",
807
+ "findLast",
808
+ "findLastIndex",
809
+ "flatMap",
810
+ "forEach",
811
+ "reduce",
812
+ "reduceRight",
813
+ "some"
814
+ ].includes(method)) {
815
+ invalidateReplayFunctionCaptures(callback.node, state, context);
816
+ const body = callback.node.body;
817
+ if (body.type !== "BlockStatement" && replayExpressionHasWrites(body, state) || body.type === "BlockStatement" && body.body.some((statement) => statement.type !== "ReturnStatement")) markReplayContainerEscaped(value);
818
+ }
819
+ if ([
820
+ "pop",
821
+ "push",
822
+ "shift",
823
+ "splice",
824
+ "unshift"
825
+ ].includes(method) && applyReplayArrayMutation(value, method, node, scope, state, context)) return createReplayLeaf(node, scope, state);
826
+ if (!READONLY_ARRAY_TRANSFORMS.has(method)) markReplayContainerEscaped(value);
827
+ return;
828
+ }
829
+ }
830
+ for (const argument of node.arguments) {
831
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") continue;
832
+ const value = evaluateReplayExpression(argument, scope, state, context);
833
+ if (value?.type === "container") markReplayContainerEscaped(value);
834
+ if (value?.type === "ref") markReplayRefEscaped(value);
835
+ if (value?.type === "collection") markReplayCollectionEscaped(value);
836
+ }
837
+ }
838
+ /** Produces a stable key for the finite Map/Set values the replay supports. */
839
+ function replayCollectionKey(value, state) {
840
+ if (value.type === "leaf") {
841
+ if (value.knownValue) return knownValueKey(value.knownValue);
842
+ const primitive = readStaticFromScope(value.expression.node, value.expression.scope, /* @__PURE__ */ new Set(), value.expression.node.end ?? Number.POSITIVE_INFINITY, state.analysis);
843
+ return primitive.ok ? `${typeof primitive.value}:${String(primitive.value)}` : void 0;
844
+ }
845
+ if (value.type !== "container" && value.type !== "ref" && value.type !== "collection") return;
846
+ const identity = value.identity;
847
+ const existing = state.replayIdentityKeys.get(identity);
848
+ if (existing) return existing;
849
+ const key = `identity:${state.nextReplayIdentityKey++}`;
850
+ state.replayIdentityKeys.set(identity, key);
851
+ return key;
852
+ }
853
+ /** Names a collection key when the template can reference the same binding. */
854
+ function replayCollectionTemplateKey(value, context, state) {
855
+ if (value.type === "leaf") {
856
+ const primitive = readStaticFromScope(value.expression.node, value.expression.scope, /* @__PURE__ */ new Set(), value.expression.node.end ?? Number.POSITIVE_INFINITY, state.analysis);
857
+ if (primitive.ok && (typeof primitive.value === "string" || typeof primitive.value === "number")) return String(primitive.value);
858
+ return readResolvedMemberPath(value.expression.node, value.expression.scope, state);
859
+ }
860
+ if (!("identity" in value)) return void 0;
861
+ for (const [binding, candidate] of context.values) if (candidate && candidate.type === value.type && "identity" in candidate && candidate.identity === value.identity) return binding.identifier.name;
862
+ }
863
+ /** Evaluates finite Map, Set, and transparent Proxy constructors. */
864
+ function evaluateReplayNewExpression(node, scope, state, context) {
865
+ const callee = unwrapExpression(node.callee);
866
+ if (callee?.type !== "Identifier") return;
867
+ const localBinding = scope.getBinding(callee.name);
868
+ if (localBinding) {
869
+ const declaration = localBinding.path.node;
870
+ const classNode = declaration.type === "ClassDeclaration" || declaration.type === "ClassExpression" ? declaration : declaration.type === "VariableDeclarator" && declaration.init?.type === "ClassExpression" ? declaration.init : void 0;
871
+ if (!classNode || classNode.superClass || classNode.decorators?.length) return;
872
+ const prototypeEntries = /* @__PURE__ */ new Map();
873
+ const prototypeSetters = /* @__PURE__ */ new Map();
874
+ const instanceEntries = /* @__PURE__ */ new Map();
875
+ const instance = createReplayContainer({
876
+ kind: "object",
877
+ entries: instanceEntries,
878
+ prototype: createReplayContainer({
879
+ kind: "object",
880
+ entries: prototypeEntries,
881
+ setters: prototypeSetters
882
+ })
883
+ });
884
+ const instanceContext = {
885
+ ...context,
886
+ thisValue: instance
887
+ };
888
+ let constructor;
889
+ for (const member of classNode.body.body) {
890
+ if ("decorators" in member && member.decorators?.length) return void 0;
891
+ if (member.type === "ClassProperty" && !member.static) {
892
+ if (!member.value) continue;
893
+ const key = readResolvedPropertyKey(member, scope, state);
894
+ if (key === void 0) return void 0;
895
+ const value = evaluateReplayExpression(member.value, state.scopes.get(member.value) ?? scope, state, instanceContext);
896
+ if (!value) return void 0;
897
+ instanceEntries.set(key, value);
898
+ continue;
899
+ }
900
+ if (member.type !== "ClassMethod" || member.static) continue;
901
+ if (member.kind === "constructor") {
902
+ constructor = {
903
+ node: member,
904
+ scope: state.scopes.get(member) ?? scope
905
+ };
906
+ continue;
907
+ }
908
+ const key = readResolvedPropertyKey(member, scope, state);
909
+ if (key === void 0) return void 0;
910
+ if (member.kind === "get") prototypeEntries.set(key, {
911
+ type: "getter",
912
+ getter: {
913
+ node: member,
914
+ scope: state.scopes.get(member) ?? scope
915
+ },
916
+ substitutions: new Map(context.substitutions)
917
+ });
918
+ else if (member.kind === "method") prototypeEntries.set(key, {
919
+ type: "method",
920
+ callable: {
921
+ node: member,
922
+ scope: state.scopes.get(member) ?? scope
923
+ },
924
+ substitutions: new Map(context.substitutions)
925
+ });
926
+ else if (member.kind === "set") prototypeSetters.set(key, {
927
+ type: "method",
928
+ callable: {
929
+ node: member,
930
+ scope: state.scopes.get(member) ?? scope
931
+ },
932
+ substitutions: new Map(context.substitutions)
933
+ });
934
+ }
935
+ if (!constructor) return instance;
936
+ const arguments_ = [];
937
+ for (const argument of node.arguments) {
938
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") return;
939
+ const value = evaluateReplayExpression(argument, scope, state, context);
940
+ if (!value) return void 0;
941
+ arguments_.push(value);
942
+ }
943
+ const result = executeReplayFunction(constructor, arguments_, state, instanceContext, instance);
944
+ if (!result.executed) {
945
+ markReplayContainerEscaped(instance);
946
+ return;
947
+ }
948
+ return result.value?.type === "container" ? result.value : instance;
949
+ }
950
+ const first = node.arguments[0];
951
+ if (callee.name === "Map" || callee.name === "Set") {
952
+ const entries = /* @__PURE__ */ new Map();
953
+ const templateKeys = /* @__PURE__ */ new Map();
954
+ if (first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement") {
955
+ const source = evaluateReplayExpression(first, scope, state, context);
956
+ if (source?.type !== "container" || source.identity.snapshot.kind !== "array") return;
957
+ const copied = copyReplayContainerEntries(source, state, context);
958
+ if (!copied || copied.kind !== "array") return void 0;
959
+ for (const [index, item] of copied.entries.entries()) {
960
+ if (!item) continue;
961
+ if (callee.name === "Set") {
962
+ const key = replayCollectionKey(item, state) ?? `index:${index}`;
963
+ entries.set(key, item);
964
+ const templateKey = replayCollectionTemplateKey(item, context, state);
965
+ if (templateKey !== void 0) templateKeys.set(key, templateKey);
966
+ continue;
967
+ }
968
+ if (item.type !== "container" || item.identity.snapshot.kind !== "array") return;
969
+ const keyValue = readReplayContainerEntry(item, "0", state, context);
970
+ const mapValue = readReplayContainerEntry(item, "1", state, context);
971
+ if (!keyValue || !mapValue) return void 0;
972
+ const key = replayCollectionKey(keyValue, state);
973
+ if (key === void 0) return void 0;
974
+ entries.set(key, mapValue);
975
+ const templateKey = replayCollectionTemplateKey(keyValue, context, state);
976
+ if (templateKey !== void 0) templateKeys.set(key, templateKey);
977
+ }
978
+ }
979
+ return {
980
+ type: "collection",
981
+ identity: {
982
+ entries,
983
+ escaped: false,
984
+ kind: callee.name === "Map" ? "map" : "set",
985
+ templateKeys
986
+ },
987
+ iteration: callee.name === "Map" ? "entries" : "values",
988
+ writePolicy: "forward"
989
+ };
990
+ }
991
+ if (callee.name !== "Proxy" || !first || first.type === "ArgumentPlaceholder" || first.type === "SpreadElement") return;
992
+ const target = evaluateReplayExpression(first, scope, state, context);
993
+ const handlerNode = node.arguments[1];
994
+ if (!handlerNode || handlerNode.type === "ArgumentPlaceholder" || handlerNode.type === "SpreadElement") return;
995
+ const handler = unwrapExpression(handlerNode);
996
+ if (handler?.type !== "ObjectExpression") return void 0;
997
+ if (handler.properties.length === 0) return target;
998
+ const getProperty = handler.properties.find((property) => property.type === "ObjectMethod" && readResolvedPropertyKey(property, scope, state) === "get");
999
+ if (getProperty?.type !== "ObjectMethod") return void 0;
1000
+ const returns = collectFunctionReturnExpressions(getProperty, scope, state);
1001
+ if (returns.length !== 1) return void 0;
1002
+ const returned = evaluateReplayExpression(returns[0].node, returns[0].scope, state, context);
1003
+ return returned ? createReplayContainer({
1004
+ kind: "object",
1005
+ entries: new Map([[unknownTemplatePathSegment, returned]])
1006
+ }) : void 0;
1007
+ }
1008
+ /** Evaluates the container identity or captured leaf produced by an expression. */
1009
+ function evaluateReplayExpression(node, scope, state, context) {
1010
+ const expression = unwrapExpression(node);
1011
+ if (!expression) return void 0;
1012
+ if (expression.type === "ThisExpression") return context.thisValue;
1013
+ if (expression.type === "Identifier") {
1014
+ const binding = scope.getBinding(expression.name);
1015
+ if (binding) {
1016
+ const substituted = context.substitutions.get(binding);
1017
+ if (substituted) return substituted;
1018
+ if (context.values.has(binding)) return context.values.get(binding);
1019
+ }
1020
+ return createReplayLeaf(expression, scope, state);
1021
+ }
1022
+ if (expression.type === "ArrowFunctionExpression" || expression.type === "FunctionExpression") return {
1023
+ type: "function",
1024
+ boundArguments: [],
1025
+ callable: {
1026
+ node: expression,
1027
+ scope: state.scopes.get(expression) ?? scope
1028
+ },
1029
+ substitutions: new Map(context.substitutions)
1030
+ };
1031
+ if (expression.type === "ArrayExpression") return evaluateReplayArray(expression, scope, state, context);
1032
+ if (expression.type === "ObjectExpression") return evaluateReplayObject(expression, scope, state, context);
1033
+ if (expression.type === "NewExpression") return evaluateReplayNewExpression(expression, scope, state, context);
1034
+ if (expression.type === "MemberExpression" || expression.type === "OptionalMemberExpression") return evaluateReplayMember(expression, scope, state, context) ?? createReplayLeaf(expression, scope, state);
1035
+ if (expression.type === "CallExpression" || expression.type === "OptionalCallExpression") return evaluateReplayCall(expression, scope, state, context);
1036
+ if (expression.type === "SequenceExpression") {
1037
+ const last = expression.expressions.at(-1);
1038
+ return last ? evaluateReplayExpression(last, scope, state, context) : void 0;
1039
+ }
1040
+ if (expression.type === "AssignmentExpression") return evaluateReplayExpression(expression.right, scope, state, context);
1041
+ return createReplayLeaf(expression, scope, state);
1042
+ }
1043
+ /** Splits a static member target into its base expression and property path. */
1044
+ function readReplayMemberTarget(node, scope, state) {
1045
+ const properties = [];
1046
+ let current = node;
1047
+ while (current.type === "MemberExpression" || current.type === "OptionalMemberExpression") {
1048
+ const property = readResolvedMemberProperty(current, scope, state);
1049
+ if (property === void 0) return void 0;
1050
+ properties.unshift(property);
1051
+ current = current.object;
1052
+ }
1053
+ return {
1054
+ base: current,
1055
+ properties
1056
+ };
1057
+ }
1058
+ /** Finds the accessor setter JavaScript would invoke for one property write. */
1059
+ function readReplayContainerSetter(value, property, receiver = value, seen = /* @__PURE__ */ new Set()) {
1060
+ if (value.identity.escaped || value.identity.snapshot.kind !== "object" || seen.has(value.identity)) return;
1061
+ const snapshot = value.identity.snapshot;
1062
+ const setter = snapshot.setters?.get(property);
1063
+ if (setter) return {
1064
+ ...setter,
1065
+ receiver
1066
+ };
1067
+ if (snapshot.entries.has(property)) return snapshot.entries.get(property)?.type === "getter" ? void 0 : null;
1068
+ return snapshot.prototype ? readReplayContainerSetter(snapshot.prototype, property, receiver, new Set(seen).add(value.identity)) : null;
1069
+ }
1070
+ /** Applies one direct or nested member assignment to a replayed identity. */
1071
+ function applyReplayMemberAssignment(left, right, scope, state, context) {
1072
+ const target = readReplayMemberTarget(left, scope, state);
1073
+ if (!target || target.properties.length === 0) return false;
1074
+ let value = evaluateReplayExpression(target.base, scope, state, context);
1075
+ for (const property of target.properties.slice(0, -1)) {
1076
+ const child = value?.type === "container" ? readReplayContainerEntry(value, property, state, context) : value?.type === "ref" && property === "value" ? readReplayRefValue(value) : value?.type === "computed" && property === "value" ? evaluateReplayComputed(value, state, context) : void 0;
1077
+ if (!child) {
1078
+ if (value?.type === "container") markReplayContainerEscaped(value);
1079
+ if (value?.type === "ref") markReplayRefEscaped(value);
1080
+ return false;
1081
+ }
1082
+ value = child;
1083
+ }
1084
+ const property = target.properties.at(-1);
1085
+ if (value?.type === "ref") {
1086
+ if (property !== "value") {
1087
+ markReplayRefEscaped(value);
1088
+ return false;
1089
+ }
1090
+ if (value.writePolicy !== "forward") return true;
1091
+ value.identity.value = evaluateReplayExpression(right, scope, state, context);
1092
+ return value.identity.value !== void 0;
1093
+ }
1094
+ if (value?.type !== "container") return false;
1095
+ if (value.writePolicy !== "forward") return true;
1096
+ const snapshot = value.identity.snapshot;
1097
+ if (snapshot.kind === "array" && property === "length") {
1098
+ const length = readStaticFromScope(right, scope, /* @__PURE__ */ new Set(), right.end ?? Number.POSITIVE_INFINITY, state.analysis, true);
1099
+ if (!length.ok || typeof length.value !== "number" || !Number.isInteger(length.value) || length.value < 0) {
1100
+ markReplayContainerEscaped(value);
1101
+ return false;
1102
+ }
1103
+ snapshot.entries.length = length.value;
1104
+ return true;
1105
+ }
1106
+ const replacement = evaluateReplayExpression(right, scope, state, context);
1107
+ if (!replacement) {
1108
+ markReplayContainerEscaped(value);
1109
+ return false;
1110
+ }
1111
+ if (snapshot.kind === "object") {
1112
+ const setter = readReplayContainerSetter(value, property);
1113
+ if (setter === void 0) {
1114
+ markReplayContainerEscaped(value);
1115
+ return false;
1116
+ }
1117
+ if (setter) {
1118
+ if (!executeReplayFunction(setter.callable, [replacement], state, {
1119
+ ...context,
1120
+ substitutions: new Map(setter.substitutions)
1121
+ }, setter.receiver).executed) {
1122
+ markReplayContainerEscaped(value);
1123
+ return false;
1124
+ }
1125
+ return true;
1126
+ }
1127
+ }
1128
+ if (snapshot.kind === "array") {
1129
+ if (!/^(0|[1-9]\d*)$/.test(property)) {
1130
+ markReplayContainerEscaped(value);
1131
+ return false;
1132
+ }
1133
+ snapshot.entries[Number(property)] = replacement;
1134
+ } else snapshot.entries.set(property, replacement);
1135
+ return true;
1136
+ }
1137
+ /** Applies JavaScript delete semantics to one replayed own property. */
1138
+ function applyReplayMemberDelete(argument, scope, state, context) {
1139
+ const target = readReplayMemberTarget(argument, scope, state);
1140
+ if (!target || target.properties.length === 0) return false;
1141
+ let value = evaluateReplayExpression(target.base, scope, state, context);
1142
+ for (const property of target.properties.slice(0, -1)) {
1143
+ value = value?.type === "container" ? readReplayContainerEntry(value, property, state, context) : value?.type === "ref" && property === "value" ? readReplayRefValue(value) : value?.type === "computed" && property === "value" ? evaluateReplayComputed(value, state, context) : void 0;
1144
+ if (!value) return false;
1145
+ }
1146
+ if (value?.type !== "container") return false;
1147
+ if (value.writePolicy !== "forward") return true;
1148
+ const property = target.properties.at(-1);
1149
+ const snapshot = value.identity.snapshot;
1150
+ if (snapshot.kind === "array") {
1151
+ if (!/^(0|[1-9]\d*)$/.test(property)) return false;
1152
+ snapshot.entries[Number(property)] = void 0;
1153
+ } else snapshot.entries.delete(property);
1154
+ return true;
1155
+ }
1156
+ /** Invalidates one replay binding and every identity reachable through it. */
1157
+ function invalidateReplayBinding(binding, context) {
1158
+ if (!binding || !context.values.has(binding)) return;
1159
+ const value = context.values.get(binding);
1160
+ if (value?.type === "container") markReplayContainerEscaped(value);
1161
+ if (value?.type === "ref") markReplayRefEscaped(value);
1162
+ if (value?.type === "collection") markReplayCollectionEscaped(value);
1163
+ context.unsafeBindings.add(binding);
1164
+ context.values.set(binding, void 0);
1165
+ }
1166
+ /** Invalidates identities captured by a local callback we cannot execute. */
1167
+ function invalidateReplayFunctionCaptures(fn, state, context) {
1168
+ const path = state.paths.get(fn);
1169
+ if (!path) return;
1170
+ path.traverse({ Identifier(identifierPath) {
1171
+ invalidateReplayBinding(identifierPath.scope.getBinding(identifierPath.node.name), context);
1172
+ } });
1173
+ }
1174
+ /** Invalidates only identities referenced by unsupported control flow. */
1175
+ function invalidateReplayStatement(path, state, context) {
1176
+ if (path.isIdentifier()) invalidateReplayBinding(path.scope.getBinding(path.node.name), context);
1177
+ path.traverse({
1178
+ CallExpression(callPath) {
1179
+ const callable = resolveCalledFunction(callPath.node.callee, callPath.scope, state, /* @__PURE__ */ new Set());
1180
+ if (callable) invalidateReplayFunctionCaptures(callable.node, state, context);
1181
+ for (const argument of callPath.node.arguments) {
1182
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") continue;
1183
+ markReplayValueEscaped(evaluateReplayExpression(argument, callPath.scope, state, context));
1184
+ }
1185
+ },
1186
+ OptionalCallExpression(callPath) {
1187
+ const callable = resolveCalledFunction(callPath.node.callee, callPath.scope, state, /* @__PURE__ */ new Set());
1188
+ if (callable) invalidateReplayFunctionCaptures(callable.node, state, context);
1189
+ for (const argument of callPath.node.arguments) {
1190
+ if (argument.type === "ArgumentPlaceholder" || argument.type === "SpreadElement") continue;
1191
+ markReplayValueEscaped(evaluateReplayExpression(argument, callPath.scope, state, context));
1192
+ }
1193
+ },
1194
+ Identifier(identifierPath) {
1195
+ invalidateReplayBinding(identifierPath.scope.getBinding(identifierPath.node.name), context);
1196
+ }
1197
+ });
1198
+ }
1199
+ /** Executes one direct sibling statement in the finite identity subset. */
1200
+ function replayContainerStatement(path, state, context) {
1201
+ if (path.isImportDeclaration() || path.isFunctionDeclaration()) return;
1202
+ if (path.isVariableDeclaration()) {
1203
+ for (const declarator of path.get("declarations")) {
1204
+ if (!declarator.isVariableDeclarator()) continue;
1205
+ if (declarator.node.id.type !== "Identifier") {
1206
+ const source = declarator.node.init ? evaluateReplayExpression(declarator.node.init, declarator.scope, state, context) : void 0;
1207
+ if (source?.type === "unsafe" || source?.type === "container" && source.identity.escaped || source?.type === "collection" && source.identity.escaped || source?.type === "ref" && source.identity.escaped) {
1208
+ for (const name of collectPatternBindingNames(declarator.node.id)) {
1209
+ const binding = declarator.scope.getBinding(name);
1210
+ if (!binding) continue;
1211
+ context.unsafeBindings.add(binding);
1212
+ context.values.set(binding, replayUnsafe);
1213
+ }
1214
+ continue;
1215
+ }
1216
+ invalidateReplayStatement(declarator, state, context);
1217
+ continue;
1218
+ }
1219
+ const binding = declarator.scope.getBinding(declarator.node.id.name);
1220
+ if (!binding) continue;
1221
+ const value = declarator.node.init ? evaluateReplayExpression(declarator.node.init, declarator.scope, state, context) : void 0;
1222
+ if (value?.type === "unsafe") context.unsafeBindings.add(binding);
1223
+ else context.unsafeBindings.delete(binding);
1224
+ context.values.set(binding, value);
1225
+ }
1226
+ return;
1227
+ }
1228
+ if (!path.isExpressionStatement()) {
1229
+ invalidateReplayStatement(path, state, context);
1230
+ return;
1231
+ }
1232
+ const expression = unwrapExpression(path.node.expression);
1233
+ if (expression?.type === "UnaryExpression" && expression.operator === "delete" && (expression.argument.type === "MemberExpression" || expression.argument.type === "OptionalMemberExpression")) {
1234
+ if (!applyReplayMemberDelete(expression.argument, path.scope, state, context)) invalidateReplayStatement(path, state, context);
1235
+ return;
1236
+ }
1237
+ if (expression?.type === "AssignmentExpression") {
1238
+ if (expression.operator !== "=") {
1239
+ invalidateReplayStatement(path, state, context);
1240
+ return;
1241
+ }
1242
+ if (expression.left.type === "Identifier") {
1243
+ const binding = path.scope.getBinding(expression.left.name);
1244
+ if (!binding) return;
1245
+ const value = evaluateReplayExpression(expression.right, path.scope, state, context);
1246
+ if (value?.type === "unsafe") context.unsafeBindings.add(binding);
1247
+ else context.unsafeBindings.delete(binding);
1248
+ context.values.set(binding, value);
1249
+ return;
1250
+ }
1251
+ if (expression.left.type === "MemberExpression" || expression.left.type === "OptionalMemberExpression") {
1252
+ if (!applyReplayMemberAssignment(expression.left, expression.right, path.scope, state, context)) invalidateReplayStatement(path, state, context);
1253
+ return;
1254
+ }
1255
+ invalidateReplayStatement(path, state, context);
1256
+ return;
1257
+ }
1258
+ if (expression?.type === "CallExpression" || expression?.type === "OptionalCallExpression") {
1259
+ evaluateReplayCall(expression, path.scope, state, context);
1260
+ return;
1261
+ }
1262
+ invalidateReplayStatement(path, state, context);
1263
+ }
1264
+ /** Replays one lexical statement list once and caches it for every binding. */
1265
+ function readContainerIdentityReplay(binding, state) {
1266
+ const statement = binding.path.getStatementParent();
1267
+ const bodyPath = statement?.parentPath;
1268
+ if (!statement || !bodyPath || !bodyPath.isProgram() && !bodyPath.isBlockStatement()) return;
1269
+ const cached = state.containerIdentityReplays.get(bodyPath.node);
1270
+ if (cached) return cached;
1271
+ const context = {
1272
+ allowGetterEffects: true,
1273
+ substitutions: /* @__PURE__ */ new Map(),
1274
+ unsafeBindings: /* @__PURE__ */ new Set(),
1275
+ values: /* @__PURE__ */ new Map()
1276
+ };
1277
+ const body = bodyPath.get("body");
1278
+ if (!Array.isArray(body)) return void 0;
1279
+ for (const child of body) replayContainerStatement(child, state, context);
1280
+ const replay = {
1281
+ unsafeBindings: context.unsafeBindings,
1282
+ values: context.values
1283
+ };
1284
+ state.containerIdentityReplays.set(bodyPath.node, replay);
1285
+ return replay;
1286
+ }
1287
+ /** Replays earlier sibling statements and reads one call target in-place. */
1288
+ function evaluateReplayAtPosition(node, scope, atPosition, state) {
1289
+ const expression = unwrapExpression(node) ?? node;
1290
+ const statement = (state.paths.get(expression) ?? state.paths.get(node))?.getStatementParent();
1291
+ const bodyPath = statement?.parentPath;
1292
+ if (!statement || !bodyPath || !bodyPath.isProgram() && !bodyPath.isBlockStatement()) return;
1293
+ const body = bodyPath.get("body");
1294
+ if (!Array.isArray(body)) return void 0;
1295
+ const context = {
1296
+ allowGetterEffects: true,
1297
+ substitutions: /* @__PURE__ */ new Map(),
1298
+ unsafeBindings: /* @__PURE__ */ new Set(),
1299
+ values: /* @__PURE__ */ new Map()
1300
+ };
1301
+ for (const child of body) {
1302
+ if (child.node === statement.node || (child.node.start ?? Number.POSITIVE_INFINITY) >= atPosition) break;
1303
+ replayContainerStatement(child, state, context);
1304
+ }
1305
+ return evaluateReplayExpression(expression, scope, state, context);
1306
+ }
1307
+ /** Applies Vue template top-level ref/computed unwrapping to replayed bindings. */
1308
+ function readReplayTemplateValue(value, state, replay) {
1309
+ const context = {
1310
+ substitutions: /* @__PURE__ */ new Map(),
1311
+ unsafeBindings: replay.unsafeBindings,
1312
+ values: replay.values
1313
+ };
1314
+ const seen = /* @__PURE__ */ new Set();
1315
+ let current = value;
1316
+ while (current && !seen.has(current) && (current.type === "ref" || current.type === "computed")) {
1317
+ seen.add(current);
1318
+ current = current.type === "ref" ? readReplayRefValue(current) : evaluateReplayComputed(current, state, context);
1319
+ }
1320
+ return current;
1321
+ }
1322
+ /** Reads a final scalar component identity without reviving stale sources. */
1323
+ function readReplayLeafState(binding, state) {
1324
+ const replay = readContainerIdentityReplay(binding, state);
1325
+ if (!replay || !replay.values.has(binding)) return void 0;
1326
+ const value = readReplayTemplateValue(replay.values.get(binding), state, replay);
1327
+ if (value?.type === "unsafe") return { status: "unsafe" };
1328
+ return value?.type === "leaf" && value.exactSelection && value.hasGT !== void 0 ? {
1329
+ status: "leaf",
1330
+ value
1331
+ } : void 0;
1332
+ }
1333
+ /** Keeps exact replay from bypassing deliberate opaque-resolution boundaries. */
1334
+ function readSafeReplayLeafOverride(binding, replayLeaf, state) {
1335
+ if (replayLeaf?.status !== "leaf") return void 0;
1336
+ const { value } = replayLeaf;
1337
+ if (bindingReadsUnsafeMutableImport(binding, state)) return void 0;
1338
+ if (value.knownValue?.type === "vue-builtin") return void 0;
1339
+ if (value.selectionKind === "ref" && value.knownValue?.type === "component") return;
1340
+ return isReplayGetterStringLeaf(value) ? void 0 : replayLeaf;
1341
+ }
1342
+ /** String translators selected through a getter remain intentionally opaque. */
1343
+ function isReplayGetterStringLeaf(value) {
1344
+ return value.selectionKind === "getter" && value.knownValue?.type === "string";
1345
+ }
1346
+ /** Detects unresolved mutable identities retained by one final replay value. */
1347
+ function replayBindingRetainsUnsafeIdentity(binding, state) {
1348
+ const replay = readContainerIdentityReplay(binding, state);
1349
+ if (!replay || replay.unsafeBindings.has(binding)) return Boolean(replay);
1350
+ const seen = /* @__PURE__ */ new Set();
1351
+ const visit = (value) => {
1352
+ if (!value) return false;
1353
+ if (value.type === "unsafe") return true;
1354
+ if (value.type === "container") {
1355
+ if (value.identity.escaped || seen.has(value.identity)) return value.identity.escaped;
1356
+ seen.add(value.identity);
1357
+ const snapshot = value.identity.snapshot;
1358
+ const entries = snapshot.kind === "array" ? snapshot.entries : snapshot.entries.values();
1359
+ for (const entry of entries) if (visit(entry)) return true;
1360
+ return snapshot.kind === "object" && snapshot.prototype ? visit(snapshot.prototype) : false;
1361
+ }
1362
+ if (value.type === "ref") {
1363
+ if (value.identity.escaped || seen.has(value.identity)) return value.identity.escaped;
1364
+ seen.add(value.identity);
1365
+ return visit(value.identity.value);
1366
+ }
1367
+ if (value.type === "collection") {
1368
+ if (value.identity.escaped || seen.has(value.identity)) return value.identity.escaped;
1369
+ seen.add(value.identity);
1370
+ return [...value.identity.entries.values()].some(visit);
1371
+ }
1372
+ if (value.type === "function") return value.boundArguments.some(visit) || [...value.substitutions.values()].some(visit);
1373
+ if (value.type === "getter" || value.type === "method") return [...value.substitutions.values()].some(visit);
1374
+ return false;
1375
+ };
1376
+ return visit(replay.values.get(binding));
1377
+ }
1378
+ /** Collects exact tainted-container paths from one final runtime identity. */
1379
+ function replayContainerIdentityHasGT(value, seen, state, context) {
1380
+ if (value.identity.escaped) return void 0;
1381
+ if (seen.has(value.identity)) return false;
1382
+ const nextSeen = new Set(seen).add(value.identity);
1383
+ const visible = readReplayVisibleContainerEntries(value, state, context);
1384
+ if (!visible) return void 0;
1385
+ let unknown = false;
1386
+ for (const [, entry] of visible) {
1387
+ if (!entry) continue;
1388
+ if (entry.type === "leaf") {
1389
+ if (entry.hasGT) return true;
1390
+ if (entry.hasGT === void 0) unknown = true;
1391
+ continue;
1392
+ }
1393
+ if (entry.type !== "container") {
1394
+ unknown = true;
1395
+ continue;
1396
+ }
1397
+ const nested = replayContainerIdentityHasGT(entry, nextSeen, state, context);
1398
+ if (nested) return true;
1399
+ if (nested === void 0) unknown = true;
1400
+ }
1401
+ return unknown ? void 0 : false;
1402
+ }
1403
+ /** Collects exact tainted-container paths from one final runtime identity. */
1404
+ function collectReplayGTContainerPaths(value, basePath, seen, state, context) {
1405
+ if (value.identity.escaped) return new Set([basePath]);
1406
+ if (seen.has(value.identity)) {
1407
+ const hasGT = replayContainerIdentityHasGT(value, /* @__PURE__ */ new Set(), state, context);
1408
+ return hasGT === void 0 ? void 0 : hasGT ? new Set([appendTemplatePath(basePath, recursiveTemplatePathSegment)]) : /* @__PURE__ */ new Set();
1409
+ }
1410
+ const nextSeen = new Set(seen).add(value.identity);
1411
+ const result = /* @__PURE__ */ new Set();
1412
+ const entries = readReplayVisibleContainerEntries(value, state, context);
1413
+ if (!entries) return void 0;
1414
+ for (const [key, entry] of entries) {
1415
+ if (!entry) continue;
1416
+ if (entry.type === "leaf") {
1417
+ if (entry.hasGT === void 0) return void 0;
1418
+ if (entry.hasGT) result.add(basePath);
1419
+ continue;
1420
+ }
1421
+ if (entry.type !== "container") return void 0;
1422
+ const nested = collectReplayGTContainerPaths(entry, appendTemplatePath(basePath, key), nextSeen, state, context);
1423
+ if (!nested) return void 0;
1424
+ for (const path of nested) result.add(path);
1425
+ }
1426
+ return result;
1427
+ }
1428
+ /** Conservatively taints a finite Map/Set when any selected value can be T. */
1429
+ function collectReplayCollectionGTContainerPaths(value, basePath, state, context) {
1430
+ if (value.identity.escaped) return new Set([basePath]);
1431
+ let nestedGT = false;
1432
+ for (const entry of value.identity.entries.values()) {
1433
+ if (entry.type === "leaf") {
1434
+ if (entry.hasGT === void 0) return void 0;
1435
+ continue;
1436
+ }
1437
+ if (entry.type === "container") {
1438
+ const nested = collectReplayGTContainerPaths(entry, basePath, /* @__PURE__ */ new Set(), state, context);
1439
+ if (!nested) return void 0;
1440
+ nestedGT ||= nested.size > 0;
1441
+ continue;
1442
+ }
1443
+ return;
1444
+ }
1445
+ return nestedGT ? new Set([basePath]) : /* @__PURE__ */ new Set();
1446
+ }
1447
+ /** Reads exact final T-container paths when identity replay stayed finite. */
1448
+ function readDefiniteReplayGTContainerPaths(binding, state) {
1449
+ const replay = readContainerIdentityReplay(binding, state);
1450
+ if (!replay || !replay.values.has(binding)) return void 0;
1451
+ const context = {
1452
+ substitutions: /* @__PURE__ */ new Map(),
1453
+ unsafeBindings: replay.unsafeBindings,
1454
+ values: replay.values
1455
+ };
1456
+ const value = replay ? readReplayTemplateValue(replay.values.get(binding), state, replay) : void 0;
1457
+ if (value?.type === "container") return collectReplayGTContainerPaths(value, binding.identifier.name, /* @__PURE__ */ new Set(), state, context) ?? null;
1458
+ if (value?.type === "collection") return collectReplayCollectionGTContainerPaths(value, binding.identifier.name, state, context) ?? null;
1459
+ if (value?.type === "unsafe") return null;
1460
+ return value === void 0 && replay.unsafeBindings.has(binding) ? null : void 0;
1461
+ }
1462
+ /** Reads exact final array/object shape from the same identity replay. */
1463
+ function readReplayContainerMetadata(binding, basePath, state) {
1464
+ const replay = readContainerIdentityReplay(binding, state);
1465
+ if (!replay) return void 0;
1466
+ const context = {
1467
+ substitutions: /* @__PURE__ */ new Map(),
1468
+ unsafeBindings: replay.unsafeBindings,
1469
+ values: replay.values
1470
+ };
1471
+ const root = replay ? readReplayTemplateValue(replay.values.get(binding), state, replay) : void 0;
1472
+ if (root?.type === "collection") return root.identity.escaped ? void 0 : {
1473
+ arrayLengths: /* @__PURE__ */ new Map(),
1474
+ kinds: new Map([[basePath, "object"]])
1475
+ };
1476
+ if (root?.type !== "container") return void 0;
1477
+ const arrayLengths = /* @__PURE__ */ new Map();
1478
+ const kinds = /* @__PURE__ */ new Map();
1479
+ const visit = (value, path, seen) => {
1480
+ if (value.identity.escaped) return false;
1481
+ if (seen.has(value.identity)) return true;
1482
+ const nextSeen = new Set(seen).add(value.identity);
1483
+ const snapshot = value.identity.snapshot;
1484
+ kinds.set(path, snapshot.kind);
1485
+ if (snapshot.kind === "array") arrayLengths.set(path, snapshot.entries.length);
1486
+ const entries = readReplayVisibleContainerEntries(value, state, context);
1487
+ if (!entries) return false;
1488
+ for (const [key, entry] of entries) if (entry?.type === "container" && !visit(entry, appendTemplatePath(path, key), nextSeen)) return false;
1489
+ return true;
1490
+ };
1491
+ return visit(root, basePath, /* @__PURE__ */ new Set()) ? {
1492
+ arrayLengths,
1493
+ kinds
1494
+ } : void 0;
1495
+ }
1496
+ /** Exposes exact component leaves from a replayed final container. */
1497
+ function readReplayComponentCandidates(binding, basePath, state) {
1498
+ const replay = readContainerIdentityReplay(binding, state);
1499
+ if (!replay) return void 0;
1500
+ const context = {
1501
+ substitutions: /* @__PURE__ */ new Map(),
1502
+ unsafeBindings: replay.unsafeBindings,
1503
+ values: replay.values
1504
+ };
1505
+ const root = replay ? readReplayTemplateValue(replay.values.get(binding), state, replay) : void 0;
1506
+ if (root?.type === "collection") {
1507
+ if (root.identity.escaped) return void 0;
1508
+ const result = [];
1509
+ for (const [key, entry] of root.identity.entries) {
1510
+ if (entry.type !== "leaf" || entry.hasGT === void 0) return void 0;
1511
+ if (!entry.knownValue) continue;
1512
+ const name = appendTemplatePath(basePath, root.identity.templateKeys.get(key) ?? "%GT_UNKNOWN%");
1513
+ result.push({
1514
+ certain: !isReplayGetterStringLeaf(entry),
1515
+ name,
1516
+ value: entry.knownValue
1517
+ });
1518
+ }
1519
+ return result;
1520
+ }
1521
+ if (root?.type !== "container") return void 0;
1522
+ const result = [];
1523
+ const visit = (value, path, seen) => {
1524
+ if (value.identity.escaped) return false;
1525
+ if (seen.has(value.identity)) return true;
1526
+ const nextSeen = new Set(seen).add(value.identity);
1527
+ const entries = readReplayVisibleContainerEntries(value, state, context);
1528
+ if (!entries) return false;
1529
+ for (const [key, entry] of entries) {
1530
+ if (!entry) continue;
1531
+ const childPath = appendTemplatePath(path, key);
1532
+ if (entry.type === "container") {
1533
+ if (!visit(entry, childPath, nextSeen)) return false;
1534
+ } else if (entry.type === "leaf") {
1535
+ if (entry.hasGT === void 0) return false;
1536
+ if (entry.knownValue) result.push({
1537
+ certain: !isReplayGetterStringLeaf(entry),
1538
+ name: childPath,
1539
+ value: entry.knownValue
1540
+ });
1541
+ } else return false;
1542
+ }
1543
+ return true;
1544
+ };
1545
+ return visit(root, basePath, /* @__PURE__ */ new Set()) ? result : void 0;
1546
+ }
1547
+ /** Exposes pure receiver methods whose final return is a known component. */
1548
+ function readReplayComponentFactoryCandidates(binding, basePath, state) {
1549
+ const replay = readContainerIdentityReplay(binding, state);
1550
+ if (!replay) return void 0;
1551
+ const context = {
1552
+ substitutions: /* @__PURE__ */ new Map(),
1553
+ unsafeBindings: replay.unsafeBindings,
1554
+ values: replay.values
1555
+ };
1556
+ const root = readReplayTemplateValue(replay.values.get(binding), state, replay);
1557
+ if (root?.type !== "container") return void 0;
1558
+ const result = [];
1559
+ const visit = (value, path, seen) => {
1560
+ if (value.identity.escaped) return false;
1561
+ if (seen.has(value.identity)) return true;
1562
+ const entries = readReplayVisibleContainerEntries(value, state, context);
1563
+ if (!entries) return false;
1564
+ const nextSeen = new Set(seen).add(value.identity);
1565
+ for (const [key, entry] of entries) {
1566
+ if (!entry) continue;
1567
+ const childPath = appendTemplatePath(path, key);
1568
+ if (entry.type === "container") {
1569
+ if (!visit(entry, childPath, nextSeen)) return false;
1570
+ continue;
1571
+ }
1572
+ if (entry.type === "leaf") {
1573
+ if (entry.hasGT === void 0) return false;
1574
+ continue;
1575
+ }
1576
+ if (entry.type !== "method" || !entry.receiver) return false;
1577
+ const body = entry.callable.node.body;
1578
+ if (body.type === "BlockStatement" && (body.body.length !== 1 || body.body[0]?.type !== "ReturnStatement")) return false;
1579
+ const returns = collectFunctionReturnExpressions(entry.callable.node, entry.callable.scope, state);
1580
+ if (returns.length !== 1) return false;
1581
+ const returned = evaluateReplayExpression(returns[0].node, returns[0].scope, state, {
1582
+ ...context,
1583
+ substitutions: new Map(entry.substitutions),
1584
+ thisValue: entry.receiver
1585
+ });
1586
+ if (returned?.type !== "leaf" || returned.hasGT === void 0) return false;
1587
+ if (returned.knownValue?.type === "component" || returned.knownValue?.type === "vue-builtin") result.push({
1588
+ gt: returned.knownValue.type === "component" && returned.knownValue.name === "T",
1589
+ name: childPath
1590
+ });
1591
+ }
1592
+ return true;
1593
+ };
1594
+ return visit(root, basePath, /* @__PURE__ */ new Set()) ? result : void 0;
1595
+ }
1596
+ return {
1597
+ evaluateReplayAtPosition,
1598
+ isReplayGetterStringLeaf,
1599
+ readDefiniteReplayGTContainerPaths,
1600
+ readReplayComponentCandidates,
1601
+ readReplayComponentFactoryCandidates,
1602
+ readReplayContainerMetadata,
1603
+ readReplayLeafState,
1604
+ readSafeReplayLeafOverride,
1605
+ replayBindingRetainsUnsafeIdentity
1606
+ };
1607
+ }
1608
+ //#endregion
1609
+ export { createReplayAnalysis };
1610
+
1611
+ //# sourceMappingURL=replay.js.map