@epoint-testtech/ep-stage-skill 0.0.3-alpha.1
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/SKILL.md +27 -0
- package/codex-skill/ep-stage/create-project/SKILL.md +59 -0
- package/codex-skill/ep-stage/glue-test/SKILL.md +258 -0
- package/codex-skill/ep-stage/glue-test/references/crud-pipeline.md +139 -0
- package/codex-skill/ep-stage/glue-test/references/gap-review-protocol.md +43 -0
- package/codex-skill/ep-stage/glue-test/references/harness-principles.md +46 -0
- package/codex-skill/ep-stage/glue-test/scripts/generate-crud-spec.mjs +149 -0
- package/codex-skill/ep-stage/glue-testcase/SKILL.md +31 -0
- package/codex-skill/ep-stage/glue-testcase/examples/observable-testcase.json +40 -0
- package/codex-skill/ep-stage/glue-testcase/references/testcase-schema.md +67 -0
- package/codex-skill/ep-stage/recording-to-glue/SKILL.md +27 -0
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +73 -0
- package/dist/src/capability/coverage-diff.d.ts +34 -0
- package/dist/src/capability/coverage-diff.d.ts.map +1 -0
- package/dist/src/capability/coverage-diff.js +91 -0
- package/dist/src/capability/page-structure.d.ts +31 -0
- package/dist/src/capability/page-structure.d.ts.map +1 -0
- package/dist/src/capability/page-structure.js +50 -0
- package/dist/src/capability/scenario-inference.d.ts +36 -0
- package/dist/src/capability/scenario-inference.d.ts.map +1 -0
- package/dist/src/capability/scenario-inference.js +114 -0
- package/dist/src/cli/generate-crud-contract.d.ts +2 -0
- package/dist/src/cli/generate-crud-contract.d.ts.map +1 -0
- package/dist/src/cli/generate-crud-contract.js +77 -0
- package/dist/src/cli/generate-playwright-tests.d.ts +30 -0
- package/dist/src/cli/generate-playwright-tests.d.ts.map +1 -0
- package/dist/src/cli/generate-playwright-tests.js +81 -0
- package/dist/src/cli/run-gap-pipeline.d.ts +256 -0
- package/dist/src/cli/run-gap-pipeline.d.ts.map +1 -0
- package/dist/src/cli/run-gap-pipeline.js +1468 -0
- package/dist/src/context/stage-context.d.ts +63 -0
- package/dist/src/context/stage-context.d.ts.map +1 -0
- package/dist/src/context/stage-context.js +297 -0
- package/dist/src/contracts/crud-business-module.d.ts +645 -0
- package/dist/src/contracts/crud-business-module.d.ts.map +1 -0
- package/dist/src/contracts/crud-business-module.js +1 -0
- package/dist/src/contracts/gap-inference.d.ts +213 -0
- package/dist/src/contracts/gap-inference.d.ts.map +1 -0
- package/dist/src/contracts/gap-inference.js +11 -0
- package/dist/src/contracts/observable-chain.d.ts +250 -0
- package/dist/src/contracts/observable-chain.d.ts.map +1 -0
- package/dist/src/contracts/observable-chain.js +1 -0
- package/dist/src/extractors/code-list.d.ts +40 -0
- package/dist/src/extractors/code-list.d.ts.map +1 -0
- package/dist/src/extractors/code-list.js +225 -0
- package/dist/src/extractors/html-page.d.ts +67 -0
- package/dist/src/extractors/html-page.d.ts.map +1 -0
- package/dist/src/extractors/html-page.js +195 -0
- package/dist/src/extractors/java-action.d.ts +8 -0
- package/dist/src/extractors/java-action.d.ts.map +1 -0
- package/dist/src/extractors/java-action.js +53 -0
- package/dist/src/extractors/spec-yaml.d.ts +28 -0
- package/dist/src/extractors/spec-yaml.d.ts.map +1 -0
- package/dist/src/extractors/spec-yaml.js +29 -0
- package/dist/src/gap-planner/action-candidates.d.ts +9 -0
- package/dist/src/gap-planner/action-candidates.d.ts.map +1 -0
- package/dist/src/gap-planner/action-candidates.js +66 -0
- package/dist/src/gap-planner/list-gap-workflows.d.ts +17 -0
- package/dist/src/gap-planner/list-gap-workflows.d.ts.map +1 -0
- package/dist/src/gap-planner/list-gap-workflows.js +47 -0
- package/dist/src/gap-planner/plan-agent-workflows.d.ts +26 -0
- package/dist/src/gap-planner/plan-agent-workflows.d.ts.map +1 -0
- package/dist/src/gap-planner/plan-agent-workflows.js +116 -0
- package/dist/src/gap-planner/skeleton-coverage.d.ts +9 -0
- package/dist/src/gap-planner/skeleton-coverage.d.ts.map +1 -0
- package/dist/src/gap-planner/skeleton-coverage.js +41 -0
- package/dist/src/gap-planner/stable-id.d.ts +16 -0
- package/dist/src/gap-planner/stable-id.d.ts.map +1 -0
- package/dist/src/gap-planner/stable-id.js +19 -0
- package/dist/src/generalization/generalization-eval.d.ts +71 -0
- package/dist/src/generalization/generalization-eval.d.ts.map +1 -0
- package/dist/src/generalization/generalization-eval.js +53 -0
- package/dist/src/generators/agent-inferred-workflow-script.d.ts +22 -0
- package/dist/src/generators/agent-inferred-workflow-script.d.ts.map +1 -0
- package/dist/src/generators/agent-inferred-workflow-script.js +230 -0
- package/dist/src/generators/stage-skeleton-script.d.ts +107 -0
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -0
- package/dist/src/generators/stage-skeleton-script.js +607 -0
- package/dist/src/index.d.ts +52 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +26 -0
- package/dist/src/material/material-inventory.d.ts +92 -0
- package/dist/src/material/material-inventory.d.ts.map +1 -0
- package/dist/src/material/material-inventory.js +191 -0
- package/dist/src/normalizers/crud-contract.d.ts +107 -0
- package/dist/src/normalizers/crud-contract.d.ts.map +1 -0
- package/dist/src/normalizers/crud-contract.js +1068 -0
- package/dist/src/testcase/testcase-generator.d.ts +43 -0
- package/dist/src/testcase/testcase-generator.d.ts.map +1 -0
- package/dist/src/testcase/testcase-generator.js +152 -0
- package/dist/src/testcase/testcase-skeleton.d.ts +91 -0
- package/dist/src/testcase/testcase-skeleton.d.ts.map +1 -0
- package/dist/src/testcase/testcase-skeleton.js +121 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts +11 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts.map +1 -0
- package/dist/src/testcase/testcase-spec-assembly.js +24 -0
- package/dist/src/trace/review-summary.d.ts +17 -0
- package/dist/src/trace/review-summary.d.ts.map +1 -0
- package/dist/src/trace/review-summary.js +34 -0
- package/dist/src/trace/trace-writer.d.ts +17 -0
- package/dist/src/trace/trace-writer.d.ts.map +1 -0
- package/dist/src/trace/trace-writer.js +81 -0
- package/dist/test/crud-contract.test.d.ts +2 -0
- package/dist/test/crud-contract.test.d.ts.map +1 -0
- package/dist/test/crud-contract.test.js +819 -0
- package/dist/test/gap-inference.test.d.ts +2 -0
- package/dist/test/gap-inference.test.d.ts.map +1 -0
- package/dist/test/gap-inference.test.js +597 -0
- package/dist/test/generalization.test.d.ts +2 -0
- package/dist/test/generalization.test.d.ts.map +1 -0
- package/dist/test/generalization.test.js +73 -0
- package/dist/test/material-inventory.test.d.ts +2 -0
- package/dist/test/material-inventory.test.d.ts.map +1 -0
- package/dist/test/material-inventory.test.js +141 -0
- package/dist/test/observable-chain.test.d.ts +2 -0
- package/dist/test/observable-chain.test.d.ts.map +1 -0
- package/dist/test/observable-chain.test.js +123 -0
- package/dist/test/observable-pipeline.test.d.ts +2 -0
- package/dist/test/observable-pipeline.test.d.ts.map +1 -0
- package/dist/test/observable-pipeline.test.js +461 -0
- package/dist/test/page-structure.test.d.ts +2 -0
- package/dist/test/page-structure.test.d.ts.map +1 -0
- package/dist/test/page-structure.test.js +45 -0
- package/dist/test/scenario-inference.test.d.ts +2 -0
- package/dist/test/scenario-inference.test.d.ts.map +1 -0
- package/dist/test/scenario-inference.test.js +73 -0
- package/dist/test/stage-context.test.d.ts +2 -0
- package/dist/test/stage-context.test.d.ts.map +1 -0
- package/dist/test/stage-context.test.js +263 -0
- package/dist/test/testcase-generator.test.d.ts +2 -0
- package/dist/test/testcase-generator.test.d.ts.map +1 -0
- package/dist/test/testcase-generator.test.js +276 -0
- package/dist/test/testcase-skeleton.test.d.ts +2 -0
- package/dist/test/testcase-skeleton.test.d.ts.map +1 -0
- package/dist/test/testcase-skeleton.test.js +185 -0
- package/dist/test/testcase-spec-assembly.test.d.ts +2 -0
- package/dist/test/testcase-spec-assembly.test.d.ts.map +1 -0
- package/dist/test/testcase-spec-assembly.test.js +105 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +7 -0
- package/docs/README.md +134 -0
- package/docs/mvp-usage-guide.md +298 -0
- package/examples/schemeresource-observable-docs/schemeresource.context.md +20 -0
- package/examples/schemeresource.module-hints.json +38 -0
- package/examples/schemeresource.observable.code_list.md +37 -0
- package/examples/zwplace-observable-docs/zwplace.context.md +16 -0
- package/examples/zwplace-placecategory-validation.json +29 -0
- package/examples/zwplace.module-hints.json +69 -0
- package/examples/zwplace.observable.code_list.md +37 -0
- package/package.json +38 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { extractHtmlPage } from './extractors/html-page.js';
|
|
2
|
+
export { extractSpecYaml } from './extractors/spec-yaml.js';
|
|
3
|
+
export { extractCodeListSummary } from './extractors/code-list.js';
|
|
4
|
+
export { extractJavaAction } from './extractors/java-action.js';
|
|
5
|
+
export { buildCrudBusinessModuleContract } from './normalizers/crud-contract.js';
|
|
6
|
+
export { generateStageSkeletonCrudSpec, mapContractToStageSkeletonCrudSlots, renderStageSkeletonCrudSlots } from './generators/stage-skeleton-script.js';
|
|
7
|
+
export { createTraceWriter, } from './trace/trace-writer.js';
|
|
8
|
+
export { readStageContext, resolveStageContext, writeProjectIndex, } from './context/stage-context.js';
|
|
9
|
+
export { renderReviewSummary, } from './trace/review-summary.js';
|
|
10
|
+
export { collectActionCandidates, } from './gap-planner/action-candidates.js';
|
|
11
|
+
export { createSkeletonCoverage, } from './gap-planner/skeleton-coverage.js';
|
|
12
|
+
export { stableActionHash, stableActionId, stableWorkflowId, } from './gap-planner/stable-id.js';
|
|
13
|
+
export { planAgentInferredWorkflows, } from './gap-planner/plan-agent-workflows.js';
|
|
14
|
+
export { listGapWorkflows, } from './gap-planner/list-gap-workflows.js';
|
|
15
|
+
export { appendAgentWorkflowTest, renderAgentWorkflowTest, } from './generators/agent-inferred-workflow-script.js';
|
|
16
|
+
export { resolveMaterialInventory, } from './material/material-inventory.js';
|
|
17
|
+
export { summarizePageStructure, } from './capability/page-structure.js';
|
|
18
|
+
export { applyScenarioHumanCorrection, inferPageScenarios, } from './capability/scenario-inference.js';
|
|
19
|
+
export { createCoverageDiff, } from './capability/coverage-diff.js';
|
|
20
|
+
export { generateGlueTestcases, } from './testcase/testcase-generator.js';
|
|
21
|
+
export { mapContractToCrudTestcaseSlots, renderGlueTestcaseSkeleton, selectTestcaseSkeletonByScenario, } from './testcase/testcase-skeleton.js';
|
|
22
|
+
export { validateGlueTestcaseDocumentForSpecAssembly, } from './testcase/testcase-spec-assembly.js';
|
|
23
|
+
export { applyCodeListWriteBack, collectCodeListMaterialRefsFromPath, isProtectedKnowledgeProjectPath, parseObservablePipelineArgs, resolveMenuRouteForPipeline, } from './cli/run-gap-pipeline.js';
|
|
24
|
+
export { createRuntimeFailureSummary, extractLoginSystemUrlFromEnvFile, parseRuntimeSummaryOutput, runtimeSummaryToTrace, } from './cli/run-gap-pipeline.js';
|
|
25
|
+
export { glueReportToTrace, glueSpecAssemblyToTrace, playwrightExecutionToTrace, } from './cli/run-gap-pipeline.js';
|
|
26
|
+
export { compareObservableRuns, summarizeGeneralizationRun, } from './generalization/generalization-eval.js';
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ExtractedCodeListSummary } from '../extractors/code-list.js';
|
|
2
|
+
import type { ObservableGate, ObservableStagePayload } from '../contracts/observable-chain.js';
|
|
3
|
+
import type { StageContext } from '../context/stage-context.js';
|
|
4
|
+
/**
|
|
5
|
+
* 单个物料解析槽位的状态。
|
|
6
|
+
*
|
|
7
|
+
* - resolved:已唯一定位,下游可直接消费。
|
|
8
|
+
* - candidate:存在多个候选,需人工确认。
|
|
9
|
+
* - missing:物料缺失或无法从 code_list.md 钻探出来。
|
|
10
|
+
*/
|
|
11
|
+
export type MaterialResolution = {
|
|
12
|
+
status: 'resolved';
|
|
13
|
+
path: string;
|
|
14
|
+
evidence: string;
|
|
15
|
+
} | {
|
|
16
|
+
status: 'candidate';
|
|
17
|
+
candidates: string[];
|
|
18
|
+
evidence: string;
|
|
19
|
+
} | {
|
|
20
|
+
status: 'missing';
|
|
21
|
+
reason: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 单个标量解析槽位的状态(如 moduleId、menu)。
|
|
25
|
+
*/
|
|
26
|
+
export type ValueResolution = {
|
|
27
|
+
status: 'resolved';
|
|
28
|
+
value: string;
|
|
29
|
+
evidence: string;
|
|
30
|
+
} | {
|
|
31
|
+
status: 'candidate';
|
|
32
|
+
candidates: string[];
|
|
33
|
+
evidence: string;
|
|
34
|
+
} | {
|
|
35
|
+
status: 'missing';
|
|
36
|
+
reason: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* 将 code_list.md 物料解析为既有契约生成链路所需输入的结果。
|
|
40
|
+
*/
|
|
41
|
+
export type ResolvedMaterialInventory = {
|
|
42
|
+
moduleId: ValueResolution;
|
|
43
|
+
docsDir: MaterialResolution;
|
|
44
|
+
webappDir: MaterialResolution;
|
|
45
|
+
javaActionsDir: MaterialResolution;
|
|
46
|
+
hintsPath: MaterialResolution;
|
|
47
|
+
menu: ValueResolution;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* `resolveMaterialInventory` 的入参。
|
|
51
|
+
*
|
|
52
|
+
* @property codeListPath - code_list.md 绝对路径。
|
|
53
|
+
* @property codeList - 已经过 extractCodeListSummary 钻探的物料摘要。
|
|
54
|
+
* @property stageContext - 可选,stage-context.md 解析结果。
|
|
55
|
+
* @property debugOverrides - 调试覆盖参数,始终优先于自动解析。
|
|
56
|
+
*/
|
|
57
|
+
export type ResolveMaterialInventoryInput = {
|
|
58
|
+
codeListPath: string;
|
|
59
|
+
codeList: ExtractedCodeListSummary;
|
|
60
|
+
stageContext?: StageContext;
|
|
61
|
+
debugOverrides: {
|
|
62
|
+
moduleId?: string;
|
|
63
|
+
docs?: string;
|
|
64
|
+
webapp?: string;
|
|
65
|
+
javaActions?: string;
|
|
66
|
+
hints?: string;
|
|
67
|
+
menu?: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* `resolveMaterialInventory` 的产物。
|
|
72
|
+
*
|
|
73
|
+
* @property resolvedInputs - 各槽位解析结果,供下游契约生成消费。
|
|
74
|
+
* @property trace - 同构的 material-inventory 阶段 trace payload。
|
|
75
|
+
* @property gate - 阶段门禁结论,供 CLI 决定是否继续。
|
|
76
|
+
*/
|
|
77
|
+
export type ResolveMaterialInventoryResult = {
|
|
78
|
+
resolvedInputs: ResolvedMaterialInventory;
|
|
79
|
+
trace: ObservableStagePayload;
|
|
80
|
+
gate: ObservableGate;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* 把 code_list.md 钻探出的 `materialRefs` 解析为既有契约生成链路所需的输入槽位。
|
|
84
|
+
*
|
|
85
|
+
* 解析优先级:调试覆盖参数 → 物料钻探唯一候选 → 多候选标记 candidate → 缺失。
|
|
86
|
+
* docsDir 缺失允许下游 fallback 为低置信 spec;webapp / javaActions 缺失则停在 material gate。
|
|
87
|
+
*
|
|
88
|
+
* @param input - 物料解析所需上下文。
|
|
89
|
+
* @returns 解析结果 + 同构 trace + 门禁结论。
|
|
90
|
+
*/
|
|
91
|
+
export declare function resolveMaterialInventory(input: ResolveMaterialInventoryInput): ResolveMaterialInventoryResult;
|
|
92
|
+
//# sourceMappingURL=material-inventory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"material-inventory.d.ts","sourceRoot":"","sources":["../../../src/material/material-inventory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAwB,MAAM,4BAA4B,CAAC;AACjG,OAAO,KAAK,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,cAAc,EAAE,kBAAkB,CAAC;IACnC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,IAAI,EAAE,eAAe,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,wBAAwB,CAAC;IACnC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,cAAc,EAAE;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,cAAc,EAAE,yBAAyB,CAAC;IAC1C,KAAK,EAAE,sBAAsB,CAAC;IAC9B,IAAI,EAAE,cAAc,CAAC;CACtB,CAAC;AAqHF;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,6BAA6B,GACnC,8BAA8B,CAmEhC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* 字符串数组去重,保留首次出现顺序。
|
|
4
|
+
*/
|
|
5
|
+
function unique(values) {
|
|
6
|
+
return Array.from(new Set(values));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 从已存在的物料中收集指定 kind 的父目录候选列表。
|
|
10
|
+
*/
|
|
11
|
+
function parentDirs(refs, kind) {
|
|
12
|
+
return unique(refs
|
|
13
|
+
.filter((ref) => ref.kind === kind && ref.exists)
|
|
14
|
+
.map((ref) => path.dirname(ref.path)));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 解析目录槽位:调试覆盖 > 唯一候选 > 多候选 > 缺失。
|
|
18
|
+
*/
|
|
19
|
+
function resolveDir(explicitPath, candidates, label) {
|
|
20
|
+
if (explicitPath) {
|
|
21
|
+
return { status: 'resolved', path: explicitPath, evidence: `${label} 来自调试覆盖参数` };
|
|
22
|
+
}
|
|
23
|
+
if (candidates.length === 1) {
|
|
24
|
+
return { status: 'resolved', path: candidates[0], evidence: `${label} 来自 code_list.md 物料路径` };
|
|
25
|
+
}
|
|
26
|
+
if (candidates.length > 1) {
|
|
27
|
+
return {
|
|
28
|
+
status: 'candidate',
|
|
29
|
+
candidates,
|
|
30
|
+
evidence: `${label} 存在多个候选,需要人工确认`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return { status: 'missing', reason: `无法从 code_list.md 解析 ${label}` };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 解析文件槽位:调试覆盖 > 唯一候选 > 多候选 > 缺失。
|
|
37
|
+
*/
|
|
38
|
+
function resolveFile(explicitPath, candidates, label) {
|
|
39
|
+
if (explicitPath) {
|
|
40
|
+
return { status: 'resolved', path: explicitPath, evidence: `${label} 来自调试覆盖参数` };
|
|
41
|
+
}
|
|
42
|
+
if (candidates.length === 1) {
|
|
43
|
+
return { status: 'resolved', path: candidates[0], evidence: `${label} 来自 code_list.md 物料路径` };
|
|
44
|
+
}
|
|
45
|
+
if (candidates.length > 1) {
|
|
46
|
+
return {
|
|
47
|
+
status: 'candidate',
|
|
48
|
+
candidates,
|
|
49
|
+
evidence: `${label} 存在多个候选,需要人工确认`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return { status: 'missing', reason: `未提供 ${label}` };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 解析 moduleId:调试覆盖 > HTML 目录名 > code_list 标题稳定化 > 缺失。
|
|
56
|
+
*/
|
|
57
|
+
function resolveModuleId(input) {
|
|
58
|
+
if (input.debugOverrides.moduleId) {
|
|
59
|
+
return {
|
|
60
|
+
status: 'resolved',
|
|
61
|
+
value: input.debugOverrides.moduleId,
|
|
62
|
+
evidence: 'moduleId 来自调试覆盖参数',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const htmlDirs = parentDirs(input.codeList.materialRefs, 'html');
|
|
66
|
+
const moduleId = htmlDirs[0] ? path.basename(htmlDirs[0]) : undefined;
|
|
67
|
+
if (moduleId) {
|
|
68
|
+
return { status: 'resolved', value: moduleId, evidence: 'moduleId 来自 HTML 目录名' };
|
|
69
|
+
}
|
|
70
|
+
if (input.codeList.moduleLabel) {
|
|
71
|
+
return {
|
|
72
|
+
status: 'resolved',
|
|
73
|
+
value: input.codeList.moduleLabel.replace(/\s+/g, '-'),
|
|
74
|
+
evidence: 'moduleId 来自 code_list 标题稳定化',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return { status: 'missing', reason: '无法解析 moduleId' };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 根据已解析输入决定阶段门禁结论。
|
|
81
|
+
*
|
|
82
|
+
* 阻断条件:moduleId 缺失、webappDir 或 javaActionsDir 未达 resolved。
|
|
83
|
+
* 其它情况(docsDir 可空 fallback、hintsPath 可缺失但限定 candidate、menu 可缺失但禁入 spec assembly/runtime)
|
|
84
|
+
* 不在此处阻断,留给下游阶段按需提示。
|
|
85
|
+
*/
|
|
86
|
+
function buildGate(inputs) {
|
|
87
|
+
const blocking = [
|
|
88
|
+
inputs.moduleId.status === 'missing' ? 'moduleId' : undefined,
|
|
89
|
+
inputs.webappDir.status !== 'resolved' ? 'webappDir' : undefined,
|
|
90
|
+
inputs.javaActionsDir.status !== 'resolved' ? 'javaActionsDir' : undefined,
|
|
91
|
+
].filter((item) => Boolean(item));
|
|
92
|
+
if (blocking.length > 0) {
|
|
93
|
+
return {
|
|
94
|
+
status: 'needs_review',
|
|
95
|
+
reason: `物料输入缺失或不唯一:${blocking.join(', ')}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { status: 'confirmed', confirmedBy: 'policy', reason: '契约生成关键输入已解析' };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 把 code_list.md 钻探出的 `materialRefs` 解析为既有契约生成链路所需的输入槽位。
|
|
102
|
+
*
|
|
103
|
+
* 解析优先级:调试覆盖参数 → 物料钻探唯一候选 → 多候选标记 candidate → 缺失。
|
|
104
|
+
* docsDir 缺失允许下游 fallback 为低置信 spec;webapp / javaActions 缺失则停在 material gate。
|
|
105
|
+
*
|
|
106
|
+
* @param input - 物料解析所需上下文。
|
|
107
|
+
* @returns 解析结果 + 同构 trace + 门禁结论。
|
|
108
|
+
*/
|
|
109
|
+
export function resolveMaterialInventory(input) {
|
|
110
|
+
const refs = input.codeList.materialRefs;
|
|
111
|
+
const specDirs = parentDirs(refs, 'spec').filter((dir) => path.basename(dir) !== '_docs');
|
|
112
|
+
const htmlDirs = parentDirs(refs, 'html');
|
|
113
|
+
const javaDirs = parentDirs(refs, 'java_action');
|
|
114
|
+
const hintFiles = refs
|
|
115
|
+
.filter((ref) => ref.kind === 'module_hints' && ref.exists)
|
|
116
|
+
.map((ref) => ref.path);
|
|
117
|
+
const resolvedInputs = {
|
|
118
|
+
moduleId: resolveModuleId(input),
|
|
119
|
+
docsDir: resolveDir(input.debugOverrides.docs, specDirs, 'docsDir'),
|
|
120
|
+
webappDir: resolveDir(input.debugOverrides.webapp, htmlDirs, 'webappDir'),
|
|
121
|
+
javaActionsDir: resolveDir(input.debugOverrides.javaActions, javaDirs, 'javaActionsDir'),
|
|
122
|
+
hintsPath: resolveFile(input.debugOverrides.hints, hintFiles, 'hintsPath'),
|
|
123
|
+
menu: resolveMenu(input),
|
|
124
|
+
};
|
|
125
|
+
const gate = buildGate(resolvedInputs);
|
|
126
|
+
return {
|
|
127
|
+
resolvedInputs,
|
|
128
|
+
gate,
|
|
129
|
+
trace: {
|
|
130
|
+
stage: 'material-inventory',
|
|
131
|
+
stageLabel: '物料清单追踪',
|
|
132
|
+
inputs: [{ kind: 'code_list', path: input.codeListPath }],
|
|
133
|
+
outputs: refs.map((ref) => ({
|
|
134
|
+
kind: ref.kind,
|
|
135
|
+
path: ref.path,
|
|
136
|
+
description: ref.exists ? 'exists' : 'missing',
|
|
137
|
+
})),
|
|
138
|
+
reasoningSummary: {
|
|
139
|
+
conclusion: gate.status === 'confirmed'
|
|
140
|
+
? '契约生成关键输入已从 code_list.md 解析。'
|
|
141
|
+
: gate.reason,
|
|
142
|
+
evidenceChain: [
|
|
143
|
+
...(input.codeList.knowledgeRoot
|
|
144
|
+
? [{
|
|
145
|
+
source: 'code_list',
|
|
146
|
+
path: input.codeListPath,
|
|
147
|
+
text: `knowledgeRoot=${input.codeList.knowledgeRoot} source=${input.codeList.knowledgeRootSource}`,
|
|
148
|
+
}]
|
|
149
|
+
: []),
|
|
150
|
+
...(input.codeList.menu
|
|
151
|
+
? [{
|
|
152
|
+
source: 'code_list',
|
|
153
|
+
path: input.codeListPath,
|
|
154
|
+
text: `menu=${input.codeList.menu}`,
|
|
155
|
+
}]
|
|
156
|
+
: []),
|
|
157
|
+
...refs.map((ref) => ({
|
|
158
|
+
source: 'code_list',
|
|
159
|
+
path: ref.path,
|
|
160
|
+
text: `${ref.kind}:${ref.rawPath}`,
|
|
161
|
+
})),
|
|
162
|
+
],
|
|
163
|
+
alternatives: ['debug override', 'stage-context', 'code_list material refs'],
|
|
164
|
+
confidence: gate.status === 'confirmed' ? 'high' : 'medium',
|
|
165
|
+
risks: gate.status === 'confirmed' ? [] : [gate.reason],
|
|
166
|
+
needsHumanReview: gate.status !== 'confirmed',
|
|
167
|
+
},
|
|
168
|
+
candidateCount: refs.length,
|
|
169
|
+
unresolvedCount: gate.status === 'confirmed' ? 0 : 1,
|
|
170
|
+
gate,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 解析菜单路由,调试覆盖优先,其次使用 code_list.md 扎口字段。
|
|
176
|
+
*
|
|
177
|
+
* @param input - 物料解析输入。
|
|
178
|
+
* @returns 菜单路由解析结果。
|
|
179
|
+
*/
|
|
180
|
+
function resolveMenu(input) {
|
|
181
|
+
if (input.debugOverrides.menu) {
|
|
182
|
+
return { status: 'resolved', value: input.debugOverrides.menu, evidence: 'menu 来自调试覆盖参数' };
|
|
183
|
+
}
|
|
184
|
+
if (input.codeList.menu) {
|
|
185
|
+
return { status: 'resolved', value: input.codeList.menu, evidence: 'menu 来自 code_list.md 扎口字段' };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
status: 'missing',
|
|
189
|
+
reason: '未提供 menu;可继续 testcase,但不得进入 spec assembly/runtime',
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRUD 业务模块契约 Normalizer
|
|
3
|
+
*
|
|
4
|
+
* 核心职责:
|
|
5
|
+
* - 将上游 extractor 提取的结构化信息归一化为 crud-business-module/v1 契约
|
|
6
|
+
* - 消费 ModuleHints 显式输入的测试策略(dataKey、buttonAliases、deletePolicy、assertionPolicy 等)
|
|
7
|
+
* - 优先使用结构化证据,证据不足时输出 unresolvedSlots
|
|
8
|
+
* - 不猜测、不编造,确保契约的每个字段都有来源溯源
|
|
9
|
+
*
|
|
10
|
+
* 设计原则:
|
|
11
|
+
* - 确定性优先:能从源码确定的值直接确定,不能确定的通过 hints 或 unresolvedSlots 处理
|
|
12
|
+
* - 来源溯源:每个字段都带有 sources 数组,记录信息来源(html/spec/java_action/human_required)
|
|
13
|
+
* - 策略隔离:测试策略(如 dataKey 选择、删除预期)与结构提取分离,通过 hints 传入
|
|
14
|
+
*
|
|
15
|
+
* 修复历史(Code Review 问题闭环):
|
|
16
|
+
* - overrideFields 丢失 strategy/value → 新增 OverrideFieldContract,透传 strategy/value
|
|
17
|
+
* - assertionPolicy 定义未消费 → buildAssertions 接收 hints,afterCreate/afterDelete 策略生效
|
|
18
|
+
* - deletePolicy 输入-输出不对称 → 将 prepare_deletable_draft_then_delete 提升为正式成员
|
|
19
|
+
* - grid 精细分类未消费 → GridContract 增加 selectionColumn/indexColumn/rowActions
|
|
20
|
+
* - findButton 单标签匹配 → 支持别名列表,searchFlow 消费 buttonAliases
|
|
21
|
+
* - '不可删除' 硬编码 → 提取为 BLOCK_DELETE_KEYWORDS 常量
|
|
22
|
+
*/
|
|
23
|
+
import type { CrudBusinessModuleContract, ModuleHints } from '../contracts/crud-business-module.js';
|
|
24
|
+
import type { ExtractedCodeListSummary } from '../extractors/code-list.js';
|
|
25
|
+
import type { ExtractedHtmlPage } from '../extractors/html-page.js';
|
|
26
|
+
import type { ExtractedJavaAction } from '../extractors/java-action.js';
|
|
27
|
+
import type { ExtractedSpecYaml } from '../extractors/spec-yaml.js';
|
|
28
|
+
/**
|
|
29
|
+
* 按钮标签配置
|
|
30
|
+
*
|
|
31
|
+
* 定义 CRUD 操作中各个按钮的显示文本。
|
|
32
|
+
* 支持通过 ModuleHints.buttonAliases 进行覆盖。
|
|
33
|
+
*
|
|
34
|
+
* @property create - 新增按钮文本(如"新增场所信息管理")
|
|
35
|
+
* @property saveAndClose - 保存并关闭按钮文本
|
|
36
|
+
* @property delete - 删除按钮文本
|
|
37
|
+
* @property search - 搜索按钮文本
|
|
38
|
+
* @property edit - 修改/编辑按钮文本
|
|
39
|
+
*/
|
|
40
|
+
export type ButtonLabelConfig = {
|
|
41
|
+
create: string;
|
|
42
|
+
saveAndClose: string;
|
|
43
|
+
delete: string;
|
|
44
|
+
search: string;
|
|
45
|
+
edit: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* 构建 CRUD 契约的输入参数
|
|
49
|
+
*
|
|
50
|
+
* 包含所有 extractor 提取的原始数据和可选的测试策略 hints。
|
|
51
|
+
*
|
|
52
|
+
* @property moduleId - 模块唯一标识(如 'zwplace')
|
|
53
|
+
* @property spec - spec.yaml 提取的结构化信息
|
|
54
|
+
* @property codeList - code_list.md 提取的代码清单摘要
|
|
55
|
+
* @property pages - HTML 页面提取的结构化信息数组
|
|
56
|
+
* @property actions - Java Action 提取的结构化信息数组
|
|
57
|
+
* @property buttonLabels - 可选的按钮标签覆盖
|
|
58
|
+
* @property dataKeyField - 可选的数据主键字段覆盖
|
|
59
|
+
* @property hints - 可选的模块测试策略 hints
|
|
60
|
+
*/
|
|
61
|
+
export type BuildCrudContractInput = {
|
|
62
|
+
moduleId: string;
|
|
63
|
+
spec: ExtractedSpecYaml;
|
|
64
|
+
codeList: ExtractedCodeListSummary;
|
|
65
|
+
pages: ExtractedHtmlPage[];
|
|
66
|
+
actions: ExtractedJavaAction[];
|
|
67
|
+
buttonLabels?: Partial<ButtonLabelConfig>;
|
|
68
|
+
dataKeyField?: string;
|
|
69
|
+
hints?: ModuleHints;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* 构建 CRUD 业务模块契约(主入口函数)
|
|
73
|
+
*
|
|
74
|
+
* 将上游 extractor 提取的结构化信息和可选的测试策略 hints
|
|
75
|
+
* 归一化为 crud-business-module/v1 契约。
|
|
76
|
+
*
|
|
77
|
+
* 处理流程:
|
|
78
|
+
* 1. 解析模块标签和按钮标签配置
|
|
79
|
+
* 2. 解析数据主键字段
|
|
80
|
+
* 3. 构建页面契约(list/add/edit/detail)
|
|
81
|
+
* 4. 构建流程契约(create/search/update/delete)
|
|
82
|
+
* 5. 构建断言和业务规则契约
|
|
83
|
+
* 6. 检查未解决槽位
|
|
84
|
+
*
|
|
85
|
+
* @param input - 构建契约的输入参数
|
|
86
|
+
* @returns 完整的 CRUD 业务模块契约
|
|
87
|
+
* @throws 当缺少列表页时抛出错误
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* import { buildCrudBusinessModuleContract } from './normalizers/crud-contract.js';
|
|
92
|
+
*
|
|
93
|
+
* const contract = buildCrudBusinessModuleContract({
|
|
94
|
+
* moduleId: 'zwplace',
|
|
95
|
+
* spec: extractedSpec,
|
|
96
|
+
* codeList: extractedCodeList,
|
|
97
|
+
* pages: extractedPages,
|
|
98
|
+
* actions: extractedActions,
|
|
99
|
+
* hints: {
|
|
100
|
+
* dataKey: { selectedField: 'placename', generationStrategy: 'timestamp_prefix' },
|
|
101
|
+
* deletePolicy: 'blocked_by_business_rule'
|
|
102
|
+
* }
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildCrudBusinessModuleContract(input: BuildCrudContractInput): CrudBusinessModuleContract;
|
|
107
|
+
//# sourceMappingURL=crud-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud-contract.d.ts","sourceRoot":"","sources":["../../../src/normalizers/crud-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAIV,0BAA0B,EAQ1B,WAAW,EASZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,KAAK,EAAuB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,wBAAwB,CAAC;IACnC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAuhCF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,sBAAsB,GAAG,0BAA0B,CAmDzG"}
|