rspress-plugin-api-extractor 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-extracted-package.js +2 -1
- package/build-program.js +20 -12
- package/build-stages.js +123 -29
- package/config-utils.js +36 -7
- package/index.d.ts +329 -202
- package/layers/ConfigServiceLive.js +300 -136
- package/layers/ObservabilityLive.js +49 -85
- package/layers/TypeRegistryServiceLive.js +122 -21
- package/layers/build-metrics.js +61 -0
- package/llms-program.js +29 -7
- package/loader.js +16 -2
- package/markdown/shiki-utils.js +16 -2
- package/observability/EventBus.js +38 -0
- package/observability/events.js +17 -0
- package/observability/sinks/console-sink.js +63 -0
- package/observability/sinks/metrics-sink.js +68 -0
- package/observability/sinks/trace-sink.js +38 -0
- package/observability/spans.js +57 -0
- package/og-resolver.js +37 -5
- package/package.json +4 -4
- package/plugin.js +73 -19
- package/prettier-formatter.js +15 -4
- package/remark-api-codeblocks.js +22 -3
- package/remark-with-api.js +27 -14
- package/runtime/components/ApiExample/index.js +5 -5
- package/runtime/components/ApiMember/index.js +5 -7
- package/runtime/components/ApiSignature/index.js +4 -6
- package/runtime/components/EnumMembersTable/index.js +5 -0
- package/runtime/components/ExampleBlock/index.js +5 -3
- package/runtime/components/MemberSignature/index.js +4 -2
- package/runtime/components/ParametersTable/index.js +5 -0
- package/runtime/components/SignatureBlock/index.js +4 -2
- package/runtime/components/shared/variables.css +0 -15
- package/runtime/index.d.ts +65 -399
- package/runtime/index.js +1 -5
- package/runtime/utils/hast-renderer.js +1 -0
- package/schemas/config.js +105 -4
- package/schemas/index.js +2 -1
- package/schemas/observability.js +62 -0
- package/schemas/opengraph.js +30 -0
- package/schemas/performance.js +1 -1
- package/serve.js +13 -0
- package/twoslash-transformer.js +93 -8
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hashContent } from "../content-hash.js";
|
|
2
|
+
import { PluginEvent } from "../observability/events.js";
|
|
3
|
+
import { emit, wantsLevel } from "../observability/EventBus.js";
|
|
4
|
+
import { BuildMetrics } from "./build-metrics.js";
|
|
5
|
+
import "./ObservabilityLive.js";
|
|
2
6
|
import { TypeReferenceExtractor } from "../type-reference-extractor.js";
|
|
3
7
|
import { OpenGraphResolver } from "../og-resolver.js";
|
|
8
|
+
import { withPhase } from "../observability/spans.js";
|
|
4
9
|
import { resolveTypeScriptConfig } from "../typescript-config.js";
|
|
5
10
|
import { TwoslashManager } from "../twoslash-transformer.js";
|
|
6
11
|
import { extractAutoDetectedPackages, isVersionConfig, mergeLlmsPluginConfig, validateExternalPackages } from "../config-utils.js";
|
|
@@ -21,6 +26,14 @@ import os from "node:os";
|
|
|
21
26
|
import { createHighlighter } from "shiki";
|
|
22
27
|
|
|
23
28
|
//#region src/layers/ConfigServiceLive.ts
|
|
29
|
+
const DEFAULT_THRESHOLDS = {
|
|
30
|
+
slowCodeBlock: 100,
|
|
31
|
+
slowPageGeneration: 500,
|
|
32
|
+
slowApiLoad: 1e3,
|
|
33
|
+
slowFileOperation: 50,
|
|
34
|
+
slowHttpRequest: 2e3,
|
|
35
|
+
slowDbOperation: 100
|
|
36
|
+
};
|
|
24
37
|
/**
|
|
25
38
|
* Normalize theme configuration from user input to a consistent format.
|
|
26
39
|
*/
|
|
@@ -41,18 +54,40 @@ function normalizeThemeConfig(theme) {
|
|
|
41
54
|
}
|
|
42
55
|
/**
|
|
43
56
|
* Prepend import statements for external type references to the VFS declaration files.
|
|
57
|
+
* Returns per-entry payloads for event emission (heavy content/importRefs gated on wantTrace).
|
|
44
58
|
*/
|
|
45
|
-
function prependImportsToVfs(vfs, apiPackage, packageName) {
|
|
59
|
+
function prependImportsToVfs(vfs, apiPackage, packageName, wantTrace) {
|
|
46
60
|
const extractor = new TypeReferenceExtractor(apiPackage, packageName);
|
|
61
|
+
const payloads = [];
|
|
47
62
|
for (const entryPoint of apiPackage.entryPoints) {
|
|
48
|
-
const
|
|
63
|
+
const entryEp = entryPoint;
|
|
64
|
+
const imports = extractor.extractImportsForEntryPoint(entryEp);
|
|
49
65
|
const importStatements = TypeReferenceExtractor.formatImports(imports);
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
const entryName = entryEp.displayName || "";
|
|
67
|
+
const file = `node_modules/${packageName}/${entryName ? `${entryName}.d.ts` : "index.d.ts"}`;
|
|
68
|
+
const hasImports = importStatements.length > 0;
|
|
69
|
+
if (hasImports) {
|
|
70
|
+
const existing = vfs.get(file);
|
|
71
|
+
if (existing) vfs.set(file, `${importStatements.join("\n")}\n\n${existing}`);
|
|
72
|
+
}
|
|
73
|
+
const content = vfs.get(file) ?? "";
|
|
74
|
+
const declCount = entryEp.members.length;
|
|
75
|
+
const contentHash = hashContent(content);
|
|
76
|
+
const importRefs = wantTrace && hasImports ? imports.map((i) => ({
|
|
77
|
+
from: i.packageName,
|
|
78
|
+
symbols: [...i.symbols]
|
|
79
|
+
})) : [];
|
|
80
|
+
payloads.push({
|
|
81
|
+
file,
|
|
82
|
+
entryPoint: entryName,
|
|
83
|
+
declCount,
|
|
84
|
+
contentHash,
|
|
85
|
+
content: wantTrace ? content : "",
|
|
86
|
+
hasImports,
|
|
87
|
+
importRefs
|
|
88
|
+
});
|
|
55
89
|
}
|
|
90
|
+
return payloads;
|
|
56
91
|
}
|
|
57
92
|
/**
|
|
58
93
|
* Validate plugin options and return an Effect that fails with ConfigValidationError.
|
|
@@ -92,7 +127,13 @@ function validateOptions(options, rspressConfig) {
|
|
|
92
127
|
reason: `api.versions keys [${[...pluginKeys].join(", ")}] must exactly match multiVersion.versions [${[...rspressKeys].join(", ")}].`
|
|
93
128
|
});
|
|
94
129
|
} else {
|
|
95
|
-
if (api.versions) yield*
|
|
130
|
+
if (api.versions) yield* emit(PluginEvent.ConfigCascadeWarning({
|
|
131
|
+
ctx: { buildId: "" },
|
|
132
|
+
level: "warn",
|
|
133
|
+
field: "versions",
|
|
134
|
+
chosen: "(none — multiVersion not configured)",
|
|
135
|
+
ignored: ["api.versions"]
|
|
136
|
+
}));
|
|
96
137
|
if (!api.model) return yield* new ConfigValidationError({
|
|
97
138
|
field: "api.model",
|
|
98
139
|
reason: "'model' is required when multiVersion is not active."
|
|
@@ -105,12 +146,13 @@ function validateOptions(options, rspressConfig) {
|
|
|
105
146
|
* Resolves plugin options + RSPress config into a fully prepared build context
|
|
106
147
|
* with loaded models, type system, and resources.
|
|
107
148
|
*/
|
|
108
|
-
function ConfigServiceLive(options, shikiCrossLinker) {
|
|
149
|
+
function ConfigServiceLive(options, shikiCrossLinker, buildId = "", resolvedThresholds) {
|
|
109
150
|
return Layer.effect(ConfigService, Effect.gen(function* () {
|
|
110
151
|
const typeRegistry = yield* TypeRegistryService;
|
|
111
152
|
const pathService = yield* PathDerivationService;
|
|
112
153
|
return { resolve: (rspressConfig) => Effect.gen(function* () {
|
|
113
154
|
const loadStart = performance.now();
|
|
155
|
+
const wantTrace = yield* wantsLevel("trace");
|
|
114
156
|
yield* validateOptions(options, { ...rspressConfig.multiVersion ? { multiVersion: {
|
|
115
157
|
default: rspressConfig.multiVersion.default,
|
|
116
158
|
versions: [...rspressConfig.multiVersion.versions]
|
|
@@ -130,7 +172,7 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
130
172
|
/**
|
|
131
173
|
* Helper to process a single API model (shared by single and multi modes).
|
|
132
174
|
*/
|
|
133
|
-
const processSimpleApi = (api, model, outputDir, fullRoute) => Effect.promise(async () => {
|
|
175
|
+
const processSimpleApi = (api, model, outputDir, fullRoute, wantTrace) => Effect.promise(async () => {
|
|
134
176
|
const { apiPackage, source: loaderSource } = await ApiModelLoader.loadApiModel(model);
|
|
135
177
|
const resolvedCategories = categoryResolver.resolveCategoryConfig(pluginDefaults, api.categories);
|
|
136
178
|
const resolvedSource = categoryResolver.resolveSourceConfig(api.source, loaderSource);
|
|
@@ -140,11 +182,12 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
140
182
|
const externalPackages = api.externalPackages || extractAutoDetectedPackages(packageJson, api.autoDetectDependencies);
|
|
141
183
|
if (externalPackages && externalPackages.length > 0) Effect.runSync(Metric.incrementBy(BuildMetrics.externalPackagesTotal, externalPackages.length));
|
|
142
184
|
const vfs = ApiExtractedPackage.fromPackage(apiPackage, api.packageName).generateVfs();
|
|
143
|
-
prependImportsToVfs(vfs, apiPackage, api.packageName);
|
|
185
|
+
const vfsPayloads = prependImportsToVfs(vfs, apiPackage, api.packageName, wantTrace);
|
|
144
186
|
const resolvedOgImage = api.ogImage ?? options.ogImage;
|
|
145
187
|
const resolvedTheme = normalizeThemeConfig(api.theme);
|
|
146
188
|
return {
|
|
147
189
|
vfs,
|
|
190
|
+
vfsPayloads,
|
|
148
191
|
externalPackages: externalPackages || [],
|
|
149
192
|
config: {
|
|
150
193
|
apiPackage,
|
|
@@ -164,123 +207,216 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
164
207
|
}
|
|
165
208
|
};
|
|
166
209
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
210
|
+
yield* withPhase("modelLoad", { buildId }, Effect.gen(function* () {
|
|
211
|
+
if (options.api) {
|
|
212
|
+
const api = options.api;
|
|
213
|
+
const baseRoute = yield* pathService.normalizeBaseRoute(api.baseRoute ?? "/");
|
|
214
|
+
firstApiTsconfig = api.tsconfig;
|
|
215
|
+
firstApiCompilerOptions = api.compilerOptions;
|
|
216
|
+
if (rspressMultiVersion && api.versions) {
|
|
217
|
+
const versionResults = yield* Effect.forEach(Object.entries(api.versions), ([version, versionValue]) => Effect.gen(function* () {
|
|
218
|
+
const versionDp = (yield* pathService.derivePaths({
|
|
219
|
+
mode: "single",
|
|
220
|
+
docsRoot: rspressRoot,
|
|
221
|
+
baseRoute,
|
|
222
|
+
apiFolder: api.apiFolder ?? "api",
|
|
223
|
+
locales: rspressLocales,
|
|
224
|
+
defaultLang: rspressLang,
|
|
225
|
+
versions: [version],
|
|
226
|
+
defaultVersion: rspressMultiVersion?.default
|
|
227
|
+
}))[0];
|
|
228
|
+
if (!versionDp) return {
|
|
229
|
+
vfs: /* @__PURE__ */ new Map(),
|
|
230
|
+
vfsPayloads: [],
|
|
231
|
+
externalPackages: [],
|
|
232
|
+
config: null
|
|
233
|
+
};
|
|
234
|
+
return yield* Effect.promise(async () => {
|
|
235
|
+
const versionConfig = isVersionConfig(versionValue) ? versionValue : { model: versionValue };
|
|
236
|
+
const { apiPackage, packageJson: versionPackageJson, categories: versionCategories, source: versionSource, externalPackages: versionExternalPackages, autoDetectDependencies: versionAutoDetectDependencies, llmsPlugin: versionLlms, ogImage: versionOgImage } = await ApiModelLoader.loadVersionModel(versionConfig);
|
|
237
|
+
Effect.runSync(Metric.increment(BuildMetrics.apiVersionsLoaded));
|
|
238
|
+
const resolvedCategories = categoryResolver.resolveCategoryConfig(pluginDefaults, api.categories, versionCategories);
|
|
239
|
+
const resolvedSource = categoryResolver.resolveSourceConfig(api.source, versionSource);
|
|
240
|
+
const resolvedLlms = mergeLlmsPluginConfig(options.llmsPlugin, api.llmsPlugin, versionLlms);
|
|
241
|
+
const packageJson = versionPackageJson || (api.packageJson ? await ApiModelLoader.loadPackageJson(api.packageJson) : void 0);
|
|
242
|
+
validateExternalPackages(versionExternalPackages || api.externalPackages, packageJson);
|
|
243
|
+
const autoDetectOptions = versionAutoDetectDependencies || api.autoDetectDependencies;
|
|
244
|
+
const externalPackages = versionExternalPackages || api.externalPackages || extractAutoDetectedPackages(packageJson, autoDetectOptions);
|
|
245
|
+
if (externalPackages && externalPackages.length > 0) Effect.runSync(Metric.incrementBy(BuildMetrics.externalPackagesTotal, externalPackages.length));
|
|
246
|
+
const vfs = ApiExtractedPackage.fromPackage(apiPackage, api.packageName).generateVfs();
|
|
247
|
+
const vfsPayloads = prependImportsToVfs(vfs, apiPackage, api.packageName, wantTrace);
|
|
248
|
+
const resolvedOgImage = versionOgImage ?? api.ogImage ?? options.ogImage;
|
|
249
|
+
const resolvedTheme = normalizeThemeConfig(api.theme);
|
|
250
|
+
const outputDir = versionDp.outputDir;
|
|
251
|
+
const fullRoute = versionDp.routeBase;
|
|
252
|
+
return {
|
|
253
|
+
vfs,
|
|
254
|
+
vfsPayloads,
|
|
255
|
+
externalPackages: externalPackages || [],
|
|
256
|
+
config: {
|
|
257
|
+
apiPackage,
|
|
258
|
+
packageName: `${api.packageName} (${version})`,
|
|
259
|
+
...api.name != null ? { apiName: api.name } : {},
|
|
260
|
+
outputDir,
|
|
261
|
+
baseRoute: fullRoute,
|
|
262
|
+
categories: resolvedCategories,
|
|
263
|
+
...resolvedSource != null ? { source: resolvedSource } : {},
|
|
264
|
+
...packageJson != null ? { packageJson } : {},
|
|
265
|
+
...resolvedLlms != null ? { llmsPlugin: resolvedLlms } : {},
|
|
266
|
+
...options.siteUrl != null ? { siteUrl: options.siteUrl } : {},
|
|
267
|
+
...resolvedOgImage != null ? { ogImage: resolvedOgImage } : {},
|
|
268
|
+
docsDir: path.dirname(outputDir),
|
|
269
|
+
...docsRoot != null ? { docsRoot } : {},
|
|
270
|
+
...resolvedTheme != null ? { theme: resolvedTheme } : {}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
}), { concurrency: "unbounded" });
|
|
275
|
+
for (const result of versionResults) {
|
|
276
|
+
for (const [filepath, content] of result.vfs.entries()) combinedVfs.set(filepath, content);
|
|
277
|
+
if (result.externalPackages.length > 0) allExternalPackages.push(...result.externalPackages);
|
|
278
|
+
if (result.config) apiConfigs.push(result.config);
|
|
279
|
+
for (const payload of result.vfsPayloads) {
|
|
280
|
+
yield* emit(PluginEvent.VfsGenerated({
|
|
281
|
+
ctx: {
|
|
282
|
+
buildId: "",
|
|
283
|
+
packageName: api.packageName,
|
|
284
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
285
|
+
},
|
|
286
|
+
level: "debug",
|
|
287
|
+
file: payload.file,
|
|
288
|
+
declCount: payload.declCount,
|
|
289
|
+
contentHash: payload.contentHash,
|
|
290
|
+
...wantTrace && payload.content ? { content: payload.content } : {}
|
|
291
|
+
}));
|
|
292
|
+
if (payload.hasImports) yield* emit(PluginEvent.ImportsPrepended({
|
|
293
|
+
ctx: {
|
|
294
|
+
buildId: "",
|
|
295
|
+
packageName: api.packageName,
|
|
296
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
297
|
+
},
|
|
298
|
+
level: "debug",
|
|
299
|
+
file: payload.file,
|
|
300
|
+
imports: wantTrace ? payload.importRefs : []
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
} else if (api.model) {
|
|
305
|
+
const dp = (yield* pathService.derivePaths({
|
|
175
306
|
mode: "single",
|
|
176
307
|
docsRoot: rspressRoot,
|
|
177
308
|
baseRoute,
|
|
178
309
|
apiFolder: api.apiFolder ?? "api",
|
|
179
310
|
locales: rspressLocales,
|
|
180
311
|
defaultLang: rspressLang,
|
|
181
|
-
versions: [
|
|
182
|
-
defaultVersion:
|
|
312
|
+
versions: [],
|
|
313
|
+
defaultVersion: void 0
|
|
183
314
|
}))[0];
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (result.externalPackages.length > 0) allExternalPackages.push(...result.externalPackages);
|
|
232
|
-
if (result.config) apiConfigs.push(result.config);
|
|
315
|
+
if (dp) {
|
|
316
|
+
const result = yield* processSimpleApi(api, api.model, dp.outputDir, dp.routeBase, wantTrace);
|
|
317
|
+
for (const [filepath, content] of result.vfs.entries()) combinedVfs.set(filepath, content);
|
|
318
|
+
if (result.externalPackages.length > 0) allExternalPackages.push(...result.externalPackages);
|
|
319
|
+
apiConfigs.push(result.config);
|
|
320
|
+
for (const payload of result.vfsPayloads) {
|
|
321
|
+
yield* emit(PluginEvent.VfsGenerated({
|
|
322
|
+
ctx: {
|
|
323
|
+
buildId: "",
|
|
324
|
+
packageName: api.packageName,
|
|
325
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
326
|
+
},
|
|
327
|
+
level: "debug",
|
|
328
|
+
file: payload.file,
|
|
329
|
+
declCount: payload.declCount,
|
|
330
|
+
contentHash: payload.contentHash,
|
|
331
|
+
...wantTrace && payload.content ? { content: payload.content } : {}
|
|
332
|
+
}));
|
|
333
|
+
if (payload.hasImports) yield* emit(PluginEvent.ImportsPrepended({
|
|
334
|
+
ctx: {
|
|
335
|
+
buildId: "",
|
|
336
|
+
packageName: api.packageName,
|
|
337
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
338
|
+
},
|
|
339
|
+
level: "debug",
|
|
340
|
+
file: payload.file,
|
|
341
|
+
imports: wantTrace ? payload.importRefs : []
|
|
342
|
+
}));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} else if (options.apis) {
|
|
347
|
+
const apisWithTsconfig = options.apis.filter((a) => a.tsconfig);
|
|
348
|
+
if (apisWithTsconfig.length > 0) {
|
|
349
|
+
firstApiTsconfig = apisWithTsconfig[0].tsconfig;
|
|
350
|
+
const uniqueTsconfigs = new Set(apisWithTsconfig.map((a) => String(a.tsconfig)));
|
|
351
|
+
if (uniqueTsconfigs.size > 1) {
|
|
352
|
+
const chosen = String(firstApiTsconfig);
|
|
353
|
+
const ignored = [...uniqueTsconfigs].filter((t) => t !== chosen);
|
|
354
|
+
yield* emit(PluginEvent.ConfigCascadeWarning({
|
|
355
|
+
ctx: { buildId: "" },
|
|
356
|
+
level: "warn",
|
|
357
|
+
field: "tsconfig",
|
|
358
|
+
chosen,
|
|
359
|
+
ignored
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
233
362
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
363
|
+
const apisWithCompilerOptions = options.apis.filter((a) => a.compilerOptions);
|
|
364
|
+
if (apisWithCompilerOptions.length > 0) firstApiCompilerOptions = apisWithCompilerOptions[0].compilerOptions;
|
|
365
|
+
const multiResults = yield* Effect.forEach(options.apis, (api) => Effect.gen(function* () {
|
|
366
|
+
const apiBaseRoute = yield* pathService.normalizeBaseRoute(api.baseRoute ?? `/${unscopedName(api.packageName)}`);
|
|
367
|
+
const dp = (yield* pathService.derivePaths({
|
|
368
|
+
mode: "multi",
|
|
369
|
+
docsRoot: rspressRoot,
|
|
370
|
+
baseRoute: apiBaseRoute,
|
|
371
|
+
apiFolder: api.apiFolder ?? "api",
|
|
372
|
+
locales: rspressLocales,
|
|
373
|
+
defaultLang: rspressLang,
|
|
374
|
+
versions: [],
|
|
375
|
+
defaultVersion: void 0
|
|
376
|
+
}))[0];
|
|
377
|
+
if (!dp) return [];
|
|
378
|
+
const result = yield* processSimpleApi(api, api.model, dp.outputDir, dp.routeBase, wantTrace);
|
|
379
|
+
for (const payload of result.vfsPayloads) {
|
|
380
|
+
yield* emit(PluginEvent.VfsGenerated({
|
|
381
|
+
ctx: {
|
|
382
|
+
buildId: "",
|
|
383
|
+
packageName: api.packageName,
|
|
384
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
385
|
+
},
|
|
386
|
+
level: "debug",
|
|
387
|
+
file: payload.file,
|
|
388
|
+
declCount: payload.declCount,
|
|
389
|
+
contentHash: payload.contentHash,
|
|
390
|
+
...wantTrace && payload.content ? { content: payload.content } : {}
|
|
391
|
+
}));
|
|
392
|
+
if (payload.hasImports) yield* emit(PluginEvent.ImportsPrepended({
|
|
393
|
+
ctx: {
|
|
394
|
+
buildId: "",
|
|
395
|
+
packageName: api.packageName,
|
|
396
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
397
|
+
},
|
|
398
|
+
level: "debug",
|
|
399
|
+
file: payload.file,
|
|
400
|
+
imports: wantTrace ? payload.importRefs : []
|
|
401
|
+
}));
|
|
402
|
+
}
|
|
403
|
+
return [result];
|
|
404
|
+
}), { concurrency: "unbounded" });
|
|
405
|
+
for (const results of multiResults) for (const result of results) {
|
|
247
406
|
for (const [filepath, content] of result.vfs.entries()) combinedVfs.set(filepath, content);
|
|
248
407
|
if (result.externalPackages.length > 0) allExternalPackages.push(...result.externalPackages);
|
|
249
408
|
apiConfigs.push(result.config);
|
|
250
409
|
}
|
|
251
410
|
}
|
|
252
|
-
}
|
|
253
|
-
const apisWithTsconfig = options.apis.filter((a) => a.tsconfig);
|
|
254
|
-
if (apisWithTsconfig.length > 0) {
|
|
255
|
-
firstApiTsconfig = apisWithTsconfig[0].tsconfig;
|
|
256
|
-
const uniqueTsconfigs = new Set(apisWithTsconfig.map((a) => String(a.tsconfig)));
|
|
257
|
-
if (uniqueTsconfigs.size > 1) yield* Effect.logWarning(`Multiple APIs specify different tsconfig values: ${[...uniqueTsconfigs].join(", ")}. Using '${String(firstApiTsconfig)}' for TypeScript resolution. Per-API tsconfig resolution will be supported in a future release.`);
|
|
258
|
-
}
|
|
259
|
-
const apisWithCompilerOptions = options.apis.filter((a) => a.compilerOptions);
|
|
260
|
-
if (apisWithCompilerOptions.length > 0) firstApiCompilerOptions = apisWithCompilerOptions[0].compilerOptions;
|
|
261
|
-
const multiResults = yield* Effect.forEach(options.apis, (api) => Effect.gen(function* () {
|
|
262
|
-
const apiBaseRoute = yield* pathService.normalizeBaseRoute(api.baseRoute ?? `/${unscopedName(api.packageName)}`);
|
|
263
|
-
const dp = (yield* pathService.derivePaths({
|
|
264
|
-
mode: "multi",
|
|
265
|
-
docsRoot: rspressRoot,
|
|
266
|
-
baseRoute: apiBaseRoute,
|
|
267
|
-
apiFolder: api.apiFolder ?? "api",
|
|
268
|
-
locales: rspressLocales,
|
|
269
|
-
defaultLang: rspressLang,
|
|
270
|
-
versions: [],
|
|
271
|
-
defaultVersion: void 0
|
|
272
|
-
}))[0];
|
|
273
|
-
if (!dp) return [];
|
|
274
|
-
return [yield* processSimpleApi(api, api.model, dp.outputDir, dp.routeBase)];
|
|
275
|
-
}), { concurrency: "unbounded" });
|
|
276
|
-
for (const results of multiResults) for (const result of results) {
|
|
277
|
-
for (const [filepath, content] of result.vfs.entries()) combinedVfs.set(filepath, content);
|
|
278
|
-
if (result.externalPackages.length > 0) allExternalPackages.push(...result.externalPackages);
|
|
279
|
-
apiConfigs.push(result.config);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
411
|
+
}), resolvedThresholds ?? DEFAULT_THRESHOLDS);
|
|
282
412
|
const loadMs = performance.now() - loadStart;
|
|
283
|
-
yield*
|
|
413
|
+
yield* emit(PluginEvent.ModelLoaded({
|
|
414
|
+
ctx: { buildId: "" },
|
|
415
|
+
level: "debug",
|
|
416
|
+
entryPoints: apiConfigs.length,
|
|
417
|
+
itemCount: apiConfigs.reduce((sum, cfg) => sum + cfg.apiPackage.entryPoints.reduce((s, ep) => s + ep.members.length, 0), 0),
|
|
418
|
+
durationMs: Math.round(loadMs)
|
|
419
|
+
}));
|
|
284
420
|
const projectRoot = process.cwd();
|
|
285
421
|
let globalTsConfig;
|
|
286
422
|
if (firstApiTsconfig || firstApiCompilerOptions) {
|
|
@@ -289,28 +425,50 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
289
425
|
if (firstApiCompilerOptions != null) globalTsConfig.compilerOptions = firstApiCompilerOptions;
|
|
290
426
|
}
|
|
291
427
|
const resolvedCompilerOptions = yield* Effect.promise(() => resolveTypeScriptConfig(projectRoot, globalTsConfig));
|
|
292
|
-
yield*
|
|
293
|
-
|
|
428
|
+
yield* emit(PluginEvent.TsCacheCreated({
|
|
429
|
+
ctx: { buildId: "" },
|
|
430
|
+
level: "debug",
|
|
431
|
+
compilerOptions: `target=${resolvedCompilerOptions.target}, module=${resolvedCompilerOptions.module}, lib=[${resolvedCompilerOptions.lib?.join(", ") ?? ""}]`,
|
|
432
|
+
durationMs: 0
|
|
433
|
+
}));
|
|
434
|
+
const documentedPackageNames = new Set(apiConfigs.map((config) => config.packageName));
|
|
435
|
+
const externalPackagesToLoad = allExternalPackages.filter((pkg) => !documentedPackageNames.has(pkg.name));
|
|
294
436
|
const typeLoadResult = yield* Effect.either(Effect.gen(function* () {
|
|
295
|
-
if (
|
|
296
|
-
const
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
437
|
+
if (externalPackagesToLoad.length > 0) {
|
|
438
|
+
const resolvedPackages = yield* typeRegistry.resolveVersions(externalPackagesToLoad);
|
|
439
|
+
const droppedCount = externalPackagesToLoad.length - resolvedPackages.length;
|
|
440
|
+
if (droppedCount > 0) yield* emit(PluginEvent.ExternalPackageSkipped({
|
|
441
|
+
ctx: { buildId: "" },
|
|
442
|
+
level: "debug",
|
|
443
|
+
reason: `${droppedCount} unresolvable package(s) (unpublished or workspace-only)`
|
|
444
|
+
}));
|
|
445
|
+
if (resolvedPackages.length > 0) {
|
|
446
|
+
const result = yield* typeRegistry.loadPackages(resolvedPackages);
|
|
447
|
+
for (const [filePath, content] of result.vfs.entries()) combinedVfs.set(filePath, content);
|
|
448
|
+
yield* emit(PluginEvent.VfsMerged({
|
|
449
|
+
ctx: { buildId: "" },
|
|
450
|
+
level: "debug",
|
|
451
|
+
totalFiles: result.vfs.size,
|
|
452
|
+
packages: resolvedPackages.map((p) => p.name)
|
|
453
|
+
}));
|
|
454
|
+
}
|
|
302
455
|
}
|
|
303
|
-
return yield* typeRegistry.createTypeScriptCache([], resolvedCompilerOptions);
|
|
304
456
|
}));
|
|
305
|
-
if (typeLoadResult._tag === "
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
457
|
+
if (typeLoadResult._tag === "Left") yield* emit(PluginEvent.ConfigCascadeWarning({
|
|
458
|
+
ctx: { buildId: "" },
|
|
459
|
+
level: "warn",
|
|
460
|
+
field: "externalTypes",
|
|
461
|
+
chosen: "empty VFS",
|
|
462
|
+
ignored: [typeLoadResult.left.message ?? String(typeLoadResult.left)]
|
|
463
|
+
}));
|
|
311
464
|
const twoslashStartMs = performance.now();
|
|
312
|
-
TwoslashManager.getInstance().initialize(combinedVfs, void 0, void 0,
|
|
313
|
-
yield*
|
|
465
|
+
TwoslashManager.getInstance().initialize(combinedVfs, void 0, void 0, void 0, resolvedCompilerOptions);
|
|
466
|
+
yield* emit(PluginEvent.TwoslashInitialized({
|
|
467
|
+
ctx: { buildId: "" },
|
|
468
|
+
level: "debug",
|
|
469
|
+
durationMs: Math.round(performance.now() - twoslashStartMs),
|
|
470
|
+
vfsFileCount: combinedVfs.size
|
|
471
|
+
}));
|
|
314
472
|
const shikiStartMs = performance.now();
|
|
315
473
|
const themeSet = /* @__PURE__ */ new Set();
|
|
316
474
|
const customThemes = [];
|
|
@@ -338,7 +496,12 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
338
496
|
themes,
|
|
339
497
|
langs
|
|
340
498
|
}));
|
|
341
|
-
yield*
|
|
499
|
+
yield* emit(PluginEvent.PhaseCompleted({
|
|
500
|
+
ctx: { buildId: "" },
|
|
501
|
+
level: "debug",
|
|
502
|
+
phase: "shikiInit",
|
|
503
|
+
durationMs: Math.round(performance.now() - shikiStartMs)
|
|
504
|
+
}));
|
|
342
505
|
const ogResolver = options.siteUrl ? new OpenGraphResolver({
|
|
343
506
|
siteUrl: options.siteUrl,
|
|
344
507
|
...docsRoot != null ? { docsRoot } : {}
|
|
@@ -352,7 +515,6 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
352
515
|
apiConfigs,
|
|
353
516
|
combinedVfs,
|
|
354
517
|
highlighter,
|
|
355
|
-
tsEnvCache,
|
|
356
518
|
resolvedCompilerOptions,
|
|
357
519
|
ogResolver,
|
|
358
520
|
shikiCrossLinker,
|
|
@@ -361,7 +523,9 @@ function ConfigServiceLive(options, shikiCrossLinker) {
|
|
|
361
523
|
twoslashTransformer,
|
|
362
524
|
pageConcurrency: os.cpus().length,
|
|
363
525
|
logLevel: logLevel === "none" ? "info" : logLevel,
|
|
364
|
-
suppressExampleErrors
|
|
526
|
+
suppressExampleErrors,
|
|
527
|
+
thresholds: resolvedThresholds ?? DEFAULT_THRESHOLDS,
|
|
528
|
+
buildId
|
|
365
529
|
};
|
|
366
530
|
}) };
|
|
367
531
|
}));
|