kcode-pi 0.1.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 +358 -0
- package/dist/cli/kcode.d.ts +15 -0
- package/dist/cli/kcode.js +153 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +7 -0
- package/docs/KCODE_DISTRIBUTION.md +91 -0
- package/extensions/kingdee-harness.ts +180 -0
- package/extensions/kingdee-header.ts +122 -0
- package/extensions/kingdee-tools.ts +379 -0
- package/knowledge/.backup/v1.0.0/version.json +10 -0
- package/knowledge/cangqiong/product-notes.md +15 -0
- package/knowledge/common/business-flows.md +115 -0
- package/knowledge/common/config-guides.md +110 -0
- package/knowledge/common/error-patterns.md +170 -0
- package/knowledge/common/implementation.md +144 -0
- package/knowledge/cosmic/hard-constraints.md +38 -0
- package/knowledge/cosmic/ksql-datafix.md +34 -0
- package/knowledge/cosmic/platform-baseline.md +32 -0
- package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
- package/knowledge/cosmic/review-checklist.md +40 -0
- package/knowledge/cosmic/unittest.md +35 -0
- package/knowledge/enterprise/api-reference.md +186 -0
- package/knowledge/enterprise/code-patterns.md +217 -0
- package/knowledge/enterprise/plugin-lifecycle.md +188 -0
- package/knowledge/enterprise/tables.json +159 -0
- package/knowledge/flagship/api-reference.md +237 -0
- package/knowledge/flagship/code-patterns.md +246 -0
- package/knowledge/flagship/cosmic-platform-note.md +15 -0
- package/knowledge/flagship/plugin-lifecycle.md +248 -0
- package/knowledge/flagship/tables.json +159 -0
- package/knowledge/version.json +10 -0
- package/knowledge/xinghan/product-notes.md +15 -0
- package/package.json +71 -0
- package/prompts/kd-discuss.md +11 -0
- package/prompts/kd-execute.md +12 -0
- package/prompts/kd-plan.md +12 -0
- package/prompts/kd-ship.md +12 -0
- package/prompts/kd-spec.md +12 -0
- package/prompts/kd-verify.md +12 -0
- package/skills/kd-check/SKILL.md +26 -0
- package/skills/kd-cosmic-dev/SKILL.md +82 -0
- package/skills/kd-cosmic-review/SKILL.md +90 -0
- package/skills/kd-cosmic-unittest/SKILL.md +92 -0
- package/skills/kd-debug/SKILL.md +30 -0
- package/skills/kd-discuss/SKILL.md +24 -0
- package/skills/kd-execute/SKILL.md +22 -0
- package/skills/kd-gen/SKILL.md +34 -0
- package/skills/kd-ksql/SKILL.md +86 -0
- package/skills/kd-plan/SKILL.md +24 -0
- package/skills/kd-ship/SKILL.md +22 -0
- package/skills/kd-spec/SKILL.md +24 -0
- package/skills/kd-verify/SKILL.md +22 -0
- package/themes/kcode-dark.json +81 -0
- package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
- package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
- package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
- package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
- 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/ok-cosmic-docs.db +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
- package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
- package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
|
@@ -0,0 +1,262 @@
|
|
|
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))
|
|
@@ -0,0 +1,293 @@
|
|
|
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))
|