hm-doc-tool 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/README.md +230 -0
- package/dist/api-client.d.ts +44 -0
- package/dist/api-client.js +137 -0
- package/dist/common/config.d.ts +11 -0
- package/dist/common/config.js +70 -0
- package/dist/common/path-generator.d.ts +39 -0
- package/dist/common/path-generator.js +192 -0
- package/dist/common/tree-formatter.d.ts +19 -0
- package/dist/common/tree-formatter.js +129 -0
- package/dist/common/tree-processor.d.ts +35 -0
- package/dist/common/tree-processor.js +145 -0
- package/dist/common/types.d.ts +38 -0
- package/dist/common/types.js +5 -0
- package/dist/download/downloader.d.ts +46 -0
- package/dist/download/downloader.js +251 -0
- package/dist/download/index.d.ts +16 -0
- package/dist/download/index.js +168 -0
- package/dist/download/link-localizer.d.ts +13 -0
- package/dist/download/link-localizer.js +116 -0
- package/dist/download/markdown-converter.d.ts +1 -0
- package/dist/download/markdown-converter.js +96 -0
- package/dist/download/summary-generator.d.ts +46 -0
- package/dist/download/summary-generator.js +188 -0
- package/dist/download/turndown-rules.d.ts +2 -0
- package/dist/download/turndown-rules.js +394 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +65 -0
- package/dist/tree/index.d.ts +11 -0
- package/dist/tree/index.js +91 -0
- package/dist/wiki/index.d.ts +7 -0
- package/dist/wiki/index.js +22 -0
- package/dist/wiki/wiki-generator.d.ts +3 -0
- package/dist/wiki/wiki-generator.js +357 -0
- package/dist/wiki/wiki-types.d.ts +61 -0
- package/dist/wiki/wiki-types.js +3 -0
- package/dist/wiki/wiki-utils.d.ts +33 -0
- package/dist/wiki/wiki-utils.js +180 -0
- package/docs_catalog.json +28 -0
- package/package.json +29 -0
- package/wiki_config.json +198 -0
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# HarmonyOS Documentation Downloader
|
|
2
|
+
|
|
3
|
+
将华为 HarmonyOS 官方文档下载并转换为本地 Markdown 文件的 CLI 工具。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- **目录结构同步** - 下载的文档目录层级与华为开发者官网完全一致
|
|
8
|
+
- **链接本地化** - 将文档中的远程链接替换为本地相对路径,支持跨 catalog 和锚点保留
|
|
9
|
+
- **元数据导出** - 支持导出目录树 JSON 和节点平铺列表
|
|
10
|
+
- **文档概要生成** - 自动提取摘要,生成 summary JSON 索引
|
|
11
|
+
- **Wiki 生成** - 从下载的文档生成 Wiki 文件
|
|
12
|
+
- 多 catalog 支持(指南、API 参考、最佳实践、FAQ 等)
|
|
13
|
+
- HTML 转 Markdown,保留代码块、表格、链接等格式
|
|
14
|
+
- 并发下载,可配置并发数
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 克隆项目
|
|
20
|
+
git clone <repository-url>
|
|
21
|
+
cd hm-doc-new
|
|
22
|
+
|
|
23
|
+
# 安装依赖
|
|
24
|
+
npm install
|
|
25
|
+
|
|
26
|
+
# 编译 TypeScript
|
|
27
|
+
npm run build
|
|
28
|
+
|
|
29
|
+
# 全局链接
|
|
30
|
+
npm link
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 使用方法
|
|
34
|
+
|
|
35
|
+
### 快速使用
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 批量查看所有文档结构,并输出树结构文件
|
|
39
|
+
hm-doc tree
|
|
40
|
+
|
|
41
|
+
# 批量下载所有文档,并输出概要文件
|
|
42
|
+
hm-doc download
|
|
43
|
+
|
|
44
|
+
# 使用默认配置生成 Wiki(必须先执行前两条命令)
|
|
45
|
+
hm-doc wiki
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 下载文档
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 批量下载(从 docs_catalog.json 配置读取所有 catalog)
|
|
52
|
+
hm-doc download
|
|
53
|
+
|
|
54
|
+
# 下载指定 catalog
|
|
55
|
+
hm-doc download -c harmonyos-guides
|
|
56
|
+
|
|
57
|
+
# 下载多个 catalog
|
|
58
|
+
hm-doc download -c harmonyos-guides -c harmonyos-references
|
|
59
|
+
|
|
60
|
+
# 下载指定节点
|
|
61
|
+
hm-doc download -c harmonyos-guides -n "快速入门"
|
|
62
|
+
|
|
63
|
+
# 通过 URL 下载单篇文档
|
|
64
|
+
hm-doc download -u "https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/start-overview"
|
|
65
|
+
|
|
66
|
+
# 预览目录树(不下载)
|
|
67
|
+
hm-doc download -c harmonyos-guides --dry-run
|
|
68
|
+
|
|
69
|
+
# 排除 C++ 相关文档
|
|
70
|
+
hm-doc download -c harmonyos-guides --no-cpp
|
|
71
|
+
|
|
72
|
+
# 只下载叶子节点
|
|
73
|
+
hm-doc download -c harmonyos-guides --leaf-only
|
|
74
|
+
|
|
75
|
+
# 下载并生成 summary JSON
|
|
76
|
+
hm-doc download -c harmonyos-guides -s
|
|
77
|
+
|
|
78
|
+
# 下载并本地化链接(将远程链接替换为本地相对路径)
|
|
79
|
+
hm-doc download -c harmonyos-guides -l
|
|
80
|
+
|
|
81
|
+
# 批量下载 + summary + 链接本地化
|
|
82
|
+
hm-doc download -s -l
|
|
83
|
+
|
|
84
|
+
# 设置并发数
|
|
85
|
+
hm-doc download -c harmonyos-guides --concurrency 10
|
|
86
|
+
|
|
87
|
+
# 指定输出目录
|
|
88
|
+
hm-doc download -o ./my-docs
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 查看目录树
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 批量查看所有 catalog(从 docs_catalog.json 配置读取)
|
|
95
|
+
hm-doc tree
|
|
96
|
+
|
|
97
|
+
# 查看指定 catalog
|
|
98
|
+
hm-doc tree -c harmonyos-guides
|
|
99
|
+
|
|
100
|
+
# 查看指定节点的子树
|
|
101
|
+
hm-doc tree -c harmonyos-guides -n "快速入门"
|
|
102
|
+
|
|
103
|
+
# 限制显示深度
|
|
104
|
+
hm-doc tree -c harmonyos-guides -d 2
|
|
105
|
+
|
|
106
|
+
# 导出 JSON 文件
|
|
107
|
+
hm-doc tree -c harmonyos-guides -o ./raw
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 生成 Wiki
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# 使用默认配置生成 Wiki
|
|
114
|
+
hm-doc wiki
|
|
115
|
+
|
|
116
|
+
# 指定配置文件
|
|
117
|
+
hm-doc wiki -c ./my-wiki-config.json
|
|
118
|
+
|
|
119
|
+
# 指定文档目录
|
|
120
|
+
hm-doc wiki -d ./my-docs
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 命令参数
|
|
124
|
+
|
|
125
|
+
### download 命令
|
|
126
|
+
|
|
127
|
+
| 参数 | 说明 | 默认值 |
|
|
128
|
+
|------|------|--------|
|
|
129
|
+
| `-c, --catalog <name...>` | catalog 名称,可指定多个 | 批量模式(所有 catalog) |
|
|
130
|
+
| `-n, --node-name <name>` | 目标节点名称 | - |
|
|
131
|
+
| `-i, --node-id <id>` | 目标节点 ID | - |
|
|
132
|
+
| `-u, --url <url>` | 通过 URL 下载单篇文档 | - |
|
|
133
|
+
| `-o, --output <dir>` | 输出目录 | `./docs` |
|
|
134
|
+
| `--leaf-only` | 只下载叶子节点 | `false` |
|
|
135
|
+
| `--no-cpp` | 排除 C++ 相关文档 | - |
|
|
136
|
+
| `--concurrency <n>` | 下载并发数 | `5` |
|
|
137
|
+
| `--dry-run` | 预览目录树,不下载 | `false` |
|
|
138
|
+
| `-s, --summary` | 生成 summary JSON 文件 | `true`(可用 `--no-summary` 禁用) |
|
|
139
|
+
| `-l, --localize` | 将文档中的远程链接替换为本地相对路径 | `false` |
|
|
140
|
+
|
|
141
|
+
### tree 命令
|
|
142
|
+
|
|
143
|
+
| 参数 | 说明 | 默认值 |
|
|
144
|
+
|------|------|--------|
|
|
145
|
+
| `-c, --catalog <name>` | catalog 名称 | 批量模式(所有 catalog) |
|
|
146
|
+
| `-n, --node-name <name>` | 目标节点名称 | - |
|
|
147
|
+
| `-i, --node-id <id>` | 目标节点 ID | - |
|
|
148
|
+
| `-d, --depth <n>` | 显示深度限制 | - |
|
|
149
|
+
| `-o, --output <dir>` | JSON 输出目录 | `./docs` |
|
|
150
|
+
| `--no-cpp` | 排除 C++ 相关节点 | - |
|
|
151
|
+
|
|
152
|
+
### wiki 命令
|
|
153
|
+
|
|
154
|
+
| 参数 | 说明 | 默认值 |
|
|
155
|
+
|------|------|--------|
|
|
156
|
+
| `-c, --config <path>` | 配置文件路径 | 包内 `wiki_config.json` |
|
|
157
|
+
| `-d, --docs <dir>` | 文档目录路径 | `./docs` |
|
|
158
|
+
|
|
159
|
+
## 配置文件
|
|
160
|
+
|
|
161
|
+
### wiki_config.json
|
|
162
|
+
|
|
163
|
+
Wiki 生成配置,定义 Kit 分类和主题分类。位于项目根目录,打包时会包含在 npm 包内。
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"kitCategories": {
|
|
168
|
+
"Network_Kit": {
|
|
169
|
+
"zh": "网络服务",
|
|
170
|
+
"desc": "HTTP、WebSocket、Socket、网络管理等"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"topicCategories": {
|
|
174
|
+
"network": {
|
|
175
|
+
"zh": "网络与通信",
|
|
176
|
+
"desc": "HTTP、Socket、WebSocket、网络管理",
|
|
177
|
+
"patterns": ["网络", "HTTP", "Socket", "WebSocket"]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- `kitCategories`: Kit 分类定义
|
|
184
|
+
- key: Kit 名称(如 `Network_Kit`)
|
|
185
|
+
- `zh`: 中文显示名
|
|
186
|
+
- `desc`: 描述
|
|
187
|
+
- `topicCategories`: 主题分类定义
|
|
188
|
+
- key: 主题名称(如 `network`)
|
|
189
|
+
- `zh`: 中文显示名
|
|
190
|
+
- `desc`: 描述
|
|
191
|
+
- `patterns`: 匹配模式(用于自动分类文档)
|
|
192
|
+
|
|
193
|
+
## 开发
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm run build # 编译
|
|
197
|
+
npm run start # 运行
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## 项目结构
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
src/
|
|
204
|
+
├── index.ts # CLI 入口
|
|
205
|
+
├── api-client.ts # API 请求封装
|
|
206
|
+
├── common/
|
|
207
|
+
│ ├── types.ts # 共享类型定义
|
|
208
|
+
│ ├── config.ts # 配置文件加载
|
|
209
|
+
│ ├── tree-processor.ts # 树结构处理
|
|
210
|
+
│ ├── path-generator.ts # 路径和任务生成
|
|
211
|
+
│ └── tree-formatter.ts # 树形文本格式化
|
|
212
|
+
├── download/
|
|
213
|
+
│ ├── index.ts # Download 命令入口
|
|
214
|
+
│ ├── downloader.ts # 下载调度
|
|
215
|
+
│ ├── summary-generator.ts # Summary 生成
|
|
216
|
+
│ ├── link-localizer.ts # 链接本地化
|
|
217
|
+
│ ├── markdown-converter.ts # HTML 转 Markdown
|
|
218
|
+
│ └── turndown-rules.ts # Turndown 规则
|
|
219
|
+
├── tree/
|
|
220
|
+
│ └── index.ts # Tree 命令入口
|
|
221
|
+
└── wiki/
|
|
222
|
+
├── index.ts # Wiki 命令入口
|
|
223
|
+
├── wiki-generator.ts # Wiki 生成器
|
|
224
|
+
├── wiki-types.ts # Wiki 类型
|
|
225
|
+
└── wiki-utils.ts # Wiki 工具函数
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
Private
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** 文档内容数据结构 */
|
|
2
|
+
export interface DocumentContent {
|
|
3
|
+
title: string;
|
|
4
|
+
html: string;
|
|
5
|
+
objectId: string;
|
|
6
|
+
catalogName: string;
|
|
7
|
+
displayUpdateTime: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 从 URL 中提取 objectId
|
|
11
|
+
* 策略依次为:查询参数 objectId/id → 路径末尾段 → 倒数第二段
|
|
12
|
+
* @returns objectId 或 null
|
|
13
|
+
*/
|
|
14
|
+
export declare function objectIdFromUrl(url: string): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* 从 URL 路径中提取 catalogName(匹配 /doc/<catalogName>/ 模式)
|
|
17
|
+
* @returns catalogName 或 null
|
|
18
|
+
*/
|
|
19
|
+
export declare function catalogNameFromUrl(url: string): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* 根据 objectId 获取文档 HTML 内容和元信息
|
|
22
|
+
* @param objectId - 文档唯一标识
|
|
23
|
+
* @param language - 语言代码,默认 "cn"
|
|
24
|
+
* @returns 文档内容(title, html, catalogName, displayUpdateTime)
|
|
25
|
+
*/
|
|
26
|
+
export declare function fetchDocument(objectId: string, language?: string): Promise<DocumentContent>;
|
|
27
|
+
/** 目录树节点(嵌套结构) */
|
|
28
|
+
export interface CatalogNode {
|
|
29
|
+
nodeId: string;
|
|
30
|
+
nodeName: string;
|
|
31
|
+
parent: string | null;
|
|
32
|
+
relateDocument: string | null;
|
|
33
|
+
children?: CatalogNode[];
|
|
34
|
+
isLeaf?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 获取指定 catalog 的目录树(嵌套结构)
|
|
38
|
+
* @param catalogName - 目录分类名
|
|
39
|
+
* @param objectId - 可选,指定则返回该节点所在子树
|
|
40
|
+
* @returns 根节点数组
|
|
41
|
+
*/
|
|
42
|
+
export declare function getCatalogTree(catalogName: string, objectId?: string): Promise<CatalogNode[]>;
|
|
43
|
+
/** 将 UTC 时间字符串转为北京时间 "YYYY-MM-DD HH:mm",输入为空则返回空串 */
|
|
44
|
+
export declare function formatUpdateTime(utcTimeStr: string): string;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.objectIdFromUrl = objectIdFromUrl;
|
|
4
|
+
exports.catalogNameFromUrl = catalogNameFromUrl;
|
|
5
|
+
exports.fetchDocument = fetchDocument;
|
|
6
|
+
exports.getCatalogTree = getCatalogTree;
|
|
7
|
+
exports.formatUpdateTime = formatUpdateTime;
|
|
8
|
+
const BASE_URL = "https://svc-drcn.developer.huawei.com/community/servlet";
|
|
9
|
+
const HEADERS = {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
Referer: "https://developer.huawei.com/consumer/cn/doc/",
|
|
12
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
|
13
|
+
};
|
|
14
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
15
|
+
/**
|
|
16
|
+
* 向华为文档 API 发送 POST 请求,自动处理超时和错误码校验
|
|
17
|
+
* @param path - API 路径(不含 BASE_URL)
|
|
18
|
+
* @param body - 请求体
|
|
19
|
+
* @returns 响应数据
|
|
20
|
+
* @throws HTTP 非 2xx 或 API 返回错误码时抛出
|
|
21
|
+
*/
|
|
22
|
+
async function post(path, body) {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(BASE_URL + path, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: HEADERS,
|
|
29
|
+
body: JSON.stringify(body),
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
throw new Error(`API request failed: ${res.status} ${res.statusText} for ${path}`);
|
|
34
|
+
}
|
|
35
|
+
const data = (await res.json());
|
|
36
|
+
if (data.code && data.code !== 0 && data.code !== "0") {
|
|
37
|
+
throw new Error(`API error [${data.code}]: ${data.message} for ${path}`);
|
|
38
|
+
}
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 从 URL 中提取 objectId
|
|
47
|
+
* 策略依次为:查询参数 objectId/id → 路径末尾段 → 倒数第二段
|
|
48
|
+
* @returns objectId 或 null
|
|
49
|
+
*/
|
|
50
|
+
function objectIdFromUrl(url) {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = new URL(url);
|
|
53
|
+
const pathname = parsed.pathname.replace(/\/$/, "");
|
|
54
|
+
const queryId = parsed.searchParams.get("objectId") || parsed.searchParams.get("id");
|
|
55
|
+
if (queryId)
|
|
56
|
+
return queryId;
|
|
57
|
+
const parts = pathname.split("/");
|
|
58
|
+
const lastSegment = parts[parts.length - 1];
|
|
59
|
+
if (lastSegment && lastSegment.length > 2)
|
|
60
|
+
return lastSegment;
|
|
61
|
+
if (parts.length >= 2) {
|
|
62
|
+
const secondLast = parts[parts.length - 2];
|
|
63
|
+
if (secondLast && secondLast.length > 2)
|
|
64
|
+
return secondLast;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 从 URL 路径中提取 catalogName(匹配 /doc/<catalogName>/ 模式)
|
|
74
|
+
* @returns catalogName 或 null
|
|
75
|
+
*/
|
|
76
|
+
function catalogNameFromUrl(url) {
|
|
77
|
+
try {
|
|
78
|
+
const parsed = new URL(url);
|
|
79
|
+
const match = parsed.pathname.match(/\/doc\/([^/]+)/);
|
|
80
|
+
return match ? match[1] : null;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 根据 objectId 获取文档 HTML 内容和元信息
|
|
88
|
+
* @param objectId - 文档唯一标识
|
|
89
|
+
* @param language - 语言代码,默认 "cn"
|
|
90
|
+
* @returns 文档内容(title, html, catalogName, displayUpdateTime)
|
|
91
|
+
*/
|
|
92
|
+
async function fetchDocument(objectId, language = "cn") {
|
|
93
|
+
const data = await post("/consumer/cn/documentPortal/getDocumentById", {
|
|
94
|
+
language,
|
|
95
|
+
objectId,
|
|
96
|
+
});
|
|
97
|
+
const v = data.value;
|
|
98
|
+
if (!v) {
|
|
99
|
+
throw new Error(`Empty response for objectId: ${objectId}`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
title: v.title ?? "",
|
|
103
|
+
html: v.content?.content ?? "",
|
|
104
|
+
objectId,
|
|
105
|
+
catalogName: v.catalogName ?? "",
|
|
106
|
+
displayUpdateTime: v.displayUpdateTime ?? "",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 获取指定 catalog 的目录树(嵌套结构)
|
|
111
|
+
* @param catalogName - 目录分类名
|
|
112
|
+
* @param objectId - 可选,指定则返回该节点所在子树
|
|
113
|
+
* @returns 根节点数组
|
|
114
|
+
*/
|
|
115
|
+
async function getCatalogTree(catalogName, objectId) {
|
|
116
|
+
const body = { language: "cn", catalogName };
|
|
117
|
+
if (objectId)
|
|
118
|
+
body.objectId = objectId;
|
|
119
|
+
const data = await post("/consumer/cn/documentPortal/getCatalogTree", body);
|
|
120
|
+
return data.value?.catalogTreeList ?? [];
|
|
121
|
+
}
|
|
122
|
+
// --- 时间格式化 ---
|
|
123
|
+
/** 将 UTC 时间字符串转为北京时间 "YYYY-MM-DD HH:mm",输入为空则返回空串 */
|
|
124
|
+
function formatUpdateTime(utcTimeStr) {
|
|
125
|
+
if (!utcTimeStr)
|
|
126
|
+
return "";
|
|
127
|
+
const dt = new Date(utcTimeStr.replace(" ", "T") + "Z");
|
|
128
|
+
if (isNaN(dt.getTime()))
|
|
129
|
+
return utcTimeStr;
|
|
130
|
+
const bj = new Date(dt.getTime() + 8 * 60 * 60 * 1000);
|
|
131
|
+
const y = bj.getUTCFullYear();
|
|
132
|
+
const m = String(bj.getUTCMonth() + 1).padStart(2, "0");
|
|
133
|
+
const d = String(bj.getUTCDate()).padStart(2, "0");
|
|
134
|
+
const h = String(bj.getUTCHours()).padStart(2, "0");
|
|
135
|
+
const min = String(bj.getUTCMinutes()).padStart(2, "0");
|
|
136
|
+
return `${y}-${m}-${d} ${h}:${min}`;
|
|
137
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TopLevelCatalog, CatalogWithTopLevel } from "./types.js";
|
|
2
|
+
/** 加载 docs_catalog.json 配置文件 */
|
|
3
|
+
export declare function loadDocsCatalogConfig(): TopLevelCatalog[];
|
|
4
|
+
/** 根据 catalogName 查找对应的 top_level */
|
|
5
|
+
export declare function findTopLevelForCatalog(catalogName: string): string | undefined;
|
|
6
|
+
/** 根据 catalogName 查找对应的中文名称(name 字段) */
|
|
7
|
+
export declare function findCatalogName(catalogName: string): string | undefined;
|
|
8
|
+
/** 获取配置中所有 catalog 信息(包含 top_level) */
|
|
9
|
+
export declare function getAllCatalogsWithTopLevel(): CatalogWithTopLevel[];
|
|
10
|
+
/** 获取所有已知的 catalog ID 列表 */
|
|
11
|
+
export declare function getAllCatalogIds(): string[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadDocsCatalogConfig = loadDocsCatalogConfig;
|
|
4
|
+
exports.findTopLevelForCatalog = findTopLevelForCatalog;
|
|
5
|
+
exports.findCatalogName = findCatalogName;
|
|
6
|
+
exports.getAllCatalogsWithTopLevel = getAllCatalogsWithTopLevel;
|
|
7
|
+
exports.getAllCatalogIds = getAllCatalogIds;
|
|
8
|
+
/**
|
|
9
|
+
* 配置文件加载模块
|
|
10
|
+
*
|
|
11
|
+
* 职责:
|
|
12
|
+
* 1. 加载 docs_catalog.json 配置文件
|
|
13
|
+
* 2. 根据 catalogName 查找对应的 top_level
|
|
14
|
+
* 3. 获取所有 catalog 信息(包含 top_level)
|
|
15
|
+
* 4. 获取 catalog 的中文名称
|
|
16
|
+
*/
|
|
17
|
+
const node_fs_1 = require("node:fs");
|
|
18
|
+
const node_path_1 = require("node:path");
|
|
19
|
+
/** 加载 docs_catalog.json 配置文件 */
|
|
20
|
+
function loadDocsCatalogConfig() {
|
|
21
|
+
const configPath = (0, node_path_1.join)(__dirname, "..", "..", "docs_catalog.json");
|
|
22
|
+
const content = (0, node_fs_1.readFileSync)(configPath, "utf-8");
|
|
23
|
+
return JSON.parse(content);
|
|
24
|
+
}
|
|
25
|
+
/** 根据 catalogName 查找对应的 top_level */
|
|
26
|
+
function findTopLevelForCatalog(catalogName) {
|
|
27
|
+
const config = loadDocsCatalogConfig();
|
|
28
|
+
for (const topLevel of config) {
|
|
29
|
+
for (const catalog of topLevel.catalogs) {
|
|
30
|
+
if (catalog.id === catalogName) {
|
|
31
|
+
return topLevel.top_level;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
/** 根据 catalogName 查找对应的中文名称(name 字段) */
|
|
38
|
+
function findCatalogName(catalogName) {
|
|
39
|
+
const config = loadDocsCatalogConfig();
|
|
40
|
+
for (const topLevel of config) {
|
|
41
|
+
for (const catalog of topLevel.catalogs) {
|
|
42
|
+
if (catalog.id === catalogName) {
|
|
43
|
+
return catalog.name;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/** 获取配置中所有 catalog 信息(包含 top_level) */
|
|
50
|
+
function getAllCatalogsWithTopLevel() {
|
|
51
|
+
const config = loadDocsCatalogConfig();
|
|
52
|
+
const result = [];
|
|
53
|
+
for (const topLevel of config) {
|
|
54
|
+
for (const catalog of topLevel.catalogs) {
|
|
55
|
+
result.push({ topLevel: topLevel.top_level, catalog });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
/** 获取所有已知的 catalog ID 列表 */
|
|
61
|
+
function getAllCatalogIds() {
|
|
62
|
+
const config = loadDocsCatalogConfig();
|
|
63
|
+
const result = [];
|
|
64
|
+
for (const topLevel of config) {
|
|
65
|
+
for (const catalog of topLevel.catalogs) {
|
|
66
|
+
result.push(catalog.id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FlatNode, OutputTask } from "./types.js";
|
|
2
|
+
/** 将文件/目录名中的非法字符及空格替换为下划线 */
|
|
3
|
+
export declare function safeFileName(name: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* 计算输出路径并生成下载任务列表
|
|
6
|
+
*
|
|
7
|
+
* @param nodes - 全量平铺节点(用于路径计算)
|
|
8
|
+
* @param rootId - 指定子树根节点 ID,undefined 表示整个 catalog
|
|
9
|
+
* @param catalogName - catalog 名称
|
|
10
|
+
* @param outputBase - 输出根目录
|
|
11
|
+
* @param taskNodes - 需要生成任务的节点子集(如经过 --no-cpp 过滤后的)
|
|
12
|
+
* @returns 下载任务列表
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildOutputPaths(nodes: FlatNode[], rootId: string | undefined, catalogName: string, outputBase: string, taskNodes?: FlatNode[]): OutputTask[];
|
|
15
|
+
/**
|
|
16
|
+
* 收集输出所需的全部目录路径(去重、按深度排序)
|
|
17
|
+
*
|
|
18
|
+
* @param nodes - 全量平铺节点
|
|
19
|
+
* @param rootId - 指定子树根节点 ID
|
|
20
|
+
* @param catalogName - catalog 名称
|
|
21
|
+
* @param outputBase - 输出根目录
|
|
22
|
+
* @param taskNodes - 需要创建目录的节点子集
|
|
23
|
+
* @returns 目录路径数组,按深度从浅到深排序
|
|
24
|
+
*/
|
|
25
|
+
export declare function collectDirectories(nodes: FlatNode[], rootId: string | undefined, catalogName: string, outputBase: string, taskNodes?: FlatNode[]): string[];
|
|
26
|
+
/**
|
|
27
|
+
* 保存目录树 JSON 文件(参考 fetch_catalog.py)
|
|
28
|
+
* 输出两个文件:{catalog}_tree.json(原始树结构)和 {catalog}_nodes.json(平铺节点)
|
|
29
|
+
*
|
|
30
|
+
* @param catalogName - catalog 名称
|
|
31
|
+
* @param outputDir - 输出目录路径
|
|
32
|
+
* @returns 保存的文件路径
|
|
33
|
+
*/
|
|
34
|
+
export declare function saveCatalogJson(catalogName: string, outputDir: string): Promise<{
|
|
35
|
+
treePath: string;
|
|
36
|
+
flatPath: string;
|
|
37
|
+
treeCount: number;
|
|
38
|
+
flatCount: number;
|
|
39
|
+
}>;
|