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,375 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""场景错配检查 (SCENE-*) — 来源: anti-patterns.md 场景错配表"""
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from typing import List, Optional, Set, Tuple
|
|
6
|
+
|
|
7
|
+
from .base import (
|
|
8
|
+
LintIssue,
|
|
9
|
+
Severity,
|
|
10
|
+
analyze_java_context,
|
|
11
|
+
analyze_plugin_context,
|
|
12
|
+
classify_lines,
|
|
13
|
+
code_for_structure,
|
|
14
|
+
detect_listener_interfaces,
|
|
15
|
+
detect_plugin_type,
|
|
16
|
+
parse_java,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
INITIALIZE_UI_PATTERN = re.compile(
|
|
21
|
+
r"getView\s*\(\)\s*\.\s*"
|
|
22
|
+
r"(setEnable|setVisible|updateView|show\w+|setFocus|setMustInput|setCaption)\s*\("
|
|
23
|
+
)
|
|
24
|
+
INITIALIZE_LISTENER_PATTERN = re.compile(r"add\w*Listener[s]?\s*\(")
|
|
25
|
+
BIND_MUTATION_PATTERN = re.compile(
|
|
26
|
+
r"(?:(?:getModel\s*\(\)|\bmodel)\s*\.\s*"
|
|
27
|
+
r"(setValue|deleteEntryRow|createNewEntryRow|insertEntryRow|batchCreateNewEntryRow|setDataEntity)\s*\()"
|
|
28
|
+
r"|(?:\.\s*setValueFast\s*\()"
|
|
29
|
+
)
|
|
30
|
+
META_TABLE_PATTERN = re.compile(r"\bt_meta_[A-Za-z0-9_]+\b", re.IGNORECASE)
|
|
31
|
+
ENTITY_METADATA_CREATE_PATTERN = re.compile(
|
|
32
|
+
r"EntityMetadataCache\s*\.\s*getDataEntityType\s*\([^)]*\)\s*\.\s*createInstance\s*\("
|
|
33
|
+
)
|
|
34
|
+
# SCENE-012: propertyChanged 中无条件 setValue 检测
|
|
35
|
+
_PC_SETVALUE_PATTERN = re.compile(
|
|
36
|
+
r"(?:getModel\s*\(\)\s*\.\s*setValue|model\s*\.\s*setValue|\.\s*setValueFast)\s*\("
|
|
37
|
+
)
|
|
38
|
+
_PC_GUARD_PATTERN = re.compile(r"getProperty\s*\(\s*\)|getChangeSet\s*\(\s*\)")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check(filepath: str, lines: List[str]) -> List[LintIssue]:
|
|
42
|
+
"""执行场景错配检查,返回问题列表。"""
|
|
43
|
+
issues: List[LintIssue] = []
|
|
44
|
+
listeners = detect_listener_interfaces(lines)
|
|
45
|
+
tree, lang = parse_java(lines)
|
|
46
|
+
method_context, _ = analyze_java_context(lines, tree=tree)
|
|
47
|
+
plugin_context = analyze_plugin_context(lines)
|
|
48
|
+
skip_lines = classify_lines(lines)
|
|
49
|
+
|
|
50
|
+
# 有状态上下文
|
|
51
|
+
_model_alias_vars: Set[str] = set() # 追踪操作插件中 getModel() 赋值的变量名
|
|
52
|
+
current_method: Optional[str] = None
|
|
53
|
+
|
|
54
|
+
# ── 逐行检查 ──
|
|
55
|
+
for i, line in enumerate(lines):
|
|
56
|
+
lineno = i + 1
|
|
57
|
+
code_line = code_for_structure(line)
|
|
58
|
+
method_name = (method_context[i] or "").lower()
|
|
59
|
+
is_op_line = plugin_context[i] == "op"
|
|
60
|
+
|
|
61
|
+
if method_context[i] != current_method:
|
|
62
|
+
_model_alias_vars.clear()
|
|
63
|
+
current_method = method_context[i]
|
|
64
|
+
|
|
65
|
+
# SCENE-001: 操作插件不应调 getView()
|
|
66
|
+
if is_op_line and not skip_lines[i]:
|
|
67
|
+
if re.search(r"this\s*\.\s*getView\s*\(\s*\)", code_line) or re.search(r"getView\(\)", code_line):
|
|
68
|
+
if not re.search(r"(log\.|getContextSample\s*\()", code_line):
|
|
69
|
+
issues.append(LintIssue(
|
|
70
|
+
file=filepath, line=lineno,
|
|
71
|
+
severity=Severity.ERROR,
|
|
72
|
+
rule_id="SCENE-001",
|
|
73
|
+
message="操作插件中调用 getView():操作插件无 UI 上下文",
|
|
74
|
+
fix_hint="使用 log 记录日志或 OpUtils.addErrorMessage() 报告错误",
|
|
75
|
+
source_line=line.strip(),
|
|
76
|
+
))
|
|
77
|
+
|
|
78
|
+
# SCENE-002: 操作插件不应通过 model 操作
|
|
79
|
+
if is_op_line and not skip_lines[i]:
|
|
80
|
+
if re.search(r"this\s*\.\s*getModel\s*\(\s*\)\s*\.\s*setValue", code_line):
|
|
81
|
+
issues.append(LintIssue(
|
|
82
|
+
file=filepath, line=lineno,
|
|
83
|
+
severity=Severity.ERROR,
|
|
84
|
+
rule_id="SCENE-002",
|
|
85
|
+
message="操作插件中调用 getModel().setValue():操作插件不通过 model 操作",
|
|
86
|
+
fix_hint="直接操作 DynamicObject 数据包: dataEntity.set(\"field\", value)",
|
|
87
|
+
source_line=line.strip(),
|
|
88
|
+
))
|
|
89
|
+
else:
|
|
90
|
+
# 追踪 model 别名: Type varName = this.getModel() 或 getModel()
|
|
91
|
+
_model_assign = re.search(
|
|
92
|
+
r'\b(\w+)\s*=\s*(?:this\s*\.\s*)?getModel\s*\(\s*\)', code_line
|
|
93
|
+
)
|
|
94
|
+
if _model_assign:
|
|
95
|
+
_model_alias_vars.add(_model_assign.group(1))
|
|
96
|
+
# 检测 model 别名调用 setValue
|
|
97
|
+
for _mvar in _model_alias_vars:
|
|
98
|
+
if re.search(rf'\b{re.escape(_mvar)}\s*\.\s*setValue\s*\(', code_line):
|
|
99
|
+
issues.append(LintIssue(
|
|
100
|
+
file=filepath, line=lineno,
|
|
101
|
+
severity=Severity.ERROR,
|
|
102
|
+
rule_id="SCENE-002",
|
|
103
|
+
message=f"操作插件中通过 model 变量 '{_mvar}' 调用 setValue():操作插件不通过 model 操作",
|
|
104
|
+
fix_hint="直接操作 DynamicObject 数据包: dataEntity.set(\"field\", value)",
|
|
105
|
+
source_line=line.strip(),
|
|
106
|
+
))
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# SCENE-003: registerListener 中读数据
|
|
110
|
+
if method_name == "registerlistener" and re.search(r"(getModel|getValue)\s*\(", code_line) and not skip_lines[i]:
|
|
111
|
+
issues.append(LintIssue(
|
|
112
|
+
file=filepath, line=lineno,
|
|
113
|
+
severity=Severity.WARNING,
|
|
114
|
+
rule_id="SCENE-003",
|
|
115
|
+
message="在 registerListener 中调用 getValue():此时数据尚未绑定",
|
|
116
|
+
fix_hint="推迟到 afterBindData() 中处理",
|
|
117
|
+
source_line=line.strip(),
|
|
118
|
+
))
|
|
119
|
+
|
|
120
|
+
# SCENE-006: initialize 中注册监听
|
|
121
|
+
if method_name == "initialize" and INITIALIZE_LISTENER_PATTERN.search(code_line):
|
|
122
|
+
issues.append(LintIssue(
|
|
123
|
+
file=filepath, line=lineno,
|
|
124
|
+
severity=Severity.ERROR,
|
|
125
|
+
rule_id="SCENE-006",
|
|
126
|
+
message="禁止在 initialize() 中注册监听事件",
|
|
127
|
+
fix_hint="将 addXxxListener(...) 挪到 registerListener() 中",
|
|
128
|
+
source_line=line.strip(),
|
|
129
|
+
))
|
|
130
|
+
|
|
131
|
+
# SCENE-007: initialize 中做 UI 状态逻辑
|
|
132
|
+
if method_name == "initialize" and INITIALIZE_UI_PATTERN.search(code_line):
|
|
133
|
+
issues.append(LintIssue(
|
|
134
|
+
file=filepath, line=lineno,
|
|
135
|
+
severity=Severity.ERROR,
|
|
136
|
+
rule_id="SCENE-007",
|
|
137
|
+
message="禁止在 initialize() 中处理 UI 状态或弹窗逻辑",
|
|
138
|
+
fix_hint="将界面控制逻辑挪到 afterBindData() 或正确的 UI 事件中",
|
|
139
|
+
source_line=line.strip(),
|
|
140
|
+
))
|
|
141
|
+
|
|
142
|
+
# SCENE-008: before/afterBindData 中修改数据对象
|
|
143
|
+
if method_name in {"beforebinddata", "afterbinddata"} and BIND_MUTATION_PATTERN.search(code_line):
|
|
144
|
+
issues.append(LintIssue(
|
|
145
|
+
file=filepath, line=lineno,
|
|
146
|
+
severity=Severity.ERROR,
|
|
147
|
+
rule_id="SCENE-008",
|
|
148
|
+
message="禁止在 beforeBindData()/afterBindData() 中修改数据对象",
|
|
149
|
+
fix_hint="将 setValue/分录增删等数据变更挪到 createNewData、afterCreateNewData、propertyChanged 或正确的业务事件",
|
|
150
|
+
source_line=line.strip(),
|
|
151
|
+
))
|
|
152
|
+
|
|
153
|
+
# SCENE-009: 直接访问平台元数据表
|
|
154
|
+
if META_TABLE_PATTERN.search(code_line) and not skip_lines[i]:
|
|
155
|
+
issues.append(LintIssue(
|
|
156
|
+
file=filepath, line=lineno,
|
|
157
|
+
severity=Severity.ERROR,
|
|
158
|
+
rule_id="SCENE-009",
|
|
159
|
+
message="业务代码禁止直接访问平台元数据表 t_meta_xxx",
|
|
160
|
+
fix_hint="使用元数据脚本或平台 API 获取字段/实体信息,不要直接查 t_meta_xxx",
|
|
161
|
+
source_line=line.strip(),
|
|
162
|
+
))
|
|
163
|
+
|
|
164
|
+
# SCENE-010: 用其他实体 createInstance() 构造引用对象
|
|
165
|
+
if ENTITY_METADATA_CREATE_PATTERN.search(code_line):
|
|
166
|
+
issues.append(LintIssue(
|
|
167
|
+
file=filepath, line=lineno,
|
|
168
|
+
severity=Severity.ERROR,
|
|
169
|
+
rule_id="SCENE-010",
|
|
170
|
+
message="直接用 EntityMetadataCache.getDataEntityType(...).createInstance() 构造对象,容易出现引用类型不一致",
|
|
171
|
+
fix_hint="优先通过当前实体属性复杂类型或当前实体元数据 createInstance()",
|
|
172
|
+
source_line=line.strip(),
|
|
173
|
+
))
|
|
174
|
+
|
|
175
|
+
# ── 方法级检查: propertyChanged 无条件 setValue ──
|
|
176
|
+
_check_unguarded_setvalue_in_property_changed(filepath, lines, method_context, skip_lines, issues)
|
|
177
|
+
|
|
178
|
+
# ── 文件级检查: Listener 注册 ──
|
|
179
|
+
if listeners:
|
|
180
|
+
has_register = any(
|
|
181
|
+
re.search(r"void\s+registerListener\s*\(", l) for l in lines
|
|
182
|
+
)
|
|
183
|
+
if not has_register:
|
|
184
|
+
# SCENE-004: 实现了 Listener 但没有 registerListener 方法
|
|
185
|
+
issues.append(LintIssue(
|
|
186
|
+
file=filepath, line=1,
|
|
187
|
+
severity=Severity.WARNING,
|
|
188
|
+
rule_id="SCENE-004",
|
|
189
|
+
message=f"实现了 Listener 接口 ({', '.join(listeners)}) 但未找到 registerListener 方法",
|
|
190
|
+
fix_hint="在 registerListener() 中调用 addXxxListener() 注册监听",
|
|
191
|
+
))
|
|
192
|
+
else:
|
|
193
|
+
# SCENE-005: 有 registerListener 但没有 addXxxListener 调用
|
|
194
|
+
# 使用 AST 树精确定位 registerListener 方法体
|
|
195
|
+
has_add_listener = False
|
|
196
|
+
try:
|
|
197
|
+
import tree_sitter
|
|
198
|
+
q = tree_sitter.Query(lang, "(method_declaration name: (identifier) @name body: (block) @body)")
|
|
199
|
+
for match in q.matches(tree.root_node):
|
|
200
|
+
if len(match) > 1 and isinstance(match[1], dict):
|
|
201
|
+
match_dict = match[1]
|
|
202
|
+
m_name_nodes = match_dict.get("name", [])
|
|
203
|
+
m_body_nodes = match_dict.get("body", [])
|
|
204
|
+
if m_name_nodes and m_body_nodes:
|
|
205
|
+
if m_name_nodes[0].text.decode('utf-8') == "registerListener":
|
|
206
|
+
raw_body_text = m_body_nodes[0].text.decode('utf-8')
|
|
207
|
+
clean_body_lines = [code_for_structure(l) for l in raw_body_text.splitlines()]
|
|
208
|
+
body_text = "\n".join(clean_body_lines)
|
|
209
|
+
if re.search(r"add\w*Listener[s]?\s*\(", body_text):
|
|
210
|
+
has_add_listener = True
|
|
211
|
+
except Exception:
|
|
212
|
+
# 降级:如果 AST 失败,假设通过避免误报
|
|
213
|
+
has_add_listener = True
|
|
214
|
+
|
|
215
|
+
if not has_add_listener:
|
|
216
|
+
issues.append(LintIssue(
|
|
217
|
+
file=filepath, line=1,
|
|
218
|
+
severity=Severity.WARNING,
|
|
219
|
+
rule_id="SCENE-005",
|
|
220
|
+
message=f"实现了 Listener 接口 ({', '.join(listeners)}) 但 registerListener 中未调用 addXxxListener()",
|
|
221
|
+
fix_hint="在 registerListener() 中调用对应的 addXxxListener(this) 注册",
|
|
222
|
+
))
|
|
223
|
+
|
|
224
|
+
# ── 文件级检查: 继承型插件 @Override 不调 super ──
|
|
225
|
+
is_op, is_ui, is_other = detect_plugin_type(lines)
|
|
226
|
+
is_inheritable = is_op or is_ui or is_other
|
|
227
|
+
if is_inheritable:
|
|
228
|
+
_check_missing_super(filepath, lines, plugin_context, issues, tree=tree, lang=lang)
|
|
229
|
+
|
|
230
|
+
return issues
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _check_unguarded_setvalue_in_property_changed(
|
|
234
|
+
filepath: str, lines: List[str],
|
|
235
|
+
method_context: List, skip_lines: List[bool], issues: List[LintIssue],
|
|
236
|
+
):
|
|
237
|
+
"""SCENE-012: propertyChanged 中调用 setValue 但未判断 getProperty() 或 getChangeSet(),死循环风险。"""
|
|
238
|
+
# 收集 propertyChanged 方法体的行范围
|
|
239
|
+
ranges: List[Tuple[int, int]] = []
|
|
240
|
+
start: int = -1
|
|
241
|
+
for i, mc in enumerate(method_context):
|
|
242
|
+
if mc and mc.lower() == "propertychanged":
|
|
243
|
+
if start < 0:
|
|
244
|
+
start = i
|
|
245
|
+
else:
|
|
246
|
+
if start >= 0:
|
|
247
|
+
ranges.append((start, i))
|
|
248
|
+
start = -1
|
|
249
|
+
if start >= 0:
|
|
250
|
+
ranges.append((start, len(lines)))
|
|
251
|
+
|
|
252
|
+
for s, e in ranges:
|
|
253
|
+
has_set_value = False
|
|
254
|
+
has_guard = False
|
|
255
|
+
first_sv_line: int = -1
|
|
256
|
+
for i in range(s, e):
|
|
257
|
+
if skip_lines[i]:
|
|
258
|
+
continue
|
|
259
|
+
code = code_for_structure(lines[i])
|
|
260
|
+
if _PC_SETVALUE_PATTERN.search(code):
|
|
261
|
+
if not has_set_value:
|
|
262
|
+
first_sv_line = i
|
|
263
|
+
has_set_value = True
|
|
264
|
+
if _PC_GUARD_PATTERN.search(code):
|
|
265
|
+
has_guard = True
|
|
266
|
+
if has_set_value and not has_guard:
|
|
267
|
+
issues.append(LintIssue(
|
|
268
|
+
file=filepath, line=first_sv_line + 1,
|
|
269
|
+
severity=Severity.ERROR,
|
|
270
|
+
rule_id="SCENE-012",
|
|
271
|
+
message="propertyChanged 中调用 setValue 但未判断 e.getProperty().getName(),可能导致死循环(栈溢出)",
|
|
272
|
+
fix_hint="先用 e.getProperty().getName().equals(\"目标字段\") 守卫,赋值前比对新旧值避免无限递归",
|
|
273
|
+
source_line=lines[first_sv_line].strip(),
|
|
274
|
+
))
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# 继承型插件生命周期方法(需要调 super 的方法名,全小写)
|
|
278
|
+
_LIFECYCLE_METHODS = {
|
|
279
|
+
"initialize", "registerlistener", "preopenform",
|
|
280
|
+
"createnewdata", "aftercreatenewdata", "loaddata", "afterloaddata",
|
|
281
|
+
"beforebinddata", "afterbinddata", "aftercopydata",
|
|
282
|
+
"propertychanged", "beforedooperation", "afterdooperation",
|
|
283
|
+
"beforeitemclick", "itemclick", "beforeclick", "click",
|
|
284
|
+
"beforef7select", "confirmcallback", "closedcallback",
|
|
285
|
+
"clientcallback", "beforeclosed", "customevent",
|
|
286
|
+
"afteraddrow", "afterdeleterow", "afterdeleteentry", "destory",
|
|
287
|
+
"onpreparepropertys", "onaddvalidators",
|
|
288
|
+
"beforeexecuteoperationtransaction", "beginoperationtransaction",
|
|
289
|
+
"endoperationtransaction", "afterexecuteoperationtransaction",
|
|
290
|
+
"onreturnoperation",
|
|
291
|
+
"setfilter", "beforedoselectrow",
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
_OVERRIDE_PATTERN = re.compile(r"@Override")
|
|
295
|
+
_METHOD_NAME_PATTERN = re.compile(
|
|
296
|
+
r"(?:public|protected)\s+\w[\w<>\[\], ?.]*\s+([A-Za-z_]\w*)\s*\("
|
|
297
|
+
)
|
|
298
|
+
_SUPER_CALL_PATTERN_TEMPLATE = r"\bsuper\s*\.\s*{method}\s*\("
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _check_missing_super(filepath: str, lines: List[str],
|
|
302
|
+
plugin_context: List, issues: List[LintIssue],
|
|
303
|
+
tree=None, lang=None):
|
|
304
|
+
"""检测继承型插件中 @Override 生命周期方法是否遗漏 super 调用。"""
|
|
305
|
+
try:
|
|
306
|
+
import tree_sitter
|
|
307
|
+
if tree is None or lang is None:
|
|
308
|
+
tree, lang = parse_java(lines)
|
|
309
|
+
|
|
310
|
+
q = tree_sitter.Query(lang, """
|
|
311
|
+
(method_declaration
|
|
312
|
+
name: (identifier) @name
|
|
313
|
+
body: (block) @body
|
|
314
|
+
) @method
|
|
315
|
+
""")
|
|
316
|
+
|
|
317
|
+
for match in q.matches(tree.root_node):
|
|
318
|
+
if len(match) < 2 or not isinstance(match[1], dict):
|
|
319
|
+
continue
|
|
320
|
+
match_dict = match[1]
|
|
321
|
+
|
|
322
|
+
method_nodes = match_dict.get("method", [])
|
|
323
|
+
if not method_nodes: continue
|
|
324
|
+
method_node = method_nodes[0]
|
|
325
|
+
|
|
326
|
+
# Check @Override
|
|
327
|
+
is_override = False
|
|
328
|
+
for child in method_node.children:
|
|
329
|
+
if child.type == "modifiers":
|
|
330
|
+
for mod in child.children:
|
|
331
|
+
if mod.type == "marker_annotation" and "Override" in mod.text.decode('utf-8'):
|
|
332
|
+
is_override = True
|
|
333
|
+
|
|
334
|
+
if not is_override:
|
|
335
|
+
continue
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# Get Method Name
|
|
339
|
+
name_nodes = match_dict.get("name", [])
|
|
340
|
+
if not name_nodes: continue
|
|
341
|
+
method_name = name_nodes[0].text.decode('utf-8')
|
|
342
|
+
|
|
343
|
+
if method_name.lower() not in _LIFECYCLE_METHODS:
|
|
344
|
+
continue
|
|
345
|
+
|
|
346
|
+
# Check Plugin Context for this method
|
|
347
|
+
# Just take the context of the line where method name is
|
|
348
|
+
method_line = name_nodes[0].start_point[0]
|
|
349
|
+
if method_line < len(plugin_context) and plugin_context[method_line] not in {"op", "ui", "other"}:
|
|
350
|
+
continue
|
|
351
|
+
|
|
352
|
+
# Check if super.methodName() exists in the body
|
|
353
|
+
body_nodes = match_dict.get("body", [])
|
|
354
|
+
if not body_nodes: continue
|
|
355
|
+
raw_body_text = body_nodes[0].text.decode('utf-8')
|
|
356
|
+
|
|
357
|
+
clean_body_lines = [code_for_structure(l) for l in raw_body_text.splitlines()]
|
|
358
|
+
body_text = "\n".join(clean_body_lines)
|
|
359
|
+
|
|
360
|
+
super_pattern = re.compile(
|
|
361
|
+
_SUPER_CALL_PATTERN_TEMPLATE.format(method=re.escape(method_name))
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
if not super_pattern.search(body_text):
|
|
365
|
+
issues.append(LintIssue(
|
|
366
|
+
file=filepath, line=method_line + 1,
|
|
367
|
+
severity=Severity.WARNING,
|
|
368
|
+
rule_id="SCENE-011",
|
|
369
|
+
message=f"继承型插件 @Override {method_name}() 未调用 super.{method_name}(),基类初始化逻辑可能不执行",
|
|
370
|
+
fix_hint=f"在方法体首行添加 super.{method_name}(...);接口型插件(如 IWorkflowPlugin)无需此调用",
|
|
371
|
+
source_line=method_name,
|
|
372
|
+
))
|
|
373
|
+
except Exception:
|
|
374
|
+
# 降级:如果 AST 失败,不做检查,避免由于解析失败导致的误报
|
|
375
|
+
pass
|