@typed/virtual-modules-ts-plugin 1.0.0-beta.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.
package/dist/plugin.js ADDED
@@ -0,0 +1,2475 @@
1
+ "use strict";
2
+
3
+ // ../virtual-modules/dist/types.js
4
+ function isVirtualModuleBuildError(result) {
5
+ return typeof result === "object" && result !== null && "errors" in result && Array.isArray(result.errors) && result.errors.length > 0;
6
+ }
7
+ function isVirtualModuleBuildSuccess(result) {
8
+ return typeof result === "object" && result !== null && "sourceText" in result && typeof result.sourceText === "string";
9
+ }
10
+
11
+ // ../virtual-modules/dist/internal/sanitize.js
12
+ function sanitizeErrorMessage(message) {
13
+ const withoutStack = message.split(/\r?\n/).filter((line) => !/^\s*at\s+/.test(line.trim())).join("\n").trim();
14
+ const unixPath = /\/[\w./-]+\/[\w./-]+(?:\/[\w./-]*)*/g;
15
+ const winPath = /[A-Za-z]:[\\/][\w.-]+(?:[\\/][\w.-]+)*/g;
16
+ let out = withoutStack.replace(unixPath, "[path]").replace(winPath, "[path]");
17
+ return out.replace(/\s{2,}/g, " ").trim();
18
+ }
19
+
20
+ // ../virtual-modules/dist/internal/validation.js
21
+ var DEFAULT_MAX_LENGTH = 4096;
22
+ function validateNonEmptyString(value, name, maxLength = DEFAULT_MAX_LENGTH) {
23
+ if (typeof value !== "string") {
24
+ return { ok: false, reason: `${name} must be a string` };
25
+ }
26
+ const trimmed = value.trim();
27
+ if (trimmed === "") {
28
+ return { ok: false, reason: `${name} must be non-empty` };
29
+ }
30
+ if (value.includes("\0")) {
31
+ return { ok: false, reason: `${name} must not contain null bytes` };
32
+ }
33
+ if (value.length > maxLength) {
34
+ return { ok: false, reason: `${name} exceeds max length ${maxLength}` };
35
+ }
36
+ return { ok: true, value: trimmed };
37
+ }
38
+ function validatePathSegment(value, name, maxLength = DEFAULT_MAX_LENGTH) {
39
+ if (typeof value !== "string") {
40
+ return { ok: false, reason: `${name} must be a string` };
41
+ }
42
+ if (value.length === 0 || value.trim() === "") {
43
+ return { ok: false, reason: `${name} must be non-empty` };
44
+ }
45
+ if (value.includes("\0")) {
46
+ return { ok: false, reason: `${name} must not contain null bytes` };
47
+ }
48
+ if (value.length > maxLength) {
49
+ return { ok: false, reason: `${name} exceeds max length ${maxLength}` };
50
+ }
51
+ return { ok: true, value };
52
+ }
53
+ function validateRelativeGlobs(value, name, maxLength = DEFAULT_MAX_LENGTH) {
54
+ const arr = Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
55
+ const result = [];
56
+ for (let i = 0; i < arr.length; i++) {
57
+ const v = arr[i];
58
+ const r = validatePathSegment(v, `${name}[${i}]`, maxLength);
59
+ if (!r.ok)
60
+ return r;
61
+ const normalized = r.value.replaceAll("\\", "/");
62
+ if (normalized.includes("..")) {
63
+ return { ok: false, reason: `${name}[${i}] must not contain parent path segments (..)` };
64
+ }
65
+ if (normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized)) {
66
+ return { ok: false, reason: `${name}[${i}] must be a relative glob, not absolute` };
67
+ }
68
+ result.push(r.value);
69
+ }
70
+ return { ok: true, value: result };
71
+ }
72
+
73
+ // ../virtual-modules/dist/PluginManager.js
74
+ var noopTypeInfoApi = {
75
+ file: () => ({ ok: false, error: "invalid-input" }),
76
+ directory: () => [],
77
+ resolveExport: () => void 0,
78
+ isAssignableTo: () => false
79
+ };
80
+ var noopSession = {
81
+ api: noopTypeInfoApi,
82
+ consumeDependencies: () => []
83
+ };
84
+ var toMessage = (error) => {
85
+ if (error instanceof Error) {
86
+ return error.message;
87
+ }
88
+ return String(error);
89
+ };
90
+ var createDiagnostic = (code, pluginName, message) => ({
91
+ code,
92
+ pluginName,
93
+ message
94
+ });
95
+ var PluginManager = class {
96
+ #plugins;
97
+ constructor(plugins = []) {
98
+ this.#plugins = [...plugins];
99
+ }
100
+ get plugins() {
101
+ return this.#plugins;
102
+ }
103
+ register(plugin) {
104
+ this.#plugins.push(plugin);
105
+ }
106
+ registerMany(plugins) {
107
+ for (const plugin of plugins) {
108
+ this.register(plugin);
109
+ }
110
+ }
111
+ resolveModule(options) {
112
+ const idResult = validateNonEmptyString(options.id, "options.id");
113
+ if (!idResult.ok) {
114
+ return {
115
+ status: "error",
116
+ diagnostic: createDiagnostic("invalid-options", "", idResult.reason)
117
+ };
118
+ }
119
+ const importerResult = validateNonEmptyString(options.importer, "options.importer");
120
+ if (!importerResult.ok) {
121
+ return {
122
+ status: "error",
123
+ diagnostic: createDiagnostic("invalid-options", "", importerResult.reason)
124
+ };
125
+ }
126
+ const createSession = options.createTypeInfoApiSession;
127
+ for (const plugin of this.#plugins) {
128
+ const nameResult = validateNonEmptyString(plugin.name, "Plugin name");
129
+ if (!nameResult.ok) {
130
+ return {
131
+ status: "error",
132
+ diagnostic: createDiagnostic("invalid-options", "", nameResult.reason)
133
+ };
134
+ }
135
+ const shouldResolve = this.#safeShouldResolve(plugin, options.id, options.importer);
136
+ if (shouldResolve.status === "error") {
137
+ return shouldResolve;
138
+ }
139
+ if (!shouldResolve.value) {
140
+ continue;
141
+ }
142
+ let session;
143
+ try {
144
+ session = createSession?.({ id: options.id, importer: options.importer }) ?? noopSession;
145
+ } catch (error) {
146
+ const msg = toMessage(error);
147
+ if (msg.includes("Program not yet available") || msg.includes("TypeInfo session creation failed")) {
148
+ continue;
149
+ }
150
+ return {
151
+ status: "error",
152
+ diagnostic: createDiagnostic("session-creation-failed", plugin.name, `Session creation failed: ${sanitizeErrorMessage(msg)}`)
153
+ };
154
+ }
155
+ try {
156
+ const result = plugin.build(options.id, options.importer, session.api);
157
+ if (typeof result === "string") {
158
+ return {
159
+ status: "resolved",
160
+ pluginName: plugin.name,
161
+ sourceText: result,
162
+ dependencies: session.consumeDependencies()
163
+ };
164
+ }
165
+ if (isVirtualModuleBuildError(result)) {
166
+ const first = result.errors[0];
167
+ const diagnostic = first && typeof first === "object" && typeof first.code === "string" && typeof first.message === "string" && typeof first.pluginName === "string" ? first : createDiagnostic("invalid-build-output", plugin.name, `Plugin "${plugin.name}" returned errors with invalid diagnostic shape`);
168
+ return { status: "error", diagnostic };
169
+ }
170
+ if (isVirtualModuleBuildSuccess(result)) {
171
+ return {
172
+ status: "resolved",
173
+ pluginName: plugin.name,
174
+ sourceText: result.sourceText,
175
+ dependencies: session.consumeDependencies(),
176
+ ...result.warnings?.length ? { warnings: result.warnings } : {}
177
+ };
178
+ }
179
+ return {
180
+ status: "error",
181
+ diagnostic: createDiagnostic("invalid-build-output", plugin.name, `Plugin "${plugin.name}" returned a non-string build result`)
182
+ };
183
+ } catch (error) {
184
+ return {
185
+ status: "error",
186
+ diagnostic: createDiagnostic("plugin-build-threw", plugin.name, `Plugin "${plugin.name}" build failed: ${sanitizeErrorMessage(toMessage(error))}`)
187
+ };
188
+ }
189
+ }
190
+ return { status: "unresolved" };
191
+ }
192
+ #safeShouldResolve(plugin, id, importer) {
193
+ try {
194
+ return {
195
+ status: "ok",
196
+ value: plugin.shouldResolve(id, importer)
197
+ };
198
+ } catch (error) {
199
+ return {
200
+ status: "error",
201
+ diagnostic: createDiagnostic("plugin-should-resolve-threw", plugin.name, `Plugin "${plugin.name}" shouldResolve failed: ${sanitizeErrorMessage(toMessage(error))}`)
202
+ };
203
+ }
204
+ }
205
+ };
206
+
207
+ // ../virtual-modules/dist/collectTypeTargetSpecs.js
208
+ function collectTypeTargetSpecsFromPlugins(plugins) {
209
+ const seen = /* @__PURE__ */ new Set();
210
+ const result = [];
211
+ for (const plugin of plugins) {
212
+ const specs = plugin.typeTargetSpecs;
213
+ if (!specs?.length)
214
+ continue;
215
+ for (const spec of specs) {
216
+ if (!seen.has(spec.id)) {
217
+ seen.add(spec.id);
218
+ result.push(spec);
219
+ }
220
+ }
221
+ }
222
+ return result;
223
+ }
224
+
225
+ // ../virtual-modules/dist/TypeInfoApi.js
226
+ var import_node_path2 = require("path");
227
+
228
+ // ../virtual-modules/dist/internal/tsInternal.js
229
+ function getIndexInfosOfType(type, checker) {
230
+ try {
231
+ const fn = checker.getIndexInfosOfType;
232
+ return fn?.(type);
233
+ } catch {
234
+ return void 0;
235
+ }
236
+ }
237
+ function getAliasedSymbol(symbol, checker, tsMod) {
238
+ if ((symbol.flags & tsMod.SymbolFlags.Alias) === 0)
239
+ return symbol;
240
+ try {
241
+ const aliased = checker.getAliasedSymbol(symbol);
242
+ return aliased ?? symbol;
243
+ } catch {
244
+ return symbol;
245
+ }
246
+ }
247
+ function getTypeReferenceTarget(type, checker) {
248
+ try {
249
+ const args = checker.getTypeArguments(type);
250
+ if (args.length > 0) {
251
+ const target = type.target;
252
+ return target;
253
+ }
254
+ } catch {
255
+ }
256
+ return void 0;
257
+ }
258
+ function getTypeSymbol(type) {
259
+ return type.symbol;
260
+ }
261
+ function getSymbolExports(symbol) {
262
+ return symbol.exports;
263
+ }
264
+ function getBaseTypes(type, checker) {
265
+ try {
266
+ const fn = checker.getBaseTypes;
267
+ return fn?.(type);
268
+ } catch {
269
+ return void 0;
270
+ }
271
+ }
272
+ var FALLBACK_OBJECT_FLAGS_MAPPED = 32;
273
+
274
+ // ../virtual-modules/dist/internal/path.js
275
+ var import_node_crypto = require("crypto");
276
+ var import_node_fs = require("fs");
277
+ var import_node_path = require("path");
278
+ var VIRTUAL_NODE_MODULES_RELATIVE = "node_modules/.typed/virtual";
279
+ var toPosixPath = (path) => path.replaceAll("\\", "/");
280
+ var resolveRelativePath = (baseDir, relativePath) => toPosixPath((0, import_node_path.resolve)(baseDir, relativePath));
281
+ function resolvePathUnderBase(baseDir, relativePath) {
282
+ const baseAbs = (0, import_node_path.resolve)(baseDir);
283
+ const resolved = (0, import_node_path.resolve)(baseDir, relativePath);
284
+ const rel = (0, import_node_path.relative)(baseAbs, resolved);
285
+ if (rel.startsWith("..") || (0, import_node_path.isAbsolute)(rel)) {
286
+ return { ok: false, error: "path-escapes-base" };
287
+ }
288
+ return { ok: true, path: toPosixPath(resolved) };
289
+ }
290
+ function pathIsUnderBase(baseDir, absolutePath) {
291
+ let baseAbs;
292
+ let resolvedAbs;
293
+ try {
294
+ baseAbs = (0, import_node_fs.realpathSync)((0, import_node_path.resolve)(baseDir));
295
+ resolvedAbs = (0, import_node_fs.realpathSync)((0, import_node_path.resolve)(absolutePath));
296
+ } catch {
297
+ baseAbs = (0, import_node_path.resolve)(baseDir);
298
+ resolvedAbs = (0, import_node_path.resolve)(absolutePath);
299
+ }
300
+ const rel = (0, import_node_path.relative)(baseAbs, resolvedAbs);
301
+ if (rel.startsWith("..") || (0, import_node_path.isAbsolute)(rel)) {
302
+ return false;
303
+ }
304
+ return true;
305
+ }
306
+ var stableHash = (input) => (0, import_node_crypto.createHash)("sha1").update(input).digest("hex").slice(0, 16);
307
+ var sanitizeSegment = (value) => value.replaceAll(/[^a-zA-Z0-9._-]/g, "-");
308
+ var VIRTUAL_MODULE_URI_SCHEME = "typed-virtual";
309
+ var createVirtualKey = (id, importer) => `${importer}::${id}`;
310
+ var createVirtualFileName = (pluginName, virtualKey, params, options) => {
311
+ const safePluginName = sanitizeSegment(pluginName);
312
+ const hash = stableHash(virtualKey);
313
+ const basename = `__virtual_${safePluginName}_${hash}.ts`;
314
+ if (params) {
315
+ const projectRoot = options?.projectRoot;
316
+ if (typeof projectRoot === "string" && projectRoot.trim().length > 0) {
317
+ return toPosixPath((0, import_node_path.join)((0, import_node_path.resolve)(projectRoot), VIRTUAL_NODE_MODULES_RELATIVE, basename));
318
+ }
319
+ const importerDir = (0, import_node_path.dirname)(toPosixPath(params.importer));
320
+ return `${importerDir}/${basename}`;
321
+ }
322
+ return `${VIRTUAL_MODULE_URI_SCHEME}://0/${safePluginName}/${hash}.ts`;
323
+ };
324
+ var createWatchDescriptorKey = (descriptor) => {
325
+ if (descriptor.type === "file") {
326
+ return `file:${toPosixPath(descriptor.path)}`;
327
+ }
328
+ const globs = [...descriptor.relativeGlobs].sort().join("|");
329
+ return `glob:${toPosixPath(descriptor.baseDir)}:${descriptor.recursive ? "r" : "nr"}:${globs}`;
330
+ };
331
+ var dedupeSorted = (values) => [...new Set(values.map(toPosixPath))].sort();
332
+
333
+ // ../virtual-modules/dist/TypeInfoApi.js
334
+ var TYPE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".d.ts"];
335
+ var DEFAULT_MAX_DEPTH = 6;
336
+ var compareByName = (a, b) => a.name.localeCompare(b.name);
337
+ var toOptionalFlag = (symbol, tsMod) => (symbol.flags & tsMod.SymbolFlags.Optional) !== 0;
338
+ var hasReadonlyModifier = (declaration, tsMod) => {
339
+ if (!declaration || !tsMod.canHaveModifiers(declaration)) {
340
+ return false;
341
+ }
342
+ const modifiers = tsMod.getModifiers(declaration);
343
+ return modifiers?.some((modifier) => modifier.kind === tsMod.SyntaxKind.ReadonlyKeyword) ?? false;
344
+ };
345
+ var asLiteral = (type, checker, tsMod) => {
346
+ const text = checker.typeToString(type);
347
+ if ((type.flags & tsMod.TypeFlags.StringLiteral) !== 0 || (type.flags & tsMod.TypeFlags.NumberLiteral) !== 0 || (type.flags & tsMod.TypeFlags.BooleanLiteral) !== 0 || (type.flags & tsMod.TypeFlags.BigIntLiteral) !== 0) {
348
+ return { kind: "literal", text };
349
+ }
350
+ return void 0;
351
+ };
352
+ var serializeFunctionSignature = (signature, checker, tsMod, depth, maxDepth, visited, onInternalError, registry) => {
353
+ const parameters = signature.getParameters().map((parameter) => {
354
+ const declaration = parameter.valueDeclaration ?? parameter.declarations?.[0];
355
+ const parameterType = declaration ? checker.getTypeOfSymbolAtLocation(parameter, declaration) : checker.getDeclaredTypeOfSymbol(parameter);
356
+ return {
357
+ name: parameter.getName(),
358
+ optional: toOptionalFlag(parameter, tsMod),
359
+ type: serializeTypeNode(parameterType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry)
360
+ };
361
+ });
362
+ const returnType = serializeTypeNode(checker.getReturnTypeOfSignature(signature), checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry);
363
+ return {
364
+ parameters: parameters.sort(compareByName),
365
+ returnType
366
+ };
367
+ };
368
+ var serializeObjectProperties = (type, checker, tsMod, depth, maxDepth, visited, onInternalError, registry) => {
369
+ const properties = checker.getPropertiesOfType(type);
370
+ const snapshots = properties.map((property) => {
371
+ const declaration = property.valueDeclaration ?? property.declarations?.[0];
372
+ const propertyType = declaration ? checker.getTypeOfSymbolAtLocation(property, declaration) : checker.getDeclaredTypeOfSymbol(property);
373
+ return {
374
+ name: property.getName(),
375
+ optional: toOptionalFlag(property, tsMod),
376
+ readonly: hasReadonlyModifier(declaration, tsMod),
377
+ type: serializeTypeNode(propertyType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry)
378
+ };
379
+ });
380
+ return snapshots.sort(compareByName);
381
+ };
382
+ var serializeIndexSignature = (type, checker, tsMod, depth, maxDepth, visited, onInternalError, registry) => {
383
+ const infos = getIndexInfosOfType(type, checker);
384
+ if (!infos || infos.length === 0)
385
+ return void 0;
386
+ const first = infos[0];
387
+ if (!first)
388
+ return void 0;
389
+ return {
390
+ keyType: serializeTypeNode(first.keyType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry),
391
+ valueType: serializeTypeNode(first.type, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry),
392
+ readonly: first.isReadonly ?? false
393
+ };
394
+ };
395
+ var primitiveTypeNode = (type, checker, tsMod) => {
396
+ const text = checker.typeToString(type);
397
+ if ((type.flags & tsMod.TypeFlags.Any) !== 0) {
398
+ return { kind: "any", text };
399
+ }
400
+ if ((type.flags & tsMod.TypeFlags.Unknown) !== 0) {
401
+ return { kind: "unknown", text };
402
+ }
403
+ if ((type.flags & tsMod.TypeFlags.Never) !== 0) {
404
+ return { kind: "never", text };
405
+ }
406
+ if ((type.flags & tsMod.TypeFlags.StringLike) !== 0 || (type.flags & tsMod.TypeFlags.NumberLike) !== 0 || (type.flags & tsMod.TypeFlags.BooleanLike) !== 0 || (type.flags & tsMod.TypeFlags.BigIntLike) !== 0 || (type.flags & tsMod.TypeFlags.ESSymbolLike) !== 0 || (type.flags & tsMod.TypeFlags.Null) !== 0 || (type.flags & tsMod.TypeFlags.Undefined) !== 0 || (type.flags & tsMod.TypeFlags.Void) !== 0) {
407
+ return { kind: "primitive", text };
408
+ }
409
+ return void 0;
410
+ };
411
+ var UNKNOWN_NODE = { kind: "unknown", text: "unknown" };
412
+ var serializeTypeNode = (type, checker, tsMod, depth, maxDepth, visited, onInternalError, registry) => {
413
+ const text = checker.typeToString(type);
414
+ const reg = (node) => {
415
+ registry?.set(node, type);
416
+ return node;
417
+ };
418
+ const typeId = `${type.id ?? "anon"}:${text}`;
419
+ if (depth > maxDepth || visited.has(typeId)) {
420
+ return reg({ kind: "reference", text });
421
+ }
422
+ visited.add(typeId);
423
+ const literal = asLiteral(type, checker, tsMod);
424
+ if (literal) {
425
+ return reg(literal);
426
+ }
427
+ if (type.isUnion()) {
428
+ const union = {
429
+ kind: "union",
430
+ text,
431
+ elements: type.types.map((value) => serializeTypeNode(value, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry))
432
+ };
433
+ return reg(union);
434
+ }
435
+ if (type.isIntersection()) {
436
+ const intersection = {
437
+ kind: "intersection",
438
+ text,
439
+ elements: type.types.map((value) => serializeTypeNode(value, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry))
440
+ };
441
+ return reg(intersection);
442
+ }
443
+ const primitive = primitiveTypeNode(type, checker, tsMod);
444
+ if (primitive) {
445
+ return reg(primitive);
446
+ }
447
+ if ((type.flags & tsMod.TypeFlags.Enum) !== 0) {
448
+ const members = [];
449
+ try {
450
+ const props = checker.getPropertiesOfType(type);
451
+ for (const sym of props) {
452
+ const name = sym.name;
453
+ let value;
454
+ const decl = sym.valueDeclaration;
455
+ if (decl && tsMod.isEnumMember?.(decl) && decl.initializer) {
456
+ const init2 = decl.initializer;
457
+ if (tsMod.isNumericLiteral?.(init2)) {
458
+ value = parseInt(init2.text, 10);
459
+ } else if (tsMod.isStringLiteral?.(init2) || tsMod.isNoSubstitutionTemplateLiteral?.(init2)) {
460
+ value = init2.text;
461
+ } else {
462
+ const cv = checker.getConstantValue?.(init2);
463
+ if (cv !== void 0)
464
+ value = cv;
465
+ }
466
+ }
467
+ members.push(value !== void 0 ? { name, value } : { name });
468
+ }
469
+ } catch (err) {
470
+ onInternalError?.(err, "enum-members");
471
+ }
472
+ const enumNode = {
473
+ kind: "enum",
474
+ text,
475
+ members: members.length > 0 ? members : void 0
476
+ };
477
+ return reg(enumNode);
478
+ }
479
+ if ((type.flags & tsMod.TypeFlags.Conditional) !== 0) {
480
+ const ct = type;
481
+ const trueType = ct.resolvedTrueType ?? (ct.root?.node?.trueType ? checker.getTypeFromTypeNode?.(ct.root.node.trueType) : void 0);
482
+ const falseType = ct.resolvedFalseType ?? (ct.root?.node?.falseType ? checker.getTypeFromTypeNode?.(ct.root.node.falseType) : void 0);
483
+ const conditional = {
484
+ kind: "conditional",
485
+ text,
486
+ checkType: serializeTypeNode(ct.checkType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry),
487
+ extendsType: serializeTypeNode(ct.extendsType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry),
488
+ trueType: trueType ? serializeTypeNode(trueType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry) : UNKNOWN_NODE,
489
+ falseType: falseType ? serializeTypeNode(falseType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry) : UNKNOWN_NODE
490
+ };
491
+ return reg(conditional);
492
+ }
493
+ if ((type.flags & tsMod.TypeFlags.IndexedAccess) !== 0) {
494
+ const iat = type;
495
+ const indexed = {
496
+ kind: "indexedAccess",
497
+ text,
498
+ objectType: serializeTypeNode(iat.objectType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry),
499
+ indexType: serializeTypeNode(iat.indexType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry)
500
+ };
501
+ return reg(indexed);
502
+ }
503
+ if ((type.flags & tsMod.TypeFlags.TemplateLiteral) !== 0) {
504
+ const tlt = type;
505
+ const texts = tlt.texts ?? [];
506
+ const types = tlt.types ?? [];
507
+ const template = {
508
+ kind: "templateLiteral",
509
+ text,
510
+ texts,
511
+ types: types.map((t) => serializeTypeNode(t, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry))
512
+ };
513
+ return reg(template);
514
+ }
515
+ const objType = type;
516
+ const mappedFlag = tsMod.ObjectFlags?.Mapped ?? FALLBACK_OBJECT_FLAGS_MAPPED;
517
+ if (objType.objectFlags !== void 0 && (objType.objectFlags & mappedFlag) !== 0) {
518
+ const mt = type;
519
+ const constraintType = mt.constraint ?? mt.typeParameter?.constraint;
520
+ const mappedType = mt.templateType ?? mt.mappedType;
521
+ const mapped = {
522
+ kind: "mapped",
523
+ text,
524
+ constraintType: constraintType ? serializeTypeNode(constraintType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry) : UNKNOWN_NODE,
525
+ mappedType: mappedType ? serializeTypeNode(mappedType, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry) : UNKNOWN_NODE
526
+ };
527
+ return reg(mapped);
528
+ }
529
+ if ((type.flags & tsMod.TypeFlags.Index) !== 0) {
530
+ const idxType = type;
531
+ const typeOperator = {
532
+ kind: "typeOperator",
533
+ text,
534
+ operator: "keyof",
535
+ type: serializeTypeNode(idxType.type, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry)
536
+ };
537
+ return reg(typeOperator);
538
+ }
539
+ if (checker.isTupleType(type)) {
540
+ const typeArguments = checker.getTypeArguments(type);
541
+ const tuple = {
542
+ kind: "tuple",
543
+ text,
544
+ elements: typeArguments.map((value) => serializeTypeNode(value, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry))
545
+ };
546
+ return reg(tuple);
547
+ }
548
+ if (checker.isArrayType(type)) {
549
+ const typeArguments = checker.getTypeArguments(type);
550
+ const element = typeArguments[0];
551
+ const array = {
552
+ kind: "array",
553
+ text,
554
+ elements: element ? [serializeTypeNode(element, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry)] : [UNKNOWN_NODE]
555
+ };
556
+ return reg(array);
557
+ }
558
+ const referenceArguments = checker.getTypeArguments(type);
559
+ if (referenceArguments.length > 0) {
560
+ const ref = {
561
+ kind: "reference",
562
+ text,
563
+ typeArguments: referenceArguments.map((value) => serializeTypeNode(value, checker, tsMod, depth + 1, maxDepth, visited, onInternalError, registry))
564
+ };
565
+ return reg(ref);
566
+ }
567
+ const constructSignatures = checker.getSignaturesOfType(type, tsMod.SignatureKind.Construct);
568
+ if (constructSignatures.length > 0) {
569
+ const sig = serializeFunctionSignature(constructSignatures[0], checker, tsMod, depth, maxDepth, visited, onInternalError, registry);
570
+ const ctor = {
571
+ kind: "constructor",
572
+ text,
573
+ parameters: sig.parameters,
574
+ returnType: sig.returnType
575
+ };
576
+ return reg(ctor);
577
+ }
578
+ const callSignatures = checker.getSignaturesOfType(type, tsMod.SignatureKind.Call);
579
+ if (callSignatures.length > 0) {
580
+ if (callSignatures.length > 1) {
581
+ const signatures = callSignatures.map((s) => {
582
+ const serialized = serializeFunctionSignature(s, checker, tsMod, depth, maxDepth, visited, onInternalError, registry);
583
+ return { parameters: serialized.parameters, returnType: serialized.returnType };
584
+ });
585
+ const overload = { kind: "overloadSet", text, signatures };
586
+ return reg(overload);
587
+ }
588
+ const signature = serializeFunctionSignature(callSignatures[0], checker, tsMod, depth, maxDepth, visited, onInternalError, registry);
589
+ const fn = {
590
+ kind: "function",
591
+ text,
592
+ parameters: signature.parameters,
593
+ returnType: signature.returnType
594
+ };
595
+ return reg(fn);
596
+ }
597
+ const indexSig = serializeIndexSignature(type, checker, tsMod, depth, maxDepth, visited, onInternalError, registry);
598
+ const object = {
599
+ kind: "object",
600
+ text,
601
+ properties: serializeObjectProperties(type, checker, tsMod, depth, maxDepth, visited, onInternalError, registry),
602
+ ...indexSig !== void 0 && { indexSignature: indexSig }
603
+ };
604
+ return reg(object);
605
+ };
606
+ function createTypeTargetBootstrapContent(specs) {
607
+ const seen = /* @__PURE__ */ new Set();
608
+ const lines = [
609
+ "/**",
610
+ " * Auto-generated bootstrap for type target resolution.",
611
+ " * Imports canonical modules so resolveTypeTargetsFromSpecs can find types.",
612
+ " * Include in program rootNames when using typeTargetSpecs without user imports.",
613
+ " */"
614
+ ];
615
+ for (const spec of specs) {
616
+ if (seen.has(spec.module))
617
+ continue;
618
+ seen.add(spec.module);
619
+ const id = spec.module.replace(/\W+/g, "_").replace(/_+/g, "_") || "m";
620
+ lines.push(`import * as _${id} from "${spec.module}";`);
621
+ lines.push(`void _${id};`);
622
+ }
623
+ lines.push("export {};");
624
+ return lines.join("\n");
625
+ }
626
+ function resolveTypeTargetsFromSpecs(program, tsMod, specs) {
627
+ const checker = program.getTypeChecker();
628
+ const found = /* @__PURE__ */ new Map();
629
+ const getTypeFromSymbol = (symbol) => {
630
+ const aliased = getAliasedSymbol(symbol, checker, tsMod);
631
+ const decls = aliased.declarations ?? (aliased.valueDeclaration ? [aliased.valueDeclaration] : []);
632
+ const typeDecl = decls.find((d) => tsMod.isTypeAliasDeclaration(d) || tsMod.isInterfaceDeclaration(d) || tsMod.isTypeParameterDeclaration(d));
633
+ const decl = typeDecl ?? decls[0];
634
+ const useDeclaredType = decl && (tsMod.isTypeAliasDeclaration(decl) || tsMod.isInterfaceDeclaration(decl) || tsMod.isTypeParameterDeclaration(decl));
635
+ const type = useDeclaredType ? checker.getDeclaredTypeOfSymbol(aliased) : decl ? checker.getTypeOfSymbolAtLocation(aliased, decl) : checker.getDeclaredTypeOfSymbol(aliased);
636
+ if (!type || (type.flags & tsMod.TypeFlags.Any) !== 0)
637
+ return void 0;
638
+ return type;
639
+ };
640
+ const getTypeFromSpec = (symbol, spec) => {
641
+ const primaryType = getTypeFromSymbol(symbol);
642
+ if (!primaryType || !spec.typeMember)
643
+ return primaryType;
644
+ const aliased = getAliasedSymbol(symbol, checker, tsMod);
645
+ const exports2 = getSymbolExports(aliased);
646
+ if (!exports2)
647
+ return primaryType;
648
+ const memberSymbol = Array.from(exports2.values()).find((s) => s.getName() === spec.typeMember);
649
+ if (!memberSymbol)
650
+ return primaryType;
651
+ const memberType = checker.getDeclaredTypeOfSymbol(memberSymbol);
652
+ if (!memberType || (memberType.flags & tsMod.TypeFlags.Any) !== 0)
653
+ return primaryType;
654
+ return memberType;
655
+ };
656
+ const addFromModuleSymbol = (moduleSymbol, moduleSpec) => {
657
+ if (!moduleSymbol)
658
+ return;
659
+ const exportsByName = new Map(checker.getExportsOfModule(moduleSymbol).map((moduleExport) => [
660
+ moduleExport.getName(),
661
+ moduleExport
662
+ ]));
663
+ for (const spec of specs) {
664
+ if (spec.module !== moduleSpec || found.has(spec.id))
665
+ continue;
666
+ const moduleExport = exportsByName.get(spec.exportName);
667
+ if (!moduleExport)
668
+ continue;
669
+ const type = getTypeFromSpec(moduleExport, spec);
670
+ if (type)
671
+ found.set(spec.id, type);
672
+ }
673
+ };
674
+ for (const sourceFile of program.getSourceFiles()) {
675
+ if (sourceFile.isDeclarationFile)
676
+ continue;
677
+ tsMod.forEachChild(sourceFile, (node) => {
678
+ if (!tsMod.isImportDeclaration(node))
679
+ return;
680
+ const moduleSpecifier = node.moduleSpecifier;
681
+ if (!tsMod.isStringLiteral(moduleSpecifier))
682
+ return;
683
+ const moduleSpec = moduleSpecifier.text;
684
+ const binding = node.importClause;
685
+ if (!binding)
686
+ return;
687
+ const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier);
688
+ const addNamed = (name) => {
689
+ const exportName = (name.propertyName ?? name.name).getText(sourceFile);
690
+ const spec = specs.find((s) => s.module === moduleSpec && s.exportName === exportName);
691
+ if (!spec || found.has(spec.id))
692
+ return;
693
+ const symbol = checker.getSymbolAtLocation(name.name);
694
+ if (!symbol)
695
+ return;
696
+ const type = getTypeFromSpec(symbol, spec);
697
+ if (type)
698
+ found.set(spec.id, type);
699
+ };
700
+ if (binding.namedBindings) {
701
+ if (tsMod.isNamedImports(binding.namedBindings)) {
702
+ for (const elem of binding.namedBindings.elements) {
703
+ addNamed(elem);
704
+ }
705
+ } else if (tsMod.isNamespaceImport(binding.namedBindings)) {
706
+ const nsName = binding.namedBindings.name;
707
+ const symbol = checker.getSymbolAtLocation(nsName);
708
+ const nsType = symbol ? checker.getTypeOfSymbolAtLocation(symbol, nsName) : void 0;
709
+ for (const spec of specs) {
710
+ if (spec.module !== moduleSpec || found.has(spec.id))
711
+ continue;
712
+ const prop = nsType?.getProperty?.(spec.exportName);
713
+ if (!prop)
714
+ continue;
715
+ const type = getTypeFromSpec(prop, spec);
716
+ if (type)
717
+ found.set(spec.id, type);
718
+ }
719
+ addFromModuleSymbol(moduleSymbol, moduleSpec);
720
+ }
721
+ } else if (binding.name) {
722
+ const symbol = checker.getSymbolAtLocation(binding.name);
723
+ const nsType = symbol ? checker.getTypeOfSymbolAtLocation(symbol, binding.name) : void 0;
724
+ for (const spec of specs) {
725
+ if (spec.module !== moduleSpec || found.has(spec.id))
726
+ continue;
727
+ const prop = nsType?.getProperty?.(spec.exportName);
728
+ if (!prop)
729
+ continue;
730
+ const type = getTypeFromSpec(prop, spec);
731
+ if (type)
732
+ found.set(spec.id, type);
733
+ }
734
+ addFromModuleSymbol(moduleSymbol, moduleSpec);
735
+ }
736
+ });
737
+ }
738
+ return specs.filter((s) => found.has(s.id)).map((s) => ({ id: s.id, type: found.get(s.id) }));
739
+ }
740
+ var resolveExportSymbol = (symbol, checker, tsMod) => getAliasedSymbol(symbol, checker, tsMod);
741
+ var getGenericBase = (type, checker) => getTypeReferenceTarget(type, checker);
742
+ var getComparisonSymbol = (type, checker) => {
743
+ const base = getGenericBase(type, checker);
744
+ if (base?.symbol)
745
+ return base.symbol;
746
+ return getTypeSymbol(type);
747
+ };
748
+ var isAssignableTo = (source, target, checker, tsMod, mode) => {
749
+ if (checker.isTypeAssignableTo(source, target))
750
+ return true;
751
+ if (mode === "strict")
752
+ return false;
753
+ const tgtBase = getGenericBase(target, checker);
754
+ const tgtSymbol = tgtBase?.symbol ?? getTypeSymbol(target);
755
+ const matchSymbol = (sym) => sym && tgtSymbol && sym === tgtSymbol;
756
+ if (source.isUnion()) {
757
+ const constituents = source.types;
758
+ if (!constituents.every((t) => isAssignableTo(t, target, checker, tsMod, mode)))
759
+ return false;
760
+ return true;
761
+ }
762
+ const srcBase = getGenericBase(source, checker);
763
+ if (srcBase?.symbol && matchSymbol(srcBase.symbol))
764
+ return true;
765
+ const tgtTarget = getTypeReferenceTarget(target, checker);
766
+ if (srcBase?.symbol && tgtTarget?.symbol && srcBase.symbol === tgtTarget.symbol)
767
+ return true;
768
+ const srcSymbol = getComparisonSymbol(source, checker);
769
+ if (matchSymbol(srcSymbol))
770
+ return true;
771
+ if ((source.flags & tsMod.TypeFlags.Object) !== 0) {
772
+ const srcSym = source.symbol;
773
+ const isClassOrInterface = srcSym && (srcSym.flags & (tsMod.SymbolFlags.Class | tsMod.SymbolFlags.Interface)) !== 0;
774
+ if (isClassOrInterface) {
775
+ const bases = getBaseTypes(source, checker);
776
+ const hasMatchingBase = (bases ?? []).some((b) => {
777
+ const bSym = getTypeSymbol(b);
778
+ return bSym && matchSymbol(bSym);
779
+ });
780
+ if (hasMatchingBase)
781
+ return true;
782
+ }
783
+ }
784
+ const tgtName = tgtSymbol?.getName();
785
+ if (tgtName && srcBase?.symbol?.getName() === tgtName)
786
+ return true;
787
+ if (tgtName && srcSymbol?.getName() === tgtName)
788
+ return true;
789
+ return false;
790
+ };
791
+ var serializeExport = (symbol, checker, tsMod, maxDepth, onInternalError, registry) => {
792
+ const resolved = resolveExportSymbol(symbol, checker, tsMod);
793
+ const declaration = resolved.valueDeclaration ?? resolved.declarations?.[0];
794
+ const useDeclaredType = declaration && (tsMod.isTypeAliasDeclaration(declaration) || tsMod.isInterfaceDeclaration(declaration));
795
+ const exportedType = useDeclaredType ? checker.getDeclaredTypeOfSymbol(resolved) : declaration ? checker.getTypeOfSymbolAtLocation(resolved, declaration) : checker.getDeclaredTypeOfSymbol(resolved);
796
+ return {
797
+ name: symbol.getName(),
798
+ declarationKind: declaration ? tsMod.SyntaxKind[declaration.kind] : void 0,
799
+ declarationText: declaration ? declaration.getText() : void 0,
800
+ docs: tsMod.displayPartsToString(symbol.getDocumentationComment(checker)) || void 0,
801
+ type: serializeTypeNode(exportedType, checker, tsMod, 0, maxDepth, /* @__PURE__ */ new Set(), onInternalError, registry)
802
+ };
803
+ };
804
+ var collectImports = (sourceFile, program, tsMod) => {
805
+ const imports = [];
806
+ tsMod.forEachChild(sourceFile, (node) => {
807
+ if (!tsMod.isImportDeclaration(node))
808
+ return;
809
+ const moduleSpecifier = node.moduleSpecifier;
810
+ if (!tsMod.isStringLiteral(moduleSpecifier))
811
+ return;
812
+ const spec = moduleSpecifier.text;
813
+ const binding = node.importClause;
814
+ let info = { moduleSpecifier: spec };
815
+ if (binding) {
816
+ if (binding.namedBindings) {
817
+ if (tsMod.isNamedImports(binding.namedBindings)) {
818
+ info = {
819
+ ...info,
820
+ importedNames: binding.namedBindings.elements.map((el) => (el.propertyName ?? el.name).getText(sourceFile))
821
+ };
822
+ } else if (tsMod.isNamespaceImport(binding.namedBindings)) {
823
+ info = {
824
+ ...info,
825
+ namespaceImport: binding.namedBindings.name.getText(sourceFile)
826
+ };
827
+ }
828
+ }
829
+ if (binding.name) {
830
+ info = { ...info, defaultImport: binding.name.getText(sourceFile) };
831
+ }
832
+ }
833
+ imports.push(info);
834
+ });
835
+ return imports;
836
+ };
837
+ var createFileSnapshot = (sourceFile, checker, program, tsMod, maxDepth, includeImports, onInternalError, registry) => {
838
+ const filePath = sourceFile.fileName;
839
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
840
+ const exports2 = moduleSymbol ? checker.getExportsOfModule(moduleSymbol).map((value) => serializeExport(value, checker, tsMod, maxDepth, onInternalError, registry)).sort(compareByName) : [];
841
+ const imports = includeImports ? collectImports(sourceFile, program, tsMod) : void 0;
842
+ return {
843
+ filePath,
844
+ exports: exports2,
845
+ ...imports !== void 0 && imports.length > 0 ? { imports } : {}
846
+ };
847
+ };
848
+ var applyProjection = (type, steps, checker, tsMod, opts) => {
849
+ const { onInternalError, targetsByIdMap, assignabilityMode, maxDepth } = opts;
850
+ let current = type;
851
+ for (const step of steps) {
852
+ try {
853
+ switch (step.kind) {
854
+ case "returnType": {
855
+ const sigs = checker.getSignaturesOfType(current, tsMod.SignatureKind.Call);
856
+ if (sigs.length === 0)
857
+ return void 0;
858
+ current = checker.getReturnTypeOfSignature(sigs[0]);
859
+ break;
860
+ }
861
+ case "param": {
862
+ const sigs = checker.getSignaturesOfType(current, tsMod.SignatureKind.Call);
863
+ if (sigs.length === 0)
864
+ return void 0;
865
+ const params = sigs[0].getParameters();
866
+ if (step.index < 0 || step.index >= params.length)
867
+ return void 0;
868
+ const param = params[step.index];
869
+ const decl = param.valueDeclaration ?? param.declarations?.[0];
870
+ current = decl ? checker.getTypeOfSymbolAtLocation(param, decl) : checker.getDeclaredTypeOfSymbol(param);
871
+ break;
872
+ }
873
+ case "typeArg": {
874
+ const args = checker.getTypeArguments(current);
875
+ if (step.index < 0 || step.index >= args.length)
876
+ return void 0;
877
+ current = args[step.index];
878
+ break;
879
+ }
880
+ case "property": {
881
+ const prop = current.getProperty(step.name);
882
+ if (!prop)
883
+ return void 0;
884
+ const decl = prop.valueDeclaration ?? prop.declarations?.[0];
885
+ current = decl ? checker.getTypeOfSymbolAtLocation(prop, decl) : checker.getDeclaredTypeOfSymbol(prop);
886
+ break;
887
+ }
888
+ case "ensure": {
889
+ const target = targetsByIdMap.get(step.targetId);
890
+ if (!target)
891
+ return void 0;
892
+ if (!isAssignableTo(current, target, checker, tsMod, assignabilityMode))
893
+ return void 0;
894
+ break;
895
+ }
896
+ case "predicate": {
897
+ const serialized = serializeTypeNode(current, checker, tsMod, 0, maxDepth, /* @__PURE__ */ new Set(), onInternalError);
898
+ if (!step.fn(serialized))
899
+ return void 0;
900
+ break;
901
+ }
902
+ default:
903
+ return void 0;
904
+ }
905
+ } catch (err) {
906
+ onInternalError?.(err, `applyProjection:${step.kind}`);
907
+ return void 0;
908
+ }
909
+ }
910
+ return current;
911
+ };
912
+ var createTypeInfoApiSession = (options) => {
913
+ let effectiveTypeTargets = options.typeTargets ?? (options.typeTargetSpecs?.length ? resolveTypeTargetsFromSpecs(options.program, options.ts, options.typeTargetSpecs) : void 0);
914
+ const failWhenNoTargets = options.failWhenNoTargetsResolved !== false;
915
+ if (failWhenNoTargets && options.typeTargetSpecs && options.typeTargetSpecs.length > 0 && (!effectiveTypeTargets || effectiveTypeTargets.length === 0)) {
916
+ const modules = [...new Set(options.typeTargetSpecs.map((s) => s.module))].join(", ");
917
+ throw new Error(`type targets could not be resolved; ensure program includes imports from: ${modules}. Use createTypeTargetBootstrapContent(typeTargetSpecs) to generate a bootstrap file and add it to program rootNames.`);
918
+ }
919
+ const checker = options.program.getTypeChecker();
920
+ const descriptors = /* @__PURE__ */ new Map();
921
+ const snapshotCache = /* @__PURE__ */ new Map();
922
+ const directoryCache = /* @__PURE__ */ new Map();
923
+ const maxDepth = options.maxTypeDepth ?? DEFAULT_MAX_DEPTH;
924
+ const assignabilityMode = options.assignabilityMode ?? "compatibility";
925
+ const typeNodeRegistry = /* @__PURE__ */ new WeakMap();
926
+ const targetsByIdMap = new Map((effectiveTypeTargets ?? []).map((t) => [t.id, t.type]));
927
+ const registerDescriptor = (descriptor) => {
928
+ if (descriptor.type === "file") {
929
+ descriptors.set(`file:${descriptor.path}`, descriptor);
930
+ return;
931
+ }
932
+ const globs = descriptor.relativeGlobs.join("|");
933
+ descriptors.set(`glob:${descriptor.baseDir}:${descriptor.recursive ? "r" : "nr"}:${globs}`, descriptor);
934
+ };
935
+ const file = (relativePath, queryOptions) => {
936
+ const baseDirResult = validatePathSegment(queryOptions.baseDir, "baseDir");
937
+ if (!baseDirResult.ok)
938
+ return { ok: false, error: "invalid-input" };
939
+ const relativePathResult = validatePathSegment(relativePath, "relativePath");
940
+ if (!relativePathResult.ok)
941
+ return { ok: false, error: "invalid-input" };
942
+ const baseDir = baseDirResult.value;
943
+ const normalizedRelativePath = relativePathResult.value;
944
+ const pathResult = resolvePathUnderBase(baseDir, normalizedRelativePath);
945
+ if (!pathResult.ok) {
946
+ return {
947
+ ok: false,
948
+ error: "path-escapes-base",
949
+ path: resolveRelativePath(baseDir, normalizedRelativePath)
950
+ };
951
+ }
952
+ const absolutePath = pathResult.path;
953
+ try {
954
+ if (!pathIsUnderBase(baseDir, absolutePath)) {
955
+ return { ok: false, error: "path-escapes-base", path: absolutePath };
956
+ }
957
+ } catch {
958
+ return { ok: false, error: "path-escapes-base", path: absolutePath };
959
+ }
960
+ if (queryOptions.watch) {
961
+ registerDescriptor({
962
+ type: "file",
963
+ path: absolutePath
964
+ });
965
+ }
966
+ const sourceFile = options.program.getSourceFile(absolutePath);
967
+ if (!sourceFile) {
968
+ return { ok: false, error: "file-not-in-program", path: absolutePath };
969
+ }
970
+ const cached = snapshotCache.get(absolutePath);
971
+ if (cached !== void 0) {
972
+ return { ok: true, snapshot: cached };
973
+ }
974
+ const snapshot = createFileSnapshot(sourceFile, checker, options.program, options.ts, maxDepth, true, options.onInternalError, typeNodeRegistry);
975
+ snapshotCache.set(absolutePath, snapshot);
976
+ return { ok: true, snapshot };
977
+ };
978
+ const directoryCacheKey = (baseDir, normalizedGlobs, recursive) => `${baseDir}\0${normalizedGlobs.join("\0")}\0${recursive ? "r" : "nr"}`;
979
+ const directory = (relativeGlobs, queryOptions) => {
980
+ const baseDirResult = validatePathSegment(queryOptions.baseDir, "baseDir");
981
+ if (!baseDirResult.ok)
982
+ return [];
983
+ const baseDir = baseDirResult.value;
984
+ const globsResult = validateRelativeGlobs(relativeGlobs, "relativeGlobs");
985
+ if (!globsResult.ok)
986
+ return [];
987
+ const normalizedGlobs = dedupeSorted(globsResult.value);
988
+ const cacheKey = directoryCacheKey(baseDir, normalizedGlobs, queryOptions.recursive ?? false);
989
+ const cached = directoryCache.get(cacheKey);
990
+ if (cached !== void 0)
991
+ return cached;
992
+ if (queryOptions.watch) {
993
+ registerDescriptor({
994
+ type: "glob",
995
+ baseDir: toPosixPath(baseDir),
996
+ relativeGlobs: normalizedGlobs,
997
+ recursive: queryOptions.recursive
998
+ });
999
+ }
1000
+ const depth = queryOptions.recursive ? void 0 : 1;
1001
+ const includes = queryOptions.recursive && normalizedGlobs.every((g) => !g.includes("**")) ? [...normalizedGlobs, ...normalizedGlobs.map((g) => `**/${g}`)] : normalizedGlobs;
1002
+ const matchedPaths = options.ts.sys.readDirectory(baseDir, TYPE_EXTENSIONS, void 0, includes, depth);
1003
+ const normalizedMatches = dedupeSorted(matchedPaths.map((value) => resolveRelativePath(baseDir, value)));
1004
+ const underBase = normalizedMatches.filter((filePath) => pathIsUnderBase(baseDir, filePath));
1005
+ const filteredMatches = queryOptions.recursive ? underBase : underBase.filter((filePath) => {
1006
+ const relativePath = toPosixPath((0, import_node_path2.relative)(baseDir, filePath));
1007
+ return !relativePath.includes("/");
1008
+ });
1009
+ const program = options.program;
1010
+ const tsMod = options.ts;
1011
+ const snapshots = filteredMatches.flatMap((filePath) => {
1012
+ const sf = program.getSourceFile(filePath);
1013
+ if (!sf)
1014
+ return [];
1015
+ try {
1016
+ return [
1017
+ createFileSnapshot(sf, checker, program, tsMod, maxDepth, true, options.onInternalError, typeNodeRegistry)
1018
+ ];
1019
+ } catch (err) {
1020
+ options.onInternalError?.(err, `directory() serialization for ${filePath}`);
1021
+ return [];
1022
+ }
1023
+ });
1024
+ directoryCache.set(cacheKey, snapshots);
1025
+ return snapshots;
1026
+ };
1027
+ const resolveExport = (baseDir, filePath, exportName) => {
1028
+ const result = file(filePath, { baseDir });
1029
+ if (!result.ok)
1030
+ return void 0;
1031
+ return result.snapshot.exports.find((e) => e.name === exportName);
1032
+ };
1033
+ const apiIsAssignableTo = (node, targetId, projection) => {
1034
+ const sourceType = typeNodeRegistry.get(node);
1035
+ if (!sourceType)
1036
+ return false;
1037
+ const targetType = targetsByIdMap.get(targetId);
1038
+ if (!targetType)
1039
+ return false;
1040
+ const projected = projection?.length ? applyProjection(sourceType, projection, checker, options.ts, {
1041
+ onInternalError: options.onInternalError,
1042
+ targetsByIdMap,
1043
+ assignabilityMode,
1044
+ maxDepth
1045
+ }) : sourceType;
1046
+ if (!projected)
1047
+ return false;
1048
+ return isAssignableTo(projected, targetType, checker, options.ts, assignabilityMode);
1049
+ };
1050
+ return {
1051
+ api: {
1052
+ file,
1053
+ directory,
1054
+ resolveExport,
1055
+ isAssignableTo: apiIsAssignableTo
1056
+ },
1057
+ consumeDependencies: () => [...descriptors.values()]
1058
+ };
1059
+ };
1060
+
1061
+ // ../virtual-modules/dist/NodeModulePluginLoader.js
1062
+ var import_node_fs2 = require("fs");
1063
+ var import_node_module = require("module");
1064
+ var import_node_path3 = require("path");
1065
+ var import_node_vm = require("vm");
1066
+ var toMessage2 = (error) => {
1067
+ if (error instanceof Error) {
1068
+ return error.message;
1069
+ }
1070
+ return String(error);
1071
+ };
1072
+ var isPluginLike = (value) => {
1073
+ if (!value || typeof value !== "object") {
1074
+ return false;
1075
+ }
1076
+ const candidate = value;
1077
+ return typeof candidate.name === "string" && typeof candidate.shouldResolve === "function" && typeof candidate.build === "function";
1078
+ };
1079
+ var invalidPluginError = (request, message) => ({
1080
+ status: "error",
1081
+ specifier: request.specifier,
1082
+ baseDir: request.baseDir,
1083
+ code: "invalid-plugin-export",
1084
+ message
1085
+ });
1086
+ var loadFailedError = (request, message) => ({
1087
+ status: "error",
1088
+ specifier: request.specifier,
1089
+ baseDir: request.baseDir,
1090
+ code: "module-load-failed",
1091
+ message
1092
+ });
1093
+ var notFoundError = (request, message) => ({
1094
+ status: "error",
1095
+ specifier: request.specifier,
1096
+ baseDir: request.baseDir,
1097
+ code: "module-not-found",
1098
+ message
1099
+ });
1100
+ var pathEscapesError = (request, message) => ({
1101
+ status: "error",
1102
+ specifier: request.specifier,
1103
+ baseDir: request.baseDir,
1104
+ code: "path-escapes-base",
1105
+ message
1106
+ });
1107
+ var MAX_PATH_LENGTH = 4096;
1108
+ var invalidRequestError = (message) => ({
1109
+ status: "error",
1110
+ specifier: "",
1111
+ baseDir: "",
1112
+ code: "invalid-request",
1113
+ message
1114
+ });
1115
+ var getErrorCode = (error) => typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
1116
+ var NodeModulePluginLoader = class {
1117
+ load(input) {
1118
+ if (isPluginLike(input)) {
1119
+ return {
1120
+ status: "loaded",
1121
+ plugin: input,
1122
+ resolvedPath: "<preloaded>"
1123
+ };
1124
+ }
1125
+ const request = input;
1126
+ if (typeof request.baseDir !== "string" || request.baseDir.trim() === "") {
1127
+ return invalidRequestError("baseDir must be a non-empty string");
1128
+ }
1129
+ if (typeof request.specifier !== "string" || request.specifier.trim() === "") {
1130
+ return invalidRequestError("specifier must be a non-empty string");
1131
+ }
1132
+ if (request.baseDir.length > MAX_PATH_LENGTH || request.specifier.length > MAX_PATH_LENGTH) {
1133
+ return invalidRequestError(`baseDir and specifier must be at most ${MAX_PATH_LENGTH} characters`);
1134
+ }
1135
+ const require2 = (0, import_node_module.createRequire)((0, import_node_path3.resolve)(request.baseDir, "__typed_virtual_modules_loader__.cjs"));
1136
+ let resolvedPath;
1137
+ try {
1138
+ resolvedPath = require2.resolve(request.specifier, { paths: [request.baseDir] });
1139
+ } catch (error) {
1140
+ return notFoundError(request, `Could not resolve plugin "${request.specifier}" from "${request.baseDir}": ${sanitizeErrorMessage(toMessage2(error))}`);
1141
+ }
1142
+ if (!pathIsUnderBase(request.baseDir, resolvedPath)) {
1143
+ return pathEscapesError(request, sanitizeErrorMessage(`Resolved plugin path "${resolvedPath}" is not under baseDir "${request.baseDir}"`));
1144
+ }
1145
+ let mod;
1146
+ try {
1147
+ mod = require2(resolvedPath);
1148
+ } catch (error) {
1149
+ const errorCode = getErrorCode(error);
1150
+ if (errorCode === "ERR_REQUIRE_ASYNC_MODULE") {
1151
+ return loadFailedError(request, sanitizeErrorMessage(`Could not load plugin module "${resolvedPath}": plugin module uses top-level await and cannot be loaded synchronously`));
1152
+ }
1153
+ if (errorCode === "ERR_REQUIRE_ESM") {
1154
+ const esmFallback = this.#loadSyncEsmModule(resolvedPath, require2);
1155
+ if (esmFallback.status === "loaded") {
1156
+ mod = esmFallback.moduleExport;
1157
+ } else {
1158
+ return loadFailedError(request, esmFallback.message);
1159
+ }
1160
+ } else {
1161
+ return loadFailedError(request, `Could not load plugin module "${resolvedPath}": ${sanitizeErrorMessage(toMessage2(error))}`);
1162
+ }
1163
+ }
1164
+ const normalizedPlugin = this.#normalizeModuleExport(mod);
1165
+ if (!normalizedPlugin) {
1166
+ return invalidPluginError(request, sanitizeErrorMessage(`Resolved module "${resolvedPath}" does not export a valid VirtualModulePlugin`));
1167
+ }
1168
+ return {
1169
+ status: "loaded",
1170
+ plugin: normalizedPlugin,
1171
+ resolvedPath
1172
+ };
1173
+ }
1174
+ loadMany(inputs) {
1175
+ return inputs.map((input) => this.load(input));
1176
+ }
1177
+ #loadSyncEsmModule(resolvedPath, localRequire) {
1178
+ let tsMod;
1179
+ try {
1180
+ tsMod = localRequire("typescript");
1181
+ } catch (error) {
1182
+ return loadFailedError({ specifier: resolvedPath, baseDir: (0, import_node_path3.dirname)(resolvedPath) }, sanitizeErrorMessage(`Could not load sync ESM plugin "${resolvedPath}": failed to load TypeScript for transpilation: ${toMessage2(error)}`));
1183
+ }
1184
+ try {
1185
+ const sourceText = (0, import_node_fs2.readFileSync)(resolvedPath, "utf8");
1186
+ const transpiled = tsMod.transpileModule(sourceText, {
1187
+ fileName: resolvedPath,
1188
+ compilerOptions: {
1189
+ module: tsMod.ModuleKind.CommonJS,
1190
+ target: tsMod.ScriptTarget.ES2020,
1191
+ moduleResolution: tsMod.ModuleResolutionKind.NodeNext,
1192
+ esModuleInterop: true,
1193
+ allowSyntheticDefaultImports: true
1194
+ },
1195
+ reportDiagnostics: false
1196
+ }).outputText;
1197
+ const module2 = { exports: {} };
1198
+ const evaluate = (0, import_node_vm.runInThisContext)(`(function (exports, require, module, __filename, __dirname) {${transpiled}
1199
+ })`, { filename: resolvedPath });
1200
+ evaluate(module2.exports, localRequire, module2, resolvedPath, (0, import_node_path3.dirname)(resolvedPath));
1201
+ return { status: "loaded", moduleExport: module2.exports };
1202
+ } catch (error) {
1203
+ return {
1204
+ status: "error",
1205
+ message: sanitizeErrorMessage(`Could not load sync ESM plugin "${resolvedPath}": ${toMessage2(error)}`)
1206
+ };
1207
+ }
1208
+ }
1209
+ #normalizeModuleExport(mod) {
1210
+ if (isPluginLike(mod)) {
1211
+ return mod;
1212
+ }
1213
+ if (!mod || typeof mod !== "object") {
1214
+ return void 0;
1215
+ }
1216
+ const candidate = mod;
1217
+ if (isPluginLike(candidate.default)) {
1218
+ return candidate.default;
1219
+ }
1220
+ if (isPluginLike(candidate.plugin)) {
1221
+ return candidate.plugin;
1222
+ }
1223
+ return void 0;
1224
+ }
1225
+ };
1226
+
1227
+ // ../virtual-modules/dist/LanguageServiceAdapter.js
1228
+ var import_node_url = require("url");
1229
+ var import_node_fs4 = require("fs");
1230
+
1231
+ // ../virtual-modules/dist/internal/materializeVirtualFile.js
1232
+ var import_node_fs3 = require("fs");
1233
+ var import_node_path4 = require("path");
1234
+ function rewriteSourceForPreviewLocation(sourceText, importer, virtualFilePath) {
1235
+ const importerDir = (0, import_node_path4.dirname)((0, import_node_path4.resolve)(importer));
1236
+ const previewDir = (0, import_node_path4.dirname)((0, import_node_path4.resolve)(virtualFilePath));
1237
+ return sourceText.replace(/from\s+['"](\.\.?\/[^'"]+)['"]/g, (match, spec) => {
1238
+ const absoluteTarget = (0, import_node_path4.resolve)(importerDir, spec);
1239
+ const newRel = toPosixPath((0, import_node_path4.relative)(previewDir, absoluteTarget));
1240
+ const newSpec = newRel.startsWith(".") ? newRel : `./${newRel}`;
1241
+ const quote = match.includes('"') ? '"' : "'";
1242
+ return `from ${quote}${newSpec}${quote}`;
1243
+ });
1244
+ }
1245
+ function materializeVirtualFile(virtualFilePath, importer, sourceText) {
1246
+ const rewritten = rewriteSourceForPreviewLocation(sourceText, importer, virtualFilePath);
1247
+ (0, import_node_fs3.mkdirSync)((0, import_node_path4.dirname)((0, import_node_path4.resolve)(virtualFilePath)), { recursive: true });
1248
+ (0, import_node_fs3.writeFileSync)(virtualFilePath, rewritten, "utf8");
1249
+ }
1250
+
1251
+ // ../virtual-modules/dist/internal/VirtualRecordStore.js
1252
+ function toResolvedModule(tsMod, fileName) {
1253
+ return {
1254
+ resolvedFileName: fileName,
1255
+ extension: tsMod.Extension.Ts,
1256
+ isExternalLibraryImport: false
1257
+ };
1258
+ }
1259
+ function createVirtualRecordStore(options) {
1260
+ const recordsByKey = /* @__PURE__ */ new Map();
1261
+ const recordsByVirtualFile = /* @__PURE__ */ new Map();
1262
+ const descriptorToVirtualKeys = /* @__PURE__ */ new Map();
1263
+ const watcherByDescriptor = /* @__PURE__ */ new Map();
1264
+ let debounceTimer;
1265
+ const pendingStaleKeys = /* @__PURE__ */ new Set();
1266
+ const { debounceMs, watchHost, shouldEvictRecord, onFlushStale, onMarkStale, onBeforeResolve, onAfterResolve, onRecordResolved, onEvictRecord } = options;
1267
+ const evictRecord = (record) => {
1268
+ onEvictRecord?.(record);
1269
+ recordsByKey.delete(record.key);
1270
+ recordsByVirtualFile.delete(record.virtualFileName);
1271
+ for (const descriptor of record.dependencies) {
1272
+ const descriptorKey = createWatchDescriptorKey(descriptor);
1273
+ const dependents = descriptorToVirtualKeys.get(descriptorKey);
1274
+ if (dependents) {
1275
+ dependents.delete(record.key);
1276
+ if (dependents.size === 0) {
1277
+ descriptorToVirtualKeys.delete(descriptorKey);
1278
+ const watcher = watcherByDescriptor.get(descriptorKey);
1279
+ if (watcher) {
1280
+ watcher.close();
1281
+ watcherByDescriptor.delete(descriptorKey);
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+ };
1287
+ const evictStaleImporters = () => {
1288
+ const toEvict = [];
1289
+ for (const record of recordsByKey.values()) {
1290
+ if (shouldEvictRecord(record)) {
1291
+ toEvict.push(record);
1292
+ }
1293
+ }
1294
+ for (const record of toEvict) {
1295
+ evictRecord(record);
1296
+ }
1297
+ };
1298
+ const registerWatchers = (record) => {
1299
+ for (const descriptor of record.dependencies) {
1300
+ const descriptorKey = createWatchDescriptorKey(descriptor);
1301
+ const dependents = descriptorToVirtualKeys.get(descriptorKey) ?? /* @__PURE__ */ new Set();
1302
+ dependents.add(record.key);
1303
+ descriptorToVirtualKeys.set(descriptorKey, dependents);
1304
+ if (watcherByDescriptor.has(descriptorKey)) {
1305
+ continue;
1306
+ }
1307
+ if (descriptor.type === "file" && watchHost?.watchFile) {
1308
+ const watcher = watchHost.watchFile(descriptor.path, () => {
1309
+ markStale(descriptorKey);
1310
+ });
1311
+ watcherByDescriptor.set(descriptorKey, watcher);
1312
+ } else if (descriptor.type === "glob" && watchHost?.watchDirectory) {
1313
+ const watcher = watchHost.watchDirectory(descriptor.baseDir, () => {
1314
+ markStale(descriptorKey);
1315
+ }, descriptor.recursive);
1316
+ watcherByDescriptor.set(descriptorKey, watcher);
1317
+ }
1318
+ }
1319
+ };
1320
+ const flushPendingStale = () => {
1321
+ if (pendingStaleKeys.size === 0) {
1322
+ return;
1323
+ }
1324
+ onFlushStale?.();
1325
+ for (const descriptorKey of pendingStaleKeys) {
1326
+ const keys = descriptorToVirtualKeys.get(descriptorKey);
1327
+ if (!keys || keys.size === 0) {
1328
+ continue;
1329
+ }
1330
+ for (const key of keys) {
1331
+ const record = recordsByKey.get(key);
1332
+ if (record) {
1333
+ record.stale = true;
1334
+ onMarkStale?.(record);
1335
+ }
1336
+ }
1337
+ }
1338
+ pendingStaleKeys.clear();
1339
+ debounceTimer = void 0;
1340
+ };
1341
+ const markStale = (descriptorKey) => {
1342
+ if (debounceMs !== void 0 && debounceMs > 0) {
1343
+ pendingStaleKeys.add(descriptorKey);
1344
+ if (debounceTimer === void 0) {
1345
+ debounceTimer = setTimeout(() => {
1346
+ flushPendingStale();
1347
+ }, debounceMs);
1348
+ }
1349
+ return;
1350
+ }
1351
+ const keys = descriptorToVirtualKeys.get(descriptorKey);
1352
+ if (!keys || keys.size === 0) {
1353
+ return;
1354
+ }
1355
+ for (const key of keys) {
1356
+ const record = recordsByKey.get(key);
1357
+ if (record) {
1358
+ record.stale = true;
1359
+ onMarkStale?.(record);
1360
+ }
1361
+ }
1362
+ };
1363
+ const resolveRecord = (id, importer, previous) => {
1364
+ onBeforeResolve?.();
1365
+ try {
1366
+ const resolveOptions = {
1367
+ id,
1368
+ importer,
1369
+ createTypeInfoApiSession: options.createTypeInfoApiSession
1370
+ };
1371
+ const resolution = options.resolver.resolveModule(resolveOptions);
1372
+ if (resolution.status === "unresolved") {
1373
+ return { status: "unresolved" };
1374
+ }
1375
+ if (resolution.status === "error") {
1376
+ return {
1377
+ status: "error",
1378
+ diagnostic: resolution.diagnostic
1379
+ };
1380
+ }
1381
+ const key = createVirtualKey(id, importer);
1382
+ const virtualFileName = createVirtualFileName(resolution.pluginName, key, { id, importer }, { projectRoot: options.projectRoot });
1383
+ const record = {
1384
+ key,
1385
+ id,
1386
+ importer,
1387
+ pluginName: resolution.pluginName,
1388
+ virtualFileName,
1389
+ sourceText: resolution.sourceText,
1390
+ dependencies: resolution.dependencies,
1391
+ ...resolution.warnings?.length ? { warnings: resolution.warnings } : {},
1392
+ version: previous ? previous.version + 1 : 1,
1393
+ stale: false
1394
+ };
1395
+ recordsByKey.set(key, record);
1396
+ recordsByVirtualFile.set(virtualFileName, record);
1397
+ registerWatchers(record);
1398
+ onRecordResolved?.(record);
1399
+ return {
1400
+ status: "resolved",
1401
+ record
1402
+ };
1403
+ } finally {
1404
+ onAfterResolve?.();
1405
+ }
1406
+ };
1407
+ const getOrBuildRecord = (id, importer) => {
1408
+ evictStaleImporters();
1409
+ const key = createVirtualKey(id, importer);
1410
+ const existing = recordsByKey.get(key);
1411
+ if (existing && !existing.stale) {
1412
+ return {
1413
+ status: "resolved",
1414
+ record: existing
1415
+ };
1416
+ }
1417
+ return resolveRecord(id, importer, existing);
1418
+ };
1419
+ const dispose = () => {
1420
+ if (debounceTimer !== void 0) {
1421
+ clearTimeout(debounceTimer);
1422
+ debounceTimer = void 0;
1423
+ }
1424
+ pendingStaleKeys.clear();
1425
+ for (const watcher of watcherByDescriptor.values()) {
1426
+ watcher.close();
1427
+ }
1428
+ watcherByDescriptor.clear();
1429
+ descriptorToVirtualKeys.clear();
1430
+ recordsByKey.clear();
1431
+ recordsByVirtualFile.clear();
1432
+ };
1433
+ return {
1434
+ recordsByKey,
1435
+ recordsByVirtualFile,
1436
+ descriptorToVirtualKeys,
1437
+ watcherByDescriptor,
1438
+ evictRecord,
1439
+ evictStaleImporters,
1440
+ registerWatchers,
1441
+ markStale,
1442
+ flushPendingStale,
1443
+ resolveRecord,
1444
+ getOrBuildRecord,
1445
+ dispose
1446
+ };
1447
+ }
1448
+
1449
+ // ../virtual-modules/dist/LanguageServiceAdapter.js
1450
+ var IN_MEMORY_RESOURCE_PREFIX = "^";
1451
+ var PREVIEW_SCHEMES = ["virtual-module", VIRTUAL_MODULE_URI_SCHEME];
1452
+ function parsePreviewUri(fileName) {
1453
+ const pathBased = tryParsePathBasedFromTsServer(fileName);
1454
+ if (pathBased)
1455
+ return pathBased;
1456
+ if (!fileName.includes("://"))
1457
+ return void 0;
1458
+ try {
1459
+ const url = new URL(fileName);
1460
+ if (!PREVIEW_SCHEMES.includes(url.protocol.replace(":", "")))
1461
+ return void 0;
1462
+ const id = url.searchParams.get("id");
1463
+ const importerRaw = url.searchParams.get("importer");
1464
+ if (!id || !importerRaw)
1465
+ return void 0;
1466
+ const importer = importerRaw.startsWith("file:") ? (() => {
1467
+ try {
1468
+ return (0, import_node_url.fileURLToPath)(importerRaw);
1469
+ } catch {
1470
+ return importerRaw;
1471
+ }
1472
+ })() : importerRaw;
1473
+ return { id, importer };
1474
+ } catch {
1475
+ return void 0;
1476
+ }
1477
+ }
1478
+ function tryParsePathBasedFromTsServer(fileName) {
1479
+ if (!fileName.startsWith(IN_MEMORY_RESOURCE_PREFIX + "/"))
1480
+ return void 0;
1481
+ const rest = fileName.slice(IN_MEMORY_RESOURCE_PREFIX.length);
1482
+ const parts = rest.split("/");
1483
+ if (parts.length < 4)
1484
+ return void 0;
1485
+ const [scheme] = [parts[1], parts[2]];
1486
+ if (!PREVIEW_SCHEMES.includes(scheme))
1487
+ return void 0;
1488
+ const path = "/" + parts.slice(3).join("/");
1489
+ if (!path.includes("__virtual_"))
1490
+ return void 0;
1491
+ return { virtualPath: path };
1492
+ }
1493
+ var ADAPTER_DIAGNOSTIC_CODE = 99001;
1494
+ var toTsDiagnostic = (tsMod, message, file) => ({
1495
+ category: tsMod.DiagnosticCategory.Error,
1496
+ code: ADAPTER_DIAGNOSTIC_CODE,
1497
+ file,
1498
+ start: 0,
1499
+ length: 0,
1500
+ messageText: message
1501
+ });
1502
+ var attachLanguageServiceAdapter = (options) => {
1503
+ if (typeof options.projectRoot !== "string" || options.projectRoot.trim() === "") {
1504
+ throw new Error("projectRoot must be a non-empty string");
1505
+ }
1506
+ const host = options.languageServiceHost;
1507
+ const watchHost = options.watchHost ?? options.languageServiceHost;
1508
+ const diagnosticsByFile = /* @__PURE__ */ new Map();
1509
+ let epoch = 0;
1510
+ let inResolution = false;
1511
+ let inResolveRecord = false;
1512
+ let pendingRetry = false;
1513
+ const originalGetScriptFileNames = host.getScriptFileNames?.bind(host);
1514
+ const originalResolveModuleNameLiterals = host.resolveModuleNameLiterals?.bind(host);
1515
+ const originalResolveModuleNames = host.resolveModuleNames?.bind(host);
1516
+ const originalGetScriptSnapshot = host.getScriptSnapshot?.bind(host);
1517
+ const originalGetScriptVersion = host.getScriptVersion?.bind(host);
1518
+ const originalGetProjectVersion = host.getProjectVersion?.bind(host);
1519
+ const originalFileExists = host.fileExists?.bind(host);
1520
+ const originalReadFile = host.readFile?.bind(host);
1521
+ const originalGetSemanticDiagnostics = options.languageService.getSemanticDiagnostics.bind(options.languageService);
1522
+ const originalGetSyntacticDiagnostics = options.languageService.getSyntacticDiagnostics.bind(options.languageService);
1523
+ const addDiagnosticForFile = (filePath, message) => {
1524
+ const diagnostic = toTsDiagnostic(options.ts, message);
1525
+ const diagnostics = diagnosticsByFile.get(filePath) ?? [];
1526
+ diagnostics.push(diagnostic);
1527
+ diagnosticsByFile.set(filePath, diagnostics);
1528
+ };
1529
+ const clearDiagnosticsForFile = (filePath) => {
1530
+ diagnosticsByFile.delete(filePath);
1531
+ };
1532
+ const store = createVirtualRecordStore({
1533
+ projectRoot: options.projectRoot,
1534
+ resolver: options.resolver,
1535
+ createTypeInfoApiSession: options.createTypeInfoApiSession,
1536
+ debounceMs: options.debounceMs,
1537
+ watchHost,
1538
+ shouldEvictRecord: (record) => {
1539
+ const currentFiles = new Set(originalGetScriptFileNames ? originalGetScriptFileNames() : []);
1540
+ return !currentFiles.has(record.importer);
1541
+ },
1542
+ onFlushStale: () => {
1543
+ epoch += 1;
1544
+ },
1545
+ onBeforeResolve: () => {
1546
+ inResolveRecord = true;
1547
+ },
1548
+ onAfterResolve: () => {
1549
+ inResolveRecord = false;
1550
+ },
1551
+ onRecordResolved: (record) => {
1552
+ clearDiagnosticsForFile(record.importer);
1553
+ },
1554
+ onEvictRecord: (record) => {
1555
+ clearDiagnosticsForFile(record.importer);
1556
+ if (record.virtualFileName.includes(VIRTUAL_NODE_MODULES_RELATIVE)) {
1557
+ try {
1558
+ (0, import_node_fs4.unlinkSync)(record.virtualFileName);
1559
+ } catch {
1560
+ }
1561
+ }
1562
+ }
1563
+ });
1564
+ const { recordsByVirtualFile } = store;
1565
+ const getOrBuildRecord = (id, importer) => {
1566
+ store.evictStaleImporters();
1567
+ if (inResolveRecord) {
1568
+ return {
1569
+ status: "error",
1570
+ diagnostic: {
1571
+ code: "re-entrant-resolution",
1572
+ pluginName: "",
1573
+ message: "Re-entrant resolution not allowed; plugins must not trigger module resolution during build()"
1574
+ }
1575
+ };
1576
+ }
1577
+ return store.getOrBuildRecord(id, importer);
1578
+ };
1579
+ const rebuildRecordIfNeeded = (record) => {
1580
+ if (!record.stale) {
1581
+ return record;
1582
+ }
1583
+ const rebuilt = store.resolveRecord(record.id, record.importer, record);
1584
+ if (rebuilt.status === "resolved") {
1585
+ clearDiagnosticsForFile(record.importer);
1586
+ return rebuilt.record;
1587
+ }
1588
+ if (rebuilt.status === "error") {
1589
+ const diagnostic = toTsDiagnostic(options.ts, `Virtual module rebuild failed: ${rebuilt.diagnostic.message}`);
1590
+ const diagnostics = diagnosticsByFile.get(record.importer) ?? [];
1591
+ diagnostics.push(diagnostic);
1592
+ diagnosticsByFile.set(record.importer, diagnostics);
1593
+ }
1594
+ return record;
1595
+ };
1596
+ const fallbackResolveModule = (moduleName, containingFile, compilerOptions) => {
1597
+ const result = options.ts.resolveModuleName(moduleName, containingFile, compilerOptions ?? {}, {
1598
+ fileExists: (path) => host.fileExists?.(path) ?? false,
1599
+ readFile: (path) => host.readFile?.(path),
1600
+ directoryExists: (path) => host.directoryExists?.(path) ?? options.ts.sys.directoryExists(path),
1601
+ getCurrentDirectory: () => host.getCurrentDirectory?.() ?? options.ts.sys.getCurrentDirectory(),
1602
+ getDirectories: (path) => {
1603
+ const fromHost = host.getDirectories?.(path);
1604
+ if (fromHost !== void 0)
1605
+ return [...fromHost];
1606
+ const fromSys = options.ts.sys.getDirectories?.(path);
1607
+ return fromSys !== void 0 ? [...fromSys] : [];
1608
+ },
1609
+ realpath: (path) => host.realpath?.(path) ?? options.ts.sys.realpath?.(path) ?? path,
1610
+ useCaseSensitiveFileNames: host.useCaseSensitiveFileNames?.() ?? options.ts.sys.useCaseSensitiveFileNames
1611
+ });
1612
+ return result.resolvedModule;
1613
+ };
1614
+ host.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile) => {
1615
+ if (inResolution) {
1616
+ if (inResolveRecord) {
1617
+ const diagnostic = toTsDiagnostic(options.ts, "Re-entrant resolution not allowed; plugins must not trigger module resolution during build()");
1618
+ const diagnostics = diagnosticsByFile.get(containingFile) ?? [];
1619
+ diagnostics.push(diagnostic);
1620
+ diagnosticsByFile.set(containingFile, diagnostics);
1621
+ }
1622
+ return moduleNames.map(() => void 0);
1623
+ }
1624
+ inResolution = true;
1625
+ try {
1626
+ const parsed = parsePreviewUri(containingFile);
1627
+ let effectiveContainingFile = containingFile;
1628
+ let importerForVirtual = containingFile;
1629
+ if (parsed) {
1630
+ if ("virtualPath" in parsed) {
1631
+ const r = recordsByVirtualFile.get(parsed.virtualPath);
1632
+ if (r) {
1633
+ effectiveContainingFile = r.virtualFileName;
1634
+ importerForVirtual = r.importer;
1635
+ }
1636
+ } else {
1637
+ const r = getOrBuildRecord(parsed.id, parsed.importer);
1638
+ if (r.status === "resolved") {
1639
+ effectiveContainingFile = r.record.virtualFileName;
1640
+ importerForVirtual = r.record.importer;
1641
+ }
1642
+ }
1643
+ }
1644
+ const fallback = originalResolveModuleNames ? originalResolveModuleNames(moduleNames, effectiveContainingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile) : moduleNames.map((moduleName) => fallbackResolveModule(moduleName, effectiveContainingFile, compilerOptions));
1645
+ let hadVirtualError = false;
1646
+ let hadUnresolvedVirtual = false;
1647
+ const results = moduleNames.map((moduleName, index) => {
1648
+ const resolved = getOrBuildRecord(moduleName, importerForVirtual);
1649
+ if (resolved.status === "resolved") {
1650
+ pendingRetry = false;
1651
+ return toResolvedModule(options.ts, resolved.record.virtualFileName);
1652
+ }
1653
+ if (resolved.status === "error") {
1654
+ hadVirtualError = true;
1655
+ addDiagnosticForFile(containingFile, resolved.diagnostic.message);
1656
+ if (resolved.diagnostic.code === "re-entrant-resolution") {
1657
+ return void 0;
1658
+ }
1659
+ }
1660
+ if (resolved.status === "unresolved" && moduleName.includes(":")) {
1661
+ hadUnresolvedVirtual = true;
1662
+ }
1663
+ return fallback[index];
1664
+ });
1665
+ if ((hadVirtualError || hadUnresolvedVirtual) && !pendingRetry) {
1666
+ pendingRetry = true;
1667
+ epoch += 1;
1668
+ }
1669
+ return results;
1670
+ } finally {
1671
+ inResolution = false;
1672
+ }
1673
+ };
1674
+ const assignResolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, compilerOptions, containingSourceFile, reusedNames) => {
1675
+ if (inResolution) {
1676
+ if (inResolveRecord) {
1677
+ const diagnostic = toTsDiagnostic(options.ts, "Re-entrant resolution not allowed; plugins must not trigger module resolution during build()");
1678
+ const diagnostics = diagnosticsByFile.get(containingFile) ?? [];
1679
+ diagnostics.push(diagnostic);
1680
+ diagnosticsByFile.set(containingFile, diagnostics);
1681
+ }
1682
+ return moduleLiterals.map(() => ({ resolvedModule: void 0 }));
1683
+ }
1684
+ inResolution = true;
1685
+ try {
1686
+ const parsed = parsePreviewUri(containingFile);
1687
+ let effectiveContainingFile = containingFile;
1688
+ let importerForVirtual = containingFile;
1689
+ if (parsed) {
1690
+ if ("virtualPath" in parsed) {
1691
+ const r = recordsByVirtualFile.get(parsed.virtualPath);
1692
+ if (r) {
1693
+ effectiveContainingFile = r.virtualFileName;
1694
+ importerForVirtual = r.importer;
1695
+ }
1696
+ } else {
1697
+ const r = getOrBuildRecord(parsed.id, parsed.importer);
1698
+ if (r.status === "resolved") {
1699
+ effectiveContainingFile = r.record.virtualFileName;
1700
+ importerForVirtual = r.record.importer;
1701
+ }
1702
+ }
1703
+ }
1704
+ const fallback = originalResolveModuleNameLiterals ? originalResolveModuleNameLiterals(moduleLiterals, effectiveContainingFile, redirectedReference, compilerOptions, containingSourceFile, reusedNames) : moduleLiterals.map((moduleLiteral) => ({
1705
+ resolvedModule: fallbackResolveModule(moduleLiteral.text, effectiveContainingFile, compilerOptions)
1706
+ }));
1707
+ let hadVirtualError = false;
1708
+ let hadUnresolvedVirtual = false;
1709
+ const results = moduleLiterals.map((moduleLiteral, index) => {
1710
+ const resolved = getOrBuildRecord(moduleLiteral.text, importerForVirtual);
1711
+ if (moduleLiteral.text.includes(":")) {
1712
+ try {
1713
+ require("fs").appendFileSync("/tmp/vm-ts-plugin-debug.log", JSON.stringify({
1714
+ tag: "LS:resolveLiterals",
1715
+ id: moduleLiteral.text,
1716
+ status: resolved.status,
1717
+ err: resolved.status === "error" ? resolved.diagnostic?.message : void 0,
1718
+ t: Date.now()
1719
+ }) + "\n", { flag: "a" });
1720
+ } catch {
1721
+ }
1722
+ }
1723
+ if (resolved.status === "resolved") {
1724
+ pendingRetry = false;
1725
+ return {
1726
+ resolvedModule: toResolvedModule(options.ts, resolved.record.virtualFileName)
1727
+ };
1728
+ }
1729
+ if (resolved.status === "error") {
1730
+ hadVirtualError = true;
1731
+ addDiagnosticForFile(containingFile, resolved.diagnostic.message);
1732
+ if (resolved.diagnostic.code === "re-entrant-resolution") {
1733
+ return fallback[index];
1734
+ }
1735
+ }
1736
+ if (resolved.status === "unresolved" && moduleLiteral.text.includes(":")) {
1737
+ hadUnresolvedVirtual = true;
1738
+ }
1739
+ return fallback[index];
1740
+ });
1741
+ if ((hadVirtualError || hadUnresolvedVirtual) && !pendingRetry) {
1742
+ pendingRetry = true;
1743
+ epoch += 1;
1744
+ }
1745
+ return results;
1746
+ } finally {
1747
+ inResolution = false;
1748
+ }
1749
+ };
1750
+ host.resolveModuleNameLiterals = assignResolveModuleNameLiterals;
1751
+ const projectService = host.projectService;
1752
+ host.getScriptSnapshot = (fileName) => {
1753
+ let record = recordsByVirtualFile.get(fileName);
1754
+ if (!record) {
1755
+ const parsed = parsePreviewUri(fileName);
1756
+ if (parsed) {
1757
+ if ("virtualPath" in parsed) {
1758
+ record = recordsByVirtualFile.get(parsed.virtualPath) ?? void 0;
1759
+ } else {
1760
+ const resolved = getOrBuildRecord(parsed.id, parsed.importer);
1761
+ if (resolved.status === "resolved")
1762
+ record = resolved.record;
1763
+ }
1764
+ }
1765
+ }
1766
+ if (!record) {
1767
+ return originalGetScriptSnapshot?.(fileName);
1768
+ }
1769
+ const freshRecord = rebuildRecordIfNeeded(record);
1770
+ let sourceToServe = freshRecord.sourceText;
1771
+ const isNodeModulesPath = fileName.includes(VIRTUAL_NODE_MODULES_RELATIVE);
1772
+ if (isNodeModulesPath) {
1773
+ sourceToServe = rewriteSourceForPreviewLocation(freshRecord.sourceText, freshRecord.importer, fileName);
1774
+ materializeVirtualFile(fileName, freshRecord.importer, freshRecord.sourceText);
1775
+ }
1776
+ if (projectService?.getOrCreateOpenScriptInfo) {
1777
+ projectService.getOrCreateOpenScriptInfo(fileName, sourceToServe, options.ts.ScriptKind.TS, false, options.projectRoot);
1778
+ }
1779
+ return options.ts.ScriptSnapshot.fromString(sourceToServe);
1780
+ };
1781
+ if (originalGetScriptVersion) {
1782
+ host.getScriptVersion = (fileName) => {
1783
+ let record = recordsByVirtualFile.get(fileName);
1784
+ if (!record) {
1785
+ const parsed = parsePreviewUri(fileName);
1786
+ if (parsed) {
1787
+ if ("virtualPath" in parsed) {
1788
+ record = recordsByVirtualFile.get(parsed.virtualPath) ?? void 0;
1789
+ } else {
1790
+ const resolved = getOrBuildRecord(parsed.id, parsed.importer);
1791
+ if (resolved.status === "resolved")
1792
+ record = resolved.record;
1793
+ }
1794
+ }
1795
+ }
1796
+ if (!record)
1797
+ return originalGetScriptVersion(fileName);
1798
+ return String(record.version);
1799
+ };
1800
+ }
1801
+ if (originalGetProjectVersion) {
1802
+ host.getProjectVersion = () => `${originalGetProjectVersion()}:vm:${epoch}`;
1803
+ }
1804
+ if (originalGetScriptFileNames) {
1805
+ host.getScriptFileNames = () => {
1806
+ const files = originalGetScriptFileNames();
1807
+ const virtualFiles = [...recordsByVirtualFile.keys()];
1808
+ return [.../* @__PURE__ */ new Set([...files, ...virtualFiles])];
1809
+ };
1810
+ }
1811
+ host.fileExists = (path) => {
1812
+ if (recordsByVirtualFile.has(path))
1813
+ return true;
1814
+ const parsed = parsePreviewUri(path);
1815
+ if (parsed) {
1816
+ if ("virtualPath" in parsed) {
1817
+ if (recordsByVirtualFile.has(parsed.virtualPath))
1818
+ return true;
1819
+ } else {
1820
+ const resolved = getOrBuildRecord(parsed.id, parsed.importer);
1821
+ if (resolved.status === "resolved")
1822
+ return true;
1823
+ }
1824
+ }
1825
+ return originalFileExists ? originalFileExists(path) : false;
1826
+ };
1827
+ host.readFile = (path) => {
1828
+ let record = recordsByVirtualFile.get(path);
1829
+ if (!record) {
1830
+ const parsed = parsePreviewUri(path);
1831
+ if (parsed) {
1832
+ if ("virtualPath" in parsed) {
1833
+ record = recordsByVirtualFile.get(parsed.virtualPath) ?? void 0;
1834
+ } else {
1835
+ const resolved = getOrBuildRecord(parsed.id, parsed.importer);
1836
+ if (resolved.status === "resolved")
1837
+ record = resolved.record;
1838
+ }
1839
+ }
1840
+ }
1841
+ if (record)
1842
+ return rebuildRecordIfNeeded(record).sourceText;
1843
+ return originalReadFile?.(path);
1844
+ };
1845
+ options.languageService.getSemanticDiagnostics = (fileName) => {
1846
+ const diagnostics = originalGetSemanticDiagnostics(fileName);
1847
+ const adapterDiagnostics = diagnosticsByFile.get(fileName);
1848
+ if (!adapterDiagnostics || adapterDiagnostics.length === 0) {
1849
+ return [...diagnostics];
1850
+ }
1851
+ return [...diagnostics, ...adapterDiagnostics];
1852
+ };
1853
+ options.languageService.getSyntacticDiagnostics = (fileName) => {
1854
+ const diagnostics = originalGetSyntacticDiagnostics(fileName);
1855
+ const adapterDiagnostics = diagnosticsByFile.get(fileName);
1856
+ if (!adapterDiagnostics || adapterDiagnostics.length === 0) {
1857
+ return [...diagnostics];
1858
+ }
1859
+ const withLocation = adapterDiagnostics.filter((d) => d.file !== void 0);
1860
+ return [...diagnostics, ...withLocation];
1861
+ };
1862
+ return {
1863
+ dispose() {
1864
+ for (const [virtualPath] of recordsByVirtualFile) {
1865
+ if (virtualPath.includes(VIRTUAL_NODE_MODULES_RELATIVE)) {
1866
+ try {
1867
+ (0, import_node_fs4.unlinkSync)(virtualPath);
1868
+ } catch {
1869
+ }
1870
+ }
1871
+ }
1872
+ host.resolveModuleNameLiterals = originalResolveModuleNameLiterals;
1873
+ host.resolveModuleNames = originalResolveModuleNames;
1874
+ if (originalGetScriptSnapshot) {
1875
+ host.getScriptSnapshot = originalGetScriptSnapshot;
1876
+ }
1877
+ if (originalGetScriptVersion) {
1878
+ host.getScriptVersion = originalGetScriptVersion;
1879
+ }
1880
+ if (originalGetProjectVersion) {
1881
+ host.getProjectVersion = originalGetProjectVersion;
1882
+ }
1883
+ if (originalGetScriptFileNames) {
1884
+ host.getScriptFileNames = originalGetScriptFileNames;
1885
+ }
1886
+ if (originalFileExists) {
1887
+ host.fileExists = originalFileExists;
1888
+ }
1889
+ if (originalReadFile) {
1890
+ host.readFile = originalReadFile;
1891
+ }
1892
+ options.languageService.getSemanticDiagnostics = originalGetSemanticDiagnostics;
1893
+ options.languageService.getSyntacticDiagnostics = originalGetSyntacticDiagnostics;
1894
+ store.dispose();
1895
+ diagnosticsByFile.clear();
1896
+ }
1897
+ };
1898
+ };
1899
+
1900
+ // ../virtual-modules/dist/VmcConfigLoader.js
1901
+ var import_node_fs5 = require("fs");
1902
+ var import_node_module2 = require("module");
1903
+ var import_node_path5 = require("path");
1904
+ var import_node_vm2 = require("vm");
1905
+ var VMC_CONFIG_NAMES = ["vmc.config.ts"];
1906
+ var toMessage3 = (error) => {
1907
+ if (error instanceof Error)
1908
+ return error.message;
1909
+ return String(error);
1910
+ };
1911
+ var isPluginLike2 = (value) => {
1912
+ if (!value || typeof value !== "object")
1913
+ return false;
1914
+ const candidate = value;
1915
+ return typeof candidate.name === "string" && typeof candidate.shouldResolve === "function" && typeof candidate.build === "function";
1916
+ };
1917
+ var isResolverLike = (value) => {
1918
+ if (!value || typeof value !== "object")
1919
+ return false;
1920
+ return typeof value.resolveModule === "function";
1921
+ };
1922
+ var normalizePluginEntries = (value) => {
1923
+ if (value === void 0)
1924
+ return { ok: true, plugins: [] };
1925
+ if (!Array.isArray(value))
1926
+ return { ok: false };
1927
+ const plugins = [];
1928
+ for (const entry of value) {
1929
+ if (typeof entry === "string" && entry.trim().length > 0) {
1930
+ plugins.push(entry.trim());
1931
+ continue;
1932
+ }
1933
+ if (isPluginLike2(entry)) {
1934
+ plugins.push(entry);
1935
+ continue;
1936
+ }
1937
+ return { ok: false };
1938
+ }
1939
+ return { ok: true, plugins };
1940
+ };
1941
+ function validateProjectRoot(projectRoot) {
1942
+ const projectRootResult = validatePathSegment(projectRoot, "projectRoot");
1943
+ if (!projectRootResult.ok) {
1944
+ return {
1945
+ status: "error",
1946
+ message: projectRootResult.reason
1947
+ };
1948
+ }
1949
+ const resolvedProjectRoot = (0, import_node_path5.resolve)(projectRootResult.value);
1950
+ if (!(0, import_node_fs5.existsSync)(resolvedProjectRoot)) {
1951
+ return {
1952
+ status: "error",
1953
+ path: resolvedProjectRoot,
1954
+ message: `projectRoot does not exist: ${resolvedProjectRoot}`
1955
+ };
1956
+ }
1957
+ if (!(0, import_node_fs5.statSync)(resolvedProjectRoot).isDirectory()) {
1958
+ return {
1959
+ status: "error",
1960
+ path: resolvedProjectRoot,
1961
+ message: `projectRoot must be a directory: ${resolvedProjectRoot}`
1962
+ };
1963
+ }
1964
+ return resolvedProjectRoot;
1965
+ }
1966
+ function resolveConfigPath(projectRoot, configPath) {
1967
+ if (configPath !== void 0) {
1968
+ const configPathResult = validatePathSegment(configPath, "configPath");
1969
+ if (!configPathResult.ok) {
1970
+ return {
1971
+ status: "error",
1972
+ message: configPathResult.reason
1973
+ };
1974
+ }
1975
+ const configPathValue = configPathResult.value;
1976
+ if (!configPathValue.endsWith(".ts")) {
1977
+ return {
1978
+ status: "error",
1979
+ message: `configPath must point to a .ts file: ${configPathValue}`
1980
+ };
1981
+ }
1982
+ const resolvedPath = (0, import_node_path5.resolve)(projectRoot, configPathValue);
1983
+ const underBase = resolvePathUnderBase(projectRoot, configPathValue);
1984
+ if (!underBase.ok || (0, import_node_path5.resolve)(underBase.path) !== resolvedPath) {
1985
+ return {
1986
+ status: "error",
1987
+ message: `vmc config path escapes project root: ${configPathValue}`
1988
+ };
1989
+ }
1990
+ if (!(0, import_node_fs5.existsSync)(resolvedPath)) {
1991
+ return {
1992
+ status: "error",
1993
+ path: resolvedPath,
1994
+ message: `vmc config not found: ${resolvedPath}`
1995
+ };
1996
+ }
1997
+ if (!(0, import_node_fs5.statSync)(resolvedPath).isFile()) {
1998
+ return {
1999
+ status: "error",
2000
+ path: resolvedPath,
2001
+ message: `vmc config path must point to a file: ${resolvedPath}`
2002
+ };
2003
+ }
2004
+ if (!pathIsUnderBase(projectRoot, resolvedPath)) {
2005
+ return {
2006
+ status: "error",
2007
+ path: resolvedPath,
2008
+ message: `vmc config path is outside project root after resolving symlinks: ${resolvedPath}`
2009
+ };
2010
+ }
2011
+ return resolvedPath;
2012
+ }
2013
+ for (const name of VMC_CONFIG_NAMES) {
2014
+ const candidate = (0, import_node_path5.join)(projectRoot, name);
2015
+ if (!(0, import_node_fs5.existsSync)(candidate))
2016
+ continue;
2017
+ if (!(0, import_node_fs5.statSync)(candidate).isFile())
2018
+ continue;
2019
+ if (!pathIsUnderBase(projectRoot, candidate)) {
2020
+ return {
2021
+ status: "error",
2022
+ path: candidate,
2023
+ message: `vmc config is outside project root after resolving symlinks: ${candidate}`
2024
+ };
2025
+ }
2026
+ return candidate;
2027
+ }
2028
+ return { status: "not-found" };
2029
+ }
2030
+ function loadTsConfigModule(tsMod, configPath) {
2031
+ const sourceText = (0, import_node_fs5.readFileSync)(configPath, "utf8");
2032
+ const transpiled = tsMod.transpileModule(sourceText, {
2033
+ fileName: configPath,
2034
+ compilerOptions: {
2035
+ module: tsMod.ModuleKind.CommonJS,
2036
+ target: tsMod.ScriptTarget.ES2020,
2037
+ moduleResolution: tsMod.ModuleResolutionKind.NodeNext,
2038
+ esModuleInterop: true
2039
+ },
2040
+ reportDiagnostics: false
2041
+ }).outputText;
2042
+ const localRequire = (0, import_node_module2.createRequire)(configPath);
2043
+ const module2 = { exports: {} };
2044
+ const evaluate = (0, import_node_vm2.runInThisContext)(`(function (exports, require, module, __filename, __dirname) {${transpiled}
2045
+ })`, { filename: configPath });
2046
+ evaluate(module2.exports, localRequire, module2, configPath, (0, import_node_path5.dirname)(configPath));
2047
+ return module2.exports;
2048
+ }
2049
+ function normalizeConfigModule(loadedModule) {
2050
+ const withDefault = loadedModule && typeof loadedModule === "object" && "default" in loadedModule ? loadedModule.default : loadedModule;
2051
+ if (!withDefault || typeof withDefault !== "object") {
2052
+ return { ok: false };
2053
+ }
2054
+ const candidate = withDefault;
2055
+ if (candidate.resolver !== void 0 && !isResolverLike(candidate.resolver)) {
2056
+ return { ok: false };
2057
+ }
2058
+ const normalizedPlugins = normalizePluginEntries(candidate.plugins);
2059
+ if (!normalizedPlugins.ok) {
2060
+ return { ok: false };
2061
+ }
2062
+ return {
2063
+ ok: true,
2064
+ config: {
2065
+ ...candidate.resolver !== void 0 ? { resolver: candidate.resolver } : {},
2066
+ ...normalizedPlugins.plugins.length > 0 ? { plugins: normalizedPlugins.plugins } : {}
2067
+ }
2068
+ };
2069
+ }
2070
+ function loadVmcConfig(options) {
2071
+ let attemptedPath;
2072
+ try {
2073
+ const projectRootOrStatus = validateProjectRoot(options.projectRoot);
2074
+ if (typeof projectRootOrStatus !== "string")
2075
+ return projectRootOrStatus;
2076
+ const projectRoot = projectRootOrStatus;
2077
+ const resolvedPathOrStatus = resolveConfigPath(projectRoot, options.configPath);
2078
+ if (typeof resolvedPathOrStatus !== "string")
2079
+ return resolvedPathOrStatus;
2080
+ const resolvedPath = resolvedPathOrStatus;
2081
+ attemptedPath = resolvedPath;
2082
+ const loadedModule = resolvedPath.endsWith(".ts") ? (() => {
2083
+ if (!options.ts) {
2084
+ return {
2085
+ __vmcConfigLoaderError: "TypeScript module is required to load vmc.config.ts"
2086
+ };
2087
+ }
2088
+ return loadTsConfigModule(options.ts, resolvedPath);
2089
+ })() : (0, import_node_module2.createRequire)(resolvedPath)(resolvedPath);
2090
+ if (loadedModule && typeof loadedModule === "object" && "__vmcConfigLoaderError" in loadedModule) {
2091
+ return {
2092
+ status: "error",
2093
+ path: resolvedPath,
2094
+ message: loadedModule.__vmcConfigLoaderError
2095
+ };
2096
+ }
2097
+ const normalized = normalizeConfigModule(loadedModule);
2098
+ if (!normalized.ok) {
2099
+ return {
2100
+ status: "error",
2101
+ path: resolvedPath,
2102
+ message: `Invalid vmc config export in ${resolvedPath}`
2103
+ };
2104
+ }
2105
+ return {
2106
+ status: "loaded",
2107
+ path: resolvedPath,
2108
+ config: normalized.config
2109
+ };
2110
+ } catch (error) {
2111
+ return {
2112
+ status: "error",
2113
+ ...attemptedPath ? { path: attemptedPath } : {},
2114
+ message: sanitizeErrorMessage(`Failed to load vmc config${attemptedPath ? ` "${attemptedPath}"` : ""}: ${toMessage3(error)}`)
2115
+ };
2116
+ }
2117
+ }
2118
+
2119
+ // ../virtual-modules/dist/VmcResolverLoader.js
2120
+ var import_node_path6 = require("path");
2121
+ function collectFromResolver(resolver) {
2122
+ const pm = resolver;
2123
+ if (!Array.isArray(pm.plugins) || pm.plugins.length === 0)
2124
+ return void 0;
2125
+ const merged = collectTypeTargetSpecsFromPlugins(pm.plugins);
2126
+ return merged.length > 0 ? merged : void 0;
2127
+ }
2128
+ function loadPluginsFromEntries(entries, baseDir) {
2129
+ const loader = new NodeModulePluginLoader();
2130
+ const plugins = [];
2131
+ const pluginSpecifiers = [];
2132
+ const errors = [];
2133
+ for (const entry of entries) {
2134
+ if (typeof entry === "string") {
2135
+ pluginSpecifiers.push(entry);
2136
+ const loaded = loader.load({ specifier: entry, baseDir });
2137
+ if (loaded.status === "loaded") {
2138
+ plugins.push(loaded.plugin);
2139
+ } else {
2140
+ errors.push(loaded);
2141
+ }
2142
+ continue;
2143
+ }
2144
+ plugins.push(entry);
2145
+ }
2146
+ return {
2147
+ plugins,
2148
+ pluginSpecifiers,
2149
+ errors
2150
+ };
2151
+ }
2152
+ function loadResolverFromVmcConfig(options) {
2153
+ const loadedVmcConfig = loadVmcConfig(options);
2154
+ if (loadedVmcConfig.status === "not-found") {
2155
+ return loadedVmcConfig;
2156
+ }
2157
+ if (loadedVmcConfig.status === "error") {
2158
+ return loadedVmcConfig;
2159
+ }
2160
+ const vmcPlugins = loadedVmcConfig.config.plugins ?? [];
2161
+ const pluginSpecifiers = vmcPlugins.filter((entry) => typeof entry === "string");
2162
+ if (loadedVmcConfig.config.resolver) {
2163
+ const resolver2 = loadedVmcConfig.config.resolver;
2164
+ const typeTargetSpecs2 = collectFromResolver(resolver2);
2165
+ return {
2166
+ status: "loaded",
2167
+ path: loadedVmcConfig.path,
2168
+ resolver: resolver2,
2169
+ pluginSpecifiers,
2170
+ pluginLoadErrors: [],
2171
+ ...typeTargetSpecs2 ? { typeTargetSpecs: typeTargetSpecs2 } : {}
2172
+ };
2173
+ }
2174
+ const loadedPlugins = loadPluginsFromEntries(vmcPlugins, (0, import_node_path6.dirname)(loadedVmcConfig.path));
2175
+ const resolver = loadedPlugins.plugins.length > 0 ? new PluginManager(loadedPlugins.plugins) : void 0;
2176
+ const typeTargetSpecs = resolver ? collectFromResolver(resolver) : void 0;
2177
+ return {
2178
+ status: "loaded",
2179
+ path: loadedVmcConfig.path,
2180
+ ...resolver ? { resolver } : {},
2181
+ pluginSpecifiers: loadedPlugins.pluginSpecifiers,
2182
+ pluginLoadErrors: loadedPlugins.errors,
2183
+ ...typeTargetSpecs ? { typeTargetSpecs } : {}
2184
+ };
2185
+ }
2186
+
2187
+ // ../virtual-modules/dist/typeTargetBootstrap.js
2188
+ var import_node_fs6 = require("fs");
2189
+ var import_node_path7 = require("path");
2190
+ function getTypeTargetBootstrapPath(projectRoot) {
2191
+ return (0, import_node_path7.join)(projectRoot, "node_modules", ".typed", "type-target-bootstrap.ts");
2192
+ }
2193
+ var defaultFs = {
2194
+ mkdirSync(path, options) {
2195
+ (0, import_node_fs6.mkdirSync)(path, options);
2196
+ },
2197
+ writeFile(path, content) {
2198
+ (0, import_node_fs6.writeFileSync)(path, content, "utf8");
2199
+ }
2200
+ };
2201
+ function ensureTypeTargetBootstrapFile(projectRoot, typeTargetSpecs, fs = defaultFs) {
2202
+ const bootstrapPath = getTypeTargetBootstrapPath(projectRoot);
2203
+ if (typeTargetSpecs.length === 0)
2204
+ return bootstrapPath;
2205
+ const dir = (0, import_node_path7.dirname)(bootstrapPath);
2206
+ fs.mkdirSync(dir, { recursive: true });
2207
+ fs.writeFile(bootstrapPath, createTypeTargetBootstrapContent(typeTargetSpecs));
2208
+ return bootstrapPath;
2209
+ }
2210
+ function getProgramWithTypeTargetBootstrap(tsMod, program, projectRoot, typeTargetSpecs) {
2211
+ if (!typeTargetSpecs?.length)
2212
+ return program;
2213
+ const bootstrapPath = ensureTypeTargetBootstrapFile(projectRoot, typeTargetSpecs);
2214
+ const rootNames = program.getRootFileNames();
2215
+ const canonicalBootstrap = (0, import_node_path7.resolve)(bootstrapPath);
2216
+ const alreadyHasBootstrap = rootNames.some((p) => (0, import_node_path7.resolve)(p) === canonicalBootstrap);
2217
+ if (alreadyHasBootstrap)
2218
+ return program;
2219
+ const opts = program.getCompilerOptions();
2220
+ const host = tsMod.createCompilerHost(opts, true);
2221
+ return tsMod.createProgram([...rootNames, bootstrapPath], opts, host);
2222
+ }
2223
+
2224
+ // ../virtual-modules/dist/LanguageServiceSession.js
2225
+ var import_node_fs7 = require("fs");
2226
+ var import_node_path8 = require("path");
2227
+
2228
+ // src/plugin.ts
2229
+ var import_node_fs8 = require("fs");
2230
+ var import_node_path9 = require("path");
2231
+ function findTsconfig(fromDir) {
2232
+ let dir = (0, import_node_path9.resolve)(fromDir);
2233
+ const root = (0, import_node_path9.resolve)(dir, "/");
2234
+ while (dir !== root) {
2235
+ const candidate = (0, import_node_path9.join)(dir, "tsconfig.json");
2236
+ if ((0, import_node_fs8.existsSync)(candidate)) return candidate;
2237
+ const parent = (0, import_node_path9.dirname)(dir);
2238
+ if (parent === dir) break;
2239
+ dir = parent;
2240
+ }
2241
+ return void 0;
2242
+ }
2243
+ function createFallbackProgram(tsMod, projectRoot, log, tsconfigPath, typeTargetSpecs) {
2244
+ const configPath = tsconfigPath ?? findTsconfig(projectRoot);
2245
+ if (!configPath) {
2246
+ log(`fallback program: no tsconfig found from ${projectRoot}`);
2247
+ return void 0;
2248
+ }
2249
+ try {
2250
+ const configFile = tsMod.readConfigFile(configPath, tsMod.sys.readFile);
2251
+ if (configFile.error) {
2252
+ log(`fallback program: tsconfig read error: ${configFile.error.messageText}`);
2253
+ return void 0;
2254
+ }
2255
+ const configDir = (0, import_node_path9.dirname)(configPath);
2256
+ const parsed = tsMod.parseJsonConfigFileContent(
2257
+ configFile.config,
2258
+ tsMod.sys,
2259
+ configDir,
2260
+ void 0,
2261
+ configPath
2262
+ );
2263
+ if (parsed.errors.length > 0) {
2264
+ log(`fallback program: tsconfig parse errors: ${parsed.errors.map((e) => e.messageText).join(", ")}`);
2265
+ return void 0;
2266
+ }
2267
+ let rootNames = parsed.fileNames;
2268
+ if (typeTargetSpecs && typeTargetSpecs.length > 0) {
2269
+ ensureTypeTargetBootstrapFile(projectRoot, typeTargetSpecs);
2270
+ const bootstrapPath = getTypeTargetBootstrapPath(projectRoot);
2271
+ rootNames = [...rootNames, bootstrapPath];
2272
+ log(`fallback program: added bootstrap ${bootstrapPath}`);
2273
+ }
2274
+ const program = tsMod.createProgram(
2275
+ rootNames,
2276
+ parsed.options,
2277
+ tsMod.createCompilerHost(parsed.options)
2278
+ );
2279
+ log(`fallback program: created with ${rootNames.length} root files`);
2280
+ return program;
2281
+ } catch (err) {
2282
+ log(`fallback program: exception: ${err instanceof Error ? err.message : String(err)}`);
2283
+ return void 0;
2284
+ }
2285
+ }
2286
+ function init(modules) {
2287
+ const ts = modules.typescript;
2288
+ function create(info) {
2289
+ const config = info.config ?? {};
2290
+ const logger = info.project?.projectService?.logger;
2291
+ const log = (msg) => logger?.info?.(`[@typed/virtual-modules-ts-plugin] ${msg}`);
2292
+ const project = info.project;
2293
+ const projectRoot = typeof project.configFilePath === "string" && project.configFilePath.length > 0 ? (0, import_node_path9.dirname)(project.configFilePath) : typeof project.getCurrentDirectory === "function" ? project.getCurrentDirectory() : process.cwd();
2294
+ log(`create: projectRoot=${projectRoot}`);
2295
+ const debounceMs = typeof config.debounceMs === "number" && Number.isFinite(config.debounceMs) && config.debounceMs >= 0 ? config.debounceMs : 50;
2296
+ if (config.debounceMs !== void 0 && (typeof config.debounceMs !== "number" || !Number.isFinite(config.debounceMs))) {
2297
+ log("Ignoring invalid debounceMs; expected finite number");
2298
+ }
2299
+ const vmcConfigPath = typeof config.vmcConfigPath === "string" && config.vmcConfigPath.trim().length > 0 ? config.vmcConfigPath : void 0;
2300
+ if (config.vmcConfigPath !== void 0 && vmcConfigPath === void 0) {
2301
+ log("Ignoring invalid vmcConfigPath; expected non-empty string");
2302
+ }
2303
+ let resolver;
2304
+ const loadedResolver = loadResolverFromVmcConfig({
2305
+ projectRoot,
2306
+ ts,
2307
+ ...vmcConfigPath ? { configPath: vmcConfigPath } : {}
2308
+ });
2309
+ log(`vmc: status=${loadedResolver.status}`);
2310
+ if (loadedResolver.status === "error") {
2311
+ log(`vmc error: ${loadedResolver.message}`);
2312
+ return info.languageService;
2313
+ }
2314
+ if (loadedResolver.status === "loaded") {
2315
+ for (const pluginLoadError of loadedResolver.pluginLoadErrors) {
2316
+ log(`plugin load error: "${pluginLoadError.specifier}": ${pluginLoadError.message}`);
2317
+ }
2318
+ resolver = loadedResolver.resolver;
2319
+ if (!resolver) {
2320
+ log(`${loadedResolver.path} has no resolver/plugins`);
2321
+ return info.languageService;
2322
+ }
2323
+ }
2324
+ if (!resolver || loadedResolver.status === "not-found") {
2325
+ log("vmc.config.ts not found; virtual module resolution disabled");
2326
+ return info.languageService;
2327
+ }
2328
+ log("Virtual module resolver initialized");
2329
+ const typeTargetSpecs = loadedResolver.typeTargetSpecs ?? [];
2330
+ log(`typeTargetSpecs: ${typeTargetSpecs.length} specs`);
2331
+ const projectConfigPath = info.project.configFilePath;
2332
+ const tsconfigPath = typeof projectConfigPath === "string" && projectConfigPath.length > 0 ? projectConfigPath : void 0;
2333
+ let cachedFallbackProgram = createFallbackProgram(
2334
+ ts,
2335
+ projectRoot,
2336
+ log,
2337
+ tsconfigPath,
2338
+ typeTargetSpecs
2339
+ );
2340
+ let preCreatedSession;
2341
+ if (cachedFallbackProgram) {
2342
+ try {
2343
+ const programWithBootstrap = getProgramWithTypeTargetBootstrap(
2344
+ ts,
2345
+ cachedFallbackProgram,
2346
+ projectRoot,
2347
+ typeTargetSpecs
2348
+ );
2349
+ preCreatedSession = createTypeInfoApiSession({
2350
+ ts,
2351
+ program: programWithBootstrap,
2352
+ ...typeTargetSpecs.length > 0 ? { typeTargetSpecs, failWhenNoTargetsResolved: false } : {}
2353
+ });
2354
+ log("pre-created TypeInfoApiSession OK");
2355
+ } catch (err) {
2356
+ log(`pre-created TypeInfoApiSession failed: ${err instanceof Error ? err.message : String(err)}`);
2357
+ }
2358
+ }
2359
+ const getProgramForTypeInfo = () => {
2360
+ const fromLS = info.languageService.getProgram();
2361
+ if (fromLS !== void 0) return fromLS;
2362
+ const projectLike = info.project;
2363
+ const fromProject = projectLike.getProgram?.();
2364
+ if (fromProject !== void 0) return fromProject;
2365
+ if (cachedFallbackProgram !== void 0) return cachedFallbackProgram;
2366
+ const fallback = createFallbackProgram(ts, projectRoot, log, tsconfigPath, typeTargetSpecs);
2367
+ if (fallback !== void 0) cachedFallbackProgram = fallback;
2368
+ return fallback;
2369
+ };
2370
+ const createTypeInfoApiSessionFactory2 = ({
2371
+ id: _id,
2372
+ importer: _importer
2373
+ }) => {
2374
+ let session = null;
2375
+ let apiUsed = false;
2376
+ const getSession = () => {
2377
+ if (session) return session;
2378
+ const program = getProgramForTypeInfo();
2379
+ if (program === void 0) {
2380
+ if (preCreatedSession) {
2381
+ session = preCreatedSession;
2382
+ return session;
2383
+ }
2384
+ log(`getSession: no program available for ${_id}`);
2385
+ throw new Error(
2386
+ "TypeInfo session creation failed: Program not yet available. Retry when project is loaded."
2387
+ );
2388
+ }
2389
+ try {
2390
+ const programWithBootstrap = getProgramWithTypeTargetBootstrap(
2391
+ ts,
2392
+ program,
2393
+ projectRoot,
2394
+ typeTargetSpecs
2395
+ );
2396
+ session = createTypeInfoApiSession({
2397
+ ts,
2398
+ program: programWithBootstrap,
2399
+ ...typeTargetSpecs.length > 0 ? { typeTargetSpecs, failWhenNoTargetsResolved: false } : {}
2400
+ });
2401
+ } catch (err) {
2402
+ if (preCreatedSession) {
2403
+ log(`getSession: real program session failed, using pre-created session: ${err instanceof Error ? err.message : String(err)}`);
2404
+ session = preCreatedSession;
2405
+ return session;
2406
+ }
2407
+ throw err;
2408
+ }
2409
+ return session;
2410
+ };
2411
+ return {
2412
+ api: {
2413
+ file: (path, opts) => {
2414
+ apiUsed = true;
2415
+ return getSession().api.file(path, opts);
2416
+ },
2417
+ directory: (glob, opts) => {
2418
+ apiUsed = true;
2419
+ return getSession().api.directory(glob, opts);
2420
+ },
2421
+ resolveExport: (baseDir, filePath, exportName) => {
2422
+ apiUsed = true;
2423
+ return getSession().api.resolveExport(baseDir, filePath, exportName);
2424
+ },
2425
+ isAssignableTo: (node, targetId, projection) => {
2426
+ apiUsed = true;
2427
+ return getSession().api.isAssignableTo(node, targetId, projection);
2428
+ }
2429
+ },
2430
+ consumeDependencies: () => apiUsed ? getSession().consumeDependencies() : []
2431
+ };
2432
+ };
2433
+ const projectWithWatch = info.project;
2434
+ const sys = ts.sys;
2435
+ const projectWatchFile = projectWithWatch.watchFile;
2436
+ const projectWatchDirectory = projectWithWatch.watchDirectory;
2437
+ const sysWatchFile = sys?.watchFile;
2438
+ const sysWatchDirectory = sys?.watchDirectory;
2439
+ const watchHost = typeof projectWatchFile === "function" ? {
2440
+ watchFile: (path, callback) => projectWatchFile(path, callback),
2441
+ watchDirectory: typeof projectWatchDirectory === "function" ? (path, callback, recursive) => projectWatchDirectory(path, callback, recursive) : void 0
2442
+ } : typeof sysWatchFile === "function" ? {
2443
+ watchFile: (path, callback) => sysWatchFile(path, callback),
2444
+ watchDirectory: typeof sysWatchDirectory === "function" ? (path, callback, recursive) => sysWatchDirectory(path, callback, recursive) : void 0
2445
+ } : void 0;
2446
+ attachLanguageServiceAdapter({
2447
+ ts,
2448
+ languageService: info.languageService,
2449
+ languageServiceHost: info.project,
2450
+ resolver,
2451
+ projectRoot,
2452
+ createTypeInfoApiSession: createTypeInfoApiSessionFactory2,
2453
+ watchHost,
2454
+ debounceMs
2455
+ });
2456
+ const projectWithDirty = info.project;
2457
+ if (typeof projectWithDirty.invalidateResolutionsOfFailedLookupLocations === "function") {
2458
+ projectWithDirty.invalidateResolutionsOfFailedLookupLocations();
2459
+ } else if (typeof projectWithDirty.markAsDirty === "function") {
2460
+ projectWithDirty.markAsDirty();
2461
+ }
2462
+ setTimeout(() => {
2463
+ log("deferred retry: invalidating failed lookups");
2464
+ if (typeof projectWithDirty.invalidateResolutionsOfFailedLookupLocations === "function") {
2465
+ projectWithDirty.invalidateResolutionsOfFailedLookupLocations();
2466
+ }
2467
+ if (typeof projectWithDirty.markAsDirty === "function") {
2468
+ projectWithDirty.markAsDirty();
2469
+ }
2470
+ }, 200);
2471
+ return info.languageService;
2472
+ }
2473
+ return { create };
2474
+ }
2475
+ module.exports = init;