@epoint-testtech/ep-stage-skill 0.0.4-alpha.0 → 0.0.5
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 -27
- package/codex-skill/ep-stage/glue-create-project/SKILL.md +223 -186
- package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +275 -199
- package/codex-skill/ep-stage/glue-generate-testcase/examples/observable-testcase.json +40 -40
- package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-schema.md +95 -112
- package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-tpl.md +72 -0
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +292 -249
- package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +30 -0
- package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +132 -145
- package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +44 -43
- package/codex-skill/ep-stage/glue-run-test/references/harness-principles.md +46 -46
- package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +166 -0
- package/codex-skill/ep-stage/glue-run-test/scripts/extract-page-elements-eval.mjs +233 -0
- package/codex-skill/ep-stage/glue-run-test/scripts/generate-crud-spec.mjs +149 -149
- package/codex-skill/ep-stage/page-element-scan/SKILL.md +91 -0
- package/codex-skill/ep-stage/page-element-scan/evals/evals.json +37 -0
- package/codex-skill/ep-stage/page-element-scan/evals/fixtures/sample-list-page.html +85 -0
- package/codex-skill/ep-stage/page-element-scan/references/pagination-controls.md +153 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements-eval.mjs +233 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements.mjs +298 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/scan-page.mjs +749 -0
- package/codex-skill/ep-stage/recording-to-glue/SKILL.md +28 -28
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +98 -95
- package/dist/src/cli/generate-testcase.d.ts +18 -51
- package/dist/src/cli/generate-testcase.d.ts.map +1 -1
- package/dist/src/cli/generate-testcase.js +127 -131
- package/dist/src/cli/index.d.ts +11 -2
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +49 -16
- package/dist/src/cli/probe.d.ts +2 -0
- package/dist/src/cli/probe.d.ts.map +1 -1
- package/dist/src/cli/probe.js +239 -13
- package/dist/src/cli/run.d.ts +136 -29
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +494 -65
- package/dist/src/cli/spec.d.ts +18 -11
- package/dist/src/cli/spec.d.ts.map +1 -1
- package/dist/src/cli/spec.js +74 -20
- package/dist/src/contracts/crud-business-module.d.ts +6 -0
- package/dist/src/contracts/crud-business-module.d.ts.map +1 -1
- package/dist/src/contracts/glue-contract-v1.d.ts +98 -0
- package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -0
- package/dist/src/contracts/glue-contract-v1.js +9 -0
- package/dist/src/contracts/inference-trace.d.ts +223 -0
- package/dist/src/contracts/inference-trace.d.ts.map +1 -0
- package/dist/src/contracts/inference-trace.js +12 -0
- package/dist/src/contracts/observable-chain.d.ts +4 -0
- package/dist/src/contracts/observable-chain.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.d.ts +192 -0
- package/dist/src/extractors/code-list-json5.d.ts.map +1 -0
- package/dist/src/extractors/code-list-json5.js +91 -0
- package/dist/src/extractors/code-list.d.ts +3 -3
- package/dist/src/extractors/code-list.d.ts.map +1 -1
- package/dist/src/extractors/code-list.js +46 -11
- package/dist/src/extractors/html-page.d.ts +9 -0
- package/dist/src/extractors/html-page.d.ts.map +1 -1
- package/dist/src/extractors/html-page.js +26 -2
- package/dist/src/extractors/prd-extractor.d.ts +70 -0
- package/dist/src/extractors/prd-extractor.d.ts.map +1 -0
- package/dist/src/extractors/prd-extractor.js +248 -0
- package/dist/src/generators/agent-inferred-workflow-script.js +66 -66
- package/dist/src/generators/stage-skeleton-script.d.ts +87 -20
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +656 -238
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/inference/module-hints-inference.d.ts +30 -0
- package/dist/src/inference/module-hints-inference.d.ts.map +1 -0
- package/dist/src/inference/module-hints-inference.js +363 -0
- package/dist/src/inference/source-analysis.d.ts +26 -0
- package/dist/src/inference/source-analysis.d.ts.map +1 -0
- package/dist/src/inference/source-analysis.js +258 -0
- package/dist/src/normalizers/crud-contract.d.ts +3 -0
- package/dist/src/normalizers/crud-contract.d.ts.map +1 -1
- package/dist/src/normalizers/crud-contract.js +3 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts +88 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -0
- package/dist/src/runtime/ai-runtime-trace.js +119 -0
- package/dist/src/testcase/button-interaction-inference.d.ts +37 -0
- package/dist/src/testcase/button-interaction-inference.d.ts.map +1 -0
- package/dist/src/testcase/button-interaction-inference.js +385 -0
- package/dist/src/testcase/contract-testcase-assembler.d.ts +44 -0
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -0
- package/dist/src/testcase/contract-testcase-assembler.js +806 -0
- package/dist/src/testcase/prd-button-mapper.d.ts +72 -0
- package/dist/src/testcase/prd-button-mapper.d.ts.map +1 -0
- package/dist/src/testcase/prd-button-mapper.js +148 -0
- package/dist/src/testcase/runtime-context.d.ts +9 -0
- package/dist/src/testcase/runtime-context.d.ts.map +1 -0
- package/dist/src/testcase/runtime-context.js +1 -0
- package/dist/src/testcase/test-access.d.ts +38 -0
- package/dist/src/testcase/test-access.d.ts.map +1 -0
- package/dist/src/testcase/test-access.js +106 -0
- package/dist/src/testcase/testcase-execution-fields.d.ts +10 -0
- package/dist/src/testcase/testcase-execution-fields.d.ts.map +1 -0
- package/dist/src/testcase/testcase-execution-fields.js +1 -0
- package/dist/src/testcase/testcase-generator.d.ts.map +1 -1
- package/dist/src/testcase/testcase-generator.js +6 -0
- package/dist/src/testcase/testcase-markdown.d.ts +11 -0
- package/dist/src/testcase/testcase-markdown.d.ts.map +1 -0
- package/dist/src/testcase/testcase-markdown.js +181 -0
- package/dist/src/testcase/testcase-skeleton.d.ts +4 -0
- package/dist/src/testcase/testcase-skeleton.d.ts.map +1 -1
- package/dist/src/testcase/testcase-spec-assembly.d.ts +4 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts.map +1 -1
- package/dist/src/testcase/testcase-v1-draft.d.ts +58 -0
- package/dist/src/testcase/testcase-v1-draft.d.ts.map +1 -0
- package/dist/src/testcase/testcase-v1-draft.js +13 -0
- package/dist/src/validation/contract.d.ts +14 -0
- package/dist/src/validation/contract.d.ts.map +1 -0
- package/dist/src/validation/contract.js +132 -0
- package/dist/src/validation/credentials.d.ts +7 -2
- package/dist/src/validation/credentials.d.ts.map +1 -1
- package/dist/src/validation/credentials.js +15 -4
- package/dist/src/validation/index.d.ts +2 -0
- package/dist/src/validation/index.d.ts.map +1 -1
- package/dist/src/validation/index.js +2 -0
- package/dist/src/validation/inference-trace.d.ts +13 -0
- package/dist/src/validation/inference-trace.d.ts.map +1 -0
- package/dist/src/validation/inference-trace.js +31 -0
- package/dist/src/validation/testcase.d.ts +9 -7
- package/dist/src/validation/testcase.d.ts.map +1 -1
- package/dist/src/validation/testcase.js +181 -34
- package/docs/README.md +124 -134
- package/docs/mvp-usage-guide.md +298 -298
- package/examples/schemeresource-observable-docs/schemeresource.context.md +20 -20
- package/examples/schemeresource.module-hints.json +38 -38
- package/examples/schemeresource.observable.code_list.md +37 -37
- package/examples/zwplace-observable-docs/zwplace.context.md +16 -16
- package/examples/zwplace-placecategory-validation.json +29 -29
- package/examples/zwplace.module-hints.json +69 -69
- package/examples/zwplace.observable.code_list.md +37 -37
- package/package.json +2 -2
- package/dist/test/cli/extract-contract.test.d.ts +0 -2
- package/dist/test/cli/extract-contract.test.d.ts.map +0 -1
- package/dist/test/cli/extract-contract.test.js +0 -32
- package/dist/test/cli/generate-testcase.test.d.ts +0 -2
- package/dist/test/cli/generate-testcase.test.d.ts.map +0 -1
- package/dist/test/cli/generate-testcase.test.js +0 -130
- package/dist/test/cli/index.test.d.ts +0 -2
- package/dist/test/cli/index.test.d.ts.map +0 -1
- package/dist/test/cli/index.test.js +0 -93
- package/dist/test/cli/run.test.d.ts +0 -2
- package/dist/test/cli/run.test.d.ts.map +0 -1
- package/dist/test/cli/run.test.js +0 -149
- package/dist/test/cli/spec.test.d.ts +0 -2
- package/dist/test/cli/spec.test.d.ts.map +0 -1
- package/dist/test/cli/spec.test.js +0 -196
- package/dist/test/crud-contract.test.d.ts +0 -2
- package/dist/test/crud-contract.test.d.ts.map +0 -1
- package/dist/test/crud-contract.test.js +0 -819
- package/dist/test/gap-inference.test.d.ts +0 -2
- package/dist/test/gap-inference.test.d.ts.map +0 -1
- package/dist/test/gap-inference.test.js +0 -597
- package/dist/test/generalization.test.d.ts +0 -2
- package/dist/test/generalization.test.d.ts.map +0 -1
- package/dist/test/generalization.test.js +0 -73
- package/dist/test/material-inventory.test.d.ts +0 -2
- package/dist/test/material-inventory.test.d.ts.map +0 -1
- package/dist/test/material-inventory.test.js +0 -141
- package/dist/test/observable-chain.test.d.ts +0 -2
- package/dist/test/observable-chain.test.d.ts.map +0 -1
- package/dist/test/observable-chain.test.js +0 -123
- package/dist/test/observable-pipeline.test.d.ts +0 -2
- package/dist/test/observable-pipeline.test.d.ts.map +0 -1
- package/dist/test/observable-pipeline.test.js +0 -461
- package/dist/test/page-structure.test.d.ts +0 -2
- package/dist/test/page-structure.test.d.ts.map +0 -1
- package/dist/test/page-structure.test.js +0 -45
- package/dist/test/scenario-inference.test.d.ts +0 -2
- package/dist/test/scenario-inference.test.d.ts.map +0 -1
- package/dist/test/scenario-inference.test.js +0 -73
- package/dist/test/stage-context.test.d.ts +0 -2
- package/dist/test/stage-context.test.d.ts.map +0 -1
- package/dist/test/stage-context.test.js +0 -395
- package/dist/test/testcase-generator.test.d.ts +0 -2
- package/dist/test/testcase-generator.test.d.ts.map +0 -1
- package/dist/test/testcase-generator.test.js +0 -276
- package/dist/test/testcase-skeleton.test.d.ts +0 -2
- package/dist/test/testcase-skeleton.test.d.ts.map +0 -1
- package/dist/test/testcase-skeleton.test.js +0 -185
- package/dist/test/testcase-spec-assembly.test.d.ts +0 -2
- package/dist/test/testcase-spec-assembly.test.d.ts.map +0 -1
- package/dist/test/testcase-spec-assembly.test.js +0 -105
- package/dist/test/util/credentials.test.d.ts +0 -2
- package/dist/test/util/credentials.test.d.ts.map +0 -1
- package/dist/test/util/credentials.test.js +0 -64
- package/dist/test/util/i18n-testcase.test.d.ts +0 -2
- package/dist/test/util/i18n-testcase.test.d.ts.map +0 -1
- package/dist/test/util/i18n-testcase.test.js +0 -119
- package/dist/test/util/softlink.test.d.ts +0 -2
- package/dist/test/util/softlink.test.d.ts.map +0 -1
- package/dist/test/util/softlink.test.js +0 -82
- package/dist/test/validation/credentials.test.d.ts +0 -2
- package/dist/test/validation/credentials.test.d.ts.map +0 -1
- package/dist/test/validation/credentials.test.js +0 -72
- package/dist/test/validation/projects-index.test.d.ts +0 -2
- package/dist/test/validation/projects-index.test.d.ts.map +0 -1
- package/dist/test/validation/projects-index.test.js +0 -48
- package/dist/test/validation/testcase.test.d.ts +0 -2
- package/dist/test/validation/testcase.test.d.ts.map +0 -1
- package/dist/test/validation/testcase.test.js +0 -129
- package/dist/vitest.config.d.ts +0 -3
- package/dist/vitest.config.d.ts.map +0 -1
- package/dist/vitest.config.js +0 -7
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* code_list.json5 输入读取器
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. assertCodeListJson5Path — 路径硬校验,拒绝非 .json5 文件(含 .md)
|
|
6
|
+
* 2. extractCodeListJson5 — 读取并解析 JSON5 文件,校验必填字段,返回强类型产出
|
|
7
|
+
*/
|
|
8
|
+
import { type TestAccessConfig } from '../testcase/test-access.js';
|
|
9
|
+
/** 查询字段 */
|
|
10
|
+
export type QueryField = {
|
|
11
|
+
label: string;
|
|
12
|
+
type?: string;
|
|
13
|
+
component?: string;
|
|
14
|
+
modelRef?: string;
|
|
15
|
+
bind?: string;
|
|
16
|
+
};
|
|
17
|
+
/** 按钮/操作 */
|
|
18
|
+
export type ButtonAction = {
|
|
19
|
+
label: string;
|
|
20
|
+
action: string;
|
|
21
|
+
backendMethod: string | null;
|
|
22
|
+
customAction?: string;
|
|
23
|
+
};
|
|
24
|
+
/** 行级操作 */
|
|
25
|
+
export type RowAction = {
|
|
26
|
+
label: string;
|
|
27
|
+
action: string;
|
|
28
|
+
};
|
|
29
|
+
/** 数据加载方法 */
|
|
30
|
+
export type DataLoadingMethod = {
|
|
31
|
+
method: string;
|
|
32
|
+
description: string;
|
|
33
|
+
};
|
|
34
|
+
export type ChildGridEditMode = 'cell_edit' | 'row_button_dialog' | 'none';
|
|
35
|
+
/** 子表列定义 */
|
|
36
|
+
export type ChildGridColumn = {
|
|
37
|
+
field: string;
|
|
38
|
+
label: string;
|
|
39
|
+
required?: boolean;
|
|
40
|
+
modelRef?: string;
|
|
41
|
+
component?: 'input' | 'listbox';
|
|
42
|
+
};
|
|
43
|
+
/** 子表定义 */
|
|
44
|
+
export type ChildGridItem = {
|
|
45
|
+
id: string;
|
|
46
|
+
label: string;
|
|
47
|
+
actions?: Array<{
|
|
48
|
+
label: string;
|
|
49
|
+
actionName: string;
|
|
50
|
+
}>;
|
|
51
|
+
columns: ChildGridColumn[];
|
|
52
|
+
/** 操作方式覆盖;缺失时由 HTML 信号推断。 */
|
|
53
|
+
editMode?: ChildGridEditMode;
|
|
54
|
+
};
|
|
55
|
+
/** 页面物料 */
|
|
56
|
+
export type PageItem = {
|
|
57
|
+
path: string;
|
|
58
|
+
role: string;
|
|
59
|
+
description: string;
|
|
60
|
+
pageId?: string;
|
|
61
|
+
title?: string;
|
|
62
|
+
directUrl?: string;
|
|
63
|
+
queryFields?: QueryField[];
|
|
64
|
+
formFields?: QueryField[] | string[];
|
|
65
|
+
buttons: ButtonAction[];
|
|
66
|
+
rowActions: RowAction[];
|
|
67
|
+
usedDataModels?: string[];
|
|
68
|
+
dataLoadingMethods?: DataLoadingMethod[];
|
|
69
|
+
childGrids?: ChildGridItem[] | string[];
|
|
70
|
+
};
|
|
71
|
+
/** 业务系统 */
|
|
72
|
+
export type SystemItem = {
|
|
73
|
+
name: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
defaultLoginUrl?: string;
|
|
76
|
+
version?: string;
|
|
77
|
+
frameVersion?: string;
|
|
78
|
+
targetEnd?: string;
|
|
79
|
+
};
|
|
80
|
+
/** 角色 */
|
|
81
|
+
export type RoleItem = {
|
|
82
|
+
systemName?: string;
|
|
83
|
+
role: string;
|
|
84
|
+
loginMethod?: string;
|
|
85
|
+
permission?: string;
|
|
86
|
+
label?: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
menuPath?: string;
|
|
89
|
+
};
|
|
90
|
+
/** 下拉数据模型 */
|
|
91
|
+
export type DataModelItem = {
|
|
92
|
+
ref: string;
|
|
93
|
+
description: string;
|
|
94
|
+
};
|
|
95
|
+
/** 实体字段 */
|
|
96
|
+
export type EntityField = {
|
|
97
|
+
name: string;
|
|
98
|
+
type: string;
|
|
99
|
+
description: string;
|
|
100
|
+
dataKey?: boolean;
|
|
101
|
+
};
|
|
102
|
+
/** 数据实体 */
|
|
103
|
+
export type EntityItem = {
|
|
104
|
+
name: string;
|
|
105
|
+
table: string;
|
|
106
|
+
fields: EntityField[];
|
|
107
|
+
};
|
|
108
|
+
/** 业务规则 */
|
|
109
|
+
export type BusinessRule = {
|
|
110
|
+
rule: string;
|
|
111
|
+
scope: string[];
|
|
112
|
+
assertion: string;
|
|
113
|
+
};
|
|
114
|
+
/** 业务角色事实 */
|
|
115
|
+
export type BusinessRoleItem = {
|
|
116
|
+
label: string;
|
|
117
|
+
targetEnd?: string;
|
|
118
|
+
responsibilities?: string[];
|
|
119
|
+
};
|
|
120
|
+
/** 需求事实摘要 */
|
|
121
|
+
export type RequirementItem = {
|
|
122
|
+
id?: string;
|
|
123
|
+
name?: string;
|
|
124
|
+
businessRoles?: BusinessRoleItem[];
|
|
125
|
+
};
|
|
126
|
+
/** 源码根目录配置(可选,用于解析 pages[].path 等物料路径) */
|
|
127
|
+
export type SourceRootConfig = {
|
|
128
|
+
/** 源码根目录绝对路径 */
|
|
129
|
+
root?: string;
|
|
130
|
+
/** 路径别名标识 */
|
|
131
|
+
pathBase?: string;
|
|
132
|
+
/** 说明 pages[].path 相对哪个根目录解析 */
|
|
133
|
+
sourceFilesAreRelativeTo?: string;
|
|
134
|
+
};
|
|
135
|
+
/** extractCodeListJson5 的完整产出类型 */
|
|
136
|
+
export type ExtractedCodeListJson5 = {
|
|
137
|
+
/** 文件绝对路径 */
|
|
138
|
+
path: string;
|
|
139
|
+
/** 所属需求目录(code_list.json5 所在的 _docs 目录) */
|
|
140
|
+
requirementDir: string;
|
|
141
|
+
/** 模块标识 */
|
|
142
|
+
module: string;
|
|
143
|
+
/** 模块中文名称 */
|
|
144
|
+
moduleName: string;
|
|
145
|
+
/** 模块描述 */
|
|
146
|
+
description?: string;
|
|
147
|
+
/** 需求事实摘要(可选) */
|
|
148
|
+
requirement?: RequirementItem;
|
|
149
|
+
/** 源码根目录配置(可选) */
|
|
150
|
+
sourceRoot?: SourceRootConfig;
|
|
151
|
+
/** 业务系统清单 */
|
|
152
|
+
systems: SystemItem[];
|
|
153
|
+
/** 角色清单 */
|
|
154
|
+
roles: RoleItem[];
|
|
155
|
+
/** 页面物料清单 */
|
|
156
|
+
pages: PageItem[];
|
|
157
|
+
/** 下拉数据模型(可选) */
|
|
158
|
+
dataModels?: DataModelItem[];
|
|
159
|
+
/** 数据实体(可选) */
|
|
160
|
+
entities?: EntityItem[];
|
|
161
|
+
/** 业务规则(可选) */
|
|
162
|
+
businessRules?: BusinessRule[];
|
|
163
|
+
/** 开发阶段测试访问配置(可选) */
|
|
164
|
+
testAccess?: TestAccessConfig;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* 校验 filePath 是否为合法的 code_list.json5 路径。
|
|
168
|
+
* 拒绝非 .json5 后缀的文件(包括 .md)。
|
|
169
|
+
*
|
|
170
|
+
* @param filePath - 待校验的文件路径
|
|
171
|
+
* @throws Error 当文件后缀不是 .json5 时抛出中文错误
|
|
172
|
+
*/
|
|
173
|
+
export declare function assertCodeListJson5Path(filePath: string): void;
|
|
174
|
+
/**
|
|
175
|
+
* 读取并解析 code_list.json5 文件,返回强类型产出。
|
|
176
|
+
* 校验必填字段 module / moduleName / systems / pages,缺失时抛出中文错误。
|
|
177
|
+
*
|
|
178
|
+
* @param filePath - code_list.json5 文件的绝对路径
|
|
179
|
+
* @returns 解析后的强类型数据
|
|
180
|
+
* @throws Error 路径非法 / 文件不存在 / 必填字段缺失
|
|
181
|
+
*/
|
|
182
|
+
export declare function extractCodeListJson5Object(raw: unknown): Omit<ExtractedCodeListJson5, 'path' | 'requirementDir'>;
|
|
183
|
+
/**
|
|
184
|
+
* 读取并解析 code_list.json5 文件,返回强类型产出。
|
|
185
|
+
* 校验必填字段 module / moduleName / systems / pages,缺失时抛出中文错误。
|
|
186
|
+
*
|
|
187
|
+
* @param filePath - code_list.json5 文件的绝对路径
|
|
188
|
+
* @returns 解析后的强类型数据
|
|
189
|
+
* @throws Error 路径非法 / 文件不存在 / 必填字段缺失
|
|
190
|
+
*/
|
|
191
|
+
export declare function extractCodeListJson5(filePath: string): ExtractedCodeListJson5;
|
|
192
|
+
//# sourceMappingURL=code-list-json5.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-list-json5.d.ts","sourceRoot":"","sources":["../../../src/extractors/code-list-json5.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* code_list.json5 输入读取器
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. assertCodeListJson5Path — 路径硬校验,拒绝非 .json5 文件(含 .md)
|
|
6
|
+
* 2. extractCodeListJson5 — 读取并解析 JSON5 文件,校验必填字段,返回强类型产出
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import JSON5 from 'json5';
|
|
11
|
+
import { normalizeTestAccessConfig, } from '../testcase/test-access.js';
|
|
12
|
+
/* ──────── 路径硬校验 ──────── */
|
|
13
|
+
/**
|
|
14
|
+
* 校验 filePath 是否为合法的 code_list.json5 路径。
|
|
15
|
+
* 拒绝非 .json5 后缀的文件(包括 .md)。
|
|
16
|
+
*
|
|
17
|
+
* @param filePath - 待校验的文件路径
|
|
18
|
+
* @throws Error 当文件后缀不是 .json5 时抛出中文错误
|
|
19
|
+
*/
|
|
20
|
+
export function assertCodeListJson5Path(filePath) {
|
|
21
|
+
if (!filePath.endsWith('.json5')) {
|
|
22
|
+
throw new Error('glue-generate-testcase 只接受 _docs/code_list.json5');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/* ──────── JSON5 读取与解析 ──────── */
|
|
26
|
+
/**
|
|
27
|
+
* 读取并解析 code_list.json5 文件,返回强类型产出。
|
|
28
|
+
* 校验必填字段 module / moduleName / systems / pages,缺失时抛出中文错误。
|
|
29
|
+
*
|
|
30
|
+
* @param filePath - code_list.json5 文件的绝对路径
|
|
31
|
+
* @returns 解析后的强类型数据
|
|
32
|
+
* @throws Error 路径非法 / 文件不存在 / 必填字段缺失
|
|
33
|
+
*/
|
|
34
|
+
export function extractCodeListJson5Object(raw) {
|
|
35
|
+
if (!raw || typeof raw !== 'object') {
|
|
36
|
+
throw new Error('code_list.json5 顶层必须为对象');
|
|
37
|
+
}
|
|
38
|
+
const data = raw;
|
|
39
|
+
// 必填字段校验
|
|
40
|
+
if (!data.module) {
|
|
41
|
+
throw new Error('code_list.json5 缺少必填字段: module');
|
|
42
|
+
}
|
|
43
|
+
if (!data.moduleName) {
|
|
44
|
+
throw new Error('code_list.json5 缺少必填字段: moduleName');
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(data.systems)) {
|
|
47
|
+
throw new Error('code_list.json5 缺少必填字段: systems');
|
|
48
|
+
}
|
|
49
|
+
if (!Array.isArray(data.pages)) {
|
|
50
|
+
throw new Error('code_list.json5 缺少必填字段: pages');
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
module: data.module,
|
|
54
|
+
moduleName: data.moduleName,
|
|
55
|
+
description: data.description,
|
|
56
|
+
requirement: data.requirement,
|
|
57
|
+
sourceRoot: data.sourceRoot,
|
|
58
|
+
systems: data.systems,
|
|
59
|
+
roles: (data.roles ?? []),
|
|
60
|
+
pages: data.pages,
|
|
61
|
+
dataModels: data.dataModels,
|
|
62
|
+
entities: data.entities,
|
|
63
|
+
businessRules: data.businessRules,
|
|
64
|
+
testAccess: data.testAccess === undefined
|
|
65
|
+
? undefined
|
|
66
|
+
: normalizeTestAccessConfig(data.testAccess, 'code_list.json5.testAccess'),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 读取并解析 code_list.json5 文件,返回强类型产出。
|
|
71
|
+
* 校验必填字段 module / moduleName / systems / pages,缺失时抛出中文错误。
|
|
72
|
+
*
|
|
73
|
+
* @param filePath - code_list.json5 文件的绝对路径
|
|
74
|
+
* @returns 解析后的强类型数据
|
|
75
|
+
* @throws Error 路径非法 / 文件不存在 / 必填字段缺失
|
|
76
|
+
*/
|
|
77
|
+
export function extractCodeListJson5(filePath) {
|
|
78
|
+
assertCodeListJson5Path(filePath);
|
|
79
|
+
const absPath = path.resolve(filePath);
|
|
80
|
+
if (!existsSync(absPath)) {
|
|
81
|
+
throw new Error(`code_list.json5 文件不存在: ${absPath}`);
|
|
82
|
+
}
|
|
83
|
+
const raw = readFileSync(absPath, 'utf-8');
|
|
84
|
+
const parsed = JSON5.parse(raw);
|
|
85
|
+
const extracted = extractCodeListJson5Object(parsed);
|
|
86
|
+
return {
|
|
87
|
+
path: absPath,
|
|
88
|
+
requirementDir: path.dirname(absPath),
|
|
89
|
+
...extracted,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* 从 `code_list.md` 钻探出的单条上游物料引用。
|
|
3
3
|
*
|
|
4
4
|
* @property kind - 物料类别(html / java_action / spec / module_hints / other)。
|
|
5
|
-
* @property rawPath - markdown
|
|
6
|
-
* @property path -
|
|
5
|
+
* @property rawPath - markdown 中以反引号包裹的原始路径。
|
|
6
|
+
* @property path - 解析后的绝对路径(优先相对 knowledgeRoot,兼容回落到 code_list 所在目录)。
|
|
7
7
|
* @property exists - 解析后的路径是否真实存在,供下游 material-inventory gate 判定。
|
|
8
8
|
*/
|
|
9
9
|
export type ExtractedMaterialRef = {
|
|
@@ -15,7 +15,7 @@ export type ExtractedMaterialRef = {
|
|
|
15
15
|
export type ExtractedCodeListSummary = {
|
|
16
16
|
path: string;
|
|
17
17
|
knowledgeRoot?: string;
|
|
18
|
-
knowledgeRootSource: 'input' | 'code_list' | '
|
|
18
|
+
knowledgeRootSource: 'input' | 'code_list' | 'none';
|
|
19
19
|
menu?: string;
|
|
20
20
|
moduleLabel: string;
|
|
21
21
|
pages: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-list.d.ts","sourceRoot":"","sources":["../../../src/extractors/code-list.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,CAAC;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,OAAO,GAAG,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"code-list.d.ts","sourceRoot":"","sources":["../../../src/extractors/code-list.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,CAAC;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,oBAAoB,EAAE,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAyPF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,6BAAkC,GAC1C,wBAAwB,CAuC1B"}
|
|
@@ -57,6 +57,24 @@ function extractDeclaredKnowledgeRoot(content, filePath) {
|
|
|
57
57
|
const rawValue = cleanScalarValue(match[1]);
|
|
58
58
|
return path.isAbsolute(rawValue) ? rawValue : path.resolve(path.dirname(filePath), rawValue);
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* 解析 code_list.md 中“整理目录”声明的上游源码根。
|
|
62
|
+
*
|
|
63
|
+
* 支持格式:
|
|
64
|
+
* - `> 整理目录:`/abs/path``
|
|
65
|
+
* - `> 整理目录: /abs/path`
|
|
66
|
+
*
|
|
67
|
+
* @param content - code_list.md 文本内容。
|
|
68
|
+
* @returns 整理目录绝对路径;缺失或非绝对路径时返回 undefined。
|
|
69
|
+
*/
|
|
70
|
+
function extractOrganizeRoot(content) {
|
|
71
|
+
const match = content.match(/^>\s*整理目录[::]\s*`?(.+?)`?\s*$/m);
|
|
72
|
+
if (!match?.[1]) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const candidate = cleanScalarValue(match[1]);
|
|
76
|
+
return path.isAbsolute(candidate) ? candidate : undefined;
|
|
77
|
+
}
|
|
60
78
|
/**
|
|
61
79
|
* 提取 code_list.md 顶层标量字段。
|
|
62
80
|
*
|
|
@@ -79,12 +97,27 @@ function cleanScalarValue(value) {
|
|
|
79
97
|
/**
|
|
80
98
|
* 解析 code_list.md 中声明的菜单路由。
|
|
81
99
|
*
|
|
100
|
+
* 人工读写约定:code_list.md 用中文键「菜单」,与「整理目录」同风格,
|
|
101
|
+
* 支持 blockquote 形式 `> 菜单:一级菜单>二级菜单` 与裸行 `菜单: …`(反引号包裹可选)。
|
|
102
|
+
* 同时向后兼容英文键 menu / menuPath(编码内部字段名仍为 menu)。
|
|
103
|
+
*
|
|
82
104
|
* @param content - code_list.md 文本内容。
|
|
83
105
|
* @returns 菜单路由;未声明时返回 undefined。
|
|
84
106
|
*/
|
|
85
107
|
function extractDeclaredMenu(content) {
|
|
86
|
-
|
|
87
|
-
|
|
108
|
+
// 优先:中文键「菜单」blockquote 形式(与「整理目录」同风格,反引号包裹可选)
|
|
109
|
+
const blockquoteMatch = content.match(/^>\s*菜单[::]\s*`?(.+?)`?\s*$/m);
|
|
110
|
+
if (blockquoteMatch?.[1]) {
|
|
111
|
+
const value = cleanScalarValue(blockquoteMatch[1]);
|
|
112
|
+
if (value) {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// 裸行标量形式:菜单 / menu / menuPath(向后兼容英文键)
|
|
117
|
+
const scalarMatch = extractScalar(content, '菜单') ??
|
|
118
|
+
extractScalar(content, 'menu') ??
|
|
119
|
+
extractScalar(content, 'menuPath');
|
|
120
|
+
return scalarMatch?.[1] ? cleanScalarValue(scalarMatch[1]) : undefined;
|
|
88
121
|
}
|
|
89
122
|
/**
|
|
90
123
|
* 解析本次 code_list 应使用的上游物料根路径。
|
|
@@ -105,17 +138,20 @@ function resolveKnowledgeRoot(content, filePath, options) {
|
|
|
105
138
|
source: 'code_list',
|
|
106
139
|
};
|
|
107
140
|
}
|
|
108
|
-
|
|
141
|
+
const organizeRoot = extractOrganizeRoot(content);
|
|
142
|
+
if (organizeRoot) {
|
|
143
|
+
if (!existsSync(organizeRoot)) {
|
|
144
|
+
throw new Error(`code_list.md 声明的整理目录不存在:${organizeRoot}`);
|
|
145
|
+
}
|
|
109
146
|
return {
|
|
110
|
-
knowledgeRoot:
|
|
111
|
-
source: '
|
|
147
|
+
knowledgeRoot: organizeRoot,
|
|
148
|
+
source: 'code_list',
|
|
112
149
|
};
|
|
113
150
|
}
|
|
114
|
-
|
|
115
|
-
if (path.basename(codeListDir) === '_docs') {
|
|
151
|
+
if (options.knowledgeRoot) {
|
|
116
152
|
return {
|
|
117
|
-
knowledgeRoot: path.
|
|
118
|
-
source: '
|
|
153
|
+
knowledgeRoot: path.resolve(options.knowledgeRoot),
|
|
154
|
+
source: 'input',
|
|
119
155
|
};
|
|
120
156
|
}
|
|
121
157
|
return {
|
|
@@ -123,7 +159,7 @@ function resolveKnowledgeRoot(content, filePath, options) {
|
|
|
123
159
|
};
|
|
124
160
|
}
|
|
125
161
|
/**
|
|
126
|
-
* 按
|
|
162
|
+
* 按 knowledgeRoot / code_list 所在目录顺序产生候选根目录。
|
|
127
163
|
*
|
|
128
164
|
* @param filePath - code_list.md 的绝对路径。
|
|
129
165
|
* @param knowledgeRoot - 显式知识库根(可选)。
|
|
@@ -134,7 +170,6 @@ function materialRoots(filePath, knowledgeRoot) {
|
|
|
134
170
|
return [
|
|
135
171
|
...(knowledgeRoot ? [knowledgeRoot] : []),
|
|
136
172
|
codeListDir,
|
|
137
|
-
...(path.basename(codeListDir) === '_docs' ? [path.dirname(codeListDir)] : []),
|
|
138
173
|
];
|
|
139
174
|
}
|
|
140
175
|
/**
|
|
@@ -23,6 +23,8 @@ export type ExtractedHtmlGridColumn = {
|
|
|
23
23
|
field: string;
|
|
24
24
|
headerText: string;
|
|
25
25
|
columnType: string;
|
|
26
|
+
editorType?: string;
|
|
27
|
+
editorAction?: string;
|
|
26
28
|
};
|
|
27
29
|
export type ExtractedHtmlRowAction = {
|
|
28
30
|
label: string;
|
|
@@ -36,6 +38,13 @@ export type ExtractedHtmlGrid = {
|
|
|
36
38
|
selectionColumn?: ExtractedHtmlGridColumn;
|
|
37
39
|
indexColumn?: ExtractedHtmlGridColumn;
|
|
38
40
|
rowActions: ExtractedHtmlRowAction[];
|
|
41
|
+
/** MiniUI cell-edit 信号 */
|
|
42
|
+
allowCellEdit?: boolean;
|
|
43
|
+
cellEditAction?: string;
|
|
44
|
+
allowCellSelect?: boolean;
|
|
45
|
+
editNextOnEnterKey?: boolean;
|
|
46
|
+
oncellbeginedit?: boolean;
|
|
47
|
+
onrowdblclick?: boolean;
|
|
39
48
|
};
|
|
40
49
|
export type ExtractedPageStructureSignal = {
|
|
41
50
|
staticPresent: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-page.d.ts","sourceRoot":"","sources":["../../../src/extractors/html-page.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"html-page.d.ts","sourceRoot":"","sources":["../../../src/extractors/html-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,6 +38,17 @@ function buildButtonLocator(label, tagName) {
|
|
|
38
38
|
}
|
|
39
39
|
return `xpath=//a[contains(@class,'mini-button')][normalize-space()='${label}'] | //button[contains(@class,'mini-button')][normalize-space()='${label}']`;
|
|
40
40
|
}
|
|
41
|
+
function parseEditorAttribute(editorAttribute) {
|
|
42
|
+
const normalized = normalizeAttribute(editorAttribute);
|
|
43
|
+
if (!normalized)
|
|
44
|
+
return {};
|
|
45
|
+
const typeMatch = normalized.match(/type\s*:\s*['"]([^'"]+)['"]/i);
|
|
46
|
+
const actionMatch = normalized.match(/action\s*:\s*['"]([^'"]+)['"]/i);
|
|
47
|
+
return {
|
|
48
|
+
type: typeMatch?.[1],
|
|
49
|
+
action: actionMatch?.[1],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
41
52
|
function buildFieldLocator(label, controlType) {
|
|
42
53
|
if (controlType === 'mini-textbox') {
|
|
43
54
|
return `//div[@label='${label}']//input[@class='mini-textbox-input']`;
|
|
@@ -116,7 +127,14 @@ export function extractHtmlPage(filePath) {
|
|
|
116
127
|
const field = column.attr('field') ?? '';
|
|
117
128
|
const columnType = column.attr('type') ?? (field ? 'data' : 'unknown');
|
|
118
129
|
const headerText = normalizeText(column.clone().children().remove().end().text());
|
|
119
|
-
const
|
|
130
|
+
const editor = parseEditorAttribute(column.attr('editor'));
|
|
131
|
+
const extractedColumn = {
|
|
132
|
+
field,
|
|
133
|
+
headerText,
|
|
134
|
+
columnType,
|
|
135
|
+
editorType: editor.type,
|
|
136
|
+
editorAction: editor.action,
|
|
137
|
+
};
|
|
120
138
|
if (columnType === 'checkcolumn') {
|
|
121
139
|
selectionColumn = extractedColumn;
|
|
122
140
|
return;
|
|
@@ -149,7 +167,13 @@ export function extractHtmlPage(filePath) {
|
|
|
149
167
|
dataColumns,
|
|
150
168
|
selectionColumn,
|
|
151
169
|
indexColumn,
|
|
152
|
-
rowActions
|
|
170
|
+
rowActions,
|
|
171
|
+
allowCellEdit: booleanAttribute(grid.attr('allowCellEdit')) || undefined,
|
|
172
|
+
cellEditAction: normalizeAttribute(grid.attr('cellEditAction')) || undefined,
|
|
173
|
+
allowCellSelect: booleanAttribute(grid.attr('allowCellSelect')) || undefined,
|
|
174
|
+
editNextOnEnterKey: booleanAttribute(grid.attr('editNextOnEnterKey')) || undefined,
|
|
175
|
+
oncellbeginedit: normalizeAttribute(grid.attr('oncellbeginedit')) ? true : undefined,
|
|
176
|
+
onrowdblclick: normalizeAttribute(grid.attr('onrowdblclick')) ? true : undefined,
|
|
153
177
|
});
|
|
154
178
|
});
|
|
155
179
|
const scriptContent = $('script')
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD markdown 解析器。
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 在需求目录中发现 PRD markdown 文件。
|
|
6
|
+
* 2. 解析 PRD 章节 4.1(功能列表)和 4.2.x(功能详细说明)。
|
|
7
|
+
* 3. 输出结构化的 PrdFunctionEntry[],供 testcase 装配阶段确定性使用。
|
|
8
|
+
*
|
|
9
|
+
* 设计取舍:
|
|
10
|
+
* - 全程使用正则/行解析,不调用 LLM,保证幂等性。
|
|
11
|
+
* - 只识别当前观察到的 PRD 结构(`4.1` 表格 + `4.2.x` 子章节 + 粗体字段标题)。
|
|
12
|
+
* - 解析失败时返回空数组并在 inferenceTrace 中记录,不阻断 pipeline。
|
|
13
|
+
*/
|
|
14
|
+
/** PRD 中的单个功能条目。 */
|
|
15
|
+
export type PrdFunctionEntry = {
|
|
16
|
+
/** 功能编号,如 F001。 */
|
|
17
|
+
featureId: string;
|
|
18
|
+
/** 功能名称,如「同步窗口管理系统」。 */
|
|
19
|
+
featureName: string;
|
|
20
|
+
/** 功能模块,如「大厅地址管理」。 */
|
|
21
|
+
featureModule?: string;
|
|
22
|
+
/** 功能描述。 */
|
|
23
|
+
description: string;
|
|
24
|
+
/** 输入条件。 */
|
|
25
|
+
inputConditions?: string;
|
|
26
|
+
/** 处理逻辑,保留列表顺序。 */
|
|
27
|
+
processingLogic: string[];
|
|
28
|
+
/** 输出结果,保留列表顺序。 */
|
|
29
|
+
outputResult: string[];
|
|
30
|
+
/** 业务规则,保留列表顺序。 */
|
|
31
|
+
businessRules: string[];
|
|
32
|
+
/** 约束条件,保留列表顺序。 */
|
|
33
|
+
constraints: string[];
|
|
34
|
+
};
|
|
35
|
+
/** PRD 提取产物。 */
|
|
36
|
+
export type PrdExtraction = {
|
|
37
|
+
/** PRD 文件绝对路径。 */
|
|
38
|
+
prdPath: string;
|
|
39
|
+
/** 解析出的功能条目,按 PRD 顺序排列。 */
|
|
40
|
+
functions: PrdFunctionEntry[];
|
|
41
|
+
/** 解析时间 ISO 字符串,仅用于审计,不影响 testcase 生成。 */
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* 在目录中查找 PRD markdown 文件。
|
|
46
|
+
*
|
|
47
|
+
* 规则(满足任一即返回):
|
|
48
|
+
* 1. 文件名包含 `prd`(大小写不敏感)且以 `.md` 结尾。
|
|
49
|
+
* 2. 文件正文包含 `## 4. 功能需求` 标题。
|
|
50
|
+
*
|
|
51
|
+
* @param dir - 需求文档目录。
|
|
52
|
+
* @returns PRD 文件绝对路径;不存在时返回 undefined。
|
|
53
|
+
*/
|
|
54
|
+
export declare function findPrdMarkdown(dir: string): string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* 读取 PRD 文件并提取功能条目。
|
|
57
|
+
*
|
|
58
|
+
* @param prdPath - PRD markdown 文件绝对路径。
|
|
59
|
+
* @param now - 可选的解析时间戳,用于测试冻结。
|
|
60
|
+
* @returns PRD 提取产物。
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadPrdExtraction(prdPath: string, now?: string): PrdExtraction;
|
|
63
|
+
/**
|
|
64
|
+
* 解析 PRD markdown 文本,提取功能列表 + 功能详细说明。
|
|
65
|
+
*
|
|
66
|
+
* @param markdown - PRD 完整 markdown 文本。
|
|
67
|
+
* @returns 按 PRD 顺序排列的功能条目数组。
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractPrdFunctions(markdown: string): PrdFunctionEntry[];
|
|
70
|
+
//# sourceMappingURL=prd-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prd-extractor.d.ts","sourceRoot":"","sources":["../../../src/extractors/prd-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,oBAAoB;AACpB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,mBAAmB;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,mBAAmB;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mBAAmB;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,gBAAgB;AAChB,MAAM,MAAM,aAAa,GAAG;IAC1B,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAsB/D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAA2B,GAAG,aAAa,CAIhG;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAqBxE"}
|