- 重命名 ContentRules→ContentExpectations, KeyValueExpect→KeyedExpectations - 新增 Raw/Resolved 双层模型:resolve 阶段物化为执行计划,store 持久化 Raw 快照 - HTTP body 按需读取:status/headers 失败或无 body expectation 时不读取 body - 新增 displayValueExpectation() 解包 failure.expected 用户可读展示 - 修复 checkEarlyTimeout 独立 lte/lt 检查,修复 KeyedExpectations JSON Schema - 新增 expect/value.ts(resolve/check/display)、keyed.ts、content.ts、headers.ts、status.ts - 删除旧 normalize.ts/matcher.ts/validate-matcher.ts/key-value.ts - 更新 DEVELOPMENT.md:expect 五层管线表、displayValueExpectation、1.7↔1.10 交叉引用 - 同步 13 个 main specs,归档 refactor-expect-type-model 变更(62/62 tasks)
8.5 KiB
Purpose
定义 checker 模块的内聚化组织结构,确保每个 checker 以独立目录形式存在,包含其全部类型定义、schema 声明、语义校验、执行逻辑和断言逻辑。同时定义共享的 expect/ 和 schema/ 基础设施,以及严格的依赖方向约束。
Requirements
Requirement: Checker 目录内聚结构
每个 checker SHALL 以独立目录形式存在于 src/server/checker/runner/<type>/,目录内 SHALL 包含该 checker 的全部类型定义、schema 声明、语义校验、执行逻辑和断言逻辑。
Scenario: HTTP checker 目录完整性
- WHEN 开发者查看
src/server/checker/runner/http/目录 - THEN 该目录 SHALL 包含
index.ts、types.ts、schema.ts、execute.ts、expect.ts、body.ts、validate.ts
Scenario: Cmd checker 目录完整性
- WHEN 开发者查看
src/server/checker/runner/cmd/目录 - THEN 该目录 SHALL 包含
index.ts、types.ts、schema.ts、execute.ts、expect.ts、text.ts、validate.ts
Scenario: 新增 checker 最小改动
- WHEN 开发者新增一个 checker 类型(如 dns)
- THEN 开发者 SHALL 只需创建
src/server/checker/runner/dns/目录及其内部文件,并在runner/index.ts注册列表中添加一行 import 和一行数组项
Requirement: Checker 目录文件职责
每个 checker 目录内的文件 SHALL 遵循统一的职责划分。
Scenario: index.ts 仅做 re-export
- WHEN 开发者查看某 checker 的
index.ts - THEN 该文件 SHALL 仅包含对
execute.ts中 Checker 类的 re-export,不包含任何逻辑
Scenario: types.ts 包含该 checker 全部专属类型
- WHEN 开发者需要该 checker 的配置类型、resolved 类型或 expect 类型
- THEN 这些类型 SHALL 全部定义在该 checker 目录的
types.ts中,不在顶层types.ts中
Scenario: schema.ts 包含 TypeBox schema 定义
- WHEN 开发者需要该 checker 的 config/defaults/expect schema
- THEN 这些 schema SHALL 定义在该 checker 目录的
schema.ts中
Scenario: execute.ts 包含 Checker 类实现
- WHEN 开发者需要查看该 checker 的执行逻辑
- THEN Checker 类(实现 CheckerDefinition 接口)SHALL 定义在
execute.ts中
Scenario: validate.ts 包含该 checker 全部语义校验
- WHEN 开发者需要查看该 checker 的配置校验逻辑
- THEN 该 checker 专属的语义校验函数 SHALL 全部定义在
validate.ts中
Scenario: expect.ts 包含该 checker 专属断言
- WHEN 开发者需要查看该 checker 的断言逻辑
- THEN 该 checker 专属的断言函数 SHALL 定义在
expect.ts中
Requirement: 断言基础设施目录
系统 SHALL 在 src/server/checker/expect/ 目录中提供所有 checker 共享的断言基础设施。共享 expect 目录 SHALL 使用 Raw/Resolved expectation 术语和 value/content/keyed/status/headers 模块边界。
Scenario: expect 共享类型位置
- WHEN 任何 checker 需要使用断言相关的共享类型(如
ExpectationResult、ValueExpectation、ContentExpectations或KeyedExpectations) - THEN 这些类型 SHALL 从
src/server/checker/expect/types.ts导入
Scenario: value 断言引擎位置
- WHEN 任何 checker 需要使用
applyValueMatcher、evaluateJsonPath、resolveValueExpectation或checkValueExpectation - THEN 这些函数 SHALL 从
src/server/checker/expect/value.ts导入
Scenario: content 和 keyed 断言位置
- WHEN 任何 checker 需要执行内容数组或键值表 expectation
- THEN SHALL 分别从
src/server/checker/expect/content.ts和src/server/checker/expect/keyed.ts导入共享函数
Scenario: failure 构造器位置
- WHEN 任何 checker 需要使用
errorFailure或mismatchFailure - THEN 这些函数 SHALL 从
src/server/checker/expect/failure.ts导入
Scenario: expectation 校验位置
- WHEN 任何 checker 的 validate 需要校验 Raw value、Raw content 或 Raw keyed expectation
- THEN 对应函数 SHALL 从
src/server/checker/expect/validate.ts导入
Scenario: ExpectationResult 类型位置
- WHEN 任何 checker 需要使用
ExpectationResult类型 - THEN 该类型 SHALL 从
src/server/checker/expect/types.ts导入
Requirement: Schema 目录结构
系统 SHALL 在 src/server/checker/schema/ 目录中组织配置 schema 体系,替代原 config-contract/ 目录。
Scenario: schema 目录包含 builder
- WHEN 系统需要从 registry 动态构建整体配置 schema
- THEN 该逻辑 SHALL 位于
src/server/checker/schema/builder.ts
Scenario: schema 目录包含 fragments
- WHEN checker 的 schema.ts 需要引用共享 schema 片段(如 durationSchema、sizeSchema)
- THEN 这些片段 SHALL 从
src/server/checker/schema/fragments.ts导入
Scenario: schema 目录包含 Ajv 校验入口
- WHEN config-loader 需要执行契约校验
- THEN 校验入口 SHALL 位于
src/server/checker/schema/validate.ts
Scenario: schema 目录包含 issue 工具
- WHEN 任何校验逻辑需要构造 ConfigValidationIssue
- THEN issue 类型和工具函数 SHALL 从
src/server/checker/schema/issues.ts导入
Requirement: 工具函数归集
系统 SHALL 在 src/server/checker/utils.ts 中提供纯工具函数。
Scenario: parseSize 位置
- WHEN 任何模块需要解析 size 字符串(如 "100MB")
- THEN
parseSizeSHALL 从src/server/checker/utils.ts导入
Scenario: parseDuration 位置
- WHEN 任何模块需要解析 duration 字符串(如 "30s")
- THEN
parseDurationSHALL 从src/server/checker/utils.ts导入
Requirement: 依赖方向约束
checker 系统内的模块依赖 SHALL 遵循严格的分层方向。
Scenario: checker 之间无横向依赖
- WHEN 开发者查看任何 checker 目录的 import 语句
- THEN 该 checker SHALL NOT 导入其他 checker 目录的任何模块
Scenario: expect/ 不依赖 runner/
- WHEN 开发者查看
expect/目录的 import 语句 - THEN
expect/中的文件 SHALL NOT 导入runner/目录的任何模块
Scenario: schema/ 不依赖 runner/ 的具体 checker
- WHEN 开发者查看
schema/目录的 import 语句 - THEN
schema/中的文件 SHALL 仅通过CheckerDefinition接口与 checker 交互,SHALL NOT 直接导入具体 checker 目录
Requirement: 显式注册列表
系统 SHALL 在 src/server/checker/runner/index.ts 中使用显式 import 列表注册所有 checker。
Scenario: 注册入口结构
- WHEN 开发者查看
runner/index.ts - THEN 该文件 SHALL 包含所有 checker 的静态 import 和一个 checker 实例数组,通过循环调用
registry.register()完成注册
Scenario: 新增 checker 注册
- WHEN 开发者新增一个 checker
- THEN 开发者 SHALL 在
runner/index.ts中添加一行 import 和一行数组项,无需修改其他文件
Requirement: 公共类型文件瘦身
顶层 src/server/checker/types.ts SHALL 仅保留跨 checker 共享的 base 类型和存储相关类型;expect 专属类型 SHALL 放在 src/server/checker/expect/types.ts。
Scenario: types.ts 不包含 checker 或 expect 专属类型
- WHEN 开发者查看顶层
types.ts - THEN 该文件 SHALL NOT 包含
HttpTargetConfig、ResolvedHttpTarget、RawCommandExpectConfig、ContentExpectation等 checker 专属或 expect 专属类型
Scenario: types.ts 保留 base 类型
- WHEN 开发者查看顶层
types.ts - THEN 该文件 SHALL 包含
ResolvedTargetBase、RawTargetConfig、DefaultsConfig、CheckResult、CheckFailure、StoredTarget、StoredCheckResult、JsonValue等公共类型
Scenario: ResolvedTargetBase 替代联合类型
- WHEN engine、store、config-loader 需要引用 resolved target 类型
- THEN 这些模块 SHALL 使用
ResolvedTargetBaseinterface,不再使用硬编码联合类型
Scenario: DefaultsConfig 为宽松 base 形式
- WHEN 开发者查看顶层
types.ts中的DefaultsConfig - THEN 该 interface SHALL 仅包含公共字段(
interval?、timeout?)和 index signature([checkerKey: string]: unknown),SHALL NOT 包含cmd?、http?等 checker 专属字段
Scenario: 各 checker validate 自行 narrow defaults
- WHEN checker 的
validate()方法需要访问自身的 defaults 配置 - THEN checker SHALL 从
DefaultsConfig中通过defaults[configKey]获取并自行 narrow 为具体类型