1
0

feat: ValueMatcher 支持 primitive 原始值简写,等价于 { equals: value }

This commit is contained in:
2026-05-19 17:07:47 +08:00
parent 8d8549d07f
commit 12cd05b04e
37 changed files with 1836 additions and 1022 deletions

View File

@@ -1,7 +1,7 @@
import { isEmptyObject, isEqual, isNil, isPlainObject } from "es-toolkit";
import type { CheckFailure, JsonValue } from "../types";
import type { ExpectResult, ValueMatcher } from "./types";
import type { ExpectResult, ValueMatcher, ValueMatcherInput } from "./types";
import { mismatchFailure } from "./failure";
@@ -66,18 +66,19 @@ export function checkExpectValue(actual: unknown, expected: JsonValue | ValueMat
export function checkValueMatcher(
actual: unknown,
matcher: undefined | ValueMatcher,
matcher: undefined | ValueMatcherInput,
options: { message?: string; path: string; phase: CheckFailure["phase"]; stringifyNonString?: boolean },
): ExpectResult {
if (matcher === undefined) return { failure: null, matched: true };
if (applyMatcher(actual, matcher, { stringifyNonString: options.stringifyNonString })) {
const normalized = isValueMatcherObject(matcher) ? matcher : { equals: matcher };
if (applyMatcher(actual, normalized, { stringifyNonString: options.stringifyNonString })) {
return { failure: null, matched: true };
}
return {
failure: mismatchFailure(
options.phase,
options.path,
matcher,
normalized,
actual,
options.message ?? `${options.path} mismatch`,
),

View File

@@ -0,0 +1,22 @@
import type { ValueMatcherPrimitive } from "./types";
import { isValueMatcherObject } from "./matcher";
export function isValueMatcherPrimitive(value: unknown): value is ValueMatcherPrimitive {
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
}
export function normalizeExpectMatchers(expect: Record<string, unknown>, keys: string[]): void {
for (const key of keys) {
if (key in expect) {
expect[key] = normalizeValueMatcher(expect[key]);
}
}
}
export function normalizeValueMatcher(value: unknown): unknown {
if (value === undefined) return undefined;
if (isValueMatcherObject(value)) return value;
if (isValueMatcherPrimitive(value)) return { equals: value };
return value;
}

View File

@@ -39,3 +39,7 @@ export interface ValueMatcher {
lte?: number;
regex?: string;
}
export type ValueMatcherInput = ValueMatcher | ValueMatcherPrimitive;
export type ValueMatcherPrimitive = boolean | null | number | string;

View File

@@ -6,6 +6,7 @@ import type { ConfigValidationIssue } from "../schema/issues";
import type { JsonValue } from "../types";
import { issue, joinPath } from "../schema/issues";
import { isValueMatcherPrimitive } from "./normalize";
import { isUnsafeRegex } from "./redos";
export const MatcherKeys = ["contains", "empty", "equals", "exists", "gt", "gte", "lt", "lte", "regex"] as const;
@@ -72,7 +73,9 @@ export function validateValueMatcher(
options: { requireAtLeastOne?: boolean } = {},
): ConfigValidationIssue[] {
const requireAtLeastOne = options.requireAtLeastOne ?? true;
if (!isPlainRecord(matcher)) return [issue("invalid-type", path, "必须为 matcher 对象", targetName)];
if (isValueMatcherPrimitive(matcher)) return [];
if (!isPlainRecord(matcher))
return [issue("invalid-type", path, "必须为 primitive 原始值或 matcher 对象", targetName)];
const issues: ConfigValidationIssue[] = [];
let found = 0;