@generaltranslation/vue-extractor 0.0.0 → 0.1.0-iris.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 (87) hide show
  1. package/LICENSE.md +18 -102
  2. package/dist/detect.d.ts +8 -0
  3. package/dist/detect.js +2 -0
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +2 -1
  6. package/dist/inspect.d.ts +9 -0
  7. package/dist/inspect.js +2 -0
  8. package/dist/integration.d.ts +69 -0
  9. package/dist/integration.js +162 -0
  10. package/dist/integration.js.map +1 -0
  11. package/dist/internal/config/configFiles.d.ts +6 -0
  12. package/dist/internal/config/configFiles.js +34 -0
  13. package/dist/internal/config/configFiles.js.map +1 -0
  14. package/dist/internal/config/resolveVueCompilerOptions.d.ts +6 -0
  15. package/dist/internal/config/resolveVueCompilerOptions.js +74 -56
  16. package/dist/internal/config/resolveVueCompilerOptions.js.map +1 -1
  17. package/dist/internal/extractFromVueSource.d.ts +4 -3
  18. package/dist/internal/extractFromVueSource.js +255 -12
  19. package/dist/internal/extractFromVueSource.js.map +1 -1
  20. package/dist/internal/project/consumerUsage.d.ts +34 -0
  21. package/dist/internal/project/consumerUsage.js +1220 -0
  22. package/dist/internal/project/consumerUsage.js.map +1 -0
  23. package/dist/internal/project/detectVueProject.d.ts +13 -0
  24. package/dist/internal/project/detectVueProject.js +65 -0
  25. package/dist/internal/project/detectVueProject.js.map +1 -0
  26. package/dist/internal/project/extractFromVueProject.d.ts +10 -0
  27. package/dist/internal/project/extractFromVueProject.js +579 -0
  28. package/dist/internal/project/extractFromVueProject.js.map +1 -0
  29. package/dist/internal/project/inspectVueProject.d.ts +48 -0
  30. package/dist/internal/project/inspectVueProject.js +143 -0
  31. package/dist/internal/project/inspectVueProject.js.map +1 -0
  32. package/dist/internal/project/manifest.d.ts +64 -0
  33. package/dist/internal/project/manifest.js +270 -0
  34. package/dist/internal/project/manifest.js.map +1 -0
  35. package/dist/internal/project/mergeVueProjectExtraction.d.ts +18 -0
  36. package/dist/internal/project/mergeVueProjectExtraction.js +79 -0
  37. package/dist/internal/project/mergeVueProjectExtraction.js.map +1 -0
  38. package/dist/internal/project/moduleResolver.d.ts +18 -0
  39. package/dist/internal/project/moduleResolver.js +325 -0
  40. package/dist/internal/project/moduleResolver.js.map +1 -0
  41. package/dist/internal/project/scopes.d.ts +31 -0
  42. package/dist/internal/project/scopes.js +182 -0
  43. package/dist/internal/project/scopes.js.map +1 -0
  44. package/dist/internal/project/sourcePatterns.d.ts +4 -0
  45. package/dist/internal/project/sourcePatterns.js +32 -0
  46. package/dist/internal/project/sourcePatterns.js.map +1 -0
  47. package/dist/internal/project/viteAliases.d.ts +42 -0
  48. package/dist/internal/project/viteAliases.js +1020 -0
  49. package/dist/internal/project/viteAliases.js.map +1 -0
  50. package/dist/internal/project/vueSourceClassification.d.ts +13 -0
  51. package/dist/internal/project/vueSourceClassification.js +146 -0
  52. package/dist/internal/project/vueSourceClassification.js.map +1 -0
  53. package/dist/internal/project/workspaces.d.ts +31 -0
  54. package/dist/internal/project/workspaces.js +326 -0
  55. package/dist/internal/project/workspaces.js.map +1 -0
  56. package/dist/internal/project/wrapperProvenance.d.ts +21 -0
  57. package/dist/internal/project/wrapperProvenance.js +287 -0
  58. package/dist/internal/project/wrapperProvenance.js.map +1 -0
  59. package/dist/internal/script/analyze.js +252 -85
  60. package/dist/internal/script/analyze.js.map +1 -1
  61. package/dist/internal/script/jsx.d.ts +7 -4
  62. package/dist/internal/script/jsx.js +351 -79
  63. package/dist/internal/script/jsx.js.map +1 -1
  64. package/dist/internal/script/localModules.d.ts +23 -2
  65. package/dist/internal/script/localModules.js +533 -20
  66. package/dist/internal/script/localModules.js.map +1 -1
  67. package/dist/internal/script/model.d.ts +9 -2
  68. package/dist/internal/script/parser.js +2 -1
  69. package/dist/internal/script/parser.js.map +1 -1
  70. package/dist/internal/script/runtimeModules.d.ts +10 -0
  71. package/dist/internal/script/runtimeModules.js +27 -0
  72. package/dist/internal/script/runtimeModules.js.map +1 -0
  73. package/dist/internal/stringCalls.js +1 -1
  74. package/dist/internal/stringCalls.js.map +1 -1
  75. package/dist/internal/template.js +263 -141
  76. package/dist/internal/template.js.map +1 -1
  77. package/dist/internal/types.d.ts +4 -1
  78. package/dist/internal/utils.d.ts +14 -3
  79. package/dist/internal/utils.js +63 -3
  80. package/dist/internal/utils.js.map +1 -1
  81. package/dist/internal/vueCompiler.d.ts +9 -1
  82. package/dist/internal/vueCompiler.js +37 -14
  83. package/dist/internal/vueCompiler.js.map +1 -1
  84. package/dist/project.d.ts +11 -0
  85. package/dist/project.js +3 -0
  86. package/dist/types.d.ts +95 -4
  87. package/package.json +30 -4
@@ -1,11 +1,12 @@
1
- import { addVueError, babelLocation, readStaticPrimitive, unwrapExpression } from "../utils.js";
1
+ import { parseScriptAst } from "./parser.js";
2
+ import { isKnownNonVueGTRuntime } from "./runtimeModules.js";
3
+ import { addVueError, babelLocation, readStaticGlobalPrimitive, readStaticPrimitive, unwrapExpression } from "../utils.js";
2
4
  import { processVueStringCall } from "../stringCalls.js";
3
5
  import { appendTemplatePath, unknownTemplatePathSegment } from "../templatePath.js";
4
6
  import { createReplayAnalysis } from "./replay.js";
5
7
  import { createSnapshotAnalysis } from "./snapshot.js";
6
8
  import { COMPONENT_IMPORTS, ORDINARY_GLOBAL_VALUES, READONLY_ARRAY_TRANSFORMS, VUE_BUILTIN_IMPORTS, knownExport, knownValueKey } from "./knownValues.js";
7
9
  import { extractVueJSXTranslation, isNestedInVueJSXTranslation, resolveVueJSXElementIdentity, validateVueJSXVariableComponent } from "./jsx.js";
8
- import { parseScriptAst } from "./parser.js";
9
10
  import { isAssignmentTargetWrapper, isBindingPattern, isStaticallyUndefined, patternContains, readMemberProperty, readPatternIdentifier, readPropertyKey } from "./syntax.js";
10
11
  import traverseModule from "@babel/traverse";
11
12
  //#region src/internal/script/analyze.ts
@@ -33,6 +34,7 @@ function createVueScriptAnalysis(stats) {
33
34
  directBindings: /* @__PURE__ */ new Set(),
34
35
  gtComponentFactories: /* @__PURE__ */ new Set(),
35
36
  gtContainerFactories: /* @__PURE__ */ new Set(),
37
+ hasGTSourceReference: false,
36
38
  possibleGTContainers: /* @__PURE__ */ new Set(),
37
39
  possibleStaticStrings: /* @__PURE__ */ new Map(),
38
40
  staticValues: /* @__PURE__ */ new Map(),
@@ -81,6 +83,7 @@ function collectVueScriptImports(source, language, analysis) {
81
83
  /** Extracts calls and component bindings from one padded Vue script block. */
82
84
  function parseVueScript(source, language, context, templateBindings, exposeToTemplate, analysis = createVueScriptAnalysis(), analyzeOptionsApi = true) {
83
85
  if (!source.trim()) return true;
86
+ const initialErrorCount = context.errors.length;
84
87
  let ast;
85
88
  try {
86
89
  ast = parseScriptAst(source, language);
@@ -121,8 +124,14 @@ function parseVueScript(source, language, context, templateBindings, exposeToTem
121
124
  if (state.activeTranslationFunctions.size > 0 && resolveKnownCallTargetWithoutParameterSubstitutions(path.node.callee, path.scope, path.node.start ?? Number.POSITIVE_INFINITY, state).value?.type === "string") return;
122
125
  const vueHelper = readImportedFunctionName(path.node.callee, path.scope, "vue", state);
123
126
  const firstArgument = path.node.arguments[0];
124
- if (vueHelper && ["createVNode", "h"].includes(vueHelper) && firstArgument && firstArgument.type !== "ArgumentPlaceholder" && firstArgument.type !== "SpreadElement" && expressionContainsGTReference(firstArgument, path.scope, state)) addVueError(context, consumerLocation, "Found an unsupported gt-vue <T> component in a Vue render function", "Move the rich translation into a Vue single-file component template");
125
- if (vueHelper === "defineAsyncComponent" && firstArgument && firstArgument.type !== "ArgumentPlaceholder" && firstArgument.type !== "SpreadElement" && expressionContainsGTReference(firstArgument, path.scope, state)) addVueError(context, consumerLocation, "Could not statically extract a gt-vue <T> component behind defineAsyncComponent()", "Use a direct gt-vue component binding in the Vue template");
127
+ if (vueHelper && ["createVNode", "h"].includes(vueHelper) && firstArgument && firstArgument.type !== "ArgumentPlaceholder" && firstArgument.type !== "SpreadElement" && expressionContainsGTReference(firstArgument, path.scope, state)) {
128
+ state.analysis.hasGTSourceReference = true;
129
+ addVueError(context, consumerLocation, "Found an unsupported gt-vue <T> component in a Vue render function", "Move the rich translation into a Vue single-file component template");
130
+ }
131
+ if (vueHelper === "defineAsyncComponent" && firstArgument && firstArgument.type !== "ArgumentPlaceholder" && firstArgument.type !== "SpreadElement" && expressionContainsGTReference(firstArgument, path.scope, state)) {
132
+ state.analysis.hasGTSourceReference = true;
133
+ addVueError(context, consumerLocation, "Could not statically extract a gt-vue <T> component behind defineAsyncComponent()", "Use a direct gt-vue component binding in the Vue template");
134
+ }
126
135
  const callTarget = resolveKnownCallTargetAtPosition(path.node.callee, path.scope, path.node.start ?? Number.POSITIVE_INFINITY, state);
127
136
  const value = callTarget.value;
128
137
  if (value?.type !== "string") {
@@ -133,6 +142,7 @@ function parseVueScript(source, language, context, templateBindings, exposeToTem
133
142
  processForwardedTranslationCalls(path, consumerLocation);
134
143
  return;
135
144
  }
145
+ state.analysis.hasGTSourceReference = true;
136
146
  processVueStringCall(path.node, value.kind, consumerLocation, context, (node) => {
137
147
  if (!node) return { ok: false };
138
148
  const materialized = materializeParameterExpression(node, path.scope, state);
@@ -172,16 +182,20 @@ function parseVueScript(source, language, context, templateBindings, exposeToTem
172
182
  OptionalCallExpression: processCall,
173
183
  TaggedTemplateExpression(path) {
174
184
  if (resolveKnownExpression(path.node.tag, path.scope, state, /* @__PURE__ */ new Set())?.type !== "string") return;
185
+ state.analysis.hasGTSourceReference = true;
175
186
  addVueError(context, babelLocation(path.node.loc), "Found an unsupported tagged template translation in gt-vue", "Call the translation function with a string literal instead");
176
187
  },
177
188
  JSXElement(path) {
178
189
  const value = resolveVueJSXElementIdentity(path.node.openingElement.name, path.scope, jsxAnalysis);
190
+ if (value?.type === "component") state.analysis.hasGTSourceReference = true;
179
191
  if (value?.type === "component" && (value.name === "Var" || value.name === "Num" || value.name === "DateTime" || value.name === "Currency")) validateVueJSXVariableComponent(path.node, value.name, context);
180
192
  if (value?.type !== "component" || value.name !== "T") return;
181
193
  if (isNestedInVueJSXTranslation(path, jsxAnalysis)) return;
182
194
  extractVueJSXTranslation(path, context, jsxAnalysis);
183
195
  }
184
196
  });
197
+ if (state.unsupportedDynamicGTReference && context.errors.length === initialErrorCount) addVueError(context, void 0, "Could not statically resolve possible gt-vue string function alias from a dynamic import", "Use a static gt-vue import so translation ownership can be extracted deterministically");
198
+ if (state.unsupportedMalformedGTReference && context.errors.length === initialErrorCount) addVueError(context, void 0, "Could not statically resolve a gt-vue reference imported through a malformed local module", "Fix the local module syntax so translation ownership can be extracted deterministically");
185
199
  return true;
186
200
  }
187
201
  /** Indexes Babel's lexical scopes so deferred function analysis stays exact. */
@@ -234,6 +248,8 @@ function createScriptState(ast, analysis) {
234
248
  transformArrayEntries: /* @__PURE__ */ new Map(),
235
249
  transformArrayEntriesInProgress: /* @__PURE__ */ new Set(),
236
250
  uncertainTranslationHelperBindings: /* @__PURE__ */ new Set(),
251
+ unsupportedDynamicGTReference: false,
252
+ unsupportedMalformedGTReference: false,
237
253
  unsafeMutableNamespaceSources: /* @__PURE__ */ new Set()
238
254
  };
239
255
  traverse(ast, { enter(path) {
@@ -281,8 +297,9 @@ function memberChainWrites(memberPath) {
281
297
  function collectImports(ast, state, importerFile = state.analysis.entryFile) {
282
298
  traverse(ast, {
283
299
  ImportDeclaration(path) {
284
- if (path.node.importKind === "type") return;
300
+ if (isTypeOnlyImportKind(path.node.importKind)) return;
285
301
  const source = path.node.source.value;
302
+ if (source === "gt-vue" && hasRuntimeImport(path.node) && importerFile === state.analysis.entryFile) state.analysis.hasGTSourceReference = true;
286
303
  if (source !== "gt-vue" && source !== "vue") {
287
304
  registerLocalImportDeclaration(path.node, path.scope, importerFile, state);
288
305
  return;
@@ -297,16 +314,32 @@ function collectImports(ast, state, importerFile = state.analysis.entryFile) {
297
314
  }, specifierPath.scope, state);
298
315
  continue;
299
316
  }
300
- if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type") continue;
317
+ if (specifier.type !== "ImportSpecifier" || isTypeOnlyImportKind(specifier.importKind)) continue;
301
318
  const value = knownExport(source, specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value);
302
319
  if (value) registerImport(specifier.local.name, value, specifierPath.scope, state);
303
320
  }
304
321
  },
322
+ ExportNamedDeclaration(path) {
323
+ if (path.node.exportKind === "type" || !path.node.source || importerFile !== state.analysis.entryFile) return;
324
+ const exportNames = path.node.specifiers.flatMap((specifier) => {
325
+ if (specifier.type === "ExportSpecifier" && isTypeOnlyImportKind(specifier.exportKind)) return [];
326
+ if (specifier.type === "ExportNamespaceSpecifier") return ["*"];
327
+ if (specifier.type !== "ExportSpecifier") return [];
328
+ return [specifier.local.name];
329
+ });
330
+ recordRuntimeReexport(path.node.source.value, exportNames, importerFile, state);
331
+ },
332
+ ExportAllDeclaration(path) {
333
+ if (path.node.exportKind === "type" || importerFile !== state.analysis.entryFile) return;
334
+ recordRuntimeReexport(path.node.source.value, ["*"], importerFile, state);
335
+ },
305
336
  TSImportEqualsDeclaration(path) {
337
+ if (path.node.importKind === "type") return;
306
338
  const reference = path.node.moduleReference;
307
339
  if (reference.type !== "TSExternalModuleReference" || reference.expression.type !== "StringLiteral") return;
308
340
  const source = reference.expression.value;
309
341
  if (source !== "gt-vue" && source !== "vue") return;
342
+ if (source === "gt-vue" && importerFile === state.analysis.entryFile) state.analysis.hasGTSourceReference = true;
310
343
  registerImport(path.node.id.name, {
311
344
  type: "namespace",
312
345
  source,
@@ -321,11 +354,38 @@ function collectImports(ast, state, importerFile = state.analysis.entryFile) {
321
354
  }
322
355
  const namespace = readRequireNamespace(path.node.init, path.scope);
323
356
  if (!namespace) return;
357
+ if (namespace.source === "gt-vue" && importerFile === state.analysis.entryFile) state.analysis.hasGTSourceReference = true;
324
358
  registerRequirePattern(path.node.id, namespace, path.scope, state);
325
359
  }
326
360
  });
327
361
  propagateUncertainTranslationHelperAliases(ast, state);
328
362
  }
363
+ /** Marks only runtime re-exports statically connected to gt-vue. */
364
+ function recordRuntimeReexport(source, exportNames, importerFile, state) {
365
+ if (!importerFile || exportNames.length === 0) return;
366
+ if (source === "gt-vue") {
367
+ state.analysis.hasGTSourceReference = true;
368
+ return;
369
+ }
370
+ if (source === "vue" || isKnownNonVueGTRuntime(source)) return;
371
+ const resolver = state.analysis.localModules;
372
+ const modulePath = resolver?.resolveModule(importerFile, source);
373
+ if (!resolver || !modulePath || !resolver.isProjectModule(modulePath)) return;
374
+ if ((exportNames.includes("*") ? [
375
+ ...COMPONENT_IMPORTS,
376
+ "msg",
377
+ "useGT",
378
+ "useMessages"
379
+ ] : exportNames).some((name) => resolver.hasGTExportReference(modulePath, name))) state.analysis.hasGTSourceReference = true;
380
+ }
381
+ /** Returns whether an import causes a runtime module reference. */
382
+ function hasRuntimeImport(declaration) {
383
+ return declaration.specifiers.length === 0 || declaration.specifiers.some((specifier) => specifier.type !== "ImportSpecifier" || !isTypeOnlyImportKind(specifier.importKind));
384
+ }
385
+ /** Returns whether Babel classified an ESM binding as type-only. */
386
+ function isTypeOnlyImportKind(kind) {
387
+ return kind === "type" || kind === "typeof";
388
+ }
329
389
  /** Retains unresolved-helper provenance through simple immutable aliases. */
330
390
  function propagateUncertainTranslationHelperAliases(ast, state) {
331
391
  const candidates = [];
@@ -371,18 +431,26 @@ function readDynamicImport(node) {
371
431
  /** Marks GT-shaped values selected from a dynamic namespace as unresolved. */
372
432
  function recordDynamicImportPattern(pattern, source, scope, importerFile, state) {
373
433
  if (pattern.type === "VoidPattern") return;
434
+ if (source && isKnownNonVueGTRuntime(source)) return;
435
+ if (source === "gt-vue" && importerFile === state.analysis.entryFile) {
436
+ state.analysis.hasGTSourceReference = true;
437
+ state.unsupportedDynamicGTReference = true;
438
+ }
374
439
  const resolver = state.analysis.localModules;
375
440
  const modulePath = source && source !== "gt-vue" && source !== "vue" && importerFile ? resolver?.resolveModule(importerFile, source) : void 0;
376
441
  if (source === "vue") return;
377
442
  if (source && source !== "gt-vue" && !modulePath) return;
443
+ if (modulePath && resolver && !resolver.isProjectModule(modulePath)) return;
378
444
  if (pattern.type === "Identifier") {
379
- if (modulePath && resolver) for (const exportName of [
380
- ...COMPONENT_IMPORTS,
381
- "msg",
382
- "useGT",
383
- "useMessages"
384
- ]) recordDynamicImportBinding(appendTemplatePath(pattern.name, exportName), exportName, modulePath, state);
385
- else {
445
+ if (modulePath && resolver) {
446
+ const binding = scope.getBinding(pattern.name);
447
+ for (const exportName of [
448
+ ...COMPONENT_IMPORTS,
449
+ "msg",
450
+ "useGT",
451
+ "useMessages"
452
+ ]) recordDynamicImportBinding(appendTemplatePath(pattern.name, exportName), exportName, modulePath, state, bindingReferencesNamespaceMember(binding, exportName, state));
453
+ } else {
386
454
  for (const component of COMPONENT_IMPORTS) {
387
455
  const path = appendTemplatePath(pattern.name, component);
388
456
  state.analysis.uncertainComponents.add(path);
@@ -401,61 +469,102 @@ function recordDynamicImportPattern(pattern, source, scope, importerFile, state)
401
469
  if (property.type !== "ObjectProperty") continue;
402
470
  const exportedName = readPropertyKey(property);
403
471
  const localName = readPatternIdentifier(property.value);
404
- if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state);
472
+ if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state, importerFile === state.analysis.entryFile);
405
473
  else recordUnresolvedGTShapedBinding(localName, exportedName, state);
406
474
  }
407
475
  for (const property of pattern.properties) {
408
476
  if (property.type !== "ObjectProperty" || !property.computed) continue;
409
477
  const exportedName = readResolvedPropertyKey(property, scope, state);
410
478
  const localName = readPatternIdentifier(property.value);
411
- if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state);
479
+ if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state, importerFile === state.analysis.entryFile);
412
480
  else recordUnresolvedGTShapedBinding(localName, exportedName, state);
413
481
  }
414
482
  }
483
+ /** Returns whether one namespace binding is used through a static member. */
484
+ function bindingReferencesNamespaceMember(binding, memberName, state, seen = /* @__PURE__ */ new Set()) {
485
+ if (!binding || seen.has(binding)) return false;
486
+ const nextSeen = new Set(seen).add(binding);
487
+ return Boolean(binding.referencePaths.some((referencePath) => {
488
+ let reference = referencePath;
489
+ while (reference.parentPath && unwrapExpression(reference.parentPath.node) === reference.node) reference = reference.parentPath;
490
+ const parent = reference.parentPath;
491
+ if (parent?.isMemberExpression() || parent?.isOptionalMemberExpression()) return parent.node.object === reference.node && readResolvedMemberProperty(parent.node, parent.scope, state) === memberName;
492
+ if (parent?.isJSXMemberExpression()) return parent.node.object === reference.node && parent.node.property.name === memberName;
493
+ if (parent?.isVariableDeclarator() && parent.node.init === reference.node) {
494
+ if (parent.node.id.type === "Identifier") return bindingReferencesNamespaceMember(parent.scope.getBinding(parent.node.id.name), memberName, state, nextSeen);
495
+ if (parent.node.id.type === "ObjectPattern") return parent.node.id.properties.some((property) => property.type === "RestElement" || property.type === "ObjectProperty" && readResolvedPropertyKey(property, parent.scope, state) === memberName);
496
+ }
497
+ if (parent?.isCallExpression() || parent?.isNewExpression() || parent?.isReturnStatement() || parent?.isSpreadElement() || parent?.isArrayExpression() || parent?.isObjectProperty()) return true;
498
+ return false;
499
+ }));
500
+ }
415
501
  /** Marks only GT roles proven reachable from one static dynamic import. */
416
- function recordDynamicImportBinding(localName, exportName, modulePath, state) {
502
+ function recordDynamicImportBinding(localName, exportName, modulePath, state, establishesEntryProvenance) {
417
503
  const resolution = state.analysis.localModules?.resolveExport(modulePath, exportName);
418
504
  if (!resolution || resolution.status === "absent") return;
419
505
  if (resolution.status !== "resolved") {
420
- recordUnresolvedGTShapedBinding(localName, exportName, state);
506
+ if (resolution.status === "invalid" && materializeRecoveredOrdinaryResolution(resolution, state) !== void 0) return;
507
+ if (establishesEntryProvenance && resolution.status === "invalid" && resolution.hasGTSourceReference) {
508
+ state.analysis.hasGTSourceReference = true;
509
+ state.unsupportedDynamicGTReference = true;
510
+ state.unsupportedMalformedGTReference = true;
511
+ }
512
+ if (resolution.status === "invalid" && resolution.hasGTSourceReference) recordInvalidGTResolution(localName, resolution, state);
513
+ else recordUnresolvedGTShapedBinding(localName, exportName, state);
421
514
  return;
422
515
  }
423
- recordMaterializedLocalUncertainty(localName, materializeLocalExport(resolution.target, state), state, true);
516
+ const materialized = materializeLocalExport(resolution.target, state);
517
+ if (establishesEntryProvenance && materialized.hasGTSourceReference) {
518
+ state.analysis.hasGTSourceReference = true;
519
+ state.unsupportedDynamicGTReference = true;
520
+ }
521
+ recordMaterializedLocalUncertainty(localName, materialized, state, true);
424
522
  }
425
523
  /** Resolves one ESM import through a local, read-only source module graph. */
426
524
  function registerLocalImportDeclaration(declaration, scope, importerFile, state) {
427
525
  const resolver = state.analysis.localModules;
428
526
  const source = declaration.source.value;
527
+ if (isKnownNonVueGTRuntime(source)) return;
429
528
  const modulePath = resolver && importerFile ? resolver.resolveModule(importerFile, source) : void 0;
430
- if (!modulePath || !resolver?.getRecord(modulePath)) {
529
+ if (modulePath && resolver && !resolver.isProjectModule(modulePath)) return;
530
+ if (!resolver || !modulePath) {
431
531
  recordUnresolvedTranslationHelperImports(declaration, scope, state);
432
532
  if (source.startsWith(".") || source.startsWith("/") || resolver?.hasCustomResolver) recordUnresolvedGTShapedImports(declaration, state);
433
533
  return;
434
534
  }
435
535
  for (const specifier of declaration.specifiers) {
436
- if (specifier.type === "ImportSpecifier" && specifier.importKind === "type") continue;
536
+ if (specifier.type === "ImportSpecifier" && isTypeOnlyImportKind(specifier.importKind)) continue;
437
537
  if (specifier.type === "ImportNamespaceSpecifier") {
438
538
  const value = {
439
539
  type: "local-namespace",
440
540
  modulePath
441
541
  };
442
542
  registerImport(specifier.local.name, value, scope, state);
443
- if (importerFile === state.analysis.entryFile) recordLocalNamespaceMembers(specifier.local.name, modulePath, state);
543
+ if (importerFile === state.analysis.entryFile) recordLocalNamespaceMembers(specifier.local.name, modulePath, state, scope.getBinding(specifier.local.name));
444
544
  continue;
445
545
  }
446
546
  const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
447
547
  const resolution = resolver.resolveExport(modulePath, exportName);
548
+ let materialized;
448
549
  if (resolution.status !== "resolved") {
449
- recordUncertainTranslationHelperBinding(specifier.local.name, scope, state);
450
- if (resolution.status === "ambiguous") recordAmbiguousLocalBinding(specifier.local.name, state);
451
- else recordUnresolvedGTShapedBinding(specifier.local.name, exportName, state);
452
- continue;
453
- }
454
- const materialized = materializeLocalExport(resolution.target, state);
550
+ if (resolution.status === "invalid") materialized = materializeRecoveredOrdinaryResolution(resolution, state, true);
551
+ if (!materialized) {
552
+ if (importerFile === state.analysis.entryFile && resolution.status === "invalid" && resolution.hasGTSourceReference) {
553
+ state.analysis.hasGTSourceReference = true;
554
+ state.unsupportedMalformedGTReference = true;
555
+ }
556
+ recordUncertainTranslationHelperBinding(specifier.local.name, scope, state);
557
+ if (resolution.status === "ambiguous") recordAmbiguousLocalBinding(specifier.local.name, state);
558
+ else if (resolution.status === "invalid" && resolution.hasGTSourceReference) recordInvalidGTResolution(specifier.local.name, resolution, state);
559
+ else recordUnresolvedGTShapedBinding(specifier.local.name, exportName, state);
560
+ continue;
561
+ }
562
+ } else materialized = materializeLocalExport(resolution.target, state);
563
+ if (importerFile === state.analysis.entryFile && materialized.hasGTSourceReference) state.analysis.hasGTSourceReference = true;
455
564
  const binding = scope.getBinding(specifier.local.name);
456
565
  if (materialized.value) {
457
566
  registerImport(specifier.local.name, materialized.value, scope, state);
458
- if (materialized.value.type === "local-namespace" && importerFile === state.analysis.entryFile) recordLocalNamespaceMembers(specifier.local.name, materialized.value.modulePath, state);
567
+ if (materialized.value.type === "local-namespace" && importerFile === state.analysis.entryFile) recordLocalNamespaceMembers(specifier.local.name, materialized.value.modulePath, state, binding);
459
568
  }
460
569
  if (binding && materialized.callable) state.localCallableBindings.set(binding, materialized.callable);
461
570
  recordMaterializedLocalUncertainty(specifier.local.name, materialized, state);
@@ -472,25 +581,35 @@ function attachLocalModule(record, state) {
472
581
  } });
473
582
  collectImports(record.ast, state, record.filePath);
474
583
  }
475
- /** Converts a graph export into an analyzer identity or callable. */
476
584
  function materializeLocalExport(target, state) {
477
- if (target.type === "external") return { value: knownExport(target.source, target.exportName) };
478
- if (target.type === "external-namespace") return { value: {
479
- mutable: false,
480
- source: target.source,
481
- type: "namespace"
482
- } };
585
+ if (target.type === "ordinary-external") return {};
586
+ if (target.type === "external") return {
587
+ hasGTSourceReference: target.source === "gt-vue",
588
+ value: knownExport(target.source, target.exportName)
589
+ };
590
+ if (target.type === "external-namespace") return {
591
+ hasGTSourceReference: target.source === "gt-vue",
592
+ value: {
593
+ mutable: false,
594
+ source: target.source,
595
+ type: "namespace"
596
+ }
597
+ };
483
598
  if (target.type === "namespace") return { value: {
484
599
  type: "local-namespace",
485
600
  modulePath: target.modulePath
486
601
  } };
487
602
  attachLocalModule(target.record, state);
488
- if (target.type === "expression") return {
489
- callable: resolveCalledFunction(target.node, target.record.programScope, state, /* @__PURE__ */ new Set()),
490
- value: resolveKnownExpression(target.node, target.record.programScope, state, /* @__PURE__ */ new Set()),
491
- possibleGTComponent: expressionMayProduceComponent(target.node, target.record.programScope, state, /* @__PURE__ */ new Set(), "translation"),
492
- possibleStringFunction: expressionMayProduceStringFunction(target.node, target.record.programScope, state, /* @__PURE__ */ new Set())
493
- };
603
+ if (target.type === "expression") {
604
+ const materialized = {
605
+ callable: resolveCalledFunction(target.node, target.record.programScope, state, /* @__PURE__ */ new Set()),
606
+ value: resolveKnownExpression(target.node, target.record.programScope, state, /* @__PURE__ */ new Set()),
607
+ possibleGTComponent: expressionMayProduceComponent(target.node, target.record.programScope, state, /* @__PURE__ */ new Set(), "translation"),
608
+ possibleStringFunction: expressionMayProduceStringFunction(target.node, target.record.programScope, state, /* @__PURE__ */ new Set())
609
+ };
610
+ materialized.hasGTSourceReference = isKnownGTValue(materialized.value);
611
+ return materialized;
612
+ }
494
613
  const binding = target.record.programScope.getBinding(target.exportName);
495
614
  if (!binding) return {};
496
615
  const possibleGTComponent = expressionMayProduceComponent(binding.identifier, target.record.programScope, state, /* @__PURE__ */ new Set(), "translation");
@@ -500,15 +619,59 @@ function materializeLocalExport(target, state) {
500
619
  possibleStringFunction,
501
620
  unsafeCallable: bindingMayReferenceLocalCallable(binding, state)
502
621
  };
503
- return {
622
+ const materialized = {
504
623
  callable: resolveCalledFunction(binding.identifier, target.record.programScope, state, /* @__PURE__ */ new Set()),
505
624
  possibleGTComponent,
506
625
  possibleStringFunction,
507
626
  value: resolveKnownBinding(binding, state, /* @__PURE__ */ new Set())
508
627
  };
628
+ materialized.hasGTSourceReference = isKnownGTValue(materialized.value);
629
+ return materialized;
630
+ }
631
+ /** Returns whether an exact analyzer identity came from gt-vue. */
632
+ function isKnownGTValue(value) {
633
+ return value?.type === "component" || value?.type === "hook" || value?.type === "string" || value?.type === "namespace" && value.source === "gt-vue";
634
+ }
635
+ /** Materializes the one ordinary origin proven through a malformed module. */
636
+ function materializeRecoveredOrdinaryResolution(resolution, state, preserveLocalIdentity = false) {
637
+ if (resolution.hasGTSourceReference || resolution.gtExportName || resolution.recoveredTargets?.length !== 1) return;
638
+ const target = resolution.recoveredTargets[0];
639
+ if (target.type === "ordinary-external") return {};
640
+ if (target.type === "external" || target.type === "external-namespace") return target.source === "vue" ? materializeLocalExport(target, state) : void 0;
641
+ if (target.type === "namespace") return void 0;
642
+ const materialized = materializeLocalExport(target, state);
643
+ if (materialized.hasGTSourceReference || materialized.possibleGTComponent || materialized.possibleStringFunction || materialized.unsafeCallable || isKnownGTValue(materialized.value)) return;
644
+ if (localTargetAliasesKnownNonVueRuntime(target)) return materialized;
645
+ return preserveLocalIdentity && materialized.callable && isOrdinaryIdentityFunction(materialized.callable.node) ? materialized : void 0;
646
+ }
647
+ /** Proves a direct immutable alias back to an official non-Vue GT runtime. */
648
+ function localTargetAliasesKnownNonVueRuntime(target) {
649
+ if (target.type === "expression") return expressionAliasesKnownNonVueRuntime(target.node, target.record.programScope, /* @__PURE__ */ new Set());
650
+ const binding = target.record.programScope.getBinding(target.exportName);
651
+ if (!binding) return false;
652
+ const source = getBindingSource(binding);
653
+ if (!source || source.pattern.type !== "Identifier") return false;
654
+ return expressionAliasesKnownNonVueRuntime(source.expression.node, source.expression.scope, new Set([binding]));
655
+ }
656
+ /** Follows only immutable identifier aliases to named or default imports. */
657
+ function expressionAliasesKnownNonVueRuntime(node, scope, seen) {
658
+ const expression = unwrapExpression(node);
659
+ if (expression?.type !== "Identifier") return false;
660
+ const binding = scope.getBinding(expression.name);
661
+ if (!binding || seen.has(binding)) return false;
662
+ const declaration = binding.path.parentPath;
663
+ if (declaration?.isImportDeclaration() && isKnownNonVueGTRuntime(declaration.node.source.value)) return true;
664
+ const source = getBindingSource(binding);
665
+ return Boolean(source && source.pattern.type === "Identifier" && expressionAliasesKnownNonVueRuntime(source.expression.node, source.expression.scope, new Set(seen).add(binding)));
666
+ }
667
+ /** Proves the narrow local helper form without following unknown dependencies. */
668
+ function isOrdinaryIdentityFunction(node) {
669
+ if (node.async || node.generator || node.params.length !== 1 || node.params[0]?.type !== "Identifier") return false;
670
+ const expression = unwrapExpression(node.body.type === "BlockStatement" ? node.body.body.length === 1 && node.body.body[0]?.type === "ReturnStatement" ? node.body.body[0].argument : void 0 : node.body);
671
+ return expression?.type === "Identifier" && expression.name === node.params[0].name;
509
672
  }
510
673
  /** Makes statically known members of a local namespace visible to templates. */
511
- function recordLocalNamespaceMembers(localName, modulePath, state) {
674
+ function recordLocalNamespaceMembers(localName, modulePath, state, binding) {
512
675
  const resolver = state.analysis.localModules;
513
676
  if (!resolver) return;
514
677
  const exportNames = new Set([
@@ -523,8 +686,14 @@ function recordLocalNamespaceMembers(localName, modulePath, state) {
523
686
  const resolution = resolver.resolveExport(modulePath, exportName);
524
687
  if (resolution.status === "absent") continue;
525
688
  if (resolution.status !== "resolved") {
689
+ if (resolution.status === "invalid" && materializeRecoveredOrdinaryResolution(resolution, state) !== void 0) continue;
690
+ if (resolution.status === "invalid" && resolution.hasGTSourceReference && bindingReferencesNamespaceMember(binding, exportName, state)) {
691
+ state.analysis.hasGTSourceReference = true;
692
+ state.unsupportedMalformedGTReference = true;
693
+ }
526
694
  state.analysis.uncertainTranslationHelpers.add(memberPath);
527
695
  if (resolution.status === "ambiguous") recordAmbiguousLocalBinding(memberPath, state);
696
+ else if (resolution.status === "invalid" && resolution.hasGTSourceReference) recordInvalidGTResolution(memberPath, resolution, state);
528
697
  else recordUnresolvedGTShapedBinding(memberPath, exportName, state);
529
698
  continue;
530
699
  }
@@ -533,6 +702,31 @@ function recordLocalNamespaceMembers(localName, modulePath, state) {
533
702
  recordMaterializedLocalUncertainty(memberPath, materialized, state);
534
703
  }
535
704
  }
705
+ /** Retains the original gt-vue role hidden by a malformed re-export alias. */
706
+ function recordInvalidGTResolution(localName, resolution, state) {
707
+ if (resolution.gtExportName === "*") {
708
+ recordUnresolvedGTNamespace(localName, state);
709
+ return;
710
+ }
711
+ if (resolution.gtExportName) {
712
+ recordUnresolvedGTShapedBinding(localName, resolution.gtExportName, state);
713
+ return;
714
+ }
715
+ state.analysis.uncertainTranslationHelpers.add(localName);
716
+ }
717
+ /** Marks the GT-shaped members of one unresolved namespace path. */
718
+ function recordUnresolvedGTNamespace(localName, state) {
719
+ for (const component of COMPONENT_IMPORTS) {
720
+ const componentPath = appendTemplatePath(localName, component);
721
+ state.analysis.uncertainComponents.add(componentPath);
722
+ state.analysis.uncertainGTComponents.add(componentPath);
723
+ }
724
+ for (const name of [
725
+ "msg",
726
+ "useGT",
727
+ "useMessages"
728
+ ]) state.analysis.uncertainStringFunctions.add(appendTemplatePath(localName, name));
729
+ }
536
730
  /** Records unresolved roles only when a local export can actually be GT. */
537
731
  function recordMaterializedLocalUncertainty(localName, materialized, state, forceKnownValues = false) {
538
732
  if (materialized.possibleGTComponent || forceKnownValues && materialized.value?.type === "component") {
@@ -552,19 +746,10 @@ function bindingMayReferenceLocalCallable(binding, state) {
552
746
  function recordUnresolvedGTShapedImports(declaration, state) {
553
747
  for (const specifier of declaration.specifiers) {
554
748
  if (specifier.type === "ImportNamespaceSpecifier") {
555
- for (const component of COMPONENT_IMPORTS) {
556
- const path = appendTemplatePath(specifier.local.name, component);
557
- state.analysis.uncertainComponents.add(path);
558
- state.analysis.uncertainGTComponents.add(path);
559
- }
560
- for (const name of [
561
- "msg",
562
- "useGT",
563
- "useMessages"
564
- ]) state.analysis.uncertainStringFunctions.add(appendTemplatePath(specifier.local.name, name));
749
+ recordUnresolvedGTNamespace(specifier.local.name, state);
565
750
  continue;
566
751
  }
567
- if (specifier.type === "ImportSpecifier" && specifier.importKind === "type") continue;
752
+ if (specifier.type === "ImportSpecifier" && isTypeOnlyImportKind(specifier.importKind)) continue;
568
753
  const importedName = specifier.type === "ImportDefaultSpecifier" ? specifier.local.name : specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
569
754
  recordUnresolvedGTShapedBinding(specifier.local.name, importedName, state);
570
755
  }
@@ -572,7 +757,7 @@ function recordUnresolvedGTShapedImports(declaration, state) {
572
757
  /** Marks unresolved imports only when a call later passes a translator. */
573
758
  function recordUnresolvedTranslationHelperImports(declaration, scope, state) {
574
759
  for (const specifier of declaration.specifiers) {
575
- if (specifier.type === "ImportSpecifier" && specifier.importKind === "type") continue;
760
+ if (specifier.type === "ImportSpecifier" && isTypeOnlyImportKind(specifier.importKind)) continue;
576
761
  recordUncertainTranslationHelperBinding(specifier.local.name, scope, state);
577
762
  }
578
763
  }
@@ -4187,7 +4372,7 @@ function collectTransformArrayEntries(node, scope, state, seen, atPosition = nod
4187
4372
  ok: true,
4188
4373
  value: fallback
4189
4374
  };
4190
- const value = readStaticFromScope(node, scope, /* @__PURE__ */ new Set(), node.end ?? atPosition, state.analysis, true);
4375
+ const value = readStaticFromScope(node, scope, /* @__PURE__ */ new Set(), node.end ?? atPosition, state.analysis);
4191
4376
  if (!value.ok || typeof value.value === "bigint") return { ok: false };
4192
4377
  try {
4193
4378
  const numeric = Number(value.value);
@@ -4402,7 +4587,7 @@ function collectTransformArrayEntries(node, scope, state, seen, atPosition = nod
4402
4587
  let entries = collectTransformArrayEntries(callee.object, scope, state, nextSeen, atPosition);
4403
4588
  if (!entries) return void 0;
4404
4589
  const depthNode = argument(0);
4405
- const staticDepth = depthNode ? readStaticFromScope(depthNode, scope, /* @__PURE__ */ new Set(), depthNode.end ?? atPosition, state.analysis, true) : {
4590
+ const staticDepth = depthNode ? readStaticFromScope(depthNode, scope, /* @__PURE__ */ new Set(), depthNode.end ?? atPosition, state.analysis) : {
4406
4591
  ok: true,
4407
4592
  value: 1
4408
4593
  };
@@ -4640,35 +4825,24 @@ function memberChainCanMutate(memberPath, allowCalls) {
4640
4825
  }
4641
4826
  return true;
4642
4827
  }
4643
- function readStaticFromScope(node, scope, seen, atPosition, analysis, allowNumericGlobals = false) {
4828
+ function readStaticFromScope(node, scope, seen, atPosition, analysis) {
4644
4829
  return readStaticPrimitive(node, (identifier) => {
4645
4830
  const binding = scope.getBinding(identifier.name);
4646
4831
  if (!binding) {
4647
- const value = analysis?.staticValues.get(identifier.name);
4648
4832
  if (analysis?.staticValues.has(identifier.name)) return {
4649
4833
  ok: true,
4650
- value
4651
- };
4652
- if (allowNumericGlobals && identifier.name === "Infinity") return {
4653
- ok: true,
4654
- value: Number.POSITIVE_INFINITY
4834
+ value: analysis.staticValues.get(identifier.name)
4655
4835
  };
4656
- if (allowNumericGlobals && identifier.name === "NaN") return {
4657
- ok: true,
4658
- value: NaN
4659
- };
4660
- return { ok: false };
4836
+ return readStaticGlobalPrimitive(identifier.name);
4661
4837
  }
4662
4838
  const cacheable = analysis !== void 0 && atPosition === Number.POSITIVE_INFINITY;
4663
- const cached = cacheable ? staticBindingResults.get(analysis)?.get(binding)?.get(allowNumericGlobals) : void 0;
4839
+ const cached = cacheable ? staticBindingResults.get(analysis)?.get(binding) : void 0;
4664
4840
  if (cached) return cached;
4665
4841
  if (seen.has(binding)) return { ok: false };
4666
4842
  if (cacheable) {
4667
- const active = staticBindingsInProgress.get(analysis) ?? /* @__PURE__ */ new Map();
4668
- const modes = active.get(binding) ?? /* @__PURE__ */ new Set();
4669
- if (modes.has(allowNumericGlobals)) return { ok: false };
4670
- modes.add(allowNumericGlobals);
4671
- active.set(binding, modes);
4843
+ const active = staticBindingsInProgress.get(analysis) ?? /* @__PURE__ */ new Set();
4844
+ if (active.has(binding)) return { ok: false };
4845
+ active.add(binding);
4672
4846
  staticBindingsInProgress.set(analysis, active);
4673
4847
  }
4674
4848
  const nextSeen = new Set(seen);
@@ -4676,22 +4850,15 @@ function readStaticFromScope(node, scope, seen, atPosition, analysis, allowNumer
4676
4850
  try {
4677
4851
  const source = getBindingSource(binding);
4678
4852
  const expression = source && (source.expression.node.end ?? 0) <= atPosition ? selectPatternExpression(source.pattern, source.expression.node, binding.identifier.name, source.expression.scope, source.expression.node.end ?? Number.POSITIVE_INFINITY) : void 0;
4679
- const result = expression ? readStaticFromScope(expression.node, expression.scope, nextSeen, atPosition, analysis, allowNumericGlobals) : { ok: false };
4853
+ const result = expression ? readStaticFromScope(expression.node, expression.scope, nextSeen, atPosition, analysis) : { ok: false };
4680
4854
  if (cacheable) {
4681
4855
  const results = staticBindingResults.get(analysis) ?? /* @__PURE__ */ new Map();
4682
- const modes = results.get(binding) ?? /* @__PURE__ */ new Map();
4683
- modes.set(allowNumericGlobals, result);
4684
- results.set(binding, modes);
4856
+ results.set(binding, result);
4685
4857
  staticBindingResults.set(analysis, results);
4686
4858
  }
4687
4859
  return result;
4688
4860
  } finally {
4689
- if (cacheable) {
4690
- const active = staticBindingsInProgress.get(analysis);
4691
- const modes = active?.get(binding);
4692
- modes?.delete(allowNumericGlobals);
4693
- if (modes?.size === 0) active?.delete(binding);
4694
- }
4861
+ if (cacheable) staticBindingsInProgress.get(analysis)?.delete(binding);
4695
4862
  }
4696
4863
  });
4697
4864
  }