kcode-pi 0.1.6 → 0.1.7
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 +18 -2
- package/package.json +1 -1
- package/src/official/kingdee-skills.ts +60 -13
- package/src/rules/checker.ts +143 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +2 -2
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +52 -101
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +4 -4
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +21 -20
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +2 -2
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +4 -4
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +3 -3
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +8 -8
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +19 -18
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +9 -9
- package/vendor/kingdee-skills/ok-ksql/manifest.json +2 -1
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +2 -2
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +0 -336
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +0 -121
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +0 -295
- package/vendor/kingdee-skills/ok-cosmic/README.md +0 -460
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +0 -2
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +0 -204
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +0 -910
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +0 -359
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +0 -181
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +0 -389
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +0 -856
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +0 -262
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +0 -293
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +0 -2
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +0 -393
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +0 -176
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +0 -375
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +0 -434
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +0 -36
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +0 -186
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +0 -40
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +0 -142
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +0 -18
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +0 -53
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +0 -363
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
金蝶代码问题模式匹配器
|
|
4
|
-
用于快速识别代码中的严重问题
|
|
5
|
-
|
|
6
|
-
使用方法:
|
|
7
|
-
python pattern-matcher.py <file_path>
|
|
8
|
-
|
|
9
|
-
输出:
|
|
10
|
-
- P0 级问题(阻断/严重)
|
|
11
|
-
- P1 级问题(高危/性能)
|
|
12
|
-
- P2 级问题(规范/建议)
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
import re
|
|
16
|
-
import sys
|
|
17
|
-
from typing import List, Tuple, Dict, Optional
|
|
18
|
-
|
|
19
|
-
# ==========================================
|
|
20
|
-
# 上下文验证函数(减少误判)
|
|
21
|
-
# ==========================================
|
|
22
|
-
|
|
23
|
-
def _is_in_try_with_resources(code: str, match_start: int) -> bool:
|
|
24
|
-
"""检查匹配位置是否在 try-with-resources 块内"""
|
|
25
|
-
# 向前查找最近的 try( 语句
|
|
26
|
-
before = code[:match_start]
|
|
27
|
-
# 查找最近的 try 块
|
|
28
|
-
try_pos = before.rfind('try (')
|
|
29
|
-
try_pos2 = before.rfind('try(')
|
|
30
|
-
try_pos = max(try_pos, try_pos2)
|
|
31
|
-
if try_pos == -1:
|
|
32
|
-
return False
|
|
33
|
-
# 检查 try 和 match 之间是否有闭合的 }
|
|
34
|
-
between = before[try_pos:]
|
|
35
|
-
open_braces = between.count('{') - between.count('}')
|
|
36
|
-
return open_braces > 0
|
|
37
|
-
|
|
38
|
-
def _is_in_comment(code: str, match_start: int) -> bool:
|
|
39
|
-
"""检查匹配位置是否在注释中"""
|
|
40
|
-
# 检查是否在单行注释中
|
|
41
|
-
line_start = code.rfind('\n', 0, match_start) + 1
|
|
42
|
-
line = code[line_start:match_start]
|
|
43
|
-
if '//' in line:
|
|
44
|
-
return True
|
|
45
|
-
# 检查是否在多行注释中
|
|
46
|
-
last_open = code.rfind('/*', 0, match_start)
|
|
47
|
-
if last_open != -1:
|
|
48
|
-
last_close = code.rfind('*/', 0, match_start)
|
|
49
|
-
if last_close < last_open:
|
|
50
|
-
return True
|
|
51
|
-
return False
|
|
52
|
-
|
|
53
|
-
def _is_org_user_id_field(match_text: str) -> bool:
|
|
54
|
-
"""检查是否是组织/用户/部门相关字段(真正的硬编码ID问题)"""
|
|
55
|
-
id_field_patterns = [
|
|
56
|
-
r'"[^"]*org[^"]*"', # 组织相关
|
|
57
|
-
r'"[^"]*user[^"]*"', # 用户相关
|
|
58
|
-
r'"[^"]*dept[^"]*"', # 部门相关
|
|
59
|
-
r'"[^"]*creator[^"]*"', # 创建人
|
|
60
|
-
r'"[^"]*modifier[^"]*"', # 修改人
|
|
61
|
-
r'"[^"]*approver[^"]*"', # 审核人
|
|
62
|
-
]
|
|
63
|
-
for pattern in id_field_patterns:
|
|
64
|
-
if re.search(pattern, match_text, re.IGNORECASE):
|
|
65
|
-
return True
|
|
66
|
-
return False
|
|
67
|
-
|
|
68
|
-
def _is_null_checked_before(code: str, var_name: str, match_start: int) -> bool:
|
|
69
|
-
"""检查变量在使用前是否已做过空检查"""
|
|
70
|
-
before = code[:match_start]
|
|
71
|
-
# 查找最近100个字符内是否有空检查
|
|
72
|
-
check_range = before[-200:] if len(before) > 200 else before
|
|
73
|
-
null_check_patterns = [
|
|
74
|
-
rf'{var_name}\s*!=\s*null',
|
|
75
|
-
rf'{var_name}\s*==\s*null',
|
|
76
|
-
rf'Optional\.ofNullable\s*\(\s*{var_name}',
|
|
77
|
-
rf'if\s*\(\s*{var_name}\s*!=\s*null',
|
|
78
|
-
]
|
|
79
|
-
for pattern in null_check_patterns:
|
|
80
|
-
if re.search(pattern, check_range):
|
|
81
|
-
return True
|
|
82
|
-
return False
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# ==========================================
|
|
86
|
-
# P0 级问题模式定义(阻断/严重)
|
|
87
|
-
# ==========================================
|
|
88
|
-
|
|
89
|
-
PATTERNS_P0 = [
|
|
90
|
-
# 生命周期问题
|
|
91
|
-
(r'public\s+void\s+initialize\s*\([^)]*\)\s*\{[^}]*addItemClickListener',
|
|
92
|
-
'Initialize 注册监听', 'lifecycle-checklist.md', '内存泄漏,监听器无法正确释放'),
|
|
93
|
-
(r'public\s+void\s+initialize\s*\([^)]*\)\s*\{[^}]*getView\(\)',
|
|
94
|
-
'Initialize 操作 UI', 'lifecycle-checklist.md', '生命周期违规'),
|
|
95
|
-
|
|
96
|
-
# 事务问题
|
|
97
|
-
(r'beforeExecuteOperationTransaction[^}]*SaveServiceHelper\.save',
|
|
98
|
-
'操作插件独立保存破坏事务', 'data-transaction-checklist.md', '事务分离,数据不一致,无法回滚'),
|
|
99
|
-
(r'afterExecuteOperationTransaction[^}]*SaveServiceHelper\.save',
|
|
100
|
-
'操作插件独立保存破坏事务', 'data-transaction-checklist.md', '事务分离,数据不一致'),
|
|
101
|
-
|
|
102
|
-
# 资源泄漏 - DataSet(需上下文验证:排除已在 try-with-resources 中的情况)
|
|
103
|
-
(r'DataSet\s+\w+\s*=\s*QueryServiceHelper\.',
|
|
104
|
-
'DataSet 查询未使用 try-with-resources', 'data-transaction-checklist.md', '连接池耗尽,系统崩溃',
|
|
105
|
-
'check_try_with_resources'),
|
|
106
|
-
(r'DataSet\s+\w+\s*=\s*Algo\.',
|
|
107
|
-
'DataSet (Algo) 未使用 try-with-resources', 'data-transaction-checklist.md', '计算资源泄漏',
|
|
108
|
-
'check_try_with_resources'),
|
|
109
|
-
|
|
110
|
-
# 资源泄漏 - AlgoContext(需上下文验证)
|
|
111
|
-
(r'AlgoContext\s+\w+\s*=\s*Algo\.newContext\(\)',
|
|
112
|
-
'AlgoContext 可能未关闭', 'data-transaction-checklist.md', '计算资源泄漏',
|
|
113
|
-
'check_try_with_resources'),
|
|
114
|
-
|
|
115
|
-
# 硬编码组织/用户 ID(缩小匹配范围,仅匹配 org/user/dept 相关字段)
|
|
116
|
-
(r'\.set\s*\(\s*"[^"]*(org|creator|modifier|approver|dept|user)[^"]*"\s*,\s*\d{4,}L?\s*\)',
|
|
117
|
-
'硬编码组织/用户 ID', 'data-transaction-checklist.md', '跨环境部署失败'),
|
|
118
|
-
|
|
119
|
-
# 空指针风险 - P0级(链式调用未判空)
|
|
120
|
-
(r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getPkValue\s*\(',
|
|
121
|
-
'getDynamicObject() 结果未判空调用 getPkValue', 'coding-standard-checklist.md', 'NullPointerException'),
|
|
122
|
-
(r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getString\s*\(',
|
|
123
|
-
'getDynamicObject() 结果未判空调用 getString', 'coding-standard-checklist.md', 'NullPointerException'),
|
|
124
|
-
(r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getBigDecimal\s*\(',
|
|
125
|
-
'getDynamicObject() 结果未判空调用 getBigDecimal', 'coding-standard-checklist.md', 'NullPointerException'),
|
|
126
|
-
(r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getLong\s*\(',
|
|
127
|
-
'getDynamicObject() 结果未判空调用 getLong', 'coding-standard-checklist.md', 'NullPointerException'),
|
|
128
|
-
|
|
129
|
-
# 分布式锁未在 finally 释放
|
|
130
|
-
(r'\.lock\s*\(\s*\)[^}]*(?!finally)',
|
|
131
|
-
'分布式锁可能未在 finally 中释放', 'infra-checklist.md', '锁永久不释放,线程阻塞'),
|
|
132
|
-
]
|
|
133
|
-
|
|
134
|
-
# ==========================================
|
|
135
|
-
# P1 级问题模式定义(高危/性能)
|
|
136
|
-
# ==========================================
|
|
137
|
-
|
|
138
|
-
PATTERNS_P1 = [
|
|
139
|
-
# 性能问题 - UI
|
|
140
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*updateView\s*\(',
|
|
141
|
-
'循环内调用 updateView', 'ui-performance-checklist.md', '界面卡顿'),
|
|
142
|
-
(r'while\s*\([^)]+\)\s*\{[^}]*updateView\s*\(',
|
|
143
|
-
'循环内调用 updateView', 'ui-performance-checklist.md', '界面卡顿'),
|
|
144
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*getFieldIndex\s*\(',
|
|
145
|
-
'循环内获取 FieldIndex', 'ui-performance-checklist.md', '性能损耗'),
|
|
146
|
-
|
|
147
|
-
# 性能问题 - 数据库
|
|
148
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*BusinessDataServiceHelper\.loadSingle',
|
|
149
|
-
'循环内调用 loadSingle', 'data-transaction-checklist.md', 'N+1 查询问题'),
|
|
150
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*BusinessDataServiceHelper\.load\s*\(',
|
|
151
|
-
'循环内调用 load', 'data-transaction-checklist.md', 'N+1 查询问题'),
|
|
152
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*SaveServiceHelper\.save',
|
|
153
|
-
'循环内调用 save', 'data-transaction-checklist.md', '性能问题+事务风险'),
|
|
154
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*QueryServiceHelper\.query',
|
|
155
|
-
'循环内调用 QueryServiceHelper', 'data-transaction-checklist.md', 'N+1 查询问题'),
|
|
156
|
-
(r'for\s*\([^)]+\)\s*\{[^}]*DispatchServiceHelper\.invoke',
|
|
157
|
-
'循环内调用微服务', 'data-transaction-checklist.md', 'N+1 远程调用'),
|
|
158
|
-
|
|
159
|
-
# 空指针风险 - P1级
|
|
160
|
-
(r'getDataEntities\s*\(\s*\)\s*\[\s*\d+\s*\]',
|
|
161
|
-
'getDataEntities() 数组访问未判空', 'coding-standard-checklist.md', 'ArrayIndexOutOfBoundsException'),
|
|
162
|
-
(r'this\.dataEntities\s*\[',
|
|
163
|
-
'dataEntities 数组访问未判空', 'coding-standard-checklist.md', '空指针风险'),
|
|
164
|
-
|
|
165
|
-
# JDK 原生线程
|
|
166
|
-
(r'new\s+Thread\s*\(',
|
|
167
|
-
'使用 JDK 原生 Thread', 'infra-checklist.md', '绕过平台线程管理'),
|
|
168
|
-
(r'Executors\.\s*new\w+Pool',
|
|
169
|
-
'使用 JDK 原生线程池', 'infra-checklist.md', '绕过平台线程管理'),
|
|
170
|
-
|
|
171
|
-
# System.out
|
|
172
|
-
(r'System\s*\.\s*out\s*\.\s*print',
|
|
173
|
-
'使用 System.out 而非平台日志', 'coding-standard-checklist.md', '日志不规范'),
|
|
174
|
-
|
|
175
|
-
# 集合问题
|
|
176
|
-
(r'\.size\s*\(\s*\)\s*>\s*0',
|
|
177
|
-
'建议使用 !isEmpty() 替代 size()>0', 'coding-standard-checklist.md', '代码可读性'),
|
|
178
|
-
|
|
179
|
-
# MQ publisher 未关闭
|
|
180
|
-
(r'createSimplePublisher\s*\([^)]*\)',
|
|
181
|
-
'MQ Publisher 可能未关闭', 'infra-checklist.md', '资源泄漏',
|
|
182
|
-
'check_try_with_resources'),
|
|
183
|
-
]
|
|
184
|
-
|
|
185
|
-
# ==========================================
|
|
186
|
-
# P2 级问题模式定义(规范/建议)
|
|
187
|
-
# ==========================================
|
|
188
|
-
|
|
189
|
-
PATTERNS_P2 = [
|
|
190
|
-
# 编码规范
|
|
191
|
-
(r'private\s+final\s+\w+\s+ZERO\s*=\s*BigDecimal\.ZERO',
|
|
192
|
-
'ZERO 字段应声明为 static final', 'coding-standard-checklist.md', '内存浪费'),
|
|
193
|
-
(r'public\s+\w+\s*\(\s*\)\s*\{\s*super\s*\(\s*\)\s*;\s*\}',
|
|
194
|
-
'冗余的空构造函数', 'coding-standard-checklist.md', '代码冗余'),
|
|
195
|
-
(r'logger\.error\s*\(\s*"[^"]+"\s*\)',
|
|
196
|
-
'异常日志缺少堆栈信息', 'coding-standard-checklist.md', '排查困难'),
|
|
197
|
-
(r'new\s+Object\[\s*0\s*\]',
|
|
198
|
-
'new Object[0] 可简化', 'coding-standard-checklist.md', '代码冗余'),
|
|
199
|
-
|
|
200
|
-
# e.printStackTrace
|
|
201
|
-
(r'\.printStackTrace\s*\(\s*\)',
|
|
202
|
-
'禁止直接调用 printStackTrace', 'coding-standard-checklist.md', '日志不规范'),
|
|
203
|
-
|
|
204
|
-
# 空 catch 块
|
|
205
|
-
(r'catch\s*\(\s*\w+\s+\w+\s*\)\s*\{\s*\}',
|
|
206
|
-
'空 catch 块隐藏异常', 'coding-standard-checklist.md', '异常被吞'),
|
|
207
|
-
|
|
208
|
-
# BigDecimal 问题(降级为 P2 - 仅在 DataSet.Row 场景下才是真正风险)
|
|
209
|
-
(r'row\.getBigDecimal\s*\(\s*"[^"]+"\s*\)\.compareTo',
|
|
210
|
-
'DataSet Row.getBigDecimal() 结果可能为 null', 'coding-standard-checklist.md', '空指针风险'),
|
|
211
|
-
]
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def match_patterns(code: str, patterns: List[Tuple], level: str) -> List[dict]:
|
|
215
|
-
"""匹配代码中的问题模式,支持上下文验证减少误判"""
|
|
216
|
-
issues = []
|
|
217
|
-
for pattern_data in patterns:
|
|
218
|
-
# 支持带上下文验证的5元组格式和普通4/3元组格式
|
|
219
|
-
context_check = None
|
|
220
|
-
if len(pattern_data) == 5:
|
|
221
|
-
pattern, desc, ref, risk, context_check = pattern_data
|
|
222
|
-
elif len(pattern_data) == 4:
|
|
223
|
-
pattern, desc, ref, risk = pattern_data
|
|
224
|
-
else:
|
|
225
|
-
pattern, desc, ref = pattern_data
|
|
226
|
-
risk = '未指定'
|
|
227
|
-
|
|
228
|
-
matches = re.finditer(pattern, code, re.DOTALL | re.IGNORECASE)
|
|
229
|
-
for match in matches:
|
|
230
|
-
# 跳过注释中的匹配
|
|
231
|
-
if _is_in_comment(code, match.start()):
|
|
232
|
-
continue
|
|
233
|
-
|
|
234
|
-
# 上下文验证:检查是否在 try-with-resources 中
|
|
235
|
-
if context_check == 'check_try_with_resources':
|
|
236
|
-
if _is_in_try_with_resources(code, match.start()):
|
|
237
|
-
continue # 已在 try-with-resources 中,不是问题
|
|
238
|
-
|
|
239
|
-
issues.append({
|
|
240
|
-
'level': level,
|
|
241
|
-
'description': desc,
|
|
242
|
-
'reference': ref,
|
|
243
|
-
'risk': risk,
|
|
244
|
-
'match': match.group()[:100] + '...' if len(match.group()) > 100 else match.group(),
|
|
245
|
-
'start': match.start(),
|
|
246
|
-
'end': match.end()
|
|
247
|
-
})
|
|
248
|
-
return issues
|
|
249
|
-
|
|
250
|
-
def analyze_file(filepath: str) -> List[dict]:
|
|
251
|
-
"""分析单个文件"""
|
|
252
|
-
try:
|
|
253
|
-
with open(filepath, 'r', encoding='utf-8') as f:
|
|
254
|
-
code = f.read()
|
|
255
|
-
|
|
256
|
-
p0_issues = match_patterns(code, PATTERNS_P0, 'P0')
|
|
257
|
-
p1_issues = match_patterns(code, PATTERNS_P1, 'P1')
|
|
258
|
-
p2_issues = match_patterns(code, PATTERNS_P2, 'P2')
|
|
259
|
-
|
|
260
|
-
return p0_issues + p1_issues + p2_issues
|
|
261
|
-
except Exception as e:
|
|
262
|
-
print(f"Error reading file: {e}")
|
|
263
|
-
return []
|
|
264
|
-
|
|
265
|
-
def print_report(issues: List[dict]):
|
|
266
|
-
"""打印格式化的报告"""
|
|
267
|
-
if not issues:
|
|
268
|
-
print("\n✅ 未发现 P0/P1/P2 级问题模式\n")
|
|
269
|
-
return
|
|
270
|
-
|
|
271
|
-
# 按级别分组
|
|
272
|
-
p0 = [i for i in issues if i['level'] == 'P0']
|
|
273
|
-
p1 = [i for i in issues if i['level'] == 'P1']
|
|
274
|
-
p2 = [i for i in issues if i['level'] == 'P2']
|
|
275
|
-
|
|
276
|
-
print(f"\n{'='*60}")
|
|
277
|
-
print(f"📊 模式匹配扫描报告")
|
|
278
|
-
print(f"{'='*60}")
|
|
279
|
-
print(f" 总计发现 {len(issues)} 个潜在问题\n")
|
|
280
|
-
|
|
281
|
-
if p0:
|
|
282
|
-
print(f"🔴 P0 级问题 ({len(p0)} 个):")
|
|
283
|
-
for i, issue in enumerate(p0, 1):
|
|
284
|
-
print(f" {i}. {issue['description']}")
|
|
285
|
-
print(f" 风险: {issue['risk']}")
|
|
286
|
-
print(f" 参考: references/{issue['reference']}")
|
|
287
|
-
print()
|
|
288
|
-
|
|
289
|
-
if p1:
|
|
290
|
-
print(f"🟠 P1 级问题 ({len(p1)} 个):")
|
|
291
|
-
for i, issue in enumerate(p1, 1):
|
|
292
|
-
print(f" {i}. {issue['description']}")
|
|
293
|
-
print(f" 风险: {issue['risk']}")
|
|
294
|
-
print(f" 参考: references/{issue['reference']}")
|
|
295
|
-
print()
|
|
296
|
-
|
|
297
|
-
if p2:
|
|
298
|
-
print(f"🟡 P2 级问题 ({len(p2)} 个):")
|
|
299
|
-
for i, issue in enumerate(p2, 1):
|
|
300
|
-
print(f" {i}. {issue['description']}")
|
|
301
|
-
print(f" 风险: {issue['risk']}")
|
|
302
|
-
print(f" 参考: references/{issue['reference']}")
|
|
303
|
-
print()
|
|
304
|
-
|
|
305
|
-
# 计算评分
|
|
306
|
-
base_score = 100
|
|
307
|
-
score = base_score - len(p0) * 15 - len(p1) * 8 - len(p2) * 3
|
|
308
|
-
score = max(0, score)
|
|
309
|
-
|
|
310
|
-
print(f"{'='*60}")
|
|
311
|
-
print(f"📐 综合评分: {score} 分", end="")
|
|
312
|
-
if score >= 90:
|
|
313
|
-
print(" (优秀)")
|
|
314
|
-
elif score >= 75:
|
|
315
|
-
print(" (良好)")
|
|
316
|
-
elif score >= 60:
|
|
317
|
-
print(" (中等)")
|
|
318
|
-
else:
|
|
319
|
-
print(" (需改进)")
|
|
320
|
-
print(f"{'='*60}\n")
|
|
321
|
-
|
|
322
|
-
def main():
|
|
323
|
-
if len(sys.argv) < 2:
|
|
324
|
-
print("Usage: python pattern-matcher.py <file_path>")
|
|
325
|
-
print("\n示例:")
|
|
326
|
-
print(" python pattern-matcher.py MyPlugin.java")
|
|
327
|
-
sys.exit(1)
|
|
328
|
-
|
|
329
|
-
filepath = sys.argv[1]
|
|
330
|
-
print(f"\n🔍 正在扫描文件: {filepath}")
|
|
331
|
-
|
|
332
|
-
issues = analyze_file(filepath)
|
|
333
|
-
print_report(issues)
|
|
334
|
-
|
|
335
|
-
if __name__ == '__main__':
|
|
336
|
-
main()
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
金蝶代码审查评分计算器
|
|
4
|
-
根据发现的问题数量和严重程度计算综合评分
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from typing import List, Dict
|
|
8
|
-
|
|
9
|
-
# 问题扣分权重
|
|
10
|
-
WEIGHTS = {
|
|
11
|
-
'P0': 25, # 阻断问题 - 严重扣分
|
|
12
|
-
'P1': 10, # 高危问题 - 中等扣分
|
|
13
|
-
'P2': 3, # 规范问题 - 轻微扣分
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
# 评分等级描述
|
|
17
|
-
GRADE_DESCRIPTIONS = {
|
|
18
|
-
(90, 100): '🟢 优秀 - 代码质量高,可上线',
|
|
19
|
-
(70, 89): '🟡 良好 - 存在改进空间',
|
|
20
|
-
(50, 69): '🟠 一般 - 需要修复部分问题',
|
|
21
|
-
(0, 49): '🔴 差 - 必须修复后才能上线',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
def calculate_score(issues: List[Dict]) -> int:
|
|
25
|
-
"""
|
|
26
|
-
计算代码评分
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
issues: 问题列表,每个问题包含 level 字段
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
评分 (0-100)
|
|
33
|
-
"""
|
|
34
|
-
score = 100
|
|
35
|
-
for issue in issues:
|
|
36
|
-
level = issue.get('level', 'P2')
|
|
37
|
-
score -= WEIGHTS.get(level, 0)
|
|
38
|
-
return max(0, score)
|
|
39
|
-
|
|
40
|
-
def get_grade(score: int) -> str:
|
|
41
|
-
"""
|
|
42
|
-
获取评分等级描述
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
score: 评分 (0-100)
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
等级描述
|
|
49
|
-
"""
|
|
50
|
-
for (low, high), desc in GRADE_DESCRIPTIONS.items():
|
|
51
|
-
if low <= score <= high:
|
|
52
|
-
return desc
|
|
53
|
-
return '🔴 差 - 必须修复后才能上线'
|
|
54
|
-
|
|
55
|
-
def get_statistics(issues: List[Dict]) -> Dict:
|
|
56
|
-
"""
|
|
57
|
-
获取问题统计
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
issues: 问题列表
|
|
61
|
-
|
|
62
|
-
Returns:
|
|
63
|
-
统计信息字典
|
|
64
|
-
"""
|
|
65
|
-
stats = {
|
|
66
|
-
'total': len(issues),
|
|
67
|
-
'P0': 0,
|
|
68
|
-
'P1': 0,
|
|
69
|
-
'P2': 0,
|
|
70
|
-
}
|
|
71
|
-
for issue in issues:
|
|
72
|
-
level = issue.get('level', 'P2')
|
|
73
|
-
stats[level] = stats.get(level, 0) + 1
|
|
74
|
-
return stats
|
|
75
|
-
|
|
76
|
-
def generate_report(issues: List[Dict], filename: str = '') -> str:
|
|
77
|
-
"""
|
|
78
|
-
生成审查报告摘要
|
|
79
|
-
|
|
80
|
-
Args:
|
|
81
|
-
issues: 问题列表
|
|
82
|
-
filename: 文件名
|
|
83
|
-
|
|
84
|
-
Returns:
|
|
85
|
-
报告摘要字符串
|
|
86
|
-
"""
|
|
87
|
-
stats = get_statistics(issues)
|
|
88
|
-
score = calculate_score(issues)
|
|
89
|
-
grade = get_grade(score)
|
|
90
|
-
|
|
91
|
-
report = f"""
|
|
92
|
-
# 🛡️ 代码审查摘要
|
|
93
|
-
|
|
94
|
-
## 📊 综述
|
|
95
|
-
- **审查文件**: {filename or '未指定'}
|
|
96
|
-
- **发现问题总数**: {stats['total']} (🔴 P0: {stats['P0']} | 🟠 P1: {stats['P1']} | 🟡 P2: {stats['P2']})
|
|
97
|
-
- **综合评分**: {score} 分
|
|
98
|
-
- **评级**: {grade}
|
|
99
|
-
|
|
100
|
-
## 📋 改进建议
|
|
101
|
-
"""
|
|
102
|
-
|
|
103
|
-
if stats['P0'] > 0:
|
|
104
|
-
report += f"- ⚠️ 发现 {stats['P0']} 个 P0 级阻断问题,必须修复后才能上线\n"
|
|
105
|
-
if stats['P1'] > 0:
|
|
106
|
-
report += f"- ⚡ 发现 {stats['P1']} 个 P1 级高危问题,强烈建议修复\n"
|
|
107
|
-
if stats['P2'] > 0:
|
|
108
|
-
report += f"- 📝 发现 {stats['P2']} 个 P2 级规范问题,建议优化\n"
|
|
109
|
-
|
|
110
|
-
return report
|
|
111
|
-
|
|
112
|
-
# 示例用法
|
|
113
|
-
if __name__ == '__main__':
|
|
114
|
-
# 测试数据
|
|
115
|
-
test_issues = [
|
|
116
|
-
{'level': 'P0', 'description': 'Initialize 注册监听'},
|
|
117
|
-
{'level': 'P1', 'description': '循环内调用 updateView'},
|
|
118
|
-
{'level': 'P2', 'description': '硬编码中文字符串'},
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
print(generate_report(test_issues, 'TestPlugin.java'))
|