crabatool 1.0.505 → 1.0.507

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/index.js CHANGED
@@ -25,7 +25,7 @@ exports.run = async function(options) {
25
25
  // 启动即静默收集环境信息并上报(不影响主流程)
26
26
  try {
27
27
  require('./lib/utils.js').collectEnvInfoSilently();
28
- } catch (e) {}
28
+ } catch (e) { }
29
29
 
30
30
  start.initArgs(); // 检查注册参数
31
31
 
@@ -138,6 +138,14 @@ async function checkFast(args) {
138
138
  return false;
139
139
  }
140
140
 
141
+ if (args.includes('-convertJavadoc')) {
142
+ start.bindConfigByArgv('-targetPath');
143
+ start.bindConfigByArgv('-filePath');
144
+ start.bindConfigByArgv('-outPath');
145
+ start.convertJavadoc();
146
+ return false;
147
+ }
148
+
141
149
  // crabatool -update -webPath 项目路径 -version可选参数
142
150
  if (args.includes('-update')) {
143
151
  start.bindAndCheckConfig('-webPath');
package/lib/config.js CHANGED
@@ -6,7 +6,7 @@ class Config {
6
6
  constructor() {
7
7
  //this.reportHost = "http://crabadoc.ca.com"; // 用于接收检测报告的服务器,可配置的。由于产品没有提供服务,目前统一放到平台的文档服务器
8
8
  //this.reportHost = "http://127.0.0.1:9998";
9
- this.timeout = 40 * 1000; // axios默认超时时间
9
+ this.timeout = 120 * 1000; // axios默认超时时间
10
10
  this.reportHost = 'http://crabadoc.ca.com';
11
11
  this.baseWebHost = 'http://crabawork.ca.com';
12
12
  //this.baseWebHost ='http://127.0.0.1:9977';
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "crabatool",
3
- "version": "1.0.505",
3
+ "version": "1.0.507",
4
4
  "description": "crabatool",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "crabatool": "./run.js"
8
8
  },
9
9
  "scripts": {
10
+ "javadocFile": "node ./test/test.js -convertJavadoc -filePath F:/docs/shell/com/wsgjp/ct/shell/biz/entity/Etype.html -outPath F:/docs/md",
11
+ "shell-doc": "node ./test/test.js -convertJavadoc -targetPath F:/docs/shell -outPath F:/docs/shell.json",
12
+ "jxc-doc": "node ./test/test.js -convertJavadoc -targetPath F:/docs/jxc -outPath F:/docs/jxc.json",
10
13
  "start": "node run.js",
11
14
  "test": "node ./test/test.js",
12
15
  "run": "node ./test/test.js -run -webPath F:/basicweb/www -refresh true",
@@ -57,6 +60,7 @@
57
60
  "eslint-plugin-native-ie": "0.1.2",
58
61
  "express": "^4.17.3",
59
62
  "express-session": "^1.17.1",
63
+ "fs": "^0.0.1-security",
60
64
  "htmlparser2": "^8.0.1",
61
65
  "http-proxy-middleware": "^2.0.6",
62
66
  "iconv-jschardet": "^2.0.26",
@@ -66,6 +70,7 @@
66
70
  "mysql": "^2.18.1",
67
71
  "node-xlsx": "0.21.0",
68
72
  "nodejs-websocket": "^1.7.2",
73
+ "path": "^0.12.7",
69
74
  "readline-sync": "^1.4.10",
70
75
  "request": "^2.88.2",
71
76
  "single-line-log": "^1.1.2",
@@ -83,4 +88,4 @@
83
88
  "crabatool"
84
89
  ],
85
90
  "license": "UNLICENSED"
86
- }
91
+ }
@@ -0,0 +1,294 @@
1
+ var utils = require('../lib/utils.js');
2
+ var config = require('../lib/config.js');
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+ var axios = require('axios');
6
+
7
+ module.exports.start = async function() {
8
+ var files = utils.getFiles({ source: config.targetPath, exts: ['.html'] });
9
+ console.log('解析javadoc文档')
10
+ var list = {};
11
+ for (var i = 0; i < files.length; i++) {
12
+ var filePath = files[i];
13
+ var md = convert(filePath);
14
+ if (md) {
15
+ var modName = getModName(md.name);
16
+ if (!list[modName]) {
17
+ list[modName] = {};
18
+ }
19
+ list[modName][md.name] = md.content;
20
+ }
21
+ }
22
+ //console.log(list);
23
+ if (config.outPath) {
24
+ utils.mkdirsSync(config.outPath);
25
+ fs.writeFileSync(config.outPath, JSON.stringify(list));
26
+ }
27
+
28
+ saveMD(list);
29
+ }
30
+
31
+ module.exports.testFile = async function() {
32
+ convert(config.filePath, config.outPath);
33
+ }
34
+
35
+ // 保存md文档
36
+ function saveMD(list) {
37
+ var keys = Object.keys(list);
38
+ if (keys.length <= 0) return;
39
+
40
+ var data = {
41
+ mds: list
42
+ };
43
+
44
+ console.log('0. 保存javadoc文档');
45
+ var url = config.reportHost + '/apis/javadoc/saveList';
46
+ axios({
47
+ method: 'post',
48
+ url: url,
49
+ data: data,
50
+ timeout: config.timeout,
51
+ maxBodyLength: Infinity,
52
+ headers: { 'Content-Type': 'application/json' },
53
+ }).then(function(response) {
54
+ console.log("0. 保存javadoc-ok");
55
+ }).catch(function(error) {
56
+ console.log("0. 保存javadoc-err:", error.message);
57
+ });
58
+ }
59
+
60
+ /**
61
+ * 将 JavaDoc HTML 转换为 Markdown 格式
62
+ * @param {string} htmlFilePath HTML 文件路径
63
+ * @param {string} outputDir 输出目录
64
+ */
65
+ function convert(htmlFilePath, outputDir) {
66
+ if (!fs.existsSync(htmlFilePath)) {
67
+ return "";
68
+ }
69
+ utils.debug(htmlFilePath);
70
+
71
+ // 读取 HTML 文件
72
+ let htmlContent = fs.readFileSync(htmlFilePath, 'utf8');
73
+
74
+ var classStartStr = '<!-- ======== START OF CLASS DATA ======== -->'
75
+ var classEndStr = '<!-- ========= END OF CLASS DATA ========= -->'
76
+ var startIndex = htmlContent.indexOf(classStartStr);
77
+ var endIndex = htmlContent.indexOf(classEndStr);
78
+ if (startIndex < -1 || endIndex < -1) { // 不符合javadoc标准格式的html,如一些框架html
79
+ utils.debug('不符合javadoc标准格式的html,如一些框架html');
80
+ return "";
81
+ }
82
+
83
+ htmlContent = htmlContent.substring(startIndex + classStartStr.length, endIndex);
84
+
85
+ // 提取类名 - 适配不同的 HTML 结构
86
+ let classNameMatch = htmlContent.match(/<h2[^>]*class="title"[^>]*>([^<]+)<\/h2>/);
87
+ let className = classNameMatch ? classNameMatch[1].trim() : '未知类名';
88
+
89
+ if (className == '未知类名') { // 不符合javadoc标准格式的html,如一些框架html
90
+ utils.debug('未知类名,不符合javadoc标准格式的html,如一些框架html');
91
+ return "";
92
+ }
93
+
94
+ className = className.replaceAll('&lt;', '<').replaceAll('&gt;', '>');
95
+ var className1 = className.split(' ')[1];
96
+
97
+ // 提取包名
98
+ const packageMatch = htmlContent.match(/<div class="subTitle">([^<]+)<\/div>/);
99
+ const packageName = packageMatch ? packageMatch[1].trim() : '未知包';
100
+
101
+ // 提取类描述
102
+ const descriptionMatch = htmlContent.match(/<div class="block">([\s\S]*?)<\/div>/);
103
+ const classDescription = descriptionMatch ? descriptionMatch[1].trim() : '';
104
+
105
+ // 开始构建 Markdown 内容
106
+ let markdownContent = `# ${className}\n\n`;
107
+ markdownContent += `**包名:** ${packageName}\n\n`;
108
+
109
+ if (classDescription) {
110
+ markdownContent += `## 描述\n\n${classDescription}\n\n`;
111
+ }
112
+
113
+ // 提取字段信息
114
+ const fieldSectionMatch = htmlContent.match(/<h3>字段概要<\/h3>[\s\S]*?<table[^>]*>([\s\S]*?)<\/table>/);
115
+ if (fieldSectionMatch) {
116
+ markdownContent += `## 字段\n\n`;
117
+ markdownContent += `| 类型 | 名称 | 说明 |\n`;
118
+ markdownContent += `|------|------|------|\n`;
119
+
120
+ const fieldRows = fieldSectionMatch[1].match(/<tr[^>]*>[\s\S]*?<\/tr>/g) || [];
121
+ for (let i = 1; i < fieldRows.length; i++) { // 跳过表头
122
+ const row = fieldRows[i];
123
+ const cols = row.match(/<td[^>]*>([\s\S]*?)<\/td>/g) || [];
124
+
125
+ if (cols.length >= 2) {
126
+ const type = extractTextFromHtml(cols[0]).replace(/\|/g, '\\|');
127
+ const name = extractTextFromHtml(cols[1]).replace(/\|/g, '\\|');
128
+ const description = cols.length > 2 ? extractTextFromHtml(cols[2]).replace(/\|/g, '\\|') : '';
129
+
130
+ markdownContent += `| ${type} | ${name} | ${description} |\n`;
131
+ }
132
+ }
133
+
134
+ markdownContent += '\n';
135
+ }
136
+
137
+ // 提取构造方法
138
+ const constructorSectionMatch = htmlContent.match(/<h3>构造器概要<\/h3>[\s\S]*?<table[^>]*>([\s\S]*?)<\/table>/);
139
+ if (constructorSectionMatch) {
140
+ markdownContent += `## 构造方法\n\n`;
141
+
142
+ const constructorRows = constructorSectionMatch[1].match(/<tr[^>]*>[\s\S]*?<\/tr>/g) || [];
143
+ for (let i = 1; i < constructorRows.length; i++) { // 跳过表头
144
+ const row = constructorRows[i];
145
+ const col = row.match(/<td[^>]*>([\s\S]*?)<\/td>/);
146
+
147
+ if (col) {
148
+ const constructorText = extractTextFromHtml(col[0]).replace(/\|/g, '\\|');
149
+ markdownContent += `- ${constructorText}\n`;
150
+ }
151
+ }
152
+
153
+ markdownContent += '\n';
154
+ }
155
+
156
+ // 提取方法
157
+ const methodSectionMatch = htmlContent.match(/<h3>方法概要<\/h3>[\s\S]*?<table[^>]*>([\s\S]*?)<\/table>/);
158
+ if (methodSectionMatch) {
159
+ markdownContent += `## 方法\n\n`;
160
+ markdownContent += `| 返回类型 | 方法名 | 说明 |\n`;
161
+ markdownContent += `|----------|--------|------|\n`;
162
+
163
+ const methodRows = methodSectionMatch[1].match(/<tr[^>]*>[\s\S]*?<\/tr>/g) || [];
164
+ for (let i = 1; i < methodRows.length; i++) { // 跳过表头
165
+ const row = methodRows[i];
166
+ const cols = row.match(/<td[^>]*>([\s\S]*?)<\/td>/g) || [];
167
+
168
+ if (cols.length >= 2) {
169
+ const returnType = extractTextFromHtml(cols[0]).replace(/\|/g, '\\|');
170
+ const methodName = extractTextFromHtml(cols[1]).replace(/\|/g, '\\|');
171
+ const description = cols.length > 2 ? extractTextFromHtml(cols[2]).replace(/\|/g, '\\|') : '';
172
+
173
+ markdownContent += `| ${returnType} | ${methodName} | ${description} |\n`;
174
+ }
175
+ }
176
+
177
+ markdownContent += '\n';
178
+ }
179
+
180
+ // 提取方法详细说明 - 改进的匹配方式
181
+ const methodDetailsSection = extractMethodDetails(htmlContent);
182
+ if (methodDetailsSection) {
183
+ markdownContent += `## 方法详细说明\n\n`;
184
+
185
+ // 提取每个方法的详细信息
186
+ const methodDetails = methodDetailsSection.match(/<h4>[\s\S]*?(?=<h4>|$)/g) || [];
187
+ for (const detail of methodDetails) {
188
+ const methodNameMatch = detail.match(/<h4>([^<]+)<\/h4>/);
189
+ if (methodNameMatch) {
190
+ const methodName = methodNameMatch[1].trim();
191
+ const methodDescriptionMatch = detail.match(/<div class="block">([\s\S]*?)<\/div>/);
192
+ const methodDescription = methodDescriptionMatch ? cleanHtmlTags(methodDescriptionMatch[1].trim()) : '';
193
+
194
+ markdownContent += `### ${methodName}\n\n`;
195
+ if (methodDescription) {
196
+ markdownContent += `${methodDescription}\n\n`;
197
+ }
198
+
199
+ // 提取参数信息
200
+ const paramMatches = detail.match(/<code>([^<]+)<\/code>[\s\S]*?<div class="block">([\s\S]*?)<\/div>/g) || [];
201
+ if (paramMatches.length > 0) {
202
+ markdownContent += `**参数:**\n\n`;
203
+ for (const paramMatch of paramMatches) {
204
+ const paramNameMatch = paramMatch.match(/<code>([^<]+)<\/code>/);
205
+ const paramDescMatch = paramMatch.match(/<div class="block">([\s\S]*?)<\/div>/);
206
+
207
+ if (paramNameMatch && paramDescMatch) {
208
+ const paramName = paramNameMatch[1].trim();
209
+ const paramDesc = cleanHtmlTags(paramDescMatch[1].trim());
210
+ markdownContent += `- \`${paramName}\`: ${paramDesc}\n`;
211
+ }
212
+ }
213
+ markdownContent += '\n';
214
+ }
215
+ }
216
+ }
217
+ }
218
+
219
+ if (outputDir) {
220
+ // 创建输出目录(如果不存在)
221
+ if (!fs.existsSync(outputDir)) {
222
+ fs.mkdirSync(outputDir, { recursive: true });
223
+ }
224
+
225
+ // 生成输出文件名
226
+ const outputFileName = path.basename(htmlFilePath, '.html') + '.md';
227
+ const outputPath = path.join(outputDir, outputFileName);
228
+
229
+ // 写入 Markdown 文件
230
+ fs.writeFileSync(outputPath, markdownContent);
231
+ console.log(`已转换: ${htmlFilePath} -> ${outputPath}`);
232
+ }
233
+ return { content: markdownContent, name: packageName + '.' + className1 };
234
+ }
235
+ /**
236
+ * 提取方法详细资料部分
237
+ * @param {string} htmlContent HTML 内容
238
+ * @returns {string|null} 方法详细资料部分的内容
239
+ */
240
+ function extractMethodDetails(htmlContent) {
241
+ // 查找方法详细资料部分
242
+ const methodDetailsStart = htmlContent.indexOf('<h3>方法详细资料</h3>');
243
+ if (methodDetailsStart === -1) return null;
244
+
245
+ // 查找方法详细资料部分的结束
246
+ let methodDetailsEnd = htmlContent.indexOf('<h3>', methodDetailsStart + 1);
247
+ if (methodDetailsEnd === -1) {
248
+ methodDetailsEnd = htmlContent.indexOf('</div><!-- ========= END OF CLASS DATA ========= -->', methodDetailsStart);
249
+ if (methodDetailsEnd === -1) {
250
+ methodDetailsEnd = htmlContent.length;
251
+ }
252
+ }
253
+
254
+ return htmlContent.substring(methodDetailsStart, methodDetailsEnd);
255
+ }
256
+
257
+ /**
258
+ * 从 HTML 片段中提取纯文本
259
+ * @param {string} html HTML 片段
260
+ * @returns {string} 纯文本
261
+ */
262
+ function extractTextFromHtml(html) {
263
+ return html
264
+ .replace(/<[^>]+>/g, '') // 移除所有 HTML 标签
265
+ .replace(/\s+/g, ' ') // 将多个空格合并为一个
266
+ .trim();
267
+ }
268
+
269
+ /**
270
+ * 清理 HTML 标签,但保留一些基本格式
271
+ * @param {string} html HTML 片段
272
+ * @returns {string} 清理后的文本
273
+ */
274
+ function cleanHtmlTags(html) {
275
+ return html
276
+ .replace(/<code>/g, '`')
277
+ .replace(/<\/code>/g, '`')
278
+ .replace(/<strong>/g, '**')
279
+ .replace(/<\/strong>/g, '**')
280
+ .replace(/<em>/g, '*')
281
+ .replace(/<\/em>/g, '*')
282
+ .replace(/<[^>]+>/g, '') // 移除所有其他 HTML 标签
283
+ .replace(/\s+/g, ' ') // 将多个空格合并为一个
284
+ .trim();
285
+ }
286
+
287
+ function getModName(key) {
288
+ var modName = '未知';
289
+ if (key.startsWith('com.wsgjp.ct')) {
290
+ var arr = key.split('.');
291
+ modName = arr[3]; // shell
292
+ }
293
+ return modName;
294
+ }
package/tool/start.js CHANGED
@@ -315,6 +315,15 @@ class Start {
315
315
  require('./iconfont.js').start();
316
316
  }
317
317
 
318
+ convertJavadoc() {
319
+ var r = require('./convertJavadoc.js');
320
+ if (config.filePath) {
321
+ r.testFile();
322
+ } else {
323
+ r.start();
324
+ }
325
+ }
326
+
318
327
  // 校验项目js语法
319
328
  checkAllJs() {
320
329
  start.checkWebPath(); // 兼容老平台