@generaltranslation/vue-extractor 0.1.0-iris.0 → 0.1.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.
- package/dist/internal/extractFromVueSource.js +8 -1
- package/dist/internal/extractFromVueSource.js.map +1 -1
- package/dist/internal/script/analyze.js +76 -28
- package/dist/internal/script/analyze.js.map +1 -1
- package/dist/internal/script/knownValues.js +4 -0
- package/dist/internal/script/knownValues.js.map +1 -1
- package/dist/internal/script/localModules.js +2 -0
- package/dist/internal/script/localModules.js.map +1 -1
- package/dist/internal/script/model.d.ts +1 -1
- package/dist/internal/script/runtimeModules.d.ts +1 -1
- package/dist/internal/script/runtimeModules.js +1 -1
- package/dist/internal/script/runtimeModules.js.map +1 -1
- package/dist/internal/stringCalls.js +8 -2
- package/dist/internal/stringCalls.js.map +1 -1
- package/dist/internal/template.js +1 -1
- package/dist/internal/template.js.map +1 -1
- package/dist/internal/types.d.ts +1 -1
- package/package.json +3 -3
|
@@ -223,7 +223,14 @@ function malformedSuffixHasGTProvenance(sourceCode, filePath, options, language,
|
|
|
223
223
|
}
|
|
224
224
|
/** Removes block closers orphaned when recovery starts inside a function. */
|
|
225
225
|
function trimTrailingRecoveryClosers(sourceCode) {
|
|
226
|
-
|
|
226
|
+
let end = sourceCode.length;
|
|
227
|
+
while (end > 0 && sourceCode[end - 1].trim() === "") end -= 1;
|
|
228
|
+
if (sourceCode[end - 1] !== "}") return sourceCode.slice(0, end);
|
|
229
|
+
do {
|
|
230
|
+
end -= 1;
|
|
231
|
+
while (end > 0 && sourceCode[end - 1].trim() === "") end -= 1;
|
|
232
|
+
} while (sourceCode[end - 1] === "}");
|
|
233
|
+
return sourceCode.slice(0, end);
|
|
227
234
|
}
|
|
228
235
|
/** Chooses the grammar that parsed furthest before a recoverable error. */
|
|
229
236
|
function selectMalformedSuffixLanguage(sourceCode, languages) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractFromVueSource.js","names":["initModuleLexer","parseModuleImports"],"sources":["../../src/internal/extractFromVueSource.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport {\n init as initModuleLexer,\n parse as parseModuleImports,\n} from 'es-module-lexer';\nimport type { ParserPlugin } from '@babel/parser';\nimport type { SFCBlock, TemplateCompiler } from '#vue-compiler-sfc';\nimport type { RootNode } from '@vue/compiler-dom';\nimport type {\n VueCompilerOptions,\n VueExtractionOptions,\n VueExtractionOutput,\n} from '../types.js';\nimport {\n collectVueScriptImports,\n createVueScriptAnalysis,\n exposeVueScriptImportsToTemplate,\n parseVueScript,\n type VueScriptAnalysis,\n} from './script.js';\nimport { parseScriptAst } from './script/parser.js';\nimport {\n shiftCompilerAstLocations,\n shiftCompilerLocation,\n} from './compilerAst.js';\nimport {\n createLocalModuleResolver,\n type LocalModuleResolver,\n} from './script/localModules.js';\nimport { parseVueTemplate } from './template.js';\nimport type { TemplateBindings, VueExtractionContext } from './types.js';\nimport { addVueError, createVueExtractionContext } from './utils.js';\nimport {\n inspectVueCompiler,\n resolveVueCompiler,\n type ResolvedVueCompiler,\n} from './vueCompiler.js';\n\nconst DEFAULT_SURROUNDING_LINE_COUNT = 5;\nconst MAX_MALFORMED_SUFFIX_RECOVERIES = 64;\n\n/** Parser options supported at runtime but omitted from Vue 3.3 declarations. */\ntype CompatibleTemplateParserOptions = NonNullable<\n Parameters<TemplateCompiler['parse']>[1]\n> & {\n expressionPlugins?: ParserPlugin[];\n};\n\n/** compiler-dom options supported at runtime across the supported Vue range. */\ntype CompatibleCompilerDomParserOptions = NonNullable<\n Parameters<NonNullable<ResolvedVueCompiler['parseTemplate']>>[1]\n> & {\n expressionPlugins?: ParserPlugin[];\n};\n\n/**\n * Extracts General Translation content from one Vue SFC or JavaScript file.\n *\n * This low-level API lets callers parse an individual in-memory source file.\n * Use `@generaltranslation/vue-extractor/project` when discovery, I/O,\n * compiler configuration, hashing, and deduplication should be handled by the\n * package as one project-level operation.\n */\nexport async function extractFromVueSource(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions = {}\n): Promise<VueExtractionOutput> {\n const results: VueExtractionOutput['results'] = [];\n const errors: string[] = [];\n const warnings = new Set<string>();\n const context = createVueExtractionContext(\n filePath,\n sourceCode,\n options.projectRoot ?? process.cwd(),\n options.includeSourceCodeContext ?? false,\n options.surroundingLineCount ?? DEFAULT_SURROUNDING_LINE_COUNT,\n results,\n errors,\n warnings\n );\n const extension = extname(filePath).toLowerCase();\n const scriptAnalysis = createVueScriptAnalysis();\n scriptAnalysis.entryFile = filePath;\n scriptAnalysis.localModules = createLocalModuleResolver(\n options.resolveModule\n );\n\n if (extension === '.vue') {\n const compilerResolution =\n options.compiler !== undefined\n ? inspectVueCompiler(options.compiler)\n : resolveVueCompiler(filePath, options.projectRoot ?? process.cwd());\n if (!compilerResolution.ok) {\n addVueError(\n context,\n undefined,\n 'Could not load the Vue compiler used by this single-file component',\n `Install a supported Vue 3 compiler beside the app. ${compilerResolution.details}`\n );\n return { results, errors, warnings: [...warnings] };\n }\n context.implicitSlotWhitespace =\n compilerResolution.value.implicitSlotWhitespace;\n context.valuedVIsReplacesElement =\n compilerResolution.value.valuedVIsReplacesElement;\n parseVueSingleFileComponent(\n sourceCode,\n context,\n options.compilerOptions ?? {},\n compilerResolution.value,\n scriptAnalysis\n );\n } else {\n if (\n options.requireGTProvenance &&\n !(await hasStandaloneGTProvenance(sourceCode, filePath, options))\n ) {\n return { results, errors, warnings: [...warnings] };\n }\n parseVueScript(\n sourceCode,\n languageFromExtension(extension),\n context,\n createTemplateBindings(),\n false,\n scriptAnalysis,\n false\n );\n }\n\n return { results, errors, warnings: [...warnings] };\n}\n\n/**\n * Uses the declared language, then permissive TSX and Flow, to prove gt-vue\n * ownership without changing the grammar used for extraction.\n *\n * The normal extraction pass still parses the file according to its extension.\n * Diagnostics caused only by GT-shaped names do not establish ownership. This\n * keeps mixed-framework dispatch from making otherwise valid React files fatal.\n */\nasync function hasStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions\n): Promise<boolean> {\n const extension = extname(filePath).toLowerCase();\n const probeLanguages = new Set<StandaloneProbeLanguage>([\n languageFromExtension(extension),\n 'tsx',\n 'flow',\n ]);\n const localModules = createLocalModuleResolver(options.resolveModule);\n for (const language of probeLanguages) {\n const probe = probeStandaloneGTProvenance(\n sourceCode,\n filePath,\n options,\n language,\n localModules\n );\n if (probe.hasProvenance) return true;\n if (probe.parsed) return false;\n }\n const suffixSelection = selectMalformedSuffixLanguage(\n sourceCode,\n probeLanguages\n );\n const moduleRecovery = suffixSelection?.recoverable\n ? await recoverMalformedModuleReferences(\n sourceCode,\n filePath,\n options,\n probeLanguages,\n localModules\n )\n : { hasProvenance: false, preamble: '' };\n if (moduleRecovery.hasProvenance) {\n return true;\n }\n return hasMalformedStandaloneGTProvenance(\n sourceCode,\n filePath,\n options,\n probeLanguages,\n localModules,\n moduleRecovery.preamble\n );\n}\n\n/**\n * Recovers static module ownership without reparsing an entire malformed file.\n *\n * es-module-lexer ignores comments and literal contents while continuing past\n * unrelated syntax errors. Each declaration is then analyzed on its own,\n * preserving type-only and binding-specific local-barrel semantics. Parseable\n * declarations are also returned as a preamble for later recovered uses.\n */\nasync function recoverMalformedModuleReferences(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n languages: ReadonlySet<StandaloneProbeLanguage>,\n localModules: LocalModuleResolver\n): Promise<{ hasProvenance: boolean; preamble: string }> {\n await initModuleLexer;\n let imports: ReturnType<typeof parseModuleImports>[0];\n try {\n [imports] = parseModuleImports(sourceCode);\n } catch {\n imports = [];\n }\n\n const declarations = new Set<string>();\n for (const moduleImport of imports) {\n if (!moduleImport.n) continue;\n for (const declaration of readModuleStatementCandidates(\n sourceCode,\n moduleImport.ss,\n moduleImport.se\n )) {\n for (const language of languages) {\n const probe = probeStandaloneGTProvenance(\n declaration,\n filePath,\n options,\n language,\n localModules\n );\n if (probe.hasProvenance) {\n return { hasProvenance: true, preamble: '' };\n }\n if (probe.parsed) {\n declarations.add(declaration);\n break;\n }\n }\n if (declarations.has(declaration)) break;\n }\n }\n return {\n hasProvenance: false,\n preamble: [...declarations].join('\\n'),\n };\n}\n\n/** Returns small statement slices enclosing one lexed module reference. */\nfunction readModuleStatementCandidates(\n sourceCode: string,\n statementStart: number,\n specifierEnd: number\n): string[] {\n const precedingBoundaries = [';', '\\n', '{', '}']\n .map((separator) => sourceCode.lastIndexOf(separator, statementStart - 1))\n .filter((offset) => offset >= 0)\n .map((offset) => offset + 1);\n precedingBoundaries.push(0);\n const followingBoundaries = [';', '\\n', '}']\n .map((separator) => sourceCode.indexOf(separator, specifierEnd))\n .filter((offset) => offset >= 0)\n .map((offset) => offset + 1);\n const starts = [\n ...precedingBoundaries.sort((left, right) => right - left),\n statementStart,\n ];\n const ends = [\n ...followingBoundaries.sort((left, right) => left - right),\n specifierEnd,\n ];\n const candidates = new Set<string>();\n for (const start of starts) {\n for (const end of ends) {\n if (end <= start) continue;\n const candidate = sourceCode.slice(start, end).trim();\n if (candidate) candidates.add(candidate);\n }\n }\n return [...candidates];\n}\n\ntype StandaloneProbeLanguage = 'flow' | 'js' | 'jsx' | 'ts' | 'tsx';\n\n/** Runs one syntax-tolerant, read-only provenance classification pass. */\nfunction probeStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver\n): { hasProvenance: boolean; parsed: boolean } {\n const results: VueExtractionOutput['results'] = [];\n const errors: string[] = [];\n const warnings = new Set<string>();\n const projectRoot = options.projectRoot ?? process.cwd();\n const context = createVueExtractionContext(\n filePath,\n sourceCode,\n projectRoot,\n false,\n options.surroundingLineCount ?? DEFAULT_SURROUNDING_LINE_COUNT,\n results,\n errors,\n warnings\n );\n const analysis = createVueScriptAnalysis();\n analysis.entryFile = filePath;\n analysis.localModules = localModules;\n const parsed = parseVueScript(\n sourceCode,\n language,\n context,\n createTemplateBindings(),\n false,\n analysis,\n false\n );\n if (results.length > 0 || analysisHasGTProvenance(analysis)) {\n return { hasProvenance: true, parsed };\n }\n return { hasProvenance: false, parsed };\n}\n\n/**\n * Finds concrete module references when malformed syntax prevents a full AST.\n *\n * Each supported grammar recovers a complete prefix, then the grammar that\n * parsed furthest gets a bounded suffix search. Unterminated literal errors\n * never receive suffix recovery, so literal contents cannot become code.\n */\nfunction hasMalformedStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n languages: ReadonlySet<StandaloneProbeLanguage>,\n localModules: LocalModuleResolver,\n recoveredPreamble: string\n): boolean {\n for (const language of languages) {\n if (\n leadingStatementPrefixHasGTProvenance(\n sourceCode,\n filePath,\n options,\n language,\n localModules\n )\n ) {\n return true;\n }\n }\n const suffixSelection = selectMalformedSuffixLanguage(sourceCode, languages);\n return Boolean(\n suffixSelection?.recoverable &&\n malformedSuffixHasGTProvenance(\n sourceCode,\n filePath,\n options,\n suffixSelection.language,\n localModules,\n recoveredPreamble\n )\n );\n}\n\n/** Preserves CommonJS and TypeScript import ownership before a syntax error. */\nfunction leadingStatementPrefixHasGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver\n): boolean {\n let errorOffset: number;\n try {\n parseScriptAst(sourceCode, language);\n return false;\n } catch (error) {\n const offset = (error as { pos?: unknown }).pos;\n if (typeof offset !== 'number') return false;\n errorOffset = offset;\n }\n const boundary = Math.max(\n sourceCode.lastIndexOf(';', errorOffset - 1) + 1,\n sourceCode.lastIndexOf('\\n', errorOffset - 1) + 1,\n sourceCode.lastIndexOf('}', errorOffset - 1) + 1\n );\n if (boundary <= 0) return false;\n const prefix = sourceCode.slice(0, boundary).trimEnd();\n if (!prefix) return false;\n const probe = probeStandaloneGTProvenance(\n prefix,\n filePath,\n options,\n language,\n localModules\n );\n return probe.hasProvenance;\n}\n\n/** Recovers later imports and CommonJS calls after a bounded number of errors. */\nfunction malformedSuffixHasGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver,\n recoveredPreamble: string\n): boolean {\n let remaining = sourceCode;\n for (let attempt = 0; attempt < MAX_MALFORMED_SUFFIX_RECOVERIES; attempt++) {\n let errorOffset: number;\n try {\n parseScriptAst(remaining, language);\n const recoveredSource = recoveredPreamble\n ? `${recoveredPreamble}\\n${remaining}`\n : remaining;\n const recoveredProbe = probeStandaloneGTProvenance(\n recoveredSource,\n filePath,\n options,\n language,\n localModules\n );\n if (recoveredProbe.parsed) return recoveredProbe.hasProvenance;\n // The remaining suffix may already contain the declaration retained in\n // the preamble. Probe it alone to avoid a duplicate-binding parse error.\n return probeStandaloneGTProvenance(\n remaining,\n filePath,\n options,\n language,\n localModules\n ).hasProvenance;\n } catch (error) {\n const parseError = readRecoverableParseError(error);\n if (!parseError) return false;\n errorOffset = parseError.offset;\n }\n const boundary = findMalformedRecoveryBoundary(remaining, errorOffset);\n if (boundary <= 0 || boundary >= remaining.length) return false;\n remaining = remaining.slice(boundary);\n const recoveredSource = recoveredPreamble\n ? `${recoveredPreamble}\\n${remaining}`\n : remaining;\n let probe = probeStandaloneGTProvenance(\n recoveredSource,\n filePath,\n options,\n language,\n localModules\n );\n if (!probe.parsed && recoveredPreamble) {\n const trimmedRemaining = trimTrailingRecoveryClosers(remaining);\n if (trimmedRemaining !== remaining) {\n probe = probeStandaloneGTProvenance(\n `${recoveredPreamble}\\n${trimmedRemaining}`,\n filePath,\n options,\n language,\n localModules\n );\n }\n }\n if (probe.hasProvenance) return true;\n if (probe.parsed) return false;\n }\n return false;\n}\n\n/** Removes block closers orphaned when recovery starts inside a function. */\nfunction trimTrailingRecoveryClosers(sourceCode: string): string {\n return sourceCode.replace(/(?:\\s*\\}\\s*)+$/u, '').trimEnd();\n}\n\n/** Chooses the grammar that parsed furthest before a recoverable error. */\nfunction selectMalformedSuffixLanguage(\n sourceCode: string,\n languages: ReadonlySet<StandaloneProbeLanguage>\n): { language: StandaloneProbeLanguage; recoverable: boolean } | undefined {\n let selected:\n | { language: StandaloneProbeLanguage; recoverable: boolean }\n | undefined;\n let furthestOffset = -1;\n for (const language of languages) {\n try {\n parseScriptAst(sourceCode, language);\n } catch (error) {\n const parseError = readParseError(error);\n if (parseError && parseError.offset > furthestOffset) {\n selected = {\n language,\n recoverable: parseError.recoverable,\n };\n furthestOffset = parseError.offset;\n }\n }\n }\n return selected;\n}\n\n/** Rejects recovery that could reinterpret unterminated literal contents. */\nfunction readRecoverableParseError(\n error: unknown\n): { offset: number } | undefined {\n const parsed = readParseError(error);\n return parsed?.recoverable ? { offset: parsed.offset } : undefined;\n}\n\n/** Reads one Babel parser error without trusting unterminated literal state. */\nfunction readParseError(\n error: unknown\n): { offset: number; recoverable: boolean } | undefined {\n const parsed = error as { pos?: unknown; reasonCode?: unknown };\n if (typeof parsed.pos !== 'number') return undefined;\n const unsafeReasonCodes = new Set([\n 'UnterminatedComment',\n 'UnterminatedJsxContent',\n 'UnterminatedRegExp',\n 'UnterminatedString',\n 'UnterminatedTemplate',\n ]);\n return {\n offset: parsed.pos,\n recoverable:\n typeof parsed.reasonCode !== 'string' ||\n !unsafeReasonCodes.has(parsed.reasonCode),\n };\n}\n\n/** Selects the first statement-like boundary after a parser error. */\nfunction findMalformedRecoveryBoundary(\n sourceCode: string,\n errorOffset: number\n): number {\n const candidates = [';', '\\n', '}']\n .map((separator) => sourceCode.indexOf(separator, errorOffset))\n .filter((offset) => offset >= 0);\n return candidates.length > 0 ? Math.min(...candidates) + 1 : -1;\n}\n\n/** Returns whether permissive analysis reached a concrete gt-vue identity. */\nfunction analysisHasGTProvenance(analysis: VueScriptAnalysis): boolean {\n return analysis.hasGTSourceReference;\n}\n\nfunction parseVueSingleFileComponent(\n source: string,\n context: VueExtractionContext,\n compilerOptions: VueCompilerOptions,\n resolvedCompiler: ResolvedVueCompiler,\n scriptAnalysis: VueScriptAnalysis\n): void {\n const { compiler } = resolvedCompiler;\n if (\n compilerOptions.delimiters &&\n !resolvedCompiler.templateCompiler &&\n !resolvedCompiler.templateParseOptionsSupported\n ) {\n addVueError(\n context,\n undefined,\n 'Could not safely apply custom Vue template delimiters with the supplied compiler',\n 'Let the extractor resolve the consuming app compiler, or supply a Vue compiler that applies templateParseOptions during SFC parsing'\n );\n return;\n }\n const expressionPlugins: ParserPlugin[] = sourceUsesTypeScript(source)\n ? ['typescript']\n : [];\n const templateCompiler = createConfiguredTemplateCompiler(\n resolvedCompiler,\n compilerOptions,\n expressionPlugins,\n true\n );\n const result = compiler.parse(source, {\n ...(templateCompiler && { compiler: templateCompiler }),\n filename: context.file,\n pad: 'space',\n sourceMap: false,\n templateParseOptions: {\n ...compilerOptions,\n comments: true,\n expressionPlugins,\n },\n });\n\n for (const error of result.errors) {\n const compilerError =\n typeof error === 'string'\n ? undefined\n : (error as SyntaxError & {\n loc?: Parameters<typeof normalizeCompilerLocation>[0];\n });\n addVueError(\n context,\n compilerError?.loc\n ? normalizeCompilerLocation(compilerError.loc)\n : undefined,\n `Could not parse a gt-vue single-file component: ${typeof error === 'string' ? error : error.message}`,\n 'Fix the Vue template syntax before extracting translations'\n );\n }\n // Vue's SFC parser recovers a partial AST for malformed markup. Publishing\n // translations from that recovery tree can replace complete catalogs with\n // an incomplete source set, so structural parse errors are file-fatal.\n if (result.errors.length > 0) return;\n\n const bindings = createTemplateBindings();\n collectScriptBlockImports(result.descriptor.script, scriptAnalysis);\n collectScriptBlockImports(result.descriptor.scriptSetup, scriptAnalysis);\n const scriptValid = parseScriptBlock(\n result.descriptor.script,\n false,\n context,\n bindings,\n scriptAnalysis\n );\n if (result.descriptor.scriptSetup) {\n exposeVueScriptImportsToTemplate(scriptAnalysis, bindings);\n }\n const scriptSetupValid = parseScriptBlock(\n result.descriptor.scriptSetup,\n true,\n context,\n bindings,\n scriptAnalysis\n );\n if (!scriptValid || !scriptSetupValid) {\n context.results.length = 0;\n return;\n }\n\n const template = result.descriptor.template;\n if (!template) return;\n if (template.lang && template.lang !== 'html') {\n addVueError(\n context,\n template.loc,\n `Found unsupported Vue template language \"${template.lang}\"`,\n 'Use a standard HTML Vue template for gt-vue extraction'\n );\n context.results.length = 0;\n return;\n }\n if (template.src) {\n addVueError(\n context,\n template.loc,\n 'Found an externally sourced Vue template',\n 'Keep the template in the .vue file so gt-vue can extract it'\n );\n context.results.length = 0;\n return;\n }\n const templateAst = resolvedCompiler.parseTemplate\n ? parseTemplateWithCompiler(\n template.content,\n compilerOptions,\n expressionPlugins,\n true,\n context,\n resolvedCompiler.parseTemplate,\n template.loc.start\n )\n : (template.ast as unknown as RootNode);\n if (templateAst) {\n const templateResultStart = context.results.length;\n const templateErrorStart = context.errors.length;\n parseVueTemplate(templateAst, bindings, expressionPlugins, context);\n if (\n context.errors.length === templateErrorStart &&\n template.content.includes('<!--') &&\n !matchesProductionTemplate(\n source,\n compilerOptions,\n expressionPlugins,\n bindings,\n context,\n templateResultStart,\n resolvedCompiler\n )\n ) {\n context.results.length = templateResultStart;\n addVueError(\n context,\n template.loc,\n 'Found translatable Vue content whose hash changes between development and production',\n 'Remove comments that split translatable text or whitespace, or move those comments outside gt-vue <T> components'\n );\n }\n }\n}\n\n/**\n * Verifies that Vite's production comment stripping preserves extracted data.\n *\n * Vue parses templates with comments in development and without them in\n * production. Removing a comment can renormalize adjacent whitespace, so a\n * single persisted catalog key cannot serve both builds. The second parse is\n * limited to templates that contain comments and never executes project code.\n */\nfunction matchesProductionTemplate(\n source: string,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n bindings: TemplateBindings,\n context: VueExtractionContext,\n developmentResultStart: number,\n resolvedCompiler: ResolvedVueCompiler\n): boolean {\n const { compiler } = resolvedCompiler;\n const templateCompiler = createConfiguredTemplateCompiler(\n resolvedCompiler,\n compilerOptions,\n expressionPlugins,\n false\n );\n const production = compiler.parse(source, {\n ...(templateCompiler && { compiler: templateCompiler }),\n filename: context.file,\n pad: 'space',\n sourceMap: false,\n templateParseOptions: {\n ...compilerOptions,\n comments: false,\n expressionPlugins,\n },\n });\n const template = production.descriptor.template;\n if (production.errors.length > 0 || !template) return false;\n\n const productionContext: VueExtractionContext = {\n ...context,\n errors: [],\n results: [],\n warnings: new Set(),\n };\n const templateAst = resolvedCompiler.parseTemplate\n ? parseTemplateWithCompiler(\n template.content,\n compilerOptions,\n expressionPlugins,\n false,\n productionContext,\n resolvedCompiler.parseTemplate,\n template.loc.start\n )\n : (template.ast as unknown as RootNode);\n if (!templateAst) return false;\n parseVueTemplate(templateAst, bindings, expressionPlugins, productionContext);\n if (productionContext.errors.length > 0) return false;\n\n const developmentResults = context.results.slice(developmentResultStart);\n return (\n comparableTemplateResults(developmentResults) ===\n comparableTemplateResults(productionContext.results)\n );\n}\n\n/**\n * Applies hash-affecting options during compiler-sfc's structural parse.\n *\n * Vue 3.3 ignores `templateParseOptions`, which can make delimiter-shaped text\n * close an SFC block before the exact template-content parse runs. Supplying\n * the adjacent compiler-dom parser makes the descriptor structural parse use\n * the same delimiters and whitespace. Vue 3.3 caches SFC parses using the\n * parser function's string form, so its deterministic identity includes every\n * closure-captured option to prevent cross-option cache poisoning.\n */\nfunction createConfiguredTemplateCompiler(\n resolvedCompiler: ResolvedVueCompiler,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n comments: boolean\n): TemplateCompiler | undefined {\n const templateCompiler = resolvedCompiler.templateCompiler;\n if (!templateCompiler) return undefined;\n\n const parse: TemplateCompiler['parse'] = (source, baseOptions) => {\n const options: CompatibleTemplateParserOptions = {\n ...baseOptions,\n ...compilerOptions,\n comments,\n expressionPlugins,\n };\n return templateCompiler.parse(source, options);\n };\n const identity = JSON.stringify({\n comments,\n delimiters: compilerOptions.delimiters,\n expressionPlugins,\n version: resolvedCompiler.version,\n whitespace: compilerOptions.whitespace,\n });\n Object.defineProperty(parse, 'toString', {\n value: () => `gtVueTemplateParse:${identity}`,\n });\n\n return { compile: templateCompiler.compile, parse };\n}\n\n/** Parses template content with the exact compiler-dom beside consumer Vue. */\nfunction parseTemplateWithCompiler(\n source: string,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n comments: boolean,\n context: VueExtractionContext,\n parseTemplate: NonNullable<ResolvedVueCompiler['parseTemplate']>,\n origin: CompilerPosition\n): RootNode | undefined {\n const errors: Array<SyntaxError & { loc?: ExtractionLocationLike }> = [];\n const options: CompatibleCompilerDomParserOptions = {\n ...compilerOptions,\n comments,\n expressionPlugins,\n onError(error) {\n errors.push(error as SyntaxError & { loc?: ExtractionLocationLike });\n },\n };\n const ast = parseTemplate(source, options);\n if (errors.length === 0) {\n shiftCompilerAstLocations(ast, origin);\n return ast;\n }\n const shiftedErrorPositions = new WeakSet<object>();\n for (const error of errors) {\n if (error.loc) {\n shiftCompilerLocation(error.loc, origin, shiftedErrorPositions);\n }\n addVueError(\n context,\n error.loc ? normalizeCompilerLocation(error.loc) : undefined,\n `Could not parse a gt-vue template: ${error.message}`,\n 'Fix the Vue template syntax before extracting translations'\n );\n }\n return undefined;\n}\n\ntype ExtractionLocationLike = Parameters<typeof normalizeCompilerLocation>[0];\ntype CompilerPosition = {\n column: number;\n line: number;\n offset: number;\n};\n\n/** Omits location-only metadata while comparing persisted template content. */\nfunction comparableTemplateResults(\n results: VueExtractionOutput['results']\n): string {\n return JSON.stringify(\n results.map((result) => ({\n dataFormat: result.dataFormat,\n metadata: {\n context: result.metadata.context,\n id: result.metadata.id,\n maxChars: result.metadata.maxChars,\n requiresReview: result.metadata.requiresReview,\n },\n source: result.source,\n }))\n );\n}\n\nfunction collectScriptBlockImports(\n block: SFCBlock | null,\n scriptAnalysis: VueScriptAnalysis\n): void {\n if (!block || block.src || !isSupportedScriptLanguage(block.lang)) return;\n collectVueScriptImports(block.content, block.lang, scriptAnalysis);\n}\n\nfunction parseScriptBlock(\n block: SFCBlock | null,\n exposeToTemplate: boolean,\n context: VueExtractionContext,\n bindings: TemplateBindings,\n scriptAnalysis: VueScriptAnalysis\n): boolean {\n if (!block) return true;\n if (block.src) {\n addVueError(\n context,\n block.loc,\n 'Found an externally sourced Vue script block',\n 'Keep translation calls and gt-vue imports in the .vue file'\n );\n return false;\n }\n if (!isSupportedScriptLanguage(block.lang)) {\n addVueError(\n context,\n block.loc,\n `Found unsupported Vue script language \"${block.lang}\"`,\n 'Use JavaScript or TypeScript for gt-vue extraction'\n );\n return false;\n }\n\n return parseVueScript(\n block.content,\n block.lang,\n context,\n bindings,\n exposeToTemplate,\n scriptAnalysis\n );\n}\n\nfunction createTemplateBindings(): TemplateBindings {\n return {\n arrayLengths: new Map(),\n componentFactories: new Set(),\n components: new Map(),\n containerKinds: new Map(),\n possibleGTContainers: new Set(),\n gtContainerFactories: new Set(),\n directBindings: new Set(),\n registeredComponents: new Map(),\n registeredVueBuiltins: new Map(),\n staticValues: new Map(),\n identityFunctions: new Set(),\n possibleStaticStrings: new Map(),\n stringFunctions: new Map(),\n uncertainStringFunctions: new Set(),\n uncertainComponents: new Set(),\n uncertainGTComponents: new Set(),\n gtComponentFactories: new Set(),\n uncertainRegisteredComponents: new Set(),\n uncertainRegisteredGTComponents: new Set(),\n vueBuiltins: new Map(),\n };\n}\n\nfunction sourceUsesTypeScript(source: string): boolean {\n let offset = 0;\n while (offset < source.length) {\n const start = source.indexOf('<script', offset);\n if (start === -1) return false;\n const boundary = source[start + '<script'.length];\n if (boundary !== '>' && !boundary?.match(/\\s/)) {\n offset = start + '<script'.length;\n continue;\n }\n\n const end = findOpeningTagEnd(source, start + '<script'.length);\n if (end === -1) return false;\n const language = readOpeningTagAttribute(\n source.slice(start + '<script'.length, end),\n 'lang'\n );\n if (typeof language === 'string' && /^tsx?$/i.test(language)) return true;\n offset = end + 1;\n }\n return false;\n}\n\nfunction isSupportedScriptLanguage(language: string | undefined): boolean {\n const normalizedLanguage = language?.toLowerCase();\n return (\n normalizedLanguage === undefined ||\n normalizedLanguage === 'js' ||\n normalizedLanguage === 'jsx' ||\n normalizedLanguage === 'ts' ||\n normalizedLanguage === 'tsx'\n );\n}\n\n/** Finds an opening tag boundary while respecting quoted attribute values. */\nfunction findOpeningTagEnd(source: string, start: number): number {\n let quote: '\"' | \"'\" | undefined;\n for (let index = start; index < source.length; index += 1) {\n const character = source[index];\n if (quote) {\n if (character === quote) quote = undefined;\n } else if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '>') {\n return index;\n }\n }\n return -1;\n}\n\n/** Reads one case-sensitive SFC attribute with quoted or unquoted syntax. */\nfunction readOpeningTagAttribute(\n attributes: string,\n requestedName: string\n): string | true | undefined {\n let offset = 0;\n while (offset < attributes.length) {\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n if (attributes[offset] === '/') {\n offset += 1;\n continue;\n }\n const nameStart = offset;\n while (offset < attributes.length && !/[\\s=]/.test(attributes[offset])) {\n offset += 1;\n }\n const name = attributes.slice(nameStart, offset);\n if (!name) break;\n\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n let value: string | true = true;\n if (attributes[offset] === '=') {\n offset += 1;\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n const quote = attributes[offset];\n if (quote === '\"' || quote === \"'\") {\n offset += 1;\n const valueStart = offset;\n while (offset < attributes.length && attributes[offset] !== quote) {\n offset += 1;\n }\n value = attributes.slice(valueStart, offset);\n if (attributes[offset] === quote) offset += 1;\n } else {\n const valueStart = offset;\n while (offset < attributes.length && !/\\s/.test(attributes[offset])) {\n offset += 1;\n }\n value = attributes.slice(valueStart, offset);\n }\n }\n if (name === requestedName) return value;\n }\n return undefined;\n}\n\nfunction languageFromExtension(\n extension: string\n): Exclude<StandaloneProbeLanguage, 'flow'> {\n if (extension === '.ts' || extension === '.mts' || extension === '.cts') {\n return 'ts';\n }\n if (extension === '.tsx') return 'tsx';\n if (extension === '.jsx') return 'jsx';\n return 'js';\n}\n\nfunction normalizeCompilerLocation(location: {\n end?: { column?: number; line?: number; offset?: number };\n start?: { column?: number; line?: number; offset?: number };\n}) {\n const start = location.start ?? {};\n const end = location.end ?? start;\n return {\n start: {\n column: start.column ?? 1,\n line: start.line ?? 1,\n offset: start.offset ?? 0,\n },\n end: {\n column: end.column ?? start.column ?? 1,\n line: end.line ?? start.line ?? 1,\n offset: end.offset ?? start.offset ?? 0,\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAsCA,MAAM,iCAAiC;AACvC,MAAM,kCAAkC;;;;;;;;;AAwBxC,eAAsB,qBACpB,YACA,UACA,UAAgC,EAAE,EACJ;CAC9B,MAAM,UAA0C,EAAE;CAClD,MAAM,SAAmB,EAAE;CAC3B,MAAM,2BAAW,IAAI,KAAa;CAClC,MAAM,UAAU,2BACd,UACA,YACA,QAAQ,eAAe,QAAQ,KAAK,EACpC,QAAQ,4BAA4B,OACpC,QAAQ,wBAAwB,gCAChC,SACA,QACA,SACD;CACD,MAAM,YAAY,QAAQ,SAAS,CAAC,aAAa;CACjD,MAAM,iBAAiB,yBAAyB;AAChD,gBAAe,YAAY;AAC3B,gBAAe,eAAe,0BAC5B,QAAQ,cACT;AAED,KAAI,cAAc,QAAQ;EACxB,MAAM,qBACJ,QAAQ,aAAa,KAAA,IACjB,mBAAmB,QAAQ,SAAS,GACpC,mBAAmB,UAAU,QAAQ,eAAe,QAAQ,KAAK,CAAC;AACxE,MAAI,CAAC,mBAAmB,IAAI;AAC1B,eACE,SACA,KAAA,GACA,sEACA,sDAAsD,mBAAmB,UAC1E;AACD,UAAO;IAAE;IAAS;IAAQ,UAAU,CAAC,GAAG,SAAS;IAAE;;AAErD,UAAQ,yBACN,mBAAmB,MAAM;AAC3B,UAAQ,2BACN,mBAAmB,MAAM;AAC3B,8BACE,YACA,SACA,QAAQ,mBAAmB,EAAE,EAC7B,mBAAmB,OACnB,eACD;QACI;AACL,MACE,QAAQ,uBACR,CAAE,MAAM,0BAA0B,YAAY,UAAU,QAAQ,CAEhE,QAAO;GAAE;GAAS;GAAQ,UAAU,CAAC,GAAG,SAAS;GAAE;AAErD,iBACE,YACA,sBAAsB,UAAU,EAChC,SACA,wBAAwB,EACxB,OACA,gBACA,MACD;;AAGH,QAAO;EAAE;EAAS;EAAQ,UAAU,CAAC,GAAG,SAAS;EAAE;;;;;;;;;;AAWrD,eAAe,0BACb,YACA,UACA,SACkB;CAClB,MAAM,YAAY,QAAQ,SAAS,CAAC,aAAa;CACjD,MAAM,iBAAiB,IAAI,IAA6B;EACtD,sBAAsB,UAAU;EAChC;EACA;EACD,CAAC;CACF,MAAM,eAAe,0BAA0B,QAAQ,cAAc;AACrE,MAAK,MAAM,YAAY,gBAAgB;EACrC,MAAM,QAAQ,4BACZ,YACA,UACA,SACA,UACA,aACD;AACD,MAAI,MAAM,cAAe,QAAO;AAChC,MAAI,MAAM,OAAQ,QAAO;;CAM3B,MAAM,iBAJkB,8BACtB,YACA,eAEoC,EAAE,cACpC,MAAM,iCACJ,YACA,UACA,SACA,gBACA,aACD,GACD;EAAE,eAAe;EAAO,UAAU;EAAI;AAC1C,KAAI,eAAe,cACjB,QAAO;AAET,QAAO,mCACL,YACA,UACA,SACA,gBACA,cACA,eAAe,SAChB;;;;;;;;;;AAWH,eAAe,iCACb,YACA,UACA,SACA,WACA,cACuD;AACvD,OAAMA;CACN,IAAI;AACJ,KAAI;AACF,GAAC,WAAWC,MAAmB,WAAW;SACpC;AACN,YAAU,EAAE;;CAGd,MAAM,+BAAe,IAAI,KAAa;AACtC,MAAK,MAAM,gBAAgB,SAAS;AAClC,MAAI,CAAC,aAAa,EAAG;AACrB,OAAK,MAAM,eAAe,8BACxB,YACA,aAAa,IACb,aAAa,GACd,EAAE;AACD,QAAK,MAAM,YAAY,WAAW;IAChC,MAAM,QAAQ,4BACZ,aACA,UACA,SACA,UACA,aACD;AACD,QAAI,MAAM,cACR,QAAO;KAAE,eAAe;KAAM,UAAU;KAAI;AAE9C,QAAI,MAAM,QAAQ;AAChB,kBAAa,IAAI,YAAY;AAC7B;;;AAGJ,OAAI,aAAa,IAAI,YAAY,CAAE;;;AAGvC,QAAO;EACL,eAAe;EACf,UAAU,CAAC,GAAG,aAAa,CAAC,KAAK,KAAK;EACvC;;;AAIH,SAAS,8BACP,YACA,gBACA,cACU;CACV,MAAM,sBAAsB;EAAC;EAAK;EAAM;EAAK;EAAI,CAC9C,KAAK,cAAc,WAAW,YAAY,WAAW,iBAAiB,EAAE,CAAC,CACzE,QAAQ,WAAW,UAAU,EAAE,CAC/B,KAAK,WAAW,SAAS,EAAE;AAC9B,qBAAoB,KAAK,EAAE;CAC3B,MAAM,sBAAsB;EAAC;EAAK;EAAM;EAAI,CACzC,KAAK,cAAc,WAAW,QAAQ,WAAW,aAAa,CAAC,CAC/D,QAAQ,WAAW,UAAU,EAAE,CAC/B,KAAK,WAAW,SAAS,EAAE;CAC9B,MAAM,SAAS,CACb,GAAG,oBAAoB,MAAM,MAAM,UAAU,QAAQ,KAAK,EAC1D,eACD;CACD,MAAM,OAAO,CACX,GAAG,oBAAoB,MAAM,MAAM,UAAU,OAAO,MAAM,EAC1D,aACD;CACD,MAAM,6BAAa,IAAI,KAAa;AACpC,MAAK,MAAM,SAAS,OAClB,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,OAAO,MAAO;EAClB,MAAM,YAAY,WAAW,MAAM,OAAO,IAAI,CAAC,MAAM;AACrD,MAAI,UAAW,YAAW,IAAI,UAAU;;AAG5C,QAAO,CAAC,GAAG,WAAW;;;AAMxB,SAAS,4BACP,YACA,UACA,SACA,UACA,cAC6C;CAC7C,MAAM,UAA0C,EAAE;CAClD,MAAM,SAAmB,EAAE;CAC3B,MAAM,2BAAW,IAAI,KAAa;CAElC,MAAM,UAAU,2BACd,UACA,YAHkB,QAAQ,eAAe,QAAQ,KAAK,EAKtD,OACA,QAAQ,wBAAwB,gCAChC,SACA,QACA,SACD;CACD,MAAM,WAAW,yBAAyB;AAC1C,UAAS,YAAY;AACrB,UAAS,eAAe;CACxB,MAAM,SAAS,eACb,YACA,UACA,SACA,wBAAwB,EACxB,OACA,UACA,MACD;AACD,KAAI,QAAQ,SAAS,KAAK,wBAAwB,SAAS,CACzD,QAAO;EAAE,eAAe;EAAM;EAAQ;AAExC,QAAO;EAAE,eAAe;EAAO;EAAQ;;;;;;;;;AAUzC,SAAS,mCACP,YACA,UACA,SACA,WACA,cACA,mBACS;AACT,MAAK,MAAM,YAAY,UACrB,KACE,sCACE,YACA,UACA,SACA,UACA,aACD,CAED,QAAO;CAGX,MAAM,kBAAkB,8BAA8B,YAAY,UAAU;AAC5E,QAAO,QACL,iBAAiB,eACjB,+BACE,YACA,UACA,SACA,gBAAgB,UAChB,cACA,kBACD,CACF;;;AAIH,SAAS,sCACP,YACA,UACA,SACA,UACA,cACS;CACT,IAAI;AACJ,KAAI;AACF,iBAAe,YAAY,SAAS;AACpC,SAAO;UACA,OAAO;EACd,MAAM,SAAU,MAA4B;AAC5C,MAAI,OAAO,WAAW,SAAU,QAAO;AACvC,gBAAc;;CAEhB,MAAM,WAAW,KAAK,IACpB,WAAW,YAAY,KAAK,cAAc,EAAE,GAAG,GAC/C,WAAW,YAAY,MAAM,cAAc,EAAE,GAAG,GAChD,WAAW,YAAY,KAAK,cAAc,EAAE,GAAG,EAChD;AACD,KAAI,YAAY,EAAG,QAAO;CAC1B,MAAM,SAAS,WAAW,MAAM,GAAG,SAAS,CAAC,SAAS;AACtD,KAAI,CAAC,OAAQ,QAAO;AAQpB,QAPc,4BACZ,QACA,UACA,SACA,UACA,aAEU,CAAC;;;AAIf,SAAS,+BACP,YACA,UACA,SACA,UACA,cACA,mBACS;CACT,IAAI,YAAY;AAChB,MAAK,IAAI,UAAU,GAAG,UAAU,iCAAiC,WAAW;EAC1E,IAAI;AACJ,MAAI;AACF,kBAAe,WAAW,SAAS;GAInC,MAAM,iBAAiB,4BAHC,oBACpB,GAAG,kBAAkB,IAAI,cACzB,WAGF,UACA,SACA,UACA,aACD;AACD,OAAI,eAAe,OAAQ,QAAO,eAAe;AAGjD,UAAO,4BACL,WACA,UACA,SACA,UACA,aACD,CAAC;WACK,OAAO;GACd,MAAM,aAAa,0BAA0B,MAAM;AACnD,OAAI,CAAC,WAAY,QAAO;AACxB,iBAAc,WAAW;;EAE3B,MAAM,WAAW,8BAA8B,WAAW,YAAY;AACtE,MAAI,YAAY,KAAK,YAAY,UAAU,OAAQ,QAAO;AAC1D,cAAY,UAAU,MAAM,SAAS;EAIrC,IAAI,QAAQ,4BAHY,oBACpB,GAAG,kBAAkB,IAAI,cACzB,WAGF,UACA,SACA,UACA,aACD;AACD,MAAI,CAAC,MAAM,UAAU,mBAAmB;GACtC,MAAM,mBAAmB,4BAA4B,UAAU;AAC/D,OAAI,qBAAqB,UACvB,SAAQ,4BACN,GAAG,kBAAkB,IAAI,oBACzB,UACA,SACA,UACA,aACD;;AAGL,MAAI,MAAM,cAAe,QAAO;AAChC,MAAI,MAAM,OAAQ,QAAO;;AAE3B,QAAO;;;AAIT,SAAS,4BAA4B,YAA4B;AAC/D,QAAO,WAAW,QAAQ,mBAAmB,GAAG,CAAC,SAAS;;;AAI5D,SAAS,8BACP,YACA,WACyE;CACzE,IAAI;CAGJ,IAAI,iBAAiB;AACrB,MAAK,MAAM,YAAY,UACrB,KAAI;AACF,iBAAe,YAAY,SAAS;UAC7B,OAAO;EACd,MAAM,aAAa,eAAe,MAAM;AACxC,MAAI,cAAc,WAAW,SAAS,gBAAgB;AACpD,cAAW;IACT;IACA,aAAa,WAAW;IACzB;AACD,oBAAiB,WAAW;;;AAIlC,QAAO;;;AAIT,SAAS,0BACP,OACgC;CAChC,MAAM,SAAS,eAAe,MAAM;AACpC,QAAO,QAAQ,cAAc,EAAE,QAAQ,OAAO,QAAQ,GAAG,KAAA;;;AAI3D,SAAS,eACP,OACsD;CACtD,MAAM,SAAS;AACf,KAAI,OAAO,OAAO,QAAQ,SAAU,QAAO,KAAA;CAC3C,MAAM,oBAAoB,IAAI,IAAI;EAChC;EACA;EACA;EACA;EACA;EACD,CAAC;AACF,QAAO;EACL,QAAQ,OAAO;EACf,aACE,OAAO,OAAO,eAAe,YAC7B,CAAC,kBAAkB,IAAI,OAAO,WAAW;EAC5C;;;AAIH,SAAS,8BACP,YACA,aACQ;CACR,MAAM,aAAa;EAAC;EAAK;EAAM;EAAI,CAChC,KAAK,cAAc,WAAW,QAAQ,WAAW,YAAY,CAAC,CAC9D,QAAQ,WAAW,UAAU,EAAE;AAClC,QAAO,WAAW,SAAS,IAAI,KAAK,IAAI,GAAG,WAAW,GAAG,IAAI;;;AAI/D,SAAS,wBAAwB,UAAsC;AACrE,QAAO,SAAS;;AAGlB,SAAS,4BACP,QACA,SACA,iBACA,kBACA,gBACM;CACN,MAAM,EAAE,aAAa;AACrB,KACE,gBAAgB,cAChB,CAAC,iBAAiB,oBAClB,CAAC,iBAAiB,+BAClB;AACA,cACE,SACA,KAAA,GACA,oFACA,sIACD;AACD;;CAEF,MAAM,oBAAoC,qBAAqB,OAAO,GAClE,CAAC,aAAa,GACd,EAAE;CACN,MAAM,mBAAmB,iCACvB,kBACA,iBACA,mBACA,KACD;CACD,MAAM,SAAS,SAAS,MAAM,QAAQ;EACpC,GAAI,oBAAoB,EAAE,UAAU,kBAAkB;EACtD,UAAU,QAAQ;EAClB,KAAK;EACL,WAAW;EACX,sBAAsB;GACpB,GAAG;GACH,UAAU;GACV;GACD;EACF,CAAC;AAEF,MAAK,MAAM,SAAS,OAAO,QAAQ;EACjC,MAAM,gBACJ,OAAO,UAAU,WACb,KAAA,IACC;AAGP,cACE,SACA,eAAe,MACX,0BAA0B,cAAc,IAAI,GAC5C,KAAA,GACJ,mDAAmD,OAAO,UAAU,WAAW,QAAQ,MAAM,WAC7F,6DACD;;AAKH,KAAI,OAAO,OAAO,SAAS,EAAG;CAE9B,MAAM,WAAW,wBAAwB;AACzC,2BAA0B,OAAO,WAAW,QAAQ,eAAe;AACnE,2BAA0B,OAAO,WAAW,aAAa,eAAe;CACxE,MAAM,cAAc,iBAClB,OAAO,WAAW,QAClB,OACA,SACA,UACA,eACD;AACD,KAAI,OAAO,WAAW,YACpB,kCAAiC,gBAAgB,SAAS;CAE5D,MAAM,mBAAmB,iBACvB,OAAO,WAAW,aAClB,MACA,SACA,UACA,eACD;AACD,KAAI,CAAC,eAAe,CAAC,kBAAkB;AACrC,UAAQ,QAAQ,SAAS;AACzB;;CAGF,MAAM,WAAW,OAAO,WAAW;AACnC,KAAI,CAAC,SAAU;AACf,KAAI,SAAS,QAAQ,SAAS,SAAS,QAAQ;AAC7C,cACE,SACA,SAAS,KACT,4CAA4C,SAAS,KAAK,IAC1D,yDACD;AACD,UAAQ,QAAQ,SAAS;AACzB;;AAEF,KAAI,SAAS,KAAK;AAChB,cACE,SACA,SAAS,KACT,4CACA,8DACD;AACD,UAAQ,QAAQ,SAAS;AACzB;;CAEF,MAAM,cAAc,iBAAiB,gBACjC,0BACE,SAAS,SACT,iBACA,mBACA,MACA,SACA,iBAAiB,eACjB,SAAS,IAAI,MACd,GACA,SAAS;AACd,KAAI,aAAa;EACf,MAAM,sBAAsB,QAAQ,QAAQ;EAC5C,MAAM,qBAAqB,QAAQ,OAAO;AAC1C,mBAAiB,aAAa,UAAU,mBAAmB,QAAQ;AACnE,MACE,QAAQ,OAAO,WAAW,sBAC1B,SAAS,QAAQ,SAAS,OAAO,IACjC,CAAC,0BACC,QACA,iBACA,mBACA,UACA,SACA,qBACA,iBACD,EACD;AACA,WAAQ,QAAQ,SAAS;AACzB,eACE,SACA,SAAS,KACT,wFACA,mHACD;;;;;;;;;;;;AAaP,SAAS,0BACP,QACA,iBACA,mBACA,UACA,SACA,wBACA,kBACS;CACT,MAAM,EAAE,aAAa;CACrB,MAAM,mBAAmB,iCACvB,kBACA,iBACA,mBACA,MACD;CACD,MAAM,aAAa,SAAS,MAAM,QAAQ;EACxC,GAAI,oBAAoB,EAAE,UAAU,kBAAkB;EACtD,UAAU,QAAQ;EAClB,KAAK;EACL,WAAW;EACX,sBAAsB;GACpB,GAAG;GACH,UAAU;GACV;GACD;EACF,CAAC;CACF,MAAM,WAAW,WAAW,WAAW;AACvC,KAAI,WAAW,OAAO,SAAS,KAAK,CAAC,SAAU,QAAO;CAEtD,MAAM,oBAA0C;EAC9C,GAAG;EACH,QAAQ,EAAE;EACV,SAAS,EAAE;EACX,0BAAU,IAAI,KAAK;EACpB;CACD,MAAM,cAAc,iBAAiB,gBACjC,0BACE,SAAS,SACT,iBACA,mBACA,OACA,mBACA,iBAAiB,eACjB,SAAS,IAAI,MACd,GACA,SAAS;AACd,KAAI,CAAC,YAAa,QAAO;AACzB,kBAAiB,aAAa,UAAU,mBAAmB,kBAAkB;AAC7E,KAAI,kBAAkB,OAAO,SAAS,EAAG,QAAO;AAGhD,QACE,0BAFyB,QAAQ,QAAQ,MAAM,uBAEH,CAAC,KAC7C,0BAA0B,kBAAkB,QAAQ;;;;;;;;;;;;AAcxD,SAAS,iCACP,kBACA,iBACA,mBACA,UAC8B;CAC9B,MAAM,mBAAmB,iBAAiB;AAC1C,KAAI,CAAC,iBAAkB,QAAO,KAAA;CAE9B,MAAM,SAAoC,QAAQ,gBAAgB;EAChE,MAAM,UAA2C;GAC/C,GAAG;GACH,GAAG;GACH;GACA;GACD;AACD,SAAO,iBAAiB,MAAM,QAAQ,QAAQ;;CAEhD,MAAM,WAAW,KAAK,UAAU;EAC9B;EACA,YAAY,gBAAgB;EAC5B;EACA,SAAS,iBAAiB;EAC1B,YAAY,gBAAgB;EAC7B,CAAC;AACF,QAAO,eAAe,OAAO,YAAY,EACvC,aAAa,sBAAsB,YACpC,CAAC;AAEF,QAAO;EAAE,SAAS,iBAAiB;EAAS;EAAO;;;AAIrD,SAAS,0BACP,QACA,iBACA,mBACA,UACA,SACA,eACA,QACsB;CACtB,MAAM,SAAgE,EAAE;CASxE,MAAM,MAAM,cAAc,QAAQ;EAPhC,GAAG;EACH;EACA;EACA,QAAQ,OAAO;AACb,UAAO,KAAK,MAAwD;;EAG/B,CAAC;AAC1C,KAAI,OAAO,WAAW,GAAG;AACvB,4BAA0B,KAAK,OAAO;AACtC,SAAO;;CAET,MAAM,wCAAwB,IAAI,SAAiB;AACnD,MAAK,MAAM,SAAS,QAAQ;AAC1B,MAAI,MAAM,IACR,uBAAsB,MAAM,KAAK,QAAQ,sBAAsB;AAEjE,cACE,SACA,MAAM,MAAM,0BAA0B,MAAM,IAAI,GAAG,KAAA,GACnD,sCAAsC,MAAM,WAC5C,6DACD;;;;AAaL,SAAS,0BACP,SACQ;AACR,QAAO,KAAK,UACV,QAAQ,KAAK,YAAY;EACvB,YAAY,OAAO;EACnB,UAAU;GACR,SAAS,OAAO,SAAS;GACzB,IAAI,OAAO,SAAS;GACpB,UAAU,OAAO,SAAS;GAC1B,gBAAgB,OAAO,SAAS;GACjC;EACD,QAAQ,OAAO;EAChB,EAAE,CACJ;;AAGH,SAAS,0BACP,OACA,gBACM;AACN,KAAI,CAAC,SAAS,MAAM,OAAO,CAAC,0BAA0B,MAAM,KAAK,CAAE;AACnE,yBAAwB,MAAM,SAAS,MAAM,MAAM,eAAe;;AAGpE,SAAS,iBACP,OACA,kBACA,SACA,UACA,gBACS;AACT,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,MAAM,KAAK;AACb,cACE,SACA,MAAM,KACN,gDACA,6DACD;AACD,SAAO;;AAET,KAAI,CAAC,0BAA0B,MAAM,KAAK,EAAE;AAC1C,cACE,SACA,MAAM,KACN,0CAA0C,MAAM,KAAK,IACrD,qDACD;AACD,SAAO;;AAGT,QAAO,eACL,MAAM,SACN,MAAM,MACN,SACA,UACA,kBACA,eACD;;AAGH,SAAS,yBAA2C;AAClD,QAAO;EACL,8BAAc,IAAI,KAAK;EACvB,oCAAoB,IAAI,KAAK;EAC7B,4BAAY,IAAI,KAAK;EACrB,gCAAgB,IAAI,KAAK;EACzB,sCAAsB,IAAI,KAAK;EAC/B,sCAAsB,IAAI,KAAK;EAC/B,gCAAgB,IAAI,KAAK;EACzB,sCAAsB,IAAI,KAAK;EAC/B,uCAAuB,IAAI,KAAK;EAChC,8BAAc,IAAI,KAAK;EACvB,mCAAmB,IAAI,KAAK;EAC5B,uCAAuB,IAAI,KAAK;EAChC,iCAAiB,IAAI,KAAK;EAC1B,0CAA0B,IAAI,KAAK;EACnC,qCAAqB,IAAI,KAAK;EAC9B,uCAAuB,IAAI,KAAK;EAChC,sCAAsB,IAAI,KAAK;EAC/B,+CAA+B,IAAI,KAAK;EACxC,iDAAiC,IAAI,KAAK;EAC1C,6BAAa,IAAI,KAAK;EACvB;;AAGH,SAAS,qBAAqB,QAAyB;CACrD,IAAI,SAAS;AACb,QAAO,SAAS,OAAO,QAAQ;EAC7B,MAAM,QAAQ,OAAO,QAAQ,WAAW,OAAO;AAC/C,MAAI,UAAU,GAAI,QAAO;EACzB,MAAM,WAAW,OAAO,QAAQ;AAChC,MAAI,aAAa,OAAO,CAAC,UAAU,MAAM,KAAK,EAAE;AAC9C,YAAS,QAAQ;AACjB;;EAGF,MAAM,MAAM,kBAAkB,QAAQ,QAAQ,EAAiB;AAC/D,MAAI,QAAQ,GAAI,QAAO;EACvB,MAAM,WAAW,wBACf,OAAO,MAAM,QAAQ,GAAkB,IAAI,EAC3C,OACD;AACD,MAAI,OAAO,aAAa,YAAY,UAAU,KAAK,SAAS,CAAE,QAAO;AACrE,WAAS,MAAM;;AAEjB,QAAO;;AAGT,SAAS,0BAA0B,UAAuC;CACxE,MAAM,qBAAqB,UAAU,aAAa;AAClD,QACE,uBAAuB,KAAA,KACvB,uBAAuB,QACvB,uBAAuB,SACvB,uBAAuB,QACvB,uBAAuB;;;AAK3B,SAAS,kBAAkB,QAAgB,OAAuB;CAChE,IAAI;AACJ,MAAK,IAAI,QAAQ,OAAO,QAAQ,OAAO,QAAQ,SAAS,GAAG;EACzD,MAAM,YAAY,OAAO;AACzB,MAAI;OACE,cAAc,MAAO,SAAQ,KAAA;aACxB,cAAc,QAAO,cAAc,IAC5C,SAAQ;WACC,cAAc,IACvB,QAAO;;AAGX,QAAO;;;AAIT,SAAS,wBACP,YACA,eAC2B;CAC3B,IAAI,SAAS;AACb,QAAO,SAAS,WAAW,QAAQ;AACjC,SAAO,SAAS,WAAW,UAAU,KAAK,KAAK,WAAW,QAAQ,CAChE,WAAU;AAEZ,MAAI,WAAW,YAAY,KAAK;AAC9B,aAAU;AACV;;EAEF,MAAM,YAAY;AAClB,SAAO,SAAS,WAAW,UAAU,CAAC,QAAQ,KAAK,WAAW,QAAQ,CACpE,WAAU;EAEZ,MAAM,OAAO,WAAW,MAAM,WAAW,OAAO;AAChD,MAAI,CAAC,KAAM;AAEX,SAAO,SAAS,WAAW,UAAU,KAAK,KAAK,WAAW,QAAQ,CAChE,WAAU;EAEZ,IAAI,QAAuB;AAC3B,MAAI,WAAW,YAAY,KAAK;AAC9B,aAAU;AACV,UAAO,SAAS,WAAW,UAAU,KAAK,KAAK,WAAW,QAAQ,CAChE,WAAU;GAEZ,MAAM,QAAQ,WAAW;AACzB,OAAI,UAAU,QAAO,UAAU,KAAK;AAClC,cAAU;IACV,MAAM,aAAa;AACnB,WAAO,SAAS,WAAW,UAAU,WAAW,YAAY,MAC1D,WAAU;AAEZ,YAAQ,WAAW,MAAM,YAAY,OAAO;AAC5C,QAAI,WAAW,YAAY,MAAO,WAAU;UACvC;IACL,MAAM,aAAa;AACnB,WAAO,SAAS,WAAW,UAAU,CAAC,KAAK,KAAK,WAAW,QAAQ,CACjE,WAAU;AAEZ,YAAQ,WAAW,MAAM,YAAY,OAAO;;;AAGhD,MAAI,SAAS,cAAe,QAAO;;;AAKvC,SAAS,sBACP,WAC0C;AAC1C,KAAI,cAAc,SAAS,cAAc,UAAU,cAAc,OAC/D,QAAO;AAET,KAAI,cAAc,OAAQ,QAAO;AACjC,KAAI,cAAc,OAAQ,QAAO;AACjC,QAAO;;AAGT,SAAS,0BAA0B,UAGhC;CACD,MAAM,QAAQ,SAAS,SAAS,EAAE;CAClC,MAAM,MAAM,SAAS,OAAO;AAC5B,QAAO;EACL,OAAO;GACL,QAAQ,MAAM,UAAU;GACxB,MAAM,MAAM,QAAQ;GACpB,QAAQ,MAAM,UAAU;GACzB;EACD,KAAK;GACH,QAAQ,IAAI,UAAU,MAAM,UAAU;GACtC,MAAM,IAAI,QAAQ,MAAM,QAAQ;GAChC,QAAQ,IAAI,UAAU,MAAM,UAAU;GACvC;EACF"}
|
|
1
|
+
{"version":3,"file":"extractFromVueSource.js","names":["initModuleLexer","parseModuleImports"],"sources":["../../src/internal/extractFromVueSource.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport {\n init as initModuleLexer,\n parse as parseModuleImports,\n} from 'es-module-lexer';\nimport type { ParserPlugin } from '@babel/parser';\nimport type { SFCBlock, TemplateCompiler } from '#vue-compiler-sfc';\nimport type { RootNode } from '@vue/compiler-dom';\nimport type {\n VueCompilerOptions,\n VueExtractionOptions,\n VueExtractionOutput,\n} from '../types.js';\nimport {\n collectVueScriptImports,\n createVueScriptAnalysis,\n exposeVueScriptImportsToTemplate,\n parseVueScript,\n type VueScriptAnalysis,\n} from './script.js';\nimport { parseScriptAst } from './script/parser.js';\nimport {\n shiftCompilerAstLocations,\n shiftCompilerLocation,\n} from './compilerAst.js';\nimport {\n createLocalModuleResolver,\n type LocalModuleResolver,\n} from './script/localModules.js';\nimport { parseVueTemplate } from './template.js';\nimport type { TemplateBindings, VueExtractionContext } from './types.js';\nimport { addVueError, createVueExtractionContext } from './utils.js';\nimport {\n inspectVueCompiler,\n resolveVueCompiler,\n type ResolvedVueCompiler,\n} from './vueCompiler.js';\n\nconst DEFAULT_SURROUNDING_LINE_COUNT = 5;\nconst MAX_MALFORMED_SUFFIX_RECOVERIES = 64;\n\n/** Parser options supported at runtime but omitted from Vue 3.3 declarations. */\ntype CompatibleTemplateParserOptions = NonNullable<\n Parameters<TemplateCompiler['parse']>[1]\n> & {\n expressionPlugins?: ParserPlugin[];\n};\n\n/** compiler-dom options supported at runtime across the supported Vue range. */\ntype CompatibleCompilerDomParserOptions = NonNullable<\n Parameters<NonNullable<ResolvedVueCompiler['parseTemplate']>>[1]\n> & {\n expressionPlugins?: ParserPlugin[];\n};\n\n/**\n * Extracts General Translation content from one Vue SFC or JavaScript file.\n *\n * This low-level API lets callers parse an individual in-memory source file.\n * Use `@generaltranslation/vue-extractor/project` when discovery, I/O,\n * compiler configuration, hashing, and deduplication should be handled by the\n * package as one project-level operation.\n */\nexport async function extractFromVueSource(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions = {}\n): Promise<VueExtractionOutput> {\n const results: VueExtractionOutput['results'] = [];\n const errors: string[] = [];\n const warnings = new Set<string>();\n const context = createVueExtractionContext(\n filePath,\n sourceCode,\n options.projectRoot ?? process.cwd(),\n options.includeSourceCodeContext ?? false,\n options.surroundingLineCount ?? DEFAULT_SURROUNDING_LINE_COUNT,\n results,\n errors,\n warnings\n );\n const extension = extname(filePath).toLowerCase();\n const scriptAnalysis = createVueScriptAnalysis();\n scriptAnalysis.entryFile = filePath;\n scriptAnalysis.localModules = createLocalModuleResolver(\n options.resolveModule\n );\n\n if (extension === '.vue') {\n const compilerResolution =\n options.compiler !== undefined\n ? inspectVueCompiler(options.compiler)\n : resolveVueCompiler(filePath, options.projectRoot ?? process.cwd());\n if (!compilerResolution.ok) {\n addVueError(\n context,\n undefined,\n 'Could not load the Vue compiler used by this single-file component',\n `Install a supported Vue 3 compiler beside the app. ${compilerResolution.details}`\n );\n return { results, errors, warnings: [...warnings] };\n }\n context.implicitSlotWhitespace =\n compilerResolution.value.implicitSlotWhitespace;\n context.valuedVIsReplacesElement =\n compilerResolution.value.valuedVIsReplacesElement;\n parseVueSingleFileComponent(\n sourceCode,\n context,\n options.compilerOptions ?? {},\n compilerResolution.value,\n scriptAnalysis\n );\n } else {\n if (\n options.requireGTProvenance &&\n !(await hasStandaloneGTProvenance(sourceCode, filePath, options))\n ) {\n return { results, errors, warnings: [...warnings] };\n }\n parseVueScript(\n sourceCode,\n languageFromExtension(extension),\n context,\n createTemplateBindings(),\n false,\n scriptAnalysis,\n false\n );\n }\n\n return { results, errors, warnings: [...warnings] };\n}\n\n/**\n * Uses the declared language, then permissive TSX and Flow, to prove gt-vue\n * ownership without changing the grammar used for extraction.\n *\n * The normal extraction pass still parses the file according to its extension.\n * Diagnostics caused only by GT-shaped names do not establish ownership. This\n * keeps mixed-framework dispatch from making otherwise valid React files fatal.\n */\nasync function hasStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions\n): Promise<boolean> {\n const extension = extname(filePath).toLowerCase();\n const probeLanguages = new Set<StandaloneProbeLanguage>([\n languageFromExtension(extension),\n 'tsx',\n 'flow',\n ]);\n const localModules = createLocalModuleResolver(options.resolveModule);\n for (const language of probeLanguages) {\n const probe = probeStandaloneGTProvenance(\n sourceCode,\n filePath,\n options,\n language,\n localModules\n );\n if (probe.hasProvenance) return true;\n if (probe.parsed) return false;\n }\n const suffixSelection = selectMalformedSuffixLanguage(\n sourceCode,\n probeLanguages\n );\n const moduleRecovery = suffixSelection?.recoverable\n ? await recoverMalformedModuleReferences(\n sourceCode,\n filePath,\n options,\n probeLanguages,\n localModules\n )\n : { hasProvenance: false, preamble: '' };\n if (moduleRecovery.hasProvenance) {\n return true;\n }\n return hasMalformedStandaloneGTProvenance(\n sourceCode,\n filePath,\n options,\n probeLanguages,\n localModules,\n moduleRecovery.preamble\n );\n}\n\n/**\n * Recovers static module ownership without reparsing an entire malformed file.\n *\n * es-module-lexer ignores comments and literal contents while continuing past\n * unrelated syntax errors. Each declaration is then analyzed on its own,\n * preserving type-only and binding-specific local-barrel semantics. Parseable\n * declarations are also returned as a preamble for later recovered uses.\n */\nasync function recoverMalformedModuleReferences(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n languages: ReadonlySet<StandaloneProbeLanguage>,\n localModules: LocalModuleResolver\n): Promise<{ hasProvenance: boolean; preamble: string }> {\n await initModuleLexer;\n let imports: ReturnType<typeof parseModuleImports>[0];\n try {\n [imports] = parseModuleImports(sourceCode);\n } catch {\n imports = [];\n }\n\n const declarations = new Set<string>();\n for (const moduleImport of imports) {\n if (!moduleImport.n) continue;\n for (const declaration of readModuleStatementCandidates(\n sourceCode,\n moduleImport.ss,\n moduleImport.se\n )) {\n for (const language of languages) {\n const probe = probeStandaloneGTProvenance(\n declaration,\n filePath,\n options,\n language,\n localModules\n );\n if (probe.hasProvenance) {\n return { hasProvenance: true, preamble: '' };\n }\n if (probe.parsed) {\n declarations.add(declaration);\n break;\n }\n }\n if (declarations.has(declaration)) break;\n }\n }\n return {\n hasProvenance: false,\n preamble: [...declarations].join('\\n'),\n };\n}\n\n/** Returns small statement slices enclosing one lexed module reference. */\nfunction readModuleStatementCandidates(\n sourceCode: string,\n statementStart: number,\n specifierEnd: number\n): string[] {\n const precedingBoundaries = [';', '\\n', '{', '}']\n .map((separator) => sourceCode.lastIndexOf(separator, statementStart - 1))\n .filter((offset) => offset >= 0)\n .map((offset) => offset + 1);\n precedingBoundaries.push(0);\n const followingBoundaries = [';', '\\n', '}']\n .map((separator) => sourceCode.indexOf(separator, specifierEnd))\n .filter((offset) => offset >= 0)\n .map((offset) => offset + 1);\n const starts = [\n ...precedingBoundaries.sort((left, right) => right - left),\n statementStart,\n ];\n const ends = [\n ...followingBoundaries.sort((left, right) => left - right),\n specifierEnd,\n ];\n const candidates = new Set<string>();\n for (const start of starts) {\n for (const end of ends) {\n if (end <= start) continue;\n const candidate = sourceCode.slice(start, end).trim();\n if (candidate) candidates.add(candidate);\n }\n }\n return [...candidates];\n}\n\ntype StandaloneProbeLanguage = 'flow' | 'js' | 'jsx' | 'ts' | 'tsx';\n\n/** Runs one syntax-tolerant, read-only provenance classification pass. */\nfunction probeStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver\n): { hasProvenance: boolean; parsed: boolean } {\n const results: VueExtractionOutput['results'] = [];\n const errors: string[] = [];\n const warnings = new Set<string>();\n const projectRoot = options.projectRoot ?? process.cwd();\n const context = createVueExtractionContext(\n filePath,\n sourceCode,\n projectRoot,\n false,\n options.surroundingLineCount ?? DEFAULT_SURROUNDING_LINE_COUNT,\n results,\n errors,\n warnings\n );\n const analysis = createVueScriptAnalysis();\n analysis.entryFile = filePath;\n analysis.localModules = localModules;\n const parsed = parseVueScript(\n sourceCode,\n language,\n context,\n createTemplateBindings(),\n false,\n analysis,\n false\n );\n if (results.length > 0 || analysisHasGTProvenance(analysis)) {\n return { hasProvenance: true, parsed };\n }\n return { hasProvenance: false, parsed };\n}\n\n/**\n * Finds concrete module references when malformed syntax prevents a full AST.\n *\n * Each supported grammar recovers a complete prefix, then the grammar that\n * parsed furthest gets a bounded suffix search. Unterminated literal errors\n * never receive suffix recovery, so literal contents cannot become code.\n */\nfunction hasMalformedStandaloneGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n languages: ReadonlySet<StandaloneProbeLanguage>,\n localModules: LocalModuleResolver,\n recoveredPreamble: string\n): boolean {\n for (const language of languages) {\n if (\n leadingStatementPrefixHasGTProvenance(\n sourceCode,\n filePath,\n options,\n language,\n localModules\n )\n ) {\n return true;\n }\n }\n const suffixSelection = selectMalformedSuffixLanguage(sourceCode, languages);\n return Boolean(\n suffixSelection?.recoverable &&\n malformedSuffixHasGTProvenance(\n sourceCode,\n filePath,\n options,\n suffixSelection.language,\n localModules,\n recoveredPreamble\n )\n );\n}\n\n/** Preserves CommonJS and TypeScript import ownership before a syntax error. */\nfunction leadingStatementPrefixHasGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver\n): boolean {\n let errorOffset: number;\n try {\n parseScriptAst(sourceCode, language);\n return false;\n } catch (error) {\n const offset = (error as { pos?: unknown }).pos;\n if (typeof offset !== 'number') return false;\n errorOffset = offset;\n }\n const boundary = Math.max(\n sourceCode.lastIndexOf(';', errorOffset - 1) + 1,\n sourceCode.lastIndexOf('\\n', errorOffset - 1) + 1,\n sourceCode.lastIndexOf('}', errorOffset - 1) + 1\n );\n if (boundary <= 0) return false;\n const prefix = sourceCode.slice(0, boundary).trimEnd();\n if (!prefix) return false;\n const probe = probeStandaloneGTProvenance(\n prefix,\n filePath,\n options,\n language,\n localModules\n );\n return probe.hasProvenance;\n}\n\n/** Recovers later imports and CommonJS calls after a bounded number of errors. */\nfunction malformedSuffixHasGTProvenance(\n sourceCode: string,\n filePath: string,\n options: VueExtractionOptions,\n language: StandaloneProbeLanguage,\n localModules: LocalModuleResolver,\n recoveredPreamble: string\n): boolean {\n let remaining = sourceCode;\n for (let attempt = 0; attempt < MAX_MALFORMED_SUFFIX_RECOVERIES; attempt++) {\n let errorOffset: number;\n try {\n parseScriptAst(remaining, language);\n const recoveredSource = recoveredPreamble\n ? `${recoveredPreamble}\\n${remaining}`\n : remaining;\n const recoveredProbe = probeStandaloneGTProvenance(\n recoveredSource,\n filePath,\n options,\n language,\n localModules\n );\n if (recoveredProbe.parsed) return recoveredProbe.hasProvenance;\n // The remaining suffix may already contain the declaration retained in\n // the preamble. Probe it alone to avoid a duplicate-binding parse error.\n return probeStandaloneGTProvenance(\n remaining,\n filePath,\n options,\n language,\n localModules\n ).hasProvenance;\n } catch (error) {\n const parseError = readRecoverableParseError(error);\n if (!parseError) return false;\n errorOffset = parseError.offset;\n }\n const boundary = findMalformedRecoveryBoundary(remaining, errorOffset);\n if (boundary <= 0 || boundary >= remaining.length) return false;\n remaining = remaining.slice(boundary);\n const recoveredSource = recoveredPreamble\n ? `${recoveredPreamble}\\n${remaining}`\n : remaining;\n let probe = probeStandaloneGTProvenance(\n recoveredSource,\n filePath,\n options,\n language,\n localModules\n );\n if (!probe.parsed && recoveredPreamble) {\n const trimmedRemaining = trimTrailingRecoveryClosers(remaining);\n if (trimmedRemaining !== remaining) {\n probe = probeStandaloneGTProvenance(\n `${recoveredPreamble}\\n${trimmedRemaining}`,\n filePath,\n options,\n language,\n localModules\n );\n }\n }\n if (probe.hasProvenance) return true;\n if (probe.parsed) return false;\n }\n return false;\n}\n\n/** Removes block closers orphaned when recovery starts inside a function. */\nfunction trimTrailingRecoveryClosers(sourceCode: string): string {\n let end = sourceCode.length;\n while (end > 0 && sourceCode[end - 1]!.trim() === '') end -= 1;\n if (sourceCode[end - 1] !== '}') return sourceCode.slice(0, end);\n\n do {\n end -= 1;\n while (end > 0 && sourceCode[end - 1]!.trim() === '') end -= 1;\n } while (sourceCode[end - 1] === '}');\n return sourceCode.slice(0, end);\n}\n\n/** Chooses the grammar that parsed furthest before a recoverable error. */\nfunction selectMalformedSuffixLanguage(\n sourceCode: string,\n languages: ReadonlySet<StandaloneProbeLanguage>\n): { language: StandaloneProbeLanguage; recoverable: boolean } | undefined {\n let selected:\n | { language: StandaloneProbeLanguage; recoverable: boolean }\n | undefined;\n let furthestOffset = -1;\n for (const language of languages) {\n try {\n parseScriptAst(sourceCode, language);\n } catch (error) {\n const parseError = readParseError(error);\n if (parseError && parseError.offset > furthestOffset) {\n selected = {\n language,\n recoverable: parseError.recoverable,\n };\n furthestOffset = parseError.offset;\n }\n }\n }\n return selected;\n}\n\n/** Rejects recovery that could reinterpret unterminated literal contents. */\nfunction readRecoverableParseError(\n error: unknown\n): { offset: number } | undefined {\n const parsed = readParseError(error);\n return parsed?.recoverable ? { offset: parsed.offset } : undefined;\n}\n\n/** Reads one Babel parser error without trusting unterminated literal state. */\nfunction readParseError(\n error: unknown\n): { offset: number; recoverable: boolean } | undefined {\n const parsed = error as { pos?: unknown; reasonCode?: unknown };\n if (typeof parsed.pos !== 'number') return undefined;\n const unsafeReasonCodes = new Set([\n 'UnterminatedComment',\n 'UnterminatedJsxContent',\n 'UnterminatedRegExp',\n 'UnterminatedString',\n 'UnterminatedTemplate',\n ]);\n return {\n offset: parsed.pos,\n recoverable:\n typeof parsed.reasonCode !== 'string' ||\n !unsafeReasonCodes.has(parsed.reasonCode),\n };\n}\n\n/** Selects the first statement-like boundary after a parser error. */\nfunction findMalformedRecoveryBoundary(\n sourceCode: string,\n errorOffset: number\n): number {\n const candidates = [';', '\\n', '}']\n .map((separator) => sourceCode.indexOf(separator, errorOffset))\n .filter((offset) => offset >= 0);\n return candidates.length > 0 ? Math.min(...candidates) + 1 : -1;\n}\n\n/** Returns whether permissive analysis reached a concrete gt-vue identity. */\nfunction analysisHasGTProvenance(analysis: VueScriptAnalysis): boolean {\n return analysis.hasGTSourceReference;\n}\n\nfunction parseVueSingleFileComponent(\n source: string,\n context: VueExtractionContext,\n compilerOptions: VueCompilerOptions,\n resolvedCompiler: ResolvedVueCompiler,\n scriptAnalysis: VueScriptAnalysis\n): void {\n const { compiler } = resolvedCompiler;\n if (\n compilerOptions.delimiters &&\n !resolvedCompiler.templateCompiler &&\n !resolvedCompiler.templateParseOptionsSupported\n ) {\n addVueError(\n context,\n undefined,\n 'Could not safely apply custom Vue template delimiters with the supplied compiler',\n 'Let the extractor resolve the consuming app compiler, or supply a Vue compiler that applies templateParseOptions during SFC parsing'\n );\n return;\n }\n const expressionPlugins: ParserPlugin[] = sourceUsesTypeScript(source)\n ? ['typescript']\n : [];\n const templateCompiler = createConfiguredTemplateCompiler(\n resolvedCompiler,\n compilerOptions,\n expressionPlugins,\n true\n );\n const result = compiler.parse(source, {\n ...(templateCompiler && { compiler: templateCompiler }),\n filename: context.file,\n pad: 'space',\n sourceMap: false,\n templateParseOptions: {\n ...compilerOptions,\n comments: true,\n expressionPlugins,\n },\n });\n\n for (const error of result.errors) {\n const compilerError =\n typeof error === 'string'\n ? undefined\n : (error as SyntaxError & {\n loc?: Parameters<typeof normalizeCompilerLocation>[0];\n });\n addVueError(\n context,\n compilerError?.loc\n ? normalizeCompilerLocation(compilerError.loc)\n : undefined,\n `Could not parse a gt-vue single-file component: ${typeof error === 'string' ? error : error.message}`,\n 'Fix the Vue template syntax before extracting translations'\n );\n }\n // Vue's SFC parser recovers a partial AST for malformed markup. Publishing\n // translations from that recovery tree can replace complete catalogs with\n // an incomplete source set, so structural parse errors are file-fatal.\n if (result.errors.length > 0) return;\n\n const bindings = createTemplateBindings();\n collectScriptBlockImports(result.descriptor.script, scriptAnalysis);\n collectScriptBlockImports(result.descriptor.scriptSetup, scriptAnalysis);\n const scriptValid = parseScriptBlock(\n result.descriptor.script,\n false,\n context,\n bindings,\n scriptAnalysis\n );\n if (result.descriptor.scriptSetup) {\n exposeVueScriptImportsToTemplate(scriptAnalysis, bindings);\n }\n const scriptSetupValid = parseScriptBlock(\n result.descriptor.scriptSetup,\n true,\n context,\n bindings,\n scriptAnalysis\n );\n if (!scriptValid || !scriptSetupValid) {\n context.results.length = 0;\n return;\n }\n\n const template = result.descriptor.template;\n if (!template) return;\n if (template.lang && template.lang !== 'html') {\n addVueError(\n context,\n template.loc,\n `Found unsupported Vue template language \"${template.lang}\"`,\n 'Use a standard HTML Vue template for gt-vue extraction'\n );\n context.results.length = 0;\n return;\n }\n if (template.src) {\n addVueError(\n context,\n template.loc,\n 'Found an externally sourced Vue template',\n 'Keep the template in the .vue file so gt-vue can extract it'\n );\n context.results.length = 0;\n return;\n }\n const templateAst = resolvedCompiler.parseTemplate\n ? parseTemplateWithCompiler(\n template.content,\n compilerOptions,\n expressionPlugins,\n true,\n context,\n resolvedCompiler.parseTemplate,\n template.loc.start\n )\n : (template.ast as unknown as RootNode);\n if (templateAst) {\n const templateResultStart = context.results.length;\n const templateErrorStart = context.errors.length;\n parseVueTemplate(templateAst, bindings, expressionPlugins, context);\n if (\n context.errors.length === templateErrorStart &&\n template.content.includes('<!--') &&\n !matchesProductionTemplate(\n source,\n compilerOptions,\n expressionPlugins,\n bindings,\n context,\n templateResultStart,\n resolvedCompiler\n )\n ) {\n context.results.length = templateResultStart;\n addVueError(\n context,\n template.loc,\n 'Found translatable Vue content whose hash changes between development and production',\n 'Remove comments that split translatable text or whitespace, or move those comments outside gt-vue <T> components'\n );\n }\n }\n}\n\n/**\n * Verifies that Vite's production comment stripping preserves extracted data.\n *\n * Vue parses templates with comments in development and without them in\n * production. Removing a comment can renormalize adjacent whitespace, so a\n * single persisted catalog key cannot serve both builds. The second parse is\n * limited to templates that contain comments and never executes project code.\n */\nfunction matchesProductionTemplate(\n source: string,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n bindings: TemplateBindings,\n context: VueExtractionContext,\n developmentResultStart: number,\n resolvedCompiler: ResolvedVueCompiler\n): boolean {\n const { compiler } = resolvedCompiler;\n const templateCompiler = createConfiguredTemplateCompiler(\n resolvedCompiler,\n compilerOptions,\n expressionPlugins,\n false\n );\n const production = compiler.parse(source, {\n ...(templateCompiler && { compiler: templateCompiler }),\n filename: context.file,\n pad: 'space',\n sourceMap: false,\n templateParseOptions: {\n ...compilerOptions,\n comments: false,\n expressionPlugins,\n },\n });\n const template = production.descriptor.template;\n if (production.errors.length > 0 || !template) return false;\n\n const productionContext: VueExtractionContext = {\n ...context,\n errors: [],\n results: [],\n warnings: new Set(),\n };\n const templateAst = resolvedCompiler.parseTemplate\n ? parseTemplateWithCompiler(\n template.content,\n compilerOptions,\n expressionPlugins,\n false,\n productionContext,\n resolvedCompiler.parseTemplate,\n template.loc.start\n )\n : (template.ast as unknown as RootNode);\n if (!templateAst) return false;\n parseVueTemplate(templateAst, bindings, expressionPlugins, productionContext);\n if (productionContext.errors.length > 0) return false;\n\n const developmentResults = context.results.slice(developmentResultStart);\n return (\n comparableTemplateResults(developmentResults) ===\n comparableTemplateResults(productionContext.results)\n );\n}\n\n/**\n * Applies hash-affecting options during compiler-sfc's structural parse.\n *\n * Vue 3.3 ignores `templateParseOptions`, which can make delimiter-shaped text\n * close an SFC block before the exact template-content parse runs. Supplying\n * the adjacent compiler-dom parser makes the descriptor structural parse use\n * the same delimiters and whitespace. Vue 3.3 caches SFC parses using the\n * parser function's string form, so its deterministic identity includes every\n * closure-captured option to prevent cross-option cache poisoning.\n */\nfunction createConfiguredTemplateCompiler(\n resolvedCompiler: ResolvedVueCompiler,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n comments: boolean\n): TemplateCompiler | undefined {\n const templateCompiler = resolvedCompiler.templateCompiler;\n if (!templateCompiler) return undefined;\n\n const parse: TemplateCompiler['parse'] = (source, baseOptions) => {\n const options: CompatibleTemplateParserOptions = {\n ...baseOptions,\n ...compilerOptions,\n comments,\n expressionPlugins,\n };\n return templateCompiler.parse(source, options);\n };\n const identity = JSON.stringify({\n comments,\n delimiters: compilerOptions.delimiters,\n expressionPlugins,\n version: resolvedCompiler.version,\n whitespace: compilerOptions.whitespace,\n });\n Object.defineProperty(parse, 'toString', {\n value: () => `gtVueTemplateParse:${identity}`,\n });\n\n return { compile: templateCompiler.compile, parse };\n}\n\n/** Parses template content with the exact compiler-dom beside consumer Vue. */\nfunction parseTemplateWithCompiler(\n source: string,\n compilerOptions: VueCompilerOptions,\n expressionPlugins: ParserPlugin[],\n comments: boolean,\n context: VueExtractionContext,\n parseTemplate: NonNullable<ResolvedVueCompiler['parseTemplate']>,\n origin: CompilerPosition\n): RootNode | undefined {\n const errors: Array<SyntaxError & { loc?: ExtractionLocationLike }> = [];\n const options: CompatibleCompilerDomParserOptions = {\n ...compilerOptions,\n comments,\n expressionPlugins,\n onError(error) {\n errors.push(error as SyntaxError & { loc?: ExtractionLocationLike });\n },\n };\n const ast = parseTemplate(source, options);\n if (errors.length === 0) {\n shiftCompilerAstLocations(ast, origin);\n return ast;\n }\n const shiftedErrorPositions = new WeakSet<object>();\n for (const error of errors) {\n if (error.loc) {\n shiftCompilerLocation(error.loc, origin, shiftedErrorPositions);\n }\n addVueError(\n context,\n error.loc ? normalizeCompilerLocation(error.loc) : undefined,\n `Could not parse a gt-vue template: ${error.message}`,\n 'Fix the Vue template syntax before extracting translations'\n );\n }\n return undefined;\n}\n\ntype ExtractionLocationLike = Parameters<typeof normalizeCompilerLocation>[0];\ntype CompilerPosition = {\n column: number;\n line: number;\n offset: number;\n};\n\n/** Omits location-only metadata while comparing persisted template content. */\nfunction comparableTemplateResults(\n results: VueExtractionOutput['results']\n): string {\n return JSON.stringify(\n results.map((result) => ({\n dataFormat: result.dataFormat,\n metadata: {\n context: result.metadata.context,\n id: result.metadata.id,\n maxChars: result.metadata.maxChars,\n requiresReview: result.metadata.requiresReview,\n },\n source: result.source,\n }))\n );\n}\n\nfunction collectScriptBlockImports(\n block: SFCBlock | null,\n scriptAnalysis: VueScriptAnalysis\n): void {\n if (!block || block.src || !isSupportedScriptLanguage(block.lang)) return;\n collectVueScriptImports(block.content, block.lang, scriptAnalysis);\n}\n\nfunction parseScriptBlock(\n block: SFCBlock | null,\n exposeToTemplate: boolean,\n context: VueExtractionContext,\n bindings: TemplateBindings,\n scriptAnalysis: VueScriptAnalysis\n): boolean {\n if (!block) return true;\n if (block.src) {\n addVueError(\n context,\n block.loc,\n 'Found an externally sourced Vue script block',\n 'Keep translation calls and gt-vue imports in the .vue file'\n );\n return false;\n }\n if (!isSupportedScriptLanguage(block.lang)) {\n addVueError(\n context,\n block.loc,\n `Found unsupported Vue script language \"${block.lang}\"`,\n 'Use JavaScript or TypeScript for gt-vue extraction'\n );\n return false;\n }\n\n return parseVueScript(\n block.content,\n block.lang,\n context,\n bindings,\n exposeToTemplate,\n scriptAnalysis\n );\n}\n\nfunction createTemplateBindings(): TemplateBindings {\n return {\n arrayLengths: new Map(),\n componentFactories: new Set(),\n components: new Map(),\n containerKinds: new Map(),\n possibleGTContainers: new Set(),\n gtContainerFactories: new Set(),\n directBindings: new Set(),\n registeredComponents: new Map(),\n registeredVueBuiltins: new Map(),\n staticValues: new Map(),\n identityFunctions: new Set(),\n possibleStaticStrings: new Map(),\n stringFunctions: new Map(),\n uncertainStringFunctions: new Set(),\n uncertainComponents: new Set(),\n uncertainGTComponents: new Set(),\n gtComponentFactories: new Set(),\n uncertainRegisteredComponents: new Set(),\n uncertainRegisteredGTComponents: new Set(),\n vueBuiltins: new Map(),\n };\n}\n\nfunction sourceUsesTypeScript(source: string): boolean {\n let offset = 0;\n while (offset < source.length) {\n const start = source.indexOf('<script', offset);\n if (start === -1) return false;\n const boundary = source[start + '<script'.length];\n if (boundary !== '>' && !boundary?.match(/\\s/)) {\n offset = start + '<script'.length;\n continue;\n }\n\n const end = findOpeningTagEnd(source, start + '<script'.length);\n if (end === -1) return false;\n const language = readOpeningTagAttribute(\n source.slice(start + '<script'.length, end),\n 'lang'\n );\n if (typeof language === 'string' && /^tsx?$/i.test(language)) return true;\n offset = end + 1;\n }\n return false;\n}\n\nfunction isSupportedScriptLanguage(language: string | undefined): boolean {\n const normalizedLanguage = language?.toLowerCase();\n return (\n normalizedLanguage === undefined ||\n normalizedLanguage === 'js' ||\n normalizedLanguage === 'jsx' ||\n normalizedLanguage === 'ts' ||\n normalizedLanguage === 'tsx'\n );\n}\n\n/** Finds an opening tag boundary while respecting quoted attribute values. */\nfunction findOpeningTagEnd(source: string, start: number): number {\n let quote: '\"' | \"'\" | undefined;\n for (let index = start; index < source.length; index += 1) {\n const character = source[index];\n if (quote) {\n if (character === quote) quote = undefined;\n } else if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '>') {\n return index;\n }\n }\n return -1;\n}\n\n/** Reads one case-sensitive SFC attribute with quoted or unquoted syntax. */\nfunction readOpeningTagAttribute(\n attributes: string,\n requestedName: string\n): string | true | undefined {\n let offset = 0;\n while (offset < attributes.length) {\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n if (attributes[offset] === '/') {\n offset += 1;\n continue;\n }\n const nameStart = offset;\n while (offset < attributes.length && !/[\\s=]/.test(attributes[offset])) {\n offset += 1;\n }\n const name = attributes.slice(nameStart, offset);\n if (!name) break;\n\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n let value: string | true = true;\n if (attributes[offset] === '=') {\n offset += 1;\n while (offset < attributes.length && /\\s/.test(attributes[offset])) {\n offset += 1;\n }\n const quote = attributes[offset];\n if (quote === '\"' || quote === \"'\") {\n offset += 1;\n const valueStart = offset;\n while (offset < attributes.length && attributes[offset] !== quote) {\n offset += 1;\n }\n value = attributes.slice(valueStart, offset);\n if (attributes[offset] === quote) offset += 1;\n } else {\n const valueStart = offset;\n while (offset < attributes.length && !/\\s/.test(attributes[offset])) {\n offset += 1;\n }\n value = attributes.slice(valueStart, offset);\n }\n }\n if (name === requestedName) return value;\n }\n return undefined;\n}\n\nfunction languageFromExtension(\n extension: string\n): Exclude<StandaloneProbeLanguage, 'flow'> {\n if (extension === '.ts' || extension === '.mts' || extension === '.cts') {\n return 'ts';\n }\n if (extension === '.tsx') return 'tsx';\n if (extension === '.jsx') return 'jsx';\n return 'js';\n}\n\nfunction normalizeCompilerLocation(location: {\n end?: { column?: number; line?: number; offset?: number };\n start?: { column?: number; line?: number; offset?: number };\n}) {\n const start = location.start ?? {};\n const end = location.end ?? start;\n return {\n start: {\n column: start.column ?? 1,\n line: start.line ?? 1,\n offset: start.offset ?? 0,\n },\n end: {\n column: end.column ?? start.column ?? 1,\n line: end.line ?? start.line ?? 1,\n offset: end.offset ?? start.offset ?? 0,\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -138,7 +138,7 @@ function parseVueScript(source, language, context, templateBindings, exposeToTem
|
|
|
138
138
|
const localCallable = resolveCalledFunction(path.node.callee, path.scope, state, /* @__PURE__ */ new Set());
|
|
139
139
|
const calleePath = readResolvedMemberPath(path.node.callee, path.scope, state);
|
|
140
140
|
const uncertainTranslationHelper = Boolean(calleePath && pathMayReferenceUncertainTranslationHelper(path.node.callee, calleePath, path.scope, state) && callArgumentsMayProvideTranslationFunction(path.node, path.scope, state));
|
|
141
|
-
if (!callTarget.definitelyOrdinary && !localCallable && calleePath && (callTarget.possibleStringFunction || uncertainTranslationHelper || templateBindings.uncertainStringFunctions.has(calleePath) || state.analysis.uncertainStringFunctions.has(calleePath) || calleePath.endsWith(".value") && templateBindings.uncertainStringFunctions.has(calleePath.slice(0, -6)))) addVueError(context, consumerLocation, `Could not statically resolve possible gt-vue string function alias "${calleePath}"`, "Use a direct, immutable alias of useGT(), useMessages(), or
|
|
141
|
+
if (!callTarget.definitelyOrdinary && !localCallable && calleePath && (callTarget.possibleStringFunction || uncertainTranslationHelper || templateBindings.uncertainStringFunctions.has(calleePath) || state.analysis.uncertainStringFunctions.has(calleePath) || calleePath.endsWith(".value") && templateBindings.uncertainStringFunctions.has(calleePath.slice(0, -6)))) addVueError(context, consumerLocation, `Could not statically resolve possible gt-vue string function alias "${calleePath}"`, "Use a direct, immutable alias of useGT(), useMessages(), msg(), or t()");
|
|
142
142
|
processForwardedTranslationCalls(path, consumerLocation);
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
@@ -374,6 +374,7 @@ function recordRuntimeReexport(source, exportNames, importerFile, state) {
|
|
|
374
374
|
if ((exportNames.includes("*") ? [
|
|
375
375
|
...COMPONENT_IMPORTS,
|
|
376
376
|
"msg",
|
|
377
|
+
"t",
|
|
377
378
|
"useGT",
|
|
378
379
|
"useMessages"
|
|
379
380
|
] : exportNames).some((name) => resolver.hasGTExportReference(modulePath, name))) state.analysis.hasGTSourceReference = true;
|
|
@@ -447,6 +448,7 @@ function recordDynamicImportPattern(pattern, source, scope, importerFile, state)
|
|
|
447
448
|
for (const exportName of [
|
|
448
449
|
...COMPONENT_IMPORTS,
|
|
449
450
|
"msg",
|
|
451
|
+
"t",
|
|
450
452
|
"useGT",
|
|
451
453
|
"useMessages"
|
|
452
454
|
]) recordDynamicImportBinding(appendTemplatePath(pattern.name, exportName), exportName, modulePath, state, bindingReferencesNamespaceMember(binding, exportName, state));
|
|
@@ -456,11 +458,13 @@ function recordDynamicImportPattern(pattern, source, scope, importerFile, state)
|
|
|
456
458
|
state.analysis.uncertainComponents.add(path);
|
|
457
459
|
state.analysis.uncertainGTComponents.add(path);
|
|
458
460
|
}
|
|
459
|
-
|
|
461
|
+
const stringFunctions = [
|
|
460
462
|
"msg",
|
|
461
463
|
"useGT",
|
|
462
464
|
"useMessages"
|
|
463
|
-
]
|
|
465
|
+
];
|
|
466
|
+
if (source === "gt-vue") stringFunctions.push("t");
|
|
467
|
+
for (const name of stringFunctions) state.analysis.uncertainStringFunctions.add(appendTemplatePath(pattern.name, name));
|
|
464
468
|
}
|
|
465
469
|
return;
|
|
466
470
|
}
|
|
@@ -470,14 +474,14 @@ function recordDynamicImportPattern(pattern, source, scope, importerFile, state)
|
|
|
470
474
|
const exportedName = readPropertyKey(property);
|
|
471
475
|
const localName = readPatternIdentifier(property.value);
|
|
472
476
|
if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state, importerFile === state.analysis.entryFile);
|
|
473
|
-
else recordUnresolvedGTShapedBinding(localName, exportedName, state);
|
|
477
|
+
else recordUnresolvedGTShapedBinding(localName, exportedName, state, source === "gt-vue");
|
|
474
478
|
}
|
|
475
479
|
for (const property of pattern.properties) {
|
|
476
480
|
if (property.type !== "ObjectProperty" || !property.computed) continue;
|
|
477
481
|
const exportedName = readResolvedPropertyKey(property, scope, state);
|
|
478
482
|
const localName = readPatternIdentifier(property.value);
|
|
479
483
|
if (exportedName && localName) if (modulePath) recordDynamicImportBinding(localName, exportedName, modulePath, state, importerFile === state.analysis.entryFile);
|
|
480
|
-
else recordUnresolvedGTShapedBinding(localName, exportedName, state);
|
|
484
|
+
else recordUnresolvedGTShapedBinding(localName, exportedName, state, source === "gt-vue");
|
|
481
485
|
}
|
|
482
486
|
}
|
|
483
487
|
/** Returns whether one namespace binding is used through a static member. */
|
|
@@ -678,6 +682,7 @@ function recordLocalNamespaceMembers(localName, modulePath, state, binding) {
|
|
|
678
682
|
...resolver.listExportNames(modulePath),
|
|
679
683
|
...COMPONENT_IMPORTS,
|
|
680
684
|
"msg",
|
|
685
|
+
"t",
|
|
681
686
|
"useGT",
|
|
682
687
|
"useMessages"
|
|
683
688
|
]);
|
|
@@ -705,27 +710,29 @@ function recordLocalNamespaceMembers(localName, modulePath, state, binding) {
|
|
|
705
710
|
/** Retains the original gt-vue role hidden by a malformed re-export alias. */
|
|
706
711
|
function recordInvalidGTResolution(localName, resolution, state) {
|
|
707
712
|
if (resolution.gtExportName === "*") {
|
|
708
|
-
recordUnresolvedGTNamespace(localName, state);
|
|
713
|
+
recordUnresolvedGTNamespace(localName, state, true);
|
|
709
714
|
return;
|
|
710
715
|
}
|
|
711
716
|
if (resolution.gtExportName) {
|
|
712
|
-
recordUnresolvedGTShapedBinding(localName, resolution.gtExportName, state);
|
|
717
|
+
recordUnresolvedGTShapedBinding(localName, resolution.gtExportName, state, true);
|
|
713
718
|
return;
|
|
714
719
|
}
|
|
715
720
|
state.analysis.uncertainTranslationHelpers.add(localName);
|
|
716
721
|
}
|
|
717
722
|
/** Marks the GT-shaped members of one unresolved namespace path. */
|
|
718
|
-
function recordUnresolvedGTNamespace(localName, state) {
|
|
723
|
+
function recordUnresolvedGTNamespace(localName, state, includeImmediateTranslation = false) {
|
|
719
724
|
for (const component of COMPONENT_IMPORTS) {
|
|
720
725
|
const componentPath = appendTemplatePath(localName, component);
|
|
721
726
|
state.analysis.uncertainComponents.add(componentPath);
|
|
722
727
|
state.analysis.uncertainGTComponents.add(componentPath);
|
|
723
728
|
}
|
|
724
|
-
|
|
729
|
+
const stringFunctions = [
|
|
725
730
|
"msg",
|
|
726
731
|
"useGT",
|
|
727
732
|
"useMessages"
|
|
728
|
-
]
|
|
733
|
+
];
|
|
734
|
+
if (includeImmediateTranslation) stringFunctions.push("t");
|
|
735
|
+
for (const name of stringFunctions) state.analysis.uncertainStringFunctions.add(appendTemplatePath(localName, name));
|
|
729
736
|
}
|
|
730
737
|
/** Records unresolved roles only when a local export can actually be GT. */
|
|
731
738
|
function recordMaterializedLocalUncertainty(localName, materialized, state, forceKnownValues = false) {
|
|
@@ -768,12 +775,12 @@ function recordUncertainTranslationHelperBinding(localName, scope, state) {
|
|
|
768
775
|
if (binding) state.uncertainTranslationHelperBindings.add(binding);
|
|
769
776
|
}
|
|
770
777
|
/** Records the conservative GT roles implied by an unresolved export name. */
|
|
771
|
-
function recordUnresolvedGTShapedBinding(localName, exportName, state) {
|
|
778
|
+
function recordUnresolvedGTShapedBinding(localName, exportName, state, includeImmediateTranslation = false) {
|
|
772
779
|
if (COMPONENT_IMPORTS.has(exportName)) {
|
|
773
780
|
state.analysis.uncertainComponents.add(localName);
|
|
774
781
|
state.analysis.uncertainGTComponents.add(localName);
|
|
775
782
|
}
|
|
776
|
-
if (exportName === "msg" || exportName === "useGT" || exportName === "useMessages") state.analysis.uncertainStringFunctions.add(localName);
|
|
783
|
+
if (exportName === "msg" || includeImmediateTranslation && exportName === "t" || exportName === "useGT" || exportName === "useMessages") state.analysis.uncertainStringFunctions.add(localName);
|
|
777
784
|
}
|
|
778
785
|
/** Fails closed when a resolved local export is ambiguous or mutable. */
|
|
779
786
|
function recordAmbiguousLocalBinding(localName, state) {
|
|
@@ -1060,6 +1067,7 @@ function exposeKnownValue(localName, value, templateBindings, analysis) {
|
|
|
1060
1067
|
else if (value.type === "namespace" && value.source === "gt-vue") {
|
|
1061
1068
|
for (const component of COMPONENT_IMPORTS) templateBindings.components.set(appendTemplatePath(localName, component), component);
|
|
1062
1069
|
templateBindings.stringFunctions.set(appendTemplatePath(localName, "msg"), "msg");
|
|
1070
|
+
templateBindings.stringFunctions.set(appendTemplatePath(localName, "t"), "t");
|
|
1063
1071
|
} else if (value.type === "namespace" && value.source === "vue") {
|
|
1064
1072
|
for (const builtin of VUE_BUILTIN_IMPORTS) templateBindings.vueBuiltins.set(appendTemplatePath(localName, builtin), builtin);
|
|
1065
1073
|
templateBindings.identityFunctions.add(appendTemplatePath(localName, "markRaw"));
|
|
@@ -1104,6 +1112,7 @@ function exposeUncertainKnownValue(localName, value, uncertainComponents, uncert
|
|
|
1104
1112
|
uncertainGTComponents.add(appendTemplatePath(localName, component));
|
|
1105
1113
|
}
|
|
1106
1114
|
uncertainStringFunctions.add(appendTemplatePath(localName, "msg"));
|
|
1115
|
+
uncertainStringFunctions.add(appendTemplatePath(localName, "t"));
|
|
1107
1116
|
} else if (value.type === "namespace" && value.source === "vue") for (const builtin of VUE_BUILTIN_IMPORTS) uncertainComponents.add(appendTemplatePath(localName, builtin));
|
|
1108
1117
|
}
|
|
1109
1118
|
/** Exposes a callable whose return can affect template component identity. */
|
|
@@ -1324,21 +1333,28 @@ function collectNamespaceRestMemberCandidates(localName, binding, pattern, value
|
|
|
1324
1333
|
return key !== void 0 ? [key] : [];
|
|
1325
1334
|
}));
|
|
1326
1335
|
const certain = isSafelyReadContainerBinding(binding, binding.identifier, Number.POSITIVE_INFINITY, true, state);
|
|
1327
|
-
return (namespace.source === "gt-vue" ? [
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1336
|
+
return (namespace.source === "gt-vue" ? [
|
|
1337
|
+
...[...COMPONENT_IMPORTS].map((name) => ({
|
|
1338
|
+
type: "component",
|
|
1339
|
+
name
|
|
1340
|
+
})),
|
|
1341
|
+
{
|
|
1342
|
+
type: "string",
|
|
1343
|
+
kind: "msg"
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
type: "string",
|
|
1347
|
+
kind: "t"
|
|
1348
|
+
}
|
|
1349
|
+
] : [...VUE_BUILTIN_IMPORTS].map((name) => ({
|
|
1334
1350
|
type: "vue-builtin",
|
|
1335
1351
|
name
|
|
1336
1352
|
}))).filter((entry) => {
|
|
1337
|
-
const name = entry.type === "component" ? entry.name : entry.type === "string" ?
|
|
1353
|
+
const name = entry.type === "component" ? entry.name : entry.type === "string" ? entry.kind : entry.name;
|
|
1338
1354
|
return !excluded.has(name);
|
|
1339
1355
|
}).map((entry) => ({
|
|
1340
1356
|
certain,
|
|
1341
|
-
name: appendTemplatePath(localName, entry.type === "component" ? entry.name : entry.type === "string" ?
|
|
1357
|
+
name: appendTemplatePath(localName, entry.type === "component" ? entry.name : entry.type === "string" ? entry.kind : entry.name),
|
|
1342
1358
|
value: entry
|
|
1343
1359
|
}));
|
|
1344
1360
|
}
|
|
@@ -2171,13 +2187,12 @@ function resolveKnownExpression(node, scope, state, seen) {
|
|
|
2171
2187
|
if (expression.type === "LogicalExpression") {
|
|
2172
2188
|
const left = resolveKnownExpression(expression.left, scope, state, new Set(seen));
|
|
2173
2189
|
if (left) return expression.operator === "&&" ? resolveKnownExpression(expression.right, scope, state, new Set(seen)) : left;
|
|
2174
|
-
const
|
|
2175
|
-
|
|
2176
|
-
return (expression.operator === "??" ? staticLeft.value == null : expression.operator === "||" ? !staticLeft.value : Boolean(staticLeft.value)) ? resolveKnownExpression(expression.right, scope, state, new Set(seen)) : void 0;
|
|
2190
|
+
const selection = readStaticLogicalSelection(expression, scope, state, new Set(seen));
|
|
2191
|
+
return selection ? resolveKnownExpression(expression[selection], scope, state, new Set(seen)) : void 0;
|
|
2177
2192
|
}
|
|
2178
2193
|
if (expression.type === "ConditionalExpression") {
|
|
2179
|
-
const condition =
|
|
2180
|
-
if (condition
|
|
2194
|
+
const condition = readStaticTruthiness(expression.test, scope, state, new Set(seen));
|
|
2195
|
+
if (condition) return resolveKnownExpression(condition === "truthy" ? expression.consequent : expression.alternate, scope, state, new Set(seen));
|
|
2181
2196
|
const consequent = resolveKnownExpression(expression.consequent, scope, state, new Set(seen));
|
|
2182
2197
|
const alternate = resolveKnownExpression(expression.alternate, scope, state, new Set(seen));
|
|
2183
2198
|
return consequent && alternate && knownValueKey(consequent) === knownValueKey(alternate) ? consequent : void 0;
|
|
@@ -3629,6 +3644,31 @@ function bindingMayReferenceStringFunction(binding, state) {
|
|
|
3629
3644
|
if (declaration.type === "VariableDeclarator" && declaration.init && patternMayProduceStringFunction(declaration.id, declaration.init, binding.identifier.name, binding.path.scope, state, new Set([binding]))) return true;
|
|
3630
3645
|
return binding.constantViolations.some((violation) => violation.isAssignmentExpression() && patternContains(violation.node.left, binding.identifier.name) && expressionMayProduceStringFunction(violation.node.right, violation.scope, state, new Set([binding])));
|
|
3631
3646
|
}
|
|
3647
|
+
/** Evaluates only side-effect-free truthiness needed for static branch choice. */
|
|
3648
|
+
function readStaticTruthiness(node, scope, state, seen) {
|
|
3649
|
+
const expression = unwrapExpression(node);
|
|
3650
|
+
if (!expression) return void 0;
|
|
3651
|
+
const primitive = readStaticFromScope(expression, scope, new Set(seen), expression.end ?? Number.POSITIVE_INFINITY, state.analysis);
|
|
3652
|
+
if (primitive.ok) {
|
|
3653
|
+
if (primitive.value == null) return "nullish";
|
|
3654
|
+
return primitive.value ? "truthy" : "falsy";
|
|
3655
|
+
}
|
|
3656
|
+
if (expression.type === "ConditionalExpression" || expression.type === "LogicalExpression") return;
|
|
3657
|
+
if (resolveKnownExpression(expression, scope, state, new Set(seen))) return "truthy";
|
|
3658
|
+
if (expression.type === "ArrayExpression" || expression.type === "ArrowFunctionExpression" || expression.type === "ClassExpression" || expression.type === "FunctionExpression" || expression.type === "ObjectExpression" || expression.type === "RegExpLiteral") return "truthy";
|
|
3659
|
+
if (expression.type === "Identifier") {
|
|
3660
|
+
const binding = scope.getBinding(expression.name);
|
|
3661
|
+
if (!binding) return expression.name !== "undefined" && ORDINARY_GLOBAL_VALUES.has(expression.name) ? "truthy" : void 0;
|
|
3662
|
+
if (!binding.constant || seen.has(binding)) return void 0;
|
|
3663
|
+
if (binding.path.isClassDeclaration() || binding.path.isFunctionDeclaration()) return "truthy";
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
/** Selects a logical branch when the left value's truthiness is static. */
|
|
3667
|
+
function readStaticLogicalSelection(expression, scope, state, seen = /* @__PURE__ */ new Set()) {
|
|
3668
|
+
const value = readStaticTruthiness(expression.left, scope, state, seen);
|
|
3669
|
+
if (!value) return void 0;
|
|
3670
|
+
return (expression.operator === "??" ? value === "nullish" : expression.operator === "||" ? value !== "truthy" : value === "truthy") ? "right" : "left";
|
|
3671
|
+
}
|
|
3632
3672
|
/** Tracks expressions whose resulting value can be a gt-vue string function. */
|
|
3633
3673
|
function expressionMayProduceStringFunction(node, scope, state, seen) {
|
|
3634
3674
|
if (state.analysis.stats) state.analysis.stats.stringFunctionVisits += 1;
|
|
@@ -3667,8 +3707,16 @@ function expressionMayProduceStringFunction(node, scope, state, seen) {
|
|
|
3667
3707
|
}
|
|
3668
3708
|
return expression.arguments.some((argument) => argument.type !== "ArgumentPlaceholder" && (expressionMayProduceStringFunction(argument.type === "SpreadElement" ? argument.argument : argument, scope, state, seen) || containerMayContainStringFunction(argument.type === "SpreadElement" ? argument.argument : argument, scope, state, /* @__PURE__ */ new Set())));
|
|
3669
3709
|
}
|
|
3670
|
-
if (expression.type === "ConditionalExpression")
|
|
3671
|
-
|
|
3710
|
+
if (expression.type === "ConditionalExpression") {
|
|
3711
|
+
const condition = readStaticTruthiness(expression.test, scope, state, seen);
|
|
3712
|
+
if (condition) return expressionMayProduceStringFunction(condition === "truthy" ? expression.consequent : expression.alternate, scope, state, seen);
|
|
3713
|
+
return expressionMayProduceStringFunction(expression.consequent, scope, state, seen) || expressionMayProduceStringFunction(expression.alternate, scope, state, seen);
|
|
3714
|
+
}
|
|
3715
|
+
if (expression.type === "LogicalExpression") {
|
|
3716
|
+
const selection = readStaticLogicalSelection(expression, scope, state);
|
|
3717
|
+
if (selection) return expressionMayProduceStringFunction(expression[selection], scope, state, seen);
|
|
3718
|
+
return expressionMayProduceStringFunction(expression.left, scope, state, seen) || expressionMayProduceStringFunction(expression.right, scope, state, seen);
|
|
3719
|
+
}
|
|
3672
3720
|
if (expression.type === "SequenceExpression") return expressionMayProduceStringFunction(expression.expressions.at(-1), scope, state, seen);
|
|
3673
3721
|
if (expression.type === "AssignmentExpression") return expressionMayProduceStringFunction(expression.right, scope, state, seen);
|
|
3674
3722
|
if (expression.type === "AwaitExpression" || expression.type === "YieldExpression") return expressionMayProduceStringFunction(expression.argument, scope, state, seen);
|