@rspress/plugin-api-docgen 2.0.0-beta.8 → 2.0.0-rc.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 +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +63 -60
- package/package.json +15 -18
- package/static/global-components/API.tsx +16 -13
- package/index.d.ts +0 -7
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CompilerOptions } from 'typescript';
|
|
2
2
|
import type { ParserOptions } from 'react-docgen-typescript';
|
|
3
|
-
import type { RspressPlugin } from '@rspress/
|
|
3
|
+
import type { RspressPlugin } from '@rspress/core';
|
|
4
4
|
|
|
5
5
|
declare type ApiParseTool = 'documentation' | 'react-docgen-typescript';
|
|
6
6
|
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(__dirname, '..');
|
|
1
|
+
import node_fs from "node:fs";
|
|
2
|
+
import node_path from "node:path";
|
|
3
|
+
import { RSPRESS_TEMP_DIR, logger } from "@rspress/core";
|
|
4
|
+
import chokidar from "chokidar";
|
|
5
|
+
import { withCompilerOptions, withCustomConfig, withDefaultConfig } from "react-docgen-typescript";
|
|
6
|
+
node_path.join(__dirname, '..');
|
|
8
7
|
const apiDocMap = {};
|
|
9
8
|
const locales = {
|
|
10
9
|
zh: {
|
|
11
|
-
copy:
|
|
12
|
-
copied:
|
|
13
|
-
expand:
|
|
14
|
-
collapse:
|
|
15
|
-
className:
|
|
16
|
-
style:
|
|
17
|
-
children:
|
|
18
|
-
disabled:
|
|
19
|
-
required:
|
|
20
|
-
property:
|
|
21
|
-
description:
|
|
22
|
-
type:
|
|
23
|
-
defaultValue:
|
|
24
|
-
overview:
|
|
10
|
+
copy: '复制',
|
|
11
|
+
copied: '复制成功',
|
|
12
|
+
expand: '展开代码',
|
|
13
|
+
collapse: '收起代码',
|
|
14
|
+
className: '节点类名',
|
|
15
|
+
style: '节点样式',
|
|
16
|
+
children: '子节点',
|
|
17
|
+
disabled: '是否禁用',
|
|
18
|
+
required: '必填',
|
|
19
|
+
property: '属性',
|
|
20
|
+
description: '说明',
|
|
21
|
+
type: '类型',
|
|
22
|
+
defaultValue: '默认值',
|
|
23
|
+
overview: '概览'
|
|
25
24
|
},
|
|
26
25
|
en: {
|
|
27
26
|
copy: 'Copy',
|
|
@@ -40,20 +39,20 @@ const locales = {
|
|
|
40
39
|
overview: 'Overview'
|
|
41
40
|
},
|
|
42
41
|
ru: {
|
|
43
|
-
copy:
|
|
44
|
-
copied:
|
|
45
|
-
expand:
|
|
46
|
-
collapse:
|
|
47
|
-
className:
|
|
48
|
-
style:
|
|
49
|
-
children:
|
|
50
|
-
disabled:
|
|
51
|
-
required:
|
|
52
|
-
property:
|
|
53
|
-
description:
|
|
54
|
-
type:
|
|
55
|
-
defaultValue:
|
|
56
|
-
overview:
|
|
42
|
+
copy: 'Копировать',
|
|
43
|
+
copied: 'Скопировано успешно',
|
|
44
|
+
expand: 'Развернуть код',
|
|
45
|
+
collapse: 'Свернуть код',
|
|
46
|
+
className: 'Имя класса узла',
|
|
47
|
+
style: 'Стиль узла',
|
|
48
|
+
children: 'Дочерние элементы',
|
|
49
|
+
disabled: 'Отключено',
|
|
50
|
+
required: 'Обязательно',
|
|
51
|
+
property: 'Свойство',
|
|
52
|
+
description: 'Описание',
|
|
53
|
+
type: 'Тип',
|
|
54
|
+
defaultValue: 'Значение по умолчанию',
|
|
55
|
+
overview: 'Обзор'
|
|
57
56
|
}
|
|
58
57
|
};
|
|
59
58
|
const isToolEntries = (obj)=>!!obj.documentation || !!obj["react-docgen-typescript"];
|
|
@@ -62,7 +61,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
62
61
|
const genApiDoc = async (entry, tool)=>{
|
|
63
62
|
if (0 === Object.keys(entry).length) return;
|
|
64
63
|
await Promise.all(Object.entries(entry).map(async ([key, value])=>{
|
|
65
|
-
const moduleSourceFilePath =
|
|
64
|
+
const moduleSourceFilePath = node_path.resolve(appDir, value);
|
|
66
65
|
watchFileMap[moduleSourceFilePath] = {
|
|
67
66
|
apiParseTool,
|
|
68
67
|
moduleName: key
|
|
@@ -91,22 +90,21 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
91
90
|
},
|
|
92
91
|
...restOptions
|
|
93
92
|
};
|
|
94
|
-
let fileParser =
|
|
95
|
-
if (tsconfigPath?.[key]) fileParser =
|
|
96
|
-
else if (compilerOptions?.[key]) fileParser =
|
|
93
|
+
let fileParser = withDefaultConfig(parserOpts);
|
|
94
|
+
if (tsconfigPath?.[key]) fileParser = withCustomConfig(tsconfigPath[key], parserOpts);
|
|
95
|
+
else if (compilerOptions?.[key]) fileParser = withCompilerOptions(compilerOptions[key], parserOpts);
|
|
97
96
|
const componentDoc = fileParser.parse(moduleSourceFilePath);
|
|
98
|
-
if (0 === componentDoc.length)
|
|
99
|
-
|
|
97
|
+
if (0 === componentDoc.length) logger.warn('[module-doc-plugin]', `Unable to parse API document in ${moduleSourceFilePath}`);
|
|
98
|
+
languages.forEach((language)=>{
|
|
100
99
|
apiDocMap[`${key}-${language}`] = generateTable(componentDoc, language);
|
|
101
100
|
});
|
|
102
|
-
else apiDocMap[key] = generateTable(componentDoc, 'en');
|
|
103
101
|
}
|
|
104
102
|
} catch (e) {
|
|
105
|
-
if (e instanceof Error)
|
|
103
|
+
if (e instanceof Error) logger.error('[module-doc-plugin]', 'Generate API table error:\n', e);
|
|
106
104
|
}
|
|
107
105
|
}));
|
|
108
106
|
};
|
|
109
|
-
|
|
107
|
+
logger.info('[module-doc-plugin]', 'Start to generate API table...');
|
|
110
108
|
if (isToolEntries(entries)) {
|
|
111
109
|
const reactEntries = entries["react-docgen-typescript"];
|
|
112
110
|
const documentationEntries = entries.documentation;
|
|
@@ -116,7 +114,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
116
114
|
]);
|
|
117
115
|
} else await genApiDoc(entries, apiParseTool);
|
|
118
116
|
if (!isProd) {
|
|
119
|
-
const watcher =
|
|
117
|
+
const watcher = chokidar.watch(Object.keys(watchFileMap), {
|
|
120
118
|
ignoreInitial: true,
|
|
121
119
|
ignorePermissionErrors: true,
|
|
122
120
|
ignored: [
|
|
@@ -127,12 +125,12 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
127
125
|
watcher.on('change', (changed)=>{
|
|
128
126
|
if (isUpdate) return;
|
|
129
127
|
isUpdate = true;
|
|
130
|
-
|
|
128
|
+
logger.info('[module-doc-plugin]', 'updating API');
|
|
131
129
|
const watchFileInfo = watchFileMap[changed];
|
|
132
130
|
if (watchFileInfo) {
|
|
133
131
|
const { apiParseTool, moduleName } = watchFileInfo;
|
|
134
132
|
const updateSiteData = ()=>{
|
|
135
|
-
const siteDataPath =
|
|
133
|
+
const siteDataPath = node_path.join(process.cwd(), 'node_modules', RSPRESS_TEMP_DIR, 'runtime', 'virtual-site-data.mjs');
|
|
136
134
|
import(siteDataPath).then((siteData)=>{
|
|
137
135
|
const data = {
|
|
138
136
|
...siteData.default
|
|
@@ -140,7 +138,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
140
138
|
data.pages.forEach((page)=>{
|
|
141
139
|
page.apiDocMap = apiDocMap;
|
|
142
140
|
});
|
|
143
|
-
|
|
141
|
+
node_fs.writeFileSync(siteDataPath, `export default ${JSON.stringify(data)}`);
|
|
144
142
|
isUpdate = false;
|
|
145
143
|
});
|
|
146
144
|
};
|
|
@@ -150,12 +148,12 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
|
|
|
150
148
|
}
|
|
151
149
|
});
|
|
152
150
|
}
|
|
153
|
-
|
|
151
|
+
logger.success('[module-doc-plugin]', 'Generate API table successfully!');
|
|
154
152
|
};
|
|
155
153
|
function generateTable(componentDoc, language) {
|
|
156
154
|
return componentDoc.map((param)=>{
|
|
157
155
|
const { props } = param;
|
|
158
|
-
const t = locales[language];
|
|
156
|
+
const t = locales[language] ?? locales.en;
|
|
159
157
|
const PROP_TABLE_HEADER = `|${t.property}|${t.description}|${t.type}|${t.defaultValue}|\n|:---:|:---:|:---:|:---:|`;
|
|
160
158
|
const tableContent = Object.keys(props).filter((propName)=>{
|
|
161
159
|
const { name, description } = props[propName];
|
|
@@ -208,11 +206,15 @@ function pluginApiDocgen(options) {
|
|
|
208
206
|
return config;
|
|
209
207
|
},
|
|
210
208
|
async beforeBuild (config, isProd) {
|
|
211
|
-
|
|
209
|
+
let languages = (config.themeConfig?.locales?.map((locale)=>locale.lang) || config.locales?.map((locale)=>locale.lang) || []).filter((lang)=>[
|
|
212
210
|
'zh',
|
|
213
211
|
'en',
|
|
214
212
|
'ru'
|
|
215
213
|
].includes(lang));
|
|
214
|
+
const defaultLang = config.lang || 'en';
|
|
215
|
+
if (0 === languages.length) languages = [
|
|
216
|
+
defaultLang
|
|
217
|
+
];
|
|
216
218
|
await docgen({
|
|
217
219
|
entries,
|
|
218
220
|
apiParseTool,
|
|
@@ -221,33 +223,34 @@ function pluginApiDocgen(options) {
|
|
|
221
223
|
parseToolOptions,
|
|
222
224
|
isProd
|
|
223
225
|
});
|
|
226
|
+
config.builderConfig = config.builderConfig || {};
|
|
227
|
+
config.builderConfig.source = config.builderConfig.source || {};
|
|
228
|
+
config.builderConfig.source.define = {
|
|
229
|
+
...config.builderConfig.source.define,
|
|
230
|
+
RSPRESS_PLUGIN_API_DOCGEN_MAP: JSON.stringify(apiDocMap)
|
|
231
|
+
};
|
|
224
232
|
},
|
|
225
233
|
async modifySearchIndexData (pages) {
|
|
226
234
|
const apiCompRegExp = /(<API\s+moduleName=['"](\S+)['"]\s*(.*)?\/>)|(<API\s+moduleName=['"](\S+)['"]\s*(.*)?>(.*)?<\/API>)/;
|
|
227
235
|
await Promise.all(pages.map(async (page)=>{
|
|
228
236
|
const { _filepath, lang } = page;
|
|
229
|
-
let content = await
|
|
237
|
+
let content = await node_fs.promises.readFile(_filepath, 'utf-8');
|
|
230
238
|
let matchResult = apiCompRegExp.exec(content);
|
|
231
239
|
if (!matchResult) return;
|
|
232
240
|
while(null !== matchResult){
|
|
233
241
|
const matchContent = matchResult[0];
|
|
234
242
|
const moduleName = matchResult[2] ?? matchResult[5] ?? '';
|
|
235
|
-
const apiDoc = apiDocMap[
|
|
236
|
-
if (matchContent && !apiDoc)
|
|
243
|
+
const apiDoc = apiDocMap[`${moduleName}-${lang ? lang : 'en'}`] ?? '';
|
|
244
|
+
if (matchContent && !apiDoc) logger.warn(`No api doc found for module: ${moduleName} in lang: ${lang ?? 'en'}`);
|
|
237
245
|
content = content.replace(matchContent, apiDoc);
|
|
238
246
|
matchResult = apiCompRegExp.exec(content);
|
|
239
247
|
}
|
|
240
248
|
page.content = content;
|
|
241
249
|
}));
|
|
242
250
|
},
|
|
243
|
-
extendPageData (pageData) {
|
|
244
|
-
pageData.apiDocMap = {
|
|
245
|
-
...apiDocMap
|
|
246
|
-
};
|
|
247
|
-
},
|
|
248
251
|
markdown: {
|
|
249
252
|
globalComponents: [
|
|
250
|
-
|
|
253
|
+
node_path.join(__dirname, '..', 'static', 'global-components', 'API.tsx')
|
|
251
254
|
]
|
|
252
255
|
}
|
|
253
256
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rspress/plugin-api-docgen",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc.0",
|
|
4
4
|
"description": "A plugin for rspress to generate api doc.",
|
|
5
5
|
"bugs": "https://github.com/web-infra-dev/rspress/issues",
|
|
6
6
|
"repository": {
|
|
@@ -12,43 +12,41 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"types": "./index.d.ts",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
|
-
"types": "./index.d.ts",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
|
-
"static"
|
|
23
|
-
"index.d.ts"
|
|
22
|
+
"static"
|
|
24
23
|
],
|
|
25
24
|
"dependencies": {
|
|
26
25
|
"chokidar": "^3.6.0",
|
|
27
26
|
"documentation": "14.0.3",
|
|
28
27
|
"github-slugger": "^2.0.0",
|
|
29
|
-
"react-docgen-typescript": "2.
|
|
28
|
+
"react-docgen-typescript": "2.4.0",
|
|
30
29
|
"react-markdown": "^10.1.0",
|
|
31
30
|
"remark-gfm": "^4.0.1",
|
|
32
31
|
"unified": "^11.0.5",
|
|
33
|
-
"unist-util-visit": "^5.0.0"
|
|
34
|
-
"@rspress/shared": "2.0.0-beta.8"
|
|
32
|
+
"unist-util-visit": "^5.0.0"
|
|
35
33
|
},
|
|
36
34
|
"devDependencies": {
|
|
37
|
-
"@microsoft/api-extractor": "^7.
|
|
38
|
-
"@rslib/core": "0.
|
|
35
|
+
"@microsoft/api-extractor": "^7.54.0",
|
|
36
|
+
"@rslib/core": "0.16.1",
|
|
39
37
|
"@types/hast": "^3.0.4",
|
|
40
38
|
"@types/mdast": "^4.0.4",
|
|
41
39
|
"@types/node": "^22.8.1",
|
|
42
|
-
"@types/react": "^
|
|
43
|
-
"@types/react-dom": "^
|
|
44
|
-
"react": "^19.
|
|
45
|
-
"react-dom": "^19.
|
|
46
|
-
"react-router-dom": "^6.
|
|
47
|
-
"rsbuild-plugin-publint": "^0.3.
|
|
40
|
+
"@types/react": "^19.2.2",
|
|
41
|
+
"@types/react-dom": "^19.2.2",
|
|
42
|
+
"react": "^19.2.0",
|
|
43
|
+
"react-dom": "^19.2.0",
|
|
44
|
+
"react-router-dom": "^6.30.1",
|
|
45
|
+
"rsbuild-plugin-publint": "^0.3.3",
|
|
48
46
|
"typescript": "^5.8.2"
|
|
49
47
|
},
|
|
50
48
|
"peerDependencies": {
|
|
51
|
-
"@rspress/core": "^2.0.0-
|
|
49
|
+
"@rspress/core": "^2.0.0-rc.0",
|
|
52
50
|
"typescript": "^5.8.2"
|
|
53
51
|
},
|
|
54
52
|
"peerDependenciesMeta": {
|
|
@@ -61,7 +59,6 @@
|
|
|
61
59
|
},
|
|
62
60
|
"publishConfig": {
|
|
63
61
|
"access": "public",
|
|
64
|
-
"provenance": true,
|
|
65
62
|
"registry": "https://registry.npmjs.org/"
|
|
66
63
|
},
|
|
67
64
|
"scripts": {
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { useLang } from '@rspress/core/runtime';
|
|
2
|
+
// @ts-expect-error @theme is overridden by alias in @rspress/core
|
|
3
|
+
import { getCustomMDXComponent } from '@theme';
|
|
4
|
+
import GithubSlugger from 'github-slugger';
|
|
5
|
+
import type { Content, Element, Root } from 'hast';
|
|
5
6
|
import ReactMarkdown from 'react-markdown';
|
|
6
7
|
import remarkGfm from 'remark-gfm';
|
|
7
8
|
import './API.css';
|
|
8
|
-
import GithubSlugger from 'github-slugger';
|
|
9
|
-
import type { Content, Element, Root } from 'hast';
|
|
10
9
|
// biome-ignore lint/style/useImportType: <exact>
|
|
11
10
|
import React from 'react';
|
|
12
11
|
import type { Plugin } from 'unified';
|
|
13
12
|
import { visit } from 'unist-util-visit';
|
|
14
13
|
|
|
14
|
+
declare global {
|
|
15
|
+
var RSPRESS_PLUGIN_API_DOCGEN_MAP: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
|
|
15
18
|
function headingRank(node: Root | Content): number | null {
|
|
16
19
|
const name =
|
|
17
20
|
(node && node.type === 'element' && node.tagName.toLowerCase()) || '';
|
|
@@ -36,7 +39,7 @@ const rehypeHeaderAnchor: Plugin<[], Root> = () => {
|
|
|
36
39
|
if (!node.properties?.id) {
|
|
37
40
|
const text = collectHeaderText(node);
|
|
38
41
|
node.properties ??= {};
|
|
39
|
-
node.properties.id = slugger.slug(text);
|
|
42
|
+
node.properties.id = slugger.slug(text.trim());
|
|
40
43
|
}
|
|
41
44
|
// apply to headings
|
|
42
45
|
node.children.unshift(create(node));
|
|
@@ -57,7 +60,7 @@ function create(node: Element): Element {
|
|
|
57
60
|
type: 'element',
|
|
58
61
|
tagName: 'a',
|
|
59
62
|
properties: {
|
|
60
|
-
class: 'header-anchor',
|
|
63
|
+
class: 'rp-header-anchor',
|
|
61
64
|
ariaHidden: 'true',
|
|
62
65
|
href: `#${node.properties!.id}`,
|
|
63
66
|
},
|
|
@@ -97,15 +100,13 @@ const collectHeaderText = (node: Element): string => {
|
|
|
97
100
|
return text;
|
|
98
101
|
};
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
const API = (props: { moduleName: string }) => {
|
|
101
104
|
const lang = useLang();
|
|
102
|
-
const { page } = usePageData();
|
|
103
105
|
const { moduleName } = props;
|
|
104
106
|
// some api doc have two languages.
|
|
105
|
-
const apiDocMap =
|
|
107
|
+
const apiDocMap = RSPRESS_PLUGIN_API_DOCGEN_MAP;
|
|
106
108
|
// avoid error when no page data
|
|
107
|
-
const apiDoc =
|
|
108
|
-
apiDocMap?.[moduleName] || apiDocMap?.[`${moduleName}-${lang}`] || '';
|
|
109
|
+
const apiDoc = apiDocMap?.[`${moduleName}-${lang}`] || '';
|
|
109
110
|
return (
|
|
110
111
|
<div className="rspress-plugin-api-docgen">
|
|
111
112
|
<ReactMarkdown
|
|
@@ -121,3 +122,5 @@ export default (props: { moduleName: string }) => {
|
|
|
121
122
|
</div>
|
|
122
123
|
);
|
|
123
124
|
};
|
|
125
|
+
|
|
126
|
+
export default API;
|