@rspress/plugin-api-docgen 2.0.0-beta.0 → 2.0.0-beta.10
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.js +243 -310
- package/package.json +24 -18
- package/static/global-components/API.tsx +92 -0
- package/mdx-meta-loader.cjs +0 -26
package/README.md
CHANGED
package/dist/index.js
CHANGED
@@ -1,322 +1,255 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs";
|
2
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
|
3
|
+
import * as __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__ from "@rspress/shared/logger";
|
4
|
+
import * as __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__ from "@rspress/shared";
|
5
|
+
import * as __WEBPACK_EXTERNAL_MODULE_chokidar__ from "chokidar";
|
6
|
+
import * as __WEBPACK_EXTERNAL_MODULE_react_docgen_typescript_e816f54f__ from "react-docgen-typescript";
|
7
|
+
__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(__dirname, '..');
|
8
|
+
const apiDocMap = {};
|
9
|
+
const locales = {
|
10
|
+
zh: {
|
11
|
+
copy: "\u590D\u5236",
|
12
|
+
copied: "\u590D\u5236\u6210\u529F",
|
13
|
+
expand: "\u5C55\u5F00\u4EE3\u7801",
|
14
|
+
collapse: "\u6536\u8D77\u4EE3\u7801",
|
15
|
+
className: "\u8282\u70B9\u7C7B\u540D",
|
16
|
+
style: "\u8282\u70B9\u6837\u5F0F",
|
17
|
+
children: "\u5B50\u8282\u70B9",
|
18
|
+
disabled: "\u662F\u5426\u7981\u7528",
|
19
|
+
required: "\u5FC5\u586B",
|
20
|
+
property: "\u5C5E\u6027",
|
21
|
+
description: "\u8BF4\u660E",
|
22
|
+
type: "\u7C7B\u578B",
|
23
|
+
defaultValue: "\u9ED8\u8BA4\u503C",
|
24
|
+
overview: "\u6982\u89C8"
|
25
|
+
},
|
26
|
+
en: {
|
27
|
+
copy: 'Copy',
|
28
|
+
copied: 'Copied Success!',
|
29
|
+
expand: 'Expand Code',
|
30
|
+
collapse: 'Collapse Code',
|
31
|
+
className: 'Additional css class',
|
32
|
+
style: 'Additional style',
|
33
|
+
children: 'Children',
|
34
|
+
disabled: 'Whether to disable ',
|
35
|
+
required: 'Required',
|
36
|
+
property: 'Property',
|
37
|
+
description: "Description",
|
38
|
+
type: 'Type',
|
39
|
+
defaultValue: 'Default Value',
|
40
|
+
overview: 'Overview'
|
41
|
+
},
|
42
|
+
ru: {
|
43
|
+
copy: "\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
|
44
|
+
copied: "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E \u0443\u0441\u043F\u0435\u0448\u043D\u043E",
|
45
|
+
expand: "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u043A\u043E\u0434",
|
46
|
+
collapse: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u043A\u043E\u0434",
|
47
|
+
className: "\u0418\u043C\u044F \u043A\u043B\u0430\u0441\u0441\u0430 \u0443\u0437\u043B\u0430",
|
48
|
+
style: "\u0421\u0442\u0438\u043B\u044C \u0443\u0437\u043B\u0430",
|
49
|
+
children: "\u0414\u043E\u0447\u0435\u0440\u043D\u0438\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B",
|
50
|
+
disabled: "\u041E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u043E",
|
51
|
+
required: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
|
52
|
+
property: "\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u043E",
|
53
|
+
description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435",
|
54
|
+
type: "\u0422\u0438\u043F",
|
55
|
+
defaultValue: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E",
|
56
|
+
overview: "\u041E\u0431\u0437\u043E\u0440"
|
7
57
|
}
|
8
58
|
};
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
})
|
28
|
-
(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
59
|
+
const isToolEntries = (obj)=>!!obj.documentation || !!obj["react-docgen-typescript"];
|
60
|
+
const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptions, isProd })=>{
|
61
|
+
const watchFileMap = {};
|
62
|
+
const genApiDoc = async (entry, tool)=>{
|
63
|
+
if (0 === Object.keys(entry).length) return;
|
64
|
+
await Promise.all(Object.entries(entry).map(async ([key, value])=>{
|
65
|
+
const moduleSourceFilePath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(appDir, value);
|
66
|
+
watchFileMap[moduleSourceFilePath] = {
|
67
|
+
apiParseTool,
|
68
|
+
moduleName: key
|
69
|
+
};
|
70
|
+
try {
|
71
|
+
if ('documentation' === tool) {
|
72
|
+
const documentation = await import("documentation");
|
73
|
+
const documentationRes = await documentation.build([
|
74
|
+
moduleSourceFilePath
|
75
|
+
], {
|
76
|
+
...parseToolOptions.documentation
|
77
|
+
});
|
78
|
+
const apiDoc = await documentation.formats.md(documentationRes, {
|
79
|
+
noReferenceLinks: parseToolOptions.documentation?.noReferenceLinks ?? true
|
80
|
+
});
|
81
|
+
apiDocMap[key] = apiDoc;
|
82
|
+
} else {
|
83
|
+
const { tsconfigPath, compilerOptions, ...restOptions } = parseToolOptions?.["react-docgen-typescript"] ?? {};
|
84
|
+
const parserOpts = {
|
85
|
+
propFilter: (prop)=>{
|
86
|
+
if (void 0 !== prop.declarations && prop.declarations.length > 0) {
|
87
|
+
const hasPropAdditionalDescription = prop.declarations.find((declaration)=>!declaration.fileName.includes('node_modules'));
|
88
|
+
return Boolean(hasPropAdditionalDescription);
|
89
|
+
}
|
90
|
+
return true;
|
91
|
+
},
|
92
|
+
...restOptions
|
93
|
+
};
|
94
|
+
let fileParser = (0, __WEBPACK_EXTERNAL_MODULE_react_docgen_typescript_e816f54f__.withDefaultConfig)(parserOpts);
|
95
|
+
if (tsconfigPath?.[key]) fileParser = (0, __WEBPACK_EXTERNAL_MODULE_react_docgen_typescript_e816f54f__.withCustomConfig)(tsconfigPath[key], parserOpts);
|
96
|
+
else if (compilerOptions?.[key]) fileParser = (0, __WEBPACK_EXTERNAL_MODULE_react_docgen_typescript_e816f54f__.withCompilerOptions)(compilerOptions[key], parserOpts);
|
97
|
+
const componentDoc = fileParser.parse(moduleSourceFilePath);
|
98
|
+
if (0 === componentDoc.length) __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.warn('[module-doc-plugin]', `Unable to parse API document in ${moduleSourceFilePath}`);
|
99
|
+
if (languages.length > 0) languages.forEach((language)=>{
|
100
|
+
apiDocMap[`${key}-${language}`] = generateTable(componentDoc, language);
|
101
|
+
});
|
102
|
+
else apiDocMap[key] = generateTable(componentDoc, 'en');
|
103
|
+
}
|
104
|
+
} catch (e) {
|
105
|
+
if (e instanceof Error) __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.error('[module-doc-plugin]', 'Generate API table error:\n', e);
|
106
|
+
}
|
107
|
+
}));
|
34
108
|
};
|
35
|
-
|
36
|
-
(()
|
37
|
-
|
38
|
-
|
39
|
-
(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
109
|
+
__WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.info('[module-doc-plugin]', 'Start to generate API table...');
|
110
|
+
if (isToolEntries(entries)) {
|
111
|
+
const reactEntries = entries["react-docgen-typescript"];
|
112
|
+
const documentationEntries = entries.documentation;
|
113
|
+
await Promise.all([
|
114
|
+
genApiDoc(reactEntries, "react-docgen-typescript"),
|
115
|
+
genApiDoc(documentationEntries, 'documentation')
|
116
|
+
]);
|
117
|
+
} else await genApiDoc(entries, apiParseTool);
|
118
|
+
if (!isProd) {
|
119
|
+
const watcher = __WEBPACK_EXTERNAL_MODULE_chokidar__["default"].watch(Object.keys(watchFileMap), {
|
120
|
+
ignoreInitial: true,
|
121
|
+
ignorePermissionErrors: true,
|
122
|
+
ignored: [
|
123
|
+
/node_modules/
|
124
|
+
]
|
46
125
|
});
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
external_node_path_default().join(__dirname, '..');
|
61
|
-
const apiDocMap = {};
|
62
|
-
const shared_namespaceObject = require("@rspress/shared");
|
63
|
-
const external_chokidar_namespaceObject = require("chokidar");
|
64
|
-
var external_chokidar_default = /*#__PURE__*/ __webpack_require__.n(external_chokidar_namespaceObject);
|
65
|
-
const external_react_docgen_typescript_namespaceObject = require("react-docgen-typescript");
|
66
|
-
const locales = {
|
67
|
-
zh: {
|
68
|
-
copy: '复制',
|
69
|
-
copied: '复制成功',
|
70
|
-
expand: '展开代码',
|
71
|
-
collapse: '收起代码',
|
72
|
-
className: '节点类名',
|
73
|
-
style: '节点样式',
|
74
|
-
children: '子节点',
|
75
|
-
disabled: '是否禁用',
|
76
|
-
required: '必填',
|
77
|
-
property: '属性',
|
78
|
-
description: '说明',
|
79
|
-
type: '类型',
|
80
|
-
defaultValue: '默认值',
|
81
|
-
overview: '概览'
|
82
|
-
},
|
83
|
-
en: {
|
84
|
-
copy: 'Copy',
|
85
|
-
copied: 'Copied Success!',
|
86
|
-
expand: 'Expand Code',
|
87
|
-
collapse: 'Collapse Code',
|
88
|
-
className: 'Additional css class',
|
89
|
-
style: 'Additional style',
|
90
|
-
children: 'Children',
|
91
|
-
disabled: 'Whether to disable ',
|
92
|
-
required: 'Required',
|
93
|
-
property: 'Property',
|
94
|
-
description: "Description",
|
95
|
-
type: 'Type',
|
96
|
-
defaultValue: 'Default Value',
|
97
|
-
overview: 'Overview'
|
98
|
-
},
|
99
|
-
ru: {
|
100
|
-
copy: 'Копировать',
|
101
|
-
copied: 'Скопировано успешно',
|
102
|
-
expand: 'Развернуть код',
|
103
|
-
collapse: 'Свернуть код',
|
104
|
-
className: 'Имя класса узла',
|
105
|
-
style: 'Стиль узла',
|
106
|
-
children: 'Дочерние элементы',
|
107
|
-
disabled: 'Отключено',
|
108
|
-
required: 'Обязательно',
|
109
|
-
property: 'Свойство',
|
110
|
-
description: 'Описание',
|
111
|
-
type: 'Тип',
|
112
|
-
defaultValue: 'Значение по умолчанию',
|
113
|
-
overview: 'Обзор'
|
114
|
-
}
|
115
|
-
};
|
116
|
-
const isToolEntries = (obj)=>!!obj.documentation || !!obj["react-docgen-typescript"];
|
117
|
-
const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptions, isProd })=>{
|
118
|
-
const watchFileMap = {};
|
119
|
-
const genApiDoc = async (entry, tool)=>{
|
120
|
-
if (0 === Object.keys(entry).length) return;
|
121
|
-
await Promise.all(Object.entries(entry).map(async ([key, value])=>{
|
122
|
-
const moduleSourceFilePath = external_node_path_default().resolve(appDir, value);
|
123
|
-
watchFileMap[moduleSourceFilePath] = {
|
124
|
-
apiParseTool,
|
125
|
-
moduleName: key
|
126
|
-
};
|
127
|
-
try {
|
128
|
-
if ('documentation' === tool) {
|
129
|
-
var _parseToolOptions_documentation;
|
130
|
-
const documentation = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "documentation"));
|
131
|
-
const documentationRes = await documentation.build([
|
132
|
-
moduleSourceFilePath
|
133
|
-
], {
|
134
|
-
...parseToolOptions.documentation
|
135
|
-
});
|
136
|
-
const apiDoc = await documentation.formats.md(documentationRes, {
|
137
|
-
noReferenceLinks: (null == (_parseToolOptions_documentation = parseToolOptions.documentation) ? void 0 : _parseToolOptions_documentation.noReferenceLinks) ?? true
|
138
|
-
});
|
139
|
-
apiDocMap[key] = apiDoc;
|
140
|
-
} else {
|
141
|
-
const { tsconfigPath, compilerOptions, ...restOptions } = (null == parseToolOptions ? void 0 : parseToolOptions["react-docgen-typescript"]) ?? {};
|
142
|
-
const parserOpts = {
|
143
|
-
propFilter: (prop)=>{
|
144
|
-
if (void 0 !== prop.declarations && prop.declarations.length > 0) {
|
145
|
-
const hasPropAdditionalDescription = prop.declarations.find((declaration)=>!declaration.fileName.includes('node_modules'));
|
146
|
-
return Boolean(hasPropAdditionalDescription);
|
147
|
-
}
|
148
|
-
return true;
|
149
|
-
},
|
150
|
-
...restOptions
|
126
|
+
let isUpdate = false;
|
127
|
+
watcher.on('change', (changed)=>{
|
128
|
+
if (isUpdate) return;
|
129
|
+
isUpdate = true;
|
130
|
+
__WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.info('[module-doc-plugin]', 'updating API');
|
131
|
+
const watchFileInfo = watchFileMap[changed];
|
132
|
+
if (watchFileInfo) {
|
133
|
+
const { apiParseTool, moduleName } = watchFileInfo;
|
134
|
+
const updateSiteData = ()=>{
|
135
|
+
const siteDataPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(process.cwd(), 'node_modules', __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__.RSPRESS_TEMP_DIR, 'runtime', 'virtual-site-data.mjs');
|
136
|
+
import(siteDataPath).then((siteData)=>{
|
137
|
+
const data = {
|
138
|
+
...siteData.default
|
151
139
|
};
|
152
|
-
|
153
|
-
|
154
|
-
else if (null == compilerOptions ? void 0 : compilerOptions[key]) fileParser = (0, external_react_docgen_typescript_namespaceObject.withCompilerOptions)(compilerOptions[key], parserOpts);
|
155
|
-
const componentDoc = fileParser.parse(moduleSourceFilePath);
|
156
|
-
if (0 === componentDoc.length) logger_namespaceObject.logger.warn('[module-doc-plugin]', `Unable to parse API document in ${moduleSourceFilePath}`);
|
157
|
-
if (languages.length > 0) languages.forEach((language)=>{
|
158
|
-
apiDocMap[`${key}-${language}`] = generateTable(componentDoc, language);
|
159
|
-
});
|
160
|
-
else apiDocMap[key] = generateTable(componentDoc, 'en');
|
161
|
-
}
|
162
|
-
} catch (e) {
|
163
|
-
if (e instanceof Error) logger_namespaceObject.logger.error('[module-doc-plugin]', 'Generate API table error:\n', e);
|
164
|
-
}
|
165
|
-
}));
|
166
|
-
};
|
167
|
-
logger_namespaceObject.logger.info('[module-doc-plugin]', 'Start to generate API table...');
|
168
|
-
if (isToolEntries(entries)) {
|
169
|
-
const reactEntries = entries["react-docgen-typescript"];
|
170
|
-
const documentationEntries = entries.documentation;
|
171
|
-
await Promise.all([
|
172
|
-
genApiDoc(reactEntries, "react-docgen-typescript"),
|
173
|
-
genApiDoc(documentationEntries, 'documentation')
|
174
|
-
]);
|
175
|
-
} else await genApiDoc(entries, apiParseTool);
|
176
|
-
if (!isProd) {
|
177
|
-
const watcher = external_chokidar_default().watch(Object.keys(watchFileMap), {
|
178
|
-
ignoreInitial: true,
|
179
|
-
ignorePermissionErrors: true,
|
180
|
-
ignored: [
|
181
|
-
/node_modules/
|
182
|
-
]
|
183
|
-
});
|
184
|
-
let isUpdate = false;
|
185
|
-
watcher.on('change', (changed)=>{
|
186
|
-
if (isUpdate) return;
|
187
|
-
isUpdate = true;
|
188
|
-
logger_namespaceObject.logger.info('[module-doc-plugin]', 'updating API');
|
189
|
-
const watchFileInfo = watchFileMap[changed];
|
190
|
-
if (watchFileInfo) {
|
191
|
-
const { apiParseTool, moduleName } = watchFileInfo;
|
192
|
-
const updateSiteData = ()=>{
|
193
|
-
const siteDataPath = external_node_path_default().join(process.cwd(), 'node_modules', shared_namespaceObject.RSPRESS_TEMP_DIR, 'runtime', 'virtual-site-data.mjs');
|
194
|
-
import(siteDataPath).then((siteData)=>{
|
195
|
-
const data = {
|
196
|
-
...siteData.default
|
197
|
-
};
|
198
|
-
data.pages.forEach((page)=>{
|
199
|
-
page.apiDocMap = apiDocMap;
|
200
|
-
});
|
201
|
-
external_node_fs_default().writeFileSync(siteDataPath, `export default ${JSON.stringify(data)}`);
|
202
|
-
isUpdate = false;
|
140
|
+
data.pages.forEach((page)=>{
|
141
|
+
page.apiDocMap = apiDocMap;
|
203
142
|
});
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
}, apiParseTool).then(updateSiteData);
|
208
|
-
}
|
209
|
-
});
|
210
|
-
}
|
211
|
-
logger_namespaceObject.logger.success('[module-doc-plugin]', 'Generate API table successfully!');
|
212
|
-
};
|
213
|
-
function generateTable(componentDoc, language) {
|
214
|
-
return componentDoc.map((param)=>{
|
215
|
-
const { props } = param;
|
216
|
-
const t = locales[language];
|
217
|
-
const PROP_TABLE_HEADER = `|${t.property}|${t.description}|${t.type}|${t.defaultValue}|\n|:---:|:---:|:---:|:---:|`;
|
218
|
-
const tableContent = Object.keys(props).filter((propName)=>{
|
219
|
-
const { name, description } = props[propName];
|
220
|
-
return description || [
|
221
|
-
'className',
|
222
|
-
'style',
|
223
|
-
'disabled',
|
224
|
-
'children'
|
225
|
-
].indexOf(name) > -1;
|
226
|
-
}).map((propName)=>{
|
227
|
-
const { defaultValue, description, name, required, type } = props[propName];
|
228
|
-
const getType = ()=>`\`${type.name.replace(/\|/g, '\\|')}\`${required ? ` **(${t.required})**` : ''}`;
|
229
|
-
const getDefaultValue = ()=>`\`${(null == defaultValue ? void 0 : defaultValue.value) || '-'}\``;
|
230
|
-
const getDescription = ()=>{
|
231
|
-
switch(name){
|
232
|
-
case 'className':
|
233
|
-
return description || t.className;
|
234
|
-
case 'style':
|
235
|
-
return description || t.style;
|
236
|
-
case 'children':
|
237
|
-
return description || t.children;
|
238
|
-
case 'disabled':
|
239
|
-
return description || t.disabled;
|
240
|
-
default:
|
241
|
-
return description;
|
242
|
-
}
|
143
|
+
__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].writeFileSync(siteDataPath, `export default ${JSON.stringify(data)}`);
|
144
|
+
isUpdate = false;
|
145
|
+
});
|
243
146
|
};
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
147
|
+
genApiDoc({
|
148
|
+
[moduleName]: changed
|
149
|
+
}, apiParseTool).then(updateSiteData);
|
150
|
+
}
|
151
|
+
});
|
152
|
+
}
|
153
|
+
__WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.success('[module-doc-plugin]', 'Generate API table successfully!');
|
154
|
+
};
|
155
|
+
function generateTable(componentDoc, language) {
|
156
|
+
return componentDoc.map((param)=>{
|
157
|
+
const { props } = param;
|
158
|
+
const t = locales[language];
|
159
|
+
const PROP_TABLE_HEADER = `|${t.property}|${t.description}|${t.type}|${t.defaultValue}|\n|:---:|:---:|:---:|:---:|`;
|
160
|
+
const tableContent = Object.keys(props).filter((propName)=>{
|
161
|
+
const { name, description } = props[propName];
|
162
|
+
return description || [
|
163
|
+
'className',
|
164
|
+
'style',
|
165
|
+
'disabled',
|
166
|
+
'children'
|
167
|
+
].indexOf(name) > -1;
|
168
|
+
}).map((propName)=>{
|
169
|
+
const { defaultValue, description, name, required, type } = props[propName];
|
170
|
+
const getType = ()=>`\`${type.name.replace(/\|/g, '\\|')}\`${required ? ` **(${t.required})**` : ''}`;
|
171
|
+
const getDefaultValue = ()=>`\`${defaultValue?.value || '-'}\``;
|
172
|
+
const getDescription = ()=>{
|
173
|
+
switch(name){
|
174
|
+
case 'className':
|
175
|
+
return description || t.className;
|
176
|
+
case 'style':
|
177
|
+
return description || t.style;
|
178
|
+
case 'children':
|
179
|
+
return description || t.children;
|
180
|
+
case 'disabled':
|
181
|
+
return description || t.disabled;
|
182
|
+
default:
|
183
|
+
return description;
|
184
|
+
}
|
185
|
+
};
|
186
|
+
const formattedDescription = getDescription().replace(/\n/g, ' ');
|
187
|
+
return `|${[
|
188
|
+
name,
|
189
|
+
formattedDescription,
|
190
|
+
getType(),
|
191
|
+
getDefaultValue()
|
192
|
+
].map((str)=>str.replace(/(?<!\\)\|/g, '|')).join('|')}|`;
|
193
|
+
});
|
194
|
+
return `
|
253
195
|
${param.displayName ? `### ${param.displayName}\n` : ''}
|
254
196
|
${param.description ? `**${param.description}**\n` : ''}
|
255
197
|
${PROP_TABLE_HEADER}
|
256
198
|
${tableContent.join('\n')}
|
257
199
|
`;
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
async
|
286
|
-
const
|
287
|
-
await
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
}
|
315
|
-
})();
|
316
|
-
exports.pluginApiDocgen = __webpack_exports__.pluginApiDocgen;
|
317
|
-
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
318
|
-
"pluginApiDocgen"
|
319
|
-
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
320
|
-
Object.defineProperty(exports, '__esModule', {
|
321
|
-
value: true
|
322
|
-
});
|
200
|
+
}).join('\n');
|
201
|
+
}
|
202
|
+
function pluginApiDocgen(options) {
|
203
|
+
const { entries = {}, apiParseTool = "react-docgen-typescript", appDir = process.cwd(), parseToolOptions = {} } = options || {};
|
204
|
+
return {
|
205
|
+
name: '@modern-js/doc-plugin-api-docgen',
|
206
|
+
config (config) {
|
207
|
+
config.markdown = config.markdown || {};
|
208
|
+
return config;
|
209
|
+
},
|
210
|
+
async beforeBuild (config, isProd) {
|
211
|
+
const languages = (config.themeConfig?.locales?.map((locale)=>locale.lang) || config.locales?.map((locale)=>locale.lang) || []).filter((lang)=>[
|
212
|
+
'zh',
|
213
|
+
'en',
|
214
|
+
'ru'
|
215
|
+
].includes(lang));
|
216
|
+
await docgen({
|
217
|
+
entries,
|
218
|
+
apiParseTool,
|
219
|
+
languages,
|
220
|
+
appDir,
|
221
|
+
parseToolOptions,
|
222
|
+
isProd
|
223
|
+
});
|
224
|
+
},
|
225
|
+
async modifySearchIndexData (pages) {
|
226
|
+
const apiCompRegExp = /(<API\s+moduleName=['"](\S+)['"]\s*(.*)?\/>)|(<API\s+moduleName=['"](\S+)['"]\s*(.*)?>(.*)?<\/API>)/;
|
227
|
+
await Promise.all(pages.map(async (page)=>{
|
228
|
+
const { _filepath, lang } = page;
|
229
|
+
let content = await __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].promises.readFile(_filepath, 'utf-8');
|
230
|
+
let matchResult = apiCompRegExp.exec(content);
|
231
|
+
if (!matchResult) return;
|
232
|
+
while(null !== matchResult){
|
233
|
+
const matchContent = matchResult[0];
|
234
|
+
const moduleName = matchResult[2] ?? matchResult[5] ?? '';
|
235
|
+
const apiDoc = apiDocMap[moduleName] ?? apiDocMap[`${moduleName}-${lang ? lang : 'en'}`] ?? '';
|
236
|
+
if (matchContent && !apiDoc) __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.warn(`No api doc found for module: ${moduleName} in lang: ${lang ?? 'en'}`);
|
237
|
+
content = content.replace(matchContent, apiDoc);
|
238
|
+
matchResult = apiCompRegExp.exec(content);
|
239
|
+
}
|
240
|
+
page.content = content;
|
241
|
+
}));
|
242
|
+
},
|
243
|
+
extendPageData (pageData) {
|
244
|
+
pageData.apiDocMap = {
|
245
|
+
...apiDocMap
|
246
|
+
};
|
247
|
+
},
|
248
|
+
markdown: {
|
249
|
+
globalComponents: [
|
250
|
+
__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(__dirname, '..', 'static', 'global-components', 'API.tsx')
|
251
|
+
]
|
252
|
+
}
|
253
|
+
};
|
254
|
+
}
|
255
|
+
export { pluginApiDocgen };
|
package/package.json
CHANGED
@@ -1,48 +1,54 @@
|
|
1
1
|
{
|
2
2
|
"name": "@rspress/plugin-api-docgen",
|
3
|
-
"version": "2.0.0-beta.
|
3
|
+
"version": "2.0.0-beta.10",
|
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": {
|
7
7
|
"type": "git",
|
8
|
-
"url": "https://github.com/web-infra-dev/rspress",
|
8
|
+
"url": "git+https://github.com/web-infra-dev/rspress.git",
|
9
9
|
"directory": "packages/plugin-api-docgen"
|
10
10
|
},
|
11
11
|
"license": "MIT",
|
12
|
-
"
|
12
|
+
"type": "module",
|
13
|
+
"exports": {
|
14
|
+
".": {
|
15
|
+
"types": "./index.d.ts",
|
16
|
+
"default": "./dist/index.js"
|
17
|
+
}
|
18
|
+
},
|
13
19
|
"types": "./index.d.ts",
|
14
20
|
"files": [
|
15
21
|
"dist",
|
16
22
|
"static",
|
17
|
-
"index.d.ts"
|
18
|
-
"mdx-meta-loader.cjs"
|
23
|
+
"index.d.ts"
|
19
24
|
],
|
20
25
|
"dependencies": {
|
21
26
|
"chokidar": "^3.6.0",
|
22
27
|
"documentation": "14.0.3",
|
28
|
+
"github-slugger": "^2.0.0",
|
23
29
|
"react-docgen-typescript": "2.2.2",
|
24
30
|
"react-markdown": "^10.1.0",
|
25
31
|
"remark-gfm": "^4.0.1",
|
26
|
-
"
|
32
|
+
"unified": "^11.0.5",
|
33
|
+
"unist-util-visit": "^5.0.0",
|
34
|
+
"@rspress/shared": "2.0.0-beta.10"
|
27
35
|
},
|
28
36
|
"devDependencies": {
|
29
|
-
"@microsoft/api-extractor": "^7.52.
|
30
|
-
"@rslib/core": "0.
|
37
|
+
"@microsoft/api-extractor": "^7.52.8",
|
38
|
+
"@rslib/core": "0.8.0",
|
39
|
+
"@types/hast": "^3.0.4",
|
31
40
|
"@types/mdast": "^4.0.4",
|
32
|
-
"@types/node": "^
|
33
|
-
"@types/react": "^18.3.
|
34
|
-
"@types/react-dom": "^18.3.
|
41
|
+
"@types/node": "^22.8.1",
|
42
|
+
"@types/react": "^18.3.22",
|
43
|
+
"@types/react-dom": "^18.3.7",
|
35
44
|
"react": "^19.1.0",
|
36
45
|
"react-dom": "^19.1.0",
|
37
46
|
"react-router-dom": "^6.29.0",
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"unist-util-visit": "^5.0.0"
|
47
|
+
"rsbuild-plugin-publint": "^0.3.2",
|
48
|
+
"typescript": "^5.8.2"
|
41
49
|
},
|
42
50
|
"peerDependencies": {
|
43
|
-
"@rspress/core": "^2.0.0-beta.
|
44
|
-
"react": ">=17.0.0",
|
45
|
-
"react-router-dom": "^6.8.1",
|
51
|
+
"@rspress/core": "^2.0.0-beta.10",
|
46
52
|
"typescript": "^5.8.2"
|
47
53
|
},
|
48
54
|
"peerDependenciesMeta": {
|
@@ -51,7 +57,7 @@
|
|
51
57
|
}
|
52
58
|
},
|
53
59
|
"engines": {
|
54
|
-
"node": ">=
|
60
|
+
"node": ">=18.0.0"
|
55
61
|
},
|
56
62
|
"publishConfig": {
|
57
63
|
"access": "public",
|
@@ -5,6 +5,97 @@ import { getCustomMDXComponent } from '@rspress/core/theme';
|
|
5
5
|
import ReactMarkdown from 'react-markdown';
|
6
6
|
import remarkGfm from 'remark-gfm';
|
7
7
|
import './API.css';
|
8
|
+
import GithubSlugger from 'github-slugger';
|
9
|
+
import type { Content, Element, Root } from 'hast';
|
10
|
+
// biome-ignore lint/style/useImportType: <exact>
|
11
|
+
import React from 'react';
|
12
|
+
import type { Plugin } from 'unified';
|
13
|
+
import { visit } from 'unist-util-visit';
|
14
|
+
|
15
|
+
function headingRank(node: Root | Content): number | null {
|
16
|
+
const name =
|
17
|
+
(node && node.type === 'element' && node.tagName.toLowerCase()) || '';
|
18
|
+
const code =
|
19
|
+
name.length === 2 && name.charCodeAt(0) === 104 /* `h` */
|
20
|
+
? name.charCodeAt(1)
|
21
|
+
: 0;
|
22
|
+
return code > 48 /* `0` */ && code < 55 /* `7` */
|
23
|
+
? code - 48 /* `0` */
|
24
|
+
: null;
|
25
|
+
}
|
26
|
+
|
27
|
+
const rehypeHeaderAnchor: Plugin<[], Root> = () => {
|
28
|
+
const slugger = new GithubSlugger();
|
29
|
+
return tree => {
|
30
|
+
visit(tree, 'element', node => {
|
31
|
+
if (!headingRank(node)) {
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
// generate id
|
35
|
+
|
36
|
+
if (!node.properties?.id) {
|
37
|
+
const text = collectHeaderText(node);
|
38
|
+
node.properties ??= {};
|
39
|
+
node.properties.id = slugger.slug(text);
|
40
|
+
}
|
41
|
+
// apply to headings
|
42
|
+
node.children.unshift(create(node));
|
43
|
+
});
|
44
|
+
};
|
45
|
+
};
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Create an `a`.
|
49
|
+
*
|
50
|
+
* @param {Readonly<Element>} node
|
51
|
+
* Related heading.
|
52
|
+
* @returns {Element}
|
53
|
+
* Link.
|
54
|
+
*/
|
55
|
+
function create(node: Element): Element {
|
56
|
+
return {
|
57
|
+
type: 'element',
|
58
|
+
tagName: 'a',
|
59
|
+
properties: {
|
60
|
+
class: 'header-anchor',
|
61
|
+
ariaHidden: 'true',
|
62
|
+
href: `#${node.properties!.id}`,
|
63
|
+
},
|
64
|
+
children: [
|
65
|
+
{
|
66
|
+
type: 'text',
|
67
|
+
value: '#',
|
68
|
+
},
|
69
|
+
],
|
70
|
+
};
|
71
|
+
}
|
72
|
+
|
73
|
+
const extractTextAndId = (title?: string): string => {
|
74
|
+
if (!title) {
|
75
|
+
return '';
|
76
|
+
}
|
77
|
+
const text = title.trimEnd();
|
78
|
+
return text;
|
79
|
+
};
|
80
|
+
|
81
|
+
const collectHeaderText = (node: Element): string => {
|
82
|
+
let text = '';
|
83
|
+
node.children.forEach(child => {
|
84
|
+
if (child.type === 'text') {
|
85
|
+
const textPart = extractTextAndId(child.value);
|
86
|
+
child.value = textPart;
|
87
|
+
text += textPart;
|
88
|
+
}
|
89
|
+
if (child.type === 'element') {
|
90
|
+
child.children.forEach(c => {
|
91
|
+
if (c.type === 'text') {
|
92
|
+
text += c.value;
|
93
|
+
}
|
94
|
+
});
|
95
|
+
}
|
96
|
+
});
|
97
|
+
return text;
|
98
|
+
};
|
8
99
|
|
9
100
|
export default (props: { moduleName: string }) => {
|
10
101
|
const lang = useLang();
|
@@ -19,6 +110,7 @@ export default (props: { moduleName: string }) => {
|
|
19
110
|
<div className="rspress-plugin-api-docgen">
|
20
111
|
<ReactMarkdown
|
21
112
|
remarkPlugins={[[remarkGfm]]}
|
113
|
+
rehypePlugins={[[rehypeHeaderAnchor]]}
|
22
114
|
components={
|
23
115
|
getCustomMDXComponent() as Record<string, React.ElementType>
|
24
116
|
}
|
package/mdx-meta-loader.cjs
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
const { demoMeta } = require('./dist');
|
2
|
-
|
3
|
-
module.exports = async function () {
|
4
|
-
const callback = this.async();
|
5
|
-
const demos = demoMeta[this.resourcePath] || [];
|
6
|
-
try {
|
7
|
-
const result = `
|
8
|
-
${demos
|
9
|
-
.map((item) => {
|
10
|
-
return `import Demo_${item.id} from '${item.virtualModulePath}';`;
|
11
|
-
})
|
12
|
-
.join('\n')}
|
13
|
-
export default [${demos
|
14
|
-
.map((item) => {
|
15
|
-
return `{
|
16
|
-
"id": "${item.id}",
|
17
|
-
"component": Demo_${item.id}
|
18
|
-
}`;
|
19
|
-
})
|
20
|
-
.join(',')}];
|
21
|
-
`;
|
22
|
-
callback(null, result);
|
23
|
-
} catch (err) {
|
24
|
-
callback(err);
|
25
|
-
}
|
26
|
-
};
|