rspress-plugin-api-extractor 0.2.1 → 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 +7 -7
- 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
package/api-extracted-package.js
CHANGED
|
@@ -129,7 +129,8 @@ var ApiExtractedPackage = class ApiExtractedPackage extends VirtualPackageClass
|
|
|
129
129
|
const jsDoc = this.formatJSDoc(apiFunction);
|
|
130
130
|
if (jsDoc) lines.push(jsDoc);
|
|
131
131
|
const cleaned = this.cleanExcerpt(apiFunction.excerpt.text);
|
|
132
|
-
|
|
132
|
+
const decl = cleaned.startsWith("function ") ? cleaned : `const ${cleaned}`;
|
|
133
|
+
lines.push(`export declare ${decl};`);
|
|
133
134
|
return lines.join("\n");
|
|
134
135
|
}
|
|
135
136
|
generateEnumDeclaration(apiEnum) {
|
package/build-program.js
CHANGED
|
@@ -2,6 +2,7 @@ import { markdownCrossLinker } from "./markdown/cross-linker.js";
|
|
|
2
2
|
import "./markdown/index.js";
|
|
3
3
|
import { SnapshotService } from "./services/SnapshotService.js";
|
|
4
4
|
import { buildPipelineForApi, cleanupAndCommit, prepareWorkItems, writeMetadata } from "./build-stages.js";
|
|
5
|
+
import { withPhase } from "./observability/spans.js";
|
|
5
6
|
import { TwoslashManager } from "./twoslash-transformer.js";
|
|
6
7
|
import { VfsRegistry } from "./vfs-registry.js";
|
|
7
8
|
import path from "node:path";
|
|
@@ -28,18 +29,22 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
28
29
|
const snapshotSvc = yield* SnapshotService;
|
|
29
30
|
const { apiPackage, packageName, apiName, outputDir, baseRoute, categories, source, packageJson, llmsPlugin, siteUrl, ogImage } = apiConfig;
|
|
30
31
|
const suppressExampleErrors = apiConfig.suppressExampleErrors ?? true;
|
|
31
|
-
const { shikiCrossLinker, highlighter, hideCutTransformer, hideCutLinesTransformer, twoslashTransformer, ogResolver, pageConcurrency } = buildContext;
|
|
32
|
+
const { shikiCrossLinker, highlighter, hideCutTransformer, hideCutLinesTransformer, twoslashTransformer, ogResolver, pageConcurrency, thresholds, buildId } = buildContext;
|
|
33
|
+
const phaseCtx = {
|
|
34
|
+
buildId,
|
|
35
|
+
packageName
|
|
36
|
+
};
|
|
32
37
|
const resolvedOutputDir = path.resolve(process.cwd(), outputDir);
|
|
33
38
|
const buildTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
34
39
|
const allSnapshots = yield* snapshotSvc.getAllForDirectory(resolvedOutputDir).pipe(Effect.orDie);
|
|
35
40
|
const existingSnapshots = new Map(allSnapshots.map((s) => [s.filePath, s]));
|
|
36
41
|
yield* fileSystem.makeDirectory(resolvedOutputDir, { recursive: true }).pipe(Effect.orDie);
|
|
37
|
-
const { workItems, crossLinkData } = prepareWorkItems({
|
|
42
|
+
const { workItems, crossLinkData } = yield* withPhase("resolve", phaseCtx, Effect.sync(() => prepareWorkItems({
|
|
38
43
|
apiPackage,
|
|
39
44
|
categories,
|
|
40
45
|
baseRoute,
|
|
41
46
|
packageName
|
|
42
|
-
});
|
|
47
|
+
})), thresholds);
|
|
43
48
|
markdownCrossLinker.setRoutes(crossLinkData.routes);
|
|
44
49
|
const apiScope = baseRoute.replace(/^\//, "").split("/")[0] || packageName;
|
|
45
50
|
shikiCrossLinker.reinitialize(crossLinkData.routes, crossLinkData.kinds, apiScope);
|
|
@@ -58,8 +63,9 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
58
63
|
if (apiConfig.theme != null) vfsConfig.theme = apiConfig.theme;
|
|
59
64
|
VfsRegistry.register(apiScope, vfsConfig);
|
|
60
65
|
}
|
|
61
|
-
yield* Effect.
|
|
62
|
-
const fileResults = yield* buildPipelineForApi({
|
|
66
|
+
yield* Effect.logDebug(`Generating ${workItems.length} pages across ${Object.keys(categories).length} categories in parallel`);
|
|
67
|
+
const fileResults = yield* withPhase("generate", phaseCtx, buildPipelineForApi({
|
|
68
|
+
buildId,
|
|
63
69
|
workItems,
|
|
64
70
|
baseRoute,
|
|
65
71
|
packageName,
|
|
@@ -75,9 +81,9 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
75
81
|
...ogResolver !== void 0 ? { ogResolver } : {},
|
|
76
82
|
...siteUrl != null ? { siteUrl } : {},
|
|
77
83
|
...ogImage != null ? { ogImage } : {}
|
|
78
|
-
});
|
|
84
|
+
}), thresholds);
|
|
79
85
|
const changedCount = fileResults.filter((r) => r.status !== "unchanged").length;
|
|
80
|
-
yield* Effect.
|
|
86
|
+
yield* Effect.logDebug(`Generated ${changedCount} pages`);
|
|
81
87
|
const generatedFiles = /* @__PURE__ */ new Set();
|
|
82
88
|
for (const r of fileResults) {
|
|
83
89
|
generatedFiles.add(r.relativePathWithExt);
|
|
@@ -86,7 +92,8 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
86
92
|
if (packageJson?.version != null) ctx.version = packageJson.version;
|
|
87
93
|
fileContextMap.set(r.absolutePath, ctx);
|
|
88
94
|
}
|
|
89
|
-
yield* writeMetadata({
|
|
95
|
+
yield* withPhase("write", phaseCtx, writeMetadata({
|
|
96
|
+
buildId,
|
|
90
97
|
fileResults,
|
|
91
98
|
categories,
|
|
92
99
|
resolvedOutputDir,
|
|
@@ -96,13 +103,14 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
96
103
|
packageName,
|
|
97
104
|
...apiName != null ? { apiName } : {},
|
|
98
105
|
generatedFiles
|
|
99
|
-
});
|
|
100
|
-
yield* cleanupAndCommit({
|
|
106
|
+
}), thresholds);
|
|
107
|
+
yield* withPhase("cleanup", phaseCtx, cleanupAndCommit({
|
|
108
|
+
buildId,
|
|
101
109
|
fileResults,
|
|
102
110
|
resolvedOutputDir,
|
|
103
111
|
generatedFiles
|
|
104
|
-
});
|
|
105
|
-
yield* Effect.
|
|
112
|
+
}), thresholds);
|
|
113
|
+
yield* Effect.logDebug(`Generated ${changedCount} API documentation files for ${packageName}`);
|
|
106
114
|
return {
|
|
107
115
|
crossLinkData,
|
|
108
116
|
generatedFiles,
|
package/build-stages.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { hashContent, hashFrontmatter } from "./content-hash.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PluginEvent } from "./observability/events.js";
|
|
3
|
+
import { emit } from "./observability/EventBus.js";
|
|
4
|
+
import { BuildMetrics } from "./layers/build-metrics.js";
|
|
5
|
+
import "./layers/ObservabilityLive.js";
|
|
3
6
|
import { ApiParser } from "./loader.js";
|
|
4
7
|
import { generateFrontmatter } from "./markdown/helpers.js";
|
|
5
8
|
import { ClassPageGenerator } from "./markdown/page-generators/class-page.js";
|
|
@@ -187,8 +190,9 @@ function normalizeMarkdownSpacing(content) {
|
|
|
187
190
|
function generateSinglePage(workItem, ctx) {
|
|
188
191
|
return Effect.gen(function* () {
|
|
189
192
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
190
|
-
const { existingSnapshots, baseRoute, packageName, apiScope, apiName, source, buildTime, resolvedOutputDir, suppressExampleErrors, llmsPlugin } = ctx;
|
|
193
|
+
const { buildId, existingSnapshots, baseRoute, packageName, apiScope, apiName, source, buildTime, resolvedOutputDir, suppressExampleErrors, llmsPlugin } = ctx;
|
|
191
194
|
const { item, categoryConfig, namespaceMember } = workItem;
|
|
195
|
+
const pageGenStart = performance.now();
|
|
192
196
|
let page = null;
|
|
193
197
|
switch (item.kind) {
|
|
194
198
|
case ApiItemKind.Class: {
|
|
@@ -255,7 +259,17 @@ function generateSinglePage(workItem, ctx) {
|
|
|
255
259
|
break;
|
|
256
260
|
}
|
|
257
261
|
default:
|
|
258
|
-
yield*
|
|
262
|
+
yield* emit(PluginEvent.ItemSkipped({
|
|
263
|
+
ctx: {
|
|
264
|
+
buildId,
|
|
265
|
+
packageName,
|
|
266
|
+
apiScope
|
|
267
|
+
},
|
|
268
|
+
item: item.displayName,
|
|
269
|
+
kind: String(item.kind),
|
|
270
|
+
reason: "unsupported kind",
|
|
271
|
+
level: "trace"
|
|
272
|
+
}));
|
|
259
273
|
return null;
|
|
260
274
|
}
|
|
261
275
|
if (!page) return null;
|
|
@@ -267,7 +281,20 @@ function generateSinglePage(workItem, ctx) {
|
|
|
267
281
|
content: page.content
|
|
268
282
|
};
|
|
269
283
|
}
|
|
270
|
-
|
|
284
|
+
const codeblockCount = (page.content.match(/<(ApiSignature|ApiMember|ApiExample)\b/g) ?? []).length;
|
|
285
|
+
yield* emit(PluginEvent.PageGenerated({
|
|
286
|
+
ctx: {
|
|
287
|
+
buildId,
|
|
288
|
+
packageName,
|
|
289
|
+
apiScope,
|
|
290
|
+
route: page.routePath
|
|
291
|
+
},
|
|
292
|
+
item: item.displayName,
|
|
293
|
+
category: categoryConfig.displayName,
|
|
294
|
+
codeblockCount,
|
|
295
|
+
durationMs: Math.round(performance.now() - pageGenStart),
|
|
296
|
+
level: "debug"
|
|
297
|
+
}));
|
|
271
298
|
const parsed = matter(page.content);
|
|
272
299
|
const bodyContent = normalizeMarkdownSpacing(parsed.content);
|
|
273
300
|
const frontmatterData = parsed.data;
|
|
@@ -331,7 +358,7 @@ function generateSinglePage(workItem, ctx) {
|
|
|
331
358
|
function writeSingleFile(result, ctx) {
|
|
332
359
|
return Effect.gen(function* () {
|
|
333
360
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
334
|
-
const { resolvedOutputDir, buildTime, ogResolver, siteUrl, ogImage, packageName, apiName } = ctx;
|
|
361
|
+
const { buildId, resolvedOutputDir, buildTime, ogResolver, siteUrl, ogImage, packageName, apiName } = ctx;
|
|
335
362
|
const { workItem, bodyContent, frontmatter, contentHash, frontmatterHash, publishedTime, modifiedTime, isUnchanged, routePath, relativePathWithExt } = result;
|
|
336
363
|
const { item, categoryKey, categoryConfig, namespaceMember } = workItem;
|
|
337
364
|
const absolutePath = path.join(resolvedOutputDir, relativePathWithExt);
|
|
@@ -346,8 +373,18 @@ function writeSingleFile(result, ctx) {
|
|
|
346
373
|
buildTime
|
|
347
374
|
};
|
|
348
375
|
if (isUnchanged) {
|
|
349
|
-
yield*
|
|
350
|
-
|
|
376
|
+
yield* emit(PluginEvent.FileDecision({
|
|
377
|
+
ctx: {
|
|
378
|
+
buildId,
|
|
379
|
+
...packageName != null ? { packageName } : {}
|
|
380
|
+
},
|
|
381
|
+
file: relativePathWithExt,
|
|
382
|
+
status: "unchanged",
|
|
383
|
+
contentHash,
|
|
384
|
+
frontmatterHash,
|
|
385
|
+
source: "snapshot",
|
|
386
|
+
level: "debug"
|
|
387
|
+
}));
|
|
351
388
|
return {
|
|
352
389
|
relativePathWithExt,
|
|
353
390
|
absolutePath,
|
|
@@ -379,9 +416,18 @@ function writeSingleFile(result, ctx) {
|
|
|
379
416
|
yield* fileSystem.makeDirectory(dirPath, { recursive: true }).pipe(Effect.orDie);
|
|
380
417
|
yield* fileSystem.writeFileString(absolutePath, finalContent).pipe(Effect.orDie);
|
|
381
418
|
const status = fileExisted ? "modified" : "new";
|
|
382
|
-
yield*
|
|
383
|
-
|
|
384
|
-
|
|
419
|
+
yield* emit(PluginEvent.FileDecision({
|
|
420
|
+
ctx: {
|
|
421
|
+
buildId,
|
|
422
|
+
...packageName != null ? { packageName } : {}
|
|
423
|
+
},
|
|
424
|
+
file: relativePathWithExt,
|
|
425
|
+
status,
|
|
426
|
+
contentHash,
|
|
427
|
+
frontmatterHash,
|
|
428
|
+
source: "snapshot",
|
|
429
|
+
level: "debug"
|
|
430
|
+
}));
|
|
385
431
|
return {
|
|
386
432
|
relativePathWithExt,
|
|
387
433
|
absolutePath,
|
|
@@ -411,7 +457,7 @@ function writeMetadata(input) {
|
|
|
411
457
|
return Effect.gen(function* () {
|
|
412
458
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
413
459
|
const snapshotSvc = yield* SnapshotService;
|
|
414
|
-
const { fileResults, categories, resolvedOutputDir, existingSnapshots, buildTime, baseRoute, packageName, generatedFiles } = input;
|
|
460
|
+
const { buildId, fileResults, categories, resolvedOutputDir, existingSnapshots, buildTime, baseRoute, packageName, generatedFiles } = input;
|
|
415
461
|
const categoriesWithItems = /* @__PURE__ */ new Set();
|
|
416
462
|
for (const result of fileResults) categoriesWithItems.add(result.categoryKey);
|
|
417
463
|
const apiMetaEntries = [];
|
|
@@ -456,13 +502,30 @@ function writeMetadata(input) {
|
|
|
456
502
|
}
|
|
457
503
|
if (!apiMetaUnchanged) {
|
|
458
504
|
yield* fileSystem.writeFileString(apiMetaJsonPath, apiMetaJsonContent).pipe(Effect.orDie);
|
|
459
|
-
yield*
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
505
|
+
yield* emit(PluginEvent.FileDecision({
|
|
506
|
+
ctx: {
|
|
507
|
+
buildId,
|
|
508
|
+
packageName
|
|
509
|
+
},
|
|
510
|
+
file: apiMetaJsonRelPath,
|
|
511
|
+
status: apiMetaOldSnapshot ? "modified" : "new",
|
|
512
|
+
contentHash: apiMetaContentHash,
|
|
513
|
+
frontmatterHash: "",
|
|
514
|
+
source: "snapshot",
|
|
515
|
+
level: "debug"
|
|
516
|
+
}));
|
|
517
|
+
} else yield* emit(PluginEvent.FileDecision({
|
|
518
|
+
ctx: {
|
|
519
|
+
buildId,
|
|
520
|
+
packageName
|
|
521
|
+
},
|
|
522
|
+
file: apiMetaJsonRelPath,
|
|
523
|
+
status: "unchanged",
|
|
524
|
+
contentHash: apiMetaContentHash,
|
|
525
|
+
frontmatterHash: "",
|
|
526
|
+
source: "snapshot",
|
|
527
|
+
level: "debug"
|
|
528
|
+
}));
|
|
466
529
|
yield* snapshotSvc.upsert({
|
|
467
530
|
outputDir: resolvedOutputDir,
|
|
468
531
|
filePath: apiMetaJsonRelPath,
|
|
@@ -543,13 +606,30 @@ function writeMetadata(input) {
|
|
|
543
606
|
const categoryDir = path.dirname(categoryMetaPath);
|
|
544
607
|
yield* fileSystem.makeDirectory(categoryDir, { recursive: true }).pipe(Effect.orDie);
|
|
545
608
|
yield* fileSystem.writeFileString(categoryMetaPath, content).pipe(Effect.orDie);
|
|
546
|
-
yield*
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
609
|
+
yield* emit(PluginEvent.FileDecision({
|
|
610
|
+
ctx: {
|
|
611
|
+
buildId,
|
|
612
|
+
packageName
|
|
613
|
+
},
|
|
614
|
+
file: relPath,
|
|
615
|
+
status: oldSnapshot ? "modified" : "new",
|
|
616
|
+
contentHash,
|
|
617
|
+
frontmatterHash: "",
|
|
618
|
+
source: "snapshot",
|
|
619
|
+
level: "debug"
|
|
620
|
+
}));
|
|
621
|
+
} else yield* emit(PluginEvent.FileDecision({
|
|
622
|
+
ctx: {
|
|
623
|
+
buildId,
|
|
624
|
+
packageName
|
|
625
|
+
},
|
|
626
|
+
file: relPath,
|
|
627
|
+
status: "unchanged",
|
|
628
|
+
contentHash,
|
|
629
|
+
frontmatterHash: "",
|
|
630
|
+
source: "snapshot",
|
|
631
|
+
level: "debug"
|
|
632
|
+
}));
|
|
553
633
|
generatedFiles.add(relPath);
|
|
554
634
|
if (isUnchanged) return null;
|
|
555
635
|
return {
|
|
@@ -582,14 +662,18 @@ function cleanupAndCommit(input) {
|
|
|
582
662
|
return Effect.gen(function* () {
|
|
583
663
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
584
664
|
const snapshotSvc = yield* SnapshotService;
|
|
585
|
-
const { fileResults, resolvedOutputDir, generatedFiles } = input;
|
|
665
|
+
const { buildId, fileResults, resolvedOutputDir, generatedFiles } = input;
|
|
586
666
|
const snapshotsToUpdate = fileResults.filter((r) => r.status !== "unchanged").map((r) => r.snapshot);
|
|
587
667
|
if (snapshotsToUpdate.length > 0) yield* snapshotSvc.batchUpsert(snapshotsToUpdate).pipe(Effect.ignore);
|
|
588
668
|
const staleFiles = yield* snapshotSvc.cleanupStale(resolvedOutputDir, generatedFiles).pipe(Effect.orElseSucceed(() => []));
|
|
589
669
|
yield* Effect.forEach(staleFiles, (staleFile) => Effect.gen(function* () {
|
|
590
670
|
const fullPath = path.join(resolvedOutputDir, staleFile);
|
|
591
671
|
yield* fileSystem.remove(fullPath).pipe(Effect.ignore);
|
|
592
|
-
yield*
|
|
672
|
+
yield* emit(PluginEvent.StaleDeleted({
|
|
673
|
+
ctx: { buildId },
|
|
674
|
+
file: staleFile,
|
|
675
|
+
level: "trace"
|
|
676
|
+
}));
|
|
593
677
|
}), { concurrency: "unbounded" });
|
|
594
678
|
const allFiles = yield* fileSystem.readDirectory(resolvedOutputDir, { recursive: true }).pipe(Effect.orElseSucceed(() => []));
|
|
595
679
|
const orphanedFiles = [];
|
|
@@ -603,7 +687,11 @@ function cleanupAndCommit(input) {
|
|
|
603
687
|
const fullPath = path.join(resolvedOutputDir, orphan);
|
|
604
688
|
yield* fileSystem.remove(fullPath).pipe(Effect.ignore);
|
|
605
689
|
yield* snapshotSvc.deleteSnapshot(resolvedOutputDir, orphan).pipe(Effect.ignore);
|
|
606
|
-
yield*
|
|
690
|
+
yield* emit(PluginEvent.OrphanDeleted({
|
|
691
|
+
ctx: { buildId },
|
|
692
|
+
file: orphan,
|
|
693
|
+
level: "trace"
|
|
694
|
+
}));
|
|
607
695
|
}), { concurrency: "unbounded" });
|
|
608
696
|
if (orphanedFiles.length > 0) {
|
|
609
697
|
const dirs = /* @__PURE__ */ new Set();
|
|
@@ -616,7 +704,11 @@ function cleanupAndCommit(input) {
|
|
|
616
704
|
const fullDir = path.join(resolvedOutputDir, dir);
|
|
617
705
|
if ((yield* fileSystem.readDirectory(fullDir).pipe(Effect.orElseSucceed(() => ["placeholder"]))).length === 0) {
|
|
618
706
|
yield* fileSystem.remove(fullDir).pipe(Effect.ignore);
|
|
619
|
-
yield*
|
|
707
|
+
yield* emit(PluginEvent.EmptyDirRemoved({
|
|
708
|
+
ctx: { buildId },
|
|
709
|
+
dir,
|
|
710
|
+
level: "trace"
|
|
711
|
+
}));
|
|
620
712
|
}
|
|
621
713
|
}
|
|
622
714
|
}
|
|
@@ -637,6 +729,7 @@ function cleanupAndCommit(input) {
|
|
|
637
729
|
*/
|
|
638
730
|
function buildPipelineForApi(input) {
|
|
639
731
|
const generateCtx = {
|
|
732
|
+
buildId: input.buildId,
|
|
640
733
|
existingSnapshots: input.existingSnapshots,
|
|
641
734
|
baseRoute: input.baseRoute,
|
|
642
735
|
packageName: input.packageName,
|
|
@@ -649,6 +742,7 @@ function buildPipelineForApi(input) {
|
|
|
649
742
|
...input.llmsPlugin != null ? { llmsPlugin: input.llmsPlugin } : {}
|
|
650
743
|
};
|
|
651
744
|
const writeCtx = {
|
|
745
|
+
buildId: input.buildId,
|
|
652
746
|
resolvedOutputDir: input.resolvedOutputDir,
|
|
653
747
|
buildTime: input.buildTime,
|
|
654
748
|
...input.ogResolver !== void 0 ? { ogResolver: input.ogResolver } : {},
|
package/config-utils.js
CHANGED
|
@@ -118,17 +118,19 @@ function extractTypeUtilities(packageJson) {
|
|
|
118
118
|
* devDependencies: { "type-fest": "^4.0.0" }
|
|
119
119
|
* };
|
|
120
120
|
*
|
|
121
|
-
* // Default:
|
|
121
|
+
* // Default: dependencies + peerDependencies + type utilities (devDependencies excluded).
|
|
122
|
+
* // The documented type surface is usually written against runtime dependencies,
|
|
123
|
+
* // so those must be loaded for Twoslash to resolve them.
|
|
122
124
|
* extractAutoDetectedPackages(pkg);
|
|
123
|
-
* // Returns: [{ name: "zod", version: "^3.22.4" }, { name: "type-fest", version: "^4.0.0" }]
|
|
124
|
-
*
|
|
125
|
-
* // Include all dependency types
|
|
126
|
-
* extractAutoDetectedPackages(pkg, { dependencies: true, peerDependencies: true, autoDependencies: true });
|
|
127
125
|
* // Returns: [{ name: "effect", ... }, { name: "zod", ... }, { name: "type-fest", ... }]
|
|
126
|
+
*
|
|
127
|
+
* // Opt out of dependencies (peerDependencies + type utilities only)
|
|
128
|
+
* extractAutoDetectedPackages(pkg, { dependencies: false });
|
|
129
|
+
* // Returns: [{ name: "zod", version: "^3.22.4" }, { name: "type-fest", version: "^4.0.0" }]
|
|
128
130
|
* ```
|
|
129
131
|
*/
|
|
130
132
|
function extractAutoDetectedPackages(packageJson, options = {}) {
|
|
131
|
-
const { dependencies =
|
|
133
|
+
const { dependencies = true, devDependencies = false, peerDependencies = true, autoDependencies = true } = options;
|
|
132
134
|
const packages = [];
|
|
133
135
|
if (dependencies && packageJson?.dependencies) packages.push(...Object.entries(packageJson.dependencies).map(([name, version]) => ({
|
|
134
136
|
name,
|
|
@@ -185,6 +187,33 @@ function resolvePackageVersionConflicts(packages) {
|
|
|
185
187
|
return resolved;
|
|
186
188
|
}
|
|
187
189
|
/**
|
|
190
|
+
* Resolve each external package's version spec to an exact, published version.
|
|
191
|
+
*
|
|
192
|
+
* The type registry's CDN (jsDelivr) requires an exact version — its flat-file
|
|
193
|
+
* API 404s on semver ranges (`^4.1.0`), npm tags, and unpublished/workspace
|
|
194
|
+
* versions. This helper maps each spec through the supplied `resolve` function
|
|
195
|
+
* and drops any package whose resolution fails. Failures are the intended skip
|
|
196
|
+
* signal: a workspace-only or unpublished package (e.g. `@scope/pkg@1.0.0` that
|
|
197
|
+
* was never pushed to the registry) resolves to an error and is omitted, so it
|
|
198
|
+
* never poisons the batch load. Input order is preserved for survivors.
|
|
199
|
+
*
|
|
200
|
+
* @param packages - External package specs (typically post-deduplication)
|
|
201
|
+
* @param resolve - Resolver mapping a spec to its exact published version
|
|
202
|
+
* @returns Effect yielding the resolved specs with unresolvable packages dropped
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* // [{ name: "vitest", version: "^4.1.0" }] -> [{ name: "vitest", version: "4.1.9" }]
|
|
207
|
+
* // an unpublished workspace package resolves to an error and is dropped
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
function resolveExternalPackageVersions(packages, resolve) {
|
|
211
|
+
return Effect.forEach(packages, (pkg) => resolve(pkg).pipe(Effect.map((version) => ({
|
|
212
|
+
name: pkg.name,
|
|
213
|
+
version
|
|
214
|
+
})), Effect.catchAll(() => Effect.succeed(null))), { concurrency: 5 }).pipe(Effect.map((results) => results.filter((spec) => spec !== null)));
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
188
217
|
* Strip range prefixes from a version string to get a clean semver.
|
|
189
218
|
*/
|
|
190
219
|
function stripRangePrefix(version) {
|
|
@@ -255,4 +284,4 @@ function validateExternalPackages(externalPackages, packageJson) {
|
|
|
255
284
|
}
|
|
256
285
|
|
|
257
286
|
//#endregion
|
|
258
|
-
export { extractAutoDetectedPackages, isLoadedModel, isVersionConfig, mergeLlmsPluginConfig, validateExternalPackages };
|
|
287
|
+
export { extractAutoDetectedPackages, isLoadedModel, isVersionConfig, mergeLlmsPluginConfig, resolveExternalPackageVersions, validateExternalPackages };
|