refactor: 将 checker normalize 职责下沉到各 runner 目录
- 新增 CheckerDefinition.normalize 必需方法,typecheck 兜底遗漏实现 - 新增 expect/normalize.ts 共享 helper(compactExpect、normalizeValue、 normalizeContent、normalizeKeyed) - 为 HTTP、Cmd、DB、TCP、UDP、ICMP、LLM、WS、DNS 各新增独立 normalize.ts - 简化 normalizer.ts:删除所有 checker type switch,改为 registry 委托 - 修复 DNS authoring 简写 bug:durationMs、valueCount、result 等字段 现可通过完整加载链路 - 新增 DNS 回归测试和 registry 级合同测试 - 更新 docs/development/checker.md:补充 normalize 规范、文件结构、 测试要求和 checklist
This commit is contained in:
50
src/server/checker/expect/normalize.ts
Normal file
50
src/server/checker/expect/normalize.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { isPlainObject } from "es-toolkit";
|
||||
|
||||
import { resolveContentExpectations } from "./content";
|
||||
import { CONTENT_EXTRACTOR_KEY_SET, MATCHER_KEY_SET } from "./keys";
|
||||
import { isValueMatcherObject, isValueMatcherPrimitive, resolveValueExpectation } from "./value";
|
||||
|
||||
type ExpectRecord = Record<string, unknown>;
|
||||
|
||||
export function compactExpect(original: ExpectRecord, overrides: ExpectRecord): ExpectRecord {
|
||||
const result: ExpectRecord = {};
|
||||
for (const [key, value] of Object.entries(original)) {
|
||||
if (value !== undefined) result[key] = value;
|
||||
}
|
||||
for (const [key, value] of Object.entries(overrides)) {
|
||||
if (value !== undefined) result[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function normalizeContent(value: unknown): unknown {
|
||||
if (value === undefined) return undefined;
|
||||
if (!Array.isArray(value)) return value;
|
||||
return (value as unknown[]).map((entry): unknown => {
|
||||
if (!canNormalizeContentEntry(entry)) return entry;
|
||||
const resolved = resolveContentExpectations([entry] as never);
|
||||
return resolved?.[0];
|
||||
});
|
||||
}
|
||||
|
||||
export function normalizeKeyed(value: unknown): unknown {
|
||||
if (value === undefined) return undefined;
|
||||
if (!isPlainObject(value)) return value;
|
||||
return Object.entries(value as ExpectRecord).map(([key, item]) => ({ key, matcher: normalizeValue(item) }));
|
||||
}
|
||||
|
||||
export function normalizeValue(value: unknown): unknown {
|
||||
if (value === undefined) return undefined;
|
||||
if (isValueMatcherPrimitive(value) || isValueMatcherObject(value)) return resolveValueExpectation(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
function canNormalizeContentEntry(value: unknown): boolean {
|
||||
if (!isPlainObject(value)) return false;
|
||||
const keys = Object.keys(value);
|
||||
const extractorKeys = keys.filter((key) => CONTENT_EXTRACTOR_KEY_SET.has(key));
|
||||
const matcherKeys = keys.filter((key) => MATCHER_KEY_SET.has(key));
|
||||
if (extractorKeys.length === 0) return matcherKeys.length > 0 && matcherKeys.length === keys.length;
|
||||
if (extractorKeys.length !== 1 || matcherKeys.length > 0 || keys.length !== 1) return false;
|
||||
return isPlainObject((value as ExpectRecord)[extractorKeys[0]!]);
|
||||
}
|
||||
Reference in New Issue
Block a user