@rspress/plugin-api-docgen 2.0.0-beta.2 → 2.0.0-beta.21

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 CHANGED
@@ -1,3 +1,3 @@
1
1
  # @rspress/plugin-api-docgen
2
2
 
3
- The auto api generate plugin for [Rspress](https://rspress.dev).
3
+ The auto api generate plugin for [Rspress](https://rspress.rs).
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/shared';
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 * 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, '..');
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: "\u590D\u5236",
11
+ copied: "\u590D\u5236\u6210\u529F",
12
+ expand: "\u5C55\u5F00\u4EE3\u7801",
13
+ collapse: "\u6536\u8D77\u4EE3\u7801",
14
+ className: "\u8282\u70B9\u7C7B\u540D",
15
+ style: "\u8282\u70B9\u6837\u5F0F",
16
+ children: "\u5B50\u8282\u70B9",
17
+ disabled: "\u662F\u5426\u7981\u7528",
18
+ required: "\u5FC5\u586B",
19
+ property: "\u5C5E\u6027",
20
+ description: "\u8BF4\u660E",
21
+ type: "\u7C7B\u578B",
22
+ defaultValue: "\u9ED8\u8BA4\u503C",
23
+ overview: "\u6982\u89C8"
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: "\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
43
+ copied: "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E \u0443\u0441\u043F\u0435\u0448\u043D\u043E",
44
+ expand: "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u043A\u043E\u0434",
45
+ collapse: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u043A\u043E\u0434",
46
+ className: "\u0418\u043C\u044F \u043A\u043B\u0430\u0441\u0441\u0430 \u0443\u0437\u043B\u0430",
47
+ style: "\u0421\u0442\u0438\u043B\u044C \u0443\u0437\u043B\u0430",
48
+ children: "\u0414\u043E\u0447\u0435\u0440\u043D\u0438\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B",
49
+ disabled: "\u041E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u043E",
50
+ required: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
51
+ property: "\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u043E",
52
+ description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435",
53
+ type: "\u0422\u0438\u043F",
54
+ defaultValue: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E",
55
+ overview: "\u041E\u0431\u0437\u043E\u0440"
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 = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(appDir, value);
64
+ const moduleSourceFilePath = node_path.resolve(appDir, value);
66
65
  watchFileMap[moduleSourceFilePath] = {
67
66
  apiParseTool,
68
67
  moduleName: key
@@ -91,22 +90,22 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
91
90
  },
92
91
  ...restOptions
93
92
  };
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);
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) __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.warn('[module-doc-plugin]', `Unable to parse API document in ${moduleSourceFilePath}`);
97
+ if (0 === componentDoc.length) logger.warn('[module-doc-plugin]', `Unable to parse API document in ${moduleSourceFilePath}`);
99
98
  if (languages.length > 0) languages.forEach((language)=>{
100
99
  apiDocMap[`${key}-${language}`] = generateTable(componentDoc, language);
101
100
  });
102
101
  else apiDocMap[key] = generateTable(componentDoc, 'en');
103
102
  }
104
103
  } 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);
104
+ if (e instanceof Error) logger.error('[module-doc-plugin]', 'Generate API table error:\n', e);
106
105
  }
107
106
  }));
108
107
  };
109
- __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.info('[module-doc-plugin]', 'Start to generate API table...');
108
+ logger.info('[module-doc-plugin]', 'Start to generate API table...');
110
109
  if (isToolEntries(entries)) {
111
110
  const reactEntries = entries["react-docgen-typescript"];
112
111
  const documentationEntries = entries.documentation;
@@ -116,7 +115,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
116
115
  ]);
117
116
  } else await genApiDoc(entries, apiParseTool);
118
117
  if (!isProd) {
119
- const watcher = __WEBPACK_EXTERNAL_MODULE_chokidar__["default"].watch(Object.keys(watchFileMap), {
118
+ const watcher = chokidar.watch(Object.keys(watchFileMap), {
120
119
  ignoreInitial: true,
121
120
  ignorePermissionErrors: true,
122
121
  ignored: [
@@ -127,12 +126,12 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
127
126
  watcher.on('change', (changed)=>{
128
127
  if (isUpdate) return;
129
128
  isUpdate = true;
130
- __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.info('[module-doc-plugin]', 'updating API');
129
+ logger.info('[module-doc-plugin]', 'updating API');
131
130
  const watchFileInfo = watchFileMap[changed];
132
131
  if (watchFileInfo) {
133
132
  const { apiParseTool, moduleName } = watchFileInfo;
134
133
  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');
134
+ const siteDataPath = node_path.join(process.cwd(), 'node_modules', RSPRESS_TEMP_DIR, 'runtime', 'virtual-site-data.mjs');
136
135
  import(siteDataPath).then((siteData)=>{
137
136
  const data = {
138
137
  ...siteData.default
@@ -140,7 +139,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
140
139
  data.pages.forEach((page)=>{
141
140
  page.apiDocMap = apiDocMap;
142
141
  });
143
- __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].writeFileSync(siteDataPath, `export default ${JSON.stringify(data)}`);
142
+ node_fs.writeFileSync(siteDataPath, `export default ${JSON.stringify(data)}`);
144
143
  isUpdate = false;
145
144
  });
146
145
  };
@@ -150,7 +149,7 @@ const docgen = async ({ entries, languages, apiParseTool, appDir, parseToolOptio
150
149
  }
151
150
  });
152
151
  }
153
- __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.success('[module-doc-plugin]', 'Generate API table successfully!');
152
+ logger.success('[module-doc-plugin]', 'Generate API table successfully!');
154
153
  };
155
154
  function generateTable(componentDoc, language) {
156
155
  return componentDoc.map((param)=>{
@@ -226,14 +225,14 @@ function pluginApiDocgen(options) {
226
225
  const apiCompRegExp = /(<API\s+moduleName=['"](\S+)['"]\s*(.*)?\/>)|(<API\s+moduleName=['"](\S+)['"]\s*(.*)?>(.*)?<\/API>)/;
227
226
  await Promise.all(pages.map(async (page)=>{
228
227
  const { _filepath, lang } = page;
229
- let content = await __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].promises.readFile(_filepath, 'utf-8');
228
+ let content = await node_fs.promises.readFile(_filepath, 'utf-8');
230
229
  let matchResult = apiCompRegExp.exec(content);
231
230
  if (!matchResult) return;
232
231
  while(null !== matchResult){
233
232
  const matchContent = matchResult[0];
234
233
  const moduleName = matchResult[2] ?? matchResult[5] ?? '';
235
234
  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'}`);
235
+ if (matchContent && !apiDoc) logger.warn(`No api doc found for module: ${moduleName} in lang: ${lang ?? 'en'}`);
237
236
  content = content.replace(matchContent, apiDoc);
238
237
  matchResult = apiCompRegExp.exec(content);
239
238
  }
@@ -247,7 +246,7 @@ function pluginApiDocgen(options) {
247
246
  },
248
247
  markdown: {
249
248
  globalComponents: [
250
- __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(__dirname, '..', 'static', 'global-components', 'API.tsx')
249
+ node_path.join(__dirname, '..', 'static', 'global-components', 'API.tsx')
251
250
  ]
252
251
  }
253
252
  };
package/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- declare module '@rspress/shared' {
1
+ declare module 'rspress/core' {
2
2
  interface PageIndexInfo {
3
3
  apiDocMap?: Record<string, string>;
4
4
  }
5
5
  }
6
6
 
7
+
7
8
  export * from './dist'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspress/plugin-api-docgen",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.21",
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,11 +12,11 @@
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
22
  "static",
@@ -25,27 +25,29 @@
25
25
  "dependencies": {
26
26
  "chokidar": "^3.6.0",
27
27
  "documentation": "14.0.3",
28
- "react-docgen-typescript": "2.2.2",
28
+ "github-slugger": "^2.0.0",
29
+ "react-docgen-typescript": "2.4.0",
29
30
  "react-markdown": "^10.1.0",
30
31
  "remark-gfm": "^4.0.1",
31
32
  "unified": "^11.0.5",
32
- "@rspress/shared": "2.0.0-beta.2"
33
+ "unist-util-visit": "^5.0.0"
33
34
  },
34
35
  "devDependencies": {
35
- "@microsoft/api-extractor": "^7.52.4",
36
- "@rslib/core": "0.6.5",
36
+ "@microsoft/api-extractor": "^7.52.8",
37
+ "@rslib/core": "0.10.5",
38
+ "@types/hast": "^3.0.4",
37
39
  "@types/mdast": "^4.0.4",
38
- "@types/node": "^18.11.17",
39
- "@types/react": "^18.3.20",
40
- "@types/react-dom": "^18.3.6",
40
+ "@types/node": "^22.8.1",
41
+ "@types/react": "^19.1.8",
42
+ "@types/react-dom": "^19.1.6",
41
43
  "react": "^19.1.0",
42
44
  "react-dom": "^19.1.0",
43
45
  "react-router-dom": "^6.29.0",
44
- "rsbuild-plugin-publint": "^0.3.0",
46
+ "rsbuild-plugin-publint": "^0.3.2",
45
47
  "typescript": "^5.8.2"
46
48
  },
47
49
  "peerDependencies": {
48
- "@rspress/core": "^2.0.0-beta.2",
50
+ "rspress": "^2.0.0-beta.21",
49
51
  "typescript": "^5.8.2"
50
52
  },
51
53
  "peerDependenciesMeta": {
@@ -1,10 +1,102 @@
1
1
  /// <reference path="../../index.d.ts" />
2
2
 
3
- import { useLang, usePageData } from '@rspress/core/runtime';
4
- import { getCustomMDXComponent } from '@rspress/core/theme';
3
+ // @ts-ignore @theme is overridden by alias in @rspress/core
4
+ import { getCustomMDXComponent } from '@theme';
5
5
  import ReactMarkdown from 'react-markdown';
6
6
  import remarkGfm from 'remark-gfm';
7
+ import { useLang, usePageData } from 'rspress/runtime';
7
8
  import './API.css';
9
+ import GithubSlugger from 'github-slugger';
10
+ import type { Content, Element, Root } from 'hast';
11
+ // biome-ignore lint/style/useImportType: <exact>
12
+ import React from 'react';
13
+ import type { Plugin } from 'unified';
14
+ import { visit } from 'unist-util-visit';
15
+
16
+ function headingRank(node: Root | Content): number | null {
17
+ const name =
18
+ (node && node.type === 'element' && node.tagName.toLowerCase()) || '';
19
+ const code =
20
+ name.length === 2 && name.charCodeAt(0) === 104 /* `h` */
21
+ ? name.charCodeAt(1)
22
+ : 0;
23
+ return code > 48 /* `0` */ && code < 55 /* `7` */
24
+ ? code - 48 /* `0` */
25
+ : null;
26
+ }
27
+
28
+ const rehypeHeaderAnchor: Plugin<[], Root> = () => {
29
+ const slugger = new GithubSlugger();
30
+ return tree => {
31
+ visit(tree, 'element', node => {
32
+ if (!headingRank(node)) {
33
+ return;
34
+ }
35
+ // generate id
36
+
37
+ if (!node.properties?.id) {
38
+ const text = collectHeaderText(node);
39
+ node.properties ??= {};
40
+ node.properties.id = slugger.slug(text.trim());
41
+ }
42
+ // apply to headings
43
+ node.children.unshift(create(node));
44
+ });
45
+ };
46
+ };
47
+
48
+ /**
49
+ * Create an `a`.
50
+ *
51
+ * @param {Readonly<Element>} node
52
+ * Related heading.
53
+ * @returns {Element}
54
+ * Link.
55
+ */
56
+ function create(node: Element): Element {
57
+ return {
58
+ type: 'element',
59
+ tagName: 'a',
60
+ properties: {
61
+ class: 'header-anchor',
62
+ ariaHidden: 'true',
63
+ href: `#${node.properties!.id}`,
64
+ },
65
+ children: [
66
+ {
67
+ type: 'text',
68
+ value: '#',
69
+ },
70
+ ],
71
+ };
72
+ }
73
+
74
+ const extractTextAndId = (title?: string): string => {
75
+ if (!title) {
76
+ return '';
77
+ }
78
+ const text = title.trimEnd();
79
+ return text;
80
+ };
81
+
82
+ const collectHeaderText = (node: Element): string => {
83
+ let text = '';
84
+ node.children.forEach(child => {
85
+ if (child.type === 'text') {
86
+ const textPart = extractTextAndId(child.value);
87
+ child.value = textPart;
88
+ text += textPart;
89
+ }
90
+ if (child.type === 'element') {
91
+ child.children.forEach(c => {
92
+ if (c.type === 'text') {
93
+ text += c.value;
94
+ }
95
+ });
96
+ }
97
+ });
98
+ return text;
99
+ };
8
100
 
9
101
  export default (props: { moduleName: string }) => {
10
102
  const lang = useLang();
@@ -19,6 +111,7 @@ export default (props: { moduleName: string }) => {
19
111
  <div className="rspress-plugin-api-docgen">
20
112
  <ReactMarkdown
21
113
  remarkPlugins={[[remarkGfm]]}
114
+ rehypePlugins={[[rehypeHeaderAnchor]]}
22
115
  components={
23
116
  getCustomMDXComponent() as Record<string, React.ElementType>
24
117
  }