kcode-pi 0.1.5 → 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 +35 -2
- package/dist/cli/kcode.d.ts +1 -0
- package/dist/cli/kcode.js +27 -4
- package/package.json +1 -1
- package/src/cli/kcode.ts +29 -4
- 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,262 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
cosmic-post-check.py — 苍穹代码生成后统一检查入口
|
|
5
|
-
|
|
6
|
-
逻辑:
|
|
7
|
-
1. 从目标文件/目录向上查找 Gradle 项目根目录(同时存在 build.gradle + settings.gradle)
|
|
8
|
-
2. 若找到 → 直接执行 Gradle 编译,编译通过后再执行代码规范检查
|
|
9
|
-
3. 若未找到 → 直接执行 cosmic-post-lint.py 代码规范检查
|
|
10
|
-
|
|
11
|
-
用法:
|
|
12
|
-
python3 cosmic-post-check.py <file_or_directory> [--fix-hint] [--json] [--strict]
|
|
13
|
-
|
|
14
|
-
示例:
|
|
15
|
-
python3 cosmic-post-check.py /path/to/project/code/module-bos/src/main/java/Foo.java
|
|
16
|
-
python3 cosmic-post-check.py ./src/main/java/ --fix-hint
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import os
|
|
20
|
-
import re
|
|
21
|
-
import subprocess
|
|
22
|
-
import sys
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
from typing import Dict, Optional
|
|
25
|
-
|
|
26
|
-
from script_utils import run_cli
|
|
27
|
-
|
|
28
|
-
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
29
|
-
|
|
30
|
-
# 全局 verbose 标志,通过 --verbose 开启
|
|
31
|
-
VERBOSE = False
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _verbose(msg: str):
|
|
35
|
-
"""在 --verbose 模式下输出诊断信息到 stderr。"""
|
|
36
|
-
if VERBOSE:
|
|
37
|
-
print(f" [verbose] {msg}", file=sys.stderr)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# ══════════════════════════════════════════════
|
|
41
|
-
# Gradle 项目检测
|
|
42
|
-
# ══════════════════════════════════════════════
|
|
43
|
-
|
|
44
|
-
def find_gradle_root(target: str) -> Optional[Path]:
|
|
45
|
-
"""从目标路径向上查找 Gradle 项目根目录。
|
|
46
|
-
|
|
47
|
-
判定条件:目录中同时存在 build.gradle(.kts) 和 settings.gradle(.kts)。
|
|
48
|
-
"""
|
|
49
|
-
p = Path(target).resolve()
|
|
50
|
-
if p.is_file():
|
|
51
|
-
p = p.parent
|
|
52
|
-
while p != p.parent:
|
|
53
|
-
has_build = (p / "build.gradle").exists() or (p / "build.gradle.kts").exists()
|
|
54
|
-
has_settings = (p / "settings.gradle").exists() or (p / "settings.gradle.kts").exists()
|
|
55
|
-
if has_build and has_settings:
|
|
56
|
-
return p
|
|
57
|
-
p = p.parent
|
|
58
|
-
return None
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def parse_modules(gradle_root: Path) -> Dict[str, Path]:
|
|
62
|
-
"""解析 settings.gradle 获取 模块名 → 目录 映射。
|
|
63
|
-
|
|
64
|
-
支持标准格式:
|
|
65
|
-
include 'moduleName'
|
|
66
|
-
project(':moduleName').projectDir = new File('relative/path')
|
|
67
|
-
"""
|
|
68
|
-
modules: Dict[str, Path] = {}
|
|
69
|
-
for name in ("settings.gradle", "settings.gradle.kts"):
|
|
70
|
-
settings = gradle_root / name
|
|
71
|
-
if settings.exists():
|
|
72
|
-
break
|
|
73
|
-
else:
|
|
74
|
-
return modules
|
|
75
|
-
|
|
76
|
-
text = settings.read_text(encoding="utf-8")
|
|
77
|
-
|
|
78
|
-
# 收集所有 include 声明
|
|
79
|
-
includes = re.findall(r"include\s+'([^']+)'", text)
|
|
80
|
-
|
|
81
|
-
# 收集 projectDir 映射
|
|
82
|
-
project_dirs: Dict[str, str] = dict(re.findall(
|
|
83
|
-
r"project\(':([^']+)'\)\.projectDir\s*=\s*new\s+File\('([^']+)'\)",
|
|
84
|
-
text,
|
|
85
|
-
))
|
|
86
|
-
|
|
87
|
-
for mod_name in includes:
|
|
88
|
-
if mod_name in project_dirs:
|
|
89
|
-
modules[mod_name] = (gradle_root / project_dirs[mod_name]).resolve()
|
|
90
|
-
else:
|
|
91
|
-
modules[mod_name] = (gradle_root / mod_name).resolve()
|
|
92
|
-
|
|
93
|
-
return modules
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def find_module(gradle_root: Path, target: str,
|
|
97
|
-
modules: Dict[str, Path]) -> Optional[str]:
|
|
98
|
-
"""确定目标文件/目录属于哪个 Gradle 子模块。"""
|
|
99
|
-
target_path = Path(target).resolve()
|
|
100
|
-
# 优先匹配最长路径(最具体的模块)
|
|
101
|
-
best_match: Optional[str] = None
|
|
102
|
-
best_len = 0
|
|
103
|
-
for name, mod_dir in modules.items():
|
|
104
|
-
try:
|
|
105
|
-
target_path.relative_to(mod_dir)
|
|
106
|
-
if len(str(mod_dir)) > best_len:
|
|
107
|
-
best_len = len(str(mod_dir))
|
|
108
|
-
best_match = name
|
|
109
|
-
except ValueError:
|
|
110
|
-
continue
|
|
111
|
-
return best_match
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
# ══════════════════════════════════════════════
|
|
115
|
-
# JAVA_HOME 解析(不做版本判断)
|
|
116
|
-
# ══════════════════════════════════════════════
|
|
117
|
-
|
|
118
|
-
def _read_properties(filepath: Path) -> Dict[str, str]:
|
|
119
|
-
"""读取 .properties 文件为 key→value 字典。"""
|
|
120
|
-
props: Dict[str, str] = {}
|
|
121
|
-
if not filepath.exists():
|
|
122
|
-
return props
|
|
123
|
-
for line in filepath.read_text(encoding="utf-8").splitlines():
|
|
124
|
-
line = line.strip()
|
|
125
|
-
if not line or line.startswith("#") or "=" not in line:
|
|
126
|
-
continue
|
|
127
|
-
k, v = line.split("=", 1)
|
|
128
|
-
props[k.strip()] = v.strip()
|
|
129
|
-
return props
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def resolve_java_home(gradle_root: Path) -> Optional[str]:
|
|
133
|
-
"""解析 JAVA_HOME 路径,不做版本判断。
|
|
134
|
-
|
|
135
|
-
优先级:gradle.properties 中 org.gradle.java.home → 环境变量 JAVA_HOME
|
|
136
|
-
"""
|
|
137
|
-
props = _read_properties(gradle_root / "gradle.properties")
|
|
138
|
-
explicit = props.get("org.gradle.java.home", "").strip()
|
|
139
|
-
if explicit and os.path.isdir(explicit):
|
|
140
|
-
return explicit
|
|
141
|
-
env_home = os.environ.get("JAVA_HOME", "").strip()
|
|
142
|
-
if env_home and os.path.isdir(env_home):
|
|
143
|
-
return env_home
|
|
144
|
-
return None
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# ══════════════════════════════════════════════
|
|
148
|
-
# Gradle 编译
|
|
149
|
-
# ══════════════════════════════════════════════
|
|
150
|
-
|
|
151
|
-
def run_gradle(gradle_root: Path, module: Optional[str], java_home: Optional[str]) -> int:
|
|
152
|
-
"""执行 Gradle 编译,返回退出码。不预判 JDK 版本,直接尝试构建。"""
|
|
153
|
-
# 定位 gradlew
|
|
154
|
-
wrapper_name = "gradlew.bat" if sys.platform == "win32" else "gradlew"
|
|
155
|
-
gradlew = gradle_root / wrapper_name
|
|
156
|
-
if not gradlew.exists():
|
|
157
|
-
print("[Warn] gradlew 不存在,尝试使用系统 gradle", file=sys.stderr)
|
|
158
|
-
cmd_prefix = ["gradle"]
|
|
159
|
-
else:
|
|
160
|
-
# 确保 gradlew 有可执行权限
|
|
161
|
-
if not os.access(gradlew, os.X_OK):
|
|
162
|
-
os.chmod(gradlew, 0o755)
|
|
163
|
-
cmd_prefix = [str(gradlew)]
|
|
164
|
-
|
|
165
|
-
task = f":{module}:compileJava" if module else "compileJava"
|
|
166
|
-
cmd = cmd_prefix + [task, "--console=plain"]
|
|
167
|
-
|
|
168
|
-
env = os.environ.copy()
|
|
169
|
-
if java_home:
|
|
170
|
-
env["JAVA_HOME"] = java_home
|
|
171
|
-
|
|
172
|
-
print("══════════════════════════════════════════════")
|
|
173
|
-
print(" [Build] Gradle 编译检查")
|
|
174
|
-
print("══════════════════════════════════════════════")
|
|
175
|
-
print(f" [Project] 项目根目录: {gradle_root}")
|
|
176
|
-
if module:
|
|
177
|
-
print(f" [Module] 目标模块: {module}")
|
|
178
|
-
print(f" [Java] JAVA_HOME: {java_home or '(未设置,由 Gradle 自行解析)'}")
|
|
179
|
-
print(f" [Command] 编译命令: {' '.join(cmd)}")
|
|
180
|
-
print("──────────────────────────────────────────────")
|
|
181
|
-
print(flush=True)
|
|
182
|
-
|
|
183
|
-
result = subprocess.run(cmd, cwd=str(gradle_root), env=env)
|
|
184
|
-
|
|
185
|
-
print()
|
|
186
|
-
print("══════════════════════════════════════════════")
|
|
187
|
-
if result.returncode == 0:
|
|
188
|
-
print(" ✔️ Gradle 编译成功,未发现编译错误。")
|
|
189
|
-
else:
|
|
190
|
-
print(f" ✖️ Gradle 编译失败 (exit code {result.returncode})")
|
|
191
|
-
print(" 请根据上述编译错误信息修复代码。")
|
|
192
|
-
print("══════════════════════════════════════════════")
|
|
193
|
-
|
|
194
|
-
return result.returncode
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
# ══════════════════════════════════════════════
|
|
198
|
-
# Post-Lint 代码规范检查
|
|
199
|
-
# ══════════════════════════════════════════════
|
|
200
|
-
|
|
201
|
-
def run_post_lint(args: list) -> int:
|
|
202
|
-
"""执行 cosmic-post-lint.py 代码规范检查。"""
|
|
203
|
-
post_lint = SCRIPT_DIR / "cosmic-post-lint.py"
|
|
204
|
-
if not post_lint.exists():
|
|
205
|
-
print(f"✖️ 未找到 {post_lint}", file=sys.stderr)
|
|
206
|
-
return 1
|
|
207
|
-
|
|
208
|
-
print("[Check] 执行代码规范检查")
|
|
209
|
-
print(flush=True)
|
|
210
|
-
|
|
211
|
-
cmd = [sys.executable, str(post_lint)] + args
|
|
212
|
-
result = subprocess.run(cmd)
|
|
213
|
-
return result.returncode
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
# ══════════════════════════════════════════════
|
|
217
|
-
# 主入口
|
|
218
|
-
# ══════════════════════════════════════════════
|
|
219
|
-
|
|
220
|
-
def main():
|
|
221
|
-
global VERBOSE
|
|
222
|
-
|
|
223
|
-
if len(sys.argv) < 2:
|
|
224
|
-
print("用法: cosmic-post-check.py <file_or_directory> [--fix-hint] [--json] [--strict] [--verbose]")
|
|
225
|
-
print()
|
|
226
|
-
print("优先执行 Gradle 编译;编译通过后再执行代码规范检查。非 Gradle 项目直接执行规范检查。")
|
|
227
|
-
sys.exit(1)
|
|
228
|
-
|
|
229
|
-
# 解析 --verbose 并从 argv 中移除(不传给 post-lint)
|
|
230
|
-
if "--verbose" in sys.argv:
|
|
231
|
-
VERBOSE = True
|
|
232
|
-
sys.argv.remove("--verbose")
|
|
233
|
-
|
|
234
|
-
target = sys.argv[1]
|
|
235
|
-
remaining_args = sys.argv[1:]
|
|
236
|
-
|
|
237
|
-
# 1. 检测 Gradle 项目
|
|
238
|
-
gradle_root = find_gradle_root(target)
|
|
239
|
-
_verbose(f"Gradle 项目检测: {gradle_root or '未找到'}")
|
|
240
|
-
|
|
241
|
-
if not gradle_root:
|
|
242
|
-
# 非 Gradle → 直接执行代码规范检查
|
|
243
|
-
sys.exit(run_post_lint(remaining_args))
|
|
244
|
-
|
|
245
|
-
# 2. 解析 JAVA_HOME(不做版本判断)
|
|
246
|
-
java_home = resolve_java_home(gradle_root)
|
|
247
|
-
_verbose(f"JAVA_HOME: {java_home or '未设置'}")
|
|
248
|
-
|
|
249
|
-
# 3. 直接执行 Gradle 编译
|
|
250
|
-
modules = parse_modules(gradle_root)
|
|
251
|
-
module = find_module(gradle_root, target, modules)
|
|
252
|
-
exit_code = run_gradle(gradle_root, module, java_home)
|
|
253
|
-
if exit_code != 0:
|
|
254
|
-
sys.exit(exit_code)
|
|
255
|
-
|
|
256
|
-
# 4. 编译成功 → 执行代码规范检查
|
|
257
|
-
print("[Tip] Gradle 编译通过,继续执行代码规范检查...")
|
|
258
|
-
sys.exit(run_post_lint(remaining_args))
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if __name__ == "__main__":
|
|
262
|
-
sys.exit(run_cli(main))
|
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
cosmic-post-lint.py — 苍穹代码生成后自动校验脚本
|
|
5
|
-
|
|
6
|
-
依次调用 lint/ 子模块执行各类检查,汇总输出报告。
|
|
7
|
-
|
|
8
|
-
用法:
|
|
9
|
-
python3 cosmic-post-lint.py <file_or_directory> [--fix-hint] [--json] [--strict]
|
|
10
|
-
|
|
11
|
-
示例:
|
|
12
|
-
python3 cosmic-post-lint.py ./src/main/java/
|
|
13
|
-
python3 cosmic-post-lint.py MyPlugin.java --fix-hint
|
|
14
|
-
python3 cosmic-post-lint.py ./src/ --json --strict
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import argparse
|
|
18
|
-
import json
|
|
19
|
-
import os
|
|
20
|
-
import sys
|
|
21
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
22
|
-
from pathlib import Path
|
|
23
|
-
from typing import List, Set
|
|
24
|
-
|
|
25
|
-
from lint.base import Severity, LintIssue, LintReport
|
|
26
|
-
from lint import scene_check, style_check, resource_check, verify_check
|
|
27
|
-
from script_utils import FriendlyArgumentParser, run_cli
|
|
28
|
-
|
|
29
|
-
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
30
|
-
|
|
31
|
-
# ──────────────────────────────────────────────
|
|
32
|
-
# 检查器注册表
|
|
33
|
-
# ──────────────────────────────────────────────
|
|
34
|
-
|
|
35
|
-
# 每个检查器必须暴露 check(filepath, lines) -> List[LintIssue]
|
|
36
|
-
# 新增检查器只需: 1) 在 lint/ 下新建 xxx_check.py 2) 在此列表注册
|
|
37
|
-
CHECKERS = [
|
|
38
|
-
{"name": "场景错配", "module": scene_check, "always": True},
|
|
39
|
-
{"name": "编码偏好", "module": style_check, "always": True},
|
|
40
|
-
{"name": "资源管理", "module": resource_check, "always": True},
|
|
41
|
-
{"name": "验证注释", "module": verify_check, "always": False}, # 仅 --strict 模式
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
# A 层硬约束:从 rules/a-layer-rules.json 加载(单一可信源),
|
|
45
|
-
# 以保证 lint 行为与 rules/constraints.md、rules/post-check.md 的口径一致。
|
|
46
|
-
def _load_a_layer_rule_ids() -> Set[str]:
|
|
47
|
-
"""从 rules/a-layer-rules.json 加载 A 层规则 ID 集合。"""
|
|
48
|
-
json_path = SCRIPT_DIR.parent / "rules" / "a-layer-rules.json"
|
|
49
|
-
try:
|
|
50
|
-
data = json.loads(json_path.read_text(encoding="utf-8"))
|
|
51
|
-
return set(data.get("a_layer_rule_ids", []))
|
|
52
|
-
except (FileNotFoundError, json.JSONDecodeError, OSError) as e:
|
|
53
|
-
print(f"[Warn] 无法加载 A 层规则配置 ({json_path}): {e}", file=sys.stderr)
|
|
54
|
-
return set()
|
|
55
|
-
|
|
56
|
-
A_LAYER_RULE_IDS = _load_a_layer_rule_ids()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def get_rule_layer(rule_id: str) -> str:
|
|
60
|
-
"""根据规则 ID 推断当前问题属于 A/B/C 哪一层。"""
|
|
61
|
-
if rule_id.startswith("VERIFY-"):
|
|
62
|
-
return "C"
|
|
63
|
-
if rule_id in A_LAYER_RULE_IDS:
|
|
64
|
-
return "A"
|
|
65
|
-
return "B"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# ──────────────────────────────────────────────
|
|
69
|
-
# 文件扫描
|
|
70
|
-
# ──────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
def collect_java_files(path: str) -> List[str]:
|
|
73
|
-
"""递归收集所有 .java 文件"""
|
|
74
|
-
p = Path(path)
|
|
75
|
-
if p.is_file() and p.suffix == ".java":
|
|
76
|
-
return [str(p)]
|
|
77
|
-
elif p.is_dir():
|
|
78
|
-
return sorted(str(f) for f in p.rglob("*.java"))
|
|
79
|
-
else:
|
|
80
|
-
return []
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def read_file_lines(filepath: str) -> List[str]:
|
|
84
|
-
"""读取文件内容,返回行列表"""
|
|
85
|
-
try:
|
|
86
|
-
with open(filepath, "r", encoding="utf-8") as f:
|
|
87
|
-
return [l.rstrip("\n") for l in f.readlines()]
|
|
88
|
-
except (UnicodeDecodeError, IOError):
|
|
89
|
-
return []
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# ──────────────────────────────────────────────
|
|
93
|
-
# 核心编排
|
|
94
|
-
# ──────────────────────────────────────────────
|
|
95
|
-
|
|
96
|
-
def check_file(filepath: str, strict: bool = False) -> List[LintIssue]:
|
|
97
|
-
"""对单个 Java 文件依次调用所有检查器"""
|
|
98
|
-
lines = read_file_lines(filepath)
|
|
99
|
-
if not lines:
|
|
100
|
-
return []
|
|
101
|
-
|
|
102
|
-
issues: List[LintIssue] = []
|
|
103
|
-
for checker in CHECKERS:
|
|
104
|
-
if not checker["always"] and not strict:
|
|
105
|
-
continue
|
|
106
|
-
try:
|
|
107
|
-
issues.extend(checker["module"].check(filepath, lines))
|
|
108
|
-
except Exception as e:
|
|
109
|
-
issues.append(LintIssue(
|
|
110
|
-
file=filepath,
|
|
111
|
-
line=1,
|
|
112
|
-
severity=Severity.ERROR,
|
|
113
|
-
rule_id="LINT-EXCEPTION",
|
|
114
|
-
message=f"{checker['name']} 检查执行失败: {e}",
|
|
115
|
-
fix_hint="检查脚本实现或输入文件内容;必要时单独运行该校验脚本定位。",
|
|
116
|
-
))
|
|
117
|
-
|
|
118
|
-
for issue in issues:
|
|
119
|
-
if get_rule_layer(issue.rule_id) == "A" and issue.severity != Severity.ERROR:
|
|
120
|
-
issue.severity = Severity.ERROR
|
|
121
|
-
|
|
122
|
-
return issues
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
# ──────────────────────────────────────────────
|
|
126
|
-
# 报告输出
|
|
127
|
-
# ──────────────────────────────────────────────
|
|
128
|
-
|
|
129
|
-
RED = "\033[91m"
|
|
130
|
-
YELLOW = "\033[93m"
|
|
131
|
-
CYAN = "\033[96m"
|
|
132
|
-
GREEN = "\033[92m"
|
|
133
|
-
GRAY = "\033[90m"
|
|
134
|
-
BOLD = "\033[1m"
|
|
135
|
-
RESET = "\033[0m"
|
|
136
|
-
|
|
137
|
-
SEVERITY_COLORS = {
|
|
138
|
-
Severity.ERROR: RED,
|
|
139
|
-
Severity.WARNING: YELLOW,
|
|
140
|
-
Severity.INFO: CYAN,
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
SEVERITY_ICONS = {
|
|
144
|
-
Severity.ERROR: "✖️",
|
|
145
|
-
Severity.WARNING: "[WARN]",
|
|
146
|
-
Severity.INFO: "[INFO]",
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def print_report(report: LintReport, show_fix_hint: bool = False):
|
|
151
|
-
"""终端友好格式输出"""
|
|
152
|
-
if not report.issues:
|
|
153
|
-
print(f"\n{GREEN}{BOLD}✔️ 检查通过!共扫描 {report.total_files} 个文件,未发现问题。{RESET}\n")
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
by_file: dict[str, List[LintIssue]] = {}
|
|
157
|
-
for issue in report.issues:
|
|
158
|
-
by_file.setdefault(issue.file, []).append(issue)
|
|
159
|
-
|
|
160
|
-
print(f"\n{BOLD}{'═' * 60}{RESET}")
|
|
161
|
-
print(f"{BOLD} 苍穹代码校验报告{RESET}")
|
|
162
|
-
print(f"{BOLD}{'═' * 60}{RESET}\n")
|
|
163
|
-
|
|
164
|
-
for filepath, file_issues in by_file.items():
|
|
165
|
-
rel = os.path.relpath(filepath)
|
|
166
|
-
print(f" {BOLD}[File] {rel}{RESET}")
|
|
167
|
-
for issue in sorted(file_issues, key=lambda x: x.line):
|
|
168
|
-
color = SEVERITY_COLORS[issue.severity]
|
|
169
|
-
icon = SEVERITY_ICONS[issue.severity]
|
|
170
|
-
layer = get_rule_layer(issue.rule_id)
|
|
171
|
-
print(f" {color}{icon} L{issue.line:>4d} [{layer}/{issue.rule_id}]{RESET} {issue.message}")
|
|
172
|
-
if issue.source_line:
|
|
173
|
-
print(f" {GRAY}> {issue.source_line}{RESET}")
|
|
174
|
-
if show_fix_hint and issue.fix_hint:
|
|
175
|
-
print(f" {GREEN}[Fix] {issue.fix_hint}{RESET}")
|
|
176
|
-
print()
|
|
177
|
-
|
|
178
|
-
print(f" {BOLD}{'─' * 50}{RESET}")
|
|
179
|
-
print(f" [Stats] 扫描文件: {report.total_files} "
|
|
180
|
-
f"总问题: {report.total_issues} "
|
|
181
|
-
f"{RED}ERROR: {report.errors}{RESET} "
|
|
182
|
-
f"{YELLOW}WARNING: {report.warnings}{RESET} "
|
|
183
|
-
f"{CYAN}INFO: {report.infos}{RESET}")
|
|
184
|
-
|
|
185
|
-
if report.errors > 0:
|
|
186
|
-
print(f"\n {RED}{BOLD}[Error] 发现 {report.errors} 个错误,请修复后再提交。{RESET}\n")
|
|
187
|
-
elif report.warnings > 0:
|
|
188
|
-
print(f"\n {YELLOW}{BOLD}[Warn] 发现 {report.warnings} 个警告,建议修复。{RESET}\n")
|
|
189
|
-
else:
|
|
190
|
-
print(f"\n {GREEN}{BOLD}✔️ 仅有建议项,整体良好。{RESET}\n")
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def print_json_report(report: LintReport):
|
|
194
|
-
"""JSON 格式输出(适合 CI/CD 集成)"""
|
|
195
|
-
output = {
|
|
196
|
-
"summary": {
|
|
197
|
-
"total_files": report.total_files,
|
|
198
|
-
"total_issues": report.total_issues,
|
|
199
|
-
"errors": report.errors,
|
|
200
|
-
"warnings": report.warnings,
|
|
201
|
-
"infos": report.infos,
|
|
202
|
-
"passed": report.errors == 0,
|
|
203
|
-
},
|
|
204
|
-
"issues": [
|
|
205
|
-
{
|
|
206
|
-
"file": os.path.relpath(i.file),
|
|
207
|
-
"line": i.line,
|
|
208
|
-
"severity": i.severity.value,
|
|
209
|
-
"layer": get_rule_layer(i.rule_id),
|
|
210
|
-
"rule_id": i.rule_id,
|
|
211
|
-
"message": i.message,
|
|
212
|
-
"fix_hint": i.fix_hint,
|
|
213
|
-
"source_line": i.source_line,
|
|
214
|
-
}
|
|
215
|
-
for i in report.issues
|
|
216
|
-
],
|
|
217
|
-
}
|
|
218
|
-
print(json.dumps(output, ensure_ascii=False, indent=2))
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# ──────────────────────────────────────────────
|
|
222
|
-
# 入口
|
|
223
|
-
# ──────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
def main():
|
|
226
|
-
parser = FriendlyArgumentParser(
|
|
227
|
-
description="苍穹代码生成后自动校验脚本",
|
|
228
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
229
|
-
epilog="""
|
|
230
|
-
检查模块:
|
|
231
|
-
lint/scene_check.py 场景错配 (SCENE-*)
|
|
232
|
-
lint/style_check.py 编码偏好 (STYLE-*)
|
|
233
|
-
lint/resource_check.py 资源管理 (RESOURCE-*)
|
|
234
|
-
lint/verify_check.py 验证注释治理 (VERIFY-*, C 层,仅 --strict)
|
|
235
|
-
|
|
236
|
-
扩展方式:
|
|
237
|
-
1. 在 lint/ 下新建 xxx_check.py,暴露 check(filepath, lines) 函数
|
|
238
|
-
2. 在 cosmic-post-lint.py 的 CHECKERS 列表中注册
|
|
239
|
-
""",
|
|
240
|
-
)
|
|
241
|
-
parser.add_argument("path", help="要检查的 Java 文件或目录路径")
|
|
242
|
-
parser.add_argument("--fix-hint", action="store_true", help="显示修复建议")
|
|
243
|
-
parser.add_argument("--json", action="store_true", help="输出 JSON 格式(适合 CI)")
|
|
244
|
-
parser.add_argument("--strict", action="store_true",
|
|
245
|
-
help="严格模式:额外启用 C 层验证来源治理检查")
|
|
246
|
-
parser.add_argument("--min-severity", choices=["error", "warning", "info"],
|
|
247
|
-
default="info", help="最低报告级别 (默认: info)")
|
|
248
|
-
|
|
249
|
-
args = parser.parse_args()
|
|
250
|
-
|
|
251
|
-
severity_filter = {
|
|
252
|
-
"error": {Severity.ERROR},
|
|
253
|
-
"warning": {Severity.ERROR, Severity.WARNING},
|
|
254
|
-
"info": {Severity.ERROR, Severity.WARNING, Severity.INFO},
|
|
255
|
-
}[args.min_severity]
|
|
256
|
-
|
|
257
|
-
files = collect_java_files(args.path)
|
|
258
|
-
if not files:
|
|
259
|
-
print(f"✖️ 未找到 Java 文件: {args.path}", file=sys.stderr)
|
|
260
|
-
sys.exit(1)
|
|
261
|
-
|
|
262
|
-
report = LintReport(total_files=len(files))
|
|
263
|
-
|
|
264
|
-
def _check_one(fp):
|
|
265
|
-
return fp, check_file(fp, strict=args.strict)
|
|
266
|
-
|
|
267
|
-
if len(files) == 1:
|
|
268
|
-
all_results = [_check_one(files[0])]
|
|
269
|
-
else:
|
|
270
|
-
all_results = [None] * len(files)
|
|
271
|
-
with ThreadPoolExecutor(max_workers=min(len(files), 4)) as pool:
|
|
272
|
-
future_to_idx = {
|
|
273
|
-
pool.submit(_check_one, fp): i
|
|
274
|
-
for i, fp in enumerate(files)
|
|
275
|
-
}
|
|
276
|
-
for future in as_completed(future_to_idx):
|
|
277
|
-
all_results[future_to_idx[future]] = future.result()
|
|
278
|
-
|
|
279
|
-
for _, issues in all_results:
|
|
280
|
-
for issue in issues:
|
|
281
|
-
if issue.severity in severity_filter:
|
|
282
|
-
report.add(issue)
|
|
283
|
-
|
|
284
|
-
if args.json:
|
|
285
|
-
print_json_report(report)
|
|
286
|
-
else:
|
|
287
|
-
print_report(report, show_fix_hint=args.fix_hint)
|
|
288
|
-
|
|
289
|
-
sys.exit(1 if report.errors > 0 else 0)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if __name__ == "__main__":
|
|
293
|
-
sys.exit(run_cli(main))
|