rspress-plugin-api-extractor 0.8.8 → 0.9.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/README.md +11 -11
- package/api-extracted-package.js +1 -1
- package/build-program.js +3 -3
- package/build-stages.js +30 -31
- package/config-helpers.js +61 -21
- package/errors.js +1 -7
- package/frontmatter.js +149 -0
- package/index.d.ts +11 -2
- package/layers/ConfigServiceLive.js +53 -39
- package/layers/TypeRegistryServiceLive.js +11 -6
- package/markdown/helpers.js +40 -69
- package/markdown/index.js +2 -2
- package/markdown/page-generators/class-page.js +40 -42
- package/markdown/page-generators/enum-page.js +15 -15
- package/markdown/page-generators/function-page.js +18 -20
- package/markdown/page-generators/interface-page.js +41 -43
- package/markdown/page-generators/namespace-page.js +22 -24
- package/markdown/page-generators/type-alias-page.js +14 -16
- package/markdown/page-generators/variable-page.js +14 -16
- package/markdown/prose-linker.js +22 -0
- package/model-loader.js +59 -113
- package/package.json +14 -8
- package/plugin.js +1 -5
- package/runtime/components/EnumMembersTable/index.css +18 -18
- package/runtime/components/EnumMembersTable/index.module.js +3 -3
- package/runtime/components/ExampleBlock/index.css +2 -2
- package/runtime/components/ExampleBlock/index.module.js +2 -2
- package/runtime/components/MemberSignature/index.css +6 -6
- package/runtime/components/MemberSignature/index.module.js +4 -4
- package/runtime/components/ParametersTable/index.css +19 -19
- package/runtime/components/ParametersTable/index.module.js +3 -3
- package/runtime/components/SignatureBlock/index.css +6 -6
- package/runtime/components/SignatureBlock/index.module.js +4 -4
- package/runtime/components/SignatureCode/index.css +9 -9
- package/runtime/components/SignatureCode/index.module.js +3 -3
- package/runtime/components/SignatureToolbar/index.css +18 -18
- package/runtime/components/SignatureToolbar/index.module.js +7 -7
- package/runtime/components/buttons/index.css +5 -5
- package/runtime/components/buttons/index.module.js +2 -2
- package/shiki-transformer.js +3 -3
- package/sync-node-fs.js +80 -0
- package/tsdoc-metadata.json +1 -1
- package/twoslash-transformer.js +1 -1
- package/content-hash.js +0 -79
- package/formatter.js +0 -69
- package/layers/SnapshotServiceLive.js +0 -92
- package/loader.js +0 -200
- package/markdown/cross-linker.js +0 -157
- package/migrations/001_create_snapshots.js +0 -25
- package/multi-entry-resolver.js +0 -70
- package/route-collisions.js +0 -44
- package/services/SnapshotService.js +0 -7
- package/synthetic-bases.js +0 -74
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ApiParser } from "../../loader.js";
|
|
2
1
|
import { TypeReferenceExtractor } from "../../type-reference-extractor.js";
|
|
3
2
|
import { escapeMdxGenerics, formatExampleCode, generateAvailableFrom, generateFrontmatter, prepareExampleCode, prependHiddenImports, stripTwoslashDirectives } from "../helpers.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { linkProse } from "../prose-linker.js";
|
|
4
|
+
import { ApiItems, Signature, Tsdoc } from "@tsdoctor/model";
|
|
6
5
|
|
|
7
6
|
//#region src/markdown/page-generators/type-alias-page.ts
|
|
8
7
|
/**
|
|
@@ -23,15 +22,14 @@ import { TypeSignatureFormatter } from "../../formatter.js";
|
|
|
23
22
|
*
|
|
24
23
|
* **Relationships:**
|
|
25
24
|
* - Created and invoked by {@link ApiExtractorPlugin} during page generation
|
|
26
|
-
* - Uses
|
|
27
|
-
* - Uses
|
|
28
|
-
* - Uses
|
|
25
|
+
* - Uses `Signature.format` from `@tsdoctor/model` for formatting type signatures
|
|
26
|
+
* - Uses the `Tsdoc` / `ApiItems` modules from `@tsdoctor/model` for extracting documentation
|
|
27
|
+
* - Uses the per-build prose linker (`linkProse`) for adding type reference links
|
|
29
28
|
*
|
|
30
29
|
* @see {@link InterfacePageGenerator} for interface documentation
|
|
31
30
|
* @see {@link EnumPageGenerator} for enum documentation
|
|
32
31
|
*/
|
|
33
32
|
var TypeAliasPageGenerator = class {
|
|
34
|
-
typeFormatter = new TypeSignatureFormatter();
|
|
35
33
|
/**
|
|
36
34
|
* Generate a markdown page for a type alias
|
|
37
35
|
*
|
|
@@ -40,22 +38,22 @@ var TypeAliasPageGenerator = class {
|
|
|
40
38
|
async generate(apiTypeAlias, baseRoute, packageName, singularName, apiScope, apiName, sourceConfig, suppressExampleErrors, llmsPlugin, availableFrom) {
|
|
41
39
|
const shouldSuppressErrors = suppressExampleErrors ?? true;
|
|
42
40
|
const name = apiTypeAlias.displayName;
|
|
43
|
-
const summary =
|
|
44
|
-
const releaseTag =
|
|
41
|
+
const summary = Tsdoc.summary(apiTypeAlias) || "No description available.";
|
|
42
|
+
const releaseTag = Tsdoc.releaseTag(apiTypeAlias);
|
|
45
43
|
let content = generateFrontmatter(name, summary, singularName, apiName);
|
|
46
44
|
content += `import { SourceCode } from "@rspress/core/theme";\n`;
|
|
47
45
|
content += `import { ParametersTable } from "rspress-plugin-api-extractor/runtime";\n`;
|
|
48
46
|
content += `import { ApiSignature, ApiExample } from "rspress-plugin-api-extractor/runtime";\n\n`;
|
|
49
47
|
content += `# ${name}\n\n`;
|
|
50
|
-
const deprecation =
|
|
48
|
+
const deprecation = Tsdoc.deprecation(apiTypeAlias);
|
|
51
49
|
if (deprecation) {
|
|
52
|
-
const message = escapeMdxGenerics(
|
|
50
|
+
const message = escapeMdxGenerics(linkProse(deprecation.message));
|
|
53
51
|
content += `> ⚠️ **Deprecated:** ${message}\n\n`;
|
|
54
52
|
}
|
|
55
53
|
if (releaseTag !== "Public") content += `\`${releaseTag}\`\n\n`;
|
|
56
54
|
content += `${summary}\n\n`;
|
|
57
55
|
content += generateAvailableFrom(packageName, availableFrom);
|
|
58
|
-
const sourceLink =
|
|
56
|
+
const sourceLink = ApiItems.sourceLink(apiTypeAlias, sourceConfig);
|
|
59
57
|
if (sourceLink) {
|
|
60
58
|
content += `<div className="api-docs-toolbar">\n`;
|
|
61
59
|
content += ` <div className="api-docs-toolbar-left">\n`;
|
|
@@ -68,7 +66,7 @@ var TypeAliasPageGenerator = class {
|
|
|
68
66
|
content += `</div>\n\n`;
|
|
69
67
|
}
|
|
70
68
|
if (apiTypeAlias.excerpt.text) {
|
|
71
|
-
const signature =
|
|
69
|
+
const signature = Signature.format(apiTypeAlias.excerpt).trim();
|
|
72
70
|
let signatureWithImports = signature;
|
|
73
71
|
const apiPackage = apiTypeAlias.getAssociatedPackage?.();
|
|
74
72
|
if (apiPackage) {
|
|
@@ -78,7 +76,7 @@ var TypeAliasPageGenerator = class {
|
|
|
78
76
|
const displayCode = stripTwoslashDirectives(signatureWithImports);
|
|
79
77
|
content += `<ApiSignature code={${JSON.stringify(displayCode)}} source={${JSON.stringify(signatureWithImports)}} apiScope={${JSON.stringify(apiScope)}} />\n\n`;
|
|
80
78
|
}
|
|
81
|
-
const examples =
|
|
79
|
+
const examples = Tsdoc.examples(apiTypeAlias);
|
|
82
80
|
if (examples.length > 0) {
|
|
83
81
|
content += `## Examples\n\n`;
|
|
84
82
|
for (const example of examples) {
|
|
@@ -93,11 +91,11 @@ var TypeAliasPageGenerator = class {
|
|
|
93
91
|
} else content += `\`\`\`${prepared.language}\n${formattedCode}\n\`\`\`\n\n`;
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
|
-
const seeReferences =
|
|
94
|
+
const seeReferences = Tsdoc.seeReferences(apiTypeAlias);
|
|
97
95
|
if (seeReferences.length > 0) {
|
|
98
96
|
content += `## See Also\n\n`;
|
|
99
97
|
for (const reference of seeReferences) {
|
|
100
|
-
const refText = escapeMdxGenerics(
|
|
98
|
+
const refText = escapeMdxGenerics(linkProse(reference.text));
|
|
101
99
|
content += `- ${refText}\n`;
|
|
102
100
|
}
|
|
103
101
|
content += `\n`;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ApiParser } from "../../loader.js";
|
|
2
1
|
import { TypeReferenceExtractor } from "../../type-reference-extractor.js";
|
|
3
2
|
import { escapeMdxGenerics, formatExampleCode, generateAvailableFrom, generateFrontmatter, prepareExampleCode, prependHiddenImports, stripTwoslashDirectives } from "../helpers.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { linkProse } from "../prose-linker.js";
|
|
4
|
+
import { ApiItems, Signature, Tsdoc } from "@tsdoctor/model";
|
|
6
5
|
|
|
7
6
|
//#region src/markdown/page-generators/variable-page.ts
|
|
8
7
|
/**
|
|
@@ -23,15 +22,14 @@ import { TypeSignatureFormatter } from "../../formatter.js";
|
|
|
23
22
|
*
|
|
24
23
|
* **Relationships:**
|
|
25
24
|
* - Created and invoked by {@link ApiExtractorPlugin} during page generation
|
|
26
|
-
* - Uses
|
|
27
|
-
* - Uses
|
|
28
|
-
* - Uses
|
|
25
|
+
* - Uses `Signature.format` from `@tsdoctor/model` for formatting type signatures
|
|
26
|
+
* - Uses the `Tsdoc` / `ApiItems` modules from `@tsdoctor/model` for extracting documentation
|
|
27
|
+
* - Uses the per-build prose linker (`linkProse`) for adding type reference links
|
|
29
28
|
*
|
|
30
29
|
* @see {@link FunctionPageGenerator} for function documentation
|
|
31
30
|
* @see {@link EnumPageGenerator} for enum documentation
|
|
32
31
|
*/
|
|
33
32
|
var VariablePageGenerator = class {
|
|
34
|
-
typeFormatter = new TypeSignatureFormatter();
|
|
35
33
|
/**
|
|
36
34
|
* Generate a markdown page for a variable
|
|
37
35
|
*
|
|
@@ -40,22 +38,22 @@ var VariablePageGenerator = class {
|
|
|
40
38
|
async generate(apiVariable, baseRoute, packageName, singularName, apiScope, apiName, sourceConfig, suppressExampleErrors, llmsPlugin, availableFrom) {
|
|
41
39
|
const shouldSuppressErrors = suppressExampleErrors ?? true;
|
|
42
40
|
const name = apiVariable.displayName;
|
|
43
|
-
const summary =
|
|
44
|
-
const releaseTag =
|
|
41
|
+
const summary = Tsdoc.summary(apiVariable) || "No description available.";
|
|
42
|
+
const releaseTag = Tsdoc.releaseTag(apiVariable);
|
|
45
43
|
let content = generateFrontmatter(name, summary, singularName, apiName);
|
|
46
44
|
content += `import { SourceCode } from "@rspress/core/theme";\n`;
|
|
47
45
|
content += `import { ParametersTable } from "rspress-plugin-api-extractor/runtime";\n`;
|
|
48
46
|
content += `import { ApiSignature, ApiExample } from "rspress-plugin-api-extractor/runtime";\n\n`;
|
|
49
47
|
content += `# ${name}\n\n`;
|
|
50
|
-
const deprecation =
|
|
48
|
+
const deprecation = Tsdoc.deprecation(apiVariable);
|
|
51
49
|
if (deprecation) {
|
|
52
|
-
const message = escapeMdxGenerics(
|
|
50
|
+
const message = escapeMdxGenerics(linkProse(deprecation.message));
|
|
53
51
|
content += `> ⚠️ **Deprecated:** ${message}\n\n`;
|
|
54
52
|
}
|
|
55
53
|
if (releaseTag !== "Public") content += `\`${releaseTag}\`\n\n`;
|
|
56
54
|
content += `${summary}\n\n`;
|
|
57
55
|
content += generateAvailableFrom(packageName, availableFrom);
|
|
58
|
-
const sourceLink =
|
|
56
|
+
const sourceLink = ApiItems.sourceLink(apiVariable, sourceConfig);
|
|
59
57
|
if (sourceLink) {
|
|
60
58
|
content += `<div className="api-docs-toolbar">\n`;
|
|
61
59
|
content += ` <div className="api-docs-toolbar-left">\n`;
|
|
@@ -68,7 +66,7 @@ var VariablePageGenerator = class {
|
|
|
68
66
|
content += `</div>\n\n`;
|
|
69
67
|
}
|
|
70
68
|
if (apiVariable.excerpt.text) {
|
|
71
|
-
const signature =
|
|
69
|
+
const signature = Signature.format(apiVariable.excerpt).trim();
|
|
72
70
|
let signatureWithImports = signature;
|
|
73
71
|
const apiPackage = apiVariable.getAssociatedPackage?.();
|
|
74
72
|
if (apiPackage) {
|
|
@@ -78,7 +76,7 @@ var VariablePageGenerator = class {
|
|
|
78
76
|
const displayCode = stripTwoslashDirectives(signatureWithImports);
|
|
79
77
|
content += `<ApiSignature code={${JSON.stringify(displayCode)}} source={${JSON.stringify(signatureWithImports)}} apiScope={${JSON.stringify(apiScope)}} />\n\n`;
|
|
80
78
|
}
|
|
81
|
-
const examples =
|
|
79
|
+
const examples = Tsdoc.examples(apiVariable);
|
|
82
80
|
if (examples.length > 0) {
|
|
83
81
|
content += `## Examples\n\n`;
|
|
84
82
|
for (const example of examples) {
|
|
@@ -93,11 +91,11 @@ var VariablePageGenerator = class {
|
|
|
93
91
|
} else content += `\`\`\`${prepared.language}\n${formattedCode}\n\`\`\`\n\n`;
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
|
-
const seeReferences =
|
|
94
|
+
const seeReferences = Tsdoc.seeReferences(apiVariable);
|
|
97
95
|
if (seeReferences.length > 0) {
|
|
98
96
|
content += `## See Also\n\n`;
|
|
99
97
|
for (const reference of seeReferences) {
|
|
100
|
-
const refText = escapeMdxGenerics(
|
|
98
|
+
const refText = escapeMdxGenerics(linkProse(reference.text));
|
|
101
99
|
content += `- ${refText}\n`;
|
|
102
100
|
}
|
|
103
101
|
content += `\n`;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CrossLinker } from "@tsdoctor/model";
|
|
2
|
+
|
|
3
|
+
//#region src/markdown/prose-linker.ts
|
|
4
|
+
/**
|
|
5
|
+
* Per-build prose cross-linker holder. Adapter wiring, not logic: the build
|
|
6
|
+
* program installs the immutable `@tsdoctor/model` CrossLinker built from the
|
|
7
|
+
* routes `prepareWorkItems` computed, and page generators link prose through
|
|
8
|
+
* it. Page generators run synchronously outside any service context, hence
|
|
9
|
+
* the module-level holder (the same shape as the sync-island event emitters).
|
|
10
|
+
*/
|
|
11
|
+
let current = CrossLinker.empty;
|
|
12
|
+
/** Install the cross-linker for the current API build from its route map. */
|
|
13
|
+
function setProseLinker(routes) {
|
|
14
|
+
current = CrossLinker.fromRoutes(routes);
|
|
15
|
+
}
|
|
16
|
+
/** Cross-link prose text with the currently installed linker. */
|
|
17
|
+
function linkProse(text) {
|
|
18
|
+
return current.link(text);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { linkProse, setProseLinker };
|
package/model-loader.js
CHANGED
|
@@ -1,128 +1,74 @@
|
|
|
1
|
-
import { PluginEvent } from "./observability/events.js";
|
|
2
1
|
import { isLoadedModel, isVersionConfig } from "./config-utils.js";
|
|
3
2
|
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
|
-
import {
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { Model } from "@tsdoctor/model";
|
|
6
6
|
|
|
7
7
|
//#region src/model-loader.ts
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* `Effect.promise(async () => {...})` body in `ConfigServiceLive.ts`, so a
|
|
11
|
-
* load failure cannot `yield* emit(...)` — it mirrors the sync-island pattern
|
|
12
|
-
* used by `twoslash-transformer.ts` (`setEventEmitter`) and `loader.ts`
|
|
13
|
-
* (`setLoaderEventEmitter`, a DIFFERENT module — the ApiParser/TSDoc statics,
|
|
14
|
-
* not this one). Default is a no-op; wired in plugin.ts via
|
|
15
|
-
* `setModelLoaderEventEmitter(emitSync, buildId)` right after the runtime
|
|
16
|
-
* emitter is created.
|
|
9
|
+
* Load package.json from a path (string, URL, or Buffer).
|
|
17
10
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
async function loadPackageJsonFromPath(pkgPath) {
|
|
12
|
+
const resolvedPath = path.resolve(pkgPath.toString());
|
|
13
|
+
if (!fs.existsSync(resolvedPath)) throw new Error(`Package.json file not found: ${resolvedPath}`);
|
|
14
|
+
const content = fs.readFileSync(resolvedPath, "utf-8");
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(content);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
throw new Error(`Failed to parse package.json at ${resolvedPath}: ${error.message}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
* Call this right after `makeRuntimeEmitter` in plugin.ts.
|
|
22
|
+
* Load package.json from PathLike or async function.
|
|
23
23
|
*/
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
async function loadPackageJson(loader) {
|
|
25
|
+
if (typeof loader === "function") return await loader();
|
|
26
|
+
return await loadPackageJsonFromPath(loader);
|
|
27
27
|
}
|
|
28
|
+
/** Extract the first package from a user-loader result (ApiModel-shaped object). */
|
|
29
|
+
const packageFromLoaderResult = (result) => {
|
|
30
|
+
if (result && typeof result === "object" && "packages" in result) return Model.firstPackage(result).pipe(Effect.mapError(() => new Model.EmptyModelError({ reason: "API model returned by function contains no packages" })));
|
|
31
|
+
return Effect.fail(new Model.EmptyModelError({ reason: "API model loader function must return an ApiModel" }));
|
|
32
|
+
};
|
|
28
33
|
/**
|
|
29
|
-
*
|
|
34
|
+
* Load an API model from a PathLike (via `Model.load`, typed errors) or a
|
|
35
|
+
* user-supplied async loader function (ApiModel or LoadedModel result).
|
|
30
36
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
if (!fs.existsSync(resolvedPath)) throw new Error(`API model file not found: ${resolvedPath}`);
|
|
43
|
-
return await loadApiModel(resolvedPath);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
try {
|
|
46
|
-
emitEvent(PluginEvent.ModelLoadFailed({
|
|
47
|
-
ctx: { buildId: currentBuildId },
|
|
48
|
-
level: "error",
|
|
49
|
-
modelPath: resolvedPath,
|
|
50
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
51
|
-
}));
|
|
52
|
-
} catch {}
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Load package.json from a path (string, URL, or Buffer)
|
|
58
|
-
*/
|
|
59
|
-
static async loadPackageJsonFromPath(pkgPath) {
|
|
60
|
-
const resolvedPath = path.resolve(pkgPath.toString());
|
|
61
|
-
if (!fs.existsSync(resolvedPath)) throw new Error(`Package.json file not found: ${resolvedPath}`);
|
|
62
|
-
const content = fs.readFileSync(resolvedPath, "utf-8");
|
|
63
|
-
try {
|
|
64
|
-
return JSON.parse(content);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
throw new Error(`Failed to parse package.json at ${resolvedPath}: ${error.message}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Load package.json from PathLike or async function
|
|
71
|
-
*/
|
|
72
|
-
static async loadPackageJson(loader) {
|
|
73
|
-
if (typeof loader === "function") return await loader();
|
|
74
|
-
return await ApiModelLoader.loadPackageJsonFromPath(loader);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Load an API model from PathLike or async function
|
|
78
|
-
*/
|
|
79
|
-
static async loadApiModel(loader) {
|
|
80
|
-
if (typeof loader === "function") {
|
|
81
|
-
const result = await loader();
|
|
82
|
-
if (isLoadedModel(result)) {
|
|
83
|
-
const model = result.model;
|
|
84
|
-
if (model && typeof model === "object" && "packages" in model) {
|
|
85
|
-
const packages = model.packages;
|
|
86
|
-
if (packages.length === 0) throw new Error("API model returned by function contains no packages");
|
|
87
|
-
const loadedResult = { apiPackage: packages[0] };
|
|
88
|
-
if (result.source != null) loadedResult.source = result.source;
|
|
89
|
-
return loadedResult;
|
|
90
|
-
}
|
|
91
|
-
throw new Error("API model loader function must return an ApiModel");
|
|
92
|
-
}
|
|
93
|
-
if (result && typeof result === "object" && "packages" in result) {
|
|
94
|
-
const packages = result.packages;
|
|
95
|
-
if (packages.length === 0) throw new Error("API model returned by function contains no packages");
|
|
96
|
-
return { apiPackage: packages[0] };
|
|
97
|
-
}
|
|
98
|
-
throw new Error("API model loader function must return an ApiModel or LoadedModel");
|
|
37
|
+
function loadApiModel(loader) {
|
|
38
|
+
if (typeof loader !== "function") return Model.load(loader.toString()).pipe(Effect.map((apiPackage) => ({ apiPackage })));
|
|
39
|
+
return Effect.gen(function* () {
|
|
40
|
+
const result = yield* Effect.promise(() => loader());
|
|
41
|
+
if (isLoadedModel(result)) {
|
|
42
|
+
const apiPackage = yield* packageFromLoaderResult(result.model);
|
|
43
|
+
return result.source != null ? {
|
|
44
|
+
apiPackage,
|
|
45
|
+
source: result.source
|
|
46
|
+
} : { apiPackage };
|
|
99
47
|
}
|
|
100
|
-
return { apiPackage:
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
};
|
|
48
|
+
return { apiPackage: yield* packageFromLoaderResult(result) };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve and load a version config (full VersionConfig, or a bare model
|
|
53
|
+
* path/loader).
|
|
54
|
+
*/
|
|
55
|
+
function loadVersionModel(versionValue) {
|
|
56
|
+
if (!isVersionConfig(versionValue)) return loadApiModel(versionValue);
|
|
57
|
+
return Effect.gen(function* () {
|
|
58
|
+
const { apiPackage, source: loaderSource } = yield* loadApiModel(versionValue.model);
|
|
59
|
+
const packageJson = versionValue.packageJson ? yield* Effect.promise(() => loadPackageJson(versionValue.packageJson)) : void 0;
|
|
60
|
+
const versionResult = { apiPackage };
|
|
61
|
+
if (packageJson != null) versionResult.packageJson = packageJson;
|
|
62
|
+
if (versionValue.categories != null) versionResult.categories = versionValue.categories;
|
|
63
|
+
const resolvedSource = loaderSource || versionValue.source;
|
|
64
|
+
if (resolvedSource != null) versionResult.source = resolvedSource;
|
|
65
|
+
if (versionValue.externalPackages != null) versionResult.externalPackages = versionValue.externalPackages;
|
|
66
|
+
if (versionValue.autoDetectDependencies != null) versionResult.autoDetectDependencies = versionValue.autoDetectDependencies;
|
|
67
|
+
if (versionValue.ogImage != null) versionResult.ogImage = versionValue.ogImage;
|
|
68
|
+
if (versionValue.llmsPlugin != null) versionResult.llmsPlugin = versionValue.llmsPlugin;
|
|
69
|
+
return versionResult;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
126
72
|
|
|
127
73
|
//#endregion
|
|
128
|
-
export {
|
|
74
|
+
export { loadApiModel, loadPackageJson, loadVersionModel };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rspress-plugin-api-extractor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "RSPress plugin for generating API documentation from TypeScript API Extractor models",
|
|
6
6
|
"keywords": [
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"documentation",
|
|
11
11
|
"typescript"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://github.com/spencerbeggs/
|
|
13
|
+
"homepage": "https://github.com/spencerbeggs/tsdoctor#readme",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/spencerbeggs/
|
|
17
|
-
"directory": "
|
|
16
|
+
"url": "git+https://github.com/spencerbeggs/tsdoctor.git",
|
|
17
|
+
"directory": "platforms/rspress"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "Spencer Beggs",
|
|
@@ -38,18 +38,25 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@effect/platform-node": "4.0.0-rc.109",
|
|
41
|
-
"@
|
|
41
|
+
"@effected/github": "^0.8.0",
|
|
42
|
+
"@effected/glob": "^0.4.0",
|
|
43
|
+
"@effected/npm": "^0.12.0",
|
|
44
|
+
"@effected/package-json": "^0.11.0",
|
|
42
45
|
"@effected/semver": "^0.5.0",
|
|
43
46
|
"@effected/store": "^0.4.0",
|
|
44
47
|
"@effected/tsconfig-json": "^0.6.0",
|
|
48
|
+
"@effected/walker": "^0.5.0",
|
|
45
49
|
"@effected/xdg": "^0.3.0",
|
|
50
|
+
"@effected/yaml": "^0.11.0",
|
|
46
51
|
"@microsoft/api-extractor-model": "^7.33.11",
|
|
47
52
|
"@shikijs/twoslash": "^4.4.3",
|
|
53
|
+
"@tsdoctor/bundle": "0.1.0",
|
|
54
|
+
"@tsdoctor/model": "0.2.0",
|
|
55
|
+
"@tsdoctor/registry": "0.2.0",
|
|
56
|
+
"@tsdoctor/snapshot": "0.1.0",
|
|
48
57
|
"@typescript/vfs": "^1.6.4",
|
|
49
|
-
"api-extractor-llms": "^0.2.0",
|
|
50
58
|
"clsx": "^2.1.1",
|
|
51
59
|
"effect": "4.0.0-rc.109",
|
|
52
|
-
"gray-matter": "^4.0.3",
|
|
53
60
|
"hast-util-to-jsx-runtime": "^2.3.6",
|
|
54
61
|
"image-size": "^2.0.2",
|
|
55
62
|
"ioredis": "^5.7.0",
|
|
@@ -59,7 +66,6 @@
|
|
|
59
66
|
"prettier": "^3.9.6",
|
|
60
67
|
"react-markdown": "^10.1.0",
|
|
61
68
|
"shiki": "^4.4.3",
|
|
62
|
-
"type-registry-effect": "^2.3.5",
|
|
63
69
|
"typescript": "^6.0.3",
|
|
64
70
|
"unist-util-visit": "^5.1.0"
|
|
65
71
|
},
|
package/plugin.js
CHANGED
|
@@ -3,7 +3,6 @@ import { emit, makeRuntimeEmitter } from "./observability/EventBus.js";
|
|
|
3
3
|
import { runHeartbeat } from "./observability/heartbeat.js";
|
|
4
4
|
import { writeIssuesJson } from "./observability/sinks/issues-sink.js";
|
|
5
5
|
import { buildEventBus, logBuildSummary, makeSummaryLoggerLayer } from "./layers/ObservabilityLive.js";
|
|
6
|
-
import { setLoaderEventEmitter } from "./loader.js";
|
|
7
6
|
import { setPrettierEventEmitter } from "./prettier-formatter.js";
|
|
8
7
|
import { setOgResolverEventEmitter } from "./og-resolver.js";
|
|
9
8
|
import { setBuildStagesEventEmitter } from "./build-stages.js";
|
|
@@ -14,14 +13,12 @@ import { deriveOutputPaths, normalizeBaseRoute, unscopedName } from "./path-deri
|
|
|
14
13
|
import { fromDir, fromParentDir } from "./config-helpers.js";
|
|
15
14
|
import { classifyApiConfig, mergeLlmsPluginConfig } from "./config-utils.js";
|
|
16
15
|
import { DEFAULT_SHIKI_THEMES, setShikiUtilsEventEmitter } from "./markdown/shiki-utils.js";
|
|
17
|
-
import { setModelLoaderEventEmitter } from "./model-loader.js";
|
|
18
16
|
import { resolveObservability } from "./schemas/observability.js";
|
|
19
17
|
import { PluginOptions } from "./schemas/config.js";
|
|
20
18
|
import "./schemas/index.js";
|
|
21
19
|
import { ConfigService } from "./services/ConfigService.js";
|
|
22
20
|
import { ConfigServiceLive } from "./layers/ConfigServiceLive.js";
|
|
23
21
|
import { PathDerivationServiceLive } from "./layers/PathDerivationServiceLive.js";
|
|
24
|
-
import { SnapshotServiceLive } from "./layers/SnapshotServiceLive.js";
|
|
25
22
|
import { TypeRegistryServiceLive } from "./layers/TypeRegistryServiceLive.js";
|
|
26
23
|
import { remarkApiCodeblocks, setRemarkApiCodeblocksEventEmitter } from "./remark-api-codeblocks.js";
|
|
27
24
|
import { remarkWithApi, setRemarkWithApiEventEmitter } from "./remark-with-api.js";
|
|
@@ -31,6 +28,7 @@ import fs from "node:fs";
|
|
|
31
28
|
import path from "node:path";
|
|
32
29
|
import { fileURLToPath } from "node:url";
|
|
33
30
|
import { NodeFileSystem } from "@effect/platform-node";
|
|
31
|
+
import { SnapshotServiceLive } from "@tsdoctor/snapshot";
|
|
34
32
|
import { Effect, FileSystem, Layer, ManagedRuntime, Ref, Schema } from "effect";
|
|
35
33
|
|
|
36
34
|
//#region src/plugin.ts
|
|
@@ -93,14 +91,12 @@ function ApiExtractorPluginImpl(rawOptions) {
|
|
|
93
91
|
const effectRuntime = ManagedRuntime.make(EffectAppLayer);
|
|
94
92
|
const emitSync = makeRuntimeEmitter(effectRuntime);
|
|
95
93
|
setEventEmitter(emitSync, buildId);
|
|
96
|
-
setLoaderEventEmitter(emitSync, buildId);
|
|
97
94
|
setShikiUtilsEventEmitter(emitSync, buildId);
|
|
98
95
|
setPrettierEventEmitter(emitSync, buildId);
|
|
99
96
|
setOgResolverEventEmitter(emitSync, buildId);
|
|
100
97
|
setRemarkWithApiEventEmitter(emitSync, buildId, obs.thresholds.slowCodeBlock);
|
|
101
98
|
setRemarkApiCodeblocksEventEmitter(emitSync, buildId);
|
|
102
99
|
setBuildStagesEventEmitter(emitSync, buildId);
|
|
103
|
-
setModelLoaderEventEmitter(emitSync, buildId);
|
|
104
100
|
const fileContextMap = /* @__PURE__ */ new Map();
|
|
105
101
|
let docsRoot;
|
|
106
102
|
let isFirstBuild = true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.
|
|
1
|
+
.i1orWq_table {
|
|
2
2
|
border: 1px solid var(--api-color-border);
|
|
3
3
|
border-radius: 0 0 var(--api-border-radius) var(--api-border-radius);
|
|
4
4
|
border-top: none;
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
overflow: hidden;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
html.
|
|
10
|
+
html.i1orWq_rp-dark .i1orWq_table {
|
|
11
11
|
border-color: var(--api-color-border);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
.
|
|
14
|
+
.i1orWq_scroll {
|
|
15
15
|
-webkit-overflow-scrolling: touch;
|
|
16
16
|
overflow-x: auto;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.
|
|
19
|
+
.i1orWq_table table {
|
|
20
20
|
border-collapse: collapse;
|
|
21
21
|
width: 100%;
|
|
22
22
|
font-size: var(--api-font-size-base);
|
|
@@ -25,12 +25,12 @@ html._9sEZ2a_rp-dark ._9sEZ2a_table {
|
|
|
25
25
|
margin: 0;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
.
|
|
28
|
+
.i1orWq_table thead {
|
|
29
29
|
background-color: var(--api-color-bg);
|
|
30
30
|
border-bottom: 1px solid var(--api-color-border);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
.
|
|
33
|
+
.i1orWq_table th {
|
|
34
34
|
padding: var(--api-spacing-md) var(--api-spacing-lg);
|
|
35
35
|
text-align: left;
|
|
36
36
|
color: var(--api-color-text);
|
|
@@ -38,62 +38,62 @@ html._9sEZ2a_rp-dark ._9sEZ2a_table {
|
|
|
38
38
|
font-weight: 600;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
.
|
|
41
|
+
.i1orWq_table th:first-child {
|
|
42
42
|
width: 20%;
|
|
43
43
|
min-width: 120px;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
.
|
|
46
|
+
.i1orWq_table th:nth-child(2) {
|
|
47
47
|
width: 25%;
|
|
48
48
|
min-width: 120px;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
.
|
|
51
|
+
.i1orWq_table th:last-child {
|
|
52
52
|
width: 55%;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
.
|
|
55
|
+
.i1orWq_table td {
|
|
56
56
|
padding: var(--api-spacing-md) var(--api-spacing-lg);
|
|
57
57
|
border-top: 1px solid var(--api-color-border);
|
|
58
58
|
vertical-align: top;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
.
|
|
61
|
+
.i1orWq_table td:first-child {
|
|
62
62
|
width: 20%;
|
|
63
63
|
min-width: 120px;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
.
|
|
66
|
+
.i1orWq_table td:nth-child(2) {
|
|
67
67
|
width: 25%;
|
|
68
68
|
min-width: 120px;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
.
|
|
71
|
+
.i1orWq_table td:last-child {
|
|
72
72
|
width: 55%;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
.
|
|
75
|
+
.i1orWq_table td code, .i1orWq_table th code {
|
|
76
76
|
font-size: var(--api-font-size-sm);
|
|
77
77
|
background-color: var(--api-color-code-bg);
|
|
78
78
|
border-radius: var(--api-border-radius-sm);
|
|
79
79
|
padding: .125rem .375rem;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
.
|
|
82
|
+
.i1orWq_table td:last-child p:first-child {
|
|
83
83
|
margin-top: 0;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
.
|
|
86
|
+
.i1orWq_table td:last-child p:last-child, .i1orWq_table td:last-child ul:last-child, .i1orWq_table td:last-child ol:last-child {
|
|
87
87
|
margin-bottom: 0;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
@media (width <= 768px) {
|
|
91
|
-
.
|
|
91
|
+
.i1orWq_table td, .i1orWq_table th {
|
|
92
92
|
padding: var(--api-spacing-sm) var(--api-spacing-md);
|
|
93
93
|
font-size: var(--api-font-size-sm);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
.
|
|
96
|
+
.i1orWq_table td:first-child, .i1orWq_table th:first-child, .i1orWq_table td:nth-child(2), .i1orWq_table th:nth-child(2) {
|
|
97
97
|
min-width: 100px;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import './index.css';
|
|
2
2
|
//#region src/runtime/components/EnumMembersTable/index.module.css
|
|
3
3
|
var index_module_default = {
|
|
4
|
-
"rpDark": "
|
|
5
|
-
"scroll": "
|
|
6
|
-
"table": "
|
|
4
|
+
"rpDark": "i1orWq_rp-dark",
|
|
5
|
+
"scroll": "i1orWq_scroll",
|
|
6
|
+
"table": "i1orWq_table"
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.
|
|
1
|
+
.xSQlsq_block {
|
|
2
2
|
margin: var(--api-spacing-xl) 0;
|
|
3
3
|
border-radius: var(--api-border-radius);
|
|
4
4
|
border: 1px solid var(--api-color-border);
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
overflow: visible;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
html.
|
|
9
|
+
html.xSQlsq_rp-dark .xSQlsq_block {
|
|
10
10
|
border-color: var(--api-color-border);
|
|
11
11
|
}
|