rspress-plugin-api-extractor 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-extracted-package.js +2 -1
- package/build-program.js +20 -12
- package/build-stages.js +123 -29
- package/config-utils.js +36 -7
- package/index.d.ts +329 -202
- package/layers/ConfigServiceLive.js +300 -136
- package/layers/ObservabilityLive.js +49 -85
- package/layers/TypeRegistryServiceLive.js +122 -21
- package/layers/build-metrics.js +61 -0
- package/llms-program.js +29 -7
- package/loader.js +16 -2
- package/markdown/shiki-utils.js +16 -2
- package/observability/EventBus.js +38 -0
- package/observability/events.js +17 -0
- package/observability/sinks/console-sink.js +63 -0
- package/observability/sinks/metrics-sink.js +68 -0
- package/observability/sinks/trace-sink.js +38 -0
- package/observability/spans.js +57 -0
- package/og-resolver.js +37 -5
- package/package.json +4 -4
- package/plugin.js +73 -19
- package/prettier-formatter.js +15 -4
- package/remark-api-codeblocks.js +22 -3
- package/remark-with-api.js +27 -14
- package/runtime/components/ApiExample/index.js +5 -5
- package/runtime/components/ApiMember/index.js +5 -7
- package/runtime/components/ApiSignature/index.js +4 -6
- package/runtime/components/EnumMembersTable/index.js +5 -0
- package/runtime/components/ExampleBlock/index.js +5 -3
- package/runtime/components/MemberSignature/index.js +4 -2
- package/runtime/components/ParametersTable/index.js +5 -0
- package/runtime/components/SignatureBlock/index.js +4 -2
- package/runtime/components/shared/variables.css +0 -15
- package/runtime/index.d.ts +65 -399
- package/runtime/index.js +1 -5
- package/runtime/utils/hast-renderer.js +1 -0
- package/schemas/config.js +105 -4
- package/schemas/index.js +2 -1
- package/schemas/observability.js +62 -0
- package/schemas/opengraph.js +30 -0
- package/schemas/performance.js +1 -1
- package/serve.js +13 -0
- package/twoslash-transformer.js +93 -8
package/remark-with-api.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PluginEvent } from "./observability/events.js";
|
|
2
2
|
import { formatCode } from "./prettier-formatter.js";
|
|
3
3
|
import { stripTwoslashDirectives } from "./markdown/helpers.js";
|
|
4
|
+
import { TwoslashManager } from "./twoslash-transformer.js";
|
|
4
5
|
import { DEFAULT_SHIKI_THEMES } from "./markdown/shiki-utils.js";
|
|
5
|
-
import { Effect, Metric } from "effect";
|
|
6
6
|
import { codeToHast, hastToHtml } from "shiki";
|
|
7
7
|
import { visit } from "unist-util-visit";
|
|
8
8
|
|
|
9
9
|
//#region src/remark-with-api.ts
|
|
10
|
-
|
|
10
|
+
/** Module-level emitter injected by plugin.ts at startup. */
|
|
11
|
+
let emitEvent = () => {};
|
|
12
|
+
let currentBuildId = "";
|
|
13
|
+
let currentSlowCodeBlockMs = 500;
|
|
14
|
+
function setRemarkWithApiEventEmitter(fn, buildId = "", slowCodeBlockMs = 500) {
|
|
15
|
+
emitEvent = fn;
|
|
16
|
+
currentBuildId = buildId;
|
|
17
|
+
currentSlowCodeBlockMs = slowCodeBlockMs;
|
|
18
|
+
}
|
|
11
19
|
/**
|
|
12
20
|
* Supported languages for with-api code blocks
|
|
13
21
|
* Based on GitHub Linguist standard aliases:
|
|
@@ -15,7 +23,7 @@ import { visit } from "unist-util-visit";
|
|
|
15
23
|
* - JavaScript: javascript, js, node
|
|
16
24
|
* - TSX/JSX: tsx, jsx (Shiki-supported)
|
|
17
25
|
*/
|
|
18
|
-
const SUPPORTED_LANGUAGES = new Set([
|
|
26
|
+
const SUPPORTED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
19
27
|
"typescript",
|
|
20
28
|
"ts",
|
|
21
29
|
"javascript",
|
|
@@ -53,22 +61,20 @@ const remarkWithApi = (options) => {
|
|
|
53
61
|
const { shikiCrossLinker, getTransformer, theme } = options;
|
|
54
62
|
const resolvedTheme = theme ?? DEFAULT_SHIKI_THEMES;
|
|
55
63
|
return async function remarkTransformer(tree, file) {
|
|
56
|
-
const fileStart = performance.now();
|
|
57
64
|
const promises = [];
|
|
58
|
-
let blockCount = 0;
|
|
59
65
|
let needsApiExampleImport = false;
|
|
60
66
|
const isSsgMd = import.meta.env?.SSG_MD || process.env.RSBUILD_ENVIRONMENT === "node_md" || process.env.BUILD_TARGET === "node_md";
|
|
61
67
|
const currentFilePath = file.path;
|
|
62
68
|
if (currentFilePath) {
|
|
63
69
|
const apiScope = inferApiScope(currentFilePath);
|
|
64
70
|
if (apiScope) shikiCrossLinker.setApiScope(apiScope);
|
|
71
|
+
TwoslashManager.getInstance().setCurrentFile(currentFilePath);
|
|
65
72
|
}
|
|
66
73
|
visit(tree, "code", (node, index, parent) => {
|
|
67
74
|
const hasWithApi = node.meta?.includes("with-api");
|
|
68
75
|
const lang = node.lang || "typescript";
|
|
69
76
|
const isSupported = SUPPORTED_LANGUAGES.has(lang);
|
|
70
77
|
if (!hasWithApi || !isSupported) return;
|
|
71
|
-
blockCount++;
|
|
72
78
|
const promise = (async () => {
|
|
73
79
|
const blockStart = performance.now();
|
|
74
80
|
const rawCode = node.value;
|
|
@@ -91,10 +97,19 @@ const remarkWithApi = (options) => {
|
|
|
91
97
|
if (apiScope) hast = shikiCrossLinker.transformHast(hast, apiScope);
|
|
92
98
|
const shikiTime = performance.now() - shikiStart;
|
|
93
99
|
const totalBlockTime = performance.now() - blockStart;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
const isSlow = totalBlockTime > currentSlowCodeBlockMs;
|
|
101
|
+
emitEvent(PluginEvent.CodeBlockProcessed({
|
|
102
|
+
ctx: {
|
|
103
|
+
buildId: currentBuildId,
|
|
104
|
+
...currentFilePath != null ? { file: currentFilePath } : {}
|
|
105
|
+
},
|
|
106
|
+
lang,
|
|
107
|
+
shikiMs: shikiTime,
|
|
108
|
+
twoslashMs: totalBlockTime - shikiTime,
|
|
109
|
+
totalMs: totalBlockTime,
|
|
110
|
+
slow: isSlow,
|
|
111
|
+
level: "debug"
|
|
112
|
+
}));
|
|
98
113
|
if (parent && typeof index === "number") if (isSsgMd) {
|
|
99
114
|
const cleanCode = hastToHtml(hast).replace(/<[^>]*>/g, "").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, "\"").replace(/'/g, "'").trim();
|
|
100
115
|
node.lang = "typescript";
|
|
@@ -163,10 +178,8 @@ const remarkWithApi = (options) => {
|
|
|
163
178
|
tree.children.splice(insertIndex, 0, importNode);
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
|
-
const fileTime = performance.now() - fileStart;
|
|
167
|
-
if (blockCount > 0) console.log(`⏱️ [remark-with-api] Processed ${blockCount} blocks in ${fileTime.toFixed(0)}ms (avg: ${(fileTime / blockCount).toFixed(0)}ms per block)`);
|
|
168
181
|
};
|
|
169
182
|
};
|
|
170
183
|
|
|
171
184
|
//#endregion
|
|
172
|
-
export { remarkWithApi };
|
|
185
|
+
export { remarkWithApi, setRemarkWithApiEventEmitter };
|
|
@@ -5,13 +5,13 @@ import { Fragment, jsx } from "react/jsx-runtime";
|
|
|
5
5
|
|
|
6
6
|
//#region src/runtime/components/ApiExample/index.tsx
|
|
7
7
|
/**
|
|
8
|
-
* Renders an example code block.
|
|
8
|
+
* Renders an example code block in generated API documentation pages.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Twoslash directives stripped.
|
|
10
|
+
* In browser mode renders a Shiki-highlighted code block with copy and wrap
|
|
11
|
+
* controls. In SSG-MD mode renders a plain fenced code block.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
13
|
+
* @param props - {@link ApiExampleProps}
|
|
14
|
+
* @public
|
|
15
15
|
*/
|
|
16
16
|
function ApiExample({ code, hast }) {
|
|
17
17
|
const parsedHast = useMemo(() => decodeHast(hast, "ApiExample"), [hast]);
|
|
@@ -5,15 +5,13 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
|
|
6
6
|
//#region src/runtime/components/ApiMember/index.tsx
|
|
7
7
|
/**
|
|
8
|
-
* Renders an individual class
|
|
8
|
+
* Renders an individual class or interface member signature block.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* wrapped in a class skeleton), and `summary` is plain markdown-compatible
|
|
13
|
-
* text (not HTML with anchor tags, not base64-encoded).
|
|
10
|
+
* In browser mode renders an `h3` heading with a Shiki-highlighted signature.
|
|
11
|
+
* In SSG-MD mode renders a heading, summary, and plain fenced code block.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* @param props - {@link ApiMemberProps}
|
|
14
|
+
* @public
|
|
17
15
|
*/
|
|
18
16
|
function ApiMember({ code, memberName, summary, id, hast, hasParameters }) {
|
|
19
17
|
const parsedHast = useMemo(() => decodeHast(hast, "ApiMember"), [hast]);
|
|
@@ -7,13 +7,11 @@ import { Fragment, jsx } from "react/jsx-runtime";
|
|
|
7
7
|
/**
|
|
8
8
|
* Renders a full API type signature block.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* that RSPress converts to LLM-readable markdown in SSG-MD mode, and renders
|
|
13
|
-
* interactive Shiki-highlighted code in browser mode.
|
|
10
|
+
* In browser mode renders an interactive Shiki-highlighted code block.
|
|
11
|
+
* In SSG-MD mode renders a plain fenced code block for LLM consumption.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* @param props - {@link ApiSignatureProps}
|
|
14
|
+
* @public
|
|
17
15
|
*/
|
|
18
16
|
function ApiSignature({ code, heading: _heading = "Signature", id: _id = "signature", hast, hasParameters, hasMembers }) {
|
|
19
17
|
const parsedHast = useMemo(() => decodeHast(hast, "ApiSignature"), [hast]);
|
|
@@ -3,6 +3,11 @@ import index_module_default from "./index.module.js";
|
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/runtime/components/EnumMembersTable/index.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Renders a table of enum members with their values and descriptions.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
6
11
|
const EnumMembersTable = ({ members }) => {
|
|
7
12
|
if (!members || members.length === 0) return null;
|
|
8
13
|
if (import.meta.env.SSG_MD) {
|
|
@@ -9,9 +9,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
|
|
10
10
|
//#region src/runtime/components/ExampleBlock/index.tsx
|
|
11
11
|
/**
|
|
12
|
-
* Code block for examples
|
|
13
|
-
* Similar to SignatureBlock but without the "Signature" header
|
|
14
|
-
* Includes both copy and wrap buttons in the toolbar
|
|
12
|
+
* Code block for examples — displays syntax-highlighted code without a heading.
|
|
13
|
+
* Similar to {@link SignatureBlock} but without the "Signature" header.
|
|
14
|
+
* Includes both copy and wrap buttons in the toolbar.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
15
17
|
*/
|
|
16
18
|
function ExampleBlock({ hast, code }) {
|
|
17
19
|
const { wrapped, toggleWrap } = useWrapToggle();
|
|
@@ -8,8 +8,10 @@ import clsx from "clsx";
|
|
|
8
8
|
|
|
9
9
|
//#region src/runtime/components/MemberSignature/index.tsx
|
|
10
10
|
/**
|
|
11
|
-
* Interactive member signature block with h3 header and wrap button
|
|
12
|
-
* Displays syntax-highlighted TypeScript member signatures with hover tooltips
|
|
11
|
+
* Interactive member signature block with h3 header and wrap button.
|
|
12
|
+
* Displays syntax-highlighted TypeScript member signatures with hover tooltips.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
13
15
|
*/
|
|
14
16
|
function MemberSignature({ hast, memberName, id, summary, hasParameters = false }) {
|
|
15
17
|
const { wrapped, toggleWrap } = useWrapToggle();
|
|
@@ -3,6 +3,11 @@ import index_module_default from "./index.module.js";
|
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/runtime/components/ParametersTable/index.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Renders a table of function or method parameters with their types and descriptions.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
6
11
|
const ParametersTable = ({ parameters }) => {
|
|
7
12
|
if (!parameters || parameters.length === 0) return null;
|
|
8
13
|
if (import.meta.env.SSG_MD) {
|
|
@@ -8,8 +8,10 @@ import clsx from "clsx";
|
|
|
8
8
|
|
|
9
9
|
//#region src/runtime/components/SignatureBlock/index.tsx
|
|
10
10
|
/**
|
|
11
|
-
* Interactive signature block with wrap button
|
|
12
|
-
* Displays syntax-highlighted TypeScript signatures with hover tooltips
|
|
11
|
+
* Interactive signature block with wrap button.
|
|
12
|
+
* Displays syntax-highlighted TypeScript signatures with hover tooltips.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
13
15
|
*/
|
|
14
16
|
function SignatureBlock({ hast, heading = "Signature", id = "signature", hasParameters = false }) {
|
|
15
17
|
const { wrapped, toggleWrap } = useWrapToggle();
|
|
@@ -65,18 +65,3 @@ html.rp-dark {
|
|
|
65
65
|
--api-color-link-hover: #79c0ff;
|
|
66
66
|
--api-color-code-bg: #6e768166;
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
html.rp-dark .rp-social-links__item {
|
|
70
|
-
background-color: var(--api-color-bg-secondary);
|
|
71
|
-
border-color: var(--api-color-border);
|
|
72
|
-
color: var(--api-color-text);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
html.rp-dark .rp-social-links__item:hover {
|
|
76
|
-
background-color: var(--api-color-hover-bg);
|
|
77
|
-
border-color: var(--api-color-border-hover);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
html.rp-dark .rp-social-links__item:active {
|
|
81
|
-
background-color: var(--api-color-active-bg);
|
|
82
|
-
}
|