@stalfh233/omc-cli 0.0.0-stage → 0.4.10
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/LICENSE +21 -0
- package/README.md +293 -3
- package/coverage/m1-coverage-manifest-v1.json +1278 -0
- package/dist/approval-token.js +102 -0
- package/dist/args.js +25 -0
- package/dist/artifacts.js +119 -0
- package/dist/bench/call-face-eval.js +256 -0
- package/dist/bench/context-attribution.js +151 -0
- package/dist/bench/discovery-cost-eval.js +230 -0
- package/dist/bench/driver.js +81 -0
- package/dist/bench/evals.js +236 -0
- package/dist/bench/fake-http-server.js +65 -0
- package/dist/bench/instrument.js +87 -0
- package/dist/bench/intent-face-eval.js +343 -0
- package/dist/bench/run.js +166 -0
- package/dist/bench/scenario.js +343 -0
- package/dist/bench/types.js +76 -0
- package/dist/bi-wire.js +41 -0
- package/dist/bizservice-config.js +581 -0
- package/dist/call.js +153 -0
- package/dist/capability-absences.js +23 -0
- package/dist/capability-overview.js +492 -0
- package/dist/capability-shape.js +154 -0
- package/dist/cli-contract.js +70 -0
- package/dist/cli-output.js +73 -0
- package/dist/cli.js +1418 -0
- package/dist/code-rules.js +69 -0
- package/dist/command-transport.js +155 -0
- package/dist/config-store.js +195 -0
- package/dist/context.js +21 -0
- package/dist/contract-consistency.js +66 -0
- package/dist/contract-resources.js +62 -0
- package/dist/coverage-consistency.js +62 -0
- package/dist/coverage-registry.js +76 -0
- package/dist/coverage.js +130 -0
- package/dist/data-list-filter.js +114 -0
- package/dist/discovery.js +390 -0
- package/dist/endpoints.js +154 -0
- package/dist/environment-policy.js +26 -0
- package/dist/execution-metadata.js +1092 -0
- package/dist/fake/app.js +45 -0
- package/dist/fake/b2-registration.js +594 -0
- package/dist/fake/businessrule.js +242 -0
- package/dist/fake/datarule.js +72 -0
- package/dist/fake/dictionary.js +108 -0
- package/dist/fake/environment.js +30 -0
- package/dist/fake/field.js +167 -0
- package/dist/fake/form.js +101 -0
- package/dist/fake/index.js +121 -0
- package/dist/fake/list-view.js +289 -0
- package/dist/fake/model.js +136 -0
- package/dist/fake/online-js.js +18 -0
- package/dist/fake/report.js +253 -0
- package/dist/fake/routes.js +47 -0
- package/dist/fake/rule-lifecycle.js +37 -0
- package/dist/fake/runtime-data.js +367 -0
- package/dist/fake/state.js +67 -0
- package/dist/fake/workflow.js +364 -0
- package/dist/field-change.js +200 -0
- package/dist/field-families.js +896 -0
- package/dist/form-layout.js +111 -0
- package/dist/form-support.js +821 -0
- package/dist/goal-routes.js +468 -0
- package/dist/governed-execution.js +87 -0
- package/dist/human-summary.js +212 -0
- package/dist/identity.js +62 -0
- package/dist/intent/baseline.js +57 -0
- package/dist/intent/capabilities/bizservice.js +274 -0
- package/dist/intent/capabilities/businessrule.js +493 -0
- package/dist/intent/capabilities/datarule.js +187 -0
- package/dist/intent/capabilities/field.js +545 -0
- package/dist/intent/capabilities/form.js +136 -0
- package/dist/intent/capabilities/index.js +64 -0
- package/dist/intent/capabilities/listview.js +157 -0
- package/dist/intent/capabilities/model.js +100 -0
- package/dist/intent/capabilities/onlinejs.js +108 -0
- package/dist/intent/capabilities/report.js +355 -0
- package/dist/intent/capabilities/workflow.js +458 -0
- package/dist/intent/capability.js +6 -0
- package/dist/intent/cli.js +91 -0
- package/dist/intent/compare.js +56 -0
- package/dist/intent/compiler.js +79 -0
- package/dist/intent/dsl.js +129 -0
- package/dist/intent/plan-file.js +63 -0
- package/dist/intent/readback.js +65 -0
- package/dist/intent/schema.js +158 -0
- package/dist/intent/validation.js +30 -0
- package/dist/intent/yaml.js +315 -0
- package/dist/json-column.js +68 -0
- package/dist/lanes/app-contract.js +95 -0
- package/dist/lanes/app-coverage.js +16 -0
- package/dist/lanes/app.js +174 -0
- package/dist/lanes/apply-changes.js +231 -0
- package/dist/lanes/b2-registration-contract.js +292 -0
- package/dist/lanes/b2-registration-coverage.js +48 -0
- package/dist/lanes/b2-registration.js +1187 -0
- package/dist/lanes/businessrule-contract.js +232 -0
- package/dist/lanes/businessrule-coverage.js +16 -0
- package/dist/lanes/businessrule.js +221 -0
- package/dist/lanes/contract-support.js +65 -0
- package/dist/lanes/coverage-declaration.js +9 -0
- package/dist/lanes/datarule-contract.js +155 -0
- package/dist/lanes/datarule-coverage.js +19 -0
- package/dist/lanes/datarule-protocol.js +308 -0
- package/dist/lanes/datarule.js +818 -0
- package/dist/lanes/dictionary-contract.js +78 -0
- package/dist/lanes/dictionary-coverage.js +24 -0
- package/dist/lanes/dictionary.js +235 -0
- package/dist/lanes/environment-contract.js +70 -0
- package/dist/lanes/environment-coverage.js +14 -0
- package/dist/lanes/environment.js +163 -0
- package/dist/lanes/field-contract.js +223 -0
- package/dist/lanes/field-coverage.js +27 -0
- package/dist/lanes/field.js +374 -0
- package/dist/lanes/form-contract.js +97 -0
- package/dist/lanes/form-coverage.js +16 -0
- package/dist/lanes/form.js +185 -0
- package/dist/lanes/lane-ids.js +34 -0
- package/dist/lanes/list-view-contract.js +175 -0
- package/dist/lanes/list-view-coverage.js +20 -0
- package/dist/lanes/list-view-shapes.js +1207 -0
- package/dist/lanes/list-view.js +578 -0
- package/dist/lanes/meta-contract.js +85 -0
- package/dist/lanes/meta.js +255 -0
- package/dist/lanes/model-contract.js +168 -0
- package/dist/lanes/model-coverage.js +20 -0
- package/dist/lanes/model.js +986 -0
- package/dist/lanes/online-js-contract.js +99 -0
- package/dist/lanes/online-js-coverage.js +28 -0
- package/dist/lanes/online-js.js +127 -0
- package/dist/lanes/report-contract.js +144 -0
- package/dist/lanes/report-coverage.js +21 -0
- package/dist/lanes/report.js +476 -0
- package/dist/lanes/rule-graph.js +1846 -0
- package/dist/lanes/rule-lifecycle-contract.js +92 -0
- package/dist/lanes/rule-lifecycle-coverage.js +20 -0
- package/dist/lanes/rule-lifecycle.js +176 -0
- package/dist/lanes/runtime-data-contract.js +264 -0
- package/dist/lanes/runtime-data-coverage.js +25 -0
- package/dist/lanes/runtime-data.js +1054 -0
- package/dist/lanes/workflow-contract.js +223 -0
- package/dist/lanes/workflow-coverage.js +40 -0
- package/dist/lanes/workflow.js +1813 -0
- package/dist/online-js-layout.js +58 -0
- package/dist/online-js-source.js +276 -0
- package/dist/package-tool.js +51 -0
- package/dist/package.js +73 -0
- package/dist/plan.js +73 -0
- package/dist/read.js +144 -0
- package/dist/redact.js +28 -0
- package/dist/rule-support.js +587 -0
- package/dist/runtime-support.js +134 -0
- package/dist/server.js +92 -0
- package/dist/session-manager.js +30 -0
- package/dist/session.js +149 -0
- package/dist/skills.js +112 -0
- package/dist/support.js +98 -0
- package/dist/tool-types.js +127 -0
- package/dist/tools.js +59 -0
- package/dist/usage-log.js +197 -0
- package/dist/wire.js +287 -0
- package/dist/workflow-support.js +99 -0
- package/dist/write-lease.js +26 -0
- package/dist/write-lock.js +109 -0
- package/dist/write.js +176 -0
- package/dist/zip.js +156 -0
- package/docs/tool-surface-map.md +42 -0
- package/package.json +71 -6
- package/skills/omc-acceptance-criteria.md +47 -0
- package/skills/omc-business-configuration.md +257 -0
- package/skills/omc-capabilities.md +197 -0
- package/skills/omc-capability-scouting.md +55 -0
- package/skills/omc-config-draft-review.md +171 -0
- package/skills/omc-five-piece-flow.md +35 -0
- package/skills/omc-glossary.md +86 -0
- package/skills/omc-refusals.md +110 -0
- package/skills/omc-requirement-analysis.md +161 -0
- package/skills/omc-requirement-vocabulary.md +51 -0
- package/skills/omc-start-here.md +82 -0
- package/skills/omc-tool-selection.md +119 -0
- package/skills/omc-write-hazards.md +87 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { APP_COVERAGE } from "./lanes/app-coverage.js";
|
|
2
|
+
import { DICTIONARY_COVERAGE } from "./lanes/dictionary-coverage.js";
|
|
3
|
+
import { B2_COVERAGE } from "./lanes/b2-registration-coverage.js";
|
|
4
|
+
import { BUSINESSRULE_COVERAGE } from "./lanes/businessrule-coverage.js";
|
|
5
|
+
import { ENVIRONMENT_COVERAGE } from "./lanes/environment-coverage.js";
|
|
6
|
+
import { DATARULE_COVERAGE } from "./lanes/datarule-coverage.js";
|
|
7
|
+
import { FIELD_COVERAGE } from "./lanes/field-coverage.js";
|
|
8
|
+
import { FORM_COVERAGE } from "./lanes/form-coverage.js";
|
|
9
|
+
import { LIST_VIEW_COVERAGE } from "./lanes/list-view-coverage.js";
|
|
10
|
+
import { MODEL_COVERAGE } from "./lanes/model-coverage.js";
|
|
11
|
+
import { ONLINE_JS_COVERAGE } from "./lanes/online-js-coverage.js";
|
|
12
|
+
import { RULE_LIFECYCLE_COVERAGE } from "./lanes/rule-lifecycle-coverage.js";
|
|
13
|
+
import { RUNTIME_DATA_COVERAGE } from "./lanes/runtime-data-coverage.js";
|
|
14
|
+
import { WORKFLOW_COVERAGE } from "./lanes/workflow-coverage.js";
|
|
15
|
+
import { REPORT_COVERAGE } from "./lanes/report-coverage.js";
|
|
16
|
+
/**
|
|
17
|
+
* Every lane's structured capability declaration, gathered in one frozen
|
|
18
|
+
* registry. This is the source the runtime coverage gate consults, and the
|
|
19
|
+
* source the manifest generator/validator aligns against.
|
|
20
|
+
*/
|
|
21
|
+
const DECLARATIONS = Object.freeze([
|
|
22
|
+
...ENVIRONMENT_COVERAGE,
|
|
23
|
+
...APP_COVERAGE,
|
|
24
|
+
...DICTIONARY_COVERAGE,
|
|
25
|
+
...MODEL_COVERAGE,
|
|
26
|
+
...FIELD_COVERAGE,
|
|
27
|
+
...DATARULE_COVERAGE,
|
|
28
|
+
...FORM_COVERAGE,
|
|
29
|
+
...BUSINESSRULE_COVERAGE,
|
|
30
|
+
...RULE_LIFECYCLE_COVERAGE,
|
|
31
|
+
...RUNTIME_DATA_COVERAGE,
|
|
32
|
+
...WORKFLOW_COVERAGE,
|
|
33
|
+
...ONLINE_JS_COVERAGE,
|
|
34
|
+
...B2_COVERAGE,
|
|
35
|
+
...LIST_VIEW_COVERAGE,
|
|
36
|
+
...REPORT_COVERAGE,
|
|
37
|
+
]);
|
|
38
|
+
export function laneCoverageDeclarations() {
|
|
39
|
+
return DECLARATIONS;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build-time alignment: every declaration names a real manifest capability,
|
|
43
|
+
* carries evidence, does not double-claim a tool, and any capability that
|
|
44
|
+
* claims tools maps to an executable/partial manifest item.
|
|
45
|
+
*/
|
|
46
|
+
export function assertDeclarationsAlignWithManifest(manifest) {
|
|
47
|
+
const owner = new Map();
|
|
48
|
+
for (const declaration of DECLARATIONS) {
|
|
49
|
+
const where = `${declaration.lane} / "${declaration.capability}"`;
|
|
50
|
+
if (!declaration.capability.trim())
|
|
51
|
+
throw new Error(`coverage declaration ${declaration.lane} requires a capability title`);
|
|
52
|
+
if (!declaration.lane.trim())
|
|
53
|
+
throw new Error(`coverage declaration ${where} requires a lane id`);
|
|
54
|
+
if (declaration.evidence.length === 0)
|
|
55
|
+
throw new Error(`coverage declaration ${where} requires at least one evidence anchor`);
|
|
56
|
+
const item = manifest.items.find((candidate) => candidate.lane === declaration.lane && candidate.capability === declaration.capability);
|
|
57
|
+
if (!item)
|
|
58
|
+
throw new Error(`coverage declaration ${where} has no matching manifest item`);
|
|
59
|
+
if (declaration.tools.length > 0 && item.status !== "executable" && item.status !== "partial") {
|
|
60
|
+
throw new Error(`coverage declaration ${where} claims tools but the manifest item is ${item.status}`);
|
|
61
|
+
}
|
|
62
|
+
const ledgerPaths = new Set((item.evidence ?? []).map((anchor) => anchor.path));
|
|
63
|
+
if (ledgerPaths.size > 0 && !declaration.evidence.some((anchor) => ledgerPaths.has(anchor))) {
|
|
64
|
+
throw new Error(`coverage declaration ${where} evidence anchors are not present in the manifest item's evidence ledger`);
|
|
65
|
+
}
|
|
66
|
+
for (const toolClaim of declaration.tools) {
|
|
67
|
+
if (!toolClaim.scope.trim())
|
|
68
|
+
throw new Error(`coverage declaration ${where} claims ${toolClaim.tool} without a scope`);
|
|
69
|
+
const previous = owner.get(toolClaim.tool);
|
|
70
|
+
if (previous)
|
|
71
|
+
throw new Error(`tool ${toolClaim.tool} is declared twice: ${previous} and ${where}`);
|
|
72
|
+
owner.set(toolClaim.tool, where);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=coverage-registry.js.map
|
package/dist/coverage.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { laneCoverageDeclarations } from "./coverage-registry.js";
|
|
5
|
+
export class CoverageBoundaryError extends Error {
|
|
6
|
+
citation;
|
|
7
|
+
constructor(citation) {
|
|
8
|
+
super(citation.message);
|
|
9
|
+
this.citation = citation;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
let cachedManifest = null;
|
|
13
|
+
export function loadCoverageManifest() {
|
|
14
|
+
if (cachedManifest)
|
|
15
|
+
return cachedManifest;
|
|
16
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..", "coverage");
|
|
17
|
+
cachedManifest = JSON.parse(readFileSync(join(root, "m1-coverage-manifest-v1.json"), "utf8"));
|
|
18
|
+
return cachedManifest;
|
|
19
|
+
}
|
|
20
|
+
export function coverageItemsByLane(manifest) {
|
|
21
|
+
return new Map(manifest.items.map((item) => [item.lane, item]));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Structured allowed-scope index built from the lane declarations joined to
|
|
25
|
+
* the manifest's capability status. The key is `lane\0scope`; each value is
|
|
26
|
+
* the manifest item the claim cites. A lane typo in a declaration surfaces at
|
|
27
|
+
* build time (`assertCoverageConsistency`) and here as a missing manifest item.
|
|
28
|
+
*/
|
|
29
|
+
const allowedCache = new WeakMap();
|
|
30
|
+
function allowedScopes(manifest) {
|
|
31
|
+
const cached = allowedCache.get(manifest);
|
|
32
|
+
if (cached)
|
|
33
|
+
return cached;
|
|
34
|
+
const index = new Map();
|
|
35
|
+
for (const declaration of laneCoverageDeclarations()) {
|
|
36
|
+
const item = manifest.items.find((candidate) => candidate.lane === declaration.lane && candidate.capability === declaration.capability);
|
|
37
|
+
if (!item) {
|
|
38
|
+
throw new Error(`coverage declaration ${declaration.lane} / "${declaration.capability}" has no manifest item; ` +
|
|
39
|
+
"add the capability to coverage/m1-coverage-manifest-v1.json");
|
|
40
|
+
}
|
|
41
|
+
for (const claim of declaration.tools)
|
|
42
|
+
index.set(`${declaration.lane}\u0000${claim.scope}`, item);
|
|
43
|
+
}
|
|
44
|
+
allowedCache.set(manifest, index);
|
|
45
|
+
return index;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Map a tool's declared `(lane, scope)` onto the manifest. A call is allowed
|
|
49
|
+
* only when a declared capability claims that exact pair and its manifest item
|
|
50
|
+
* is executable/partial; blocked, static-only, and unsupported items always
|
|
51
|
+
* reject with a citation.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Ticket 84 — self-correcting lane hints. Users pass capability nicknames
|
|
55
|
+
* ("listview") instead of lane ids ("W1-list-view"); normalize both sides
|
|
56
|
+
* (lowercase, strip the M1/M2/W1/B1/G1/W7/S25 prefix segment) and suggest the
|
|
57
|
+
* closest declared lane.
|
|
58
|
+
*/
|
|
59
|
+
function suggestLaneId(manifest, requested) {
|
|
60
|
+
const normalize = (value) => value.toLowerCase().replace(/^[a-z]\d+-/, "").replace(/-/g, "");
|
|
61
|
+
const target = normalize(requested);
|
|
62
|
+
if (!target)
|
|
63
|
+
return undefined;
|
|
64
|
+
const lanes = [...new Set(manifest.items.map((item) => item.lane))];
|
|
65
|
+
return lanes.find((lane) => normalize(lane) === target || lane.toLowerCase().endsWith(`-${requested.toLowerCase()}`));
|
|
66
|
+
}
|
|
67
|
+
export function assertWithinCoverage(manifest, lane, requestedScope) {
|
|
68
|
+
const claimed = allowedScopes(manifest).get(`${lane}\u0000${requestedScope}`);
|
|
69
|
+
if (claimed)
|
|
70
|
+
return claimed;
|
|
71
|
+
const laneItems = manifest.items.filter((candidate) => candidate.lane === lane);
|
|
72
|
+
if (laneItems.length === 0) {
|
|
73
|
+
const suggestion = suggestLaneId(manifest, lane);
|
|
74
|
+
const validLanes = [...new Set(manifest.items.map((item) => item.lane))].join("、");
|
|
75
|
+
throw new CoverageBoundaryError({
|
|
76
|
+
code: "capability-out-of-coverage",
|
|
77
|
+
lane,
|
|
78
|
+
capability: "<unknown>",
|
|
79
|
+
status: "blocked",
|
|
80
|
+
reason: "lane is not present in the M1 coverage manifest",
|
|
81
|
+
message: `rejected: lane ${lane} is not in coverage manifest ` +
|
|
82
|
+
`${manifest.manifest_type} v${manifest.schema_version}; no live-proven evidence exists` +
|
|
83
|
+
(suggestion ? `;capability 取 lane id,不是能力昵称——你传的 "${lane}" 最接近 "${suggestion}";合法取值:${validLanes};省略 capability 即自动按工具所属 lane 校验` : `;合法 lane 取值:${validLanes}`),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const runtimeItem = laneItems.find((candidate) => candidate.status === "executable" || candidate.status === "partial");
|
|
87
|
+
if (!runtimeItem) {
|
|
88
|
+
throw new CoverageBoundaryError(citationFor(laneItems[0], requestedScope));
|
|
89
|
+
}
|
|
90
|
+
throw new CoverageBoundaryError({
|
|
91
|
+
code: "capability-out-of-coverage",
|
|
92
|
+
lane: runtimeItem.lane,
|
|
93
|
+
capability: runtimeItem.capability,
|
|
94
|
+
status: runtimeItem.status,
|
|
95
|
+
reason: `requested scope "${requestedScope}" is not declared for ${runtimeItem.capability}`,
|
|
96
|
+
message: `rejected: requested scope "${requestedScope}" exceeds live-proven scope of ` +
|
|
97
|
+
`${runtimeItem.capability} (${runtimeItem.status}); it is not a declared scope of lane ${lane}`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function citationFor(item, requestedScope) {
|
|
101
|
+
return {
|
|
102
|
+
code: "capability-out-of-coverage",
|
|
103
|
+
lane: item.lane,
|
|
104
|
+
capability: item.capability,
|
|
105
|
+
status: item.status,
|
|
106
|
+
reason: item.excluded_or_unsupported_reason ??
|
|
107
|
+
`requested scope "${requestedScope}" is not runtime coverage for lane ${item.lane}`,
|
|
108
|
+
message: `rejected: ${item.capability} is ${item.status} in coverage manifest ` +
|
|
109
|
+
`(${item.excluded_or_unsupported_reason ?? "not a runtime coverage claim"}); ` +
|
|
110
|
+
`citing lane ${item.lane}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Version-family compatibility notice.
|
|
115
|
+
*
|
|
116
|
+
* OMC's coverage manifest is anchored on the CloudPivot 8.6 family. Rather than
|
|
117
|
+
* hard-failing every other version, the gate is now advisory: a detected version
|
|
118
|
+
* outside the anchored family is ACCEPTED and this returns the notice to surface
|
|
119
|
+
* (omc is built on 8.6; other products/versions run in compatibility mode and
|
|
120
|
+
* some faces may not apply). Returns undefined when the version is inside the
|
|
121
|
+
* family, or when there is no evidence to judge (the caller keeps its own
|
|
122
|
+
* fail-closed behavior for missing evidence).
|
|
123
|
+
*/
|
|
124
|
+
export function versionFamilyNotice(manifest, detectedVersion) {
|
|
125
|
+
if (detectedVersion.startsWith(manifest.version_family + "."))
|
|
126
|
+
return undefined;
|
|
127
|
+
return (`兼容模式:检测到 CloudPivot ${detectedVersion},不在 OMC 锚定的 ${manifest.version_family} 族` +
|
|
128
|
+
`(锚点 ${manifest.anchor_version})。OMC 基于 8.6 构建,非 8.6 环境按兼容支持,部分能力面可能不适用。`);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { RUNTIME_QUERY_OPERATORS } from "./lanes/runtime-data-contract.js";
|
|
2
|
+
export const SIMPLE_OP_MAP = {
|
|
3
|
+
eq: "Eq",
|
|
4
|
+
equals: "Eq",
|
|
5
|
+
neq: "NotEq",
|
|
6
|
+
notEquals: "NotEq",
|
|
7
|
+
gt: "Gt",
|
|
8
|
+
lt: "Lt",
|
|
9
|
+
gte: "Gte",
|
|
10
|
+
lte: "Lte",
|
|
11
|
+
like: "Like",
|
|
12
|
+
contains: "Like",
|
|
13
|
+
notlike: "NotLike",
|
|
14
|
+
isnull: "IsNull",
|
|
15
|
+
isNull: "IsNull",
|
|
16
|
+
isnotnull: "IsNotNull",
|
|
17
|
+
isNotNull: "IsNotNull",
|
|
18
|
+
in: "In",
|
|
19
|
+
notin: "NotIn",
|
|
20
|
+
between: "Between",
|
|
21
|
+
notbetween: "NotBetween",
|
|
22
|
+
};
|
|
23
|
+
export class FilterDslError extends Error {
|
|
24
|
+
code;
|
|
25
|
+
constructor(code, message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.code = code;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Translate the simplified DSL into the runtime `queryCondition` shape —
|
|
32
|
+
* `List<List<List<FilterModel>>>` consumed by /api/api/runtime/query/list
|
|
33
|
+
* (QueryDataVO.queryCondition). Semantics per decompiled 8.6.26 source
|
|
34
|
+
* (BizObjectFacadeImpl.getFiltersByQueryParam / buildFilter):
|
|
35
|
+
* level 1 = AND across groups, level 2 = OR across and-groups,
|
|
36
|
+
* level 3 = AND across leaves. A 2-level array fails JSON deserialization
|
|
37
|
+
* with errcode 10009 类型转换异常.
|
|
38
|
+
* leaf -> [[[leaf]]]
|
|
39
|
+
* and(k) -> [[[l1..lk]]]
|
|
40
|
+
* or(k) -> [[[l1]..[lk]]]
|
|
41
|
+
* Mixed nesting deeper than one group level is refused (no silent re-binding).
|
|
42
|
+
*/
|
|
43
|
+
export function toQueryCondition(payload) {
|
|
44
|
+
if (payload.rawCondition !== undefined) {
|
|
45
|
+
if (payload.rawCondition === null || typeof payload.rawCondition !== "object" || !Array.isArray(payload.rawCondition))
|
|
46
|
+
throw new FilterDslError("invalid-raw-condition", "rawCondition must be the platform queryCondition array (and>or>and>leaf)");
|
|
47
|
+
return payload.rawCondition;
|
|
48
|
+
}
|
|
49
|
+
if (payload.filterGroup !== undefined)
|
|
50
|
+
return [translateGroup(payload.filterGroup, 0)];
|
|
51
|
+
const clauses = payload.filters ?? (payload.filter === undefined ? [] : [payload.filter]);
|
|
52
|
+
if (clauses.length === 0)
|
|
53
|
+
return undefined;
|
|
54
|
+
return [[clauses.map((clause) => translateClause(clause))]];
|
|
55
|
+
}
|
|
56
|
+
function translateGroup(group, depth) {
|
|
57
|
+
if (depth > 0)
|
|
58
|
+
throw new FilterDslError("filter-depth-exceeded", "nested groups inside filterGroup are not supported by the runtime condition format");
|
|
59
|
+
if (!Array.isArray(group.clauses) || group.clauses.length === 0)
|
|
60
|
+
throw new FilterDslError("empty-group-clauses", "filterGroup.clauses must be non-empty");
|
|
61
|
+
if (group.op === "and")
|
|
62
|
+
return [group.clauses.map((clause) => ("clauses" in clause ? badNested() : translateClause(clause)))];
|
|
63
|
+
return group.clauses.map((clause) => ("clauses" in clause ? badNested() : [translateClause(clause)]));
|
|
64
|
+
}
|
|
65
|
+
function badNested() {
|
|
66
|
+
throw new FilterDslError("filter-depth-exceeded", "nested groups inside filterGroup are not supported by the runtime condition format");
|
|
67
|
+
}
|
|
68
|
+
function translateClause(clause) {
|
|
69
|
+
if (!clause || typeof clause !== "object" || !(clause.op in SIMPLE_OP_MAP))
|
|
70
|
+
throw new FilterDslError("invalid-op", `unsupported filter op '${String(clause?.op)}'`);
|
|
71
|
+
const field = String(clause.field ?? "").trim();
|
|
72
|
+
if (!field)
|
|
73
|
+
throw new FilterDslError("missing-field", "filter field is required");
|
|
74
|
+
return {
|
|
75
|
+
propertyCode: field,
|
|
76
|
+
propertyValue: encodeValue(clause.op, clause.value),
|
|
77
|
+
queryFilterType: SIMPLE_OP_MAP[clause.op],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function encodeValue(op, value) {
|
|
81
|
+
const wireOp = SIMPLE_OP_MAP[op];
|
|
82
|
+
// Encoding itself comes from the shared operator table (the same table the
|
|
83
|
+
// fake evaluator matches through) so compiler and evaluator cannot drift.
|
|
84
|
+
const operator = RUNTIME_QUERY_OPERATORS[wireOp];
|
|
85
|
+
if (!operator)
|
|
86
|
+
throw new FilterDslError("invalid-op", `unsupported filter op '${String(op)}'`);
|
|
87
|
+
if (wireOp !== "IsNull" && wireOp !== "IsNotNull" && (value === null || value === undefined))
|
|
88
|
+
throw new FilterDslError("missing-value", `filter op '${op}' requires a value`);
|
|
89
|
+
return operator.encode(value);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The runtime endpoint requires every leaf filter to carry the field's
|
|
93
|
+
* `propertyType` (int) alongside propertyCode/propertyValue/queryFilterType;
|
|
94
|
+
* without it the query fails with errcode 10009 类型转换异常. The value must
|
|
95
|
+
* come from field metadata — never guessed (cpdocs filter-condition contract).
|
|
96
|
+
*/
|
|
97
|
+
export function injectPropertyTypes(condition, resolve) {
|
|
98
|
+
const missing = new Set();
|
|
99
|
+
const walk = (node) => {
|
|
100
|
+
if (Array.isArray(node))
|
|
101
|
+
return node.map(walk);
|
|
102
|
+
const leaf = node;
|
|
103
|
+
const code = String(leaf?.propertyCode ?? "");
|
|
104
|
+
const type = resolve(code);
|
|
105
|
+
if (type === undefined) {
|
|
106
|
+
missing.add(code);
|
|
107
|
+
return leaf;
|
|
108
|
+
}
|
|
109
|
+
return { ...leaf, propertyType: type };
|
|
110
|
+
};
|
|
111
|
+
const walked = walk(condition);
|
|
112
|
+
return missing.size > 0 ? { ok: false, missing: [...missing].sort() } : { ok: true, condition: walked };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=data-list-filter.js.map
|