rspress-plugin-api-extractor 0.9.2 → 0.11.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/BuildEnv.js +58 -0
- package/README.md +2 -1
- package/build-program.js +33 -30
- package/build-stages.js +47 -39
- package/errors.js +0 -1
- package/index.d.ts +22 -14
- package/layers/ConfigServiceLive.js +349 -400
- package/layers/HighlighterServiceLive.js +52 -0
- package/layers/ObservabilityLive.js +26 -7
- package/layers/OgServiceLive.js +134 -0
- package/layers/TwoslashCacheServiceLive.js +108 -0
- package/layers/TwoslashEnvironmentsLive.js +33 -0
- package/layers/TypeRegistryServiceLive.js +54 -47
- package/layers/build-metrics.js +32 -5
- package/layers/xdg.js +44 -0
- package/markdown/helpers.js +9 -55
- package/markdown/page-generators/class-page.js +8 -31
- package/markdown/page-generators/index-pages.js +6 -8
- package/markdown/page-generators/interface-page.js +7 -7
- package/markdown/shiki-utils.js +65 -10
- package/observability/EventBus.js +29 -9
- package/observability/heartbeat.js +1 -1
- package/observability/metric-report.js +124 -0
- package/observability/sinks/console-sink.js +6 -0
- package/observability/sinks/metrics-sink.js +64 -21
- package/observability/sinks/render-sink.js +86 -0
- package/observability/sinks/trace-sink.js +10 -17
- package/observability/spans.js +4 -2
- package/observability/sync-emitter.js +78 -0
- package/og-resolver.js +46 -287
- package/package.json +4 -5
- package/path-derivation.js +19 -1
- package/plugin.js +64 -52
- package/prettier-formatter.js +4 -10
- package/remark-api-codeblocks.js +33 -15
- package/remark-with-api.js +24 -27
- package/schemas/config.js +11 -7
- package/services/HighlighterService.js +30 -0
- package/services/OgService.js +23 -0
- package/services/PluginConfig.js +26 -0
- package/services/TwoslashCacheService.js +15 -0
- package/services/TwoslashEnvironments.js +7 -0
- package/shiki-transformer.js +55 -256
- package/twoslash-access.js +48 -0
- package/twoslash-cache.js +174 -0
- package/twoslash-patterns.js +1 -1
- package/twoslash-timing-wrapper.js +23 -0
- package/twoslash-transformer.js +153 -89
- package/vfs-registry.js +1 -31
- package/layers/PathDerivationServiceLive.js +0 -16
- package/runtime/components/MarkdownText/index.js +0 -34
- package/services/PathDerivationService.js +0 -7
package/BuildEnv.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/BuildEnv.ts
|
|
4
|
+
/**
|
|
5
|
+
* Per-build configuration, as `Context.Reference` values rather than threaded
|
|
6
|
+
* parameters.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Each of these used to travel by hand. `thresholds` made a four-hop journey —
|
|
10
|
+
* `plugin.ts` → `ConfigServiceLive`'s fourth constructor argument →
|
|
11
|
+
* a `ResolvedBuildContext` field → destructured in `build-program.ts` → every
|
|
12
|
+
* `withPhase` call — while `obs.thresholds` already held the same value one
|
|
13
|
+
* scope away. `buildId` was worse: 24 event emit sites wrote
|
|
14
|
+
* `ctx: { buildId: "" }` because the value was not reachable from where they
|
|
15
|
+
* stood, and in `TypeRegistryServiceLive` it genuinely was not — that layer is
|
|
16
|
+
* module-level and has no build to name. A Reference is the fix precisely
|
|
17
|
+
* because it reaches module-level code that no parameter can.
|
|
18
|
+
*
|
|
19
|
+
* A `Context.Reference` carries a default, so nothing has to provide these for
|
|
20
|
+
* a program to run. That is convenient and it is also the hazard: a wiring
|
|
21
|
+
* mistake does not fail, it silently substitutes the default. The tests for
|
|
22
|
+
* this module provide NON-default values and assert the provided value is the
|
|
23
|
+
* one observed, which is the only way to tell the two apart.
|
|
24
|
+
*
|
|
25
|
+
* @packageDocumentation
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Identifier correlating every event emitted by one build.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* The empty-string default is deliberate: an event emitted outside a build —
|
|
32
|
+
* a test, a stray sync callback — is better tagged empty than crashing. Every
|
|
33
|
+
* production path provides a real id.
|
|
34
|
+
*/
|
|
35
|
+
const BuildId = Context.Reference("rspress-plugin-api-extractor/BuildId", { defaultValue: () => "" });
|
|
36
|
+
/** Duration thresholds above which an operation is reported as slow. */
|
|
37
|
+
const Thresholds = Context.Reference("rspress-plugin-api-extractor/Thresholds", { defaultValue: () => ({
|
|
38
|
+
slowCodeBlock: 100,
|
|
39
|
+
slowPageGeneration: 500,
|
|
40
|
+
slowApiLoad: 1e3,
|
|
41
|
+
slowFileOperation: 50,
|
|
42
|
+
slowHttpRequest: 2e3,
|
|
43
|
+
slowDbOperation: 100
|
|
44
|
+
}) });
|
|
45
|
+
/**
|
|
46
|
+
* How many pages the build pipeline generates concurrently.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* Defaults to the CPU count, which is what `ConfigServiceLive` computed
|
|
50
|
+
* inline. Kept a Reference rather than a constant so a consumer with a
|
|
51
|
+
* constrained CI runner can lower it without a code change.
|
|
52
|
+
*/
|
|
53
|
+
const PageConcurrency = Context.Reference("rspress-plugin-api-extractor/PageConcurrency", { defaultValue: () => 1 });
|
|
54
|
+
/** Whether Twoslash diagnostics inside `@example` blocks are suppressed. */
|
|
55
|
+
const SuppressExampleErrors = Context.Reference("rspress-plugin-api-extractor/SuppressExampleErrors", { defaultValue: () => true });
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { BuildId, PageConcurrency, SuppressExampleErrors, Thresholds };
|
package/README.md
CHANGED
|
@@ -47,7 +47,8 @@ The plugin reads your `.api.json` model and writes one MDX page per public API i
|
|
|
47
47
|
## Features
|
|
48
48
|
|
|
49
49
|
- Generates API docs from `.api.json` models for classes, interfaces, functions, type aliases, enums, variables and namespaces.
|
|
50
|
-
- Type-checks code examples and adds Twoslash hover tooltips that show inferred types
|
|
50
|
+
- Type-checks code examples and adds Twoslash hover tooltips that show inferred types, each documented package under its own `tsconfig`.
|
|
51
|
+
- Caches Twoslash results between builds, so repeat builds over an unchanged API render code blocks near-instantly.
|
|
51
52
|
- Cross-links type references between pages, so a type named in a signature links to its own page.
|
|
52
53
|
- Inlines compiler-generated base declarations (the `Foo_base` pattern from Effect `Schema.Class`, `Data.TaggedError` and mixin factories) in a "Base Class" section on the owning class page instead of documenting them as orphan variables.
|
|
53
54
|
- Drives single-package sites, multi-package portals, RSPress multiVersion and i18n from one plugin.
|
package/build-program.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { BuildId, PageConcurrency, SuppressExampleErrors } from "./BuildEnv.js";
|
|
1
2
|
import { setProseLinker } from "./markdown/prose-linker.js";
|
|
2
3
|
import "./markdown/index.js";
|
|
3
4
|
import { buildPipelineForApi, cleanupAndCommit, prepareWorkItems, writeMetadata } from "./build-stages.js";
|
|
5
|
+
import { HideCutLinesTransformer, MemberFormatTransformer } from "./hide-cut-transformer.js";
|
|
4
6
|
import { withPhase } from "./observability/spans.js";
|
|
5
|
-
import {
|
|
7
|
+
import { HighlighterService } from "./services/HighlighterService.js";
|
|
8
|
+
import { TwoslashEnvironments } from "./services/TwoslashEnvironments.js";
|
|
9
|
+
import { ShikiCrossLinker } from "./shiki-transformer.js";
|
|
10
|
+
import { addTypeRoutes } from "./twoslash-transformer.js";
|
|
6
11
|
import { VfsRegistry } from "./vfs-registry.js";
|
|
7
12
|
import path from "node:path";
|
|
8
13
|
import { SnapshotService } from "@tsdoctor/snapshot";
|
|
@@ -22,17 +27,17 @@ import { Effect, FileSystem } from "effect";
|
|
|
22
27
|
* Returns build result metadata including CrossLinkData for cross-link merging
|
|
23
28
|
* and generated file paths for LLMs post-processing.
|
|
24
29
|
*/
|
|
25
|
-
function generateApiDocs(apiConfig,
|
|
30
|
+
function generateApiDocs(apiConfig, fileContextMap) {
|
|
26
31
|
return Effect.gen(function* () {
|
|
27
32
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
33
|
+
const { highlighter } = yield* HighlighterService;
|
|
34
|
+
const environments = yield* TwoslashEnvironments;
|
|
35
|
+
const buildId = yield* BuildId;
|
|
36
|
+
const pageConcurrency = yield* PageConcurrency;
|
|
37
|
+
const suppressExampleErrors = yield* SuppressExampleErrors;
|
|
28
38
|
const snapshotSvc = yield* SnapshotService;
|
|
29
39
|
const { apiPackage, packageName, apiName, outputDir, baseRoute, categories, source, packageJson, llmsPlugin, siteUrl, ogImage } = apiConfig;
|
|
30
|
-
const
|
|
31
|
-
const { shikiCrossLinker, highlighter, hideCutTransformer, hideCutLinesTransformer, twoslashTransformer, ogResolver, pageConcurrency, thresholds, buildId } = buildContext;
|
|
32
|
-
const phaseCtx = {
|
|
33
|
-
buildId,
|
|
34
|
-
packageName
|
|
35
|
-
};
|
|
40
|
+
const phaseCtx = { packageName };
|
|
36
41
|
const resolvedOutputDir = path.resolve(process.cwd(), outputDir);
|
|
37
42
|
const buildTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
38
43
|
const allSnapshots = yield* snapshotSvc.getAllForDirectory(resolvedOutputDir).pipe(Effect.orDie);
|
|
@@ -43,28 +48,27 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
43
48
|
categories,
|
|
44
49
|
baseRoute,
|
|
45
50
|
packageName
|
|
46
|
-
}))
|
|
51
|
+
})));
|
|
47
52
|
setProseLinker(crossLinkData.routes);
|
|
48
53
|
const apiScope = baseRoute.replace(/^\//, "").split("/")[0] || packageName;
|
|
49
|
-
shikiCrossLinker.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
VfsRegistry.register(apiScope, vfsConfig);
|
|
64
|
-
}
|
|
54
|
+
const shikiCrossLinker = ShikiCrossLinker.fromRoutes(crossLinkData.routes, crossLinkData.kinds, apiScope);
|
|
55
|
+
addTypeRoutes(crossLinkData.routes);
|
|
56
|
+
const vfsConfig = {
|
|
57
|
+
highlighter,
|
|
58
|
+
crossLinker: shikiCrossLinker,
|
|
59
|
+
packageName,
|
|
60
|
+
apiScope
|
|
61
|
+
};
|
|
62
|
+
const scopeTransformer = environments.transformerFor(apiScope);
|
|
63
|
+
if (scopeTransformer != null) vfsConfig.twoslashTransformer = scopeTransformer;
|
|
64
|
+
vfsConfig.hideCutTransformer = MemberFormatTransformer;
|
|
65
|
+
vfsConfig.hideCutLinesTransformer = HideCutLinesTransformer;
|
|
66
|
+
if (apiConfig.theme != null) vfsConfig.theme = apiConfig.theme;
|
|
67
|
+
VfsRegistry.register(apiScope, vfsConfig);
|
|
65
68
|
yield* Effect.logDebug(`Generating ${workItems.length} pages across ${Object.keys(categories).length} categories in parallel`);
|
|
66
69
|
const fileResults = yield* withPhase("generate", phaseCtx, buildPipelineForApi({
|
|
67
70
|
buildId,
|
|
71
|
+
pageConcurrency,
|
|
68
72
|
workItems,
|
|
69
73
|
baseRoute,
|
|
70
74
|
packageName,
|
|
@@ -73,14 +77,13 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
73
77
|
...source != null ? { source } : {},
|
|
74
78
|
buildTime,
|
|
75
79
|
resolvedOutputDir,
|
|
76
|
-
pageConcurrency,
|
|
77
80
|
existingSnapshots,
|
|
78
81
|
...suppressExampleErrors != null ? { suppressExampleErrors } : {},
|
|
79
82
|
...llmsPlugin != null ? { llmsPlugin } : {},
|
|
80
|
-
...
|
|
83
|
+
...apiConfig.docsRoot != null ? { docsRoot: apiConfig.docsRoot } : {},
|
|
81
84
|
...siteUrl != null ? { siteUrl } : {},
|
|
82
85
|
...ogImage != null ? { ogImage } : {}
|
|
83
|
-
})
|
|
86
|
+
}));
|
|
84
87
|
const changedCount = fileResults.filter((r) => r.status !== "unchanged").length;
|
|
85
88
|
yield* Effect.logDebug(`Generated ${changedCount} pages`);
|
|
86
89
|
const generatedFiles = /* @__PURE__ */ new Set();
|
|
@@ -102,13 +105,13 @@ function generateApiDocs(apiConfig, buildContext, fileContextMap) {
|
|
|
102
105
|
packageName,
|
|
103
106
|
...apiName != null ? { apiName } : {},
|
|
104
107
|
generatedFiles
|
|
105
|
-
})
|
|
108
|
+
}));
|
|
106
109
|
yield* withPhase("cleanup", phaseCtx, cleanupAndCommit({
|
|
107
110
|
buildId,
|
|
108
111
|
fileResults,
|
|
109
112
|
resolvedOutputDir,
|
|
110
113
|
generatedFiles
|
|
111
|
-
})
|
|
114
|
+
}));
|
|
112
115
|
yield* Effect.logDebug(`Generated ${changedCount} API documentation files for ${packageName}`);
|
|
113
116
|
return {
|
|
114
117
|
crossLinkData,
|
package/build-stages.js
CHANGED
|
@@ -3,6 +3,7 @@ import { PluginEvent } from "./observability/events.js";
|
|
|
3
3
|
import { emit } from "./observability/EventBus.js";
|
|
4
4
|
import { BuildMetrics } from "./layers/build-metrics.js";
|
|
5
5
|
import "./layers/ObservabilityLive.js";
|
|
6
|
+
import { emitSync, syncBuildId } from "./observability/sync-emitter.js";
|
|
6
7
|
import { generateFrontmatter } from "./markdown/helpers.js";
|
|
7
8
|
import { ClassPageGenerator } from "./markdown/page-generators/class-page.js";
|
|
8
9
|
import { EnumPageGenerator } from "./markdown/page-generators/enum-page.js";
|
|
@@ -13,10 +14,11 @@ import { NamespacePageGenerator } from "./markdown/page-generators/namespace-pag
|
|
|
13
14
|
import { TypeAliasPageGenerator } from "./markdown/page-generators/type-alias-page.js";
|
|
14
15
|
import { VariablePageGenerator } from "./markdown/page-generators/variable-page.js";
|
|
15
16
|
import "./markdown/index.js";
|
|
16
|
-
import {
|
|
17
|
+
import { createPageMetadata } from "./og-resolver.js";
|
|
18
|
+
import { OgService } from "./services/OgService.js";
|
|
17
19
|
import path from "node:path";
|
|
18
20
|
import { SnapshotService, hashContent, hashFrontmatter } from "@tsdoctor/snapshot";
|
|
19
|
-
import { Effect, FileSystem, Metric, Stream } from "effect";
|
|
21
|
+
import { Effect, FileSystem, Metric, Option, Stream } from "effect";
|
|
20
22
|
import { ApiItemKind } from "@microsoft/api-extractor-model";
|
|
21
23
|
import { ApiItems, EntryPoints, Routes, SyntheticBases } from "@tsdoctor/model";
|
|
22
24
|
|
|
@@ -41,24 +43,6 @@ function crossLinkKindPriority(kind) {
|
|
|
41
43
|
return CROSS_LINK_KIND_PRIORITY[kind] ?? 100;
|
|
42
44
|
}
|
|
43
45
|
/**
|
|
44
|
-
* Module-level emitter seam. `prepareWorkItems` runs synchronously outside any
|
|
45
|
-
* Effect fiber, so a route collision cannot `yield* emit(...)` — it mirrors the
|
|
46
|
-
* sync-island pattern used by `twoslash-transformer.ts` (`setEventEmitter`) and
|
|
47
|
-
* `loader.ts` (`setLoaderEventEmitter`). Default is a no-op; wired in plugin.ts
|
|
48
|
-
* via `setBuildStagesEventEmitter(emitSync, buildId)` right after the runtime
|
|
49
|
-
* emitter is created.
|
|
50
|
-
*/
|
|
51
|
-
let emitEvent = () => {};
|
|
52
|
-
let currentBuildId = "";
|
|
53
|
-
/**
|
|
54
|
-
* Inject the runtime-bound emitter into the build-stages module.
|
|
55
|
-
* Call this right after `makeRuntimeEmitter` in plugin.ts.
|
|
56
|
-
*/
|
|
57
|
-
function setBuildStagesEventEmitter(fn, buildId = "") {
|
|
58
|
-
emitEvent = fn;
|
|
59
|
-
currentBuildId = buildId;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
46
|
* Prepare the flat list of WorkItems to process and the cross-link data maps.
|
|
63
47
|
*
|
|
64
48
|
* This function:
|
|
@@ -82,8 +66,8 @@ function prepareWorkItems(input) {
|
|
|
82
66
|
resolvedLookup.set(key, resolved);
|
|
83
67
|
}
|
|
84
68
|
const { items, uncategorized } = ApiItems.categorize(docItems, categories);
|
|
85
|
-
for (const skipped of uncategorized)
|
|
86
|
-
ctx: { buildId:
|
|
69
|
+
for (const skipped of uncategorized) emitSync(PluginEvent.ItemSkipped({
|
|
70
|
+
ctx: { buildId: syncBuildId() },
|
|
87
71
|
item: skipped.displayName,
|
|
88
72
|
kind: String(skipped.kind),
|
|
89
73
|
reason: "uncategorized",
|
|
@@ -115,9 +99,9 @@ function prepareWorkItems(input) {
|
|
|
115
99
|
const collisions = Routes.detectCollisions(candidates);
|
|
116
100
|
if (collisions.length > 0) {
|
|
117
101
|
try {
|
|
118
|
-
for (const collision of collisions)
|
|
102
|
+
for (const collision of collisions) emitSync(PluginEvent.RouteCollisionDetected({
|
|
119
103
|
ctx: {
|
|
120
|
-
buildId:
|
|
104
|
+
buildId: syncBuildId(),
|
|
121
105
|
route: collision.route
|
|
122
106
|
},
|
|
123
107
|
level: "error",
|
|
@@ -145,13 +129,14 @@ function prepareWorkItems(input) {
|
|
|
145
129
|
}
|
|
146
130
|
if (item.kind === "Class" || item.kind === "Interface") {
|
|
147
131
|
const itemWithMembers = item;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
132
|
+
const anchors = ApiItems.memberAnchors(itemWithMembers);
|
|
133
|
+
const byCanonicalRef = new Map(itemWithMembers.members.map((member) => [member.canonicalReference?.toString() ?? member.displayName, member]));
|
|
134
|
+
for (const [routeKey, memberId] of ApiItems.memberRouteKeys(itemWithMembers)) {
|
|
135
|
+
const member = byCanonicalRef.get(memberId);
|
|
136
|
+
if (!member) continue;
|
|
137
|
+
const anchor = anchors.get(memberId) ?? Routes.memberAnchor(member.displayName);
|
|
138
|
+
routes.set(routeKey, `${itemRoute}#${anchor}`);
|
|
139
|
+
kinds.set(routeKey, member.kind);
|
|
155
140
|
}
|
|
156
141
|
}
|
|
157
142
|
}
|
|
@@ -190,12 +175,14 @@ function prepareWorkItems(input) {
|
|
|
190
175
|
const lookupKey = `${item.displayName}::${item.kind}`;
|
|
191
176
|
const resolved = resolvedLookup.get(lookupKey);
|
|
192
177
|
const syntheticBase = syntheticBases.baseByOwner.get(item);
|
|
178
|
+
const memberAnchors = item.kind === "Class" || item.kind === "Interface" ? ApiItems.memberAnchors(item) : void 0;
|
|
193
179
|
workItems.push({
|
|
194
180
|
item,
|
|
195
181
|
categoryKey,
|
|
196
182
|
categoryConfig,
|
|
197
183
|
...resolved?.availableFrom != null ? { availableFrom: resolved.availableFrom } : {},
|
|
198
|
-
...syntheticBase != null ? { syntheticBase } : {}
|
|
184
|
+
...syntheticBase != null ? { syntheticBase } : {},
|
|
185
|
+
...memberAnchors != null ? { memberAnchors } : {}
|
|
199
186
|
});
|
|
200
187
|
}
|
|
201
188
|
}
|
|
@@ -240,7 +227,7 @@ function generateSinglePage(workItem, ctx) {
|
|
|
240
227
|
switch (item.kind) {
|
|
241
228
|
case ApiItemKind.Class: {
|
|
242
229
|
const generator = new ClassPageGenerator();
|
|
243
|
-
page = yield* Effect.promise(() => generator.generate(item, baseRoute, packageName, categoryConfig.singularName, apiScope, apiName, source, suppressExampleErrors, llmsPlugin, workItem.availableFrom, workItem.syntheticBase));
|
|
230
|
+
page = yield* Effect.promise(() => generator.generate(item, baseRoute, packageName, categoryConfig.singularName, apiScope, apiName, source, suppressExampleErrors, llmsPlugin, workItem.availableFrom, workItem.syntheticBase, workItem.memberAnchors));
|
|
244
231
|
page = {
|
|
245
232
|
routePath: page.routePath.replace("/class/", `/${categoryConfig.folderName}/`),
|
|
246
233
|
content: page.content
|
|
@@ -402,7 +389,7 @@ function generateSinglePage(workItem, ctx) {
|
|
|
402
389
|
function writeSingleFile(result, ctx) {
|
|
403
390
|
return Effect.gen(function* () {
|
|
404
391
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
405
|
-
const { buildId, resolvedOutputDir, buildTime,
|
|
392
|
+
const { buildId, resolvedOutputDir, buildTime, siteUrl, docsRoot, ogImage, packageName, apiName } = ctx;
|
|
406
393
|
const { workItem, bodyContent, frontmatter, contentHash, frontmatterHash, publishedTime, modifiedTime, isUnchanged, routePath, relativePathWithExt } = result;
|
|
407
394
|
const { item, categoryKey, categoryConfig, namespaceMember } = workItem;
|
|
408
395
|
const absolutePath = path.join(resolvedOutputDir, relativePathWithExt);
|
|
@@ -440,8 +427,29 @@ function writeSingleFile(result, ctx) {
|
|
|
440
427
|
};
|
|
441
428
|
}
|
|
442
429
|
let finalContent = stringifyFrontmatter(bodyContent, frontmatter);
|
|
443
|
-
if (
|
|
444
|
-
const
|
|
430
|
+
if (siteUrl && packageName) {
|
|
431
|
+
const ogSvc = yield* OgService;
|
|
432
|
+
const ogImageResult = yield* Effect.result(ogSvc.resolveImage({
|
|
433
|
+
config: ogImage,
|
|
434
|
+
siteUrl,
|
|
435
|
+
docsRoot,
|
|
436
|
+
packageName,
|
|
437
|
+
...apiName != null ? { apiName } : {}
|
|
438
|
+
}));
|
|
439
|
+
if (ogImageResult._tag === "Failure") {
|
|
440
|
+
const failure = ogImageResult.failure;
|
|
441
|
+
yield* emit(PluginEvent.ConfigValidationWarning({
|
|
442
|
+
ctx: {
|
|
443
|
+
buildId,
|
|
444
|
+
packageName
|
|
445
|
+
},
|
|
446
|
+
field: failure.field,
|
|
447
|
+
value: failure.value,
|
|
448
|
+
reason: failure.message,
|
|
449
|
+
level: "warn"
|
|
450
|
+
}));
|
|
451
|
+
}
|
|
452
|
+
const ogImageMetadata = ogImageResult._tag === "Success" && Option.isSome(ogImageResult.success) ? ogImageResult.success.value : void 0;
|
|
445
453
|
const ogMetadataOptions = {
|
|
446
454
|
siteUrl,
|
|
447
455
|
pageRoute: routePath,
|
|
@@ -452,7 +460,7 @@ function writeSingleFile(result, ctx) {
|
|
|
452
460
|
packageName
|
|
453
461
|
};
|
|
454
462
|
if (ogImageMetadata) ogMetadataOptions.ogImage = ogImageMetadata;
|
|
455
|
-
const ogMetadata =
|
|
463
|
+
const ogMetadata = createPageMetadata(ogMetadataOptions);
|
|
456
464
|
finalContent = generateFrontmatter(item.displayName, frontmatter.description, categoryConfig.singularName, apiName, ogMetadata) + bodyContent;
|
|
457
465
|
}
|
|
458
466
|
const fileExisted = yield* fileSystem.exists(absolutePath).pipe(Effect.orElseSucceed(() => false));
|
|
@@ -793,7 +801,7 @@ function buildPipelineForApi(input) {
|
|
|
793
801
|
buildId: input.buildId,
|
|
794
802
|
resolvedOutputDir: input.resolvedOutputDir,
|
|
795
803
|
buildTime: input.buildTime,
|
|
796
|
-
...input.
|
|
804
|
+
...input.docsRoot !== void 0 ? { docsRoot: input.docsRoot } : {},
|
|
797
805
|
...input.siteUrl != null ? { siteUrl: input.siteUrl } : {},
|
|
798
806
|
...input.ogImage != null ? { ogImage: input.ogImage } : {},
|
|
799
807
|
...input.packageName != null ? { packageName: input.packageName } : {},
|
|
@@ -803,4 +811,4 @@ function buildPipelineForApi(input) {
|
|
|
803
811
|
}
|
|
804
812
|
|
|
805
813
|
//#endregion
|
|
806
|
-
export { buildPipelineForApi, cleanupAndCommit, crossLinkKindPriority, generateSinglePage,
|
|
814
|
+
export { buildPipelineForApi, cleanupAndCommit, crossLinkKindPriority, generateSinglePage, prepareWorkItems, writeMetadata, writeSingleFile };
|
package/errors.js
CHANGED
|
@@ -8,7 +8,6 @@ var ConfigValidationError = class extends ConfigValidationErrorBase {
|
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
10
|
const ApiModelLoadErrorBase = Data.TaggedError("ApiModelLoadError");
|
|
11
|
-
const PathDerivationErrorBase = Data.TaggedError("PathDerivationError");
|
|
12
11
|
const TypeRegistryErrorBase = Data.TaggedError("TypeRegistryError");
|
|
13
12
|
var TypeRegistryError = class extends TypeRegistryErrorBase {
|
|
14
13
|
get message() {
|
package/index.d.ts
CHANGED
|
@@ -390,15 +390,19 @@ declare const MultiApiConfig: Schema.Struct<{
|
|
|
390
390
|
* Path to a `tsconfig.json` for Twoslash.
|
|
391
391
|
*
|
|
392
392
|
* @remarks
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
* configured tsconfigs are equivalent, or set the intended one on the
|
|
398
|
-
* first API only.
|
|
393
|
+
* This API's code blocks are type-checked under this config. APIs that
|
|
394
|
+
* declare the same config share one TypeScript environment; the file set
|
|
395
|
+
* is shared across all documented APIs either way, so a type owned by
|
|
396
|
+
* another documented package still resolves.
|
|
399
397
|
*/
|
|
400
398
|
readonly tsconfig: Schema.optional<Schema.declare<string | URL | ((...args: Array<unknown>) => unknown), string | URL | ((...args: Array<unknown>) => unknown)>>;
|
|
401
|
-
/**
|
|
399
|
+
/**
|
|
400
|
+
* TypeScript compiler options for Twoslash, applying to this API only.
|
|
401
|
+
*
|
|
402
|
+
* @remarks
|
|
403
|
+
* Merged on top of the defaults and of this API's `tsconfig`, so declaring
|
|
404
|
+
* a single option overrides just that one.
|
|
405
|
+
*/
|
|
402
406
|
readonly compilerOptions: Schema.optional<Schema.Unknown>;
|
|
403
407
|
}>;
|
|
404
408
|
/** @public */
|
|
@@ -650,15 +654,19 @@ declare const PluginOptions: Schema.Struct<{
|
|
|
650
654
|
* Path to a `tsconfig.json` for Twoslash.
|
|
651
655
|
*
|
|
652
656
|
* @remarks
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
* configured tsconfigs are equivalent, or set the intended one on the
|
|
658
|
-
* first API only.
|
|
657
|
+
* This API's code blocks are type-checked under this config. APIs that
|
|
658
|
+
* declare the same config share one TypeScript environment; the file set
|
|
659
|
+
* is shared across all documented APIs either way, so a type owned by
|
|
660
|
+
* another documented package still resolves.
|
|
659
661
|
*/
|
|
660
662
|
readonly tsconfig: Schema.optional<Schema.declare<string | URL | ((...args: Array<unknown>) => unknown), string | URL | ((...args: Array<unknown>) => unknown)>>;
|
|
661
|
-
/**
|
|
663
|
+
/**
|
|
664
|
+
* TypeScript compiler options for Twoslash, applying to this API only.
|
|
665
|
+
*
|
|
666
|
+
* @remarks
|
|
667
|
+
* Merged on top of the defaults and of this API's `tsconfig`, so declaring
|
|
668
|
+
* a single option overrides just that one.
|
|
669
|
+
*/
|
|
662
670
|
readonly compilerOptions: Schema.optional<Schema.Unknown>;
|
|
663
671
|
}>>>>>;
|
|
664
672
|
/** Canonical site URL used for Open Graph absolute URLs. */
|