@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,2198 @@
1
+ import { addVueError, createInlineMetadata, readStaticPrimitive, unwrapExpression } from "./utils.js";
2
+ import { processVueStringCall } from "./stringCalls.js";
3
+ import { appendTemplatePath, recursiveTemplatePathSegment, unknownTemplatePathSegment } from "./templatePath.js";
4
+ import { ElementTypes, NodeTypes } from "./compilerAst.js";
5
+ import { parseExpression } from "@babel/parser";
6
+ import traverseModule from "@babel/traverse";
7
+ import { isAcceptedPluralForm } from "generaltranslation/internal";
8
+ import * as babel from "@babel/types";
9
+ import { HTML_CONTENT_PROPS } from "@generaltranslation/format/types";
10
+ //#region src/internal/template.ts
11
+ const traverse = traverseModule.default || traverseModule;
12
+ const COMPONENT_SELECTING_ARRAY_METHODS = new Set([
13
+ "at",
14
+ "find",
15
+ "findLast",
16
+ "pop",
17
+ "shift"
18
+ ]);
19
+ const COMPONENT_PRESERVING_ARRAY_METHODS = new Set([
20
+ "concat",
21
+ "filter",
22
+ "reverse",
23
+ "slice",
24
+ "sort",
25
+ "splice",
26
+ "toReversed",
27
+ "toSorted",
28
+ "toSpliced"
29
+ ]);
30
+ const FOR_ALIAS_EXPRESSION = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
31
+ const FOR_ITERATOR_EXPRESSION = /,([^,}\]]*)(?:,([^,}\]]*))?$/;
32
+ const FOR_STRIP_PARENS = /^\(|\)$/g;
33
+ const NON_BRANCH_ATTRIBUTE_NAMES = new Set([
34
+ "branch",
35
+ "class",
36
+ "n",
37
+ "locales",
38
+ "key",
39
+ "ref",
40
+ "ref_for",
41
+ "ref_key",
42
+ "ref-for",
43
+ "ref-key",
44
+ "style"
45
+ ]);
46
+ const RESERVED_T_PROPS = new Set([
47
+ "key",
48
+ "ref",
49
+ "ref_for",
50
+ "ref_key",
51
+ "ref-for",
52
+ "ref-key"
53
+ ]);
54
+ const SOURCE_SHAPING_DIRECTIVES = new Set([
55
+ "if",
56
+ "else",
57
+ "else-if",
58
+ "for",
59
+ "html",
60
+ "text"
61
+ ]);
62
+ function parseVueTemplate(root, bindings, expressionPlugins, context) {
63
+ visitTemplateChildren(root.children, /* @__PURE__ */ new Set(), bindings, expressionPlugins, context, false);
64
+ }
65
+ function visitTemplateChildren(children, shadowed, bindings, expressionPlugins, context, insideTranslation) {
66
+ for (const child of children) {
67
+ if (child.type === NodeTypes.INTERPOLATION) {
68
+ processTemplateExpression(child.content, shadowed, bindings, expressionPlugins, context);
69
+ continue;
70
+ }
71
+ if (child.type !== NodeTypes.ELEMENT) continue;
72
+ const localBindings = collectElementScopeBindings(child, expressionPlugins);
73
+ const possibleScopedComponents = collectPossibleScopedComponentAliases(child, bindings, shadowed, expressionPlugins);
74
+ const possibleScopedContainers = collectPossibleScopedContainerAliases(child, bindings, shadowed, expressionPlugins);
75
+ const componentBindings = possibleScopedComponents.size > 0 ? createScopedComponentBindings(bindings, possibleScopedComponents) : bindings;
76
+ const childBindings = possibleScopedContainers.size > 0 ? createScopedContainerBindings(componentBindings, possibleScopedContainers, shadowed) : componentBindings;
77
+ const childShadowed = unionSets(shadowed, localBindings);
78
+ for (const localName of [...possibleScopedComponents, ...possibleScopedContainers.keys()]) childShadowed.delete(localName);
79
+ for (const property of child.props) {
80
+ if (property.type !== NodeTypes.DIRECTIVE) continue;
81
+ if (property.name === "for") {
82
+ const parseResult = readForParseResult(property);
83
+ for (const alias of [
84
+ parseResult?.value,
85
+ parseResult?.key,
86
+ parseResult?.index
87
+ ]) processBindingDefaults(alias, childShadowed, childBindings, expressionPlugins, context);
88
+ } else if (property.name === "slot") processBindingDefaults(property.exp, childShadowed, childBindings, expressionPlugins, context);
89
+ }
90
+ for (const property of child.props) {
91
+ if (property.type !== NodeTypes.DIRECTIVE) continue;
92
+ if (property.arg?.type === NodeTypes.SIMPLE_EXPRESSION && !property.arg.isStatic) processTemplateExpression(property.arg, childShadowed, childBindings, expressionPlugins, context);
93
+ if (property.name === "slot" || !property.exp) continue;
94
+ if (property.name === "for") {
95
+ const parseResult = readForParseResult(property);
96
+ if (parseResult?.source) processTemplateExpression(parseResult.source, shadowed, bindings, expressionPlugins, context);
97
+ continue;
98
+ }
99
+ processTemplateExpression(property.exp, property.name === "if" || property.name === "else-if" ? shadowed : childShadowed, property.name === "if" || property.name === "else-if" ? bindings : childBindings, expressionPlugins, context);
100
+ }
101
+ const component = resolveGTComponent(child, childBindings, expressionPlugins, childShadowed);
102
+ const suspense = resolveSuspenseComponent(child, childBindings, expressionPlugins, childShadowed);
103
+ const fragment = resolveFragmentComponent(child, childBindings, expressionPlugins, childShadowed);
104
+ const uncertainGTComponent = resolveUncertainComponentBinding(child, childBindings, childBindings.uncertainGTComponents, childBindings.uncertainRegisteredGTComponents, childBindings.gtComponentFactories, expressionPlugins, childShadowed);
105
+ const possibleDynamicT = component ? void 0 : resolvePossibleDynamicT(child, childBindings, expressionPlugins, childShadowed);
106
+ const unresolvedGTComponent = uncertainGTComponent ?? possibleDynamicT;
107
+ if (!insideTranslation && !component && unresolvedGTComponent) addVueError(context, child.loc, `Could not statically resolve possible gt-vue component alias "${unresolvedGTComponent}"`, "Use a direct gt-vue import or an immutable alias that does not escape static analysis");
108
+ if (component?.originalName === "Var" || component?.originalName === "Num" || component?.originalName === "DateTime" || component?.originalName === "Currency") validateVariableComponentShape(child, component.originalName, context);
109
+ if (component?.originalName === "T" && !insideTranslation) extractTranslationComponent(child, childShadowed, childBindings, expressionPlugins, context);
110
+ const childInsideTranslation = component?.originalName === "Var" || insideTranslation && isOpaqueComponent(child, component, suspense ?? fragment) ? false : insideTranslation || component?.originalName === "T";
111
+ if (childInsideTranslation && suspense) {
112
+ const suspenseElementIsFallback = hasStaticSlotName(child, "fallback");
113
+ for (const suspenseChild of child.children) visitTemplateChildren([suspenseChild], childShadowed, childBindings, expressionPlugins, context, suspenseElementIsFallback ? false : !isSuspenseFallbackTemplate(suspenseChild));
114
+ } else visitTemplateChildren(child.children, childShadowed, childBindings, expressionPlugins, context, childInsideTranslation);
115
+ }
116
+ }
117
+ /** Finds local Vue aliases whose runtime value can be a GT component. */
118
+ function collectPossibleScopedComponentAliases(element, bindings, shadowed, expressionPlugins) {
119
+ const aliases = /* @__PURE__ */ new Set();
120
+ for (const property of element.props) {
121
+ if (property.type !== NodeTypes.DIRECTIVE) continue;
122
+ if (property.name === "for") {
123
+ const parseResult = readForParseResult(property);
124
+ const pattern = parseResult?.value ? parseTemplateBindingPattern(parseResult.value, expressionPlugins) : void 0;
125
+ const source = parseResult?.source ? getExpressionNode(parseResult.source, expressionPlugins) : void 0;
126
+ if (!pattern || !source) continue;
127
+ collectPossiblePatternComponents(pattern, collectTemplateContainerCandidates(source, bindings, shadowed, /* @__PURE__ */ new Set()), bindings, shadowed, aliases);
128
+ continue;
129
+ }
130
+ if (property.name !== "slot" || property.exp?.type !== NodeTypes.SIMPLE_EXPRESSION || !property.exp.content) continue;
131
+ try {
132
+ const arrow = parseExpression(`(${property.exp.content}) => 0`, { plugins: expressionPlugins });
133
+ if (arrow.type !== "ArrowFunctionExpression") continue;
134
+ for (const parameter of arrow.params) collectPossibleComponentDefaults(parameter, bindings, shadowed, aliases);
135
+ } catch {}
136
+ }
137
+ return aliases;
138
+ }
139
+ /** Collects v-for aliases whose runtime value can itself be a container. */
140
+ function collectPossibleScopedContainerAliases(element, bindings, shadowed, expressionPlugins) {
141
+ const aliases = /* @__PURE__ */ new Map();
142
+ for (const property of element.props) {
143
+ if (property.type !== NodeTypes.DIRECTIVE || property.name !== "for") continue;
144
+ const parseResult = readForParseResult(property);
145
+ const pattern = parseResult?.value ? parseTemplateBindingPattern(parseResult.value, expressionPlugins) : void 0;
146
+ const source = parseResult?.source ? getExpressionNode(parseResult.source, expressionPlugins) : void 0;
147
+ if (!pattern || !source) continue;
148
+ collectPossiblePatternContainers(pattern, collectTemplateContainerCandidates(source, bindings, shadowed, /* @__PURE__ */ new Set()), bindings, shadowed, aliases);
149
+ }
150
+ return aliases;
151
+ }
152
+ /** Projects container alternatives through one v-for binding pattern. */
153
+ function collectPossiblePatternContainers(pattern, values, bindings, shadowed, aliases) {
154
+ if (pattern.type === "Identifier") {
155
+ if (values.containers.length === 0) return;
156
+ const existing = aliases.get(pattern.name);
157
+ aliases.set(pattern.name, existing ? mergeDynamicSelectorAnalyses([existing, values]) : values);
158
+ return;
159
+ }
160
+ if (pattern.type === "AssignmentPattern") {
161
+ if (!isTemplateBindingPattern(pattern.left)) return;
162
+ collectPossiblePatternContainers(pattern.left, values, bindings, shadowed, aliases);
163
+ collectPossiblePatternContainers(pattern.left, collectDynamicSelectorCandidates(pattern.right, bindings, shadowed, /* @__PURE__ */ new Set()), bindings, shadowed, aliases);
164
+ return;
165
+ }
166
+ if (pattern.type === "RestElement") {
167
+ if (isTemplateBindingPattern(pattern.argument)) collectPossiblePatternContainers(pattern.argument, values, bindings, shadowed, aliases);
168
+ return;
169
+ }
170
+ if (pattern.type === "ObjectPattern") {
171
+ for (const property of pattern.properties) {
172
+ const target = property.type === "RestElement" ? property.argument : property.value;
173
+ if (!isTemplateBindingPattern(target)) continue;
174
+ collectPossiblePatternContainers(target, property.type === "RestElement" ? values : selectPossibleContainerChildren(values, readTemplateLiteralPropertyKey(property, bindings, shadowed), bindings, shadowed), bindings, shadowed, aliases);
175
+ }
176
+ return;
177
+ }
178
+ pattern.elements.forEach((element, index) => {
179
+ if (!element || !isTemplateBindingPattern(element)) return;
180
+ collectPossiblePatternContainers(element, selectPossibleContainerChildren(values, element.type === "RestElement" ? void 0 : String(index), bindings, shadowed), bindings, shadowed, aliases);
181
+ });
182
+ }
183
+ /** Parses a Vue alias expression as one JavaScript binding pattern. */
184
+ function parseTemplateBindingPattern(expression, expressionPlugins) {
185
+ try {
186
+ const arrow = parseExpression(`(${expression.content}) => 0`, { plugins: expressionPlugins });
187
+ const parameter = arrow.type === "ArrowFunctionExpression" && arrow.params.length === 1 ? arrow.params[0] : void 0;
188
+ return parameter && isTemplateBindingPattern(parameter) ? parameter : void 0;
189
+ } catch {
190
+ return;
191
+ }
192
+ }
193
+ /** Projects possible iterable values through a v-for destructuring pattern. */
194
+ function collectPossiblePatternComponents(pattern, values, bindings, shadowed, aliases) {
195
+ if (pattern.type === "Identifier") {
196
+ if (selectorAnalysisMayContainGT(values, bindings)) aliases.add(pattern.name);
197
+ return;
198
+ }
199
+ if (pattern.type === "AssignmentPattern") {
200
+ if (!isTemplateBindingPattern(pattern.left)) return;
201
+ collectPossiblePatternComponents(pattern.left, values, bindings, shadowed, aliases);
202
+ const fallback = collectDynamicSelectorCandidates(pattern.right, bindings, shadowed, /* @__PURE__ */ new Set());
203
+ collectPossiblePatternComponents(pattern.left, fallback, bindings, shadowed, aliases);
204
+ return;
205
+ }
206
+ if (pattern.type === "RestElement") {
207
+ if (!isTemplateBindingPattern(pattern.argument)) return;
208
+ collectPossiblePatternComponents(pattern.argument, values, bindings, shadowed, aliases);
209
+ return;
210
+ }
211
+ if (pattern.type === "ObjectPattern") {
212
+ for (const property of pattern.properties) {
213
+ if (property.type === "RestElement") {
214
+ if (isTemplateBindingPattern(property.argument)) collectPossiblePatternComponents(property.argument, values, bindings, shadowed, aliases);
215
+ continue;
216
+ }
217
+ const selected = selectPossibleContainerChildren(values, readTemplateLiteralPropertyKey(property, bindings, shadowed), bindings, shadowed);
218
+ if (isTemplateBindingPattern(property.value)) collectPossiblePatternComponents(property.value, selected, bindings, shadowed, aliases);
219
+ }
220
+ return;
221
+ }
222
+ if (pattern.type === "ArrayPattern") pattern.elements.forEach((element, index) => {
223
+ if (!element) return;
224
+ const selected = selectPossibleContainerChildren(values, element.type === "RestElement" ? void 0 : String(index), bindings, shadowed);
225
+ if (isTemplateBindingPattern(element)) collectPossiblePatternComponents(element, selected, bindings, shadowed, aliases);
226
+ });
227
+ }
228
+ function isTemplateBindingPattern(node) {
229
+ return node.type === "ArrayPattern" || node.type === "AssignmentPattern" || node.type === "Identifier" || node.type === "ObjectPattern" || node.type === "RestElement";
230
+ }
231
+ /** Selects from every possible container carried by an abstract value. */
232
+ function selectPossibleContainerChildren(values, key, bindings, shadowed) {
233
+ const selected = values.containers.map((container) => selectTemplateContainerReference(container, key, bindings, shadowed, /* @__PURE__ */ new Set()));
234
+ return selected.length > 0 ? mergeDynamicSelectorAnalyses(selected) : emptyDynamicSelectorAnalysis(true);
235
+ }
236
+ /** Walks one binding pattern and records GT-bearing default expressions. */
237
+ function collectPossibleComponentDefaults(pattern, bindings, shadowed, aliases) {
238
+ if (pattern.type === "AssignmentPattern") {
239
+ if (pattern.left.type === "Identifier") {
240
+ if (selectorAnalysisMayContainGT(collectDynamicSelectorCandidates(pattern.right, bindings, shadowed, /* @__PURE__ */ new Set()), bindings)) aliases.add(pattern.left.name);
241
+ }
242
+ collectPossibleComponentDefaults(pattern.left, bindings, shadowed, aliases);
243
+ return;
244
+ }
245
+ if (pattern.type === "ObjectPattern") {
246
+ for (const property of pattern.properties) collectPossibleComponentDefaults(property.type === "RestElement" ? property.argument : property.value, bindings, shadowed, aliases);
247
+ return;
248
+ }
249
+ if (pattern.type === "ArrayPattern") {
250
+ for (const element of pattern.elements) if (element) collectPossibleComponentDefaults(element, bindings, shadowed, aliases);
251
+ return;
252
+ }
253
+ if (pattern.type === "RestElement") collectPossibleComponentDefaults(pattern.argument, bindings, shadowed, aliases);
254
+ }
255
+ /** Returns whether an abstract selector value can resolve to any GT component. */
256
+ function selectorAnalysisMayContainGT(analysis, bindings) {
257
+ if (analysis.possibleGT || analysis.gtComponentFactories.size > 0) return true;
258
+ return analysis.candidates.some((candidate) => {
259
+ if (candidate.kind === "expression") return bindings.components.get(candidate.name) === "T" || bindings.uncertainGTComponents.has(candidate.name);
260
+ return [...normalizeTemplateBindingNames(candidate.name)].some((name) => bindings.registeredComponents.get(name) === "T");
261
+ });
262
+ }
263
+ /** Shadows program bindings with one local alias of uncertain GT identity. */
264
+ function createScopedComponentBindings(bindings, aliases) {
265
+ const scoped = {
266
+ ...bindings,
267
+ arrayLengths: new Map(bindings.arrayLengths),
268
+ componentFactories: new Set(bindings.componentFactories),
269
+ components: new Map(bindings.components),
270
+ containerKinds: new Map(bindings.containerKinds),
271
+ possibleGTContainers: new Set(bindings.possibleGTContainers),
272
+ gtContainerFactories: new Set(bindings.gtContainerFactories),
273
+ directBindings: new Set(bindings.directBindings),
274
+ gtComponentFactories: new Set(bindings.gtComponentFactories),
275
+ identityFunctions: new Set(bindings.identityFunctions),
276
+ possibleStaticStrings: new Map([...bindings.possibleStaticStrings].map(([name, values]) => [name, new Set(values)])),
277
+ staticValues: new Map(bindings.staticValues),
278
+ stringFunctions: new Map(bindings.stringFunctions),
279
+ uncertainComponents: new Set(bindings.uncertainComponents),
280
+ uncertainGTComponents: new Set(bindings.uncertainGTComponents),
281
+ uncertainStringFunctions: new Set(bindings.uncertainStringFunctions),
282
+ vueBuiltins: new Map(bindings.vueBuiltins)
283
+ };
284
+ for (const alias of aliases) {
285
+ clearScopedPath(scoped.arrayLengths, alias);
286
+ clearScopedPath(scoped.componentFactories, alias);
287
+ clearScopedPath(scoped.components, alias);
288
+ clearScopedPath(scoped.containerKinds, alias);
289
+ clearScopedPath(scoped.possibleGTContainers, alias);
290
+ clearScopedPath(scoped.gtContainerFactories, alias);
291
+ clearScopedPath(scoped.gtComponentFactories, alias);
292
+ clearScopedPath(scoped.identityFunctions, alias);
293
+ clearScopedPath(scoped.possibleStaticStrings, alias);
294
+ clearScopedPath(scoped.staticValues, alias);
295
+ clearScopedPath(scoped.stringFunctions, alias);
296
+ clearScopedPath(scoped.uncertainComponents, alias);
297
+ clearScopedPath(scoped.uncertainGTComponents, alias);
298
+ clearScopedPath(scoped.uncertainStringFunctions, alias);
299
+ clearScopedPath(scoped.vueBuiltins, alias);
300
+ scoped.directBindings.add(alias);
301
+ scoped.uncertainComponents.add(alias);
302
+ scoped.uncertainGTComponents.add(alias);
303
+ }
304
+ return scoped;
305
+ }
306
+ /** Exposes container-valued v-for aliases to nested template scopes. */
307
+ function createScopedContainerBindings(bindings, aliases, shadowed) {
308
+ const scoped = createScopedComponentBindings(bindings, /* @__PURE__ */ new Set());
309
+ for (const [alias, values] of aliases) {
310
+ clearScopedPath(scoped.arrayLengths, alias);
311
+ clearScopedPath(scoped.componentFactories, alias);
312
+ clearScopedPath(scoped.components, alias);
313
+ clearScopedPath(scoped.containerKinds, alias);
314
+ clearScopedPath(scoped.possibleGTContainers, alias);
315
+ clearScopedPath(scoped.gtContainerFactories, alias);
316
+ clearScopedPath(scoped.gtComponentFactories, alias);
317
+ clearScopedPath(scoped.identityFunctions, alias);
318
+ clearScopedPath(scoped.possibleStaticStrings, alias);
319
+ clearScopedPath(scoped.staticValues, alias);
320
+ clearScopedPath(scoped.stringFunctions, alias);
321
+ clearScopedPath(scoped.uncertainComponents, alias);
322
+ clearScopedPath(scoped.uncertainGTComponents, alias);
323
+ clearScopedPath(scoped.uncertainStringFunctions, alias);
324
+ clearScopedPath(scoped.vueBuiltins, alias);
325
+ scoped.directBindings.add(alias);
326
+ const expose = (container, path, depth) => {
327
+ if (depth > 32) return;
328
+ const kind = container.kind === "literal" ? container.node.type === "ArrayExpression" ? "array" : "object" : container.kind === "analysis" ? container.containerKind : scoped.containerKinds.get(container.path);
329
+ if (kind) scoped.containerKinds.set(path, kind);
330
+ const children = selectTemplateContainerReference(container, void 0, scoped, shadowed, /* @__PURE__ */ new Set());
331
+ if (selectorAnalysisMayContainGT(children, scoped)) scoped.possibleGTContainers.add(path);
332
+ const childPath = appendTemplatePath(path, unknownTemplatePathSegment);
333
+ for (const child of children.containers) expose(child, childPath, depth + 1);
334
+ };
335
+ for (const container of values.containers) expose(container, alias, 0);
336
+ }
337
+ return scoped;
338
+ }
339
+ function clearScopedPath(collection, path) {
340
+ for (const key of collection.keys()) if (key === path || key.startsWith(`${path}.`)) collection.delete(key);
341
+ }
342
+ function processTemplateExpression(expression, shadowed, bindings, expressionPlugins, context) {
343
+ const expressionNode = getExpressionNode(expression, expressionPlugins);
344
+ if (!expressionNode) return;
345
+ processTemplateExpressionNode(expressionNode, expression.loc, shadowed, bindings, context);
346
+ }
347
+ function processTemplateExpressionNode(expression, location, shadowed, bindings, context) {
348
+ const file = wrapForTraversal(expression);
349
+ if (!file) return;
350
+ traverse(file, {
351
+ CallExpression(path) {
352
+ const kind = resolveTemplateStringFunction(path.node.callee, path.scope, shadowed, bindings);
353
+ if (!kind) {
354
+ reportPossibleTemplateStringFunction(path.node.callee, path.scope, location, shadowed, bindings, context);
355
+ return;
356
+ }
357
+ processVueStringCall(path.node, kind, location, context, (node) => readTemplatePrimitive(node, path.scope, shadowed, bindings));
358
+ },
359
+ OptionalCallExpression(path) {
360
+ const kind = resolveTemplateStringFunction(path.node.callee, path.scope, shadowed, bindings);
361
+ if (!kind) {
362
+ reportPossibleTemplateStringFunction(path.node.callee, path.scope, location, shadowed, bindings, context);
363
+ return;
364
+ }
365
+ processVueStringCall(path.node, kind, location, context, (node) => readTemplatePrimitive(node, path.scope, shadowed, bindings));
366
+ },
367
+ TaggedTemplateExpression(path) {
368
+ if (!resolveTemplateStringFunction(path.node.tag, path.scope, shadowed, bindings)) {
369
+ reportPossibleTemplateStringFunction(path.node.tag, path.scope, location, shadowed, bindings, context);
370
+ return;
371
+ }
372
+ addVueError(context, location, "Found an unsupported tagged template translation in gt-vue", "Call the translation function with a string literal instead");
373
+ }
374
+ });
375
+ }
376
+ /** Reports a call whose binding may be a gt-vue string translator. */
377
+ function reportPossibleTemplateStringFunction(input, scope, location, shadowed, bindings, context) {
378
+ const displayName = resolvePossibleTemplateStringFunction(input, scope, shadowed, bindings);
379
+ if (!displayName) return;
380
+ addVueError(context, location, `Could not statically resolve possible gt-vue translation function alias "${displayName}"`, "Use a direct gt-vue import or an immutable translator alias that does not escape static analysis");
381
+ }
382
+ /** Resolves direct or dynamically selected uncertain translator paths. */
383
+ function resolvePossibleTemplateStringFunction(input, scope, shadowed, bindings) {
384
+ const node = unwrapExpression(input);
385
+ if (!node) return void 0;
386
+ const path = readStaticTemplateMemberPath(node, bindings, shadowed);
387
+ const root = path?.split(".", 1)[0];
388
+ if (path && root && !scope.hasBinding(root) && bindings.uncertainStringFunctions.has(path)) return path;
389
+ if (node.type !== "MemberExpression" && node.type !== "OptionalMemberExpression") return;
390
+ const objectPath = readStaticTemplateMemberPath(node.object, bindings, shadowed);
391
+ const objectRoot = objectPath?.split(".", 1)[0];
392
+ if (!objectPath || !objectRoot || scope.hasBinding(objectRoot)) return;
393
+ const prefix = `${objectPath}.`;
394
+ return [...bindings.stringFunctions.keys(), ...bindings.uncertainStringFunctions].some((name) => {
395
+ if (!name.startsWith(prefix)) return false;
396
+ return !name.slice(prefix.length).includes(".");
397
+ }) ? objectPath : void 0;
398
+ }
399
+ /** Reads a script-exposed primitive unless a Vue or expression scope masks it. */
400
+ function readTemplatePrimitive(input, scope, shadowed, bindings) {
401
+ return readStaticPrimitive(input, (identifier) => {
402
+ if (shadowed.has(identifier.name) || scope.hasBinding(identifier.name)) return { ok: false };
403
+ const value = bindings.staticValues.get(identifier.name);
404
+ return bindings.staticValues.has(identifier.name) ? {
405
+ ok: true,
406
+ value
407
+ } : { ok: false };
408
+ });
409
+ }
410
+ /** Resolves a template call back to a statically imported gt-vue function. */
411
+ function resolveTemplateStringFunction(input, scope, shadowed, bindings) {
412
+ const node = unwrapExpression(input);
413
+ if (!node) return void 0;
414
+ const path = readStaticTemplateMemberPath(node, bindings, shadowed);
415
+ const root = path?.split(".", 1)[0];
416
+ return root && !scope.hasBinding(root) ? bindings.stringFunctions.get(path) : void 0;
417
+ }
418
+ /** Visits expressions that execute while Vue initializes binding patterns. */
419
+ function processBindingDefaults(expression, shadowed, bindings, expressionPlugins, context) {
420
+ if (!expression || expression.type !== NodeTypes.SIMPLE_EXPRESSION || !expression.content) return;
421
+ try {
422
+ const arrow = parseExpression(`(${expression.content}) => 0`, { plugins: expressionPlugins });
423
+ if (arrow.type !== "ArrowFunctionExpression") return;
424
+ for (const parameter of arrow.params) visitBindingDefaultExpressions(parameter, (node) => processTemplateExpressionNode(node, expression.loc, shadowed, bindings, context));
425
+ } catch {}
426
+ }
427
+ /** Recursively finds default and computed-key expressions in a binding. */
428
+ function visitBindingDefaultExpressions(pattern, visit) {
429
+ if (!pattern) return;
430
+ if (pattern.type === "AssignmentPattern") {
431
+ visit(pattern.right);
432
+ visitBindingDefaultExpressions(pattern.left, visit);
433
+ } else if (pattern.type === "RestElement") visitBindingDefaultExpressions(pattern.argument, visit);
434
+ else if (pattern.type === "ArrayPattern") {
435
+ for (const element of pattern.elements) if (element) visitBindingDefaultExpressions(element, visit);
436
+ } else if (pattern.type === "ObjectPattern") for (const property of pattern.properties) if (property.type === "RestElement") visitBindingDefaultExpressions(property.argument, visit);
437
+ else {
438
+ if (property.computed && babel.isExpression(property.key)) visit(property.key);
439
+ visitBindingDefaultExpressions(property.value, visit);
440
+ }
441
+ else if (pattern.type === "TSParameterProperty") visitBindingDefaultExpressions(pattern.parameter, visit);
442
+ }
443
+ function extractTranslationComponent(element, shadowed, bindings, expressionPlugins, context) {
444
+ const errorCount = context.errors.length;
445
+ const translationContext = readTContext(element, shadowed, bindings, expressionPlugins, context);
446
+ const slots = getSlotLayout(element, shadowed, expressionPlugins, context);
447
+ if (slots.namedSlots.size > 0) addVueError(context, element.loc, "Found a named slot on a gt-vue <T> component", "Place translatable content in the default slot");
448
+ const serialized = serializeChildren(slots.defaultSlot.children, { value: 0 }, slots.defaultSlot.shadowed, bindings, expressionPlugins, context);
449
+ if (context.errors.length !== errorCount) return;
450
+ context.results.push({
451
+ dataFormat: "JSX",
452
+ source: collapseChildren(serialized),
453
+ metadata: createInlineMetadata(context, element.loc, translationContext)
454
+ });
455
+ }
456
+ function readTContext(element, shadowed, bindings, expressionPlugins, context) {
457
+ let translationContext;
458
+ let hasContext = false;
459
+ for (const property of element.props) {
460
+ if (isDynamicComponentSelector(element, property)) continue;
461
+ if (property.type === NodeTypes.ATTRIBUTE) {
462
+ if (RESERVED_T_PROPS.has(property.name)) continue;
463
+ if (property.name !== "context" && property.name !== "$context") {
464
+ addVueError(context, property.loc, `Found unsupported prop "${property.name}" on a gt-vue <T> component`, "gt-vue <T> currently supports only context");
465
+ continue;
466
+ }
467
+ if (hasContext) {
468
+ addDuplicateContextError(property.loc, context);
469
+ continue;
470
+ }
471
+ hasContext = true;
472
+ translationContext = property.value?.content ?? "";
473
+ continue;
474
+ }
475
+ if (property.name !== "bind") continue;
476
+ if (property.modifiers.length > 0) {
477
+ const directive = property.rawName ?? "v-bind";
478
+ addVueError(context, property.loc, `Found unsupported directive ${directive} on a gt-vue <T> component`, "Pass context without a v-bind modifier");
479
+ continue;
480
+ }
481
+ const key = readDirectiveKey(property);
482
+ if (key === void 0) {
483
+ addVueError(context, property.loc, "Found a dynamic or spread binding on a gt-vue <T> component", "Pass context as a static context or $context prop");
484
+ continue;
485
+ }
486
+ if (RESERVED_T_PROPS.has(key)) continue;
487
+ if (key !== "context" && key !== "$context") {
488
+ addVueError(context, property.loc, `Found unsupported prop "${key}" on a gt-vue <T> component`, "gt-vue <T> currently supports only context");
489
+ continue;
490
+ }
491
+ if (hasContext) {
492
+ addDuplicateContextError(property.loc, context);
493
+ continue;
494
+ }
495
+ hasContext = true;
496
+ const value = readExpressionPrimitive(property.exp, expressionPlugins, shadowed, bindings);
497
+ if (!value.ok || typeof value.value !== "string") {
498
+ addVueError(context, property.loc, "Found a dynamic context on a gt-vue <T> component", "Use a string literal or a template literal without expressions");
499
+ continue;
500
+ }
501
+ translationContext = value.value;
502
+ }
503
+ return translationContext;
504
+ }
505
+ function addDuplicateContextError(location, context) {
506
+ addVueError(context, location, "Found duplicate context props on a gt-vue <T> component", "Pass only one context prop");
507
+ }
508
+ function serializeChildren(children, counter, shadowed, bindings, expressionPlugins, context) {
509
+ validateCommentWhitespaceParity(children, context);
510
+ const result = [];
511
+ for (const child of children) {
512
+ const values = serializeChild(child, counter, shadowed, bindings, expressionPlugins, context);
513
+ for (const value of values) appendSerializedChild(result, value);
514
+ }
515
+ return result;
516
+ }
517
+ /**
518
+ * Rejects comments whose removal can change Vue's surrounding whitespace.
519
+ *
520
+ * Vue keeps template comments in development and strips them in production.
521
+ * The compiler's whitespace transform can therefore produce different text
522
+ * VNodes, and consequently different persisted translation hashes, across
523
+ * Vue versions and build modes. Restrict this check to children that are
524
+ * actually serialized so comments in opaque or unused slots remain opaque.
525
+ */
526
+ function validateCommentWhitespaceParity(children, context) {
527
+ for (const child of children) {
528
+ if (child.type !== NodeTypes.COMMENT) continue;
529
+ const before = context.source[child.loc.start.offset - 1];
530
+ const after = context.source[child.loc.end.offset];
531
+ if (!isHtmlWhitespace(before) && !isHtmlWhitespace(after)) continue;
532
+ addVueError(context, child.loc, "Found a comment adjacent to translatable whitespace inside a gt-vue <T> component", "Remove the adjacent whitespace or move the comment outside the translated content");
533
+ }
534
+ }
535
+ /** Matches the whitespace characters normalized by the Vue HTML compiler. */
536
+ function isHtmlWhitespace(value) {
537
+ return value !== void 0 && /[\t\n\f\r ]/.test(value);
538
+ }
539
+ function serializeChild(child, counter, shadowed, bindings, expressionPlugins, context) {
540
+ if (child.type === NodeTypes.COMMENT) return [];
541
+ if (child.type === NodeTypes.TEXT) return [child.content];
542
+ if (child.type === NodeTypes.INTERPOLATION) {
543
+ const value = readExpressionPrimitive(child.content, expressionPlugins, shadowed, bindings);
544
+ if (!value.ok) {
545
+ addVueError(context, child.loc, "Found dynamic template content inside a gt-vue <T> component", "Wrap runtime values in <Var>, <Num>, <DateTime>, or <Currency>");
546
+ return [];
547
+ }
548
+ return [toDisplayString(value.value)];
549
+ }
550
+ if (child.type !== NodeTypes.ELEMENT) {
551
+ addVueError(context, child.loc, "Found unsupported template syntax inside a gt-vue <T> component", "Use static template content and gt-vue rich translation components");
552
+ return [];
553
+ }
554
+ if (resolveFragmentComponent(child, bindings, expressionPlugins, shadowed)) return serializeFragmentElement(child, counter, shadowed, bindings, expressionPlugins, context);
555
+ return [serializeElement(child, counter, shadowed, bindings, expressionPlugins, context)];
556
+ }
557
+ /** Flattens an exact Vue Fragment default slot without consuming an ID. */
558
+ function serializeFragmentElement(element, counter, shadowed, bindings, expressionPlugins, context) {
559
+ validateRichElement(element, context, true);
560
+ const slots = getSlotLayout(element, shadowed, expressionPlugins, context);
561
+ if (slots.namedSlots.size > 0) addVueError(context, element.loc, "Found a named slot on Vue Fragment inside a gt-vue <T> component", "Keep Fragment content in its default slot");
562
+ return serializeChildren(slots.defaultSlot.children, counter, slots.defaultSlot.shadowed, bindings, expressionPlugins, context);
563
+ }
564
+ function serializeElement(element, counter, shadowed, bindings, expressionPlugins, context) {
565
+ counter.value += 1;
566
+ const id = counter.value;
567
+ const component = resolveGTComponent(element, bindings, expressionPlugins, shadowed);
568
+ const suspense = resolveSuspenseComponent(element, bindings, expressionPlugins, shadowed);
569
+ const uncertainComponent = !component && !suspense ? resolveUncertainComponent(element, bindings, expressionPlugins, shadowed) : void 0;
570
+ if (uncertainComponent) addVueError(context, element.loc, `Could not statically resolve component alias "${uncertainComponent}" inside a gt-vue <T> component`, "Use a direct component import or an immutable alias that does not escape static analysis");
571
+ validateRichElement(element, context, Boolean(component || suspense || uncertainComponent));
572
+ const originalName = component?.originalName;
573
+ if (originalName === "T") addVueError(context, element.loc, "Found a nested gt-vue <T> component inside another <T>", "Split nested translations into sibling <T> components");
574
+ if (originalName === "Var" || originalName === "Num" || originalName === "DateTime" || originalName === "Currency") {
575
+ validateVariableComponentShape(element, originalName, context);
576
+ const variable = originalName === "Num" ? {
577
+ name: "n",
578
+ type: "n"
579
+ } : originalName === "DateTime" ? {
580
+ name: "date",
581
+ type: "d"
582
+ } : originalName === "Currency" ? {
583
+ name: "cost",
584
+ type: "c"
585
+ } : {
586
+ name: "value",
587
+ type: "v"
588
+ };
589
+ return {
590
+ i: id,
591
+ k: `_gt_${variable.name}_${id}`,
592
+ v: variable.type
593
+ };
594
+ }
595
+ const data = readContentProps(element, shadowed, bindings, expressionPlugins, context);
596
+ if (isOpaqueComponent(element, component, suspense)) return {
597
+ t: element.tag,
598
+ i: id,
599
+ ...Object.keys(data).length > 0 && { d: data }
600
+ };
601
+ const slotLayout = element.tagType === ElementTypes.COMPONENT ? getSlotLayout(element, shadowed, expressionPlugins, context) : {
602
+ defaultSlot: {
603
+ children: element.children,
604
+ rootCount: countVueSlotRoots(element.children),
605
+ shadowed
606
+ },
607
+ namedSlots: /* @__PURE__ */ new Map()
608
+ };
609
+ const children = serializeChildren(slotLayout.defaultSlot.children, counter, slotLayout.defaultSlot.shadowed, bindings, expressionPlugins, context);
610
+ if (suspense && slotLayout.defaultSlot.rootCount > 1) addVueError(context, element.loc, "Found more than one default root inside Vue <Suspense> within a gt-vue <T> component", "Wrap the Suspense default content in a single element or move <T> inside <Suspense>");
611
+ if ([...slotLayout.namedSlots].filter(([name]) => !suspense || name !== "fallback").length > 0 && originalName !== "Branch" && originalName !== "Plural") addVueError(context, element.loc, `Found named slots on <${originalName ?? element.tag}> inside a gt-vue <T> component`, "Move named-slot content outside <T> or use only the component default slot");
612
+ if (originalName === "Branch" || originalName === "Plural") {
613
+ const branches = readBranches(element, slotLayout, id, originalName, shadowed, bindings, expressionPlugins, context);
614
+ if (Object.keys(branches).length > 0) {
615
+ data.b = branches;
616
+ data.t = originalName === "Plural" ? "p" : "b";
617
+ }
618
+ }
619
+ return {
620
+ t: originalName ?? suspense?.originalName ?? element.tag,
621
+ i: id,
622
+ ...Object.keys(data).length > 0 && { d: data },
623
+ ...children.length > 0 && { c: collapseChildren(children) }
624
+ };
625
+ }
626
+ /** Returns true when the runtime preserves a component's slots as opaque. */
627
+ function isOpaqueComponent(element, component, vueBuiltin) {
628
+ return element.tagType === ElementTypes.COMPONENT && !component && !vueBuiltin;
629
+ }
630
+ /** Resolves literal Suspense and statically proven aliases of Vue's builtin. */
631
+ function resolveSuspenseComponent(element, bindings, expressionPlugins, shadowed) {
632
+ if (element.tagType === ElementTypes.COMPONENT && element.tag.toLowerCase() === "suspense") return {
633
+ localName: element.tag,
634
+ originalName: "Suspense"
635
+ };
636
+ const builtin = resolveVueBuiltinComponent(element, bindings, expressionPlugins, shadowed);
637
+ return builtin?.originalName === "Suspense" ? {
638
+ localName: builtin.localName,
639
+ originalName: "Suspense"
640
+ } : void 0;
641
+ }
642
+ /** Resolves an imported Vue Fragment alias without matching an ordinary tag. */
643
+ function resolveFragmentComponent(element, bindings, expressionPlugins, shadowed) {
644
+ const builtin = resolveVueBuiltinComponent(element, bindings, expressionPlugins, shadowed);
645
+ return builtin?.originalName === "Fragment" ? {
646
+ localName: builtin.localName,
647
+ originalName: "Fragment"
648
+ } : void 0;
649
+ }
650
+ /** Resolves a statically proven Vue builtin through direct or registered use. */
651
+ function resolveVueBuiltinComponent(element, bindings, expressionPlugins, shadowed) {
652
+ return resolveComponentBinding(element, bindings, bindings.vueBuiltins, bindings.registeredVueBuiltins, bindings.directBindings, expressionPlugins, shadowed);
653
+ }
654
+ /** Resolves a component-shaped binding whose exact identity is uncertain. */
655
+ function resolveUncertainComponent(element, bindings, expressionPlugins, shadowed) {
656
+ return resolveUncertainComponentBinding(element, bindings, bindings.uncertainComponents, bindings.uncertainRegisteredComponents, bindings.componentFactories, expressionPlugins, shadowed);
657
+ }
658
+ /** Resolves uncertainty while preserving direct versus registered precedence. */
659
+ function resolveUncertainComponentBinding(element, bindings, uncertainDirectBindings, uncertainRegisteredBindings, uncertainFactories, expressionPlugins, shadowed) {
660
+ if (element.tagType !== ElementTypes.COMPONENT) return void 0;
661
+ const selector = readDynamicComponentSelector(element, expressionPlugins, bindings, shadowed);
662
+ if (selector) {
663
+ if ([...selector.componentFactories].some((name) => uncertainFactories.has(name)) || [...selector.gtComponentFactories].some((name) => uncertainFactories.has(name))) return selector.displayName;
664
+ for (const candidate of selector.candidates) for (const localName of normalizeTemplateBindingNames(candidate.name)) if (candidate.kind === "string" ? uncertainRegisteredBindings.has(localName) : uncertainDirectBindings.has(localName)) return localName;
665
+ return;
666
+ }
667
+ for (const localName of normalizeTemplateBindingNames(element.tag)) {
668
+ const direct = uncertainDirectBindings.has(localName);
669
+ const registered = uncertainRegisteredBindings.has(localName);
670
+ if (isDirectTemplateBinding(localName, bindings.directBindings)) {
671
+ if (direct) return localName;
672
+ } else if (registered || direct) return localName;
673
+ }
674
+ }
675
+ /** Detects an unresolved dynamic selector whose possible result includes T. */
676
+ function resolvePossibleDynamicT(element, bindings, expressionPlugins, shadowed) {
677
+ const selector = readDynamicComponentSelector(element, expressionPlugins, bindings, shadowed);
678
+ if (!selector) return void 0;
679
+ if (selector.possibleGT || selector.gtComponentFactories.size > 0) return selector.displayName;
680
+ for (const candidate of selector.candidates) for (const localName of normalizeTemplateBindingNames(candidate.name)) if ((candidate.kind === "string" ? bindings.registeredComponents.get(localName) : bindings.components.get(localName)) === "T") return selector.displayName;
681
+ }
682
+ /** Identifies a statically named Suspense fallback slot during tree walking. */
683
+ function isSuspenseFallbackTemplate(child) {
684
+ return child.type === NodeTypes.ELEMENT && child.tag === "template" && hasStaticSlotName(child, "fallback");
685
+ }
686
+ /** Matches one statically named slot directive without emitting diagnostics. */
687
+ function hasStaticSlotName(element, name) {
688
+ const directive = element.props.find((property) => property.type === NodeTypes.DIRECTIVE && property.name === "slot");
689
+ return directive?.arg?.type === NodeTypes.SIMPLE_EXPRESSION && directive.arg.isStatic && directive.arg.content === name;
690
+ }
691
+ function validateRichElement(element, context, resolvedDynamicComponent) {
692
+ if (element.tagType === ElementTypes.SLOT || element.tag === "slot") addVueError(context, element.loc, "Found a <slot> inside a gt-vue <T> component", "Move runtime slot content outside <T> or wrap a stable value in <Var>");
693
+ if (element.tag === "template" && !element.props.some((property) => property.type === NodeTypes.DIRECTIVE && property.name === "slot")) addVueError(context, element.loc, "Found a bare <template> inside a gt-vue <T> component", "Use an ordinary element or a statically named slot template");
694
+ if (element.tag.toLowerCase() === "component" && !resolvedDynamicComponent) addVueError(context, element.loc, "Found a dynamic <component> inside a gt-vue <T> component", "Use a statically named element or component");
695
+ for (const property of element.props) {
696
+ if (property.type !== NodeTypes.DIRECTIVE) continue;
697
+ if (SOURCE_SHAPING_DIRECTIVES.has(property.name)) addVueError(context, property.loc, `Found source-shaping directive ${property.rawName ?? `v-${property.name}`} inside a gt-vue <T> component`, "Move conditional or repeated content outside <T>, or use Branch/Plural");
698
+ else if (property.name === "bind" && !readDirectiveKey(property)) addVueError(context, property.loc, "Found a dynamic or spread v-bind inside a gt-vue <T> component", "Bind props by a static name so their effect on the translation source is known");
699
+ }
700
+ }
701
+ /** Enforces the one supported public shape for every variable component. */
702
+ function validateVariableComponentShape(element, component, context) {
703
+ if (context.validatedVariableComponents.has(element)) return;
704
+ context.validatedVariableComponents.add(element);
705
+ if (component !== "Var") {
706
+ if (!hasTemplateProp(element, "value")) addVueError(context, element.loc, `Found a gt-vue <${component}> component without a value prop`, `Pass the runtime value through <${component} :value="value" />`);
707
+ if (hasMeaningfulSlotContent(element.children, context)) addVueError(context, element.loc, `Found children on a gt-vue <${component}> component`, `Use only the required value prop: <${component} :value="value" />`);
708
+ return;
709
+ }
710
+ for (const property of element.props) {
711
+ const key = property.type === NodeTypes.ATTRIBUTE ? property.name : property.name === "bind" ? readDirectiveKey(property) : void 0;
712
+ if (key === "name" || key === "value") addVueError(context, property.loc, `Found unsupported ${key} prop on a gt-vue <Var> component`, "Pass the variable as the default child of <Var>");
713
+ else if (property.type === NodeTypes.DIRECTIVE && property.name === "bind" && !property.arg) addVueError(context, property.loc, "Found a spread v-bind on a gt-vue <Var> component", "Pass the variable only as the default child of <Var>");
714
+ }
715
+ }
716
+ /** Returns whether a statically named template prop is explicitly present. */
717
+ function hasTemplateProp(element, expected) {
718
+ return element.props.some((property) => {
719
+ if (property.type === NodeTypes.ATTRIBUTE) return property.name === expected;
720
+ return property.name === "bind" && readDirectiveKey(property) === expected;
721
+ });
722
+ }
723
+ function readContentProps(element, shadowed, bindings, expressionPlugins, context) {
724
+ const data = {};
725
+ for (const [shortName, propName] of Object.entries(HTML_CONTENT_PROPS)) {
726
+ const property = findElementProperty(element, propName, expressionPlugins, shadowed, bindings);
727
+ if (!property.present) continue;
728
+ if (!property.static) {
729
+ addVueError(context, property.location, `Found dynamic translatable prop "${propName}" inside a gt-vue <T> component`, "Use a string literal for translatable HTML props");
730
+ continue;
731
+ }
732
+ if (typeof property.value === "string") data[shortName] = property.value;
733
+ }
734
+ return data;
735
+ }
736
+ function readBranches(element, slots, branchElementId, component, shadowed, bindings, expressionPlugins, context) {
737
+ const branches = {};
738
+ for (const [name, slot] of slots.namedSlots) {
739
+ if (name.startsWith("_")) continue;
740
+ if (component === "Plural" && !isAcceptedPluralForm(name)) continue;
741
+ branches[name] = collapseChildren(serializeChildren(slot.children, { value: branchElementId }, slot.shadowed, bindings, expressionPlugins, context));
742
+ }
743
+ for (const property of element.props) {
744
+ if (isDynamicComponentSelector(element, property)) continue;
745
+ if (property.type === NodeTypes.DIRECTIVE && property.name === "slot") continue;
746
+ const key = property.type === NodeTypes.ATTRIBUTE ? property.name : readDirectiveKey(property);
747
+ if (property.type === NodeTypes.DIRECTIVE && property.name === "on") continue;
748
+ if (key && (!isBranchAttributeName(key) || Object.prototype.hasOwnProperty.call(branches, key) || component === "Plural" && !isAcceptedPluralForm(key))) continue;
749
+ if (property.type === NodeTypes.DIRECTIVE && (property.name !== "bind" || property.modifiers.length > 0)) {
750
+ const directive = property.rawName ?? `v-${property.name}`;
751
+ addVueError(context, property.loc, `Found unsupported directive ${directive} on a gt-vue <${component}> component`, `Move ${directive} to an element outside <${component}>`);
752
+ continue;
753
+ }
754
+ if (key === void 0) continue;
755
+ const value = readPropertyValue(property, expressionPlugins, shadowed, bindings);
756
+ if (!value.ok) {
757
+ if (isStaticallyNonBranchValue(property, expressionPlugins, shadowed, bindings)) continue;
758
+ addVueError(context, property.loc, `Found dynamic branch prop "${key}" on a gt-vue <${component}> component`, "Use a static branch prop or a named slot");
759
+ continue;
760
+ }
761
+ branches[key] = branchPropToChildren(value.value);
762
+ }
763
+ return branches;
764
+ }
765
+ function branchPropToChildren(value) {
766
+ if (value == null || typeof value === "boolean") return [];
767
+ return String(value);
768
+ }
769
+ /**
770
+ * Mirrors the attribute-name half of gt-vue's runtime branch predicate.
771
+ *
772
+ * Vue combines explicit component props, presentation attributes, and
773
+ * normalized listeners in one VNode prop record. The extractor must discard
774
+ * the same names before evaluating values so dynamic class/style/listener
775
+ * expressions cannot change a published translation hash.
776
+ */
777
+ function isBranchAttributeName(name) {
778
+ return !(NON_BRANCH_ATTRIBUTE_NAMES.has(name) || name.startsWith("aria-") || name.startsWith("data-") || /^on[^a-z]/.test(name));
779
+ }
780
+ /**
781
+ * Identifies expressions whose top-level runtime type can never be branch
782
+ * content. Unknown identifiers and calls deliberately return false so an
783
+ * arbitrary prop whose runtime type may be primitive still fails closed.
784
+ */
785
+ function isStaticallyNonBranchValue(property, expressionPlugins, shadowed, bindings) {
786
+ if (property.type !== NodeTypes.DIRECTIVE || property.name !== "bind") return false;
787
+ const node = unwrapExpression(property.exp ? getExpressionNode(property.exp, expressionPlugins) : void 0);
788
+ if (!node) return false;
789
+ if (babel.isIdentifier(node, { name: "undefined" })) return !shadowed.has(node.name) && !bindings.staticValues.has(node.name);
790
+ return babel.isArrayExpression(node) || babel.isArrowFunctionExpression(node) || babel.isClassExpression(node) || babel.isFunctionExpression(node) || babel.isNewExpression(node) || babel.isObjectExpression(node) || babel.isRegExpLiteral(node) || babel.isUnaryExpression(node) && node.operator === "void";
791
+ }
792
+ function getSlotLayout(element, shadowed, expressionPlugins, context) {
793
+ const namedSlots = /* @__PURE__ */ new Map();
794
+ let defaultSlot = {
795
+ children: [],
796
+ rootCount: 0,
797
+ shadowed
798
+ };
799
+ let hasTemplateSlots = false;
800
+ let hasExplicitDefaultSlot = false;
801
+ let reportedDefaultConflict = false;
802
+ const componentSlot = element.props.find((property) => property.type === NodeTypes.DIRECTIVE && property.name === "slot");
803
+ if (componentSlot) {
804
+ if (componentSlot.exp) addScopedSlotError(componentSlot.loc, context);
805
+ const slotName = readSlotName(componentSlot, context);
806
+ const slotShadowed = unionSets(shadowed, collectExpressionBindings(componentSlot.exp, expressionPlugins));
807
+ if (slotName === "default") defaultSlot = {
808
+ children: element.children,
809
+ rootCount: countVueSlotRoots(element.children),
810
+ shadowed: slotShadowed
811
+ };
812
+ else if (slotName) namedSlots.set(slotName, {
813
+ children: element.children,
814
+ rootCount: countVueSlotRoots(element.children),
815
+ shadowed: slotShadowed
816
+ });
817
+ return {
818
+ defaultSlot,
819
+ namedSlots
820
+ };
821
+ }
822
+ const defaultChildren = [];
823
+ for (const child of element.children) {
824
+ const slotDirective = child.type === NodeTypes.ELEMENT && child.tag === "template" ? child.props.find((property) => property.type === NodeTypes.DIRECTIVE && property.name === "slot") : void 0;
825
+ if (!slotDirective || child.type !== NodeTypes.ELEMENT) {
826
+ defaultChildren.push(child);
827
+ continue;
828
+ }
829
+ hasTemplateSlots = true;
830
+ for (const property of child.props) if (property.type === NodeTypes.DIRECTIVE && property.name !== "slot") addVueError(context, property.loc, "Found a conditional or dynamic named slot inside a gt-vue <T> component", "Use an unconditional, statically named slot");
831
+ const slotName = readSlotName(slotDirective, context);
832
+ if (slotDirective.exp) addScopedSlotError(slotDirective.loc, context);
833
+ const slotShadowed = unionSets(shadowed, collectExpressionBindings(slotDirective.exp, expressionPlugins));
834
+ if (slotName === "default") {
835
+ if (hasMeaningfulSlotContent(defaultChildren, context) || hasExplicitDefaultSlot) {
836
+ addVueError(context, child.loc, "Found more than one default slot definition inside a gt-vue translation", "Use a single default slot");
837
+ reportedDefaultConflict = true;
838
+ }
839
+ hasExplicitDefaultSlot = true;
840
+ defaultSlot = {
841
+ children: child.children,
842
+ rootCount: countVueSlotRoots(child.children),
843
+ shadowed: slotShadowed
844
+ };
845
+ } else if (slotName) {
846
+ if (namedSlots.has(slotName)) addVueError(context, child.loc, `Found duplicate named slot "${slotName}" inside a gt-vue translation`, "Define each named slot once");
847
+ namedSlots.set(slotName, {
848
+ children: child.children,
849
+ rootCount: countVueSlotRoots(child.children),
850
+ shadowed: slotShadowed
851
+ });
852
+ }
853
+ }
854
+ const hasMeaningfulDefault = hasMeaningfulSlotContent(defaultChildren, context);
855
+ if (hasExplicitDefaultSlot && hasMeaningfulDefault && !reportedDefaultConflict) addVueError(context, defaultChildren[0].loc, "Found more than one default slot definition inside a gt-vue translation", "Use a single default slot");
856
+ else if (!hasExplicitDefaultSlot && defaultChildren.length > 0 && (!hasTemplateSlots || hasMeaningfulDefault)) defaultSlot = {
857
+ children: defaultChildren,
858
+ rootCount: countImplicitSlotRoots(element.children),
859
+ shadowed
860
+ };
861
+ return {
862
+ defaultSlot,
863
+ namedSlots
864
+ };
865
+ }
866
+ /** Matches Vue's test for an implicit slot containing more than separators. */
867
+ function hasMeaningfulSlotContent(children, context) {
868
+ return children.some((child) => child.type !== NodeTypes.COMMENT && (child.type !== NodeTypes.TEXT || !isImplicitSlotWhitespace(child.content, context.implicitSlotWhitespace)));
869
+ }
870
+ /** Mirrors the exact whitespace predicate detected from consumer compiler. */
871
+ function isImplicitSlotWhitespace(value, semantics) {
872
+ return semantics === "ecmascript" ? value.trim().length === 0 : /^[\t\n\f\r ]*$/.test(value);
873
+ }
874
+ /** Counts roots in a complete Vue slot before Suspense normalizes the array. */
875
+ function countVueSlotRoots(children) {
876
+ return countSlotRoots(children, () => false);
877
+ }
878
+ /**
879
+ * Counts roots in an implicit slot while treating named-slot templates as
880
+ * barriers. Vue removes those templates from the default slot only after its
881
+ * text transform has run, so text on opposite sides remains separate VNodes.
882
+ */
883
+ function countImplicitSlotRoots(children) {
884
+ return countSlotRoots(children, (child) => {
885
+ if (child.type !== NodeTypes.ELEMENT || child.tag !== "template") return false;
886
+ return child.props.some((property) => property.type === NodeTypes.DIRECTIVE && property.name === "slot");
887
+ });
888
+ }
889
+ function countSlotRoots(children, isExcluded) {
890
+ let roots = 0;
891
+ let previousWasText = false;
892
+ for (const child of children) {
893
+ if (child.type === NodeTypes.COMMENT || isExcluded(child)) {
894
+ previousWasText = false;
895
+ continue;
896
+ }
897
+ const isText = child.type === NodeTypes.TEXT || child.type === NodeTypes.INTERPOLATION;
898
+ if (!isText || !previousWasText) roots += 1;
899
+ previousWasText = isText;
900
+ }
901
+ return roots;
902
+ }
903
+ function addScopedSlotError(location, context) {
904
+ addVueError(context, location, "Found a scoped slot inside a gt-vue <T> component", "Use a slot without runtime slot props so the translation source is static");
905
+ }
906
+ function readSlotName(directive, context) {
907
+ if (!directive.arg) return "default";
908
+ if (directive.arg.type !== NodeTypes.SIMPLE_EXPRESSION || !directive.arg.isStatic) {
909
+ addVueError(context, directive.loc, "Found a dynamic slot name inside a gt-vue translation", "Use a static slot name");
910
+ return;
911
+ }
912
+ return directive.arg.content;
913
+ }
914
+ function findElementProperty(element, name, expressionPlugins, shadowed, bindings) {
915
+ for (const property of element.props) {
916
+ if ((property.type === NodeTypes.ATTRIBUTE ? property.name : property.name === "bind" ? readDirectiveKey(property) : void 0) !== name) continue;
917
+ const value = readPropertyValue(property, expressionPlugins, shadowed, bindings);
918
+ return {
919
+ location: property.loc,
920
+ present: true,
921
+ static: value.ok,
922
+ ...value.ok && { value: value.value }
923
+ };
924
+ }
925
+ return { present: false };
926
+ }
927
+ function readPropertyValue(property, expressionPlugins, shadowed, bindings) {
928
+ if (property.type === NodeTypes.ATTRIBUTE) return {
929
+ ok: true,
930
+ value: property.value?.content ?? ""
931
+ };
932
+ if (property.name !== "bind") return { ok: false };
933
+ return readExpressionPrimitive(property.exp, expressionPlugins, shadowed, bindings);
934
+ }
935
+ function readExpressionPrimitive(expression, expressionPlugins, shadowed, bindings) {
936
+ return readStaticPrimitive(expression ? getExpressionNode(expression, expressionPlugins) : void 0, (identifier) => {
937
+ if (shadowed.has(identifier.name)) return { ok: false };
938
+ const value = bindings.staticValues.get(identifier.name);
939
+ return bindings.staticValues.has(identifier.name) ? {
940
+ ok: true,
941
+ value
942
+ } : { ok: false };
943
+ });
944
+ }
945
+ function getExpressionNode(expression, expressionPlugins) {
946
+ if (expression.type !== NodeTypes.SIMPLE_EXPRESSION) return void 0;
947
+ if (expression.ast && typeof expression.ast === "object") return expression.ast;
948
+ try {
949
+ return parseExpression(expression.content, { plugins: expressionPlugins });
950
+ } catch {
951
+ return;
952
+ }
953
+ }
954
+ function wrapForTraversal(node) {
955
+ if (node.type === "File") return node;
956
+ if (node.type === "Program") return babel.file(node);
957
+ if (babel.isExpression(node)) return babel.file(babel.program([babel.expressionStatement(node)]));
958
+ if (babel.isStatement(node)) return babel.file(babel.program([node]));
959
+ }
960
+ function collectElementScopeBindings(element, expressionPlugins) {
961
+ const result = /* @__PURE__ */ new Set();
962
+ for (const property of element.props) {
963
+ if (property.type !== NodeTypes.DIRECTIVE) continue;
964
+ if (property.name === "for") {
965
+ const parseResult = readForParseResult(property);
966
+ for (const alias of [
967
+ parseResult?.value,
968
+ parseResult?.key,
969
+ parseResult?.index
970
+ ]) for (const name of collectExpressionBindings(alias, expressionPlugins)) result.add(name);
971
+ } else if (property.name === "slot") for (const name of collectExpressionBindings(property.exp, expressionPlugins)) result.add(name);
972
+ }
973
+ return result;
974
+ }
975
+ /**
976
+ * Reads Vue's normalized v-for fields across every supported Vue 3 release.
977
+ *
978
+ * Vue 3.4+ supplies `forParseResult`; Vue 3.3 exposes only the original
979
+ * directive expression. The fallback deliberately mirrors Vue's own alias,
980
+ * iterator, and parenthesis expressions so scope tracking sees the same value,
981
+ * key, index, and source fields without depending on a second compiler copy.
982
+ */
983
+ function readForParseResult(property) {
984
+ const compilerResult = property.forParseResult;
985
+ if (compilerResult) return compilerResult;
986
+ if (property.exp?.type !== NodeTypes.SIMPLE_EXPRESSION || !property.exp.content) return;
987
+ const match = property.exp.content.match(FOR_ALIAS_EXPRESSION);
988
+ if (!match) return void 0;
989
+ const source = match[2]?.trim();
990
+ const aliases = match[1]?.trim().replace(FOR_STRIP_PARENS, "").trim();
991
+ if (!source || !aliases) return void 0;
992
+ const iteratorMatch = aliases.match(FOR_ITERATOR_EXPRESSION);
993
+ const value = iteratorMatch ? aliases.replace(FOR_ITERATOR_EXPRESSION, "").trim() : aliases;
994
+ if (!value) return void 0;
995
+ return {
996
+ source: cloneForExpression(property.exp, source),
997
+ value: cloneForExpression(property.exp, value),
998
+ ...iteratorMatch?.[1]?.trim() && { key: cloneForExpression(property.exp, iteratorMatch[1].trim()) },
999
+ ...iteratorMatch?.[2]?.trim() && { index: cloneForExpression(property.exp, iteratorMatch[2].trim()) }
1000
+ };
1001
+ }
1002
+ /** Creates one parser-neutral v-for field from Vue's original expression. */
1003
+ function cloneForExpression(expression, content) {
1004
+ return {
1005
+ ...expression,
1006
+ ast: void 0,
1007
+ content,
1008
+ loc: {
1009
+ ...expression.loc,
1010
+ source: content
1011
+ }
1012
+ };
1013
+ }
1014
+ function collectExpressionBindings(expression, expressionPlugins) {
1015
+ const result = /* @__PURE__ */ new Set();
1016
+ if (!expression || expression.type !== NodeTypes.SIMPLE_EXPRESSION || !expression.content) return result;
1017
+ try {
1018
+ const arrow = parseExpression(`(${expression.content}) => 0`, { plugins: expressionPlugins });
1019
+ if (arrow.type === "ArrowFunctionExpression") for (const parameter of arrow.params) collectPatternNames(parameter, result);
1020
+ } catch {}
1021
+ return result;
1022
+ }
1023
+ function collectPatternNames(pattern, result) {
1024
+ if (!pattern) return;
1025
+ if (pattern.type === "Identifier") result.add(pattern.name);
1026
+ else if (pattern.type === "RestElement") collectPatternNames(pattern.argument, result);
1027
+ else if (pattern.type === "AssignmentPattern") collectPatternNames(pattern.left, result);
1028
+ else if (pattern.type === "ArrayPattern") {
1029
+ for (const element of pattern.elements) if (element) collectPatternNames(element, result);
1030
+ } else if (pattern.type === "ObjectPattern") for (const property of pattern.properties) if (property.type === "RestElement") collectPatternNames(property.argument, result);
1031
+ else collectPatternNames(property.value, result);
1032
+ else if (pattern.type === "TSParameterProperty") collectPatternNames(pattern.parameter, result);
1033
+ }
1034
+ function resolveGTComponent(element, bindings, expressionPlugins, shadowed) {
1035
+ return resolveComponentBinding(element, bindings, bindings.components, bindings.registeredComponents, bindings.directBindings, expressionPlugins, shadowed);
1036
+ }
1037
+ /** Resolves a template tag or static dynamic selector through known bindings. */
1038
+ function resolveComponentBinding(element, bindings, directBindings, registeredBindings, directTemplateBindings, expressionPlugins, shadowed) {
1039
+ if (element.tagType !== ElementTypes.COMPONENT) return void 0;
1040
+ const selector = readDynamicComponentSelector(element, expressionPlugins, bindings, shadowed);
1041
+ if (selector) {
1042
+ if (selector.unknown || selector.possibleGT || selector.componentFactories.size > 0 || selector.gtComponentFactories.size > 0 || selector.candidates.length === 0) return;
1043
+ const resolved = selector.candidates.map((candidate) => {
1044
+ for (const localName of normalizeTemplateBindingNames(candidate.name)) {
1045
+ const originalName = candidate.kind === "string" ? registeredBindings.get(localName) : directBindings.get(localName);
1046
+ if (originalName) return {
1047
+ localName,
1048
+ originalName
1049
+ };
1050
+ }
1051
+ });
1052
+ const first = resolved[0];
1053
+ return first && resolved.every((candidate) => candidate?.originalName === first.originalName) ? first : void 0;
1054
+ }
1055
+ for (const localName of normalizeTemplateBindingNames(element.tag)) {
1056
+ const originalName = isDirectTemplateBinding(localName, directTemplateBindings) ? directBindings.get(localName) : registeredBindings.get(localName);
1057
+ if (originalName) return {
1058
+ localName,
1059
+ originalName
1060
+ };
1061
+ }
1062
+ }
1063
+ function normalizeTemplateBindingNames(sourceName) {
1064
+ const camelized = sourceName.replace(/-(\w)/g, (_match, letter) => letter.toUpperCase());
1065
+ const pascalized = camelized ? camelized[0].toUpperCase() + camelized.slice(1) : camelized;
1066
+ return new Set([
1067
+ sourceName,
1068
+ camelized,
1069
+ pascalized
1070
+ ]);
1071
+ }
1072
+ /** Returns whether a program binding shadows an Options API registration. */
1073
+ function isDirectTemplateBinding(localName, directBindings) {
1074
+ return directBindings.has(localName) || directBindings.has(localName.split(".", 1)[0] ?? localName);
1075
+ }
1076
+ /** Resolves a statically knowable Vue dynamic-component selector. */
1077
+ function readDynamicComponentSelector(element, expressionPlugins, bindings, shadowed) {
1078
+ if (element.tag.toLowerCase() !== "component") return void 0;
1079
+ const property = element.props.find((candidate) => isDynamicComponentSelector(element, candidate));
1080
+ if (!property) return void 0;
1081
+ if (property.type === NodeTypes.ATTRIBUTE) return property.value ? {
1082
+ candidates: [{
1083
+ kind: "string",
1084
+ name: property.value.content
1085
+ }],
1086
+ componentFactories: /* @__PURE__ */ new Set(),
1087
+ containers: [],
1088
+ displayName: property.value.content,
1089
+ gtComponentFactories: /* @__PURE__ */ new Set(),
1090
+ possibleGT: false,
1091
+ unknown: false
1092
+ } : void 0;
1093
+ const node = property.exp ? getExpressionNode(property.exp, expressionPlugins) : void 0;
1094
+ if (!node) return void 0;
1095
+ return {
1096
+ ...collectDynamicSelectorCandidates(node, bindings, shadowed, /* @__PURE__ */ new Set()),
1097
+ displayName: property.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? property.exp.content : "dynamic component"
1098
+ };
1099
+ }
1100
+ /** Collects every statically visible result of a dynamic selector expression. */
1101
+ function collectDynamicSelectorCandidates(node, bindings, shadowed, seen) {
1102
+ const expression = unwrapExpression(node);
1103
+ if (!expression || seen.has(expression)) return emptyDynamicSelectorAnalysis(true);
1104
+ const nextSeen = new Set(seen).add(expression);
1105
+ if (expression.type === "ArrayExpression" || expression.type === "ObjectExpression") return {
1106
+ ...emptyDynamicSelectorAnalysis(false),
1107
+ containers: [{
1108
+ kind: "literal",
1109
+ node: expression
1110
+ }]
1111
+ };
1112
+ if (expression.type === "ArrowFunctionExpression" || expression.type === "FunctionExpression" || expression.type === "ObjectMethod") return {
1113
+ ...collectTemplateCallableReturnAnalysis(expression, bindings, shadowed, nextSeen),
1114
+ unknown: true
1115
+ };
1116
+ if (expression.type === "Identifier") {
1117
+ if (shadowed.has(expression.name)) return emptyDynamicSelectorAnalysis(true);
1118
+ if (bindings.containerKinds.has(expression.name)) return {
1119
+ ...emptyDynamicSelectorAnalysis(false),
1120
+ containers: [{
1121
+ kind: "path",
1122
+ path: expression.name
1123
+ }]
1124
+ };
1125
+ if (bindings.staticValues.has(expression.name)) {
1126
+ const value = bindings.staticValues.get(expression.name);
1127
+ return typeof value === "string" ? selectorCandidate("string", value) : emptyDynamicSelectorAnalysis(false);
1128
+ }
1129
+ const possibleStrings = bindings.possibleStaticStrings.get(expression.name);
1130
+ if (possibleStrings && possibleStrings.size > 0) return {
1131
+ ...mergeDynamicSelectorAnalyses([...possibleStrings].map((value) => selectorCandidate("string", value))),
1132
+ unknown: true
1133
+ };
1134
+ return selectorCandidate("expression", expression.name);
1135
+ }
1136
+ if (expression.type === "StringLiteral") return selectorCandidate("string", expression.value);
1137
+ const staticValue = readTemplateStaticPrimitive(expression, bindings, shadowed);
1138
+ if (staticValue.ok) return typeof staticValue.value === "string" ? selectorCandidate("string", staticValue.value) : emptyDynamicSelectorAnalysis(false);
1139
+ if (expression.type === "MemberExpression" || expression.type === "OptionalMemberExpression") {
1140
+ const property = readStaticTemplateMemberProperty(expression, bindings, shadowed);
1141
+ if (property !== void 0) {
1142
+ const selected = selectTemplateStaticMemberExpression(expression.object, property, bindings, shadowed, /* @__PURE__ */ new Set());
1143
+ if (selected) return collectDynamicSelectorCandidates(selected, bindings, shadowed, nextSeen);
1144
+ const objectAnalysis = collectDynamicSelectorCandidates(expression.object, bindings, shadowed, nextSeen);
1145
+ if (objectAnalysis.containers.length > 0) {
1146
+ const memberAnalysis = mergeDynamicSelectorAnalyses(objectAnalysis.containers.map((container) => selectTemplateContainerReference(container, property, bindings, shadowed, nextSeen)));
1147
+ return {
1148
+ ...memberAnalysis,
1149
+ unknown: memberAnalysis.unknown || objectAnalysis.unknown
1150
+ };
1151
+ }
1152
+ }
1153
+ const memberPath = readStaticTemplateMemberPath(expression, bindings, shadowed);
1154
+ if (memberPath) {
1155
+ const staticMember = bindings.staticValues.get(memberPath);
1156
+ if (typeof staticMember === "string") return selectorCandidate("string", staticMember);
1157
+ if (bindings.containerKinds.has(memberPath)) return {
1158
+ ...emptyDynamicSelectorAnalysis(false),
1159
+ containers: [{
1160
+ kind: "path",
1161
+ path: memberPath
1162
+ }]
1163
+ };
1164
+ const possibleStrings = bindings.possibleStaticStrings.get(memberPath);
1165
+ if (possibleStrings && possibleStrings.size > 0) return {
1166
+ ...mergeDynamicSelectorAnalyses([...possibleStrings].map((value) => selectorCandidate("string", value))),
1167
+ unknown: true
1168
+ };
1169
+ const possibleContainer = findPossibleGTContainerPath(memberPath, bindings);
1170
+ if (possibleContainer) return {
1171
+ ...emptyDynamicSelectorAnalysis(true),
1172
+ containers: [{
1173
+ kind: "path",
1174
+ path: possibleContainer
1175
+ }]
1176
+ };
1177
+ if (templatePathSelectsPossibleGT(memberPath, bindings)) return {
1178
+ ...emptyDynamicSelectorAnalysis(true),
1179
+ possibleGT: true
1180
+ };
1181
+ return selectorCandidate("expression", memberPath);
1182
+ }
1183
+ const container = collectTemplateContainerCandidates(expression.object, bindings, shadowed, nextSeen);
1184
+ if (container.candidates.length > 0 || container.componentFactories.size > 0 || container.containers.length > 0 || container.gtComponentFactories.size > 0 || container.possibleGT) return {
1185
+ ...container,
1186
+ unknown: true
1187
+ };
1188
+ return emptyDynamicSelectorAnalysis(true);
1189
+ }
1190
+ if (expression.type === "ConditionalExpression") {
1191
+ const test = readTemplateStaticPrimitive(expression.test, bindings, shadowed);
1192
+ if (test.ok) return collectDynamicSelectorCandidates(test.value ? expression.consequent : expression.alternate, bindings, shadowed, nextSeen);
1193
+ return mergeDynamicSelectorAnalyses([collectDynamicSelectorCandidates(expression.consequent, bindings, shadowed, nextSeen), collectDynamicSelectorCandidates(expression.alternate, bindings, shadowed, nextSeen)]);
1194
+ }
1195
+ if (expression.type === "LogicalExpression") {
1196
+ const leftCandidates = collectDynamicSelectorCandidates(expression.left, bindings, shadowed, nextSeen);
1197
+ if (selectorAnalysisIsKnownComponent(leftCandidates, bindings)) return expression.operator === "&&" ? collectDynamicSelectorCandidates(expression.right, bindings, shadowed, nextSeen) : leftCandidates;
1198
+ const left = readTemplateStaticPrimitive(expression.left, bindings, shadowed);
1199
+ if (left.ok) return (expression.operator === "??" ? left.value == null : expression.operator === "||" ? !left.value : Boolean(left.value)) ? collectDynamicSelectorCandidates(expression.right, bindings, shadowed, nextSeen) : emptyDynamicSelectorAnalysis(false);
1200
+ return {
1201
+ ...mergeDynamicSelectorAnalyses([leftCandidates, collectDynamicSelectorCandidates(expression.right, bindings, shadowed, nextSeen)]),
1202
+ unknown: true
1203
+ };
1204
+ }
1205
+ if (expression.type === "SequenceExpression") {
1206
+ const last = expression.expressions.at(-1);
1207
+ return last ? collectDynamicSelectorCandidates(last, bindings, shadowed, nextSeen) : emptyDynamicSelectorAnalysis(true);
1208
+ }
1209
+ if (expression.type === "CallExpression" || expression.type === "OptionalCallExpression") {
1210
+ const reduction = collectTemplateReductionResult(expression, bindings, shadowed, nextSeen);
1211
+ if (reduction) return reduction;
1212
+ const directCallable = unwrapExpression(expression.callee);
1213
+ if (directCallable && (directCallable.type === "ArrowFunctionExpression" || directCallable.type === "FunctionExpression")) return {
1214
+ ...collectTemplateCallableReturnAnalysis(directCallable, bindings, shadowed, nextSeen),
1215
+ unknown: true
1216
+ };
1217
+ const memberCallee = unwrapExpression(expression.callee);
1218
+ if (memberCallee && (memberCallee.type === "MemberExpression" || memberCallee.type === "OptionalMemberExpression")) {
1219
+ const method = readStaticTemplateMemberProperty(memberCallee, bindings, shadowed);
1220
+ const literalMethod = method ? selectTemplateStaticMemberExpression(memberCallee.object, method, bindings, shadowed, /* @__PURE__ */ new Set()) : void 0;
1221
+ if (literalMethod?.type === "ObjectMethod") return {
1222
+ ...collectTemplateCallableReturnAnalysis(literalMethod, bindings, shadowed, nextSeen),
1223
+ unknown: true
1224
+ };
1225
+ if (method === "call" || method === "apply" || method === "bind") {
1226
+ const receiver = collectDynamicSelectorCandidates(memberCallee.object, bindings, shadowed, nextSeen);
1227
+ const receiverPath = readStaticTemplateMemberPath(memberCallee.object, bindings, shadowed);
1228
+ if (receiverPath && bindings.componentFactories.has(receiverPath)) receiver.componentFactories.add(receiverPath);
1229
+ if (receiverPath && bindings.gtComponentFactories.has(receiverPath)) receiver.gtComponentFactories.add(receiverPath);
1230
+ if (receiver.componentFactories.size > 0 || receiver.gtComponentFactories.size > 0) return {
1231
+ ...receiver,
1232
+ unknown: true
1233
+ };
1234
+ }
1235
+ if (method && (COMPONENT_SELECTING_ARRAY_METHODS.has(method) || COMPONENT_PRESERVING_ARRAY_METHODS.has(method))) {
1236
+ const arrays = collectTemplateContainerReferences(memberCallee.object, bindings, shadowed, nextSeen).containers.filter((container) => isKnownTemplateArray(container, bindings) && !templateContainerHasOwnMember(container, method, bindings));
1237
+ if (arrays.length > 0) {
1238
+ if (COMPONENT_PRESERVING_ARRAY_METHODS.has(method)) {
1239
+ const argumentAnalyses = method === "concat" ? expression.arguments.flatMap((argument) => argument.type === "ArgumentPlaceholder" ? [] : [collectDynamicSelectorCandidates(argument.type === "SpreadElement" ? argument.argument : argument, bindings, shadowed, nextSeen)]) : [];
1240
+ const argumentContainers = method === "concat" ? argumentAnalyses.flatMap((analysis) => analysis.containers) : [];
1241
+ return {
1242
+ ...emptyDynamicSelectorAnalysis(true),
1243
+ containers: [...arrays, ...argumentContainers],
1244
+ possibleGT: argumentAnalyses.some((analysis) => selectorAnalysisMayContainGT(analysis, bindings))
1245
+ };
1246
+ }
1247
+ let hasUnknownSelection = false;
1248
+ const analyses = arrays.flatMap((container) => {
1249
+ const key = readSelectingArrayMethodKey(method, expression.arguments[0], container, bindings, shadowed);
1250
+ if (key === null) return [];
1251
+ hasUnknownSelection ||= key === void 0;
1252
+ return [selectTemplateContainerReference(container, key, bindings, shadowed, nextSeen)];
1253
+ });
1254
+ if (analyses.length === 0) return emptyDynamicSelectorAnalysis(false);
1255
+ const selected = mergeDynamicSelectorAnalyses(analyses);
1256
+ return {
1257
+ ...selected,
1258
+ unknown: selected.unknown || hasUnknownSelection
1259
+ };
1260
+ }
1261
+ }
1262
+ if (method === "get") {
1263
+ const receiverPath = readStaticTemplateMemberPath(memberCallee.object, bindings, shadowed);
1264
+ if (receiverPath && findPossibleGTContainerPath(receiverPath, bindings)) return {
1265
+ ...emptyDynamicSelectorAnalysis(true),
1266
+ possibleGT: true
1267
+ };
1268
+ const references = collectTemplateContainerReferences(memberCallee.object, bindings, shadowed, nextSeen);
1269
+ if (references.containers.length > 0) {
1270
+ const argument = expression.arguments[0];
1271
+ const staticKey = argument && argument.type !== "ArgumentPlaceholder" && argument.type !== "SpreadElement" ? readTemplateStaticPrimitive(argument, bindings, shadowed) : void 0;
1272
+ const key = staticKey?.ok && (typeof staticKey.value === "string" || typeof staticKey.value === "number") ? String(staticKey.value) : argument && argument.type !== "ArgumentPlaceholder" && argument.type !== "SpreadElement" ? (() => {
1273
+ const argumentPath = readStaticTemplateMemberPath(argument, bindings, shadowed);
1274
+ return argumentPath && bindings.containerKinds.has(argumentPath) ? argumentPath : void 0;
1275
+ })() : void 0;
1276
+ const selected = mergeDynamicSelectorAnalyses(references.containers.map((container) => selectTemplateContainerReference(container, key, bindings, shadowed, nextSeen)));
1277
+ return {
1278
+ ...selected,
1279
+ unknown: selected.unknown || key === void 0
1280
+ };
1281
+ }
1282
+ }
1283
+ }
1284
+ const callee = readStaticTemplateMemberPath(expression.callee, bindings, shadowed);
1285
+ if (callee === "Reflect.get" && expression.arguments.length >= 2) {
1286
+ const target = expression.arguments[0];
1287
+ const keyNode = expression.arguments[1];
1288
+ if (target && target.type !== "ArgumentPlaceholder" && target.type !== "SpreadElement" && keyNode && keyNode.type !== "ArgumentPlaceholder" && keyNode.type !== "SpreadElement") {
1289
+ const references = collectTemplateContainerReferences(target, bindings, shadowed, nextSeen);
1290
+ const staticKey = readTemplateStaticPrimitive(keyNode, bindings, shadowed);
1291
+ const key = staticKey.ok && (typeof staticKey.value === "string" || typeof staticKey.value === "number") ? String(staticKey.value) : void 0;
1292
+ const selected = mergeDynamicSelectorAnalyses(references.containers.map((container) => selectTemplateContainerReference(container, key, bindings, shadowed, nextSeen)));
1293
+ if (references.containers.length > 0) return {
1294
+ ...selected,
1295
+ unknown: selected.unknown || key === void 0
1296
+ };
1297
+ }
1298
+ }
1299
+ const first = expression.arguments[0];
1300
+ if (callee && bindings.identityFunctions.has(callee) && expression.arguments.length === 1 && first && first.type !== "ArgumentPlaceholder" && first.type !== "SpreadElement") return collectDynamicSelectorCandidates(first, bindings, shadowed, nextSeen);
1301
+ const argumentsAnalysis = mergeDynamicSelectorAnalyses(expression.arguments.filter((argument) => argument.type !== "ArgumentPlaceholder").map((argument) => collectDynamicSelectorCandidates(argument.type === "SpreadElement" ? argument.argument : argument, bindings, shadowed, nextSeen)));
1302
+ const calleeAnalysis = collectDynamicSelectorCandidates(expression.callee, bindings, shadowed, nextSeen);
1303
+ for (const candidate of calleeAnalysis.candidates) {
1304
+ if (candidate.kind !== "expression") continue;
1305
+ if (bindings.componentFactories.has(candidate.name)) argumentsAnalysis.componentFactories.add(candidate.name);
1306
+ if (bindings.gtComponentFactories.has(candidate.name)) argumentsAnalysis.gtComponentFactories.add(candidate.name);
1307
+ }
1308
+ for (const name of calleeAnalysis.componentFactories) argumentsAnalysis.componentFactories.add(name);
1309
+ for (const name of calleeAnalysis.gtComponentFactories) argumentsAnalysis.gtComponentFactories.add(name);
1310
+ if (callee && bindings.componentFactories.has(callee)) argumentsAnalysis.componentFactories.add(callee);
1311
+ if (callee && bindings.gtComponentFactories.has(callee)) argumentsAnalysis.gtComponentFactories.add(callee);
1312
+ return {
1313
+ ...argumentsAnalysis,
1314
+ unknown: true
1315
+ };
1316
+ }
1317
+ if (expression.type === "AssignmentExpression") return collectDynamicSelectorCandidates(expression.right, bindings, shadowed, nextSeen);
1318
+ if (expression.type === "AwaitExpression" || expression.type === "YieldExpression") return expression.argument ? collectDynamicSelectorCandidates(expression.argument, bindings, shadowed, nextSeen) : emptyDynamicSelectorAnalysis(true);
1319
+ return emptyDynamicSelectorAnalysis(false);
1320
+ }
1321
+ /** Finds component-bearing values that a dynamic container index may select. */
1322
+ function collectTemplateContainerCandidates(node, bindings, shadowed, seen) {
1323
+ const expression = unwrapExpression(node);
1324
+ if (!expression || seen.has(expression)) return emptyDynamicSelectorAnalysis(true);
1325
+ const nextSeen = new Set(seen).add(expression);
1326
+ if (expression.type === "ArrayExpression" || expression.type === "ObjectExpression") return collectLiteralContainerCandidates(expression, bindings, shadowed, nextSeen);
1327
+ if (expression.type === "CallExpression" || expression.type === "OptionalCallExpression") {
1328
+ const transformed = collectTemplateTransformCandidates(expression, bindings, shadowed, nextSeen);
1329
+ if (transformed) return transformed;
1330
+ }
1331
+ const path = readStaticTemplateMemberPath(expression, bindings, shadowed);
1332
+ if (path && (bindings.containerKinds.has(path) || findPossibleGTContainerPath(path, bindings) !== void 0 || hasImmediatePossibleGTContainerChild(path, bindings) || hasPossibleStaticStringChild(path, bindings))) {
1333
+ const result = bindings.containerKinds.has(path) || hasImmediatePossibleGTContainerChild(path, bindings) || hasPossibleStaticStringChild(path, bindings) ? collectExposedContainerCandidates(path, bindings) : emptyDynamicSelectorAnalysis(true);
1334
+ return {
1335
+ ...result,
1336
+ possibleGT: result.possibleGT || findPossibleGTContainerPath(path, bindings) !== void 0
1337
+ };
1338
+ }
1339
+ if (expression.type === "CallExpression" || expression.type === "OptionalCallExpression") {
1340
+ const callee = readStaticTemplateMemberPath(expression.callee, bindings, shadowed);
1341
+ if (callee && bindings.gtContainerFactories.has(callee)) return {
1342
+ ...emptyDynamicSelectorAnalysis(true),
1343
+ possibleGT: true
1344
+ };
1345
+ }
1346
+ const selected = collectDynamicSelectorCandidates(expression, bindings, shadowed, seen);
1347
+ const analyses = selected.containers.map((container) => selectTemplateContainerReference(container, void 0, bindings, shadowed, nextSeen));
1348
+ if (analyses.length === 0) return {
1349
+ ...emptyDynamicSelectorAnalysis(true),
1350
+ possibleGT: false
1351
+ };
1352
+ const result = mergeDynamicSelectorAnalyses(analyses);
1353
+ return {
1354
+ ...result,
1355
+ possibleGT: result.possibleGT,
1356
+ unknown: result.unknown || selected.unknown
1357
+ };
1358
+ }
1359
+ /** Models built-in transforms whose result is immediately selected or iterated. */
1360
+ function collectTemplateTransformCandidates(call, bindings, shadowed, seen) {
1361
+ const callee = unwrapExpression(call.callee);
1362
+ if (!callee || callee.type !== "MemberExpression" && callee.type !== "OptionalMemberExpression") return;
1363
+ const method = readStaticTemplateMemberProperty(callee, bindings, shadowed);
1364
+ if (!method) return void 0;
1365
+ const receiverPath = readStaticTemplateMemberPath(callee.object, bindings, shadowed);
1366
+ const readArgument = (index) => {
1367
+ const argument = call.arguments[index];
1368
+ return argument && argument.type !== "ArgumentPlaceholder" ? argument.type === "SpreadElement" ? argument.argument : argument : void 0;
1369
+ };
1370
+ const receiver = () => collectTemplateContainerCandidates(callee.object, bindings, shadowed, seen);
1371
+ const mapValues = (source, callbackNode, includeSourceParameter = true, thisNode) => {
1372
+ const callback = unwrapExpression(callbackNode);
1373
+ if (!callback || callback.type !== "ArrowFunctionExpression" && callback.type !== "FunctionExpression") return {
1374
+ ...source,
1375
+ unknown: true
1376
+ };
1377
+ const parameters = /* @__PURE__ */ new Map();
1378
+ const sourceArray = {
1379
+ ...emptyDynamicSelectorAnalysis(false),
1380
+ containers: [{
1381
+ kind: "analysis",
1382
+ containerKind: "array",
1383
+ values: source
1384
+ }]
1385
+ };
1386
+ bindTemplateCallbackParameters(callback, [
1387
+ source,
1388
+ emptyDynamicSelectorAnalysis(false),
1389
+ ...includeSourceParameter ? [sourceArray] : []
1390
+ ], bindings, shadowed, parameters);
1391
+ if (callback.type !== "ArrowFunctionExpression" && thisNode) parameters.set("this", collectTemplateSelectorValue(thisNode, bindings, shadowed, seen));
1392
+ const analyses = collectTemplateFunctionReturns(callback).map((value) => collectTemplateCallbackReturnValue(value, parameters, bindings, shadowed, seen));
1393
+ const mapped = mergeDynamicSelectorAnalyses(analyses);
1394
+ return {
1395
+ ...mapped,
1396
+ unknown: mapped.unknown || analyses.length === 0
1397
+ };
1398
+ };
1399
+ if (receiverPath === "Array" && method === "from" && !bindings.directBindings.has("Array") && !shadowed.has("Array")) {
1400
+ const sourceNode = readArgument(0);
1401
+ if (!sourceNode) return emptyDynamicSelectorAnalysis(true);
1402
+ const source = collectTemplateContainerCandidates(sourceNode, bindings, shadowed, seen);
1403
+ return call.arguments.length > 1 ? mapValues(source, readArgument(1), false, readArgument(2)) : source;
1404
+ }
1405
+ if (receiverPath === "Object" && (method === "values" || method === "entries") && !bindings.directBindings.has("Object") && !shadowed.has("Object")) {
1406
+ const sourceNode = readArgument(0);
1407
+ if (!sourceNode) return emptyDynamicSelectorAnalysis(true);
1408
+ if (method === "values") return collectTemplateContainerCandidates(sourceNode, bindings, shadowed, seen);
1409
+ const sourceValues = collectTemplateContainerCandidates(sourceNode, bindings, shadowed, seen);
1410
+ const source = unwrapExpression(sourceNode);
1411
+ if (source?.type !== "ObjectExpression") return {
1412
+ ...emptyDynamicSelectorAnalysis(false),
1413
+ containers: [{
1414
+ kind: "analysis",
1415
+ containerKind: "array",
1416
+ members: new Map([["0", emptyDynamicSelectorAnalysis(false)], ["1", sourceValues]]),
1417
+ values: sourceValues
1418
+ }]
1419
+ };
1420
+ const properties = flattenTemplateLiteralObject(source, /* @__PURE__ */ new Set());
1421
+ if (!properties) return emptyDynamicSelectorAnalysis(true);
1422
+ const tuples = [];
1423
+ let unknown = false;
1424
+ for (const property of properties) {
1425
+ if (property.type === "SpreadElement") {
1426
+ unknown = true;
1427
+ continue;
1428
+ }
1429
+ const key = readTemplateLiteralPropertyKey(property, bindings, shadowed);
1430
+ if (property.type !== "ObjectProperty" || !babel.isExpression(property.value)) {
1431
+ unknown = true;
1432
+ continue;
1433
+ }
1434
+ tuples.push({
1435
+ kind: "literal",
1436
+ node: babel.arrayExpression([babel.stringLiteral(key ?? ""), property.value])
1437
+ });
1438
+ unknown ||= key === void 0;
1439
+ }
1440
+ return {
1441
+ ...emptyDynamicSelectorAnalysis(unknown),
1442
+ containers: tuples
1443
+ };
1444
+ }
1445
+ const source = receiver();
1446
+ if (method === "concat") return mergeDynamicSelectorAnalyses([source, ...call.arguments.flatMap((_, index) => {
1447
+ const argument = readArgument(index);
1448
+ if (!argument) return [];
1449
+ return [flattenTemplateTransformAnalysis(collectDynamicSelectorCandidates(argument, bindings, shadowed, seen), 1, bindings, shadowed, seen)];
1450
+ })]);
1451
+ if (method === "map") return mapValues(source, readArgument(0), true, readArgument(1));
1452
+ if (method === "flatMap") return flattenTemplateTransformAnalysis(mapValues(source, readArgument(0), true, readArgument(1)), 1, bindings, shadowed, seen);
1453
+ if (method === "flat") {
1454
+ const depthNode = readArgument(0);
1455
+ const depthValue = depthNode ? readTemplateStaticPrimitive(depthNode, bindings, shadowed, true) : {
1456
+ ok: true,
1457
+ value: 1
1458
+ };
1459
+ if (!depthValue.ok) {
1460
+ const possibilities = [source];
1461
+ let current = source;
1462
+ for (let depth = 0; depth < 32 && current.containers.length > 0; depth += 1) {
1463
+ current = flattenTemplateTransformAnalysis(current, 1, bindings, shadowed, seen);
1464
+ possibilities.push(current);
1465
+ }
1466
+ return {
1467
+ ...mergeDynamicSelectorAnalyses(possibilities),
1468
+ unknown: true
1469
+ };
1470
+ }
1471
+ if (typeof depthValue.value === "bigint") return emptyDynamicSelectorAnalysis(false);
1472
+ const numericDepth = Number(depthValue.value);
1473
+ return flattenTemplateTransformAnalysis(source, Number.isNaN(numericDepth) ? 0 : numericDepth === Number.POSITIVE_INFINITY ? 32 : Math.max(0, Math.trunc(numericDepth)), bindings, shadowed, seen);
1474
+ }
1475
+ if (method === "with" || method === "toSpliced") return mergeDynamicSelectorAnalyses([source, ...(method === "with" ? [readArgument(1)] : call.arguments.slice(2).map((_, index) => readArgument(index + 2))).flatMap((value) => value ? [collectTemplateSelectorValue(value, bindings, shadowed, seen)] : [])]);
1476
+ if (method === "copyWithin") return source;
1477
+ if (method === "fill") {
1478
+ const value = readArgument(0);
1479
+ return value ? collectTemplateSelectorValue(value, bindings, shadowed, seen) : emptyDynamicSelectorAnalysis(false);
1480
+ }
1481
+ if (method === "reduce" || method === "reduceRight") {
1482
+ const reduction = collectTemplateReductionResult(call, bindings, shadowed, seen);
1483
+ if (reduction) return mergeDynamicSelectorAnalyses([{
1484
+ ...reduction,
1485
+ containers: []
1486
+ }, ...reduction.containers.map((container) => selectTemplateContainerReference(container, void 0, bindings, shadowed, seen))]);
1487
+ const flattened = flattenTemplateTransformAnalysis(source, 1, bindings, shadowed, seen);
1488
+ const initial = readArgument(1);
1489
+ return mergeDynamicSelectorAnalyses([
1490
+ source,
1491
+ flattened,
1492
+ ...initial ? [collectTemplateSelectorValue(initial, bindings, shadowed, seen)] : []
1493
+ ]);
1494
+ }
1495
+ }
1496
+ /** Evaluates a finite literal reduce/reduceRight without executing user code. */
1497
+ function collectTemplateReductionResult(call, bindings, shadowed, seen) {
1498
+ const callee = unwrapExpression(call.callee);
1499
+ if (!callee || callee.type !== "MemberExpression" && callee.type !== "OptionalMemberExpression") return;
1500
+ const method = readStaticTemplateMemberProperty(callee, bindings, shadowed);
1501
+ if (method !== "reduce" && method !== "reduceRight") return void 0;
1502
+ const receiver = unwrapExpression(callee.object);
1503
+ if (receiver?.type !== "ArrayExpression") return void 0;
1504
+ const elements = flattenTemplateLiteralArray(receiver, /* @__PURE__ */ new Set());
1505
+ if (!elements) return void 0;
1506
+ const callbackArgument = call.arguments[0];
1507
+ const callback = callbackArgument && callbackArgument.type !== "ArgumentPlaceholder" && callbackArgument.type !== "SpreadElement" ? unwrapExpression(callbackArgument) : void 0;
1508
+ if (!callback || callback.type !== "ArrowFunctionExpression" && callback.type !== "FunctionExpression") return;
1509
+ const entries = elements.filter((element) => Boolean(element)).map((element) => collectTemplateSelectorValue(element, bindings, shadowed, seen));
1510
+ const initialArgument = call.arguments[1];
1511
+ const initial = initialArgument && initialArgument.type !== "ArgumentPlaceholder" && initialArgument.type !== "SpreadElement" ? collectTemplateSelectorValue(initialArgument, bindings, shadowed, seen) : void 0;
1512
+ if (entries.length === 0) return initial ?? emptyDynamicSelectorAnalysis(false);
1513
+ const ordered = method === "reduceRight" ? [...entries].reverse() : entries;
1514
+ let accumulator = initial ?? ordered.shift();
1515
+ if (!accumulator) return emptyDynamicSelectorAnalysis(false);
1516
+ const sourceArray = collectTemplateSelectorValue(receiver, bindings, shadowed, seen);
1517
+ for (const current of ordered) {
1518
+ const parameters = /* @__PURE__ */ new Map();
1519
+ bindTemplateCallbackParameters(callback, [
1520
+ accumulator,
1521
+ current,
1522
+ emptyDynamicSelectorAnalysis(false),
1523
+ sourceArray
1524
+ ], bindings, shadowed, parameters);
1525
+ const returned = collectTemplateFunctionReturns(callback).map((value) => collectTemplateCallbackReturnValue(value, parameters, bindings, shadowed, seen));
1526
+ accumulator = returned.length > 0 ? mergeDynamicSelectorAnalyses(returned) : emptyDynamicSelectorAnalysis(true);
1527
+ }
1528
+ return accumulator;
1529
+ }
1530
+ /** Flattens only container alternatives while retaining non-array values. */
1531
+ function flattenTemplateTransformAnalysis(analysis, depth, bindings, shadowed, seen) {
1532
+ let current = analysis;
1533
+ for (let index = 0; index < depth && current.containers.length > 0; index += 1) current = mergeDynamicSelectorAnalyses([{
1534
+ ...current,
1535
+ containers: []
1536
+ }, ...current.containers.map((container) => selectTemplateContainerReference(container, void 0, bindings, shadowed, seen))]);
1537
+ return current;
1538
+ }
1539
+ /** Binds positional callback values, including a precise rest-argument tuple. */
1540
+ function bindTemplateCallbackParameters(callback, callbackArguments, bindings, shadowed, parameters) {
1541
+ callback.params.forEach((parameter, index) => {
1542
+ if (!isTemplateBindingPattern(parameter)) return;
1543
+ if (parameter.type === "RestElement") {
1544
+ if (!isTemplateBindingPattern(parameter.argument)) return;
1545
+ const restValues = callbackArguments.slice(index);
1546
+ collectTemplateCallbackParameterValues(parameter.argument, {
1547
+ ...emptyDynamicSelectorAnalysis(false),
1548
+ containers: [{
1549
+ kind: "analysis",
1550
+ containerKind: "array",
1551
+ members: new Map(restValues.map((value, memberIndex) => [String(memberIndex), value])),
1552
+ values: mergeDynamicSelectorAnalyses(restValues)
1553
+ }]
1554
+ }, bindings, shadowed, parameters);
1555
+ return;
1556
+ }
1557
+ collectTemplateCallbackParameterValues(parameter, callbackArguments[index] ?? emptyDynamicSelectorAnalysis(true), bindings, shadowed, parameters);
1558
+ });
1559
+ }
1560
+ /** Projects one mapper input through its callback parameter pattern. */
1561
+ function collectTemplateCallbackParameterValues(pattern, values, bindings, shadowed, parameters) {
1562
+ if (pattern.type === "Identifier") {
1563
+ parameters.set(pattern.name, values);
1564
+ return;
1565
+ }
1566
+ if (pattern.type === "AssignmentPattern") {
1567
+ if (isTemplateBindingPattern(pattern.left)) collectTemplateCallbackParameterValues(pattern.left, mergeDynamicSelectorAnalyses([values, collectDynamicSelectorCandidates(pattern.right, bindings, shadowed, /* @__PURE__ */ new Set())]), bindings, shadowed, parameters);
1568
+ return;
1569
+ }
1570
+ if (pattern.type === "RestElement") {
1571
+ if (isTemplateBindingPattern(pattern.argument)) collectTemplateCallbackParameterValues(pattern.argument, {
1572
+ ...emptyDynamicSelectorAnalysis(false),
1573
+ containers: [{
1574
+ kind: "analysis",
1575
+ containerKind: "array",
1576
+ values
1577
+ }]
1578
+ }, bindings, shadowed, parameters);
1579
+ return;
1580
+ }
1581
+ if (pattern.type === "ObjectPattern") {
1582
+ for (const property of pattern.properties) {
1583
+ const target = property.type === "RestElement" ? property.argument : property.value;
1584
+ if (!isTemplateBindingPattern(target)) continue;
1585
+ collectTemplateCallbackParameterValues(target, property.type === "RestElement" ? values : selectPossibleContainerChildren(values, readTemplateLiteralPropertyKey(property, bindings, shadowed), bindings, shadowed), bindings, shadowed, parameters);
1586
+ }
1587
+ return;
1588
+ }
1589
+ pattern.elements.forEach((element, index) => {
1590
+ if (!element || !isTemplateBindingPattern(element)) return;
1591
+ collectTemplateCallbackParameterValues(element, selectPossibleContainerChildren(values, element.type === "RestElement" ? void 0 : String(index), bindings, shadowed), bindings, shadowed, parameters);
1592
+ });
1593
+ }
1594
+ /** Evaluates a callback return against abstract parameter values. */
1595
+ function collectTemplateCallbackReturnValue(node, parameters, bindings, shadowed, seen) {
1596
+ const expression = unwrapExpression(node);
1597
+ if (!expression) return emptyDynamicSelectorAnalysis(true);
1598
+ if (expression.type === "Identifier") {
1599
+ const parameter = parameters.get(expression.name);
1600
+ if (parameter) return parameter;
1601
+ }
1602
+ if (expression.type === "CallExpression" || expression.type === "OptionalCallExpression") {
1603
+ const callee = unwrapExpression(expression.callee);
1604
+ if (callee && (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") && readStaticTemplateMemberProperty(callee, bindings, shadowed) === "concat") {
1605
+ const objectValue = collectTemplateCallbackReturnValue(callee.object, parameters, bindings, shadowed, seen);
1606
+ if (objectValue.containers.length > 0) {
1607
+ const flattenOne = (value) => mergeDynamicSelectorAnalyses([{
1608
+ ...value,
1609
+ containers: []
1610
+ }, ...value.containers.map((container) => selectTemplateContainerReference(container, void 0, bindings, shadowed, seen))]);
1611
+ const values = mergeDynamicSelectorAnalyses([flattenOne(objectValue), ...expression.arguments.flatMap((argument) => argument.type === "ArgumentPlaceholder" ? [] : [flattenOne(collectTemplateCallbackReturnValue(argument.type === "SpreadElement" ? argument.argument : argument, parameters, bindings, shadowed, seen))])]);
1612
+ return {
1613
+ ...emptyDynamicSelectorAnalysis(false),
1614
+ containers: [{
1615
+ kind: "analysis",
1616
+ containerKind: "array",
1617
+ values
1618
+ }]
1619
+ };
1620
+ }
1621
+ }
1622
+ }
1623
+ if (expression.type === "MemberExpression" || expression.type === "OptionalMemberExpression") {
1624
+ const objectValue = collectTemplateCallbackReturnValue(expression.object, parameters, bindings, shadowed, seen);
1625
+ if (objectValue.containers.length > 0) return selectPossibleContainerChildren(objectValue, readStaticTemplateMemberProperty(expression, bindings, shadowed), bindings, shadowed);
1626
+ }
1627
+ if (expression.type === "ThisExpression") return parameters.get("this") ?? emptyDynamicSelectorAnalysis(true);
1628
+ if (expression.type === "ArrayExpression") {
1629
+ const elementValues = expression.elements.map((element) => element ? collectTemplateCallbackReturnValue(element.type === "SpreadElement" ? element.argument : element, parameters, bindings, shadowed, seen) : emptyDynamicSelectorAnalysis(false));
1630
+ const values = mergeDynamicSelectorAnalyses(elementValues);
1631
+ const hasSpread = expression.elements.some((element) => element?.type === "SpreadElement");
1632
+ return {
1633
+ ...emptyDynamicSelectorAnalysis(false),
1634
+ containers: [{
1635
+ kind: "analysis",
1636
+ containerKind: "array",
1637
+ members: hasSpread ? void 0 : new Map(elementValues.map((value, index) => [String(index), value])),
1638
+ values
1639
+ }]
1640
+ };
1641
+ }
1642
+ if (expression.type === "ObjectExpression") {
1643
+ const values = mergeDynamicSelectorAnalyses(expression.properties.map((property) => collectTemplateCallbackReturnValue(property.type === "SpreadElement" ? property.argument : property.type === "ObjectProperty" ? property.value : property, parameters, bindings, shadowed, seen)));
1644
+ return {
1645
+ ...emptyDynamicSelectorAnalysis(false),
1646
+ containers: [{
1647
+ kind: "analysis",
1648
+ containerKind: "object",
1649
+ values
1650
+ }]
1651
+ };
1652
+ }
1653
+ if (expression.type === "ConditionalExpression") return mergeDynamicSelectorAnalyses([collectTemplateCallbackReturnValue(expression.consequent, parameters, bindings, shadowed, seen), collectTemplateCallbackReturnValue(expression.alternate, parameters, bindings, shadowed, seen)]);
1654
+ if (expression.type === "LogicalExpression") return mergeDynamicSelectorAnalyses([collectTemplateCallbackReturnValue(expression.left, parameters, bindings, shadowed, seen), collectTemplateCallbackReturnValue(expression.right, parameters, bindings, shadowed, seen)]);
1655
+ if (expression.type === "SequenceExpression") {
1656
+ const last = expression.expressions.at(-1);
1657
+ return last ? collectTemplateCallbackReturnValue(last, parameters, bindings, shadowed, seen) : emptyDynamicSelectorAnalysis(true);
1658
+ }
1659
+ return collectTemplateSelectorValue(expression, bindings, shadowed, seen);
1660
+ }
1661
+ /** Resolves an expression to container identities without selecting a child. */
1662
+ function collectTemplateContainerReferences(node, bindings, shadowed, seen) {
1663
+ const expression = unwrapExpression(node);
1664
+ if (!expression || seen.has(expression)) return emptyDynamicSelectorAnalysis(true);
1665
+ if (expression.type === "ArrayExpression" || expression.type === "ObjectExpression") return {
1666
+ ...emptyDynamicSelectorAnalysis(false),
1667
+ containers: [{
1668
+ kind: "literal",
1669
+ node: expression
1670
+ }]
1671
+ };
1672
+ const path = readStaticTemplateMemberPath(expression, bindings, shadowed);
1673
+ if (path && bindings.containerKinds.has(path)) return {
1674
+ ...emptyDynamicSelectorAnalysis(false),
1675
+ containers: [{
1676
+ kind: "path",
1677
+ path
1678
+ }]
1679
+ };
1680
+ const selected = collectDynamicSelectorCandidates(expression, bindings, shadowed, seen);
1681
+ return {
1682
+ ...emptyDynamicSelectorAnalysis(selected.unknown),
1683
+ containers: selected.containers
1684
+ };
1685
+ }
1686
+ /** Selects one exact child, or every immediate child, from a container. */
1687
+ function selectTemplateContainerReference(container, key, bindings, shadowed, seen) {
1688
+ if (container.kind === "path") return key === void 0 ? collectExposedContainerCandidates(container.path, bindings) : collectExposedPathCandidate(appendTemplatePath(container.path, key), bindings);
1689
+ if (container.kind === "analysis") {
1690
+ const selected = key === void 0 ? container.values : container.members?.get(key);
1691
+ return selected ? {
1692
+ ...selected,
1693
+ unknown: selected.unknown || key === void 0
1694
+ } : emptyDynamicSelectorAnalysis(true);
1695
+ }
1696
+ if (key === void 0) return collectLiteralContainerCandidates(container.node, bindings, shadowed, seen);
1697
+ const selected = selectTemplateLiteralMember(container.node, key);
1698
+ return selected ? collectTemplateSelectorValue(selected, bindings, shadowed, seen) : templateLiteralMemberIsUncertain(container.node, key) ? collectLiteralContainerCandidates(container.node, bindings, shadowed, seen) : emptyDynamicSelectorAnalysis(false);
1699
+ }
1700
+ /** Reads one exact flattened script path, retaining its value category. */
1701
+ function collectExposedPathCandidate(path, bindings) {
1702
+ const result = emptyDynamicSelectorAnalysis(false);
1703
+ const value = bindings.staticValues.get(path);
1704
+ if (typeof value === "string") result.candidates.push({
1705
+ kind: "string",
1706
+ name: value
1707
+ });
1708
+ const possibleStrings = bindings.possibleStaticStrings.get(path);
1709
+ if (possibleStrings) {
1710
+ for (const possible of possibleStrings) result.candidates.push({
1711
+ kind: "string",
1712
+ name: possible
1713
+ });
1714
+ result.unknown = possibleStrings.size > 0;
1715
+ }
1716
+ if (bindings.components.has(path) || bindings.vueBuiltins.has(path) || bindings.uncertainComponents.has(path)) result.candidates.push({
1717
+ kind: "expression",
1718
+ name: path
1719
+ });
1720
+ if (bindings.componentFactories.has(path)) {
1721
+ result.componentFactories.add(path);
1722
+ result.candidates.push({
1723
+ kind: "expression",
1724
+ name: path
1725
+ });
1726
+ }
1727
+ if (bindings.gtComponentFactories.has(path)) result.gtComponentFactories.add(path);
1728
+ if (bindings.containerKinds.has(path)) result.containers.push({
1729
+ kind: "path",
1730
+ path
1731
+ });
1732
+ const possibleContainer = findPossibleGTContainerPath(path, bindings);
1733
+ if (possibleContainer) result.containers.push({
1734
+ kind: "path",
1735
+ path: possibleContainer
1736
+ });
1737
+ result.possibleGT ||= templatePathSelectsPossibleGT(path, bindings);
1738
+ result.unknown = result.unknown || bindings.uncertainComponents.has(path) || result.candidates.length === 0 && result.componentFactories.size === 0 && result.containers.length === 0;
1739
+ return result;
1740
+ }
1741
+ /** Returns true only for arrays whose shape was proven by static analysis. */
1742
+ function isKnownTemplateArray(container, bindings) {
1743
+ return container.kind === "literal" ? container.node.type === "ArrayExpression" : container.kind === "analysis" ? container.containerKind === "array" : bindings.containerKinds.get(container.path) === "array";
1744
+ }
1745
+ /** Detects a statically defined own property that overrides an array method. */
1746
+ function templateContainerHasOwnMember(container, member, bindings) {
1747
+ if (container.kind !== "path") return false;
1748
+ const path = appendTemplatePath(container.path, member);
1749
+ return bindings.components.has(path) || bindings.componentFactories.has(path) || bindings.containerKinds.has(path) || bindings.gtComponentFactories.has(path) || bindings.staticValues.has(path) || bindings.uncertainComponents.has(path) || bindings.vueBuiltins.has(path);
1750
+ }
1751
+ /** Resolves the exact child selected by an array method when it is static. */
1752
+ function readSelectingArrayMethodKey(method, argument, container, bindings, shadowed) {
1753
+ if (templateContainerHasOwnMember(container, method, bindings)) return null;
1754
+ const length = container.kind === "literal" ? container.node.type === "ArrayExpression" ? flattenTemplateLiteralArray(container.node, /* @__PURE__ */ new Set())?.length : void 0 : container.kind === "path" ? bindings.arrayLengths.get(container.path) : void 0;
1755
+ if (method === "shift") return length === 0 ? null : "0";
1756
+ if (method === "pop") return length === void 0 ? void 0 : length === 0 ? null : `${length - 1}`;
1757
+ if (method !== "at") return void 0;
1758
+ if (argument?.type === "ArgumentPlaceholder" || argument?.type === "SpreadElement") return;
1759
+ const indexValue = argument ? readTemplateStaticPrimitive(argument, bindings, shadowed) : {
1760
+ ok: true,
1761
+ value: 0
1762
+ };
1763
+ if (!indexValue.ok) return void 0;
1764
+ if (typeof indexValue.value === "bigint") return null;
1765
+ let index;
1766
+ try {
1767
+ index = Number(indexValue.value);
1768
+ } catch {
1769
+ return null;
1770
+ }
1771
+ if (Number.isNaN(index)) index = 0;
1772
+ else if (!Number.isFinite(index)) return null;
1773
+ index = Math.trunc(index);
1774
+ if (index < 0) {
1775
+ if (length === void 0) return void 0;
1776
+ index += length;
1777
+ }
1778
+ if (index < 0 || length !== void 0 && index >= length) return null;
1779
+ return String(index);
1780
+ }
1781
+ /** Collects only the immediate values that one literal selection may return. */
1782
+ function collectLiteralContainerCandidates(container, bindings, shadowed, seen) {
1783
+ if (container.type === "ArrayExpression") {
1784
+ const flattened = flattenTemplateLiteralArray(container, /* @__PURE__ */ new Set());
1785
+ const analyses = (flattened ? flattened.filter((value) => Boolean(value)) : container.elements.flatMap((element) => !element ? [] : element.type === "SpreadElement" ? [] : [element])).map((value) => collectTemplateSelectorValue(value, bindings, shadowed, seen));
1786
+ if (!flattened) for (const element of container.elements) {
1787
+ if (element?.type !== "SpreadElement") continue;
1788
+ analyses.push(collectTemplateContainerCandidates(element.argument, bindings, shadowed, seen));
1789
+ }
1790
+ const result = mergeDynamicSelectorAnalyses(analyses);
1791
+ return {
1792
+ ...result,
1793
+ unknown: result.unknown || !flattened
1794
+ };
1795
+ }
1796
+ const properties = flattenTemplateLiteralObject(container, /* @__PURE__ */ new Set());
1797
+ const finalValues = /* @__PURE__ */ new Map();
1798
+ const uncertainValues = [];
1799
+ const spreadAnalyses = [];
1800
+ for (const property of properties ?? container.properties) {
1801
+ if (property.type === "SpreadElement") {
1802
+ spreadAnalyses.push(collectTemplateContainerCandidates(property.argument, bindings, shadowed, seen));
1803
+ continue;
1804
+ }
1805
+ const key = readTemplateLiteralPropertyKey(property, bindings, shadowed);
1806
+ const value = property.type === "ObjectProperty" ? property.value : property.type === "ObjectMethod" && property.kind === "get" ? property : void 0;
1807
+ if (!value) continue;
1808
+ if (key === void 0) uncertainValues.push(value);
1809
+ else finalValues.set(key, value);
1810
+ }
1811
+ const analyses = [...finalValues.values(), ...uncertainValues].map((value) => collectTemplateSelectorValue(value, bindings, shadowed, seen));
1812
+ analyses.push(...spreadAnalyses);
1813
+ const result = mergeDynamicSelectorAnalyses(analyses);
1814
+ return {
1815
+ ...result,
1816
+ unknown: result.unknown || properties === void 0 || uncertainValues.length > 0
1817
+ };
1818
+ }
1819
+ /** Preserves a nested literal as a container instead of flattening its leaves. */
1820
+ function collectTemplateSelectorValue(node, bindings, shadowed, seen) {
1821
+ if (node.type === "ObjectMethod" && node.kind === "get") return {
1822
+ ...mergeDynamicSelectorAnalyses(collectTemplateFunctionReturns(node).map((value) => collectTemplateSelectorValue(value, bindings, shadowed, seen))),
1823
+ unknown: true
1824
+ };
1825
+ const expression = unwrapExpression(node);
1826
+ if (expression?.type === "ArrayExpression" || expression?.type === "ObjectExpression") return {
1827
+ ...emptyDynamicSelectorAnalysis(false),
1828
+ containers: [{
1829
+ kind: "literal",
1830
+ node: expression
1831
+ }]
1832
+ };
1833
+ const path = readStaticTemplateMemberPath(expression, bindings, shadowed);
1834
+ if (path && bindings.containerKinds.has(path)) return {
1835
+ ...emptyDynamicSelectorAnalysis(false),
1836
+ containers: [{
1837
+ kind: "path",
1838
+ path
1839
+ }]
1840
+ };
1841
+ return expression ? collectDynamicSelectorCandidates(expression, bindings, shadowed, seen) : emptyDynamicSelectorAnalysis(true);
1842
+ }
1843
+ /** Collects returns from one function body without entering nested functions. */
1844
+ function collectTemplateCallableReturnAnalysis(fn, bindings, shadowed, seen) {
1845
+ return mergeDynamicSelectorAnalyses(collectTemplateFunctionReturns(fn).map((value) => collectTemplateSelectorValue(value, bindings, shadowed, seen)));
1846
+ }
1847
+ function collectTemplateFunctionReturns(fn) {
1848
+ if (fn.type === "ArrowFunctionExpression" && fn.body.type !== "BlockStatement") return [fn.body];
1849
+ const returns = [];
1850
+ const visit = (node) => {
1851
+ if (node !== fn && babel.isFunction(node)) return;
1852
+ if (node.type === "ReturnStatement") {
1853
+ if (node.argument && babel.isExpression(node.argument)) returns.push(node.argument);
1854
+ return;
1855
+ }
1856
+ for (const key of babel.VISITOR_KEYS[node.type] ?? []) {
1857
+ const child = node[key];
1858
+ if (Array.isArray(child)) {
1859
+ for (const entry of child) if (entry && typeof entry === "object" && "type" in entry) visit(entry);
1860
+ } else if (child && typeof child === "object" && "type" in child) visit(child);
1861
+ }
1862
+ };
1863
+ visit(fn);
1864
+ return returns;
1865
+ }
1866
+ /** Expands literal-only object spreads while preserving property write order. */
1867
+ function flattenTemplateLiteralObject(object, seen) {
1868
+ if (seen.has(object)) return void 0;
1869
+ const nextSeen = new Set(seen).add(object);
1870
+ const properties = [];
1871
+ for (const property of object.properties) {
1872
+ if (property.type !== "SpreadElement") {
1873
+ properties.push(property);
1874
+ continue;
1875
+ }
1876
+ const argument = unwrapExpression(property.argument);
1877
+ if (argument?.type !== "ObjectExpression") return void 0;
1878
+ const spread = flattenTemplateLiteralObject(argument, nextSeen);
1879
+ if (!spread) return void 0;
1880
+ properties.push(...spread);
1881
+ }
1882
+ return properties;
1883
+ }
1884
+ /** Resolves a literal object key without executing user code. */
1885
+ function readTemplateLiteralPropertyKey(property, bindings, shadowed) {
1886
+ if (property.type === "SpreadElement") return void 0;
1887
+ if (!property.computed && property.key.type === "Identifier") return property.key.name;
1888
+ if (property.key.type === "StringLiteral") return property.key.value;
1889
+ if (property.key.type === "NumericLiteral") return String(property.key.value);
1890
+ if (!property.computed) return void 0;
1891
+ const key = readTemplateStaticPrimitive(property.key, bindings, shadowed);
1892
+ return key.ok && (typeof key.value === "string" || typeof key.value === "number") ? String(key.value) : void 0;
1893
+ }
1894
+ /** Collects exact component-bearing descendants exposed by script analysis. */
1895
+ function collectExposedContainerCandidates(path, bindings) {
1896
+ const candidates = /* @__PURE__ */ new Map();
1897
+ const componentFactories = /* @__PURE__ */ new Set();
1898
+ const containers = [];
1899
+ const gtComponentFactories = /* @__PURE__ */ new Set();
1900
+ const prefix = `${path}.`;
1901
+ const isImmediateChild = (name) => {
1902
+ if (!name.startsWith(prefix)) return false;
1903
+ return !name.slice(prefix.length).includes(".");
1904
+ };
1905
+ const addExpression = (name) => {
1906
+ if (!isImmediateChild(name)) return;
1907
+ candidates.set(`expression:${name}`, {
1908
+ kind: "expression",
1909
+ name
1910
+ });
1911
+ };
1912
+ for (const name of bindings.components.keys()) addExpression(name);
1913
+ for (const name of bindings.vueBuiltins.keys()) addExpression(name);
1914
+ for (const name of bindings.uncertainComponents) addExpression(name);
1915
+ for (const [name, value] of bindings.staticValues) if (isImmediateChild(name) && typeof value === "string") candidates.set(`string:${value}`, {
1916
+ kind: "string",
1917
+ name: value
1918
+ });
1919
+ for (const [name, values] of bindings.possibleStaticStrings) {
1920
+ if (!isImmediateChild(name)) continue;
1921
+ for (const value of values) candidates.set(`string:${value}`, {
1922
+ kind: "string",
1923
+ name: value
1924
+ });
1925
+ }
1926
+ for (const name of bindings.componentFactories) {
1927
+ if (!isImmediateChild(name)) continue;
1928
+ componentFactories.add(name);
1929
+ addExpression(name);
1930
+ }
1931
+ for (const name of bindings.gtComponentFactories) {
1932
+ if (!isImmediateChild(name)) continue;
1933
+ gtComponentFactories.add(name);
1934
+ addExpression(name);
1935
+ }
1936
+ for (const [name] of bindings.containerKinds) if (isImmediateChild(name)) containers.push({
1937
+ kind: "path",
1938
+ path: name
1939
+ });
1940
+ const addNestedContainer = (name, requireNestedChild) => {
1941
+ if (!name.startsWith(prefix)) return;
1942
+ const suffix = name.slice(prefix.length);
1943
+ if (requireNestedChild && !suffix.includes(".")) return;
1944
+ const firstSegment = suffix.split(".", 1)[0];
1945
+ if (!firstSegment) return;
1946
+ const childPath = `${prefix}${firstSegment}`;
1947
+ if (!containers.some((container) => container.kind === "path" && container.path === childPath)) containers.push({
1948
+ kind: "path",
1949
+ path: childPath
1950
+ });
1951
+ };
1952
+ for (const name of bindings.possibleGTContainers) addNestedContainer(name, false);
1953
+ for (const name of bindings.possibleStaticStrings.keys()) addNestedContainer(name, true);
1954
+ return {
1955
+ candidates: [...candidates.values()],
1956
+ componentFactories,
1957
+ containers,
1958
+ gtComponentFactories,
1959
+ possibleGT: findPossibleGTContainerPath(path, bindings) !== void 0,
1960
+ unknown: true
1961
+ };
1962
+ }
1963
+ /** Returns whether selecting one direct child of a tainted path can yield T. */
1964
+ function templatePathSelectsPossibleGT(path, bindings) {
1965
+ const separator = path.lastIndexOf(".");
1966
+ return separator > 0 && findPossibleGTContainerPath(path.slice(0, separator), bindings) !== void 0;
1967
+ }
1968
+ /** Finds an exact or wildcard tainted-container path. */
1969
+ function findPossibleGTContainerPath(path, bindings) {
1970
+ if (bindings.possibleGTContainers.has(path)) return path;
1971
+ const wildcard = appendTemplatePath("", unknownTemplatePathSegment).slice(1);
1972
+ const recursiveSuffix = appendTemplatePath("", recursiveTemplatePathSegment);
1973
+ const segments = path.split(".");
1974
+ for (const candidate of bindings.possibleGTContainers) {
1975
+ if (candidate.endsWith(recursiveSuffix)) {
1976
+ const recursiveRoot = candidate.slice(0, -recursiveSuffix.length);
1977
+ if (path === recursiveRoot || path.startsWith(`${recursiveRoot}.`)) return candidate;
1978
+ }
1979
+ const candidateSegments = candidate.split(".");
1980
+ if (candidateSegments.length === segments.length && candidateSegments.every((segment, index) => segment === wildcard || segment === segments[index])) return candidate;
1981
+ }
1982
+ }
1983
+ /** Returns whether one selected child contains a tainted container path. */
1984
+ function hasImmediatePossibleGTContainerChild(path, bindings) {
1985
+ const prefix = `${path}.`;
1986
+ return [...bindings.possibleGTContainers].some((candidate) => candidate.startsWith(prefix));
1987
+ }
1988
+ /** Returns whether one selected child can expose a known selector string. */
1989
+ function hasPossibleStaticStringChild(path, bindings) {
1990
+ const prefix = `${path}.`;
1991
+ return [...bindings.possibleStaticStrings].some(([candidate, values]) => candidate.startsWith(prefix) && values.size > 0);
1992
+ }
1993
+ /** Selects through nested literal member chains in a template expression. */
1994
+ function selectTemplateStaticMemberExpression(node, key, bindings, shadowed, seen) {
1995
+ const expression = unwrapExpression(node);
1996
+ if (!expression || seen.has(expression)) return void 0;
1997
+ const nextSeen = new Set(seen).add(expression);
1998
+ if (expression.type === "MemberExpression" || expression.type === "OptionalMemberExpression") {
1999
+ const parentKey = readStaticTemplateMemberProperty(expression, bindings, shadowed);
2000
+ const parent = parentKey === void 0 ? void 0 : selectTemplateStaticMemberExpression(expression.object, parentKey, bindings, shadowed, nextSeen);
2001
+ return parent ? selectTemplateStaticMemberExpression(parent, key, bindings, shadowed, nextSeen) : void 0;
2002
+ }
2003
+ return selectTemplateLiteralMember(expression, key);
2004
+ }
2005
+ function selectorAnalysisIsKnownComponent(analysis, bindings) {
2006
+ return !analysis.unknown && analysis.componentFactories.size === 0 && analysis.candidates.length > 0 && analysis.candidates.every((candidate) => [...normalizeTemplateBindingNames(candidate.name)].some((name) => candidate.kind === "string" ? bindings.registeredComponents.has(name) || bindings.registeredVueBuiltins.has(name) : bindings.components.has(name) || bindings.vueBuiltins.has(name)));
2007
+ }
2008
+ function selectorCandidate(kind, name) {
2009
+ return {
2010
+ candidates: [{
2011
+ kind,
2012
+ name
2013
+ }],
2014
+ componentFactories: /* @__PURE__ */ new Set(),
2015
+ containers: [],
2016
+ gtComponentFactories: /* @__PURE__ */ new Set(),
2017
+ possibleGT: false,
2018
+ unknown: false
2019
+ };
2020
+ }
2021
+ function emptyDynamicSelectorAnalysis(unknown) {
2022
+ return {
2023
+ candidates: [],
2024
+ componentFactories: /* @__PURE__ */ new Set(),
2025
+ containers: [],
2026
+ gtComponentFactories: /* @__PURE__ */ new Set(),
2027
+ possibleGT: false,
2028
+ unknown
2029
+ };
2030
+ }
2031
+ function mergeDynamicSelectorAnalyses(analyses) {
2032
+ const candidates = /* @__PURE__ */ new Map();
2033
+ const componentFactories = /* @__PURE__ */ new Set();
2034
+ const containers = [];
2035
+ const containerPaths = /* @__PURE__ */ new Set();
2036
+ const literalContainers = /* @__PURE__ */ new Set();
2037
+ const abstractContainers = /* @__PURE__ */ new Set();
2038
+ const gtComponentFactories = /* @__PURE__ */ new Set();
2039
+ let possibleGT = false;
2040
+ let unknown = false;
2041
+ for (const analysis of analyses) {
2042
+ possibleGT ||= analysis.possibleGT;
2043
+ unknown ||= analysis.unknown;
2044
+ for (const candidate of analysis.candidates) candidates.set(`${candidate.kind}:${candidate.name}`, candidate);
2045
+ for (const name of analysis.componentFactories) componentFactories.add(name);
2046
+ for (const container of analysis.containers) {
2047
+ if (container.kind === "path") {
2048
+ if (containerPaths.has(container.path)) continue;
2049
+ containerPaths.add(container.path);
2050
+ } else if (container.kind === "literal") {
2051
+ if (literalContainers.has(container.node)) continue;
2052
+ literalContainers.add(container.node);
2053
+ } else {
2054
+ if (abstractContainers.has(container)) continue;
2055
+ abstractContainers.add(container);
2056
+ }
2057
+ containers.push(container);
2058
+ }
2059
+ for (const name of analysis.gtComponentFactories) gtComponentFactories.add(name);
2060
+ }
2061
+ return {
2062
+ candidates: [...candidates.values()],
2063
+ componentFactories,
2064
+ containers,
2065
+ gtComponentFactories,
2066
+ possibleGT,
2067
+ unknown
2068
+ };
2069
+ }
2070
+ /** Selects a literal array/object member used directly in a template. */
2071
+ function selectTemplateLiteralMember(node, key) {
2072
+ const expression = unwrapExpression(node);
2073
+ if (expression?.type === "ArrayExpression") {
2074
+ const index = key.match(/^(0|[1-9]\d*)$/) ? Number(key) : void 0;
2075
+ const elements = flattenTemplateLiteralArray(expression, /* @__PURE__ */ new Set());
2076
+ return index === void 0 ? void 0 : elements?.[index];
2077
+ }
2078
+ if (expression?.type !== "ObjectExpression") return void 0;
2079
+ const properties = flattenTemplateLiteralObject(expression, /* @__PURE__ */ new Set()) ?? expression.properties;
2080
+ let selected;
2081
+ let uncertainWriteAfterSelection = false;
2082
+ for (const property of properties) {
2083
+ if (property.type === "SpreadElement") {
2084
+ uncertainWriteAfterSelection = true;
2085
+ continue;
2086
+ }
2087
+ const propertyKey = !property.computed && property.key.type === "Identifier" ? property.key.name : property.key.type === "StringLiteral" ? property.key.value : property.key.type === "NumericLiteral" ? String(property.key.value) : void 0;
2088
+ if (propertyKey === void 0) {
2089
+ uncertainWriteAfterSelection = true;
2090
+ continue;
2091
+ }
2092
+ if (propertyKey === key) {
2093
+ selected = property.type === "ObjectProperty" || property.type === "ObjectMethod" ? property.type === "ObjectProperty" ? property.value : property : void 0;
2094
+ uncertainWriteAfterSelection = false;
2095
+ }
2096
+ }
2097
+ return uncertainWriteAfterSelection ? void 0 : selected;
2098
+ }
2099
+ /** Returns whether an unresolved literal member can be supplied by a spread. */
2100
+ function templateLiteralMemberIsUncertain(node, key) {
2101
+ if (node.type === "ArrayExpression") return /^(0|[1-9]\d*)$/.test(key) && flattenTemplateLiteralArray(node, /* @__PURE__ */ new Set()) === void 0;
2102
+ if (flattenTemplateLiteralObject(node, /* @__PURE__ */ new Set())) return false;
2103
+ let uncertain = false;
2104
+ for (const property of node.properties) {
2105
+ if (property.type === "SpreadElement") {
2106
+ uncertain = true;
2107
+ continue;
2108
+ }
2109
+ const propertyKey = !property.computed && property.key.type === "Identifier" ? property.key.name : property.key.type === "StringLiteral" ? property.key.value : property.key.type === "NumericLiteral" ? String(property.key.value) : void 0;
2110
+ if (propertyKey === void 0) uncertain = true;
2111
+ else if (propertyKey === key) uncertain = false;
2112
+ }
2113
+ return uncertain;
2114
+ }
2115
+ /** Flattens array spreads only when every spread operand is another literal. */
2116
+ function flattenTemplateLiteralArray(array, seen) {
2117
+ if (seen.has(array)) return void 0;
2118
+ const nextSeen = new Set(seen).add(array);
2119
+ const elements = [];
2120
+ for (const element of array.elements) {
2121
+ if (!element) {
2122
+ elements.push(void 0);
2123
+ continue;
2124
+ }
2125
+ if (element.type !== "SpreadElement") {
2126
+ elements.push(element);
2127
+ continue;
2128
+ }
2129
+ const argument = unwrapExpression(element.argument);
2130
+ if (argument?.type !== "ArrayExpression") return void 0;
2131
+ const spread = flattenTemplateLiteralArray(argument, nextSeen);
2132
+ if (!spread) return void 0;
2133
+ elements.push(...spread);
2134
+ }
2135
+ return elements;
2136
+ }
2137
+ /** Resolves a computed member key from literals or exposed static bindings. */
2138
+ function readStaticTemplateMemberProperty(node, bindings, shadowed) {
2139
+ if (!node.computed && node.property.type === "Identifier") return node.property.name;
2140
+ if (!node.computed) return void 0;
2141
+ const property = readTemplateStaticPrimitive(node.property, bindings, shadowed);
2142
+ return property.ok && (typeof property.value === "string" || typeof property.value === "number") ? String(property.value) : void 0;
2143
+ }
2144
+ function readTemplateStaticPrimitive(node, bindings, shadowed, allowNumericGlobals = false) {
2145
+ return readStaticPrimitive(node, (identifier) => {
2146
+ if (shadowed.has(identifier.name)) return { ok: false };
2147
+ if (bindings.staticValues.has(identifier.name)) return {
2148
+ ok: true,
2149
+ value: bindings.staticValues.get(identifier.name)
2150
+ };
2151
+ if (allowNumericGlobals && !bindings.directBindings.has(identifier.name) && identifier.name === "Infinity") return {
2152
+ ok: true,
2153
+ value: Number.POSITIVE_INFINITY
2154
+ };
2155
+ if (allowNumericGlobals && !bindings.directBindings.has(identifier.name) && identifier.name === "NaN") return {
2156
+ ok: true,
2157
+ value: NaN
2158
+ };
2159
+ return { ok: false };
2160
+ });
2161
+ }
2162
+ /** Reads a dotted template member chain without evaluating runtime code. */
2163
+ function readStaticTemplateMemberPath(node, bindings, shadowed) {
2164
+ const expression = unwrapExpression(node);
2165
+ if (!expression) return void 0;
2166
+ if (expression.type === "Identifier") return shadowed.has(expression.name) ? void 0 : expression.name;
2167
+ if (expression.type !== "MemberExpression" && expression.type !== "OptionalMemberExpression") return;
2168
+ const object = readStaticTemplateMemberPath(expression.object, bindings, shadowed);
2169
+ const property = readStaticTemplateMemberProperty(expression, bindings, shadowed);
2170
+ return object && property !== void 0 ? appendTemplatePath(object, property) : void 0;
2171
+ }
2172
+ /** Identifies the selector prop that Vue consumes for `<component>`. */
2173
+ function isDynamicComponentSelector(element, property) {
2174
+ if (element.tag.toLowerCase() !== "component") return false;
2175
+ if (property.type === NodeTypes.ATTRIBUTE) return property.name === "is";
2176
+ return property.name === "bind" && readDirectiveKey(property) === "is";
2177
+ }
2178
+ function readDirectiveKey(directive) {
2179
+ return directive.arg?.type === NodeTypes.SIMPLE_EXPRESSION && directive.arg.isStatic ? directive.arg.content : void 0;
2180
+ }
2181
+ function toDisplayString(value) {
2182
+ return value == null ? "" : String(value);
2183
+ }
2184
+ function appendSerializedChild(result, value) {
2185
+ const previous = result[result.length - 1];
2186
+ if (typeof previous === "string" && typeof value === "string") result[result.length - 1] = previous + value;
2187
+ else result.push(value);
2188
+ }
2189
+ function collapseChildren(children) {
2190
+ return children.length === 1 ? children[0] : children;
2191
+ }
2192
+ function unionSets(first, second) {
2193
+ return second.size === 0 ? first : new Set([...first, ...second]);
2194
+ }
2195
+ //#endregion
2196
+ export { parseVueTemplate };
2197
+
2198
+ //# sourceMappingURL=template.js.map