rspress-plugin-api-extractor 0.1.2 → 0.2.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 +2 -2
- package/api-extracted-package.js +426 -0
- package/build-program.js +120 -0
- package/build-stages.js +664 -0
- package/category-resolver.js +50 -0
- package/code-post-processor.js +38 -0
- package/config-helpers.js +106 -0
- package/config-utils.js +258 -0
- package/content-hash.js +79 -0
- package/errors.js +29 -0
- package/formatter.js +69 -0
- package/hide-cut-transformer.js +96 -0
- package/index.d.ts +901 -831
- package/index.js +4 -6128
- package/layers/ConfigServiceLive.js +377 -0
- package/layers/ObservabilityLive.js +136 -0
- package/layers/PathDerivationServiceLive.js +16 -0
- package/layers/SnapshotServiceLive.js +94 -0
- package/layers/TypeRegistryServiceLive.js +46 -0
- package/llms-processing.js +270 -0
- package/llms-program.js +262 -0
- package/loader.js +186 -0
- package/markdown/cross-linker.js +156 -0
- package/markdown/helpers.js +364 -0
- package/markdown/index.js +11 -0
- package/markdown/page-generators/class-page.js +357 -0
- package/markdown/page-generators/enum-page.js +152 -0
- package/markdown/page-generators/function-page.js +127 -0
- package/markdown/page-generators/index-pages.js +27 -0
- package/markdown/page-generators/interface-page.js +307 -0
- package/markdown/page-generators/namespace-page.js +280 -0
- package/markdown/page-generators/type-alias-page.js +110 -0
- package/markdown/page-generators/variable-page.js +110 -0
- package/markdown/shiki-utils.js +48 -0
- package/migrations/001_create_snapshots.js +25 -0
- package/model-loader.js +95 -0
- package/multi-entry-resolver.js +70 -0
- package/og-resolver.js +271 -0
- package/package.json +63 -73
- package/path-derivation.js +48 -0
- package/plugin.js +218 -0
- package/prettier-formatter.js +73 -0
- package/public/tsconfig/rspress.json +44 -0
- package/remark-api-codeblocks.js +130 -0
- package/remark-with-api.js +172 -0
- package/route-collisions.js +52 -0
- package/runtime/components/ApiExample/index.js +29 -25
- package/runtime/components/ApiLlmsPackageActions/index.js +252 -323
- package/runtime/components/ApiLlmsViewOptions/index.js +269 -340
- package/runtime/components/ApiMember/index.js +49 -47
- package/runtime/components/ApiSignature/index.js +32 -28
- package/runtime/components/EnumMembersTable/{index_module.css → index.css} +18 -19
- package/runtime/components/EnumMembersTable/index.js +36 -67
- package/runtime/components/EnumMembersTable/index.module.js +9 -6
- package/runtime/components/ExampleBlock/{index_module.css → index.css} +2 -3
- package/runtime/components/ExampleBlock/index.js +23 -28
- package/runtime/components/ExampleBlock/index.module.js +8 -5
- package/runtime/components/MarkdownContent/index.js +26 -18
- package/runtime/components/MarkdownText/index.js +28 -22
- package/runtime/components/MemberSignature/{index_module.css → index.css} +5 -6
- package/runtime/components/MemberSignature/index.js +46 -46
- package/runtime/components/MemberSignature/index.module.js +9 -6
- package/runtime/components/ParametersTable/{index_module.css → index.css} +19 -20
- package/runtime/components/ParametersTable/index.js +36 -67
- package/runtime/components/ParametersTable/index.module.js +9 -6
- package/runtime/components/SignatureBlock/{index_module.css → index.css} +5 -6
- package/runtime/components/SignatureBlock/index.js +30 -29
- package/runtime/components/SignatureBlock/index.module.js +9 -6
- package/runtime/components/SignatureCode/{index_module.css → index.css} +9 -10
- package/runtime/components/SignatureCode/index.js +40 -32
- package/runtime/components/SignatureCode/index.module.js +9 -6
- package/runtime/components/SignatureToolbar/{index_module.css → index.css} +18 -20
- package/runtime/components/SignatureToolbar/index.js +48 -51
- package/runtime/components/SignatureToolbar/index.module.js +13 -10
- package/runtime/components/buttons/ButtonGroup.js +13 -6
- package/runtime/components/buttons/CopyCodeButton.js +40 -38
- package/runtime/components/buttons/WrapSignatureButton.js +20 -16
- package/runtime/components/buttons/{index_module.css → index.css} +5 -6
- package/runtime/components/buttons/index.module.js +8 -5
- package/runtime/components/icons/CheckIcon/index.js +20 -17
- package/runtime/components/icons/CopyIcon/index.js +20 -17
- package/runtime/components/icons/UnwrapIcon/index.js +22 -18
- package/runtime/components/icons/WrapIcon/index.js +20 -17
- package/runtime/components/shared/_twoslash.css +3 -10
- package/runtime/components/shared/variables.css +0 -3
- package/runtime/hooks/useWrapToggle.js +32 -9
- package/runtime/index.d.ts +513 -173
- package/runtime/index.js +11 -9
- package/runtime/utils/decode-hast.js +31 -16
- package/runtime/utils/hast-renderer.js +21 -7
- package/schemas/config.js +199 -0
- package/schemas/index.js +5 -0
- package/schemas/opengraph.js +26 -0
- package/schemas/performance.js +19 -0
- package/serve.js +133 -0
- package/services/ConfigService.js +7 -0
- package/services/PathDerivationService.js +7 -0
- package/services/SnapshotService.js +7 -0
- package/services/TypeRegistryService.js +7 -0
- package/shiki-transformer.js +758 -0
- package/tsconfig-parser.js +127 -0
- package/tsdoc-metadata.json +11 -11
- package/twoslash-patterns.js +87 -0
- package/twoslash-transformer.js +316 -0
- package/type-reference-extractor.js +201 -0
- package/typescript-config.js +168 -0
- package/vfs-registry.js +121 -0
- package/0~llms-program.js +0 -344
- package/runtime/components/ApiLlmsPackageActions/index.module.js +0 -2
package/runtime/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import "./components/shared/variables.css";
|
|
2
2
|
import "./components/shared/_twoslash.css";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
import { hastToReact } from "./utils/hast-renderer.js";
|
|
4
|
+
import { ExampleBlock } from "./components/ExampleBlock/index.js";
|
|
5
|
+
import { ApiExample } from "./components/ApiExample/index.js";
|
|
6
|
+
import { MemberSignature } from "./components/MemberSignature/index.js";
|
|
7
|
+
import { ApiMember } from "./components/ApiMember/index.js";
|
|
8
|
+
import { SignatureBlock } from "./components/SignatureBlock/index.js";
|
|
9
|
+
import { ApiSignature } from "./components/ApiSignature/index.js";
|
|
10
|
+
import { EnumMembersTable } from "./components/EnumMembersTable/index.js";
|
|
11
|
+
import { ParametersTable } from "./components/ParametersTable/index.js";
|
|
12
|
+
|
|
13
|
+
export { ApiExample, ApiMember, ApiSignature, EnumMembersTable, ExampleBlock, MemberSignature, ParametersTable, SignatureBlock, hastToReact };
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
+
//#region src/runtime/utils/decode-hast.ts
|
|
2
|
+
/**
|
|
3
|
+
* Decode a HAST value that may be base64-encoded, plain JSON, or already parsed.
|
|
4
|
+
*
|
|
5
|
+
* Supports multiple input formats:
|
|
6
|
+
* - Root object (direct HAST) - returned as-is
|
|
7
|
+
* - Base64-encoded JSON string (from serializeHastForMdx)
|
|
8
|
+
* - Plain JSON string (legacy format)
|
|
9
|
+
*
|
|
10
|
+
* @param hast - The HAST value to decode
|
|
11
|
+
* @param componentName - Optional component name for warning messages
|
|
12
|
+
* @returns Parsed HAST Root or null if decoding fails
|
|
13
|
+
*/
|
|
1
14
|
function decodeHast(hast, componentName) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (!hast) return null;
|
|
16
|
+
if (typeof hast !== "string") return hast;
|
|
17
|
+
try {
|
|
18
|
+
if (/^[A-Za-z0-9+/=]+$/.test(hast) && hast.length > 20) {
|
|
19
|
+
const binaryString = atob(hast);
|
|
20
|
+
const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
|
|
21
|
+
const json = new TextDecoder("utf-8").decode(bytes);
|
|
22
|
+
return JSON.parse(json);
|
|
23
|
+
}
|
|
24
|
+
return JSON.parse(hast);
|
|
25
|
+
} catch {
|
|
26
|
+
const name = componentName ? `${componentName}: ` : "";
|
|
27
|
+
console.warn(`${name}Failed to decode HAST`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
17
30
|
}
|
|
18
|
-
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { decodeHast };
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
2
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/runtime/utils/hast-renderer.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Convert a HAST (Hypertext Abstract Syntax Tree) root to a React element.
|
|
7
|
+
*
|
|
8
|
+
* This function is used to render pre-generated Shiki HAST trees at runtime,
|
|
9
|
+
* avoiding the need for `dangerouslySetInnerHTML` and eliminating MDX parsing
|
|
10
|
+
* issues caused by long HTML strings with special characters.
|
|
11
|
+
*
|
|
12
|
+
* @param hast - The HAST root node from Shiki's `codeToHast()`
|
|
13
|
+
* @returns A React element representing the HAST tree
|
|
14
|
+
*/
|
|
3
15
|
function hastToReact(hast) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
16
|
+
return toJsxRuntime(hast, {
|
|
17
|
+
Fragment,
|
|
18
|
+
jsx,
|
|
19
|
+
jsxs
|
|
20
|
+
});
|
|
9
21
|
}
|
|
10
|
-
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { hastToReact };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { OpenGraphImageConfig } from "./opengraph.js";
|
|
2
|
+
import { PerformanceConfig } from "./performance.js";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
import { ApiItemKind } from "@microsoft/api-extractor-model";
|
|
5
|
+
|
|
6
|
+
//#region src/schemas/config.ts
|
|
7
|
+
/**
|
|
8
|
+
* Opaque input type for config fields that accept a file path string,
|
|
9
|
+
* an async loader function, or a URL.
|
|
10
|
+
*/
|
|
11
|
+
const ModelInput = Schema.declare((input) => typeof input === "string" || typeof input === "function" || input instanceof URL);
|
|
12
|
+
const LogLevel$1 = Schema.Literal("none", "info", "verbose", "debug", "warn", "error");
|
|
13
|
+
const ExternalPackageSpec = Schema.mutable(Schema.Struct({
|
|
14
|
+
name: Schema.String,
|
|
15
|
+
version: Schema.String,
|
|
16
|
+
tsconfig: Schema.optional(ModelInput),
|
|
17
|
+
compilerOptions: Schema.optional(Schema.Unknown)
|
|
18
|
+
}));
|
|
19
|
+
const AutoDetectDependencies = Schema.mutable(Schema.Struct({
|
|
20
|
+
dependencies: Schema.optionalWith(Schema.Boolean, { default: () => false }),
|
|
21
|
+
devDependencies: Schema.optionalWith(Schema.Boolean, { default: () => false }),
|
|
22
|
+
peerDependencies: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
23
|
+
autoDependencies: Schema.optionalWith(Schema.Boolean, { default: () => true })
|
|
24
|
+
}));
|
|
25
|
+
const ErrorConfig = Schema.mutable(Schema.Struct({ example: Schema.optional(Schema.Literal("suppress", "show")) }));
|
|
26
|
+
const LlmsPlugin = Schema.mutable(Schema.Struct({
|
|
27
|
+
enabled: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
28
|
+
scopes: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
29
|
+
apiTxt: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
30
|
+
showCopyButton: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
31
|
+
showViewOptions: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
32
|
+
copyButtonText: Schema.optionalWith(Schema.String, { default: () => "Copy Markdown" }),
|
|
33
|
+
viewOptions: Schema.optionalWith(Schema.mutable(Schema.Array(Schema.Literal("markdownLink", "chatgpt", "claude"))), { default: () => [
|
|
34
|
+
"markdownLink",
|
|
35
|
+
"chatgpt",
|
|
36
|
+
"claude"
|
|
37
|
+
] })
|
|
38
|
+
}));
|
|
39
|
+
const ApiItemKindSchema = Schema.declare((input) => typeof input === "number");
|
|
40
|
+
const CategoryConfig = Schema.mutable(Schema.Struct({
|
|
41
|
+
displayName: Schema.String,
|
|
42
|
+
singularName: Schema.String,
|
|
43
|
+
folderName: Schema.String,
|
|
44
|
+
itemKinds: Schema.optional(Schema.mutable(Schema.Array(ApiItemKindSchema))),
|
|
45
|
+
tsdocModifier: Schema.optional(Schema.String),
|
|
46
|
+
collapsible: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
47
|
+
collapsed: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
48
|
+
overviewHeaders: Schema.optionalWith(Schema.mutable(Schema.Array(Schema.Number)), { default: () => [2] })
|
|
49
|
+
}));
|
|
50
|
+
const SourceConfig = Schema.mutable(Schema.Struct({
|
|
51
|
+
url: Schema.String,
|
|
52
|
+
ref: Schema.optional(Schema.String)
|
|
53
|
+
}));
|
|
54
|
+
const ThemeConfig = Schema.Union(Schema.String, Schema.mutable(Schema.Struct({
|
|
55
|
+
light: Schema.String,
|
|
56
|
+
dark: Schema.String
|
|
57
|
+
})), Schema.mutable(Schema.Record({
|
|
58
|
+
key: Schema.String,
|
|
59
|
+
value: Schema.Unknown
|
|
60
|
+
})));
|
|
61
|
+
/**
|
|
62
|
+
* Built-in default categories
|
|
63
|
+
*/
|
|
64
|
+
const DEFAULT_CATEGORIES = {
|
|
65
|
+
classes: {
|
|
66
|
+
displayName: "Classes",
|
|
67
|
+
singularName: "Class",
|
|
68
|
+
folderName: "class",
|
|
69
|
+
itemKinds: [ApiItemKind.Class],
|
|
70
|
+
collapsible: true,
|
|
71
|
+
collapsed: true,
|
|
72
|
+
overviewHeaders: [2]
|
|
73
|
+
},
|
|
74
|
+
interfaces: {
|
|
75
|
+
displayName: "Interfaces",
|
|
76
|
+
singularName: "Interface",
|
|
77
|
+
folderName: "interface",
|
|
78
|
+
itemKinds: [ApiItemKind.Interface],
|
|
79
|
+
collapsible: true,
|
|
80
|
+
collapsed: true,
|
|
81
|
+
overviewHeaders: [2]
|
|
82
|
+
},
|
|
83
|
+
functions: {
|
|
84
|
+
displayName: "Functions",
|
|
85
|
+
singularName: "Function",
|
|
86
|
+
folderName: "function",
|
|
87
|
+
itemKinds: [ApiItemKind.Function],
|
|
88
|
+
collapsible: true,
|
|
89
|
+
collapsed: true,
|
|
90
|
+
overviewHeaders: [2]
|
|
91
|
+
},
|
|
92
|
+
types: {
|
|
93
|
+
displayName: "Types",
|
|
94
|
+
singularName: "Type",
|
|
95
|
+
folderName: "type",
|
|
96
|
+
itemKinds: [ApiItemKind.TypeAlias],
|
|
97
|
+
collapsible: true,
|
|
98
|
+
collapsed: true,
|
|
99
|
+
overviewHeaders: [2]
|
|
100
|
+
},
|
|
101
|
+
enums: {
|
|
102
|
+
displayName: "Enums",
|
|
103
|
+
singularName: "Enum",
|
|
104
|
+
folderName: "enum",
|
|
105
|
+
itemKinds: [ApiItemKind.Enum],
|
|
106
|
+
collapsible: true,
|
|
107
|
+
collapsed: true,
|
|
108
|
+
overviewHeaders: [2]
|
|
109
|
+
},
|
|
110
|
+
variables: {
|
|
111
|
+
displayName: "Variables",
|
|
112
|
+
singularName: "Variable",
|
|
113
|
+
folderName: "variable",
|
|
114
|
+
itemKinds: [ApiItemKind.Variable],
|
|
115
|
+
collapsible: true,
|
|
116
|
+
collapsed: true,
|
|
117
|
+
overviewHeaders: [2]
|
|
118
|
+
},
|
|
119
|
+
namespaces: {
|
|
120
|
+
displayName: "Namespaces",
|
|
121
|
+
singularName: "Namespace",
|
|
122
|
+
folderName: "namespace",
|
|
123
|
+
itemKinds: [ApiItemKind.Namespace],
|
|
124
|
+
collapsible: true,
|
|
125
|
+
collapsed: true,
|
|
126
|
+
overviewHeaders: [2]
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
/** Reusable categories record (internal helper) */
|
|
130
|
+
const CategoriesRecord = Schema.mutable(Schema.Record({
|
|
131
|
+
key: Schema.String,
|
|
132
|
+
value: CategoryConfig
|
|
133
|
+
}));
|
|
134
|
+
const VersionConfig = Schema.mutable(Schema.Struct({
|
|
135
|
+
model: ModelInput,
|
|
136
|
+
packageJson: Schema.optional(ModelInput),
|
|
137
|
+
categories: Schema.optional(CategoriesRecord),
|
|
138
|
+
source: Schema.optional(SourceConfig),
|
|
139
|
+
externalPackages: Schema.optional(Schema.mutable(Schema.Array(ExternalPackageSpec))),
|
|
140
|
+
autoDetectDependencies: Schema.optional(AutoDetectDependencies),
|
|
141
|
+
ogImage: Schema.optional(OpenGraphImageConfig),
|
|
142
|
+
llmsPlugin: Schema.optional(LlmsPlugin),
|
|
143
|
+
tsconfig: Schema.optional(ModelInput),
|
|
144
|
+
compilerOptions: Schema.optional(Schema.Unknown)
|
|
145
|
+
}));
|
|
146
|
+
/** Union for the versions record value: can be a path/function OR a full VersionConfig */
|
|
147
|
+
const VersionValue = Schema.Union(ModelInput, VersionConfig);
|
|
148
|
+
const SingleApiConfig = Schema.mutable(Schema.Struct({
|
|
149
|
+
packageName: Schema.String,
|
|
150
|
+
name: Schema.optional(Schema.String),
|
|
151
|
+
baseRoute: Schema.optional(Schema.String),
|
|
152
|
+
apiFolder: Schema.optional(Schema.Union(Schema.String, Schema.Null)),
|
|
153
|
+
model: Schema.optional(ModelInput),
|
|
154
|
+
packageJson: Schema.optional(ModelInput),
|
|
155
|
+
versions: Schema.optional(Schema.mutable(Schema.Record({
|
|
156
|
+
key: Schema.String,
|
|
157
|
+
value: VersionValue
|
|
158
|
+
}))),
|
|
159
|
+
theme: Schema.optional(ThemeConfig),
|
|
160
|
+
categories: Schema.optional(CategoriesRecord),
|
|
161
|
+
source: Schema.optional(SourceConfig),
|
|
162
|
+
externalPackages: Schema.optional(Schema.mutable(Schema.Array(ExternalPackageSpec))),
|
|
163
|
+
autoDetectDependencies: Schema.optional(AutoDetectDependencies),
|
|
164
|
+
ogImage: Schema.optional(OpenGraphImageConfig),
|
|
165
|
+
llmsPlugin: Schema.optional(LlmsPlugin),
|
|
166
|
+
tsconfig: Schema.optional(ModelInput),
|
|
167
|
+
compilerOptions: Schema.optional(Schema.Unknown)
|
|
168
|
+
}));
|
|
169
|
+
const MultiApiConfig = Schema.mutable(Schema.Struct({
|
|
170
|
+
packageName: Schema.String,
|
|
171
|
+
name: Schema.optional(Schema.String),
|
|
172
|
+
baseRoute: Schema.optional(Schema.String),
|
|
173
|
+
apiFolder: Schema.optional(Schema.Union(Schema.String, Schema.Null)),
|
|
174
|
+
model: ModelInput,
|
|
175
|
+
packageJson: Schema.optional(ModelInput),
|
|
176
|
+
theme: Schema.optional(ThemeConfig),
|
|
177
|
+
categories: Schema.optional(CategoriesRecord),
|
|
178
|
+
source: Schema.optional(SourceConfig),
|
|
179
|
+
externalPackages: Schema.optional(Schema.mutable(Schema.Array(ExternalPackageSpec))),
|
|
180
|
+
autoDetectDependencies: Schema.optional(AutoDetectDependencies),
|
|
181
|
+
ogImage: Schema.optional(OpenGraphImageConfig),
|
|
182
|
+
llmsPlugin: Schema.optional(LlmsPlugin),
|
|
183
|
+
tsconfig: Schema.optional(ModelInput),
|
|
184
|
+
compilerOptions: Schema.optional(Schema.Unknown)
|
|
185
|
+
}));
|
|
186
|
+
const PluginOptions = Schema.mutable(Schema.Struct({
|
|
187
|
+
api: Schema.optional(SingleApiConfig),
|
|
188
|
+
apis: Schema.optional(Schema.mutable(Schema.Array(MultiApiConfig))),
|
|
189
|
+
siteUrl: Schema.optional(Schema.String),
|
|
190
|
+
ogImage: Schema.optional(OpenGraphImageConfig),
|
|
191
|
+
defaultCategories: Schema.optional(CategoriesRecord),
|
|
192
|
+
errors: Schema.optional(ErrorConfig),
|
|
193
|
+
llmsPlugin: Schema.optional(Schema.Union(Schema.Boolean, LlmsPlugin)),
|
|
194
|
+
logLevel: Schema.optional(LogLevel$1),
|
|
195
|
+
performance: Schema.optional(PerformanceConfig)
|
|
196
|
+
}));
|
|
197
|
+
|
|
198
|
+
//#endregion
|
|
199
|
+
export { AutoDetectDependencies, CategoryConfig, DEFAULT_CATEGORIES, ErrorConfig, ExternalPackageSpec, LlmsPlugin, LogLevel$1 as LogLevel, ModelInput, MultiApiConfig, PluginOptions, SingleApiConfig, SourceConfig, ThemeConfig, VersionConfig };
|
package/schemas/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { OpenGraphImageConfig, OpenGraphImageMetadata } from "./opengraph.js";
|
|
2
|
+
import { PerformanceConfig, PerformanceThresholds } from "./performance.js";
|
|
3
|
+
import { AutoDetectDependencies, CategoryConfig, DEFAULT_CATEGORIES, ErrorConfig, ExternalPackageSpec, LlmsPlugin, LogLevel, ModelInput, MultiApiConfig, PluginOptions, SingleApiConfig, SourceConfig, ThemeConfig, VersionConfig } from "./config.js";
|
|
4
|
+
|
|
5
|
+
export { };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/opengraph.ts
|
|
4
|
+
const OpenGraphImageMetadata = Schema.mutable(Schema.Struct({
|
|
5
|
+
url: Schema.String,
|
|
6
|
+
secureUrl: Schema.optional(Schema.String),
|
|
7
|
+
type: Schema.optional(Schema.String),
|
|
8
|
+
width: Schema.optional(Schema.Number),
|
|
9
|
+
height: Schema.optional(Schema.Number),
|
|
10
|
+
alt: Schema.optional(Schema.String)
|
|
11
|
+
}));
|
|
12
|
+
const OpenGraphImageConfig = Schema.Union(Schema.String, OpenGraphImageMetadata);
|
|
13
|
+
const OpenGraphMetadata = Schema.mutable(Schema.Struct({
|
|
14
|
+
siteUrl: Schema.String,
|
|
15
|
+
pageRoute: Schema.String,
|
|
16
|
+
description: Schema.String,
|
|
17
|
+
publishedTime: Schema.String,
|
|
18
|
+
modifiedTime: Schema.String,
|
|
19
|
+
section: Schema.String,
|
|
20
|
+
tags: Schema.mutable(Schema.Array(Schema.String)),
|
|
21
|
+
ogImage: Schema.optional(OpenGraphImageMetadata),
|
|
22
|
+
ogType: Schema.String
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { OpenGraphImageConfig, OpenGraphImageMetadata };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/performance.ts
|
|
4
|
+
const PerformanceThresholds = Schema.mutable(Schema.Struct({
|
|
5
|
+
slowCodeBlock: Schema.optionalWith(Schema.Number, { default: () => 100 }),
|
|
6
|
+
slowPageGeneration: Schema.optionalWith(Schema.Number, { default: () => 500 }),
|
|
7
|
+
slowApiLoad: Schema.optionalWith(Schema.Number, { default: () => 1e3 }),
|
|
8
|
+
slowFileOperation: Schema.optionalWith(Schema.Number, { default: () => 50 }),
|
|
9
|
+
slowHttpRequest: Schema.optionalWith(Schema.Number, { default: () => 2e3 }),
|
|
10
|
+
slowDbOperation: Schema.optionalWith(Schema.Number, { default: () => 100 })
|
|
11
|
+
}));
|
|
12
|
+
const PerformanceConfig = Schema.mutable(Schema.Struct({
|
|
13
|
+
thresholds: Schema.optional(PerformanceThresholds),
|
|
14
|
+
showInsights: Schema.optionalWith(Schema.Boolean, { default: () => true }),
|
|
15
|
+
trackDetailedMetrics: Schema.optionalWith(Schema.Boolean, { default: () => false })
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { PerformanceConfig, PerformanceThresholds };
|
package/serve.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
//#region src/serve.ts
|
|
4
|
+
const DEFAULT_PORT = 4173;
|
|
5
|
+
/**
|
|
6
|
+
* Readiness heuristic over a chunk of server output. Both RSPress `dev` and
|
|
7
|
+
* `preview` print a `Local:` address line once the server is listening, which
|
|
8
|
+
* is the reliable cross-mode signal. `dev` additionally prints a
|
|
9
|
+
* "ready ... built in" line, kept as a fallback in case the address-line format
|
|
10
|
+
* changes. Pure and exported so it can be unit-tested and reused as a
|
|
11
|
+
* {@link ServeOptions.readyWhen} building block.
|
|
12
|
+
*/
|
|
13
|
+
function isServerReady(mode, output) {
|
|
14
|
+
if (output.includes("Local:")) return true;
|
|
15
|
+
if (mode === "dev") return output.includes("ready") && output.includes("built in");
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve {@link ServeOptions} into a concrete {@link ResolvedServeConfig},
|
|
20
|
+
* applying all defaults. Pure (modulo reading `process.env`) and exported so
|
|
21
|
+
* the resolution logic can be unit-tested without spawning a server.
|
|
22
|
+
*/
|
|
23
|
+
function resolveServeConfig(options = {}) {
|
|
24
|
+
const mode = options.mode ?? "dev";
|
|
25
|
+
const port = options.port ?? (mode === "dev" ? Number(process.env.DEV_PORT) || DEFAULT_PORT : DEFAULT_PORT);
|
|
26
|
+
const open = options.open ?? !process.env.NO_OPEN;
|
|
27
|
+
const openPath = options.openPath ?? "/";
|
|
28
|
+
const packageManager = options.packageManager ?? "pnpm";
|
|
29
|
+
const cwd = options.cwd ?? process.cwd();
|
|
30
|
+
const isReady = options.readyWhen ?? ((output) => isServerReady(mode, output));
|
|
31
|
+
const normalizedPath = openPath.startsWith("/") ? openPath : `/${openPath}`;
|
|
32
|
+
return {
|
|
33
|
+
mode,
|
|
34
|
+
port,
|
|
35
|
+
open,
|
|
36
|
+
openPath,
|
|
37
|
+
packageManager,
|
|
38
|
+
cwd,
|
|
39
|
+
args: [
|
|
40
|
+
"rspress",
|
|
41
|
+
mode,
|
|
42
|
+
"--port",
|
|
43
|
+
String(port)
|
|
44
|
+
],
|
|
45
|
+
url: `http://localhost:${port}${normalizedPath}`,
|
|
46
|
+
isReady
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/* v8 ignore start -- spawns child processes / opens a browser; covered by the site smoke test, not unit tests */
|
|
50
|
+
/**
|
|
51
|
+
* Best-effort kill of any process listening on `port` (frees a stale dev/preview
|
|
52
|
+
* server). Invokes `lsof` directly via `execFileSync` (no shell), so the port is
|
|
53
|
+
* never interpolated into a shell string. A no-op on platforms without `lsof`
|
|
54
|
+
* (e.g. Windows) or for a non-positive-integer port.
|
|
55
|
+
*/
|
|
56
|
+
function killProcessOnPort(port) {
|
|
57
|
+
if (!Number.isInteger(port) || port <= 0) return;
|
|
58
|
+
try {
|
|
59
|
+
const pids = execFileSync("lsof", [
|
|
60
|
+
"-t",
|
|
61
|
+
"-i",
|
|
62
|
+
`:${port}`
|
|
63
|
+
], { encoding: "utf-8" }).trim().split("\n").filter(Boolean);
|
|
64
|
+
for (const pid of pids) process.kill(Number(pid), "SIGTERM");
|
|
65
|
+
if (pids.length > 0) console.log(`Killed process(es) on port ${port}: ${pids.join(", ")}`);
|
|
66
|
+
} catch {}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Run an RSPress `dev` or `preview` server, freeing the port first and opening a
|
|
70
|
+
* browser once the server is ready. A drop-in replacement for the per-site
|
|
71
|
+
* `dev.mts` / `preview.mts` scripts:
|
|
72
|
+
*
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { serve } from "rspress-plugin-api-extractor";
|
|
75
|
+
*
|
|
76
|
+
* await serve({ mode: "dev", openPath: "/api/" });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* This runs the server for the lifetime of the host process and calls
|
|
80
|
+
* `process.exit` when the server exits (matching a top-level script runner). The
|
|
81
|
+
* returned promise resolves once the server is ready and the browser has been
|
|
82
|
+
* opened; it does not resolve when the server stops. Port-freeing and browser
|
|
83
|
+
* opening are best-effort and never reject.
|
|
84
|
+
*/
|
|
85
|
+
async function serve(options = {}) {
|
|
86
|
+
const config = resolveServeConfig(options);
|
|
87
|
+
killProcessOnPort(config.port);
|
|
88
|
+
const child = spawn(config.packageManager, config.args, {
|
|
89
|
+
cwd: config.cwd,
|
|
90
|
+
stdio: [
|
|
91
|
+
"inherit",
|
|
92
|
+
"pipe",
|
|
93
|
+
"pipe"
|
|
94
|
+
],
|
|
95
|
+
env: {
|
|
96
|
+
...process.env,
|
|
97
|
+
FORCE_COLOR: "1"
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const waitForReady = new Promise((resolve) => {
|
|
101
|
+
let resolved = false;
|
|
102
|
+
const handleOutput = (data) => {
|
|
103
|
+
const output = data.toString();
|
|
104
|
+
process.stdout.write(data);
|
|
105
|
+
if (!resolved && config.isReady(output)) {
|
|
106
|
+
resolved = true;
|
|
107
|
+
resolve();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
child.stdout?.on("data", handleOutput);
|
|
111
|
+
child.stderr?.on("data", handleOutput);
|
|
112
|
+
});
|
|
113
|
+
child.on("error", (error) => {
|
|
114
|
+
console.error(`Failed to start rspress ${config.mode} server:`, error);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
child.on("exit", (code) => {
|
|
118
|
+
console.log(`Rspress ${config.mode} server exited`);
|
|
119
|
+
process.exit(code ?? 0);
|
|
120
|
+
});
|
|
121
|
+
await waitForReady;
|
|
122
|
+
if (config.open) try {
|
|
123
|
+
const { default: open } = await import("open");
|
|
124
|
+
await open(config.url);
|
|
125
|
+
console.log(`✅ Opened ${config.url}`);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("Failed to open browser:", error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/* v8 ignore stop */
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
export { isServerReady, resolveServeConfig, serve };
|