@typed/virtual-modules 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/README.md +135 -0
- package/dist/CompilerHostAdapter.d.ts +3 -0
- package/dist/CompilerHostAdapter.d.ts.map +1 -0
- package/dist/CompilerHostAdapter.js +160 -0
- package/dist/LanguageServiceAdapter.d.ts +3 -0
- package/dist/LanguageServiceAdapter.d.ts.map +1 -0
- package/dist/LanguageServiceAdapter.js +488 -0
- package/dist/LanguageServiceSession.d.ts +16 -0
- package/dist/LanguageServiceSession.d.ts.map +1 -0
- package/dist/LanguageServiceSession.js +122 -0
- package/dist/NodeModulePluginLoader.d.ts +8 -0
- package/dist/NodeModulePluginLoader.d.ts.map +1 -0
- package/dist/NodeModulePluginLoader.js +175 -0
- package/dist/PluginManager.d.ts +10 -0
- package/dist/PluginManager.d.ts.map +1 -0
- package/dist/PluginManager.js +151 -0
- package/dist/TypeInfoApi.d.ts +71 -0
- package/dist/TypeInfoApi.d.ts.map +1 -0
- package/dist/TypeInfoApi.js +855 -0
- package/dist/VmcConfigLoader.d.ts +31 -0
- package/dist/VmcConfigLoader.d.ts.map +1 -0
- package/dist/VmcConfigLoader.js +231 -0
- package/dist/VmcResolverLoader.d.ts +30 -0
- package/dist/VmcResolverLoader.d.ts.map +1 -0
- package/dist/VmcResolverLoader.js +71 -0
- package/dist/collectTypeTargetSpecs.d.ts +6 -0
- package/dist/collectTypeTargetSpecs.d.ts.map +1 -0
- package/dist/collectTypeTargetSpecs.js +19 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/internal/VirtualRecordStore.d.ts +60 -0
- package/dist/internal/VirtualRecordStore.d.ts.map +1 -0
- package/dist/internal/VirtualRecordStore.js +199 -0
- package/dist/internal/materializeVirtualFile.d.ts +12 -0
- package/dist/internal/materializeVirtualFile.d.ts.map +1 -0
- package/dist/internal/materializeVirtualFile.js +28 -0
- package/dist/internal/path.d.ts +40 -0
- package/dist/internal/path.d.ts.map +1 -0
- package/dist/internal/path.js +71 -0
- package/dist/internal/sanitize.d.ts +6 -0
- package/dist/internal/sanitize.d.ts.map +1 -0
- package/dist/internal/sanitize.js +15 -0
- package/dist/internal/tsInternal.d.ts +65 -0
- package/dist/internal/tsInternal.d.ts.map +1 -0
- package/dist/internal/tsInternal.js +99 -0
- package/dist/internal/validation.d.ts +28 -0
- package/dist/internal/validation.d.ts.map +1 -0
- package/dist/internal/validation.js +66 -0
- package/dist/typeTargetBootstrap.d.ts +33 -0
- package/dist/typeTargetBootstrap.d.ts.map +1 -0
- package/dist/typeTargetBootstrap.js +57 -0
- package/dist/types.d.ts +405 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/package.json +38 -0
- package/src/CompilerHostAdapter.test.ts +180 -0
- package/src/CompilerHostAdapter.ts +316 -0
- package/src/LanguageServiceAdapter.test.ts +521 -0
- package/src/LanguageServiceAdapter.ts +631 -0
- package/src/LanguageServiceSession.ts +160 -0
- package/src/LanguageServiceTester.integration.test.ts +268 -0
- package/src/NodeModulePluginLoader.test.ts +170 -0
- package/src/NodeModulePluginLoader.ts +268 -0
- package/src/PluginManager.test.ts +178 -0
- package/src/PluginManager.ts +218 -0
- package/src/TypeInfoApi.test.ts +1211 -0
- package/src/TypeInfoApi.ts +1228 -0
- package/src/VmcConfigLoader.test.ts +108 -0
- package/src/VmcConfigLoader.ts +297 -0
- package/src/VmcResolverLoader.test.ts +181 -0
- package/src/VmcResolverLoader.ts +116 -0
- package/src/collectTypeTargetSpecs.ts +22 -0
- package/src/index.ts +35 -0
- package/src/internal/VirtualRecordStore.ts +304 -0
- package/src/internal/materializeVirtualFile.ts +38 -0
- package/src/internal/path.ts +106 -0
- package/src/internal/sanitize.ts +16 -0
- package/src/internal/tsInternal.ts +127 -0
- package/src/internal/validation.ts +85 -0
- package/src/typeTargetBootstrap.ts +75 -0
- package/src/types.ts +535 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { VirtualModulePlugin, VirtualModuleResolver } from "./types.js";
|
|
2
|
+
export type VmcPluginEntry = VirtualModulePlugin | string;
|
|
3
|
+
export interface VmcConfig {
|
|
4
|
+
readonly resolver?: VirtualModuleResolver;
|
|
5
|
+
readonly plugins?: readonly VmcPluginEntry[];
|
|
6
|
+
}
|
|
7
|
+
export interface LoadVmcConfigOptions {
|
|
8
|
+
readonly projectRoot: string;
|
|
9
|
+
/**
|
|
10
|
+
* TypeScript module used to transpile vmc.config.ts on the fly.
|
|
11
|
+
* Required only when loading .ts configs.
|
|
12
|
+
*/
|
|
13
|
+
readonly ts?: typeof import("typescript");
|
|
14
|
+
/**
|
|
15
|
+
* Optional explicit config file path (absolute or relative to projectRoot).
|
|
16
|
+
*/
|
|
17
|
+
readonly configPath?: string;
|
|
18
|
+
}
|
|
19
|
+
export type LoadVmcConfigResult = {
|
|
20
|
+
readonly status: "not-found";
|
|
21
|
+
} | {
|
|
22
|
+
readonly status: "loaded";
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly config: VmcConfig;
|
|
25
|
+
} | {
|
|
26
|
+
readonly status: "error";
|
|
27
|
+
readonly path?: string;
|
|
28
|
+
readonly message: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function loadVmcConfig(options: LoadVmcConfigOptions): LoadVmcConfigResult;
|
|
31
|
+
//# sourceMappingURL=VmcConfigLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VmcConfigLoader.d.ts","sourceRoot":"","sources":["../src/VmcConfigLoader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAI7E,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,cAAc,YAAY,CAAC,CAAC;IAC1C;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAChF;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA4MnF,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA0DhF"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { runInThisContext } from "node:vm";
|
|
5
|
+
import { pathIsUnderBase, resolvePathUnderBase } from "./internal/path.js";
|
|
6
|
+
import { sanitizeErrorMessage } from "./internal/sanitize.js";
|
|
7
|
+
import { validatePathSegment } from "./internal/validation.js";
|
|
8
|
+
const VMC_CONFIG_NAMES = ["vmc.config.ts"];
|
|
9
|
+
const toMessage = (error) => {
|
|
10
|
+
if (error instanceof Error)
|
|
11
|
+
return error.message;
|
|
12
|
+
return String(error);
|
|
13
|
+
};
|
|
14
|
+
const isPluginLike = (value) => {
|
|
15
|
+
if (!value || typeof value !== "object")
|
|
16
|
+
return false;
|
|
17
|
+
const candidate = value;
|
|
18
|
+
return (typeof candidate.name === "string" &&
|
|
19
|
+
typeof candidate.shouldResolve === "function" &&
|
|
20
|
+
typeof candidate.build === "function");
|
|
21
|
+
};
|
|
22
|
+
const isResolverLike = (value) => {
|
|
23
|
+
if (!value || typeof value !== "object")
|
|
24
|
+
return false;
|
|
25
|
+
return typeof value.resolveModule === "function";
|
|
26
|
+
};
|
|
27
|
+
const normalizePluginEntries = (value) => {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
return { ok: true, plugins: [] };
|
|
30
|
+
if (!Array.isArray(value))
|
|
31
|
+
return { ok: false };
|
|
32
|
+
const plugins = [];
|
|
33
|
+
for (const entry of value) {
|
|
34
|
+
if (typeof entry === "string" && entry.trim().length > 0) {
|
|
35
|
+
plugins.push(entry.trim());
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (isPluginLike(entry)) {
|
|
39
|
+
plugins.push(entry);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
return { ok: false };
|
|
43
|
+
}
|
|
44
|
+
return { ok: true, plugins };
|
|
45
|
+
};
|
|
46
|
+
function validateProjectRoot(projectRoot) {
|
|
47
|
+
const projectRootResult = validatePathSegment(projectRoot, "projectRoot");
|
|
48
|
+
if (!projectRootResult.ok) {
|
|
49
|
+
return {
|
|
50
|
+
status: "error",
|
|
51
|
+
message: projectRootResult.reason,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const resolvedProjectRoot = resolve(projectRootResult.value);
|
|
55
|
+
if (!existsSync(resolvedProjectRoot)) {
|
|
56
|
+
return {
|
|
57
|
+
status: "error",
|
|
58
|
+
path: resolvedProjectRoot,
|
|
59
|
+
message: `projectRoot does not exist: ${resolvedProjectRoot}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (!statSync(resolvedProjectRoot).isDirectory()) {
|
|
63
|
+
return {
|
|
64
|
+
status: "error",
|
|
65
|
+
path: resolvedProjectRoot,
|
|
66
|
+
message: `projectRoot must be a directory: ${resolvedProjectRoot}`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return resolvedProjectRoot;
|
|
70
|
+
}
|
|
71
|
+
function resolveConfigPath(projectRoot, configPath) {
|
|
72
|
+
if (configPath !== undefined) {
|
|
73
|
+
const configPathResult = validatePathSegment(configPath, "configPath");
|
|
74
|
+
if (!configPathResult.ok) {
|
|
75
|
+
return {
|
|
76
|
+
status: "error",
|
|
77
|
+
message: configPathResult.reason,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const configPathValue = configPathResult.value;
|
|
81
|
+
if (!configPathValue.endsWith(".ts")) {
|
|
82
|
+
return {
|
|
83
|
+
status: "error",
|
|
84
|
+
message: `configPath must point to a .ts file: ${configPathValue}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const resolvedPath = resolve(projectRoot, configPathValue);
|
|
88
|
+
const underBase = resolvePathUnderBase(projectRoot, configPathValue);
|
|
89
|
+
if (!underBase.ok || resolve(underBase.path) !== resolvedPath) {
|
|
90
|
+
return {
|
|
91
|
+
status: "error",
|
|
92
|
+
message: `vmc config path escapes project root: ${configPathValue}`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (!existsSync(resolvedPath)) {
|
|
96
|
+
return {
|
|
97
|
+
status: "error",
|
|
98
|
+
path: resolvedPath,
|
|
99
|
+
message: `vmc config not found: ${resolvedPath}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (!statSync(resolvedPath).isFile()) {
|
|
103
|
+
return {
|
|
104
|
+
status: "error",
|
|
105
|
+
path: resolvedPath,
|
|
106
|
+
message: `vmc config path must point to a file: ${resolvedPath}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!pathIsUnderBase(projectRoot, resolvedPath)) {
|
|
110
|
+
return {
|
|
111
|
+
status: "error",
|
|
112
|
+
path: resolvedPath,
|
|
113
|
+
message: `vmc config path is outside project root after resolving symlinks: ${resolvedPath}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return resolvedPath;
|
|
117
|
+
}
|
|
118
|
+
for (const name of VMC_CONFIG_NAMES) {
|
|
119
|
+
const candidate = join(projectRoot, name);
|
|
120
|
+
if (!existsSync(candidate))
|
|
121
|
+
continue;
|
|
122
|
+
if (!statSync(candidate).isFile())
|
|
123
|
+
continue;
|
|
124
|
+
if (!pathIsUnderBase(projectRoot, candidate)) {
|
|
125
|
+
return {
|
|
126
|
+
status: "error",
|
|
127
|
+
path: candidate,
|
|
128
|
+
message: `vmc config is outside project root after resolving symlinks: ${candidate}`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return candidate;
|
|
132
|
+
}
|
|
133
|
+
return { status: "not-found" };
|
|
134
|
+
}
|
|
135
|
+
function loadTsConfigModule(tsMod, configPath) {
|
|
136
|
+
// vmc config is executable project code.
|
|
137
|
+
const sourceText = readFileSync(configPath, "utf8");
|
|
138
|
+
const transpiled = tsMod.transpileModule(sourceText, {
|
|
139
|
+
fileName: configPath,
|
|
140
|
+
compilerOptions: {
|
|
141
|
+
module: tsMod.ModuleKind.CommonJS,
|
|
142
|
+
target: tsMod.ScriptTarget.ES2020,
|
|
143
|
+
moduleResolution: tsMod.ModuleResolutionKind.NodeNext,
|
|
144
|
+
esModuleInterop: true,
|
|
145
|
+
},
|
|
146
|
+
reportDiagnostics: false,
|
|
147
|
+
}).outputText;
|
|
148
|
+
const localRequire = createRequire(configPath);
|
|
149
|
+
const module = { exports: {} };
|
|
150
|
+
const evaluate = runInThisContext(`(function (exports, require, module, __filename, __dirname) {${transpiled}\n})`, { filename: configPath });
|
|
151
|
+
evaluate(module.exports, localRequire, module, configPath, dirname(configPath));
|
|
152
|
+
return module.exports;
|
|
153
|
+
}
|
|
154
|
+
function normalizeConfigModule(loadedModule) {
|
|
155
|
+
const withDefault = loadedModule && typeof loadedModule === "object" && "default" in loadedModule
|
|
156
|
+
? loadedModule.default
|
|
157
|
+
: loadedModule;
|
|
158
|
+
if (!withDefault || typeof withDefault !== "object") {
|
|
159
|
+
return { ok: false };
|
|
160
|
+
}
|
|
161
|
+
const candidate = withDefault;
|
|
162
|
+
if (candidate.resolver !== undefined && !isResolverLike(candidate.resolver)) {
|
|
163
|
+
return { ok: false };
|
|
164
|
+
}
|
|
165
|
+
const normalizedPlugins = normalizePluginEntries(candidate.plugins);
|
|
166
|
+
if (!normalizedPlugins.ok) {
|
|
167
|
+
return { ok: false };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
ok: true,
|
|
171
|
+
config: {
|
|
172
|
+
...(candidate.resolver !== undefined
|
|
173
|
+
? { resolver: candidate.resolver }
|
|
174
|
+
: {}),
|
|
175
|
+
...(normalizedPlugins.plugins.length > 0 ? { plugins: normalizedPlugins.plugins } : {}),
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function loadVmcConfig(options) {
|
|
180
|
+
let attemptedPath;
|
|
181
|
+
try {
|
|
182
|
+
const projectRootOrStatus = validateProjectRoot(options.projectRoot);
|
|
183
|
+
if (typeof projectRootOrStatus !== "string")
|
|
184
|
+
return projectRootOrStatus;
|
|
185
|
+
const projectRoot = projectRootOrStatus;
|
|
186
|
+
const resolvedPathOrStatus = resolveConfigPath(projectRoot, options.configPath);
|
|
187
|
+
if (typeof resolvedPathOrStatus !== "string")
|
|
188
|
+
return resolvedPathOrStatus;
|
|
189
|
+
const resolvedPath = resolvedPathOrStatus;
|
|
190
|
+
attemptedPath = resolvedPath;
|
|
191
|
+
const loadedModule = resolvedPath.endsWith(".ts")
|
|
192
|
+
? (() => {
|
|
193
|
+
if (!options.ts) {
|
|
194
|
+
return {
|
|
195
|
+
__vmcConfigLoaderError: "TypeScript module is required to load vmc.config.ts",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return loadTsConfigModule(options.ts, resolvedPath);
|
|
199
|
+
})()
|
|
200
|
+
: createRequire(resolvedPath)(resolvedPath);
|
|
201
|
+
if (loadedModule &&
|
|
202
|
+
typeof loadedModule === "object" &&
|
|
203
|
+
"__vmcConfigLoaderError" in loadedModule) {
|
|
204
|
+
return {
|
|
205
|
+
status: "error",
|
|
206
|
+
path: resolvedPath,
|
|
207
|
+
message: loadedModule.__vmcConfigLoaderError,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const normalized = normalizeConfigModule(loadedModule);
|
|
211
|
+
if (!normalized.ok) {
|
|
212
|
+
return {
|
|
213
|
+
status: "error",
|
|
214
|
+
path: resolvedPath,
|
|
215
|
+
message: `Invalid vmc config export in ${resolvedPath}`,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
status: "loaded",
|
|
220
|
+
path: resolvedPath,
|
|
221
|
+
config: normalized.config,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return {
|
|
226
|
+
status: "error",
|
|
227
|
+
...(attemptedPath ? { path: attemptedPath } : {}),
|
|
228
|
+
message: sanitizeErrorMessage(`Failed to load vmc config${attemptedPath ? ` "${attemptedPath}"` : ""}: ${toMessage(error)}`),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { VmcPluginEntry } from "./VmcConfigLoader.js";
|
|
2
|
+
import type { NodeModulePluginLoadError, TypeTargetSpec, VirtualModulePlugin, VirtualModuleResolver } from "./types.js";
|
|
3
|
+
export interface LoadPluginsFromEntriesResult {
|
|
4
|
+
readonly plugins: readonly VirtualModulePlugin[];
|
|
5
|
+
readonly pluginSpecifiers: readonly string[];
|
|
6
|
+
readonly errors: readonly NodeModulePluginLoadError[];
|
|
7
|
+
}
|
|
8
|
+
export declare function loadPluginsFromEntries(entries: readonly VmcPluginEntry[], baseDir: string): LoadPluginsFromEntriesResult;
|
|
9
|
+
export type LoadResolverFromVmcConfigResult = {
|
|
10
|
+
readonly status: "not-found";
|
|
11
|
+
} | {
|
|
12
|
+
readonly status: "error";
|
|
13
|
+
readonly path?: string;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly status: "loaded";
|
|
17
|
+
readonly path: string;
|
|
18
|
+
readonly resolver?: VirtualModuleResolver;
|
|
19
|
+
readonly pluginSpecifiers: readonly string[];
|
|
20
|
+
readonly pluginLoadErrors: readonly NodeModulePluginLoadError[];
|
|
21
|
+
/** Type target specs from config for structural assignability in TypeInfo API. */
|
|
22
|
+
readonly typeTargetSpecs?: readonly TypeTargetSpec[];
|
|
23
|
+
};
|
|
24
|
+
export interface LoadResolverFromVmcConfigOptions {
|
|
25
|
+
readonly projectRoot: string;
|
|
26
|
+
readonly ts: typeof import("typescript");
|
|
27
|
+
readonly configPath?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function loadResolverFromVmcConfig(options: LoadResolverFromVmcConfigOptions): LoadResolverFromVmcConfigResult;
|
|
30
|
+
//# sourceMappingURL=VmcResolverLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VmcResolverLoader.d.ts","sourceRoot":"","sources":["../src/VmcResolverLoader.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EACV,yBAAyB,EACzB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACvD;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,OAAO,EAAE,MAAM,GACd,4BAA4B,CA0B9B;AAED,MAAM,MAAM,+BAA+B,GACvC;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9E;IACE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChE,kFAAkF;IAClF,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACtD,CAAC;AAEN,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,cAAc,YAAY,CAAC,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,+BAA+B,CAqCjC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { collectTypeTargetSpecsFromPlugins } from "./collectTypeTargetSpecs.js";
|
|
3
|
+
import { NodeModulePluginLoader } from "./NodeModulePluginLoader.js";
|
|
4
|
+
import { PluginManager } from "./PluginManager.js";
|
|
5
|
+
import { loadVmcConfig } from "./VmcConfigLoader.js";
|
|
6
|
+
function collectFromResolver(resolver) {
|
|
7
|
+
const pm = resolver;
|
|
8
|
+
if (!Array.isArray(pm.plugins) || pm.plugins.length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
const merged = collectTypeTargetSpecsFromPlugins(pm.plugins);
|
|
11
|
+
return merged.length > 0 ? merged : undefined;
|
|
12
|
+
}
|
|
13
|
+
export function loadPluginsFromEntries(entries, baseDir) {
|
|
14
|
+
const loader = new NodeModulePluginLoader();
|
|
15
|
+
const plugins = [];
|
|
16
|
+
const pluginSpecifiers = [];
|
|
17
|
+
const errors = [];
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if (typeof entry === "string") {
|
|
20
|
+
pluginSpecifiers.push(entry);
|
|
21
|
+
const loaded = loader.load({ specifier: entry, baseDir });
|
|
22
|
+
if (loaded.status === "loaded") {
|
|
23
|
+
plugins.push(loaded.plugin);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
errors.push(loaded);
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
plugins.push(entry);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
plugins,
|
|
34
|
+
pluginSpecifiers,
|
|
35
|
+
errors,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function loadResolverFromVmcConfig(options) {
|
|
39
|
+
const loadedVmcConfig = loadVmcConfig(options);
|
|
40
|
+
if (loadedVmcConfig.status === "not-found") {
|
|
41
|
+
return loadedVmcConfig;
|
|
42
|
+
}
|
|
43
|
+
if (loadedVmcConfig.status === "error") {
|
|
44
|
+
return loadedVmcConfig;
|
|
45
|
+
}
|
|
46
|
+
const vmcPlugins = loadedVmcConfig.config.plugins ?? [];
|
|
47
|
+
const pluginSpecifiers = vmcPlugins.filter((entry) => typeof entry === "string");
|
|
48
|
+
if (loadedVmcConfig.config.resolver) {
|
|
49
|
+
const resolver = loadedVmcConfig.config.resolver;
|
|
50
|
+
const typeTargetSpecs = collectFromResolver(resolver);
|
|
51
|
+
return {
|
|
52
|
+
status: "loaded",
|
|
53
|
+
path: loadedVmcConfig.path,
|
|
54
|
+
resolver,
|
|
55
|
+
pluginSpecifiers,
|
|
56
|
+
pluginLoadErrors: [],
|
|
57
|
+
...(typeTargetSpecs ? { typeTargetSpecs } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const loadedPlugins = loadPluginsFromEntries(vmcPlugins, dirname(loadedVmcConfig.path));
|
|
61
|
+
const resolver = loadedPlugins.plugins.length > 0 ? new PluginManager(loadedPlugins.plugins) : undefined;
|
|
62
|
+
const typeTargetSpecs = resolver ? collectFromResolver(resolver) : undefined;
|
|
63
|
+
return {
|
|
64
|
+
status: "loaded",
|
|
65
|
+
path: loadedVmcConfig.path,
|
|
66
|
+
...(resolver ? { resolver } : {}),
|
|
67
|
+
pluginSpecifiers: loadedPlugins.pluginSpecifiers,
|
|
68
|
+
pluginLoadErrors: loadedPlugins.errors,
|
|
69
|
+
...(typeTargetSpecs ? { typeTargetSpecs } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TypeTargetSpec, VirtualModulePlugin } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Collects and merges typeTargetSpecs from plugins. Dedupes by id (first wins).
|
|
4
|
+
*/
|
|
5
|
+
export declare function collectTypeTargetSpecsFromPlugins(plugins: readonly VirtualModulePlugin[]): readonly TypeTargetSpec[];
|
|
6
|
+
//# sourceMappingURL=collectTypeTargetSpecs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collectTypeTargetSpecs.d.ts","sourceRoot":"","sources":["../src/collectTypeTargetSpecs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtE;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,SAAS,mBAAmB,EAAE,GACtC,SAAS,cAAc,EAAE,CAc3B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collects and merges typeTargetSpecs from plugins. Dedupes by id (first wins).
|
|
3
|
+
*/
|
|
4
|
+
export function collectTypeTargetSpecsFromPlugins(plugins) {
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
const result = [];
|
|
7
|
+
for (const plugin of plugins) {
|
|
8
|
+
const specs = plugin.typeTargetSpecs;
|
|
9
|
+
if (!specs?.length)
|
|
10
|
+
continue;
|
|
11
|
+
for (const spec of specs) {
|
|
12
|
+
if (!seen.has(spec.id)) {
|
|
13
|
+
seen.add(spec.id);
|
|
14
|
+
result.push(spec);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./PluginManager.js";
|
|
3
|
+
export { collectTypeTargetSpecsFromPlugins } from "./collectTypeTargetSpecs.js";
|
|
4
|
+
export { createTypeInfoApiSession, createTypeInfoApiSessionFactory, createTypeTargetBootstrapContent, resolveTypeTargetsFromSpecs, type CreateTypeInfoApiSessionOptions, type ResolvedTypeTarget, } from "./TypeInfoApi.js";
|
|
5
|
+
export * from "./NodeModulePluginLoader.js";
|
|
6
|
+
export * from "./LanguageServiceAdapter.js";
|
|
7
|
+
export * from "./CompilerHostAdapter.js";
|
|
8
|
+
export * from "./VmcConfigLoader.js";
|
|
9
|
+
export * from "./VmcResolverLoader.js";
|
|
10
|
+
export { createVirtualFileName, createVirtualKey, VIRTUAL_MODULE_URI_SCHEME, VIRTUAL_NODE_MODULES_RELATIVE, type CreateVirtualFileNameParams, type CreateVirtualFileNameOptions, } from "./internal/path.js";
|
|
11
|
+
export { ensureTypeTargetBootstrapFile, getProgramWithTypeTargetBootstrap, getTypeTargetBootstrapPath, TYPE_TARGET_BOOTSTRAP_RELATIVE, type EnsureTypeTargetBootstrapFileFs, } from "./typeTargetBootstrap.js";
|
|
12
|
+
export { createLanguageServiceSessionFactory, type CreateLanguageServiceSessionFactoryOptions, } from "./LanguageServiceSession.js";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,KAAK,+BAA+B,EACpC,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,yBAAyB,EACzB,6BAA6B,EAC7B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,GAClC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,6BAA6B,EAC7B,iCAAiC,EACjC,0BAA0B,EAC1B,8BAA8B,EAC9B,KAAK,+BAA+B,GACrC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,mCAAmC,EACnC,KAAK,0CAA0C,GAChD,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./PluginManager.js";
|
|
3
|
+
export { collectTypeTargetSpecsFromPlugins } from "./collectTypeTargetSpecs.js";
|
|
4
|
+
export { createTypeInfoApiSession, createTypeInfoApiSessionFactory, createTypeTargetBootstrapContent, resolveTypeTargetsFromSpecs, } from "./TypeInfoApi.js";
|
|
5
|
+
export * from "./NodeModulePluginLoader.js";
|
|
6
|
+
export * from "./LanguageServiceAdapter.js";
|
|
7
|
+
export * from "./CompilerHostAdapter.js";
|
|
8
|
+
export * from "./VmcConfigLoader.js";
|
|
9
|
+
export * from "./VmcResolverLoader.js";
|
|
10
|
+
export { createVirtualFileName, createVirtualKey, VIRTUAL_MODULE_URI_SCHEME, VIRTUAL_NODE_MODULES_RELATIVE, } from "./internal/path.js";
|
|
11
|
+
export { ensureTypeTargetBootstrapFile, getProgramWithTypeTargetBootstrap, getTypeTargetBootstrapPath, TYPE_TARGET_BOOTSTRAP_RELATIVE, } from "./typeTargetBootstrap.js";
|
|
12
|
+
export { createLanguageServiceSessionFactory, } from "./LanguageServiceSession.js";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type * as ts from "typescript";
|
|
2
|
+
import type { ResolveVirtualModuleOptions, VirtualModuleDiagnostic, VirtualModuleRecord, VirtualModuleResolution } from "../types.js";
|
|
3
|
+
export type MutableVirtualRecord = Omit<VirtualModuleRecord, "version" | "stale"> & {
|
|
4
|
+
version: number;
|
|
5
|
+
stale: boolean;
|
|
6
|
+
};
|
|
7
|
+
export interface ResolveRecordResultResolved {
|
|
8
|
+
readonly status: "resolved";
|
|
9
|
+
readonly record: MutableVirtualRecord;
|
|
10
|
+
}
|
|
11
|
+
export interface ResolveRecordResultUnresolved {
|
|
12
|
+
readonly status: "unresolved";
|
|
13
|
+
}
|
|
14
|
+
export interface ResolveRecordResultError {
|
|
15
|
+
readonly status: "error";
|
|
16
|
+
readonly diagnostic: VirtualModuleDiagnostic;
|
|
17
|
+
}
|
|
18
|
+
export type ResolveRecordResult = ResolveRecordResultResolved | ResolveRecordResultUnresolved | ResolveRecordResultError;
|
|
19
|
+
export interface VirtualRecordStoreOptions {
|
|
20
|
+
readonly projectRoot: string;
|
|
21
|
+
readonly resolver: {
|
|
22
|
+
resolveModule(options: ResolveVirtualModuleOptions): VirtualModuleResolution;
|
|
23
|
+
};
|
|
24
|
+
readonly createTypeInfoApiSession?: ResolveVirtualModuleOptions["createTypeInfoApiSession"];
|
|
25
|
+
readonly debounceMs?: number;
|
|
26
|
+
readonly watchHost?: {
|
|
27
|
+
watchFile?(path: string, callback: () => void): ts.FileWatcher;
|
|
28
|
+
watchDirectory?(path: string, callback: () => void, recursive?: boolean): ts.FileWatcher;
|
|
29
|
+
};
|
|
30
|
+
/** Used by evictStaleImporters: records for which this returns true are evicted. */
|
|
31
|
+
readonly shouldEvictRecord: (record: MutableVirtualRecord) => boolean;
|
|
32
|
+
/** Called when flushPendingStale runs (after debounce). LS uses for epoch++. */
|
|
33
|
+
readonly onFlushStale?: () => void;
|
|
34
|
+
/** Called when a record is marked stale (immediate or after flush). CH uses for invalidatedPaths. */
|
|
35
|
+
readonly onMarkStale?: (record: MutableVirtualRecord) => void;
|
|
36
|
+
/** Called at start of resolveRecord (e.g. LS sets inResolveRecord). */
|
|
37
|
+
readonly onBeforeResolve?: () => void;
|
|
38
|
+
/** Called in finally after resolveRecord (e.g. LS clears inResolveRecord). */
|
|
39
|
+
readonly onAfterResolve?: () => void;
|
|
40
|
+
/** Called after a record is stored and watchers registered (e.g. LS clears diagnostics for importer). */
|
|
41
|
+
readonly onRecordResolved?: (record: MutableVirtualRecord) => void;
|
|
42
|
+
/** Called when a record is evicted (e.g. LS clears diagnostics for importer). */
|
|
43
|
+
readonly onEvictRecord?: (record: MutableVirtualRecord) => void;
|
|
44
|
+
}
|
|
45
|
+
export declare function toResolvedModule(tsMod: typeof import("typescript"), fileName: string): ts.ResolvedModuleFull;
|
|
46
|
+
export declare function createVirtualRecordStore(options: VirtualRecordStoreOptions): {
|
|
47
|
+
recordsByKey: Map<string, MutableVirtualRecord>;
|
|
48
|
+
recordsByVirtualFile: Map<string, MutableVirtualRecord>;
|
|
49
|
+
descriptorToVirtualKeys: Map<string, Set<string>>;
|
|
50
|
+
watcherByDescriptor: Map<string, ts.FileWatcher>;
|
|
51
|
+
evictRecord: (record: MutableVirtualRecord) => void;
|
|
52
|
+
evictStaleImporters: () => void;
|
|
53
|
+
registerWatchers: (record: MutableVirtualRecord) => void;
|
|
54
|
+
markStale: (descriptorKey: string) => void;
|
|
55
|
+
flushPendingStale: () => void;
|
|
56
|
+
resolveRecord: (id: string, importer: string, previous?: MutableVirtualRecord) => ResolveRecordResult;
|
|
57
|
+
getOrBuildRecord: (id: string, importer: string) => ResolveRecordResult;
|
|
58
|
+
dispose: () => void;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=VirtualRecordStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualRecordStore.d.ts","sourceRoot":"","sources":["../../src/internal/VirtualRecordStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EACV,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,aAAa,CAAC;AAGrB,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;CACvC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC;CAC9C;AAED,MAAM,MAAM,mBAAmB,GAC3B,2BAA2B,GAC3B,6BAA6B,GAC7B,wBAAwB,CAAC;AAE7B,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE;QACjB,aAAa,CAAC,OAAO,EAAE,2BAA2B,GAAG,uBAAuB,CAAC;KAC9E,CAAC;IACF,QAAQ,CAAC,wBAAwB,CAAC,EAAE,2BAA2B,CAAC,0BAA0B,CAAC,CAAC;IAC5F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,SAAS,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC;QAC/D,cAAc,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC;KAC1F,CAAC;IACF,oFAAoF;IACpF,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,OAAO,CAAC;IACtE,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,qGAAqG;IACrG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,uEAAuE;IACvE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC,yGAAyG;IACzG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACnE,iFAAiF;IACjF,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACjE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,YAAY,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,EAAE,CAAC,kBAAkB,CAMvB;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB;;;;;0BAoB5C,oBAAoB,KAAG,IAAI;+BAqBxB,IAAI;+BAYF,oBAAoB,KAAG,IAAI;+BAmD3B,MAAM,KAAG,IAAI;6BAtBjB,IAAI;wBAgD5B,MAAM,YACA,MAAM,aACL,oBAAoB,KAC9B,mBAAmB;2BAsDQ,MAAM,YAAY,MAAM,KAAG,mBAAmB;mBAexD,IAAI;EA8BzB"}
|