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.
Files changed (53) hide show
  1. package/README.md +11 -11
  2. package/api-extracted-package.js +1 -1
  3. package/build-program.js +3 -3
  4. package/build-stages.js +30 -31
  5. package/config-helpers.js +61 -21
  6. package/errors.js +1 -7
  7. package/frontmatter.js +149 -0
  8. package/index.d.ts +11 -2
  9. package/layers/ConfigServiceLive.js +53 -39
  10. package/layers/TypeRegistryServiceLive.js +11 -6
  11. package/markdown/helpers.js +40 -69
  12. package/markdown/index.js +2 -2
  13. package/markdown/page-generators/class-page.js +40 -42
  14. package/markdown/page-generators/enum-page.js +15 -15
  15. package/markdown/page-generators/function-page.js +18 -20
  16. package/markdown/page-generators/interface-page.js +41 -43
  17. package/markdown/page-generators/namespace-page.js +22 -24
  18. package/markdown/page-generators/type-alias-page.js +14 -16
  19. package/markdown/page-generators/variable-page.js +14 -16
  20. package/markdown/prose-linker.js +22 -0
  21. package/model-loader.js +59 -113
  22. package/package.json +14 -8
  23. package/plugin.js +1 -5
  24. package/runtime/components/EnumMembersTable/index.css +18 -18
  25. package/runtime/components/EnumMembersTable/index.module.js +3 -3
  26. package/runtime/components/ExampleBlock/index.css +2 -2
  27. package/runtime/components/ExampleBlock/index.module.js +2 -2
  28. package/runtime/components/MemberSignature/index.css +6 -6
  29. package/runtime/components/MemberSignature/index.module.js +4 -4
  30. package/runtime/components/ParametersTable/index.css +19 -19
  31. package/runtime/components/ParametersTable/index.module.js +3 -3
  32. package/runtime/components/SignatureBlock/index.css +6 -6
  33. package/runtime/components/SignatureBlock/index.module.js +4 -4
  34. package/runtime/components/SignatureCode/index.css +9 -9
  35. package/runtime/components/SignatureCode/index.module.js +3 -3
  36. package/runtime/components/SignatureToolbar/index.css +18 -18
  37. package/runtime/components/SignatureToolbar/index.module.js +7 -7
  38. package/runtime/components/buttons/index.css +5 -5
  39. package/runtime/components/buttons/index.module.js +2 -2
  40. package/shiki-transformer.js +3 -3
  41. package/sync-node-fs.js +80 -0
  42. package/tsdoc-metadata.json +1 -1
  43. package/twoslash-transformer.js +1 -1
  44. package/content-hash.js +0 -79
  45. package/formatter.js +0 -69
  46. package/layers/SnapshotServiceLive.js +0 -92
  47. package/loader.js +0 -200
  48. package/markdown/cross-linker.js +0 -157
  49. package/migrations/001_create_snapshots.js +0 -25
  50. package/multi-entry-resolver.js +0 -70
  51. package/route-collisions.js +0 -44
  52. package/services/SnapshotService.js +0 -7
  53. 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 { markdownCrossLinker } from "../cross-linker.js";
5
- import { TypeSignatureFormatter } from "../../formatter.js";
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 {@link TypeSignatureFormatter} for formatting type signatures
27
- * - Uses {@link ApiParser} for extracting documentation from API models
28
- * - Uses {@link MarkdownCrossLinker} for adding type reference links
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 = ApiParser.getSummary(apiTypeAlias) || "No description available.";
44
- const releaseTag = ApiParser.getReleaseTag(apiTypeAlias);
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 = ApiParser.getDeprecation(apiTypeAlias);
48
+ const deprecation = Tsdoc.deprecation(apiTypeAlias);
51
49
  if (deprecation) {
52
- const message = escapeMdxGenerics(markdownCrossLinker.addCrossLinks(deprecation.message));
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 = ApiParser.getSourceLink(apiTypeAlias, sourceConfig);
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 = this.typeFormatter.format(apiTypeAlias.excerpt).trim();
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 = ApiParser.getExamples(apiTypeAlias);
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 = ApiParser.getSeeReferences(apiTypeAlias);
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(markdownCrossLinker.addCrossLinks(reference.text));
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 { markdownCrossLinker } from "../cross-linker.js";
5
- import { TypeSignatureFormatter } from "../../formatter.js";
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 {@link TypeSignatureFormatter} for formatting type signatures
27
- * - Uses {@link ApiParser} for extracting documentation from API models
28
- * - Uses {@link MarkdownCrossLinker} for adding type reference links
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 = ApiParser.getSummary(apiVariable) || "No description available.";
44
- const releaseTag = ApiParser.getReleaseTag(apiVariable);
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 = ApiParser.getDeprecation(apiVariable);
48
+ const deprecation = Tsdoc.deprecation(apiVariable);
51
49
  if (deprecation) {
52
- const message = escapeMdxGenerics(markdownCrossLinker.addCrossLinks(deprecation.message));
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 = ApiParser.getSourceLink(apiVariable, sourceConfig);
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 = this.typeFormatter.format(apiVariable.excerpt).trim();
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 = ApiParser.getExamples(apiVariable);
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 = ApiParser.getSeeReferences(apiVariable);
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(markdownCrossLinker.addCrossLinks(reference.text));
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 { loadApiModel } from "api-extractor-llms";
4
+ import { Effect } from "effect";
5
+ import { Model } from "@tsdoctor/model";
6
6
 
7
7
  //#region src/model-loader.ts
8
8
  /**
9
- * Module-level emitter seam. `loadFromPath` is called from inside an
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
- let emitEvent = () => {};
19
- let currentBuildId = "";
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
- * Inject the runtime-bound emitter into the model-loader module.
22
- * Call this right after `makeRuntimeEmitter` in plugin.ts.
22
+ * Load package.json from PathLike or async function.
23
23
  */
24
- function setModelLoaderEventEmitter(fn, buildId = "") {
25
- emitEvent = fn;
26
- currentBuildId = buildId;
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
- * Utility class for loading API models from various sources
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
- var ApiModelLoader = class ApiModelLoader {
32
- /**
33
- * Private constructor to prevent instantiation
34
- */
35
- constructor() {}
36
- /**
37
- * Load an API model from a path (string, URL, or Buffer)
38
- */
39
- static async loadFromPath(modelPath) {
40
- const resolvedPath = path.resolve(modelPath.toString());
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: await ApiModelLoader.loadFromPath(loader) };
101
- }
102
- /**
103
- * Resolve and load a version config
104
- */
105
- static async loadVersionModel(versionValue) {
106
- if (isVersionConfig(versionValue)) {
107
- const { apiPackage, source: loaderSource } = await ApiModelLoader.loadApiModel(versionValue.model);
108
- const packageJson = versionValue.packageJson ? await ApiModelLoader.loadPackageJson(versionValue.packageJson) : void 0;
109
- const versionResult = { apiPackage };
110
- if (packageJson != null) versionResult.packageJson = packageJson;
111
- if (versionValue.categories != null) versionResult.categories = versionValue.categories;
112
- const resolvedSource = loaderSource || versionValue.source;
113
- if (resolvedSource != null) versionResult.source = resolvedSource;
114
- if (versionValue.externalPackages != null) versionResult.externalPackages = versionValue.externalPackages;
115
- if (versionValue.autoDetectDependencies != null) versionResult.autoDetectDependencies = versionValue.autoDetectDependencies;
116
- if (versionValue.ogImage != null) versionResult.ogImage = versionValue.ogImage;
117
- if (versionValue.llmsPlugin != null) versionResult.llmsPlugin = versionValue.llmsPlugin;
118
- return versionResult;
119
- }
120
- const { apiPackage, source } = await ApiModelLoader.loadApiModel(versionValue);
121
- const simpleResult = { apiPackage };
122
- if (source != null) simpleResult.source = source;
123
- return simpleResult;
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 { ApiModelLoader, setModelLoaderEventEmitter };
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.8.8",
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/rspress-plugin-api-extractor#readme",
13
+ "homepage": "https://github.com/spencerbeggs/tsdoctor#readme",
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/spencerbeggs/rspress-plugin-api-extractor.git",
17
- "directory": "package"
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
- "@effect/sql-sqlite-node": "4.0.0-rc.109",
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
- ._9sEZ2a_table {
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._9sEZ2a_rp-dark ._9sEZ2a_table {
10
+ html.i1orWq_rp-dark .i1orWq_table {
11
11
  border-color: var(--api-color-border);
12
12
  }
13
13
 
14
- ._9sEZ2a_scroll {
14
+ .i1orWq_scroll {
15
15
  -webkit-overflow-scrolling: touch;
16
16
  overflow-x: auto;
17
17
  }
18
18
 
19
- ._9sEZ2a_table table {
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
- ._9sEZ2a_table thead {
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
- ._9sEZ2a_table th {
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
- ._9sEZ2a_table th:first-child {
41
+ .i1orWq_table th:first-child {
42
42
  width: 20%;
43
43
  min-width: 120px;
44
44
  }
45
45
 
46
- ._9sEZ2a_table th:nth-child(2) {
46
+ .i1orWq_table th:nth-child(2) {
47
47
  width: 25%;
48
48
  min-width: 120px;
49
49
  }
50
50
 
51
- ._9sEZ2a_table th:last-child {
51
+ .i1orWq_table th:last-child {
52
52
  width: 55%;
53
53
  }
54
54
 
55
- ._9sEZ2a_table td {
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
- ._9sEZ2a_table td:first-child {
61
+ .i1orWq_table td:first-child {
62
62
  width: 20%;
63
63
  min-width: 120px;
64
64
  }
65
65
 
66
- ._9sEZ2a_table td:nth-child(2) {
66
+ .i1orWq_table td:nth-child(2) {
67
67
  width: 25%;
68
68
  min-width: 120px;
69
69
  }
70
70
 
71
- ._9sEZ2a_table td:last-child {
71
+ .i1orWq_table td:last-child {
72
72
  width: 55%;
73
73
  }
74
74
 
75
- ._9sEZ2a_table td code, ._9sEZ2a_table th code {
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
- ._9sEZ2a_table td:last-child p:first-child {
82
+ .i1orWq_table td:last-child p:first-child {
83
83
  margin-top: 0;
84
84
  }
85
85
 
86
- ._9sEZ2a_table td:last-child p:last-child, ._9sEZ2a_table td:last-child ul:last-child, ._9sEZ2a_table td:last-child ol:last-child {
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
- ._9sEZ2a_table td, ._9sEZ2a_table th {
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
- ._9sEZ2a_table td:first-child, ._9sEZ2a_table th:first-child, ._9sEZ2a_table td:nth-child(2), ._9sEZ2a_table th:nth-child(2) {
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": "_9sEZ2a_rp-dark",
5
- "scroll": "_9sEZ2a_scroll",
6
- "table": "_9sEZ2a_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
- .L3GWXq_block {
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.L3GWXq_rp-dark .L3GWXq_block {
9
+ html.xSQlsq_rp-dark .xSQlsq_block {
10
10
  border-color: var(--api-color-border);
11
11
  }
@@ -1,8 +1,8 @@
1
1
  import './index.css';
2
2
  //#region src/runtime/components/ExampleBlock/index.module.css
3
3
  var index_module_default = {
4
- "block": "L3GWXq_block",
5
- "rpDark": "L3GWXq_rp-dark"
4
+ "block": "xSQlsq_block",
5
+ "rpDark": "xSQlsq_rp-dark"
6
6
  };
7
7
 
8
8
  //#endregion