job51-gitlab-cr-node-skill-prompt-optimize 1.3.8 → 1.3.9
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/.claude/anthropic.env +5 -0
- package/.claude/rules/code-review-rules.md +209 -0
- package/.claude/settings.json +10 -0
- package/.claude/settings.local.json +24 -1
- package/.claude/skills/simple-code-review/SKILL.md +68 -0
- package/.npmignore +12 -0
- package/index.js +628 -535
- package/mr-review-template.md +23 -141
- package/package.json +8 -4
- package/PDF_CONVERSION_README.md +0 -131
- package/convert-report-to-pdf.js +0 -240
- package/print-div-pdf.html +0 -167
- package/refactor(ci)_ /346/233/264/346/226/260GitLab CI/351/205/215/347/275/256/345/271/266/344/274/230/345/214/226/347/253/236/344/272/211/345/210/206/346/236/220/346/227/245/345/277/227/346/234/215/345/212/241 (!118) /302/267 Merge requests /302/267 51JobWeb _ dev-boot-test /302/267 GitLab.pdf +0 -0
package/mr-review-template.md
CHANGED
|
@@ -7,119 +7,19 @@
|
|
|
7
7
|
4. 不要添油加醋,仔细辨别代码的增删改;
|
|
8
8
|
5. 使用当前系统时间填充 `[当前时间]`,并根据实际变更内容计算 `[文件数量]`;
|
|
9
9
|
6. 所有占位符(如 `[具体问题描述]`)必须被真实内容替换,不可保留;
|
|
10
|
-
> - **修改建议中的代码示例**:
|
|
11
|
-
> - 错误代码:必须是**变更后实际存在的代码**(从变更内容中选取有问题的当前代码)
|
|
12
|
-
> - 正确示例代码:必须是**修复后的建议代码**
|
|
13
|
-
> - 不得将已删除的代码(- 开头的行)作为错误代码展示
|
|
14
10
|
7. 若无某类问题(如无严重问题),则**完全省略该部分**(例如不输出“🔴 严重问题”标题);
|
|
15
|
-
8.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
集合/数组未判空直接遍历:`for (Item item : list)` 或 `list.stream()` 当 `list` 为 `null` 时抛出 `NullPointerException`
|
|
25
|
-
集合索引越界:`list.get(index)` 当 `index >= list.size()` 时抛出 `IndexOutOfBoundsException`
|
|
26
|
-
类型转换错误:当 强制转换`obj`,但其实际类型不匹配时抛出 `ClassCastException`
|
|
27
|
-
`Optional` 误用:`optional.get()` 未先调用 `isPresent()` 或直接使用 `ifPresent()`
|
|
28
|
-
> - 引发资源泄漏、死锁等运行时崩溃风险
|
|
29
|
-
> - 违反事务一致性或并发安全原则
|
|
30
|
-
> - 导致核心功能失效或产生错误业务结果
|
|
31
|
-
> - 引入构建失败、测试失败或高危依赖漏洞
|
|
32
|
-
9. 警告问题的定义如下(优先级低于严重问题,不会造成立即崩溃或数据丢失,但存在隐患)
|
|
33
|
-
> - 代码可读性差(如魔法数字、命名不规范、缺少必要注释)
|
|
34
|
-
> - 性能潜在问题(如低效算法、不必要的数据库查询、内存使用不当)
|
|
35
|
-
> - **注意**:若性能问题与严重问题行号重叠,仅保留严重问题
|
|
36
|
-
> - 边界条件处理不完善(如空集合、极端值未妥善处理)
|
|
37
|
-
> - **注意**:若边界条件问题可能导致运行时异常,应归类为严重问题
|
|
38
|
-
> - 异常处理不完善(如捕获异常未记录或吞掉异常)
|
|
39
|
-
> - 资源使用不规范(如未关闭资源但无泄漏风险、连接池配置不当)
|
|
40
|
-
> - 代码重复或违反 DRY 原则
|
|
41
|
-
> - 类型安全警告(如原始类型使用、unchecked 转换)
|
|
42
|
-
> - **输出前检查**:若某行号范围的问题已在严重问题中报告,警告中**禁止**再出现该行号的任何条目
|
|
43
|
-
> - **强制排除**:警告中**不得包含**以下关键词描述的问题:
|
|
44
|
-
> - "空指针"、"NullPointerException"、"NPE"
|
|
45
|
-
> - "自动拆箱"、"Boolean 包装类"、"包装类转换"
|
|
46
|
-
> - "集合遍历"、"stream()"、"数组越界"
|
|
47
|
-
> - 任何可能导致运行时异常的描述
|
|
48
|
-
10. **问题描述准确性规则**:
|
|
49
|
-
> - 必须准确识别代码变更引入的实际风险,不得以次要风险(如性能影响)掩盖主要风险(如空指针异常)
|
|
50
|
-
> - 示例:删除 `CollectionUtils.isEmpty(jobids)` 空检查后,若后续直接调用 `jobids.stream()`,实际风险是 **NPE** 而非"不必要的 Redis 操作"或"性能影响"
|
|
51
|
-
> - 判定原则:若代码变更可能导致运行时异常,必须优先描述异常风险,不得降级为性能或健壮性描述
|
|
52
|
-
11. **问题分级规则**:
|
|
53
|
-
> - 若问题涉及以下任一情况,**必须**归类为严重问题:
|
|
54
|
-
> - 可能导致 **运行时异常**(`RuntimeException` 及其子类,如 `NullPointerException`、`ArrayIndexOutOfBoundsException`、`ClassCastException`、`NoSuchElementException` 等)
|
|
55
|
-
> - 可能导致数据丢失或损坏
|
|
56
|
-
> - 可能导致安全漏洞
|
|
57
|
-
> - 若同一代码块存在多个问题,**全部归入同一风险级别,并依次展示**
|
|
58
|
-
> - 示例:若某一个代码块同时存在"集合未判空"和"Boolean 拆箱",两者均为严重问题,应在严重问题标题下并列展示
|
|
59
|
-
12. 最终输出必须以 `<REPORT>` 开始,以 `</REPORT>` 结束,确保内容可被程序安全提取。
|
|
60
|
-
13. 需要分析的变更内容位于下方<CHANGE_CONTENT>标签内。
|
|
61
|
-
14. 变更内容的行信息位于下方<LINE_INFO>标签内,里面的内容格式为:"@@ -84,9 +84,11 @@ public class UserCompetitiveAnalyseLogServiceImpl extends ServiceImpl<UserCompet",使用变更后区域计算新代码块的起始行和结束行。
|
|
62
|
-
**行号计算规范**:
|
|
63
|
-
> - 行号必须基于 <LINE_INFO> 中的变更后行号计算(+ 号后的数字)
|
|
64
|
-
> - 格式 "@@ -84,9 +84,11 @@" 表示变更后代码从 84 行开始,共 11 行
|
|
65
|
-
> - 问题行号必须是变更后代码的实际行号,不得引用变更前行号
|
|
66
|
-
> - 若问题涉及多行,行号范围应覆盖完整问题代码块(如 84-93)
|
|
67
|
-
> - **重要**:行号对应的代码必须是变更后保留的代码,不得指向已删除的代码行
|
|
68
|
-
15. `<REPORT>`标签的每一个标题内都有两个问题块,这里只是进行示例,表示有不止一个问题时应该怎么展示,不是说每一个标题下必须有两个问题,具体问题的数量由review的结果决定,按原始代码块中对应代码的顺序依次展示即可
|
|
69
|
-
16. **输出前必须执行去重检查**:
|
|
70
|
-
> - **第一步:收集所有问题的文件及行号信息**
|
|
71
|
-
> - **第二步:检查是否存在行号重叠**(完全相同或有交集即视为重叠)
|
|
72
|
-
> - **第三步:若发现重叠,仅保留最高优先级级别的问题**
|
|
73
|
-
> - 优先级顺序:严重问题 > 警告 > 优化建议
|
|
74
|
-
> - **强制删除**:低级别中与高级别行号重叠的条目必须删除,不得保留
|
|
75
|
-
> - **第四步:验证警告中是否包含运行时异常风险**
|
|
76
|
-
> - 检查警告问题描述中是否包含"空指针"、"NullPointerException"、"自动拆箱"等关键词
|
|
77
|
-
> - 若包含,必须将该问题升级为严重问题
|
|
78
|
-
> - **第五步:验证错误代码示例**
|
|
79
|
-
> - 检查所有错误代码示例中是否包含 `-` 开头的行
|
|
80
|
-
> - 若包含,必须重新选取变更后实际存在的代码
|
|
81
|
-
> - **第六步:验证安全问题是否针对已删除代码**
|
|
82
|
-
> - 检查安全问题涉及的敏感信息(如令牌、密码等)是否在变更中已被删除
|
|
83
|
-
> - 若已删除(`-` 开头),必须删除该安全问题条目
|
|
84
|
-
> - **最终验证**:生成报告前必须确认:
|
|
85
|
-
> - 严重问题、警告、优化建议中不存在任何行号重叠的条目
|
|
86
|
-
> - 所有错误代码示例展示的是变更后实际存在的代码(无 `-` 前缀)
|
|
87
|
-
> - 不存在针对已删除代码的安全问题报告
|
|
88
|
-
17. **代码变更方向识别规则**:
|
|
89
|
-
> - **变更内容格式说明**:
|
|
90
|
-
> - 以 `-` 开头的行表示**已删除的代码**,**禁止**作为审查对象
|
|
91
|
-
> - 以 `+` 开头的行表示**新增的代码**,是审查的重点
|
|
92
|
-
> - 以空格开头的行表示**未变更的上下文代码**,仅作参考
|
|
93
|
-
> - **审查对象**:
|
|
94
|
-
> - 仅审查**变更后保留的代码**(新增代码 + 未删除的原有代码)
|
|
95
|
-
> - **禁止**对已删除的代码报告任何问题(包括安全问题、性能问题等)
|
|
96
|
-
> - **错误代码示例的选取**:
|
|
97
|
-
> - 必须从**变更后实际存在的代码**中选取(`+` 开头的行或空格开头的保留行)
|
|
98
|
-
> - **禁止**展示以 `-` 开头的已删除代码作为错误示例
|
|
99
|
-
> - **安全问题特殊处理**:
|
|
100
|
-
> - 若敏感信息(如硬编码令牌、密码等)在变更中已被删除(`-` 开头),**不得**再报告此安全问题
|
|
101
|
-
> - 仅当敏感信息在变更后仍存在(`+` 开头或空格开头的保留行)时,才报告安全问题
|
|
102
|
-
> - **示例**:
|
|
103
|
-
> - 若代码第一个位置以 `-` 开头表示已删除
|
|
104
|
-
> - **处理**:不报告此安全问题
|
|
105
|
-
> - 若该行以 `+` 开头表示新增或保留
|
|
106
|
-
> - **处理**:报告安全问题,错误代码展示该行(不带 `-` 前缀)
|
|
107
|
-
18. **变更内容解析步骤**(分析前必须执行):
|
|
108
|
-
> - **步骤 1:识别变更类型**
|
|
109
|
-
> - 遍历 `<CHANGE_CONTENT>` 中的每一行
|
|
110
|
-
> - 标记每行的类型:`-`(删除)、`+`(新增)、空格(保留)
|
|
111
|
-
> - **步骤 2:构建变更后代码视图**
|
|
112
|
-
> - 仅保留 `+` 开头的行和空格开头的行
|
|
113
|
-
> - **丢弃**所有 `-` 开头的行
|
|
114
|
-
> - **步骤 3:基于变更后代码视图进行审查**
|
|
115
|
-
> - 所有问题识别、行号计算、错误代码选取均基于变更后代码视图
|
|
116
|
-
> - **禁止**引用已丢弃的 `-` 开头行
|
|
117
|
-
> - **步骤 4:验证错误代码示例**
|
|
118
|
-
> - 检查错误代码示例中是否包含 `-` 前缀
|
|
119
|
-
> - 若包含,必须移除 `-` 前缀或重新选取变更后实际存在的代码
|
|
11
|
+
8. 严重问题的定义如下
|
|
12
|
+
> - 存在安全漏洞(如 SQL 注入、命令注入、敏感信息泄露)
|
|
13
|
+
> - 可能导致数据丢失/损坏/不一致
|
|
14
|
+
> - 引发空指针、资源泄漏、死锁等运行时崩溃风险
|
|
15
|
+
> - 违反事务一致性或并发安全原则
|
|
16
|
+
> - 导致核心功能失效或产生错误业务结果
|
|
17
|
+
> - 引入构建失败、测试失败或高危依赖漏洞
|
|
18
|
+
9. 最终输出必须以 `<REPORT>` 开始,以 `</REPORT>` 结束,确保内容可被程序安全提取。
|
|
19
|
+
10. 请分析的变更内容位于下方<CHANGE_CONTENT>标签内:
|
|
120
20
|
|
|
121
21
|
<REPORT>
|
|
122
|
-
## 🤖 AI代码审查结果
|
|
22
|
+
## 🤖 AI 代码审查结果
|
|
123
23
|
|
|
124
24
|
**生成时间**: [当前时间]
|
|
125
25
|
**审查范围**: [文件数量]个文件(仅统计有代码变更的文件)
|
|
@@ -132,42 +32,28 @@
|
|
|
132
32
|
|
|
133
33
|
### 🔴 严重问题
|
|
134
34
|
|
|
135
|
-
[
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
[带圈数字序号,如:②,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
140
|
-
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
141
|
-
**修改建议**:[修复建议,展示错误代码及对应修改后的示例代码,注意:错误代码和正确示例代码是必须存在的部分!!!]
|
|
35
|
+
**文件**: [文件路径]
|
|
36
|
+
**问题**: [具体问题描述]
|
|
37
|
+
**位置**: [问题所在行号]
|
|
38
|
+
**建议**: [修复建议和示例代码]
|
|
142
39
|
|
|
143
40
|
### 🟡 警告
|
|
144
41
|
|
|
145
|
-
[
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
[带圈数字序号,如:②,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
150
|
-
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
151
|
-
**修改建议**:[改进建议,展示相应代码及对应修改后的示例代码]
|
|
42
|
+
**文件**: [文件路径]
|
|
43
|
+
**问题**: [具体问题描述]
|
|
44
|
+
**位置**: [问题所在行号]
|
|
45
|
+
**建议**: [改进建议]
|
|
152
46
|
|
|
153
47
|
### 🟢 优化建议
|
|
154
48
|
|
|
155
|
-
[
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
[带圈数字序号,如:②,字体格式和后续优化建议一致][优化建议及可以直接使用的修改提示词]<br/>
|
|
160
|
-
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
161
|
-
**示例代码**:[展示相应代码及对应修改优化后的示例代码]
|
|
49
|
+
**文件**: [文件路径]
|
|
50
|
+
**建议**: [优化建议]
|
|
51
|
+
**示例**: [改进后的代码示例]
|
|
162
52
|
|
|
163
53
|
### 🔄 上下文影响分析(需涵盖依赖关系、功能关联性、兼容性风险三个维度)
|
|
164
54
|
|
|
165
|
-
[
|
|
166
|
-
|
|
167
|
-
**验证建议**: [如何验证是否存在此问题]
|
|
168
|
-
|
|
169
|
-
[带圈数字序号,如:②,字体格式和影响描述建议一致][影响描述:功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]<br/>
|
|
170
|
-
**受影响组件**: [直接依赖的类/方法/模块、间接关联的功能模块]<br/>
|
|
55
|
+
**受影响组件**: [直接依赖的类/方法/模块、间接关联的功能模块]
|
|
56
|
+
**影响描述**: [功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]
|
|
171
57
|
**验证建议**: [如何验证是否存在此问题]
|
|
172
58
|
|
|
173
59
|
</REPORT>
|
|
@@ -176,8 +62,4 @@
|
|
|
176
62
|
{{CODE_CHANGES}}
|
|
177
63
|
</CHANGE_CONTENT>
|
|
178
64
|
|
|
179
|
-
<LINE_INFO>
|
|
180
|
-
{{LINE_INFO}}
|
|
181
|
-
</LINE_INFO>
|
|
182
|
-
|
|
183
65
|
最后再强调一下,一定要符合上面提到的注意点,特别是必须一定要按照上面的模板输出,若无某类问题(如无严重问题),则**完全省略该部分**!!!
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job51-gitlab-cr-node-skill-prompt-optimize",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "GitLab merge request code review tool with AI-powered analysis",
|
|
3
|
+
"version": "1.3.9",
|
|
4
|
+
"description": "GitLab merge request code review tool with AI-powered analysis and project context support",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"gitlab-cr": "
|
|
7
|
+
"gitlab-cr": "index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node index.js",
|
|
@@ -14,8 +14,12 @@
|
|
|
14
14
|
"keywords": [],
|
|
15
15
|
"author": "tao.jing",
|
|
16
16
|
"license": "MIT",
|
|
17
|
+
"files": [
|
|
18
|
+
"**/*",
|
|
19
|
+
".claude/**/*"
|
|
20
|
+
],
|
|
17
21
|
"dependencies": {
|
|
18
|
-
"axios": "^1.
|
|
22
|
+
"axios": "^1.13.3"
|
|
19
23
|
},
|
|
20
24
|
"devDependencies": {
|
|
21
25
|
"nodemon": "^3.0.1"
|
package/PDF_CONVERSION_README.md
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# 代码审查报告转PDF工具使用说明
|
|
2
|
-
|
|
3
|
-
## 问题分析
|
|
4
|
-
|
|
5
|
-
您发现当前系统存在以下问题:
|
|
6
|
-
1. `mr-review-template.md` 是一个用于代码审查的提示词模板
|
|
7
|
-
2. 当前目录的PDF文件是从GitLab网页导出的页面快照,不是代码审查报告
|
|
8
|
-
3. 代码审查系统的输出直接发布到GitLab MR中,而不是保存为本地PDF
|
|
9
|
-
|
|
10
|
-
## 解决方案
|
|
11
|
-
|
|
12
|
-
我已创建了一个工具脚本 `convert-report-to-pdf.js` 来解决这个问题:
|
|
13
|
-
|
|
14
|
-
### 功能说明
|
|
15
|
-
|
|
16
|
-
1. **读取审查报告**:从包含 `<REPORT>` 和 `</REPORT>` 标签的文件中提取审查报告内容
|
|
17
|
-
2. **格式转换**:将Markdown格式的报告转换为适合打印的HTML格式
|
|
18
|
-
3. **生成可打印文档**:创建带有适当样式的HTML文档,方便转换为PDF
|
|
19
|
-
|
|
20
|
-
### 使用方法
|
|
21
|
-
|
|
22
|
-
#### 1. 生成代码审查报告
|
|
23
|
-
|
|
24
|
-
首先,确保您有代码审查系统的输出文件。如果您还没有实际的审查报告,可以使用以下示例:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# 创建示例审查报告文件
|
|
28
|
-
echo '<REPORT>
|
|
29
|
-
## 🤖 AI代码审查结果
|
|
30
|
-
|
|
31
|
-
**生成时间**: 2026-03-09 09:30:00
|
|
32
|
-
**审查范围**: 2个文件(仅统计有代码变更的文件)
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
### 审查总览
|
|
37
|
-
|
|
38
|
-
本次审查发现了1个严重问题和2个优化建议,主要涉及安全性、代码可读性和性能方面的问题。
|
|
39
|
-
|
|
40
|
-
### 🔴 严重问题
|
|
41
|
-
|
|
42
|
-
①:在UserService.java文件中,数据库查询缺少输入验证,可能存在SQL注入风险
|
|
43
|
-
**文件及行号**:UserService.java:125-130
|
|
44
|
-
**修改建议**:使用参数化查询替换字符串拼接方式,防止SQL注入攻击
|
|
45
|
-
错误代码:
|
|
46
|
-
```java
|
|
47
|
-
String sql = "SELECT * FROM users WHERE id = " + userId;
|
|
48
|
-
```
|
|
49
|
-
正确示例代码:
|
|
50
|
-
```java
|
|
51
|
-
String sql = "SELECT * FROM users WHERE id = ?";
|
|
52
|
-
PreparedStatement stmt = connection.prepareStatement(sql);
|
|
53
|
-
stmt.setString(1, userId);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 🟢 优化建议
|
|
57
|
-
|
|
58
|
-
**文件及行号**:UserController.java:45-50
|
|
59
|
-
**优化建议**:方法中存在重复代码,建议提取为公共方法提高可维护性
|
|
60
|
-
**示例代码**:
|
|
61
|
-
```java
|
|
62
|
-
// 原代码
|
|
63
|
-
public void updateUser(Long id, String name) {
|
|
64
|
-
validateUser(id);
|
|
65
|
-
validateName(name);
|
|
66
|
-
// ... update logic
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public void createUser(String name) {
|
|
70
|
-
validateUser(null); // 重复的验证逻辑
|
|
71
|
-
validateName(name);
|
|
72
|
-
// ... create logic
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**文件及行号**:ConfigService.java:78-82
|
|
77
|
-
**优化建议**:配置项可以使用枚举类型提高类型安全
|
|
78
|
-
**示例代码**:
|
|
79
|
-
```java
|
|
80
|
-
// 原代码
|
|
81
|
-
public static final String DB_TYPE_MYSQL = "mysql";
|
|
82
|
-
public static final String DB_TYPE_POSTGRES = "postgres";
|
|
83
|
-
|
|
84
|
-
// 建议
|
|
85
|
-
public enum DbType {
|
|
86
|
-
MYSQL("mysql"),
|
|
87
|
-
POSTGRES("postgres");
|
|
88
|
-
|
|
89
|
-
private final String value;
|
|
90
|
-
DbType(String value) { this.value = value; }
|
|
91
|
-
public String getValue() { return value; }
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 🔄 上下文影响分析(需涵盖依赖关系、功能关联性、兼容性风险三个维度)
|
|
96
|
-
|
|
97
|
-
**受影响组件**: 用户管理模块、数据库访问层
|
|
98
|
-
**影响描述**: 如果不修复SQL注入问题,可能导致数据库被恶意查询,造成数据泄露
|
|
99
|
-
**验证建议**: 使用恶意输入测试数据库查询接口,确认是否能阻止非法输入
|
|
100
|
-
|
|
101
|
-
</REPORT>' > sample-review-report.txt
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
#### 2. 转换为PDF可用的HTML格式
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
node convert-report-to-pdf.js sample-review-report.txt review-report.html
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### 3. 转换为PDF
|
|
111
|
-
|
|
112
|
-
1. 在浏览器中打开生成的 `review-report.html` 文件
|
|
113
|
-
2. 按 `Ctrl+P` 打开打印对话框
|
|
114
|
-
3. 选择 "另存为PDF" 作为打印机
|
|
115
|
-
4. 设置页面为A4或Letter格式
|
|
116
|
-
5. 点击保存
|
|
117
|
-
|
|
118
|
-
### 注意事项
|
|
119
|
-
|
|
120
|
-
- 转换脚本会保留报告的格式和结构
|
|
121
|
-
- HTML文件包含了自动生成PDF的JavaScript代码(在浏览器中)
|
|
122
|
-
- 如果您的审查报告格式与此不同,可以调整 `convert-report-to-pdf.js` 中的解析逻辑
|
|
123
|
-
|
|
124
|
-
## 完整的工作流程
|
|
125
|
-
|
|
126
|
-
1. 使用 `index.js` 运行代码审查并获得报告输出
|
|
127
|
-
2. 将审查结果保存到文件(包含 `<REPORT>` 标签)
|
|
128
|
-
3. 使用 `convert-report-to-pdf.js` 转换为HTML格式
|
|
129
|
-
4. 在浏览器中打开HTML文件并打印为PDF
|
|
130
|
-
|
|
131
|
-
这样您就可以得到一个格式良好的PDF版本的代码审查报告了。
|
package/convert-report-to-pdf.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 将代码审查报告转换为PDF的HTML模板
|
|
8
|
-
*/
|
|
9
|
-
function createHtmlTemplate(reportContent) {
|
|
10
|
-
return `
|
|
11
|
-
<!DOCTYPE html>
|
|
12
|
-
<html lang="zh-CN">
|
|
13
|
-
<head>
|
|
14
|
-
<meta charset="UTF-8">
|
|
15
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16
|
-
<title>AI代码审查报告</title>
|
|
17
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
18
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
19
|
-
<style>
|
|
20
|
-
body {
|
|
21
|
-
font-family: Arial, sans-serif;
|
|
22
|
-
padding: 20px;
|
|
23
|
-
line-height: 1.6;
|
|
24
|
-
}
|
|
25
|
-
.report-container {
|
|
26
|
-
max-width: 800px;
|
|
27
|
-
margin: 0 auto;
|
|
28
|
-
border: 1px solid #ddd;
|
|
29
|
-
padding: 30px;
|
|
30
|
-
background-color: #fff;
|
|
31
|
-
}
|
|
32
|
-
h1, h2, h3 {
|
|
33
|
-
color: #333;
|
|
34
|
-
}
|
|
35
|
-
h1 {
|
|
36
|
-
border-bottom: 2px solid #4CAF50;
|
|
37
|
-
padding-bottom: 10px;
|
|
38
|
-
}
|
|
39
|
-
h2 {
|
|
40
|
-
color: #2196F3;
|
|
41
|
-
border-left: 4px solid #2196F3;
|
|
42
|
-
padding-left: 10px;
|
|
43
|
-
margin-top: 25px;
|
|
44
|
-
}
|
|
45
|
-
.severity-high {
|
|
46
|
-
border-left: 4px solid #f44336;
|
|
47
|
-
background-color: #ffebee;
|
|
48
|
-
padding: 10px;
|
|
49
|
-
margin: 10px 0;
|
|
50
|
-
}
|
|
51
|
-
.severity-medium {
|
|
52
|
-
border-left: 4px solid #ff9800;
|
|
53
|
-
background-color: #fff3e0;
|
|
54
|
-
padding: 10px;
|
|
55
|
-
margin: 10px 0;
|
|
56
|
-
}
|
|
57
|
-
.severity-low {
|
|
58
|
-
border-left: 4px solid #4CAF50;
|
|
59
|
-
background-color: #e8f5e8;
|
|
60
|
-
padding: 10px;
|
|
61
|
-
margin: 10px 0;
|
|
62
|
-
}
|
|
63
|
-
.code-block {
|
|
64
|
-
background-color: #f5f5f5;
|
|
65
|
-
border: 1px solid #ddd;
|
|
66
|
-
border-radius: 4px;
|
|
67
|
-
padding: 10px;
|
|
68
|
-
overflow-x: auto;
|
|
69
|
-
font-family: monospace;
|
|
70
|
-
white-space: pre-wrap;
|
|
71
|
-
}
|
|
72
|
-
.file-info {
|
|
73
|
-
background-color: #e3f2fd;
|
|
74
|
-
padding: 8px;
|
|
75
|
-
border-radius: 4px;
|
|
76
|
-
margin: 5px 0;
|
|
77
|
-
}
|
|
78
|
-
ul {
|
|
79
|
-
padding-left: 20px;
|
|
80
|
-
}
|
|
81
|
-
li {
|
|
82
|
-
margin: 8px 0;
|
|
83
|
-
}
|
|
84
|
-
</style>
|
|
85
|
-
</head>
|
|
86
|
-
<body>
|
|
87
|
-
<div class="report-container">
|
|
88
|
-
${reportContent}
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<script>
|
|
92
|
-
// 页面加载完成后自动转换为PDF(可选)
|
|
93
|
-
function convertToPdf() {
|
|
94
|
-
const { jsPDF } = window.jspdf;
|
|
95
|
-
const element = document.querySelector('.report-container');
|
|
96
|
-
|
|
97
|
-
html2canvas(element, {
|
|
98
|
-
scale: 2,
|
|
99
|
-
useCORS: true,
|
|
100
|
-
backgroundColor: '#ffffff'
|
|
101
|
-
}).then(canvas => {
|
|
102
|
-
const imgData = canvas.toDataURL('image/png');
|
|
103
|
-
const pdf = new jsPDF('p', 'mm', 'a4');
|
|
104
|
-
const imgWidth = 210;
|
|
105
|
-
const pageHeight = 295;
|
|
106
|
-
const imgHeight = canvas.height * imgWidth / canvas.width;
|
|
107
|
-
|
|
108
|
-
let heightLeft = imgHeight;
|
|
109
|
-
let position = 0;
|
|
110
|
-
|
|
111
|
-
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
112
|
-
heightLeft -= pageHeight;
|
|
113
|
-
|
|
114
|
-
while (heightLeft >= 0) {
|
|
115
|
-
position = heightLeft - imgHeight;
|
|
116
|
-
pdf.addPage();
|
|
117
|
-
pdf.addImage(imgData, 'PNG', 0, position, imgHeight > pageHeight ? imgWidth : imgWidth, imgHeight > pageHeight ? pageHeight : imgHeight);
|
|
118
|
-
heightLeft -= pageHeight;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
pdf.save('ai-code-review-report.pdf');
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 5秒后自动执行转换,或用户手动调用
|
|
126
|
-
// setTimeout(convertToPdf, 5000);
|
|
127
|
-
</script>
|
|
128
|
-
</body>
|
|
129
|
-
</html>`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* 将Markdown格式的报告转换为HTML
|
|
134
|
-
*/
|
|
135
|
-
function mdToHtml(mdContent) {
|
|
136
|
-
// 简单的Markdown到HTML转换
|
|
137
|
-
let html = mdContent;
|
|
138
|
-
|
|
139
|
-
// 转义HTML特殊字符
|
|
140
|
-
html = html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
141
|
-
|
|
142
|
-
// 标题
|
|
143
|
-
html = html.replace(/^###\s+(.*)$/gm, '<h3>$1</h3>');
|
|
144
|
-
html = html.replace(/^##\s+(.*)$/gm, '<h2>$1</h2>');
|
|
145
|
-
html = html.replace(/^#\s+(.*)$/gm, '<h1>$1</h1>');
|
|
146
|
-
|
|
147
|
-
// 段落
|
|
148
|
-
html = html.replace(/^\s*(.+)$/gm, '<p>$1</p>');
|
|
149
|
-
|
|
150
|
-
// 特殊标记(严重问题、警告、优化建议)
|
|
151
|
-
html = html.replace(/🔴\s+严重问题/g, '<h2 class="severity-high-title">🔴 严重问题</h2>');
|
|
152
|
-
html = html.replace(/🟡\s+警告/g, '<h2 class="severity-medium-title">🟡 警告</h2>');
|
|
153
|
-
html = html.replace(/🟢\s+优化建议/g, '<h2 class="severity-low-title">🟢 优化建议</h2>');
|
|
154
|
-
|
|
155
|
-
// 回滚之前的替换,只处理行首的标题
|
|
156
|
-
html = html.replace(/<p>##\s+(.*?)<\/p>/g, '<h2>$1</h2>');
|
|
157
|
-
html = html.replace(/<p>###\s+(.*?)<\/p>/g, '<h3>$1</h3>');
|
|
158
|
-
|
|
159
|
-
// 文件和行号信息
|
|
160
|
-
html = html.replace(/\*\*文件及行号\*\*:([^\n<]+)/g, '<div class="file-info"><strong>文件及行号:</strong>$1</div>');
|
|
161
|
-
|
|
162
|
-
// 修改建议和示例代码
|
|
163
|
-
html = html.replace(/\*\*修改建议\*\*:([\s\S]*?)(?=<div class="file-info"|<h2>|<\/div>|$)/g,
|
|
164
|
-
'<div class="severity-high"><strong>修改建议:</strong><br>$1</div>');
|
|
165
|
-
html = html.replace(/\*\*优化建议\*\*:([\s\S]*?)(?=<div class="file-info"|<h2>|<\/div>|$)/g,
|
|
166
|
-
'<div class="severity-low"><strong>优化建议:</strong><br>$1</div>');
|
|
167
|
-
|
|
168
|
-
// 代码块
|
|
169
|
-
html = html.replace(/```([\s\S]*?)```/g, '<div class="code-block">$1</div>');
|
|
170
|
-
|
|
171
|
-
// 换行处理
|
|
172
|
-
html = html.replace(/\n/g, '<br>');
|
|
173
|
-
|
|
174
|
-
// 恢复一些必要的换行和结构
|
|
175
|
-
html = html.replace(/<br><\/div>/g, '</div>');
|
|
176
|
-
html = html.replace(/<br><\/h2>/g, '</h2>');
|
|
177
|
-
html = html.replace(/<br><\/h3>/g, '</h3>');
|
|
178
|
-
html = html.replace(/<br><\/p>/g, '</p>');
|
|
179
|
-
html = html.replace(/<br><\/strong>/g, '</strong>');
|
|
180
|
-
|
|
181
|
-
return html;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* 从文件读取审查报告并转换为PDF可用的HTML
|
|
186
|
-
*/
|
|
187
|
-
function convertReviewReportToPdfHtml(inputFilePath, outputHtmlPath) {
|
|
188
|
-
try {
|
|
189
|
-
// 读取输入文件
|
|
190
|
-
const content = fs.readFileSync(inputFilePath, 'utf8');
|
|
191
|
-
|
|
192
|
-
// 如果内容被REPORT标签包围,只提取标签内的内容
|
|
193
|
-
const reportMatch = content.match(/<REPORT>([\s\S]*?)<\/REPORT>/);
|
|
194
|
-
const reportContent = reportMatch ? reportMatch[1] : content;
|
|
195
|
-
|
|
196
|
-
// 转换Markdown为HTML
|
|
197
|
-
const htmlContent = mdToHtml(reportContent);
|
|
198
|
-
|
|
199
|
-
// 创建完整的HTML文档
|
|
200
|
-
const fullHtml = createHtmlTemplate(htmlContent);
|
|
201
|
-
|
|
202
|
-
// 写入输出文件
|
|
203
|
-
fs.writeFileSync(outputHtmlPath, fullHtml);
|
|
204
|
-
|
|
205
|
-
console.log(`✅ 已成功将代码审查报告转换为HTML格式: ${outputHtmlPath}`);
|
|
206
|
-
console.log(`💡 要生成PDF,请在浏览器中打开此HTML文件并使用Ctrl+P打印为PDF`);
|
|
207
|
-
|
|
208
|
-
return true;
|
|
209
|
-
} catch (error) {
|
|
210
|
-
console.error('❌ 转换过程中发生错误:', error.message);
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// 如果直接运行此脚本
|
|
216
|
-
if (require.main === module) {
|
|
217
|
-
const args = process.argv.slice(2);
|
|
218
|
-
|
|
219
|
-
if (args.length < 2) {
|
|
220
|
-
console.log('📝 使用方法:');
|
|
221
|
-
console.log(' node convert-report-to-pdf.js <输入报告文件> <输出HTML文件>');
|
|
222
|
-
console.log('');
|
|
223
|
-
console.log('📖 示例:');
|
|
224
|
-
console.log(' node convert-report-to-pdf.js review-output.txt review-report.html');
|
|
225
|
-
console.log('');
|
|
226
|
-
console.log('💡 提示: 生成的HTML文件可以直接在浏览器中打开,然后使用打印功能保存为PDF');
|
|
227
|
-
process.exit(1);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const inputPath = args[0];
|
|
231
|
-
const outputPath = args[1];
|
|
232
|
-
|
|
233
|
-
convertReviewReportToPdfHtml(inputPath, outputPath);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
module.exports = {
|
|
237
|
-
convertReviewReportToPdfHtml,
|
|
238
|
-
createHtmlTemplate,
|
|
239
|
-
mdToHtml
|
|
240
|
-
};
|