@generaltranslation/vue-extractor 0.0.0 → 0.1.0-iris.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE.md +18 -102
  2. package/dist/detect.d.ts +8 -0
  3. package/dist/detect.js +2 -0
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +2 -1
  6. package/dist/inspect.d.ts +9 -0
  7. package/dist/inspect.js +2 -0
  8. package/dist/integration.d.ts +69 -0
  9. package/dist/integration.js +162 -0
  10. package/dist/integration.js.map +1 -0
  11. package/dist/internal/config/configFiles.d.ts +6 -0
  12. package/dist/internal/config/configFiles.js +34 -0
  13. package/dist/internal/config/configFiles.js.map +1 -0
  14. package/dist/internal/config/resolveVueCompilerOptions.d.ts +6 -0
  15. package/dist/internal/config/resolveVueCompilerOptions.js +74 -56
  16. package/dist/internal/config/resolveVueCompilerOptions.js.map +1 -1
  17. package/dist/internal/extractFromVueSource.d.ts +4 -3
  18. package/dist/internal/extractFromVueSource.js +255 -12
  19. package/dist/internal/extractFromVueSource.js.map +1 -1
  20. package/dist/internal/project/consumerUsage.d.ts +34 -0
  21. package/dist/internal/project/consumerUsage.js +1220 -0
  22. package/dist/internal/project/consumerUsage.js.map +1 -0
  23. package/dist/internal/project/detectVueProject.d.ts +13 -0
  24. package/dist/internal/project/detectVueProject.js +65 -0
  25. package/dist/internal/project/detectVueProject.js.map +1 -0
  26. package/dist/internal/project/extractFromVueProject.d.ts +10 -0
  27. package/dist/internal/project/extractFromVueProject.js +579 -0
  28. package/dist/internal/project/extractFromVueProject.js.map +1 -0
  29. package/dist/internal/project/inspectVueProject.d.ts +48 -0
  30. package/dist/internal/project/inspectVueProject.js +143 -0
  31. package/dist/internal/project/inspectVueProject.js.map +1 -0
  32. package/dist/internal/project/manifest.d.ts +64 -0
  33. package/dist/internal/project/manifest.js +270 -0
  34. package/dist/internal/project/manifest.js.map +1 -0
  35. package/dist/internal/project/mergeVueProjectExtraction.d.ts +18 -0
  36. package/dist/internal/project/mergeVueProjectExtraction.js +79 -0
  37. package/dist/internal/project/mergeVueProjectExtraction.js.map +1 -0
  38. package/dist/internal/project/moduleResolver.d.ts +18 -0
  39. package/dist/internal/project/moduleResolver.js +325 -0
  40. package/dist/internal/project/moduleResolver.js.map +1 -0
  41. package/dist/internal/project/scopes.d.ts +31 -0
  42. package/dist/internal/project/scopes.js +182 -0
  43. package/dist/internal/project/scopes.js.map +1 -0
  44. package/dist/internal/project/sourcePatterns.d.ts +4 -0
  45. package/dist/internal/project/sourcePatterns.js +32 -0
  46. package/dist/internal/project/sourcePatterns.js.map +1 -0
  47. package/dist/internal/project/viteAliases.d.ts +42 -0
  48. package/dist/internal/project/viteAliases.js +1020 -0
  49. package/dist/internal/project/viteAliases.js.map +1 -0
  50. package/dist/internal/project/vueSourceClassification.d.ts +13 -0
  51. package/dist/internal/project/vueSourceClassification.js +146 -0
  52. package/dist/internal/project/vueSourceClassification.js.map +1 -0
  53. package/dist/internal/project/workspaces.d.ts +31 -0
  54. package/dist/internal/project/workspaces.js +326 -0
  55. package/dist/internal/project/workspaces.js.map +1 -0
  56. package/dist/internal/project/wrapperProvenance.d.ts +21 -0
  57. package/dist/internal/project/wrapperProvenance.js +287 -0
  58. package/dist/internal/project/wrapperProvenance.js.map +1 -0
  59. package/dist/internal/script/analyze.js +323 -108
  60. package/dist/internal/script/analyze.js.map +1 -1
  61. package/dist/internal/script/jsx.d.ts +7 -4
  62. package/dist/internal/script/jsx.js +351 -79
  63. package/dist/internal/script/jsx.js.map +1 -1
  64. package/dist/internal/script/knownValues.js +4 -0
  65. package/dist/internal/script/knownValues.js.map +1 -1
  66. package/dist/internal/script/localModules.d.ts +23 -2
  67. package/dist/internal/script/localModules.js +535 -20
  68. package/dist/internal/script/localModules.js.map +1 -1
  69. package/dist/internal/script/model.d.ts +10 -3
  70. package/dist/internal/script/parser.js +2 -1
  71. package/dist/internal/script/parser.js.map +1 -1
  72. package/dist/internal/script/runtimeModules.d.ts +10 -0
  73. package/dist/internal/script/runtimeModules.js +27 -0
  74. package/dist/internal/script/runtimeModules.js.map +1 -0
  75. package/dist/internal/stringCalls.js +9 -3
  76. package/dist/internal/stringCalls.js.map +1 -1
  77. package/dist/internal/template.js +263 -141
  78. package/dist/internal/template.js.map +1 -1
  79. package/dist/internal/types.d.ts +5 -2
  80. package/dist/internal/utils.d.ts +14 -3
  81. package/dist/internal/utils.js +63 -3
  82. package/dist/internal/utils.js.map +1 -1
  83. package/dist/internal/vueCompiler.d.ts +9 -1
  84. package/dist/internal/vueCompiler.js +37 -14
  85. package/dist/internal/vueCompiler.js.map +1 -1
  86. package/dist/project.d.ts +11 -0
  87. package/dist/project.js +3 -0
  88. package/dist/types.d.ts +95 -4
  89. package/package.json +30 -4
@@ -0,0 +1,1220 @@
1
+ import { readJavaScriptPackageManifest } from "./manifest.js";
2
+ import { parseScriptAst } from "../script/parser.js";
3
+ import { DEFAULT_VUE_SOURCE_DIRECTORIES } from "./sourcePatterns.js";
4
+ import { readPublicGTImports, readPublicImportEntries } from "./wrapperProvenance.js";
5
+ import { classifyVueSource } from "./vueSourceClassification.js";
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import traverseModule from "@babel/traverse";
9
+ import * as t from "@babel/types";
10
+ //#region src/internal/project/consumerUsage.ts
11
+ const traverse = traverseModule.default || traverseModule;
12
+ const CONSUMER_SOURCE_EXTENSIONS = new Set([
13
+ ".cjs",
14
+ ".cts",
15
+ ".js",
16
+ ".jsx",
17
+ ".mjs",
18
+ ".mts",
19
+ ".ts",
20
+ ".tsx",
21
+ ".vue"
22
+ ]);
23
+ const IGNORED_CONSUMER_DIRECTORIES = new Set([
24
+ "build",
25
+ "coverage",
26
+ "dist",
27
+ "node_modules",
28
+ "out",
29
+ "storybook-static",
30
+ "target",
31
+ "temp",
32
+ "tmp"
33
+ ]);
34
+ const GENERATED_CONSUMER_ROOT_DIRECTORIES = new Set([
35
+ "cjs",
36
+ "es",
37
+ "esm",
38
+ "generated",
39
+ "lib",
40
+ "lib-esm"
41
+ ]);
42
+ /** Prevents wrapper-use detection from walking an unbounded package tree. */
43
+ const MAX_CONSUMER_SOURCE_FILES = 2e4;
44
+ /** Creates an edit-fresh cache for one project detection or inspection. */
45
+ function createConsumerUsageCache() {
46
+ return {
47
+ consumers: /* @__PURE__ */ new Map(),
48
+ publicImports: /* @__PURE__ */ new Map(),
49
+ queries: /* @__PURE__ */ new Map()
50
+ };
51
+ }
52
+ /**
53
+ * Returns whether consumer source actually imports a wrapper's public GT API.
54
+ *
55
+ * A dependency can expose separate React and Vue entrypoints. Package
56
+ * metadata alone cannot tell which one an application uses, so Vue ownership
57
+ * propagates only through a static value import or re-export of the exact
58
+ * public subpath and export name. The dependency binding name is kept
59
+ * separate from the package's declared name so npm/workspace aliases retain
60
+ * their consumer-visible specifiers.
61
+ */
62
+ function packageConsumesPublicGT(consumerDirectory, dependencyName, packageDirectory, manifest, cache = createConsumerUsageCache()) {
63
+ const packageName = readPackageName(manifest);
64
+ if (!packageName) return false;
65
+ const consumerRoot = resolveRealPath(consumerDirectory);
66
+ const packageRoot = resolveRealPath(packageDirectory);
67
+ const queryKey = `${consumerRoot}\0${dependencyName}\0${packageRoot}`;
68
+ const cachedQuery = cache.queries.get(queryKey);
69
+ if (cachedQuery !== void 0) return cachedQuery;
70
+ let packagePublicImports = cache.publicImports.get(packageRoot);
71
+ if (!packagePublicImports) {
72
+ packagePublicImports = readPublicGTImports(packageDirectory, manifest);
73
+ cache.publicImports.set(packageRoot, packagePublicImports);
74
+ }
75
+ const publicImports = packagePublicImports.map(({ entry: _entry, exportNames, specifier }) => ({
76
+ exportNames,
77
+ specifier: `${dependencyName}${specifier.slice(packageName.length)}`
78
+ }));
79
+ if (publicImports.length === 0) return false;
80
+ const importsBySpecifier = /* @__PURE__ */ new Map();
81
+ for (const { exportNames, specifier } of publicImports) {
82
+ const existing = importsBySpecifier.get(specifier);
83
+ importsBySpecifier.set(specifier, existing ? new Set([...existing, ...exportNames]) : exportNames);
84
+ }
85
+ const result = consumerSourceUsesGT(consumerRoot, importsBySpecifier, cache);
86
+ cache.queries.set(queryKey, result);
87
+ return result;
88
+ }
89
+ /** Returns whether a wrapper exposes any public gt-vue-derived value. */
90
+ function packageExposesPublicGT(packageDirectory, manifest, cache) {
91
+ const packageRoot = resolveRealPath(packageDirectory);
92
+ let publicImports = cache.publicImports.get(packageRoot);
93
+ if (!publicImports) {
94
+ publicImports = readPublicGTImports(packageDirectory, manifest);
95
+ cache.publicImports.set(packageRoot, publicImports);
96
+ }
97
+ return publicImports.length > 0;
98
+ }
99
+ /** Scans one package boundary for static imports of its dependency's GT API. */
100
+ function consumerSourceUsesGT(consumerDirectory, importsBySpecifier, cache) {
101
+ let consumer = cache.consumers.get(consumerDirectory);
102
+ if (!consumer) {
103
+ consumer = createConsumerSourceIndex(consumerDirectory);
104
+ cache.consumers.set(consumerDirectory, consumer);
105
+ }
106
+ if (consumerImportIndexMatches(consumer.importsBySpecifier, importsBySpecifier)) return true;
107
+ while (!consumer.exhausted) {
108
+ const file = readNextConsumerSourceFile(consumer);
109
+ if (!file) break;
110
+ mergeConsumerImports(consumer.importsBySpecifier, readConsumerImports(file));
111
+ if (consumerImportIndexMatches(consumer.importsBySpecifier, importsBySpecifier)) return true;
112
+ }
113
+ return false;
114
+ }
115
+ /** Creates a lazy, single-pass source index for one consumer package. */
116
+ function createConsumerSourceIndex(root) {
117
+ const pendingFiles = /* @__PURE__ */ new Set();
118
+ const consumerManifest = readJavaScriptPackageManifest(path.join(root, "package.json"));
119
+ if (consumerManifest) {
120
+ for (const { entry } of readPublicImportEntries(root, consumerManifest)) if (isConsumerSourceFile(entry) && !isIgnoredConsumerPath(root, entry)) pendingFiles.add(entry);
121
+ }
122
+ try {
123
+ for (const entry of fs.readdirSync(root, { withFileTypes: true })) if (entry.isFile() && path.extname(entry.name).toLowerCase() === ".vue") pendingFiles.add(path.join(root, entry.name));
124
+ } catch {}
125
+ return {
126
+ exhausted: false,
127
+ importsBySpecifier: /* @__PURE__ */ new Map(),
128
+ pendingDirectories: DEFAULT_VUE_SOURCE_DIRECTORIES.map((directory) => path.join(root, directory)).filter((directory) => isContainedPhysicalDirectory(root, directory)).reverse(),
129
+ pendingFiles: [...pendingFiles].reverse(),
130
+ root,
131
+ seenFiles: /* @__PURE__ */ new Set(),
132
+ sourceFiles: 0
133
+ };
134
+ }
135
+ /** Returns each consumer source file at most once across every wrapper query. */
136
+ function readNextConsumerSourceFile(consumer) {
137
+ while (true) {
138
+ const pendingFile = consumer.pendingFiles.pop();
139
+ if (pendingFile) {
140
+ const file = resolveRealPath(pendingFile);
141
+ if (consumer.seenFiles.has(file) || !isConsumerSourceFile(file)) continue;
142
+ consumer.seenFiles.add(file);
143
+ consumer.sourceFiles += 1;
144
+ if (consumer.sourceFiles > MAX_CONSUMER_SOURCE_FILES) {
145
+ consumer.exhausted = true;
146
+ return;
147
+ }
148
+ return file;
149
+ }
150
+ const current = consumer.pendingDirectories.pop();
151
+ if (!current) {
152
+ consumer.exhausted = true;
153
+ return;
154
+ }
155
+ if (fs.existsSync(path.join(current, "package.json"))) continue;
156
+ let entries;
157
+ try {
158
+ entries = fs.readdirSync(current, { withFileTypes: true });
159
+ } catch {
160
+ continue;
161
+ }
162
+ const sourceFiles = [];
163
+ for (const entry of entries) {
164
+ if (shouldIgnoreConsumerEntry(entry)) continue;
165
+ const candidate = path.join(current, entry.name);
166
+ if (entry.isDirectory()) consumer.pendingDirectories.push(candidate);
167
+ else if (entry.isFile() && isConsumerSourceFile(candidate)) sourceFiles.push(candidate);
168
+ }
169
+ consumer.pendingFiles.push(...sourceFiles.reverse());
170
+ }
171
+ }
172
+ function mergeConsumerImports(importsBySpecifier, imports) {
173
+ for (const consumerImport of imports) {
174
+ const existing = importsBySpecifier.get(consumerImport.source);
175
+ if (existing === "*" || consumerImport.importedNames === "*") {
176
+ importsBySpecifier.set(consumerImport.source, "*");
177
+ continue;
178
+ }
179
+ importsBySpecifier.set(consumerImport.source, new Set([...existing ?? [], ...consumerImport.importedNames]));
180
+ }
181
+ }
182
+ function consumerImportIndexMatches(consumerImports, gtImports) {
183
+ for (const [specifier, gtExportNames] of gtImports) {
184
+ const importedNames = consumerImports.get(specifier);
185
+ if (importedNames === "*" || importedNames && [...importedNames].some((name) => gtExportNames.has(name))) return true;
186
+ }
187
+ return false;
188
+ }
189
+ function shouldIgnoreConsumerEntry(entry) {
190
+ return entry.isSymbolicLink() || entry.isDirectory() && (entry.name.startsWith(".") || IGNORED_CONSUMER_DIRECTORIES.has(entry.name));
191
+ }
192
+ /** Accepts executable source while rejecting ambient declaration artifacts. */
193
+ function isConsumerSourceFile(file) {
194
+ const fileName = path.basename(file).toLowerCase();
195
+ if (/\.d\.(?:c|m)?ts$/.test(fileName)) return false;
196
+ return CONSUMER_SOURCE_EXTENSIONS.has(path.extname(fileName));
197
+ }
198
+ /** Rejects public entries that resolve only into generated package output. */
199
+ function isIgnoredConsumerPath(root, file) {
200
+ const relative = path.relative(root, file);
201
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return true;
202
+ const directories = relative.split(path.sep).slice(0, -1);
203
+ const rootDirectory = directories[0]?.toLowerCase();
204
+ return Boolean(rootDirectory && GENERATED_CONSUMER_ROOT_DIRECTORIES.has(rootDirectory) || directories.some((segment) => {
205
+ const normalized = segment.toLowerCase();
206
+ return segment.startsWith(".") || IGNORED_CONSUMER_DIRECTORIES.has(normalized);
207
+ }));
208
+ }
209
+ /** Parses regular modules and the executable script blocks of Vue SFCs. */
210
+ function readConsumerImports(file) {
211
+ let source;
212
+ try {
213
+ source = fs.readFileSync(file, "utf8");
214
+ } catch {
215
+ return [];
216
+ }
217
+ const extension = path.extname(file).toLowerCase();
218
+ if (extension === ".vue") {
219
+ if (classifyVueSource(source) === "non-sfc") return readScriptImports(source, "tsx");
220
+ const { blocks, templateSource } = readVueScriptBlocks(source);
221
+ const parsedBlocks = blocks.map((block) => ({
222
+ ...block,
223
+ ast: parseConsumerScript(block.source, block.language)
224
+ }));
225
+ const hasScriptSetup = parsedBlocks.some(({ ast, setup, source }) => setup && Boolean(ast) && Boolean(source.trim()));
226
+ const templateBindings = hasScriptSetup ? readTemplateBindingMetadata(parsedBlocks) : void 0;
227
+ const siblingExternalUsage = readSiblingExternalUsage(parsedBlocks);
228
+ return parsedBlocks.flatMap(({ ast, setup }) => ast ? collectStaticImports(ast, {
229
+ externalUsage: siblingExternalUsage.get(ast.program),
230
+ scriptSetup: setup,
231
+ templateBindings,
232
+ templateSource: hasScriptSetup ? templateSource : void 0
233
+ }) : []);
234
+ }
235
+ const language = extension === ".mjs" || extension === ".cjs" ? "js" : extension === ".mts" || extension === ".cts" ? "ts" : extension.slice(1);
236
+ return readScriptImports(source, language);
237
+ }
238
+ /** Reads SFC script blocks without loading a project Vue compiler. */
239
+ function readVueScriptBlocks(source) {
240
+ const blocks = [];
241
+ const templateSources = [];
242
+ for (const block of readTopLevelSfcBlocks(source)) {
243
+ if (block.name === "template") {
244
+ templateSources.push(block.source);
245
+ continue;
246
+ }
247
+ if (block.name !== "script") continue;
248
+ const attributes = readTemplateAttributes(block.attributes);
249
+ blocks.push({
250
+ language: attributes.find(({ name }) => name === "lang")?.value,
251
+ setup: attributes.some(({ name }) => name === "setup"),
252
+ source: block.source
253
+ });
254
+ }
255
+ return {
256
+ blocks,
257
+ templateSource: templateSources.join("\n")
258
+ };
259
+ }
260
+ /** Collects unresolved runtime references made from every sibling SFC block. */
261
+ function readSiblingExternalUsage(blocks) {
262
+ const usages = /* @__PURE__ */ new Map();
263
+ const parsedBlocks = blocks.filter((block) => Boolean(block.ast));
264
+ for (const target of parsedBlocks) {
265
+ const usage = createTemplateUsage();
266
+ let hasSibling = false;
267
+ for (const source of parsedBlocks) {
268
+ if (source.ast.program === target.ast.program) continue;
269
+ hasSibling = true;
270
+ collectTemplateAstUsage(source.ast, usage, /* @__PURE__ */ new Map(), source.setup);
271
+ }
272
+ if (hasSibling) usages.set(target.ast.program, usage);
273
+ }
274
+ return usages;
275
+ }
276
+ /** Reads real top-level SFC blocks without loading the Vue compiler. */
277
+ function readTopLevelSfcBlocks(source) {
278
+ const blocks = [];
279
+ let index = 0;
280
+ while (index < source.length) {
281
+ if (source.startsWith("<!--", index)) {
282
+ index = readHtmlCommentEnd(source, index);
283
+ continue;
284
+ }
285
+ if (source[index] !== "<") {
286
+ index += 1;
287
+ continue;
288
+ }
289
+ const tag = readMarkupTag(source, index);
290
+ if (!tag) {
291
+ index += 1;
292
+ continue;
293
+ }
294
+ index = tag.end;
295
+ if (tag.closing || tag.selfClosing) continue;
296
+ const closingTag = tag.name === "script" || tag.name === "style" ? findRawBlockClosingTag(source, tag.name, tag.end) : findStructuredBlockClosingTag(source, tag.name, tag.end);
297
+ if (!closingTag) continue;
298
+ if (tag.name === "script" || tag.name === "template") blocks.push({
299
+ attributes: tag.attributes,
300
+ name: tag.name,
301
+ source: source.slice(tag.end, closingTag.start)
302
+ });
303
+ index = closingTag.end;
304
+ }
305
+ return blocks;
306
+ }
307
+ /** Reads one quote-aware markup tag at an exact source offset. */
308
+ function readMarkupTag(source, start) {
309
+ if (source[start] !== "<" || source.startsWith("<!--", start)) return;
310
+ let cursor = start + 1;
311
+ const closing = source[cursor] === "/";
312
+ if (closing) cursor += 1;
313
+ const nameStart = cursor;
314
+ while (cursor < source.length && /[A-Za-z0-9:_-]/.test(source[cursor])) cursor += 1;
315
+ if (cursor === nameStart) return void 0;
316
+ const name = source.slice(nameStart, cursor).toLowerCase();
317
+ const attributesStart = cursor;
318
+ let quote;
319
+ while (cursor < source.length) {
320
+ const character = source[cursor];
321
+ if (quote) {
322
+ if (character === quote) quote = void 0;
323
+ } else if (character === "\"" || character === "'") quote = character;
324
+ else if (character === ">") {
325
+ const attributes = source.slice(attributesStart, cursor);
326
+ return {
327
+ attributes,
328
+ closing,
329
+ end: cursor + 1,
330
+ name,
331
+ selfClosing: !closing && /\/\s*$/.test(attributes),
332
+ start
333
+ };
334
+ }
335
+ cursor += 1;
336
+ }
337
+ }
338
+ /** Finds a raw-text script/style closing tag using HTML parsing semantics. */
339
+ function findRawBlockClosingTag(source, name, start) {
340
+ const expression = new RegExp(`<\\/\\s*${escapeRegularExpression(name)}\\s*>`, "gi");
341
+ expression.lastIndex = start;
342
+ const match = expression.exec(source);
343
+ return match ? readMarkupTag(source, match.index) : void 0;
344
+ }
345
+ /** Finds a matching structured block while respecting comments and nesting. */
346
+ function findStructuredBlockClosingTag(source, name, start) {
347
+ let depth = 1;
348
+ let index = start;
349
+ while (index < source.length) {
350
+ if (source.startsWith("<!--", index)) {
351
+ index = readHtmlCommentEnd(source, index);
352
+ continue;
353
+ }
354
+ if (source[index] !== "<") {
355
+ index += 1;
356
+ continue;
357
+ }
358
+ const tag = readMarkupTag(source, index);
359
+ if (!tag) {
360
+ index += 1;
361
+ continue;
362
+ }
363
+ index = tag.end;
364
+ if (tag.name !== name) continue;
365
+ if (tag.closing) {
366
+ depth -= 1;
367
+ if (depth === 0) return tag;
368
+ } else if (!tag.selfClosing) depth += 1;
369
+ }
370
+ }
371
+ function readHtmlCommentEnd(source, start) {
372
+ const end = source.indexOf("-->", start + 4);
373
+ return end < 0 ? source.length : end + 3;
374
+ }
375
+ /** Accepts project-compatible syntax while extracting only static ESM edges. */
376
+ function readScriptImports(source, declaredLanguage) {
377
+ const ast = parseConsumerScript(source, declaredLanguage);
378
+ return ast ? collectStaticImports(ast) : [];
379
+ }
380
+ /** Parses syntax accepted by consumer discovery without requiring Vue. */
381
+ function parseConsumerScript(source, declaredLanguage) {
382
+ const languages = new Set([declaredLanguage]);
383
+ languages.add("tsx");
384
+ if (declaredLanguage === "js" || declaredLanguage === "jsx" || declaredLanguage === "tsx") languages.add("flow");
385
+ for (const language of languages) try {
386
+ return parseScriptAst(source, language);
387
+ } catch {}
388
+ }
389
+ const TEMPLATE_BINDING_RESOLUTION_ORDER = [
390
+ "setup-const",
391
+ "setup-reactive-const",
392
+ "literal-const",
393
+ "setup-let",
394
+ "setup-ref",
395
+ "setup-maybe-ref",
396
+ "props"
397
+ ];
398
+ /**
399
+ * Reproduces the binding metadata needed by Vue's component-tag resolver.
400
+ *
401
+ * Project detection cannot load a consumer's Vue compiler before ownership is
402
+ * proven. This self-contained model lets the detector choose one setup binding
403
+ * with Vue's type and spelling precedence without introducing a compiler
404
+ * dependency into the lightweight entrypoint. Where supported Vue versions or
405
+ * compiler options differ, the stronger local binding wins so ambiguous source
406
+ * cannot activate Vue in an existing non-Vue project.
407
+ */
408
+ function readTemplateBindingMetadata(blocks) {
409
+ const bindings = /* @__PURE__ */ new Map();
410
+ const normalBlocks = blocks.filter(({ setup }) => !setup);
411
+ const setupBlocks = blocks.filter(({ setup }) => setup);
412
+ const vueImportAliases = /* @__PURE__ */ new Map();
413
+ for (const block of [...normalBlocks, ...setupBlocks]) {
414
+ if (!block.ast) continue;
415
+ registerTemplateImportBindings(block.ast, bindings, vueImportAliases);
416
+ }
417
+ for (const block of normalBlocks) {
418
+ if (!block.ast) continue;
419
+ registerOptionsApiSetupBindings(block.ast, bindings);
420
+ }
421
+ for (const block of normalBlocks) {
422
+ if (!block.ast) continue;
423
+ registerTemplateDeclarationBindings(block.ast, bindings, vueImportAliases, "script", true);
424
+ }
425
+ for (const block of setupBlocks) {
426
+ if (!block.ast) continue;
427
+ registerTemplateDeclarationBindings(block.ast, bindings, vueImportAliases, "script-setup", normalBlocks.length === 0);
428
+ }
429
+ return bindings;
430
+ }
431
+ /** Adds statically named Options API setup-return bindings used by templates. */
432
+ function registerOptionsApiSetupBindings(ast, bindings) {
433
+ for (const statement of ast.program.body) {
434
+ if (statement.type !== "ExportDefaultDeclaration" || statement.declaration.type !== "ObjectExpression") continue;
435
+ for (const property of statement.declaration.properties) {
436
+ if (property.type !== "ObjectMethod" || property.computed || property.key.type !== "Identifier" || property.key.name !== "setup") continue;
437
+ for (const bodyItem of property.body.body) {
438
+ if (bodyItem.type !== "ReturnStatement" || bodyItem.argument?.type !== "ObjectExpression") continue;
439
+ for (const returnedProperty of bodyItem.argument.properties) {
440
+ if (returnedProperty.type === "SpreadElement") continue;
441
+ const name = readStaticObjectKey(returnedProperty);
442
+ if (name && !bindings.has(name)) setTemplateBinding(bindings, name, "setup-maybe-ref", ast.program);
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+ /** Mirrors compiler-sfc's static Options API object-key resolution. */
449
+ function readStaticObjectKey(property) {
450
+ const key = property.key;
451
+ if (key.type === "Identifier" && !property.computed) return key.name;
452
+ if (key.type === "StringLiteral" || key.type === "NumericLiteral") return String(key.value);
453
+ if (key.type === "TemplateLiteral" && key.expressions.length === 0) return key.quasis.map((quasi) => quasi.value.cooked ?? "").join("");
454
+ }
455
+ function registerTemplateImportBindings(ast, bindings, vueImportAliases) {
456
+ for (const statement of ast.program.body) {
457
+ if (statement.type !== "ImportDeclaration" || statement.importKind === "type" || statement.importKind === "typeof") continue;
458
+ const source = statement.source.value;
459
+ for (const specifier of statement.specifiers) {
460
+ if (specifier.type === "ImportSpecifier" && (specifier.importKind === "type" || specifier.importKind === "typeof")) continue;
461
+ const imported = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.type === "ImportNamespaceSpecifier" ? "*" : readModuleName(specifier.imported);
462
+ if (source === "vue") vueImportAliases.set(imported, specifier.local.name);
463
+ if (!bindings.has(specifier.local.name)) setTemplateBinding(bindings, specifier.local.name, imported === "*" || imported === "default" && source.endsWith(".vue") || source === "vue" ? "setup-const" : "setup-maybe-ref", ast.program);
464
+ }
465
+ }
466
+ }
467
+ /** Adds script declarations after imports in compiler-sfc's merge order. */
468
+ function registerTemplateDeclarationBindings(ast, bindings, vueImportAliases, source, hoistStatic) {
469
+ for (const statement of ast.program.body) {
470
+ const declaration = statement.type === "ExportNamedDeclaration" && statement.declaration ? statement.declaration : statement;
471
+ if ((declaration.type === "VariableDeclaration" || declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration" || declaration.type === "TSEnumDeclaration") && !declaration.declare) walkTemplateDeclaration(declaration, bindings, vueImportAliases, ast.program, source, hoistStatic);
472
+ }
473
+ }
474
+ /** Mirrors compiler-sfc's binding-type analysis used by component lookup. */
475
+ function walkTemplateDeclaration(declaration, bindings, vueImportAliases, owner, source, hoistStatic) {
476
+ if (declaration.type === "VariableDeclaration") {
477
+ const isConst = declaration.kind === "const";
478
+ const isAllLiteral = isConst && declaration.declarations.every(({ id, init }) => id.type === "Identifier" && isStaticTemplateBinding(init));
479
+ for (const { id, init: wrappedInitializer } of declaration.declarations) {
480
+ const initializer = unwrapTemplateBindingExpression(wrappedInitializer);
481
+ const isConstMacroCall = isConst && isTemplateCallOf(initializer, [
482
+ "defineProps",
483
+ "defineEmits",
484
+ "defineSlots",
485
+ "withDefaults"
486
+ ]);
487
+ if (id.type === "Identifier") {
488
+ let type;
489
+ const reactiveImport = vueImportAliases.get("reactive");
490
+ if ((hoistStatic || source === "script") && (isAllLiteral || isConst && isStaticTemplateBinding(initializer))) type = "literal-const";
491
+ else if (isTemplateCallOf(initializer, reactiveImport)) type = isConst ? "setup-reactive-const" : "setup-let";
492
+ else if (isConstMacroCall || isConst && canNeverBeTemplateRef(initializer, reactiveImport)) type = isTemplateCallOf(initializer, "defineProps") ? "setup-reactive-const" : "setup-const";
493
+ else if (isConst) type = isTemplateCallOf(initializer, [
494
+ vueImportAliases.get("ref"),
495
+ vueImportAliases.get("computed"),
496
+ vueImportAliases.get("shallowRef"),
497
+ vueImportAliases.get("customRef"),
498
+ vueImportAliases.get("toRef"),
499
+ vueImportAliases.get("useTemplateRef"),
500
+ "defineModel"
501
+ ]) ? "setup-ref" : "setup-maybe-ref";
502
+ else type = "setup-let";
503
+ setTemplateBinding(bindings, id.name, type, owner);
504
+ continue;
505
+ }
506
+ if (id.type === "ObjectPattern" && isTemplateCallOf(initializer, "defineProps")) registerTemplatePropsDestructure(id, bindings, owner);
507
+ else walkTemplateBindingPattern(id, bindings, owner, isConst, isConstMacroCall);
508
+ }
509
+ return;
510
+ }
511
+ if (declaration.type === "TSEnumDeclaration") {
512
+ const isAllLiteral = declaration.members.every(({ initializer }) => !initializer || isStaticTemplateBinding(initializer));
513
+ setTemplateBinding(bindings, declaration.id.name, isAllLiteral ? "literal-const" : "setup-const", owner);
514
+ return;
515
+ }
516
+ if (declaration.id) setTemplateBinding(bindings, declaration.id.name, "setup-const", owner);
517
+ }
518
+ /**
519
+ * Registers the conservative union of reactive and legacy prop destructuring.
520
+ *
521
+ * Vue 3.3/3.5 and `propsDestructure: false` disagree about these local binding
522
+ * types. Compiler configuration cannot be loaded safely before Vue ownership
523
+ * is established, so a local destructure takes the strongest possible type.
524
+ * This may defer an ambiguous wrapper-only project, but it cannot make that
525
+ * ambiguity poison an otherwise valid React extraction.
526
+ */
527
+ function registerTemplatePropsDestructure(pattern, bindings, owner) {
528
+ for (const property of pattern.properties) {
529
+ if (property.type === "RestElement") {
530
+ for (const identifier of Object.values(t.getBindingIdentifiers(property.argument))) setTemplateBinding(bindings, identifier.name, "setup-reactive-const", owner);
531
+ continue;
532
+ }
533
+ const publicName = readStaticPatternPropertyName(property);
534
+ if (!publicName) continue;
535
+ setTemplateBinding(bindings, publicName, "props", owner);
536
+ const value = property.value.type === "AssignmentPattern" ? property.value.left : property.value;
537
+ if (value.type === "Identifier") setTemplateBinding(bindings, value.name, "setup-const", owner);
538
+ }
539
+ }
540
+ function readStaticPatternPropertyName(property) {
541
+ if (property.computed) return void 0;
542
+ if (property.key.type === "Identifier") return property.key.name;
543
+ if (property.key.type === "StringLiteral" || property.key.type === "NumericLiteral") return String(property.key.value);
544
+ }
545
+ function walkTemplateBindingPattern(pattern, bindings, owner, isConst, isDefineCall = false) {
546
+ if (pattern.type === "ObjectPattern") {
547
+ for (const property of pattern.properties) if (property.type === "RestElement") registerTemplatePatternIdentifiers(property.argument, bindings, owner, isConst ? "setup-const" : "setup-let");
548
+ else if (property.key.type === "Identifier" && property.shorthand && property.value.type === "Identifier") setTemplateBinding(bindings, property.value.name, isDefineCall ? "setup-const" : isConst ? "setup-maybe-ref" : "setup-let", owner);
549
+ else walkTemplatePattern(property.value, bindings, owner, isConst, isDefineCall);
550
+ return;
551
+ }
552
+ if (pattern.type === "ArrayPattern") {
553
+ for (const element of pattern.elements) if (element) walkTemplatePattern(element, bindings, owner, isConst, isDefineCall);
554
+ }
555
+ }
556
+ /** Applies compiler-sfc's recursive destructuring binding classification. */
557
+ function walkTemplatePattern(pattern, bindings, owner, isConst, isDefineCall = false) {
558
+ if (pattern.type === "Identifier") setTemplateBinding(bindings, pattern.name, isDefineCall ? "setup-const" : isConst ? "setup-maybe-ref" : "setup-let", owner);
559
+ else if (pattern.type === "RestElement") registerTemplatePatternIdentifiers(pattern.argument, bindings, owner, isConst ? "setup-const" : "setup-let");
560
+ else if (pattern.type === "ObjectPattern" || pattern.type === "ArrayPattern") walkTemplateBindingPattern(pattern, bindings, owner, isConst);
561
+ else if (pattern.type === "AssignmentPattern") walkTemplatePattern(pattern.left, bindings, owner, isConst, isDefineCall);
562
+ }
563
+ function registerTemplatePatternIdentifiers(pattern, bindings, owner, type) {
564
+ for (const identifier of Object.values(t.getBindingIdentifiers(pattern))) setTemplateBinding(bindings, identifier.name, type, owner);
565
+ }
566
+ function setTemplateBinding(bindings, name, type, owner) {
567
+ bindings.set(name, {
568
+ owner,
569
+ type
570
+ });
571
+ }
572
+ function unwrapTemplateBindingExpression(input) {
573
+ let current = input ?? void 0;
574
+ while (current && (current.type === "TSAsExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSInstantiationExpression" || current.type === "TypeCastExpression" || current.type === "ParenthesizedExpression")) current = current.expression;
575
+ return current;
576
+ }
577
+ /** Matches direct compiler macros and locally aliased Vue helper calls. */
578
+ function isTemplateCallOf(node, names) {
579
+ if (!node || !names || node.type !== "CallExpression") return false;
580
+ const callee = unwrapTemplateBindingExpression(node.callee);
581
+ if (callee?.type !== "Identifier") return false;
582
+ return typeof names === "string" ? callee.name === names : names.some((name) => Boolean(name) && name === callee.name);
583
+ }
584
+ /** Returns whether compiler-sfc can prove that a value will never be a ref. */
585
+ function canNeverBeTemplateRef(node, reactiveImport) {
586
+ const expression = unwrapTemplateBindingExpression(node);
587
+ if (!expression) return false;
588
+ if (isTemplateCallOf(expression, reactiveImport)) return true;
589
+ if (expression.type === "UnaryExpression" || expression.type === "BinaryExpression" || expression.type === "ArrayExpression" || expression.type === "ObjectExpression" || expression.type === "FunctionExpression" || expression.type === "ArrowFunctionExpression" || expression.type === "UpdateExpression" || expression.type === "ClassExpression" || expression.type === "TaggedTemplateExpression") return true;
590
+ if (expression.type === "SequenceExpression") return canNeverBeTemplateRef(expression.expressions.at(-1), reactiveImport);
591
+ return expression.type.endsWith("Literal");
592
+ }
593
+ /** Reproduces compiler-sfc's static-expression predicate for hoisted bindings. */
594
+ function isStaticTemplateBinding(node) {
595
+ const expression = unwrapTemplateBindingExpression(node);
596
+ if (!expression) return false;
597
+ if (expression.type === "UnaryExpression") return isStaticTemplateBinding(expression.argument);
598
+ if (expression.type === "LogicalExpression" || expression.type === "BinaryExpression") return isStaticTemplateBinding(expression.left) && isStaticTemplateBinding(expression.right);
599
+ if (expression.type === "ConditionalExpression") return isStaticTemplateBinding(expression.test) && isStaticTemplateBinding(expression.consequent) && isStaticTemplateBinding(expression.alternate);
600
+ if (expression.type === "SequenceExpression" || expression.type === "TemplateLiteral") return expression.expressions.every(isStaticTemplateBinding);
601
+ return expression.type === "StringLiteral" || expression.type === "NumericLiteral" || expression.type === "BooleanLiteral" || expression.type === "NullLiteral" || expression.type === "BigIntLiteral";
602
+ }
603
+ function collectStaticImports(ast, options = {}) {
604
+ let programScope;
605
+ traverse(ast, { Program(programPath) {
606
+ programScope = programPath.scope;
607
+ programPath.stop();
608
+ } });
609
+ if (!programScope) return [];
610
+ const runtimeUsages = [options.templateSource && options.templateBindings ? readTemplateUsage(options.templateSource, options.templateBindings) : void 0, options.externalUsage].filter((usage) => Boolean(usage));
611
+ const imports = [];
612
+ for (const statement of ast.program.body) {
613
+ if (statement.type === "ImportDeclaration" && statement.importKind !== "type" && statement.importKind !== "typeof") {
614
+ const importedNames = /* @__PURE__ */ new Set();
615
+ for (const specifier of statement.specifiers) if (specifier.type === "ImportDefaultSpecifier") {
616
+ if (bindingHasRuntimeUsage(programScope, specifier.local.name, runtimeUsages, ast.program, options.scriptSetup)) importedNames.add("default");
617
+ } else if (specifier.type === "ImportNamespaceSpecifier") for (const name of readUsedNamespaceMembers(programScope, specifier.local.name, runtimeUsages, ast.program)) importedNames.add(name);
618
+ else if (specifier.importKind !== "type" && specifier.importKind !== "typeof" && bindingHasRuntimeUsage(programScope, specifier.local.name, runtimeUsages, ast.program, options.scriptSetup)) importedNames.add(readModuleName(specifier.imported));
619
+ if (importedNames.size > 0) imports.push({
620
+ importedNames,
621
+ source: statement.source.value
622
+ });
623
+ continue;
624
+ }
625
+ if (statement.type === "ExportAllDeclaration" && statement.exportKind !== "type") {
626
+ imports.push({
627
+ importedNames: "*",
628
+ source: statement.source.value
629
+ });
630
+ continue;
631
+ }
632
+ if (statement.type !== "ExportNamedDeclaration" || statement.exportKind === "type" || !statement.source) continue;
633
+ const importedNames = /* @__PURE__ */ new Set();
634
+ for (const specifier of statement.specifiers) if (specifier.type === "ExportSpecifier" && specifier.exportKind !== "type") importedNames.add(readModuleName(specifier.local));
635
+ if (importedNames.size > 0) imports.push({
636
+ importedNames,
637
+ source: statement.source.value
638
+ });
639
+ }
640
+ return imports;
641
+ }
642
+ function readModuleName(node) {
643
+ return node.type === "Identifier" ? node.name : node.value;
644
+ }
645
+ /** Requires a named/default import to participate in executable source. */
646
+ function bindingHasRuntimeUsage(scope, localName, runtimeUsages, owner, scriptSetup = false) {
647
+ const binding = scope.getBinding(localName);
648
+ return Boolean(binding?.referencePaths.some((reference) => !isTypeOnlyReference(reference) && !(scriptSetup && isCompilerConsumedSetupMacroReference(reference))) || runtimeUsages.some((usage) => templateUsageMatchesBinding(usage, localName, owner)));
649
+ }
650
+ const VALUE_SETUP_COMPILER_MACROS = new Set([
651
+ "defineEmits",
652
+ "defineProps",
653
+ "defineSlots",
654
+ "withDefaults"
655
+ ]);
656
+ const EXPRESSION_SETUP_COMPILER_MACROS = new Set([
657
+ ...VALUE_SETUP_COMPILER_MACROS,
658
+ "defineExpose",
659
+ "defineOptions"
660
+ ]);
661
+ /**
662
+ * Returns whether compiler-sfc removes this setup-only macro reference.
663
+ *
664
+ * Vue 3.3 and 3.5 agree on these direct top-level forms. `defineModel` is
665
+ * deliberately absent because Vue 3.3 only consumes it behind an experimental
666
+ * option, and nested calls remain ordinary runtime JavaScript in both lines.
667
+ */
668
+ function isCompilerConsumedSetupMacroReference(reference) {
669
+ if (reference.node.type !== "Identifier") return false;
670
+ const macro = reference.node.name;
671
+ if (!EXPRESSION_SETUP_COMPILER_MACROS.has(macro)) return false;
672
+ const call = reference.parentPath;
673
+ if (!call?.isCallExpression() || call.node.callee !== reference.node) return false;
674
+ let consumedCall = call;
675
+ if (macro === "defineProps") {
676
+ const parentCall = call.parentPath;
677
+ if (parentCall?.isCallExpression() && parentCall.node.arguments[0] === call.node && parentCall.node.callee.type === "Identifier" && parentCall.node.callee.name === "withDefaults") consumedCall = parentCall;
678
+ }
679
+ const parent = consumedCall.parentPath;
680
+ if (parent?.isExpressionStatement() && parent.parentPath?.isProgram()) return true;
681
+ return Boolean(VALUE_SETUP_COMPILER_MACROS.has(macro) && parent?.isVariableDeclarator() && parent.node.init === consumedCall.node && parent.parentPath?.isVariableDeclaration() && parent.parentPath.parentPath?.isProgram());
682
+ }
683
+ function isTypeOnlyReference(reference) {
684
+ if (reference.findParent((parent) => t.isTSType(parent.node) || t.isFlow(parent.node))) return true;
685
+ const exportSpecifier = reference.findParent((parent) => parent.isExportSpecifier());
686
+ return Boolean(exportSpecifier?.isExportSpecifier() && (exportSpecifier.node.exportKind === "type" || exportSpecifier.parentPath?.isExportNamedDeclaration() && exportSpecifier.parentPath.node.exportKind === "type"));
687
+ }
688
+ /** Returns only statically named namespace members used by source or template. */
689
+ function readUsedNamespaceMembers(scope, localName, runtimeUsages, owner) {
690
+ const names = /* @__PURE__ */ new Set();
691
+ const bindings = /* @__PURE__ */ new Set();
692
+ const collectImmutableAliases = (binding) => {
693
+ if (!binding?.constant || bindings.has(binding)) return;
694
+ bindings.add(binding);
695
+ for (const reference of binding.referencePaths) {
696
+ const declarator = reference.parentPath;
697
+ if (!declarator?.isVariableDeclarator() || declarator.node.init !== reference.node || declarator.node.id.type !== "Identifier" || !declarator.parentPath?.isVariableDeclaration() || declarator.parentPath.node.kind !== "const") continue;
698
+ const alias = declarator.scope.getBinding(declarator.node.id.name);
699
+ if (alias?.path.node === declarator.node) collectImmutableAliases(alias);
700
+ }
701
+ };
702
+ collectImmutableAliases(scope.getBinding(localName));
703
+ const writtenMembers = /* @__PURE__ */ new Set();
704
+ for (const binding of bindings) for (const reference of binding.referencePaths) {
705
+ const member = readNamespaceMemberPath(reference);
706
+ if (!member) continue;
707
+ const name = readStaticPropertyName(member.node);
708
+ if (name && isMemberWrite(member)) writtenMembers.add(name);
709
+ }
710
+ const templateNames = /* @__PURE__ */ new Set();
711
+ for (const binding of bindings) {
712
+ if (binding.scope === scope) templateNames.add(binding.identifier.name);
713
+ for (const reference of binding.referencePaths) {
714
+ const member = readNamespaceMemberPath(reference);
715
+ if (member) {
716
+ const name = readStaticPropertyName(member.node);
717
+ if (name && !writtenMembers.has(name)) names.add(name);
718
+ continue;
719
+ }
720
+ const jsxMember = reference.parentPath;
721
+ if (jsxMember?.isJSXMemberExpression() && jsxMember.node.object === reference.node && jsxMember.node.property.type === "JSXIdentifier" && !writtenMembers.has(jsxMember.node.property.name)) {
722
+ names.add(jsxMember.node.property.name);
723
+ continue;
724
+ }
725
+ const parent = reference.parent;
726
+ if (parent?.type !== "VariableDeclarator" || parent.init !== reference.node || parent.id.type !== "ObjectPattern") continue;
727
+ for (const property of parent.id.properties) {
728
+ if (property.type !== "ObjectProperty" || property.computed) continue;
729
+ const name = property.key.type === "Identifier" ? property.key.name : property.key.type === "StringLiteral" ? property.key.value : void 0;
730
+ if (name && !writtenMembers.has(name)) names.add(name);
731
+ }
732
+ }
733
+ }
734
+ for (const runtimeUsage of runtimeUsages) for (const templateName of templateNames) {
735
+ if (!templateUsageMatchesBinding(runtimeUsage, templateName, owner)) continue;
736
+ for (const name of runtimeUsage.namespaceMembers.get(templateName) ?? []) if (!writtenMembers.has(name)) names.add(name);
737
+ }
738
+ return names;
739
+ }
740
+ function readNamespaceMemberPath(reference) {
741
+ const member = reference.parentPath;
742
+ if ((member?.isMemberExpression() || member?.isOptionalMemberExpression()) && member.node.object === reference.node) return member;
743
+ }
744
+ function isMemberWrite(member) {
745
+ const parent = member.parentPath?.node;
746
+ return Boolean(parent?.type === "AssignmentExpression" && parent.left === member.node || parent?.type === "UpdateExpression" && parent.argument === member.node || parent?.type === "UnaryExpression" && parent.operator === "delete" && parent.argument === member.node || (parent?.type === "ForInStatement" || parent?.type === "ForOfStatement") && parent.left === member.node);
747
+ }
748
+ function createTemplateUsage(bindingOwners) {
749
+ return {
750
+ bindingOwners,
751
+ identifiers: /* @__PURE__ */ new Set(),
752
+ namespaceMembers: /* @__PURE__ */ new Map()
753
+ };
754
+ }
755
+ function templateUsageMatchesBinding(usage, name, owner) {
756
+ if (!usage.identifiers.has(name)) return false;
757
+ const expectedOwner = usage.bindingOwners?.get(name);
758
+ return !expectedOwner || expectedOwner === owner;
759
+ }
760
+ const VUE_CORE_COMPONENT_TEMPLATE_TAGS = new Set([
761
+ "BaseTransition",
762
+ "KeepAlive",
763
+ "Suspense",
764
+ "Teleport",
765
+ "Transition",
766
+ "TransitionGroup",
767
+ "base-transition",
768
+ "keep-alive",
769
+ "suspense",
770
+ "teleport",
771
+ "transition",
772
+ "transition-group"
773
+ ]);
774
+ const VUE_BUILTIN_TEMPLATE_TAGS = new Set([
775
+ ...VUE_CORE_COMPONENT_TEMPLATE_TAGS,
776
+ "slot",
777
+ "template"
778
+ ]);
779
+ const VUE_RAW_TEXT_TEMPLATE_TAGS = new Set(["script", "style"]);
780
+ const VUE_RCDATA_TEMPLATE_TAGS = new Set(["textarea", "title"]);
781
+ const VUE_VOID_TEMPLATE_TAGS = new Set("area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr".split(","));
782
+ /**
783
+ * Native platform tags recognized by Vue templates.
784
+ *
785
+ * Detection deliberately keeps this list local instead of importing
786
+ * `@vue/shared`: `/detect` runs for every CLI extraction and must not load a
787
+ * Vue runtime dependency before a project has proven Vue ownership.
788
+ */
789
+ const VUE_NATIVE_TEMPLATE_TAGS = new Set("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot,svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,tspan,unknown,use,view,annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics".split(","));
790
+ /** Parses component tags and executable expressions without raw-text guesses. */
791
+ function readTemplateUsage(templateSource, scriptBindings) {
792
+ const usage = createTemplateUsage(new Map([...scriptBindings].map(([name, binding]) => [name, binding.owner])));
793
+ const activeBindings = /* @__PURE__ */ new Map();
794
+ const elementStack = [];
795
+ let vPreDepth = 0;
796
+ let index = 0;
797
+ while (index < templateSource.length) {
798
+ if (templateSource.startsWith("<!--", index)) {
799
+ index = readHtmlCommentEnd(templateSource, index);
800
+ continue;
801
+ }
802
+ if (templateSource.startsWith("{{", index)) {
803
+ if (vPreDepth > 0) {
804
+ index += 2;
805
+ continue;
806
+ }
807
+ const interpolation = readTemplateInterpolation(templateSource, index);
808
+ if (interpolation.ast) collectTemplateAstUsage(interpolation.ast, usage, activeBindings);
809
+ index = interpolation.end;
810
+ continue;
811
+ }
812
+ if (templateSource[index] !== "<") {
813
+ index += 1;
814
+ continue;
815
+ }
816
+ const tag = readTemplateMarkupTag(templateSource, index);
817
+ if (!tag) {
818
+ index += 1;
819
+ continue;
820
+ }
821
+ const normalizedTagName = tag.name.toLowerCase();
822
+ if (tag.closing) {
823
+ vPreDepth = Math.max(0, vPreDepth - closeTemplateElementScope(normalizedTagName, elementStack, activeBindings));
824
+ index = tag.end;
825
+ continue;
826
+ }
827
+ const attributes = readTemplateAttributes(tag.attributes);
828
+ const introducesVPre = attributes.some(({ name }) => isTemplateVPreDirective(name));
829
+ const suppressUsage = vPreDepth > 0 || introducesVPre;
830
+ let descendantBindings = /* @__PURE__ */ new Set();
831
+ if (!suppressUsage) {
832
+ const directiveUsage = collectTemplateDirectiveUsage(attributes, usage, activeBindings);
833
+ descendantBindings = directiveUsage.descendantBindings;
834
+ const elementBindings = new Map(activeBindings);
835
+ for (const binding of directiveUsage.elementBindings) elementBindings.set(binding, (elementBindings.get(binding) ?? 0) + 1);
836
+ recordTemplateTagUsage(tag.name, usage, elementBindings, attributes, scriptBindings);
837
+ }
838
+ const rawTextClosingTag = !tag.selfClosing && VUE_RAW_TEXT_TEMPLATE_TAGS.has(tag.name) ? findRawBlockClosingTag(templateSource, tag.name, tag.end) : void 0;
839
+ if (rawTextClosingTag) {
840
+ index = rawTextClosingTag.end;
841
+ continue;
842
+ }
843
+ const rcdataClosingTag = !tag.selfClosing && VUE_RCDATA_TEMPLATE_TAGS.has(tag.name) ? findRawBlockClosingTag(templateSource, tag.name, tag.end) : void 0;
844
+ if (rcdataClosingTag) {
845
+ if (!suppressUsage) {
846
+ const rcdataBindings = new Map(activeBindings);
847
+ for (const binding of descendantBindings) rcdataBindings.set(binding, (rcdataBindings.get(binding) ?? 0) + 1);
848
+ collectTemplateRcdataUsage(templateSource.slice(tag.end, rcdataClosingTag.start), usage, rcdataBindings);
849
+ }
850
+ index = rcdataClosingTag.end;
851
+ continue;
852
+ }
853
+ if (!tag.selfClosing && !VUE_VOID_TEMPLATE_TAGS.has(tag.name)) {
854
+ elementStack.push({
855
+ bindings: descendantBindings,
856
+ name: normalizedTagName,
857
+ vPre: introducesVPre
858
+ });
859
+ for (const binding of descendantBindings) activeBindings.set(binding, (activeBindings.get(binding) ?? 0) + 1);
860
+ if (introducesVPre) vPreDepth += 1;
861
+ }
862
+ index = tag.end;
863
+ }
864
+ return usage;
865
+ }
866
+ function closeTemplateElementScope(name, elementStack, activeBindings) {
867
+ let matchingIndex = -1;
868
+ for (let index = elementStack.length - 1; index >= 0; index -= 1) if (elementStack[index]?.name === name) {
869
+ matchingIndex = index;
870
+ break;
871
+ }
872
+ if (matchingIndex < 0) return 0;
873
+ let closedVPreScopes = 0;
874
+ while (elementStack.length > matchingIndex) {
875
+ const element = elementStack.pop();
876
+ if (element.vPre) closedVPreScopes += 1;
877
+ for (const binding of element.bindings) {
878
+ const remaining = (activeBindings.get(binding) ?? 1) - 1;
879
+ if (remaining > 0) activeBindings.set(binding, remaining);
880
+ else activeBindings.delete(binding);
881
+ }
882
+ }
883
+ return closedVPreScopes;
884
+ }
885
+ /** Records executable Vue interpolations while keeping RCDATA tags opaque. */
886
+ function collectTemplateRcdataUsage(source, usage, shadowedBindings) {
887
+ let index = source.indexOf("{{");
888
+ while (index >= 0) {
889
+ const interpolation = readTemplateInterpolation(source, index);
890
+ if (interpolation.ast) collectTemplateAstUsage(interpolation.ast, usage, shadowedBindings);
891
+ if (interpolation.end >= source.length) return;
892
+ index = source.indexOf("{{", interpolation.end);
893
+ }
894
+ }
895
+ /** Reads one real template tag while keeping quoted attribute data opaque. */
896
+ function readTemplateMarkupTag(source, start) {
897
+ if (source[start] !== "<" || source.startsWith("<!--", start)) return;
898
+ let cursor = start + 1;
899
+ const closing = source[cursor] === "/";
900
+ if (closing) cursor += 1;
901
+ const nameStart = cursor;
902
+ while (cursor < source.length && /[A-Za-z0-9_$.:?-]/.test(source[cursor])) cursor += 1;
903
+ if (cursor === nameStart || !/[A-Za-z_$]/.test(source[nameStart])) return;
904
+ const name = source.slice(nameStart, cursor);
905
+ const attributesStart = cursor;
906
+ let quote;
907
+ while (cursor < source.length) {
908
+ const character = source[cursor];
909
+ if (quote) {
910
+ if (character === quote) quote = void 0;
911
+ } else if (character === "\"" || character === "'") quote = character;
912
+ else if (character === ">") return {
913
+ attributes: source.slice(attributesStart, cursor),
914
+ closing,
915
+ end: cursor + 1,
916
+ name,
917
+ selfClosing: !closing && /\/\s*$/.test(source.slice(attributesStart, cursor))
918
+ };
919
+ cursor += 1;
920
+ }
921
+ }
922
+ function recordTemplateTagUsage(sourceTag, usage, shadowedBindings, attributes, scriptBindings) {
923
+ if (isDynamicComponentTag(sourceTag, attributes)) return;
924
+ const valuedVIs = readValuedVIsDirective(attributes);
925
+ if (valuedVIs) {
926
+ recordVersionStableVIsUsage(sourceTag, valuedVIs, usage, shadowedBindings, attributes, scriptBindings);
927
+ return;
928
+ }
929
+ const staticVueIsTarget = readStaticVueIsTarget(attributes);
930
+ let tag = sourceTag;
931
+ if (staticVueIsTarget !== void 0) {
932
+ if (!hasStableStaticVueIsSemantics(sourceTag)) return;
933
+ tag = staticVueIsTarget;
934
+ }
935
+ const member = /^([A-Za-z_$][\w$-]*)\.([A-Za-z_$][\w$]*)$/.exec(tag);
936
+ if (member?.[1] && member[2]) {
937
+ const namespace = resolveTemplateTagBinding(member[1], shadowedBindings, scriptBindings);
938
+ if (namespace) {
939
+ usage.identifiers.add(namespace);
940
+ addTemplateNamespaceMember(usage, namespace, member[2]);
941
+ }
942
+ return;
943
+ }
944
+ if (staticVueIsTarget !== void 0 ? VUE_CORE_COMPONENT_TEMPLATE_TAGS.has(tag) : VUE_BUILTIN_TEMPLATE_TAGS.has(tag) || VUE_NATIVE_TEMPLATE_TAGS.has(tag)) return;
945
+ const name = resolveTemplateTagBinding(tag, shadowedBindings, scriptBindings);
946
+ if (name) usage.identifiers.add(name);
947
+ }
948
+ /** Reads the component target of Vue's static `is="vue:..."` syntax. */
949
+ function readStaticVueIsTarget(attributes) {
950
+ const value = attributes.find(({ name }) => name === "is")?.value;
951
+ return value?.startsWith("vue:") ? value.slice(4) : void 0;
952
+ }
953
+ /**
954
+ * Limits static `vue:` rewriting to tags whose parser classification is known.
955
+ *
956
+ * Project-level custom-element options are unavailable until Vue ownership is
957
+ * established. Unknown component/custom-element tags therefore cannot safely
958
+ * prove that the `vue:` target executes. `slot`, `template`, and dynamic
959
+ * `component` also differ from ordinary elements (and `template` differs
960
+ * between supported Vue 3.3/3.5 lines), so they remain conservative.
961
+ */
962
+ function hasStableStaticVueIsSemantics(tag) {
963
+ if (tag === "component" || tag === "Component" || tag === "slot" || tag === "template") return false;
964
+ return VUE_NATIVE_TEMPLATE_TAGS.has(tag) || VUE_BUILTIN_TEMPLATE_TAGS.has(tag);
965
+ }
966
+ /** Reads a valued `v-is` whose meaning differs across supported Vue lines. */
967
+ function readValuedVIsDirective(attributes) {
968
+ return attributes.find(({ name, value }) => value !== void 0 && /^v-is(?:$|[:.])/.test(name));
969
+ }
970
+ /**
971
+ * Retains only wrapper bindings used by both meanings of valued `v-is`.
972
+ *
973
+ * Vue 3.3 evaluates the directive expression and replaces the source tag;
974
+ * Vue 3.5 removes the directive and renders the source tag. Intersecting both
975
+ * usage sets avoids false ownership on either version while preserving a
976
+ * wrapper deliberately referenced on both sides.
977
+ */
978
+ function recordVersionStableVIsUsage(sourceTag, directive, usage, shadowedBindings, attributes, scriptBindings) {
979
+ const sourceUsage = createTemplateUsage();
980
+ recordTemplateTagUsage(sourceTag, sourceUsage, shadowedBindings, attributes.filter((attribute) => attribute !== directive), scriptBindings);
981
+ const directiveUsage = createTemplateUsage();
982
+ collectTemplateExpressionUsage(directive.value ?? "", directiveUsage, shadowedBindings);
983
+ for (const identifier of sourceUsage.identifiers) if (directiveUsage.identifiers.has(identifier)) usage.identifiers.add(identifier);
984
+ for (const [namespace, sourceMembers] of sourceUsage.namespaceMembers) {
985
+ const directiveMembers = directiveUsage.namespaceMembers.get(namespace);
986
+ if (!directiveMembers) continue;
987
+ for (const member of sourceMembers) if (directiveMembers.has(member)) addTemplateNamespaceMember(usage, namespace, member);
988
+ }
989
+ }
990
+ /** Selects the first lexical or setup binding in Vue's tag lookup order. */
991
+ function resolveTemplateTagBinding(sourceName, shadowedBindings, scriptBindings) {
992
+ const candidates = [...normalizeTemplateBindingNames(sourceName)];
993
+ for (const bindingType of TEMPLATE_BINDING_RESOLUTION_ORDER) for (const candidate of candidates) {
994
+ if (scriptBindings.get(candidate)?.type !== bindingType) continue;
995
+ return shadowedBindings.has(candidate) ? void 0 : candidate;
996
+ }
997
+ }
998
+ function isDynamicComponentTag(tag, attributes) {
999
+ if (tag !== "component" && tag !== "Component") return false;
1000
+ return attributes.some(({ name, value }) => {
1001
+ if (value === void 0) return false;
1002
+ const baseName = name.split(".")[0];
1003
+ return baseName === "is" || baseName === ":is" || baseName === "v-bind:is" || name === ".is" || name.startsWith(".is.");
1004
+ });
1005
+ }
1006
+ /** Collects dynamic directive arguments and executable directive values. */
1007
+ function collectTemplateDirectiveUsage(attributes, usage, shadowedBindings) {
1008
+ const directives = attributes.filter(({ name }) => isTemplateDirectiveName(name));
1009
+ const elementBindings = /* @__PURE__ */ new Set();
1010
+ const descendantBindings = /* @__PURE__ */ new Set();
1011
+ for (const directive of directives.filter(({ name }) => isTemplateForDirective(name))) for (const binding of collectTemplateDirective(directive.name, directive.value, usage, shadowedBindings)) {
1012
+ elementBindings.add(binding);
1013
+ descendantBindings.add(binding);
1014
+ }
1015
+ for (const directive of directives.filter(({ name }) => isTemplateConditionalDirective(name))) collectTemplateDirective(directive.name, directive.value, usage, shadowedBindings);
1016
+ const loopBindings = new Map(shadowedBindings);
1017
+ for (const binding of elementBindings) loopBindings.set(binding, (loopBindings.get(binding) ?? 0) + 1);
1018
+ for (const directive of directives) {
1019
+ if (isTemplateForDirective(directive.name) || isTemplateConditionalDirective(directive.name)) continue;
1020
+ for (const binding of collectTemplateDirective(directive.name, directive.value, usage, loopBindings)) descendantBindings.add(binding);
1021
+ }
1022
+ return {
1023
+ descendantBindings,
1024
+ elementBindings
1025
+ };
1026
+ }
1027
+ function readTemplateAttributes(attributes) {
1028
+ const parsedAttributes = [];
1029
+ let index = 0;
1030
+ while (index < attributes.length) {
1031
+ while (/\s/.test(attributes[index] ?? "")) index += 1;
1032
+ if (index >= attributes.length || attributes[index] === "/") return parsedAttributes;
1033
+ const nameStart = index;
1034
+ while (index < attributes.length && !/[\s=]/.test(attributes[index])) index += 1;
1035
+ const name = attributes.slice(nameStart, index);
1036
+ while (/\s/.test(attributes[index] ?? "")) index += 1;
1037
+ let value;
1038
+ if (attributes[index] === "=") {
1039
+ index += 1;
1040
+ while (/\s/.test(attributes[index] ?? "")) index += 1;
1041
+ const quote = attributes[index];
1042
+ if (quote === "\"" || quote === "'") {
1043
+ index += 1;
1044
+ const valueStart = index;
1045
+ while (index < attributes.length && attributes[index] !== quote) index += 1;
1046
+ value = attributes.slice(valueStart, index);
1047
+ if (attributes[index] === quote) index += 1;
1048
+ } else {
1049
+ const valueStart = index;
1050
+ while (index < attributes.length && !/[\s>]/.test(attributes[index])) index += 1;
1051
+ value = attributes.slice(valueStart, index);
1052
+ }
1053
+ }
1054
+ parsedAttributes.push({
1055
+ name,
1056
+ value
1057
+ });
1058
+ }
1059
+ return parsedAttributes;
1060
+ }
1061
+ function isTemplateDirectiveName(name) {
1062
+ return /^[.:@#]|^v-/.test(name);
1063
+ }
1064
+ function isTemplateVPreDirective(name) {
1065
+ return /^v-pre(?:$|[:.])/.test(name);
1066
+ }
1067
+ function isTemplateForDirective(name) {
1068
+ return /^v-for(?::|$)/.test(name);
1069
+ }
1070
+ function isTemplateConditionalDirective(name) {
1071
+ return /^v-(?:if|else-if)(?::|$)/.test(name);
1072
+ }
1073
+ function collectTemplateDirective(name, value, usage, shadowedBindings) {
1074
+ if (!/^[.:@#]|^v-/.test(name)) return /* @__PURE__ */ new Set();
1075
+ if (/^v-is(?:$|[:.])/.test(name)) return /* @__PURE__ */ new Set();
1076
+ const argument = readDynamicDirectiveArgument(name);
1077
+ if (argument) collectTemplateExpressionUsage(argument, usage, shadowedBindings);
1078
+ if (value === void 0) {
1079
+ if ((name.startsWith(":") || name.startsWith(".")) && !argument) collectTemplateExpressionUsage(name.slice(1).split(".")[0] ?? "", usage, shadowedBindings);
1080
+ return /* @__PURE__ */ new Set();
1081
+ }
1082
+ if (/^(?:#|v-slot(?::|$))/.test(name)) return collectTemplateBindingUsage(value, usage, shadowedBindings);
1083
+ else if (/^v-for(?::|$)/.test(name)) return collectTemplateForUsage(value, usage, shadowedBindings);
1084
+ else collectTemplateExpressionUsage(value, usage, shadowedBindings);
1085
+ return /* @__PURE__ */ new Set();
1086
+ }
1087
+ function readDynamicDirectiveArgument(name) {
1088
+ const start = name.indexOf("[");
1089
+ const end = name.lastIndexOf("]");
1090
+ return start >= 0 && end > start ? name.slice(start + 1, end) : void 0;
1091
+ }
1092
+ function collectTemplateExpressionUsage(source, usage, shadowedBindings) {
1093
+ const ast = parseTemplateExpression(source);
1094
+ if (ast) collectTemplateAstUsage(ast, usage, shadowedBindings);
1095
+ }
1096
+ function collectTemplateBindingUsage(source, usage, shadowedBindings) {
1097
+ try {
1098
+ const ast = parseScriptAst(`((${source}) => {})`, "tsx");
1099
+ collectTemplateAstUsage(ast, usage, shadowedBindings);
1100
+ const statement = ast.program.body[0];
1101
+ if (statement?.type !== "ExpressionStatement" || statement.expression.type !== "ArrowFunctionExpression") return /* @__PURE__ */ new Set();
1102
+ return new Set(statement.expression.params.flatMap((parameter) => Object.keys(t.getBindingIdentifiers(parameter))));
1103
+ } catch {
1104
+ return /* @__PURE__ */ new Set();
1105
+ }
1106
+ }
1107
+ function collectTemplateForUsage(source, usage, shadowedBindings) {
1108
+ const separator = /\s+(?:in|of)\s+/.exec(source);
1109
+ if (!separator || separator.index === void 0) {
1110
+ collectTemplateExpressionUsage(source, usage, shadowedBindings);
1111
+ return /* @__PURE__ */ new Set();
1112
+ }
1113
+ const left = source.slice(0, separator.index).trim();
1114
+ const right = source.slice(separator.index + separator[0].length).trim();
1115
+ const bindings = collectTemplateBindingUsage(left.startsWith("(") && left.endsWith(")") ? left.slice(1, -1) : left, usage, shadowedBindings);
1116
+ collectTemplateExpressionUsage(right, usage, shadowedBindings);
1117
+ return bindings;
1118
+ }
1119
+ /** Finds the first syntactically complete interpolation closing delimiter. */
1120
+ function readTemplateInterpolation(source, start) {
1121
+ let closing = source.indexOf("}}", start + 2);
1122
+ while (closing >= 0) {
1123
+ const ast = parseTemplateExpression(source.slice(start + 2, closing));
1124
+ if (ast) return {
1125
+ ast,
1126
+ end: closing + 2
1127
+ };
1128
+ closing = source.indexOf("}}", closing + 1);
1129
+ }
1130
+ return { end: source.length };
1131
+ }
1132
+ /** Accepts expression, binding-pattern, and event-statement template syntax. */
1133
+ function parseTemplateExpression(source) {
1134
+ for (const candidate of [
1135
+ `(${source})`,
1136
+ `((${source}) => {})`,
1137
+ `function __gt_template_expression__() { ${source} }`
1138
+ ]) try {
1139
+ return parseScriptAst(candidate, "tsx");
1140
+ } catch {}
1141
+ }
1142
+ /** Records only unshadowed runtime identifiers and static namespace members. */
1143
+ function collectTemplateAstUsage(ast, usage, shadowedBindings, scriptSetup = false) {
1144
+ traverse(ast, {
1145
+ ReferencedIdentifier(path) {
1146
+ if (scriptSetup && isCompilerConsumedSetupMacroReference(path) || shadowedBindings.has(path.node.name) || path.scope.getBinding(path.node.name) || path.findParent((parent) => t.isTSType(parent.node) || t.isFlow(parent.node))) return;
1147
+ usage.identifiers.add(path.node.name);
1148
+ },
1149
+ JSXIdentifier(path) {
1150
+ if (!/^[A-Z_$]/.test(path.node.name) || path.parentPath?.isJSXMemberExpression() || !(path.parentPath?.isJSXOpeningElement() && path.parentPath.node.name === path.node || path.parentPath?.isJSXClosingElement() && path.parentPath.node.name === path.node) || shadowedBindings.has(path.node.name) || path.scope.getBinding(path.node.name)) return;
1151
+ usage.identifiers.add(path.node.name);
1152
+ },
1153
+ MemberExpression(path) {
1154
+ collectTemplateMemberUsage(path, usage, shadowedBindings);
1155
+ },
1156
+ OptionalMemberExpression(path) {
1157
+ collectTemplateMemberUsage(path, usage, shadowedBindings);
1158
+ },
1159
+ JSXMemberExpression(path) {
1160
+ const object = path.node.object;
1161
+ if (object.type !== "JSXIdentifier" || shadowedBindings.has(object.name) || path.scope.getBinding(object.name) || path.node.property.type !== "JSXIdentifier") return;
1162
+ usage.identifiers.add(object.name);
1163
+ addTemplateNamespaceMember(usage, object.name, path.node.property.name);
1164
+ }
1165
+ });
1166
+ }
1167
+ function collectTemplateMemberUsage(path, usage, shadowedBindings) {
1168
+ const object = path.node.object;
1169
+ if (object.type !== "Identifier" || shadowedBindings.has(object.name) || path.scope.getBinding(object.name) || path.findParent((parent) => t.isTSType(parent.node) || t.isFlow(parent.node))) return;
1170
+ const member = readStaticPropertyName(path.node);
1171
+ if (member) addTemplateNamespaceMember(usage, object.name, member);
1172
+ }
1173
+ function addTemplateNamespaceMember(usage, namespace, member) {
1174
+ const members = usage.namespaceMembers.get(namespace) ?? /* @__PURE__ */ new Set();
1175
+ members.add(member);
1176
+ usage.namespaceMembers.set(namespace, members);
1177
+ }
1178
+ /** Mirrors Vue's kebab/camel/Pascal lookup for setup template bindings. */
1179
+ function normalizeTemplateBindingNames(sourceName) {
1180
+ const camelized = sourceName.replace(/-(\w)/g, (_match, letter) => letter.toUpperCase());
1181
+ const pascalized = camelized ? camelized[0].toUpperCase() + camelized.slice(1) : camelized;
1182
+ return new Set([
1183
+ sourceName,
1184
+ camelized,
1185
+ pascalized
1186
+ ]);
1187
+ }
1188
+ function readStaticPropertyName(member) {
1189
+ if (!member.computed && member.property.type === "Identifier") return member.property.name;
1190
+ if (member.computed && member.property.type === "StringLiteral") return member.property.value;
1191
+ }
1192
+ function readPackageName(manifest) {
1193
+ return typeof manifest.name === "string" && manifest.name ? manifest.name : void 0;
1194
+ }
1195
+ function resolveRealPath(file) {
1196
+ try {
1197
+ return fs.realpathSync(file);
1198
+ } catch {
1199
+ return path.resolve(file);
1200
+ }
1201
+ }
1202
+ /** Keeps a package's default source roots from following external symlinks. */
1203
+ function isContainedPhysicalDirectory(root, directory) {
1204
+ try {
1205
+ const stat = fs.lstatSync(directory);
1206
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return false;
1207
+ const realDirectory = fs.realpathSync(directory);
1208
+ const relative = path.relative(root, realDirectory);
1209
+ return relative !== "" && !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
1210
+ } catch {
1211
+ return false;
1212
+ }
1213
+ }
1214
+ function escapeRegularExpression(value) {
1215
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1216
+ }
1217
+ //#endregion
1218
+ export { createConsumerUsageCache, packageConsumesPublicGT, packageExposesPublicGT };
1219
+
1220
+ //# sourceMappingURL=consumerUsage.js.map