Add first business article and article layout
This commit is contained in:
32
node_modules/zod/src/v4/mini/checks.ts
generated
vendored
Normal file
32
node_modules/zod/src/v4/mini/checks.ts
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
export {
|
||||
_lt as lt,
|
||||
_lte as lte,
|
||||
_lte as maximum,
|
||||
_gt as gt,
|
||||
_gte as gte,
|
||||
_gte as minimum,
|
||||
_positive as positive,
|
||||
_negative as negative,
|
||||
_nonpositive as nonpositive,
|
||||
_nonnegative as nonnegative,
|
||||
_multipleOf as multipleOf,
|
||||
_maxSize as maxSize,
|
||||
_minSize as minSize,
|
||||
_size as size,
|
||||
_maxLength as maxLength,
|
||||
_minLength as minLength,
|
||||
_length as length,
|
||||
_regex as regex,
|
||||
_lowercase as lowercase,
|
||||
_uppercase as uppercase,
|
||||
_includes as includes,
|
||||
_startsWith as startsWith,
|
||||
_endsWith as endsWith,
|
||||
_property as property,
|
||||
_mime as mime,
|
||||
_overwrite as overwrite,
|
||||
_normalize as normalize,
|
||||
_trim as trim,
|
||||
_toLowerCase as toLowerCase,
|
||||
_toUpperCase as toUpperCase,
|
||||
} from "../core/index.js";
|
||||
27
node_modules/zod/src/v4/mini/coerce.ts
generated
vendored
Normal file
27
node_modules/zod/src/v4/mini/coerce.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as core from "../core/index.js";
|
||||
import * as schemas from "./schemas.js";
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function string<T = unknown>(params?: string | core.$ZodStringParams): schemas.ZodMiniString<T> {
|
||||
return core._coercedString(schemas.ZodMiniString, params) as schemas.ZodMiniString<T>;
|
||||
}
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function number<T = unknown>(params?: string | core.$ZodNumberParams): schemas.ZodMiniNumber<T> {
|
||||
return core._coercedNumber(schemas.ZodMiniNumber, params) as schemas.ZodMiniNumber<T>;
|
||||
}
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function boolean<T = unknown>(params?: string | core.$ZodBooleanParams): schemas.ZodMiniBoolean<T> {
|
||||
return core._coercedBoolean(schemas.ZodMiniBoolean, params) as schemas.ZodMiniBoolean<T>;
|
||||
}
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function bigint<T = unknown>(params?: string | core.$ZodBigIntParams): schemas.ZodMiniBigInt<T> {
|
||||
return core._coercedBigint(schemas.ZodMiniBigInt, params) as schemas.ZodMiniBigInt<T>;
|
||||
}
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function date<T = unknown>(params?: string | core.$ZodDateParams): schemas.ZodMiniDate<T> {
|
||||
return core._coercedDate(schemas.ZodMiniDate, params) as schemas.ZodMiniDate<T>;
|
||||
}
|
||||
41
node_modules/zod/src/v4/mini/external.ts
generated
vendored
Normal file
41
node_modules/zod/src/v4/mini/external.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
export * as core from "../core/index.js";
|
||||
export * from "./parse.js";
|
||||
export * from "./schemas.js";
|
||||
export * from "./checks.js";
|
||||
|
||||
export type { infer, output, input } from "../core/index.js";
|
||||
export type { JSONType } from "../core/util.js";
|
||||
export {
|
||||
globalRegistry,
|
||||
registry,
|
||||
config,
|
||||
$output,
|
||||
$input,
|
||||
$brand,
|
||||
clone,
|
||||
regexes,
|
||||
treeifyError,
|
||||
prettifyError,
|
||||
formatError,
|
||||
flattenError,
|
||||
TimePrecision,
|
||||
util,
|
||||
NEVER,
|
||||
} from "../core/index.js";
|
||||
export { toJSONSchema } from "../core/json-schema-processors.js";
|
||||
|
||||
export * as locales from "../locales/index.js";
|
||||
/** A special constant with type `never` */
|
||||
// export const NEVER = {} as never;
|
||||
|
||||
// iso
|
||||
export * as iso from "./iso.js";
|
||||
export {
|
||||
ZodMiniISODateTime,
|
||||
ZodMiniISODate,
|
||||
ZodMiniISOTime,
|
||||
ZodMiniISODuration,
|
||||
} from "./iso.js";
|
||||
|
||||
// coerce
|
||||
export * as coerce from "./coerce.js";
|
||||
3
node_modules/zod/src/v4/mini/index.ts
generated
vendored
Normal file
3
node_modules/zod/src/v4/mini/index.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as z from "./external.js";
|
||||
export * from "./external.js";
|
||||
export { z };
|
||||
66
node_modules/zod/src/v4/mini/iso.ts
generated
vendored
Normal file
66
node_modules/zod/src/v4/mini/iso.ts
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
import * as core from "../core/index.js";
|
||||
import * as schemas from "./schemas.js";
|
||||
|
||||
// iso time
|
||||
export interface ZodMiniISODateTime extends schemas.ZodMiniStringFormat<"datetime"> {
|
||||
_zod: core.$ZodISODateTimeInternals;
|
||||
}
|
||||
export const ZodMiniISODateTime: core.$constructor<ZodMiniISODateTime> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodMiniISODateTime",
|
||||
(inst, def) => {
|
||||
core.$ZodISODateTime.init(inst, def);
|
||||
schemas.ZodMiniStringFormat.init(inst, def);
|
||||
}
|
||||
);
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function datetime(params?: string | core.$ZodISODateTimeParams): ZodMiniISODateTime {
|
||||
return core._isoDateTime(ZodMiniISODateTime, params);
|
||||
}
|
||||
|
||||
// iso date
|
||||
export interface ZodMiniISODate extends schemas.ZodMiniStringFormat<"date"> {
|
||||
_zod: core.$ZodISODateInternals;
|
||||
}
|
||||
export const ZodMiniISODate: core.$constructor<ZodMiniISODate> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodMiniISODate",
|
||||
(inst, def) => {
|
||||
core.$ZodISODate.init(inst, def);
|
||||
schemas.ZodMiniStringFormat.init(inst, def);
|
||||
}
|
||||
);
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function date(params?: string | core.$ZodISODateParams): ZodMiniISODate {
|
||||
return core._isoDate(ZodMiniISODate, params);
|
||||
}
|
||||
|
||||
// iso time
|
||||
export interface ZodMiniISOTime extends schemas.ZodMiniStringFormat<"time"> {
|
||||
_zod: core.$ZodISOTimeInternals;
|
||||
}
|
||||
export const ZodMiniISOTime: core.$constructor<ZodMiniISOTime> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodMiniISOTime",
|
||||
(inst, def) => {
|
||||
core.$ZodISOTime.init(inst, def);
|
||||
schemas.ZodMiniStringFormat.init(inst, def);
|
||||
}
|
||||
);
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function time(params?: string | core.$ZodISOTimeParams): ZodMiniISOTime {
|
||||
return core._isoTime(ZodMiniISOTime, params);
|
||||
}
|
||||
|
||||
// iso duration
|
||||
export interface ZodMiniISODuration extends schemas.ZodMiniStringFormat<"duration"> {
|
||||
_zod: core.$ZodISODurationInternals;
|
||||
}
|
||||
export const ZodMiniISODuration: core.$constructor<ZodMiniISODuration> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodMiniISODuration",
|
||||
(inst, def) => {
|
||||
core.$ZodISODuration.init(inst, def);
|
||||
schemas.ZodMiniStringFormat.init(inst, def);
|
||||
}
|
||||
);
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function duration(params?: string | core.$ZodISODurationParams): ZodMiniISODuration {
|
||||
return core._isoDuration(ZodMiniISODuration, params);
|
||||
}
|
||||
14
node_modules/zod/src/v4/mini/parse.ts
generated
vendored
Normal file
14
node_modules/zod/src/v4/mini/parse.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
export {
|
||||
parse,
|
||||
safeParse,
|
||||
parseAsync,
|
||||
safeParseAsync,
|
||||
encode,
|
||||
decode,
|
||||
encodeAsync,
|
||||
decodeAsync,
|
||||
safeEncode,
|
||||
safeDecode,
|
||||
safeEncodeAsync,
|
||||
safeDecodeAsync,
|
||||
} from "../core/index.js";
|
||||
1947
node_modules/zod/src/v4/mini/schemas.ts
generated
vendored
Normal file
1947
node_modules/zod/src/v4/mini/schemas.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
node_modules/zod/src/v4/mini/tests/apply.test.ts
generated
vendored
Normal file
24
node_modules/zod/src/v4/mini/tests/apply.test.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "../index.js";
|
||||
|
||||
test("basic apply (number)", () => {
|
||||
const setCommonNumberChecks = <T extends z.ZodMiniNumber>(schema: T) => {
|
||||
return schema.check(z.minimum(0), z.maximum(100));
|
||||
};
|
||||
|
||||
const schema = z.nullable(z.number().apply(setCommonNumberChecks));
|
||||
|
||||
expect(() => z.parse(schema, -1)).toThrowError();
|
||||
expect(() => z.parse(schema, 101)).toThrowError();
|
||||
expect(z.parse(schema, 0)).toBe(0);
|
||||
expect(z.parse(schema, null)).toBe(null);
|
||||
expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<number | null>();
|
||||
});
|
||||
|
||||
test("The callback's return value becomes the apply's return value.", () => {
|
||||
const symbol = Symbol();
|
||||
const result = z.number().apply(() => symbol);
|
||||
|
||||
expect(result).toBe(symbol);
|
||||
expectTypeOf<typeof result>().toEqualTypeOf<symbol>();
|
||||
});
|
||||
129
node_modules/zod/src/v4/mini/tests/assignability.test.ts
generated
vendored
Normal file
129
node_modules/zod/src/v4/mini/tests/assignability.test.ts
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
import { test } from "vitest";
|
||||
|
||||
import * as z from "zod/mini";
|
||||
|
||||
test("assignability", () => {
|
||||
// $ZodString
|
||||
z.string() satisfies z.core.$ZodString;
|
||||
|
||||
// $ZodNumber
|
||||
z.number() satisfies z.core.$ZodNumber;
|
||||
|
||||
// $ZodBigInt
|
||||
z.bigint() satisfies z.core.$ZodBigInt;
|
||||
|
||||
// $ZodBoolean
|
||||
z.boolean() satisfies z.core.$ZodBoolean;
|
||||
|
||||
// $ZodDate
|
||||
z.date() satisfies z.core.$ZodDate;
|
||||
|
||||
// $ZodSymbol
|
||||
z.symbol() satisfies z.core.$ZodSymbol;
|
||||
|
||||
// $ZodUndefined
|
||||
z.undefined() satisfies z.core.$ZodUndefined;
|
||||
|
||||
// $ZodNullable
|
||||
z.nullable(z.string()) satisfies z.core.$ZodNullable;
|
||||
|
||||
// $ZodNull
|
||||
z.null() satisfies z.core.$ZodNull;
|
||||
|
||||
// $ZodAny
|
||||
z.any() satisfies z.core.$ZodAny;
|
||||
|
||||
// $ZodUnknown
|
||||
z.unknown() satisfies z.core.$ZodUnknown;
|
||||
|
||||
// $ZodNever
|
||||
z.never() satisfies z.core.$ZodNever;
|
||||
|
||||
// $ZodVoid
|
||||
z.void() satisfies z.core.$ZodVoid;
|
||||
|
||||
// $ZodArray
|
||||
z.array(z.string()) satisfies z.core.$ZodArray;
|
||||
|
||||
// $ZodObject
|
||||
z.object({ key: z.string() }) satisfies z.core.$ZodObject;
|
||||
|
||||
// $ZodUnion
|
||||
z.union([z.string(), z.number()]) satisfies z.core.$ZodUnion;
|
||||
|
||||
// $ZodIntersection
|
||||
z.intersection(z.string(), z.number()) satisfies z.core.$ZodIntersection;
|
||||
|
||||
// $ZodTuple
|
||||
z.tuple([z.string(), z.number()]) satisfies z.core.$ZodTuple;
|
||||
|
||||
// $ZodRecord
|
||||
z.record(z.string(), z.number()) satisfies z.core.$ZodRecord;
|
||||
|
||||
// $ZodMap
|
||||
z.map(z.string(), z.number()) satisfies z.core.$ZodMap;
|
||||
|
||||
// $ZodSet
|
||||
z.set(z.string()) satisfies z.core.$ZodSet;
|
||||
|
||||
// $ZodLiteral
|
||||
z.literal("example") satisfies z.core.$ZodLiteral;
|
||||
|
||||
// $ZodEnum
|
||||
z.enum(["a", "b", "c"]) satisfies z.core.$ZodEnum;
|
||||
|
||||
// $ZodPromise
|
||||
z.promise(z.string()) satisfies z.core.$ZodPromise;
|
||||
|
||||
// $ZodLazy
|
||||
const lazySchema = z.lazy(() => z.string());
|
||||
lazySchema satisfies z.core.$ZodLazy;
|
||||
|
||||
// $ZodOptional
|
||||
z.optional(z.string()) satisfies z.core.$ZodOptional;
|
||||
|
||||
// $ZodDefault
|
||||
z._default(z.string(), "default") satisfies z.core.$ZodDefault;
|
||||
|
||||
// $ZodTemplateLiteral
|
||||
z.templateLiteral([z.literal("a"), z.literal("b")]) satisfies z.core.$ZodTemplateLiteral;
|
||||
|
||||
// $ZodCustom
|
||||
z.custom<string>((val) => typeof val === "string") satisfies z.core.$ZodCustom;
|
||||
|
||||
// $ZodTransform
|
||||
z.transform((val) => val as string) satisfies z.core.$ZodTransform;
|
||||
|
||||
// $ZodNonOptional
|
||||
z.nonoptional(z.optional(z.string())) satisfies z.core.$ZodNonOptional;
|
||||
|
||||
// $ZodReadonly
|
||||
z.readonly(z.object({ key: z.string() })) satisfies z.core.$ZodReadonly;
|
||||
|
||||
// $ZodNaN
|
||||
z.nan() satisfies z.core.$ZodNaN;
|
||||
|
||||
// $ZodPipe
|
||||
z.pipe(z.unknown(), z.number()) satisfies z.core.$ZodPipe;
|
||||
|
||||
// $ZodSuccess
|
||||
z.success(z.string()) satisfies z.core.$ZodSuccess;
|
||||
|
||||
// $ZodCatch
|
||||
z.catch(z.string(), "fallback") satisfies z.core.$ZodCatch;
|
||||
|
||||
// $ZodFile
|
||||
z.file() satisfies z.core.$ZodFile;
|
||||
});
|
||||
|
||||
test("assignability with type narrowing", () => {
|
||||
type _RefinedSchema<T extends z.ZodMiniType<object> | z.ZodMiniUnion> = T extends z.ZodMiniUnion
|
||||
? RefinedUnionSchema<T> // <-- Type instantiation is excessively deep and possibly infinite.
|
||||
: T extends z.ZodMiniType<object>
|
||||
? RefinedTypeSchema<z.output<T>> // <-- Type instantiation is excessively deep and possibly infinite.
|
||||
: never;
|
||||
|
||||
type RefinedTypeSchema<T extends object> = T;
|
||||
|
||||
type RefinedUnionSchema<T extends z.ZodMiniUnion> = T;
|
||||
});
|
||||
94
node_modules/zod/src/v4/mini/tests/brand.test.ts
generated
vendored
Normal file
94
node_modules/zod/src/v4/mini/tests/brand.test.ts
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
import { expectTypeOf, test } from "vitest";
|
||||
import * as z from "../index.js";
|
||||
|
||||
test("branded types", () => {
|
||||
const mySchema = z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.brand<"superschema">();
|
||||
|
||||
// simple branding
|
||||
type MySchema = z.infer<typeof mySchema>;
|
||||
// Using true for type equality assertion
|
||||
expectTypeOf<MySchema>().toEqualTypeOf<{ name: string } & z.$brand<"superschema">>();
|
||||
|
||||
const doStuff = (arg: MySchema) => arg;
|
||||
doStuff(z.parse(mySchema, { name: "hello there" }));
|
||||
|
||||
// inheritance
|
||||
const extendedSchema = mySchema.brand<"subschema">();
|
||||
type ExtendedSchema = z.infer<typeof extendedSchema>;
|
||||
expectTypeOf<ExtendedSchema>().toEqualTypeOf<{ name: string } & z.$brand<"superschema"> & z.$brand<"subschema">>();
|
||||
|
||||
doStuff(z.parse(extendedSchema, { name: "hello again" }));
|
||||
|
||||
// number branding
|
||||
const numberSchema = z.number().brand<42>();
|
||||
type NumberSchema = z.infer<typeof numberSchema>;
|
||||
expectTypeOf<NumberSchema>().toEqualTypeOf<number & { [z.$brand]: { 42: true } }>();
|
||||
|
||||
// symbol branding
|
||||
const MyBrand: unique symbol = Symbol("hello");
|
||||
type MyBrand = typeof MyBrand;
|
||||
const symbolBrand = z.number().brand<"sup">().brand<typeof MyBrand>();
|
||||
type SymbolBrand = z.infer<typeof symbolBrand>;
|
||||
// number & { [z.$brand]: { sup: true, [MyBrand]: true } }
|
||||
expectTypeOf<SymbolBrand>().toEqualTypeOf<number & z.$brand<"sup"> & z.$brand<MyBrand>>();
|
||||
|
||||
// keeping brands out of input types
|
||||
const age = z.number().brand<"age">();
|
||||
type Age1 = z.infer<typeof age>;
|
||||
type AgeInput1 = z.input<typeof age>;
|
||||
|
||||
// Using not for type inequality assertion
|
||||
expectTypeOf<AgeInput1>().not.toEqualTypeOf<Age1>();
|
||||
expectTypeOf<number>().toEqualTypeOf<AgeInput1>();
|
||||
expectTypeOf<number & z.$brand<"age">>().toEqualTypeOf<Age1>();
|
||||
|
||||
// @ts-expect-error
|
||||
doStuff({ name: "hello there!" });
|
||||
});
|
||||
|
||||
test("brand direction: out (default)", () => {
|
||||
const schema = z.string().brand<"A">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// output is branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// input is NOT branded (default behavior)
|
||||
expectTypeOf<Input>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: out (explicit)", () => {
|
||||
const schema = z.string().brand<"A", "out">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// output is branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// input is NOT branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: in", () => {
|
||||
const schema = z.string().brand<"A", "in">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// input is branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// output is NOT branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: inout", () => {
|
||||
const schema = z.string().brand<"A", "inout">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// both are branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
});
|
||||
144
node_modules/zod/src/v4/mini/tests/checks.test.ts
generated
vendored
Normal file
144
node_modules/zod/src/v4/mini/tests/checks.test.ts
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "../index.js";
|
||||
|
||||
// lt;
|
||||
test("z.lt", () => {
|
||||
const a = z.number().check(z.lt(10));
|
||||
expect(z.safeParse(a, 9).success).toEqual(true);
|
||||
expect(z.safeParse(a, 9).data).toEqual(9);
|
||||
expect(z.safeParse(a, 10).success).toEqual(false);
|
||||
});
|
||||
|
||||
// lte;
|
||||
test("z.lte", () => {
|
||||
const a = z.number().check(z.lte(10));
|
||||
expect(z.safeParse(a, 10).success).toEqual(true);
|
||||
expect(z.safeParse(a, 10).data).toEqual(10);
|
||||
expect(z.safeParse(a, 11).success).toEqual(false);
|
||||
});
|
||||
|
||||
// min;
|
||||
test("z.max", () => {
|
||||
const a = z.number().check(z.maximum(10));
|
||||
expect(z.safeParse(a, 10).success).toEqual(true);
|
||||
expect(z.safeParse(a, 10).data).toEqual(10);
|
||||
expect(z.safeParse(a, 11).success).toEqual(false);
|
||||
});
|
||||
|
||||
// gt;
|
||||
test("z.gt", () => {
|
||||
const a = z.number().check(z.gt(10));
|
||||
expect(z.safeParse(a, 11).success).toEqual(true);
|
||||
expect(z.safeParse(a, 11).data).toEqual(11);
|
||||
expect(z.safeParse(a, 10).success).toEqual(false);
|
||||
});
|
||||
|
||||
// gte;
|
||||
test("z.gte", () => {
|
||||
const a = z.number().check(z.gte(10));
|
||||
expect(z.safeParse(a, 10).success).toEqual(true);
|
||||
expect(z.safeParse(a, 10).data).toEqual(10);
|
||||
expect(z.safeParse(a, 9).success).toEqual(false);
|
||||
});
|
||||
|
||||
// min;
|
||||
test("z.min", () => {
|
||||
const a = z.number().check(z.minimum(10));
|
||||
expect(z.safeParse(a, 10).success).toEqual(true);
|
||||
expect(z.safeParse(a, 10).data).toEqual(10);
|
||||
expect(z.safeParse(a, 9).success).toEqual(false);
|
||||
});
|
||||
|
||||
// maxSize;
|
||||
test("z.maxLength", () => {
|
||||
const a = z.array(z.string()).check(z.maxLength(3));
|
||||
expect(z.safeParse(a, ["a", "b", "c"]).success).toEqual(true);
|
||||
expect(z.safeParse(a, ["a", "b", "c", "d"]).success).toEqual(false);
|
||||
});
|
||||
|
||||
// minSize;
|
||||
test("z.minLength", () => {
|
||||
const a = z.array(z.string()).check(z.minLength(3));
|
||||
expect(z.safeParse(a, ["a", "b"]).success).toEqual(false);
|
||||
expect(z.safeParse(a, ["a", "b", "c"]).success).toEqual(true);
|
||||
});
|
||||
|
||||
// size;
|
||||
test("z.length", () => {
|
||||
const a = z.array(z.string()).check(z.length(3));
|
||||
expect(z.safeParse(a, ["a", "b"]).success).toEqual(false);
|
||||
expect(z.safeParse(a, ["a", "b", "c"]).success).toEqual(true);
|
||||
expect(z.safeParse(a, ["a", "b", "c", "d"]).success).toEqual(false);
|
||||
});
|
||||
|
||||
// regex;
|
||||
test("z.regex", () => {
|
||||
const a = z.string().check(z.regex(/^aaa$/));
|
||||
expect(z.safeParse(a, "aaa")).toMatchObject({ success: true, data: "aaa" });
|
||||
expect(z.safeParse(a, "aa")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// includes;
|
||||
test("z.includes", () => {
|
||||
const a = z.string().check(z.includes("asdf"));
|
||||
z.parse(a, "qqqasdfqqq");
|
||||
z.parse(a, "asdf");
|
||||
z.parse(a, "qqqasdf");
|
||||
z.parse(a, "asdfqqq");
|
||||
expect(z.safeParse(a, "qqq")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// startsWith;
|
||||
test("z.startsWith", () => {
|
||||
const a = z.string().check(z.startsWith("asdf"));
|
||||
z.parse(a, "asdf");
|
||||
z.parse(a, "asdfqqq");
|
||||
expect(z.safeParse(a, "qqq")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// endsWith;
|
||||
test("z.endsWith", () => {
|
||||
const a = z.string().check(z.endsWith("asdf"));
|
||||
z.parse(a, "asdf");
|
||||
z.parse(a, "qqqasdf");
|
||||
expect(z.safeParse(a, "asdfqqq")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// lowercase;
|
||||
test("z.lowercase", () => {
|
||||
const a = z.string().check(z.lowercase());
|
||||
z.parse(a, "asdf");
|
||||
expect(z.safeParse(a, "ASDF")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// uppercase;
|
||||
test("z.uppercase", () => {
|
||||
const a = z.string().check(z.uppercase());
|
||||
z.parse(a, "ASDF");
|
||||
expect(z.safeParse(a, "asdf")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// filename;
|
||||
// fileType;
|
||||
// overwrite;
|
||||
test("z.overwrite", () => {
|
||||
const a = z.string().check(z.overwrite((val) => val.toUpperCase()));
|
||||
expect(z.safeParse(a, "asdf")).toMatchObject({ data: "ASDF" });
|
||||
});
|
||||
|
||||
// normalize;
|
||||
// trim;
|
||||
// toLowerCase;
|
||||
// toUpperCase;
|
||||
// property
|
||||
|
||||
test("abort early", () => {
|
||||
const schema = z.string().check(
|
||||
z.refine((val) => val.length > 1),
|
||||
z.refine((val) => val.length > 2, { abort: true }),
|
||||
z.refine((val) => val.length > 3)
|
||||
);
|
||||
const data = "";
|
||||
const result = z.safeParse(schema, data);
|
||||
expect(result.error!.issues.length).toEqual(2);
|
||||
});
|
||||
548
node_modules/zod/src/v4/mini/tests/codec.test.ts
generated
vendored
Normal file
548
node_modules/zod/src/v4/mini/tests/codec.test.ts
generated
vendored
Normal file
@@ -0,0 +1,548 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import { en } from "zod/locales";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
z.config(en());
|
||||
|
||||
const isoDateCodec = z.codec(
|
||||
z.iso.datetime(), // Input: ISO string (validates to string)
|
||||
z.date(), // Output: Date object
|
||||
{
|
||||
decode: (isoString) => new Date(isoString), // Forward: ISO string → Date
|
||||
encode: (date) => date.toISOString(), // Backward: Date → ISO string
|
||||
}
|
||||
);
|
||||
|
||||
test("instanceof", () => {
|
||||
expect(isoDateCodec instanceof z.ZodMiniCodec).toBe(true);
|
||||
expect(isoDateCodec instanceof z.ZodMiniPipe).toBe(true);
|
||||
expect(isoDateCodec instanceof z.ZodMiniType).toBe(true);
|
||||
expect(isoDateCodec instanceof z.core.$ZodCodec).toBe(true);
|
||||
expect(isoDateCodec instanceof z.core.$ZodPipe).toBe(true);
|
||||
expect(isoDateCodec instanceof z.core.$ZodType).toBe(true);
|
||||
|
||||
expectTypeOf(isoDateCodec.def).toEqualTypeOf<z.core.$ZodCodecDef<z.ZodMiniISODateTime, z.ZodMiniDate<Date>>>();
|
||||
});
|
||||
|
||||
test("codec basic functionality", () => {
|
||||
// ISO string -> Date codec using z.iso.datetime() for input validation
|
||||
|
||||
const testIsoString = "2024-01-15T10:30:00.000Z";
|
||||
const testDate = new Date("2024-01-15T10:30:00.000Z");
|
||||
|
||||
// Forward decoding (ISO string -> Date)
|
||||
const decodedResult = z.decode(isoDateCodec, testIsoString);
|
||||
expect(decodedResult).toBeInstanceOf(Date);
|
||||
expect(decodedResult.toISOString()).toMatchInlineSnapshot(`"2024-01-15T10:30:00.000Z"`);
|
||||
|
||||
// Backward encoding (Date -> ISO string)
|
||||
const encodedResult = z.encode(isoDateCodec, testDate);
|
||||
expect(typeof encodedResult).toBe("string");
|
||||
expect(encodedResult).toMatchInlineSnapshot(`"2024-01-15T10:30:00.000Z"`);
|
||||
});
|
||||
|
||||
test("codec round trip", () => {
|
||||
const isoDateCodec = z.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
});
|
||||
|
||||
const original = "2024-12-25T15:45:30.123Z";
|
||||
const toDate = z.decode(isoDateCodec, original);
|
||||
const backToString = z.encode(isoDateCodec, toDate);
|
||||
|
||||
expect(backToString).toMatchInlineSnapshot(`"2024-12-25T15:45:30.123Z"`);
|
||||
expect(toDate).toBeInstanceOf(Date);
|
||||
expect(toDate.getTime()).toMatchInlineSnapshot(`1735141530123`);
|
||||
});
|
||||
|
||||
test("codec with refinement", () => {
|
||||
const isoDateCodec = z
|
||||
.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
})
|
||||
.check(z.refine((val) => val.getFullYear() === 2024, { error: "Year must be 2024" }));
|
||||
|
||||
// Valid 2024 date
|
||||
const validDate = z.decode(isoDateCodec, "2024-01-15T10:30:00.000Z");
|
||||
expect(validDate.getFullYear()).toMatchInlineSnapshot(`2024`);
|
||||
expect(validDate.getTime()).toMatchInlineSnapshot(`1705314600000`);
|
||||
|
||||
// Invalid year should fail safely
|
||||
const invalidYearResult = z.safeDecode(isoDateCodec, "2023-01-15T10:30:00.000Z");
|
||||
expect(invalidYearResult.success).toBe(false);
|
||||
if (!invalidYearResult.success) {
|
||||
expect(invalidYearResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Year must be 2024",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
test("safe codec operations", () => {
|
||||
const isoDateCodec = z.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
});
|
||||
|
||||
// Safe decode with invalid input
|
||||
const safeDecodeResult = z.safeDecode(isoDateCodec, "invalid-date");
|
||||
expect(safeDecodeResult.success).toBe(false);
|
||||
if (!safeDecodeResult.success) {
|
||||
expect(safeDecodeResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "datetime",
|
||||
"message": "Invalid ISO datetime",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/",
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Safe decode with valid input
|
||||
const safeDecodeValid = z.safeDecode(isoDateCodec, "2024-01-15T10:30:00.000Z");
|
||||
expect(safeDecodeValid.success).toBe(true);
|
||||
if (safeDecodeValid.success) {
|
||||
expect(safeDecodeValid.data).toBeInstanceOf(Date);
|
||||
expect(safeDecodeValid.data.getTime()).toMatchInlineSnapshot(`1705314600000`);
|
||||
}
|
||||
|
||||
// Safe encode with valid input
|
||||
const safeEncodeResult = z.safeEncode(isoDateCodec, new Date("2024-01-01"));
|
||||
expect(safeEncodeResult.success).toBe(true);
|
||||
if (safeEncodeResult.success) {
|
||||
expect(safeEncodeResult.data).toMatchInlineSnapshot(`"2024-01-01T00:00:00.000Z"`);
|
||||
}
|
||||
});
|
||||
|
||||
test("codec with different types", () => {
|
||||
// String -> Number codec
|
||||
const stringNumberCodec = z.codec(z.string(), z.number(), {
|
||||
decode: (str) => Number.parseFloat(str),
|
||||
encode: (num) => num.toString(),
|
||||
});
|
||||
|
||||
const decodedNumber = z.decode(stringNumberCodec, "42.5");
|
||||
expect(decodedNumber).toMatchInlineSnapshot(`42.5`);
|
||||
expect(typeof decodedNumber).toBe("number");
|
||||
|
||||
const encodedString = z.encode(stringNumberCodec, 42.5);
|
||||
expect(encodedString).toMatchInlineSnapshot(`"42.5"`);
|
||||
expect(typeof encodedString).toBe("string");
|
||||
});
|
||||
|
||||
test("async codec operations", async () => {
|
||||
const isoDateCodec = z.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
});
|
||||
|
||||
// Async decode
|
||||
const decodedResult = await z.decodeAsync(isoDateCodec, "2024-01-15T10:30:00.000Z");
|
||||
expect(decodedResult).toBeInstanceOf(Date);
|
||||
expect(decodedResult.getTime()).toMatchInlineSnapshot(`1705314600000`);
|
||||
|
||||
// Async encode
|
||||
const encodedResult = await z.encodeAsync(isoDateCodec, new Date("2024-01-15T10:30:00.000Z"));
|
||||
expect(typeof encodedResult).toBe("string");
|
||||
expect(encodedResult).toMatchInlineSnapshot(`"2024-01-15T10:30:00.000Z"`);
|
||||
|
||||
// Safe async operations
|
||||
const safeDecodeResult = await z.safeDecodeAsync(isoDateCodec, "2024-01-15T10:30:00.000Z");
|
||||
expect(safeDecodeResult.success).toBe(true);
|
||||
if (safeDecodeResult.success) {
|
||||
expect(safeDecodeResult.data.getTime()).toMatchInlineSnapshot(`1705314600000`);
|
||||
}
|
||||
|
||||
const safeEncodeResult = await z.safeEncodeAsync(isoDateCodec, new Date("2024-01-15T10:30:00.000Z"));
|
||||
expect(safeEncodeResult.success).toBe(true);
|
||||
if (safeEncodeResult.success) {
|
||||
expect(safeEncodeResult.data).toMatchInlineSnapshot(`"2024-01-15T10:30:00.000Z"`);
|
||||
}
|
||||
});
|
||||
|
||||
test("codec type inference", () => {
|
||||
const codec = z.codec(z.string(), z.number(), {
|
||||
decode: (str) => Number.parseInt(str),
|
||||
encode: (num) => num.toString(),
|
||||
});
|
||||
|
||||
// These should compile without type errors
|
||||
const decoded: number = z.decode(codec, "123");
|
||||
const encoded: string = z.encode(codec, 123);
|
||||
|
||||
expect(decoded).toMatchInlineSnapshot(`123`);
|
||||
expect(encoded).toMatchInlineSnapshot(`"123"`);
|
||||
});
|
||||
|
||||
test("nested codec with object containing codec property", () => {
|
||||
// Nested schema: object containing a codec as one of its properties, with refinements at all levels
|
||||
const waypointSchema = z
|
||||
.object({
|
||||
name: z.string().check(z.minLength(1, "Waypoint name required")),
|
||||
difficulty: z.enum(["easy", "medium", "hard"]),
|
||||
coordinate: z
|
||||
.codec(
|
||||
z
|
||||
.string()
|
||||
.check(z.regex(/^-?\d+,-?\d+$/, "Must be 'x,y' format")), // Input: coordinate string
|
||||
z
|
||||
.object({ x: z.number(), y: z.number() })
|
||||
.check(z.refine((coord) => coord.x >= 0 && coord.y >= 0, { error: "Coordinates must be non-negative" })), // Output: coordinate object
|
||||
{
|
||||
decode: (coordString: string) => {
|
||||
const [x, y] = coordString.split(",").map(Number);
|
||||
return { x, y };
|
||||
},
|
||||
encode: (coord: { x: number; y: number }) => `${coord.x},${coord.y}`,
|
||||
}
|
||||
)
|
||||
.check(z.refine((coord) => coord.x <= 1000 && coord.y <= 1000, { error: "Coordinates must be within bounds" })),
|
||||
})
|
||||
.check(
|
||||
z.refine((waypoint) => waypoint.difficulty !== "hard" || waypoint.coordinate.x >= 100, {
|
||||
error: "Hard waypoints must be at least 100 units from origin",
|
||||
})
|
||||
);
|
||||
|
||||
// Test data
|
||||
const inputWaypoint = {
|
||||
name: "Summit Point",
|
||||
difficulty: "medium" as const,
|
||||
coordinate: "150,200",
|
||||
};
|
||||
|
||||
// Forward decoding (object with string coordinate -> object with coordinate object)
|
||||
const decodedWaypoint = z.decode(waypointSchema, inputWaypoint);
|
||||
expect(decodedWaypoint).toMatchInlineSnapshot(`
|
||||
{
|
||||
"coordinate": {
|
||||
"x": 150,
|
||||
"y": 200,
|
||||
},
|
||||
"difficulty": "medium",
|
||||
"name": "Summit Point",
|
||||
}
|
||||
`);
|
||||
|
||||
// Backward encoding (object with coordinate object -> object with string coordinate)
|
||||
const encodedWaypoint = z.encode(waypointSchema, decodedWaypoint);
|
||||
expect(encodedWaypoint).toMatchInlineSnapshot(`
|
||||
{
|
||||
"coordinate": "150,200",
|
||||
"difficulty": "medium",
|
||||
"name": "Summit Point",
|
||||
}
|
||||
`);
|
||||
|
||||
// Test refinements at all levels
|
||||
// String validation (empty waypoint name)
|
||||
const emptyNameResult = z.safeDecode(waypointSchema, {
|
||||
name: "",
|
||||
difficulty: "easy",
|
||||
coordinate: "10,20",
|
||||
});
|
||||
expect(emptyNameResult.success).toBe(false);
|
||||
if (!emptyNameResult.success) {
|
||||
expect(emptyNameResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Waypoint name required",
|
||||
"minimum": 1,
|
||||
"origin": "string",
|
||||
"path": [
|
||||
"name",
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Enum validation (invalid difficulty)
|
||||
const invalidDifficultyResult = z.safeDecode(waypointSchema, {
|
||||
name: "Test Point",
|
||||
difficulty: "impossible" as any,
|
||||
coordinate: "10,20",
|
||||
});
|
||||
expect(invalidDifficultyResult.success).toBe(false);
|
||||
if (!invalidDifficultyResult.success) {
|
||||
expect(invalidDifficultyResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_value",
|
||||
"message": "Invalid option: expected one of "easy"|"medium"|"hard"",
|
||||
"path": [
|
||||
"difficulty",
|
||||
],
|
||||
"values": [
|
||||
"easy",
|
||||
"medium",
|
||||
"hard",
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Codec string format validation (invalid coordinate format)
|
||||
const invalidFormatResult = z.safeDecode(waypointSchema, {
|
||||
name: "Test Point",
|
||||
difficulty: "easy",
|
||||
coordinate: "invalid",
|
||||
});
|
||||
expect(invalidFormatResult.success).toBe(false);
|
||||
if (!invalidFormatResult.success) {
|
||||
expect(invalidFormatResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "regex",
|
||||
"message": "Must be 'x,y' format",
|
||||
"origin": "string",
|
||||
"path": [
|
||||
"coordinate",
|
||||
],
|
||||
"pattern": "/^-?\\d+,-?\\d+$/",
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Codec object refinement (negative coordinates)
|
||||
const negativeCoordResult = z.safeDecode(waypointSchema, {
|
||||
name: "Test Point",
|
||||
difficulty: "easy",
|
||||
coordinate: "-5,10",
|
||||
});
|
||||
expect(negativeCoordResult.success).toBe(false);
|
||||
if (!negativeCoordResult.success) {
|
||||
expect(negativeCoordResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Coordinates must be non-negative",
|
||||
"path": [
|
||||
"coordinate",
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Codec-level refinement (coordinates out of bounds)
|
||||
const outOfBoundsResult = z.safeDecode(waypointSchema, {
|
||||
name: "Test Point",
|
||||
difficulty: "easy",
|
||||
coordinate: "1500,2000",
|
||||
});
|
||||
expect(outOfBoundsResult.success).toBe(false);
|
||||
if (!outOfBoundsResult.success) {
|
||||
expect(outOfBoundsResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Coordinates must be within bounds",
|
||||
"path": [
|
||||
"coordinate",
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Object-level refinement (hard waypoint too close to origin)
|
||||
const hardWaypointResult = z.safeDecode(waypointSchema, {
|
||||
name: "Expert Point",
|
||||
difficulty: "hard",
|
||||
coordinate: "50,60", // x < 100, but hard waypoints need x >= 100
|
||||
});
|
||||
expect(hardWaypointResult.success).toBe(false);
|
||||
if (!hardWaypointResult.success) {
|
||||
expect(hardWaypointResult.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Hard waypoints must be at least 100 units from origin",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
|
||||
// Round trip test
|
||||
const roundTripResult = z.encode(waypointSchema, z.decode(waypointSchema, inputWaypoint));
|
||||
expect(roundTripResult).toMatchInlineSnapshot(`
|
||||
{
|
||||
"coordinate": "150,200",
|
||||
"difficulty": "medium",
|
||||
"name": "Summit Point",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("mutating refinements", () => {
|
||||
const A = z.codec(z.string(), z.string().check(z.trim()), {
|
||||
decode: (val) => val,
|
||||
encode: (val) => val,
|
||||
});
|
||||
|
||||
expect(z.decode(A, " asdf ")).toMatchInlineSnapshot(`"asdf"`);
|
||||
expect(z.encode(A, " asdf ")).toMatchInlineSnapshot(`"asdf"`);
|
||||
});
|
||||
|
||||
test("codec type enforcement - correct encode/decode signatures", () => {
|
||||
// Test that codec functions have correct type signatures
|
||||
const stringToNumberCodec = z.codec(z.string(), z.number(), {
|
||||
decode: (value: string) => Number(value), // core.output<A> -> core.input<B>
|
||||
encode: (value: number) => String(value), // core.input<B> -> core.output<A>
|
||||
});
|
||||
|
||||
// These should compile without errors - correct types (async support)
|
||||
expectTypeOf<(value: string, payload: z.core.ParsePayload<string>) => z.core.util.MaybeAsync<number>>(
|
||||
stringToNumberCodec.def.transform
|
||||
).toBeFunction();
|
||||
expectTypeOf<(value: number, payload: z.core.ParsePayload<number>) => z.core.util.MaybeAsync<string>>(
|
||||
stringToNumberCodec.def.reverseTransform
|
||||
).toBeFunction();
|
||||
|
||||
// Test that decode parameter type is core.output<A> (string)
|
||||
const validDecode = (value: string) => Number(value);
|
||||
expectTypeOf(validDecode).toMatchTypeOf<(value: string) => number>();
|
||||
|
||||
// Test that encode parameter type is core.input<B> (number)
|
||||
const validEncode = (value: number) => String(value);
|
||||
expectTypeOf(validEncode).toMatchTypeOf<(value: number) => string>();
|
||||
|
||||
z.codec(z.string(), z.number(), {
|
||||
// @ts-expect-error - decode should NOT accept core.input<A> as parameter
|
||||
decode: (value: never, _payload) => Number(value), // Wrong: should be string, not unknown
|
||||
encode: (value: number, _payload) => String(value),
|
||||
});
|
||||
|
||||
z.codec(z.string(), z.number(), {
|
||||
decode: (value: string) => Number(value),
|
||||
// @ts-expect-error - encode should NOT accept core.output<B> as parameter
|
||||
encode: (value: never) => String(value), // Wrong: should be number, not unknown
|
||||
});
|
||||
|
||||
z.codec(z.string(), z.number(), {
|
||||
// @ts-expect-error - decode return type should be core.input<B>
|
||||
decode: (value: string) => String(value), // Wrong: should return number, not string
|
||||
encode: (value: number) => String(value),
|
||||
});
|
||||
|
||||
z.codec(z.string(), z.number(), {
|
||||
decode: (value: string) => Number(value),
|
||||
// @ts-expect-error - encode return type should be core.output<A>
|
||||
encode: (value: number) => Number(value), // Wrong: should return string, not number
|
||||
});
|
||||
});
|
||||
|
||||
test("async codec functionality", async () => {
|
||||
// Test that async encode/decode functions work properly
|
||||
const asyncCodec = z.codec(z.string(), z.number(), {
|
||||
decode: async (str) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1)); // Simulate async work
|
||||
return Number.parseFloat(str);
|
||||
},
|
||||
encode: async (num) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1)); // Simulate async work
|
||||
return num.toString();
|
||||
},
|
||||
});
|
||||
|
||||
// Test async decode/encode
|
||||
const decoded = await z.decodeAsync(asyncCodec, "42.5");
|
||||
expect(decoded).toBe(42.5);
|
||||
|
||||
const encoded = await z.encodeAsync(asyncCodec, 42.5);
|
||||
expect(encoded).toBe("42.5");
|
||||
|
||||
// Test that both sync and async work
|
||||
const mixedCodec = z.codec(z.string(), z.number(), {
|
||||
decode: async (str) => Number.parseFloat(str),
|
||||
encode: (num) => num.toString(), // sync encode
|
||||
});
|
||||
|
||||
const mixedResult = await z.decodeAsync(mixedCodec, "123");
|
||||
expect(mixedResult).toBe(123);
|
||||
});
|
||||
|
||||
test("codec type enforcement - complex types", () => {
|
||||
type User = { id: number; name: string };
|
||||
type UserInput = { id: string; name: string };
|
||||
|
||||
const userCodec = z.codec(
|
||||
z.object({ id: z.string(), name: z.string() }),
|
||||
z.object({ id: z.number(), name: z.string() }),
|
||||
{
|
||||
decode: (input: UserInput) => ({ id: Number(input.id), name: input.name }),
|
||||
encode: (user: User) => ({ id: String(user.id), name: user.name }),
|
||||
}
|
||||
);
|
||||
|
||||
// Verify correct types are inferred (async support)
|
||||
expectTypeOf<(input: UserInput, payload: z.core.ParsePayload<UserInput>) => z.core.util.MaybeAsync<User>>(
|
||||
userCodec.def.transform
|
||||
).toBeFunction();
|
||||
expectTypeOf<(user: User, payload: z.core.ParsePayload<User>) => z.core.util.MaybeAsync<UserInput>>(
|
||||
userCodec.def.reverseTransform
|
||||
).toBeFunction();
|
||||
|
||||
z.codec(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
z.object({ id: z.number(), name: z.string() }),
|
||||
{
|
||||
// @ts-expect-error - decode parameter should be UserInput, not User
|
||||
decode: (input: User) => ({ id: Number(input.id), name: input.name }), // Wrong type
|
||||
encode: (user: User) => ({ id: String(user.id), name: user.name }),
|
||||
}
|
||||
);
|
||||
|
||||
z.codec(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
z.object({ id: z.number(), name: z.string() }),
|
||||
{
|
||||
decode: (input: UserInput) => ({ id: Number(input.id), name: input.name }),
|
||||
// @ts-expect-error - encode parameter should be User, not UserInput
|
||||
encode: (user: UserInput) => ({ id: String(user.id), name: user.name }), // Wrong type
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("invertCodec", () => {
|
||||
const inverted = z.invertCodec(isoDateCodec);
|
||||
|
||||
type InvIn = z.input<typeof inverted>;
|
||||
type InvOut = z.output<typeof inverted>;
|
||||
expectTypeOf<InvIn>().toEqualTypeOf<Date>();
|
||||
expectTypeOf<InvOut>().toEqualTypeOf<string>();
|
||||
|
||||
const testDate = new Date("2024-01-15T10:30:00.000Z");
|
||||
expect(z.decode(inverted, testDate)).toBe("2024-01-15T10:30:00.000Z");
|
||||
|
||||
const encoded = z.encode(inverted, "2024-01-15T10:30:00.000Z");
|
||||
expect(encoded).toBeInstanceOf(Date);
|
||||
expect(encoded.toISOString()).toBe("2024-01-15T10:30:00.000Z");
|
||||
|
||||
const doubleInverted = z.invertCodec(z.invertCodec(isoDateCodec));
|
||||
expect(z.decode(doubleInverted, "2024-01-15T10:30:00.000Z")).toBeInstanceOf(Date);
|
||||
});
|
||||
36
node_modules/zod/src/v4/mini/tests/computed.test.ts
generated
vendored
Normal file
36
node_modules/zod/src/v4/mini/tests/computed.test.ts
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
import { util as zc } from "zod/v4/core";
|
||||
|
||||
test("min/max", () => {
|
||||
const a = z.number().check(z.minimum(5), z.minimum(6), z.minimum(7), z.maximum(10), z.maximum(11), z.maximum(12));
|
||||
|
||||
expect(a._zod.bag.minimum).toEqual(7);
|
||||
expect(a._zod.bag.maximum).toEqual(10);
|
||||
});
|
||||
|
||||
test("multipleOf", () => {
|
||||
const b = z.number().check(z.multipleOf(5));
|
||||
expect(b._zod.bag.multipleOf).toEqual(5);
|
||||
});
|
||||
|
||||
test("int64 format", () => {
|
||||
const c = z.int64();
|
||||
expect(c._zod.bag.format).toEqual("int64");
|
||||
expect(c._zod.bag.minimum).toEqual(zc.BIGINT_FORMAT_RANGES.int64[0]);
|
||||
expect(c._zod.bag.maximum).toEqual(zc.BIGINT_FORMAT_RANGES.int64[1]);
|
||||
});
|
||||
|
||||
test("int32 format", () => {
|
||||
const d = z.int32();
|
||||
expect(d._zod.bag.format).toEqual("int32");
|
||||
expect(d._zod.bag.minimum).toEqual(zc.NUMBER_FORMAT_RANGES.int32[0]);
|
||||
expect(d._zod.bag.maximum).toEqual(zc.NUMBER_FORMAT_RANGES.int32[1]);
|
||||
});
|
||||
|
||||
test("array size", () => {
|
||||
const e = z.array(z.string()).check(z.length(5));
|
||||
expect(e._zod.bag.length).toEqual(5);
|
||||
expect(e._zod.bag.minimum).toEqual(5);
|
||||
expect(e._zod.bag.maximum).toEqual(5);
|
||||
});
|
||||
22
node_modules/zod/src/v4/mini/tests/error.test.ts
generated
vendored
Normal file
22
node_modules/zod/src/v4/mini/tests/error.test.ts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
test("no locale by default", () => {
|
||||
const result = z.safeParse(z.string(), 12);
|
||||
expect(result.success).toEqual(false);
|
||||
expect(result.error!.issues.length).toEqual(1);
|
||||
expect(result.error!.issues[0].message).toEqual("Invalid input");
|
||||
});
|
||||
|
||||
test("error inheritance", () => {
|
||||
const e1 = z.string().safeParse(123).error!;
|
||||
expect(e1).toBeInstanceOf(z.core.$ZodError);
|
||||
// expect(e1).not.toBeInstanceOf(Error);
|
||||
|
||||
try {
|
||||
z.string().parse(123);
|
||||
} catch (e2) {
|
||||
expect(e2).toBeInstanceOf(z.core.$ZodRealError);
|
||||
expect(e2).toBeInstanceOf(Error);
|
||||
}
|
||||
});
|
||||
5
node_modules/zod/src/v4/mini/tests/functions.test.ts
generated
vendored
Normal file
5
node_modules/zod/src/v4/mini/tests/functions.test.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("z.function", () => {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
993
node_modules/zod/src/v4/mini/tests/index.test.ts
generated
vendored
Normal file
993
node_modules/zod/src/v4/mini/tests/index.test.ts
generated
vendored
Normal file
@@ -0,0 +1,993 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
import type { util } from "zod/v4/core";
|
||||
|
||||
test("z.boolean", () => {
|
||||
const a = z.boolean();
|
||||
expect(z.parse(a, true)).toEqual(true);
|
||||
expect(z.parse(a, false)).toEqual(false);
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, "true")).toThrow();
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<boolean>();
|
||||
});
|
||||
|
||||
test("z.bigint", () => {
|
||||
const a = z.bigint();
|
||||
expect(z.parse(a, BigInt(123))).toEqual(BigInt(123));
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
});
|
||||
|
||||
test("z.symbol", () => {
|
||||
const a = z.symbol();
|
||||
const sym = Symbol();
|
||||
expect(z.parse(a, sym)).toEqual(sym);
|
||||
expect(() => z.parse(a, "symbol")).toThrow();
|
||||
});
|
||||
|
||||
test("z.date", () => {
|
||||
const a = z.date();
|
||||
const date = new Date();
|
||||
expect(z.parse(a, date)).toEqual(date);
|
||||
expect(() => z.parse(a, "date")).toThrow();
|
||||
});
|
||||
|
||||
test("z.coerce.string", () => {
|
||||
const a = z.coerce.string();
|
||||
expect(z.parse(a, 123)).toEqual("123");
|
||||
expect(z.parse(a, true)).toEqual("true");
|
||||
expect(z.parse(a, null)).toEqual("null");
|
||||
expect(z.parse(a, undefined)).toEqual("undefined");
|
||||
});
|
||||
|
||||
test("z.coerce.number", () => {
|
||||
const a = z.coerce.number();
|
||||
expect(z.parse(a, "123")).toEqual(123);
|
||||
expect(z.parse(a, "123.45")).toEqual(123.45);
|
||||
expect(z.parse(a, true)).toEqual(1);
|
||||
expect(z.parse(a, false)).toEqual(0);
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.coerce.boolean", () => {
|
||||
const a = z.coerce.boolean();
|
||||
// test booleans
|
||||
expect(z.parse(a, true)).toEqual(true);
|
||||
expect(z.parse(a, false)).toEqual(false);
|
||||
expect(z.parse(a, "true")).toEqual(true);
|
||||
expect(z.parse(a, "false")).toEqual(true);
|
||||
expect(z.parse(a, 1)).toEqual(true);
|
||||
expect(z.parse(a, 0)).toEqual(false);
|
||||
expect(z.parse(a, {})).toEqual(true);
|
||||
expect(z.parse(a, [])).toEqual(true);
|
||||
expect(z.parse(a, undefined)).toEqual(false);
|
||||
expect(z.parse(a, null)).toEqual(false);
|
||||
expect(z.parse(a, "")).toEqual(false);
|
||||
});
|
||||
|
||||
test("z.coerce.bigint", () => {
|
||||
const a = z.coerce.bigint();
|
||||
expect(z.parse(a, "123")).toEqual(BigInt(123));
|
||||
expect(z.parse(a, 123)).toEqual(BigInt(123));
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.coerce.date", () => {
|
||||
const a = z.coerce.date();
|
||||
const date = new Date();
|
||||
expect(z.parse(a, date.toISOString())).toEqual(date);
|
||||
expect(z.parse(a, date.getTime())).toEqual(date);
|
||||
expect(() => z.parse(a, "invalid date")).toThrow();
|
||||
});
|
||||
|
||||
test("z.iso.datetime", () => {
|
||||
const d1 = "2021-01-01T00:00:00Z";
|
||||
const d2 = "2021-01-01T00:00:00.123Z";
|
||||
const d3 = "2021-01-01T00:00:00";
|
||||
const d4 = "2021-01-01T00:00:00+07:00";
|
||||
const d5 = "bad data";
|
||||
|
||||
// local: false, offset: false, precision: null
|
||||
const a = z.iso.datetime();
|
||||
expect(z.safeParse(a, d1).success).toEqual(true);
|
||||
expect(z.safeParse(a, d2).success).toEqual(true);
|
||||
expect(z.safeParse(a, d3).success).toEqual(false);
|
||||
expect(z.safeParse(a, d4).success).toEqual(false);
|
||||
expect(z.safeParse(a, d5).success).toEqual(false);
|
||||
|
||||
const b = z.iso.datetime({ local: true });
|
||||
expect(z.safeParse(b, d1).success).toEqual(true);
|
||||
expect(z.safeParse(b, d2).success).toEqual(true);
|
||||
expect(z.safeParse(b, d3).success).toEqual(true);
|
||||
expect(z.safeParse(b, d4).success).toEqual(false);
|
||||
expect(z.safeParse(b, d5).success).toEqual(false);
|
||||
|
||||
const c = z.iso.datetime({ offset: true });
|
||||
expect(z.safeParse(c, d1).success).toEqual(true);
|
||||
expect(z.safeParse(c, d2).success).toEqual(true);
|
||||
expect(z.safeParse(c, d3).success).toEqual(false);
|
||||
expect(z.safeParse(c, d4).success).toEqual(true);
|
||||
expect(z.safeParse(c, d5).success).toEqual(false);
|
||||
|
||||
const d = z.iso.datetime({ precision: 3 });
|
||||
expect(z.safeParse(d, d1).success).toEqual(false);
|
||||
expect(z.safeParse(d, d2).success).toEqual(true);
|
||||
expect(z.safeParse(d, d3).success).toEqual(false);
|
||||
expect(z.safeParse(d, d4).success).toEqual(false);
|
||||
expect(z.safeParse(d, d5).success).toEqual(false);
|
||||
});
|
||||
|
||||
test("z.iso.date", () => {
|
||||
const d1 = "2021-01-01";
|
||||
const d2 = "bad data";
|
||||
|
||||
const a = z.iso.date();
|
||||
expect(z.safeParse(a, d1).success).toEqual(true);
|
||||
expect(z.safeParse(a, d2).success).toEqual(false);
|
||||
|
||||
const b = z.string().check(z.iso.date());
|
||||
expect(z.safeParse(b, d1).success).toEqual(true);
|
||||
expect(z.safeParse(b, d2).success).toEqual(false);
|
||||
});
|
||||
|
||||
test("z.iso.time", () => {
|
||||
const d1 = "00:00:00";
|
||||
const d2 = "00:00:00.123";
|
||||
const d3 = "bad data";
|
||||
|
||||
const a = z.iso.time();
|
||||
expect(z.safeParse(a, d1).success).toEqual(true);
|
||||
expect(z.safeParse(a, d2).success).toEqual(true);
|
||||
expect(z.safeParse(a, d3).success).toEqual(false);
|
||||
|
||||
const b = z.iso.time({ precision: 3 });
|
||||
expect(z.safeParse(b, d1).success).toEqual(false);
|
||||
expect(z.safeParse(b, d2).success).toEqual(true);
|
||||
expect(z.safeParse(b, d3).success).toEqual(false);
|
||||
|
||||
const c = z.string().check(z.iso.time());
|
||||
expect(z.safeParse(c, d1).success).toEqual(true);
|
||||
expect(z.safeParse(c, d2).success).toEqual(true);
|
||||
expect(z.safeParse(c, d3).success).toEqual(false);
|
||||
});
|
||||
|
||||
test("z.iso.duration", () => {
|
||||
const d1 = "P3Y6M4DT12H30M5S";
|
||||
const d2 = "bad data";
|
||||
|
||||
const a = z.iso.duration();
|
||||
expect(z.safeParse(a, d1).success).toEqual(true);
|
||||
expect(z.safeParse(a, d2).success).toEqual(false);
|
||||
|
||||
const b = z.string().check(z.iso.duration());
|
||||
expect(z.safeParse(b, d1).success).toEqual(true);
|
||||
expect(z.safeParse(b, d2).success).toEqual(false);
|
||||
});
|
||||
|
||||
test("z.undefined", () => {
|
||||
const a = z.undefined();
|
||||
expect(z.parse(a, undefined)).toEqual(undefined);
|
||||
expect(() => z.parse(a, "undefined")).toThrow();
|
||||
});
|
||||
|
||||
test("z.null", () => {
|
||||
const a = z.null();
|
||||
expect(z.parse(a, null)).toEqual(null);
|
||||
expect(() => z.parse(a, "null")).toThrow();
|
||||
});
|
||||
|
||||
test("z.any", () => {
|
||||
const a = z.any();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(z.parse(a, true)).toEqual(true);
|
||||
expect(z.parse(a, null)).toEqual(null);
|
||||
expect(z.parse(a, undefined)).toEqual(undefined);
|
||||
z.parse(a, {});
|
||||
z.parse(a, []);
|
||||
z.parse(a, Symbol());
|
||||
z.parse(a, new Date());
|
||||
});
|
||||
|
||||
test("z.unknown", () => {
|
||||
const a = z.unknown();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(z.parse(a, true)).toEqual(true);
|
||||
expect(z.parse(a, null)).toEqual(null);
|
||||
expect(z.parse(a, undefined)).toEqual(undefined);
|
||||
z.parse(a, {});
|
||||
z.parse(a, []);
|
||||
z.parse(a, Symbol());
|
||||
z.parse(a, new Date());
|
||||
});
|
||||
|
||||
test("z.never", () => {
|
||||
const a = z.never();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
test("z.void", () => {
|
||||
const a = z.void();
|
||||
expect(z.parse(a, undefined)).toEqual(undefined);
|
||||
expect(() => z.parse(a, null)).toThrow();
|
||||
});
|
||||
|
||||
test("z.array", () => {
|
||||
const a = z.array(z.string());
|
||||
expect(z.parse(a, ["hello", "world"])).toEqual(["hello", "world"]);
|
||||
expect(() => z.parse(a, [123])).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
test("z.union", () => {
|
||||
const a = z.union([z.string(), z.number()]);
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(() => z.parse(a, true)).toThrow();
|
||||
});
|
||||
|
||||
test("z.union([]) / z.xor([]) / z.discriminatedUnion(_, []) construct and reject all input", () => {
|
||||
for (const schema of [z.union([]), z.xor([])]) {
|
||||
const r = schema.safeParse("anything");
|
||||
expect(r.success).toEqual(false);
|
||||
if (!r.success) {
|
||||
expect(r.error.issues[0].code).toBe("invalid_union");
|
||||
expect((r.error.issues[0] as any).errors).toEqual([]);
|
||||
}
|
||||
}
|
||||
const disc = z.discriminatedUnion("type", [] as any);
|
||||
const r = disc.safeParse({ type: "x" });
|
||||
expect(r.success).toEqual(false);
|
||||
if (!r.success) {
|
||||
expect(r.error.issues[0].code).toBe("invalid_union");
|
||||
expect((r.error.issues[0] as any).errors).toEqual([]);
|
||||
expect((r.error.issues[0] as any).options).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
test("z.discriminatedUnion rejects object options missing the discriminator at type level", () => {
|
||||
// @ts-expect-error missing discriminator property
|
||||
z.discriminatedUnion("type", [z.object({ value: z.string() })]);
|
||||
});
|
||||
|
||||
test("z.intersection", () => {
|
||||
const a = z.intersection(z.object({ a: z.string() }), z.object({ b: z.number() }));
|
||||
expect(z.parse(a, { a: "hello", b: 123 })).toEqual({ a: "hello", b: 123 });
|
||||
expect(() => z.parse(a, { a: "hello" })).toThrow();
|
||||
expect(() => z.parse(a, { b: 123 })).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
test("z.tuple", () => {
|
||||
const a = z.tuple([z.string(), z.number()]);
|
||||
expect(z.parse(a, ["hello", 123])).toEqual(["hello", 123]);
|
||||
expect(() => z.parse(a, ["hello", "world"])).toThrow();
|
||||
expect(() => z.parse(a, [123, 456])).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
|
||||
// tuple with rest
|
||||
const b = z.tuple([z.string(), z.number(), z.optional(z.string())], z.boolean());
|
||||
type b = z.output<typeof b>;
|
||||
|
||||
expectTypeOf<b>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
const datas = [
|
||||
["hello", 123],
|
||||
["hello", 123, "world"],
|
||||
["hello", 123, "world", true],
|
||||
["hello", 123, "world", true, false, true],
|
||||
];
|
||||
for (const data of datas) {
|
||||
expect(z.parse(b, data)).toEqual(data);
|
||||
}
|
||||
|
||||
expect(() => z.parse(b, ["hello", 123, 123])).toThrow();
|
||||
expect(() => z.parse(b, ["hello", 123, "world", 123])).toThrow();
|
||||
|
||||
// tuple with readonly args
|
||||
const cArgs = [z.string(), z.number(), z.optional(z.string())] as const;
|
||||
const c = z.tuple(cArgs, z.boolean());
|
||||
type c = z.output<typeof c>;
|
||||
expectTypeOf<c>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
});
|
||||
|
||||
test("z.record", () => {
|
||||
// record schema with enum keys
|
||||
const a = z.record(z.string(), z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<Record<string, string>>();
|
||||
|
||||
const b = z.record(z.union([z.string(), z.number(), z.symbol()]), z.string());
|
||||
type b = z.output<typeof b>;
|
||||
expectTypeOf<b>().toEqualTypeOf<Record<string | number | symbol, string>>();
|
||||
expect(z.parse(b, { a: "hello", 1: "world", [Symbol.for("asdf")]: "symbol" })).toEqual({
|
||||
a: "hello",
|
||||
1: "world",
|
||||
[Symbol.for("asdf")]: "symbol",
|
||||
});
|
||||
|
||||
// enum keys
|
||||
const c = z.record(z.enum(["a", "b", "c"]), z.string());
|
||||
type c = z.output<typeof c>;
|
||||
expectTypeOf<c>().toEqualTypeOf<Record<"a" | "b" | "c", string>>();
|
||||
expect(z.parse(c, { a: "hello", b: "world", c: "world" })).toEqual({
|
||||
a: "hello",
|
||||
b: "world",
|
||||
c: "world",
|
||||
});
|
||||
// missing keys
|
||||
expect(() => z.parse(c, { a: "hello", b: "world" })).toThrow();
|
||||
// extra keys
|
||||
expect(() => z.parse(c, { a: "hello", b: "world", c: "world", d: "world" })).toThrow();
|
||||
|
||||
// literal union keys
|
||||
const d = z.record(z.union([z.literal("a"), z.literal(0)]), z.string());
|
||||
type d = z.output<typeof d>;
|
||||
expectTypeOf<d>().toEqualTypeOf<Record<"a" | 0, string>>();
|
||||
expect(z.parse(d, { a: "hello", 0: "world" })).toEqual({
|
||||
a: "hello",
|
||||
0: "world",
|
||||
});
|
||||
|
||||
// TypeScript enum keys
|
||||
enum Enum {
|
||||
A = 0,
|
||||
B = "hi",
|
||||
}
|
||||
|
||||
const e = z.record(z.enum(Enum), z.string());
|
||||
type e = z.output<typeof e>;
|
||||
expectTypeOf<e>().toEqualTypeOf<Record<Enum, string>>();
|
||||
expect(z.parse(e, { [Enum.A]: "hello", [Enum.B]: "world" })).toEqual({
|
||||
[Enum.A]: "hello",
|
||||
[Enum.B]: "world",
|
||||
});
|
||||
|
||||
// v3-compat single-arg form: z.record(valueType) defaults keyType to z.string()
|
||||
const f = (z.record as any)(z.number());
|
||||
expect(f._zod.def.keyType._zod.def.type).toEqual("string");
|
||||
expect(f._zod.def.valueType._zod.def.type).toEqual("number");
|
||||
expect(z.parse(f, { a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
||||
});
|
||||
|
||||
test("z.map", () => {
|
||||
const a = z.map(z.string(), z.number());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<Map<string, number>>();
|
||||
expect(z.parse(a, new Map([["hello", 123]]))).toEqual(new Map([["hello", 123]]));
|
||||
expect(() => z.parse(a, new Map([["hello", "world"]]))).toThrow();
|
||||
expect(() => z.parse(a, new Map([[1243, "world"]]))).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
|
||||
const r1 = z.safeParse(a, new Map([[123, 123]]));
|
||||
expect(r1.error?.issues[0].code).toEqual("invalid_type");
|
||||
expect(r1.error?.issues[0].path).toEqual([123]);
|
||||
|
||||
const r2: any = z.safeParse(a, new Map([[BigInt(123), 123]]));
|
||||
expect(r2.error!.issues[0].code).toEqual("invalid_key");
|
||||
expect(r2.error!.issues[0].path).toEqual([]);
|
||||
|
||||
const r3: any = z.safeParse(a, new Map([["hello", "world"]]));
|
||||
expect(r3.error!.issues[0].code).toEqual("invalid_type");
|
||||
expect(r3.error!.issues[0].path).toEqual(["hello"]);
|
||||
});
|
||||
|
||||
test("z.map invalid_element", () => {
|
||||
const a = z.map(z.bigint(), z.number());
|
||||
const r1 = z.safeParse(a, new Map([[BigInt(123), BigInt(123)]]));
|
||||
|
||||
expect(r1.error!.issues[0].code).toEqual("invalid_element");
|
||||
expect(r1.error!.issues[0].path).toEqual([]);
|
||||
});
|
||||
|
||||
test("z.map async", async () => {
|
||||
const a = z.map(z.string().check(z.refine(async () => true)), z.number().check(z.refine(async () => true)));
|
||||
const d1 = new Map([["hello", 123]]);
|
||||
expect(await z.parseAsync(a, d1)).toEqual(d1);
|
||||
|
||||
await expect(z.parseAsync(a, new Map([[123, 123]]))).rejects.toThrow();
|
||||
await expect(z.parseAsync(a, new Map([["hi", "world"]]))).rejects.toThrow();
|
||||
await expect(z.parseAsync(a, new Map([[1243, "world"]]))).rejects.toThrow();
|
||||
await expect(z.parseAsync(a, "hello")).rejects.toThrow();
|
||||
|
||||
const r = await z.safeParseAsync(a, new Map([[123, 123]]));
|
||||
expect(r.success).toEqual(false);
|
||||
expect(r.error!.issues[0].code).toEqual("invalid_type");
|
||||
expect(r.error!.issues[0].path).toEqual([123]);
|
||||
});
|
||||
|
||||
test("z.set", () => {
|
||||
const a = z.set(z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<Set<string>>();
|
||||
expect(z.parse(a, new Set(["hello", "world"]))).toEqual(new Set(["hello", "world"]));
|
||||
expect(() => z.parse(a, new Set([123]))).toThrow();
|
||||
expect(() => z.parse(a, ["hello", "world"])).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
|
||||
const b = z.set(z.number());
|
||||
expect(z.parse(b, new Set([1, 2, 3]))).toEqual(new Set([1, 2, 3]));
|
||||
expect(() => z.parse(b, new Set(["hello"]))).toThrow();
|
||||
expect(() => z.parse(b, [1, 2, 3])).toThrow();
|
||||
expect(() => z.parse(b, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.enum", () => {
|
||||
const a = z.enum(["A", "B", "C"]);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<"A" | "B" | "C">();
|
||||
expect(z.parse(a, "A")).toEqual("A");
|
||||
expect(z.parse(a, "B")).toEqual("B");
|
||||
expect(z.parse(a, "C")).toEqual("C");
|
||||
expect(() => z.parse(a, "D")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
// expect(a.enum.A).toEqual("A");
|
||||
// expect(a.enum.B).toEqual("B");
|
||||
// expect(a.enum.C).toEqual("C");
|
||||
// expect((a.enum as any).D).toEqual(undefined);
|
||||
});
|
||||
|
||||
test("z.enum - native", () => {
|
||||
enum NativeEnum {
|
||||
A = "A",
|
||||
B = "B",
|
||||
C = "C",
|
||||
}
|
||||
const a = z.enum(NativeEnum);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<NativeEnum>();
|
||||
expect(z.parse(a, NativeEnum.A)).toEqual(NativeEnum.A);
|
||||
expect(z.parse(a, NativeEnum.B)).toEqual(NativeEnum.B);
|
||||
expect(z.parse(a, NativeEnum.C)).toEqual(NativeEnum.C);
|
||||
expect(() => z.parse(a, "D")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
// test a.enum
|
||||
a;
|
||||
// expect(a.enum.A).toEqual(NativeEnum.A);
|
||||
// expect(a.enum.B).toEqual(NativeEnum.B);
|
||||
// expect(a.enum.C).toEqual(NativeEnum.C);
|
||||
});
|
||||
|
||||
test("z.nativeEnum", () => {
|
||||
enum NativeEnum {
|
||||
A = "A",
|
||||
B = "B",
|
||||
C = "C",
|
||||
}
|
||||
const a = z.nativeEnum(NativeEnum);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<NativeEnum>();
|
||||
expect(z.parse(a, NativeEnum.A)).toEqual(NativeEnum.A);
|
||||
expect(z.parse(a, NativeEnum.B)).toEqual(NativeEnum.B);
|
||||
expect(z.parse(a, NativeEnum.C)).toEqual(NativeEnum.C);
|
||||
expect(() => z.parse(a, "D")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
// test a.enum
|
||||
a;
|
||||
// expect(a.enum.A).toEqual(NativeEnum.A);
|
||||
// expect(a.enum.B).toEqual(NativeEnum.B);
|
||||
// expect(a.enum.C).toEqual(NativeEnum.C);
|
||||
});
|
||||
|
||||
test("z.literal", () => {
|
||||
const a = z.literal("hello");
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<"hello">();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, "world")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
z.literal(["adf"] as const);
|
||||
});
|
||||
|
||||
test("z.file", () => {
|
||||
const a = z.file();
|
||||
const file = new File(["content"], "filename.txt", { type: "text/plain" });
|
||||
expect(z.parse(a, file)).toEqual(file);
|
||||
expect(() => z.parse(a, "file")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.transform", () => {
|
||||
const a = z.pipe(
|
||||
z.string(),
|
||||
z.transform((val) => val.toUpperCase())
|
||||
);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, "hello")).toEqual("HELLO");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.transform async", async () => {
|
||||
const a = z.pipe(
|
||||
z.string(),
|
||||
z.transform(async (val) => val.toUpperCase())
|
||||
);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(await z.parseAsync(a, "hello")).toEqual("HELLO");
|
||||
await expect(() => z.parseAsync(a, 123)).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("z.preprocess", () => {
|
||||
const a = z.pipe(
|
||||
z.transform((val) => String(val).toUpperCase()),
|
||||
z.string()
|
||||
);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, 123)).toEqual("123");
|
||||
expect(z.parse(a, true)).toEqual("TRUE");
|
||||
expect(z.parse(a, BigInt(1234))).toEqual("1234");
|
||||
// expect(() => z.parse(a, Symbol("asdf"))).toThrow();
|
||||
});
|
||||
|
||||
// test("z.preprocess async", () => {
|
||||
// const a = z.preprocess(async (val) => String(val), z.string());
|
||||
// type a = z.output<typeof a>;
|
||||
// expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
// expect(z.parse(a, 123)).toEqual("123");
|
||||
// expect(z.parse(a, true)).toEqual("true");
|
||||
// expect(() => z.parse(a, {})).toThrow();
|
||||
// });
|
||||
|
||||
test("z.optional", () => {
|
||||
const a = z.optional(z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string | undefined>();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, undefined)).toEqual(undefined);
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.nullable", () => {
|
||||
const a = z.nullable(z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string | null>();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, null)).toEqual(null);
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.default", () => {
|
||||
const a = z._default(z.string(), "default");
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, undefined)).toEqual("default");
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
const b = z._default(z.string(), () => "default");
|
||||
expect(z.parse(b, undefined)).toEqual("default");
|
||||
expect(z.parse(b, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(b, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.catch", () => {
|
||||
const a = z.catch(z.string(), "default");
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, 123)).toEqual("default");
|
||||
|
||||
const b = z.catch(z.string(), () => "default");
|
||||
expect(z.parse(b, "hello")).toEqual("hello");
|
||||
expect(z.parse(b, 123)).toEqual("default");
|
||||
|
||||
const c = z.catch(z.string(), (ctx) => {
|
||||
return `${ctx.error.issues.length}issues`;
|
||||
});
|
||||
expect(z.parse(c, 1234)).toEqual("1issues");
|
||||
});
|
||||
|
||||
test("z.nan", () => {
|
||||
const a = z.nan();
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<number>();
|
||||
expect(z.parse(a, Number.NaN)).toEqual(Number.NaN);
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, "NaN")).toThrow();
|
||||
});
|
||||
|
||||
test("z.pipe", () => {
|
||||
const a = z.pipe(
|
||||
z.pipe(
|
||||
z.string(),
|
||||
z.transform((val) => val.length)
|
||||
),
|
||||
z.number()
|
||||
);
|
||||
type a_in = z.input<typeof a>;
|
||||
expectTypeOf<a_in>().toEqualTypeOf<string>();
|
||||
type a_out = z.output<typeof a>;
|
||||
expectTypeOf<a_out>().toEqualTypeOf<number>();
|
||||
|
||||
expect(z.parse(a, "123")).toEqual(3);
|
||||
expect(z.parse(a, "hello")).toEqual(5);
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.readonly", () => {
|
||||
const a = z.readonly(z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<Readonly<string>>();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.templateLiteral", () => {
|
||||
const a = z.templateLiteral([z.string(), z.number()]);
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<`${string}${number}`>();
|
||||
expect(z.parse(a, "hello123")).toEqual("hello123");
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
// multipart
|
||||
const b = z.templateLiteral([z.string(), z.number(), z.string()]);
|
||||
type b = z.output<typeof b>;
|
||||
expectTypeOf<b>().toEqualTypeOf<`${string}${number}${string}`>();
|
||||
expect(z.parse(b, "hello123world")).toEqual("hello123world");
|
||||
expect(z.parse(b, "123")).toEqual("123");
|
||||
expect(() => z.parse(b, "hello")).toThrow();
|
||||
expect(() => z.parse(b, 123)).toThrow();
|
||||
|
||||
// include boolean
|
||||
const c = z.templateLiteral([z.string(), z.boolean()]);
|
||||
type c = z.output<typeof c>;
|
||||
expectTypeOf<c>().toEqualTypeOf<`${string}${boolean}`>();
|
||||
expect(z.parse(c, "hellotrue")).toEqual("hellotrue");
|
||||
expect(z.parse(c, "hellofalse")).toEqual("hellofalse");
|
||||
expect(() => z.parse(c, "hello")).toThrow();
|
||||
expect(() => z.parse(c, 123)).toThrow();
|
||||
|
||||
// include literal prefix
|
||||
const d = z.templateLiteral([z.literal("hello"), z.number()]);
|
||||
type d = z.output<typeof d>;
|
||||
expectTypeOf<d>().toEqualTypeOf<`hello${number}`>();
|
||||
expect(z.parse(d, "hello123")).toEqual("hello123");
|
||||
expect(() => z.parse(d, 123)).toThrow();
|
||||
expect(() => z.parse(d, "world123")).toThrow();
|
||||
|
||||
// include literal union
|
||||
const e = z.templateLiteral([z.literal(["aa", "bb"]), z.number()]);
|
||||
type e = z.output<typeof e>;
|
||||
expectTypeOf<e>().toEqualTypeOf<`aa${number}` | `bb${number}`>();
|
||||
expect(z.parse(e, "aa123")).toEqual("aa123");
|
||||
expect(z.parse(e, "bb123")).toEqual("bb123");
|
||||
expect(() => z.parse(e, "cc123")).toThrow();
|
||||
expect(() => z.parse(e, 123)).toThrow();
|
||||
});
|
||||
|
||||
// this returns both a schema and a check
|
||||
test("z.custom", () => {
|
||||
const a = z.custom((val) => {
|
||||
return typeof val === "string";
|
||||
});
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
const b = z.string().check(z.custom((val) => val.length > 3));
|
||||
|
||||
expect(z.parse(b, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(b, "hi")).toThrow();
|
||||
});
|
||||
|
||||
test("z.check", () => {
|
||||
// this is a more flexible version of z.custom that accepts an arbitrary _parse logic
|
||||
// the function should return core.$ZodResult
|
||||
const a = z.any().check(
|
||||
z.check<string>((ctx) => {
|
||||
if (typeof ctx.value === "string") return;
|
||||
ctx.issues.push({
|
||||
code: "custom",
|
||||
origin: "custom",
|
||||
message: "Expected a string",
|
||||
input: ctx.value,
|
||||
});
|
||||
})
|
||||
);
|
||||
expect(z.safeParse(a, "hello")).toMatchObject({
|
||||
success: true,
|
||||
data: "hello",
|
||||
});
|
||||
expect(z.safeParse(a, 123)).toMatchObject({
|
||||
success: false,
|
||||
error: { issues: [{ code: "custom", message: "Expected a string" }] },
|
||||
});
|
||||
});
|
||||
|
||||
test("z.with (alias for z.check)", () => {
|
||||
// .with() should work exactly the same as .check()
|
||||
const a = z.any().with(
|
||||
z.check<string>((ctx) => {
|
||||
if (typeof ctx.value === "string") return;
|
||||
ctx.issues.push({
|
||||
code: "custom",
|
||||
origin: "custom",
|
||||
message: "Expected a string",
|
||||
input: ctx.value,
|
||||
});
|
||||
})
|
||||
);
|
||||
expect(z.safeParse(a, "hello")).toMatchObject({
|
||||
success: true,
|
||||
data: "hello",
|
||||
});
|
||||
expect(z.safeParse(a, 123)).toMatchObject({
|
||||
success: false,
|
||||
error: { issues: [{ code: "custom", message: "Expected a string" }] },
|
||||
});
|
||||
|
||||
// Test with refine
|
||||
const b = z.string().with(z.refine((val) => val.length > 3, "Must be longer than 3"));
|
||||
expect(z.safeParse(b, "hello").success).toBe(true);
|
||||
expect(z.safeParse(b, "hi").success).toBe(false);
|
||||
|
||||
// Test with function
|
||||
const c = z.string().with(({ value, issues }) => {
|
||||
if (value.length <= 3) {
|
||||
issues.push({
|
||||
code: "custom",
|
||||
input: value,
|
||||
message: "Must be longer than 3",
|
||||
});
|
||||
}
|
||||
});
|
||||
expect(z.safeParse(c, "hello").success).toBe(true);
|
||||
expect(z.safeParse(c, "hi").success).toBe(false);
|
||||
});
|
||||
|
||||
test("z.instanceof", () => {
|
||||
class A {}
|
||||
|
||||
const a = z.instanceof(A);
|
||||
expect(z.parse(a, new A())).toBeInstanceOf(A);
|
||||
expect(() => z.parse(a, {})).toThrow();
|
||||
});
|
||||
|
||||
test("z.refine", () => {
|
||||
const a = z.number().check(
|
||||
z.refine((val) => val > 3),
|
||||
z.refine((val) => val < 10)
|
||||
);
|
||||
expect(z.parse(a, 5)).toEqual(5);
|
||||
expect(() => z.parse(a, 2)).toThrow();
|
||||
expect(() => z.parse(a, 11)).toThrow();
|
||||
expect(() => z.parse(a, "hi")).toThrow();
|
||||
});
|
||||
|
||||
// test("z.superRefine", () => {
|
||||
// const a = z.number([
|
||||
// z.superRefine((val, ctx) => {
|
||||
// if (val < 3) {
|
||||
// return ctx.addIssue({
|
||||
// code: "custom",
|
||||
// origin: "custom",
|
||||
// message: "Too small",
|
||||
// input: val,
|
||||
// });
|
||||
// }
|
||||
// if (val > 10) {
|
||||
// return ctx.addIssue("Too big");
|
||||
// }
|
||||
// }),
|
||||
// ]);
|
||||
|
||||
// expect(z.parse(a, 5)).toEqual(5);
|
||||
// expect(() => z.parse(a, 2)).toThrow();
|
||||
// expect(() => z.parse(a, 11)).toThrow();
|
||||
// expect(() => z.parse(a, "hi")).toThrow();
|
||||
// });
|
||||
|
||||
test("z.transform", () => {
|
||||
const a = z.transform((val: number) => {
|
||||
return `${val}`;
|
||||
});
|
||||
type a_in = z.input<typeof a>;
|
||||
expectTypeOf<a_in>().toEqualTypeOf<number>();
|
||||
type a_out = z.output<typeof a>;
|
||||
expectTypeOf<a_out>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, 123)).toEqual("123");
|
||||
});
|
||||
|
||||
test("z.$brand()", () => {
|
||||
const a = z.string().brand<"my-brand">();
|
||||
type a = z.output<typeof a>;
|
||||
const branded = (_: a) => {};
|
||||
// @ts-expect-error
|
||||
branded("asdf");
|
||||
});
|
||||
|
||||
test("z.lazy", () => {
|
||||
const a = z.lazy(() => z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
// schema that validates JSON-like data
|
||||
test("z.json", () => {
|
||||
const a = z.json();
|
||||
type a = z.output<typeof a>;
|
||||
a._zod.output;
|
||||
|
||||
expectTypeOf<a>().toEqualTypeOf<util.JSONType>();
|
||||
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(z.parse(a, true)).toEqual(true);
|
||||
expect(z.parse(a, null)).toEqual(null);
|
||||
expect(z.parse(a, {})).toEqual({});
|
||||
expect(z.parse(a, { a: "hello" })).toEqual({ a: "hello" });
|
||||
expect(z.parse(a, [1, 2, 3])).toEqual([1, 2, 3]);
|
||||
expect(z.parse(a, [{ a: "hello" }])).toEqual([{ a: "hello" }]);
|
||||
|
||||
// fail cases
|
||||
expect(() => z.parse(a, new Date())).toThrow();
|
||||
expect(() => z.parse(a, Symbol())).toThrow();
|
||||
expect(() => z.parse(a, { a: new Date() })).toThrow();
|
||||
expect(() => z.parse(a, undefined)).toThrow();
|
||||
expect(() => z.parse(a, { a: undefined })).toThrow();
|
||||
});
|
||||
|
||||
test("z.stringbool", () => {
|
||||
const a = z.stringbool();
|
||||
|
||||
expect(z.parse(a, "true")).toEqual(true);
|
||||
expect(z.parse(a, "yes")).toEqual(true);
|
||||
expect(z.parse(a, "1")).toEqual(true);
|
||||
expect(z.parse(a, "on")).toEqual(true);
|
||||
expect(z.parse(a, "y")).toEqual(true);
|
||||
expect(z.parse(a, "enabled")).toEqual(true);
|
||||
expect(z.parse(a, "TRUE")).toEqual(true);
|
||||
|
||||
expect(z.parse(a, "false")).toEqual(false);
|
||||
expect(z.parse(a, "no")).toEqual(false);
|
||||
expect(z.parse(a, "0")).toEqual(false);
|
||||
expect(z.parse(a, "off")).toEqual(false);
|
||||
expect(z.parse(a, "n")).toEqual(false);
|
||||
expect(z.parse(a, "disabled")).toEqual(false);
|
||||
expect(z.parse(a, "FALSE")).toEqual(false);
|
||||
|
||||
expect(z.safeParse(a, "other")).toMatchObject({ success: false });
|
||||
expect(z.safeParse(a, "")).toMatchObject({ success: false });
|
||||
expect(z.safeParse(a, undefined)).toMatchObject({ success: false });
|
||||
expect(z.safeParse(a, {})).toMatchObject({ success: false });
|
||||
expect(z.safeParse(a, true)).toMatchObject({ success: false });
|
||||
expect(z.safeParse(a, false)).toMatchObject({ success: false });
|
||||
|
||||
const b = z.stringbool({
|
||||
truthy: ["y"],
|
||||
falsy: ["n"],
|
||||
});
|
||||
expect(z.parse(b, "y")).toEqual(true);
|
||||
expect(z.parse(b, "n")).toEqual(false);
|
||||
expect(z.safeParse(b, "true")).toMatchObject({ success: false });
|
||||
expect(z.safeParse(b, "false")).toMatchObject({ success: false });
|
||||
|
||||
const c = z.stringbool({
|
||||
case: "sensitive",
|
||||
});
|
||||
expect(z.parse(c, "true")).toEqual(true);
|
||||
expect(z.safeParse(c, "TRUE")).toMatchObject({ success: false });
|
||||
});
|
||||
|
||||
// promise
|
||||
test("z.promise", async () => {
|
||||
const a = z.promise(z.string());
|
||||
type a = z.output<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<Promise<string>>();
|
||||
|
||||
expect(await z.safeParseAsync(a, Promise.resolve("hello"))).toMatchObject({
|
||||
success: true,
|
||||
data: "hello",
|
||||
});
|
||||
expect(await z.safeParseAsync(a, Promise.resolve(123))).toMatchObject({
|
||||
success: false,
|
||||
});
|
||||
|
||||
const b = z.string();
|
||||
expect(() => z.parse(b, Promise.resolve("hello"))).toThrow();
|
||||
});
|
||||
|
||||
// test("type assertions", () => {
|
||||
// const schema = z.pipe(
|
||||
// z.string(),
|
||||
// z.transform((val) => val.length)
|
||||
// );
|
||||
// schema.assertInput<string>();
|
||||
// // @ts-expect-error
|
||||
// schema.assertInput<number>();
|
||||
|
||||
// schema.assertOutput<number>();
|
||||
// // @ts-expect-error
|
||||
// schema.assertOutput<string>();
|
||||
// });
|
||||
|
||||
test("z.pipe type enforcement", () => {
|
||||
z.pipe(
|
||||
z.pipe(
|
||||
z.string().check(z.regex(/asdf/)),
|
||||
z.transform((v) => new Date(v))
|
||||
),
|
||||
z.date().check(z.maximum(new Date()))
|
||||
);
|
||||
});
|
||||
|
||||
test("def typing", () => {
|
||||
z.string().def.type satisfies "string";
|
||||
z.email().def.format satisfies "email";
|
||||
z.number().def.type satisfies "number";
|
||||
z.float64().def.format satisfies z.core.$ZodNumberFormats;
|
||||
z.bigint().def.type satisfies "bigint";
|
||||
z.boolean().def.type satisfies "boolean";
|
||||
z.date().def.type satisfies "date";
|
||||
z.symbol().def.type satisfies "symbol";
|
||||
z.undefined().def.type satisfies "undefined";
|
||||
z.nullable(z.string()).def.type satisfies "nullable";
|
||||
z.null().def.type satisfies "null";
|
||||
z.any().def.type satisfies "any";
|
||||
z.unknown().def.type satisfies "unknown";
|
||||
z.never().def.type satisfies "never";
|
||||
z.void().def.type satisfies "void";
|
||||
z.array(z.string()).def.type satisfies "array";
|
||||
z.object({ key: z.string() }).def.type satisfies "object";
|
||||
z.union([z.string(), z.number()]).def.type satisfies "union";
|
||||
z.intersection(z.string(), z.number()).def.type satisfies "intersection";
|
||||
z.tuple([z.string(), z.number()]).def.type satisfies "tuple";
|
||||
z.record(z.string(), z.number()).def.type satisfies "record";
|
||||
z.map(z.string(), z.number()).def.type satisfies "map";
|
||||
z.set(z.string()).def.type satisfies "set";
|
||||
z.literal("example").def.type satisfies "literal";
|
||||
expectTypeOf(z.literal("example").def.values).toEqualTypeOf<"example"[]>();
|
||||
z.enum(["a", "b", "c"]).def.type satisfies "enum";
|
||||
z.promise(z.string()).def.type satisfies "promise";
|
||||
z.lazy(() => z.string()).def.type satisfies "lazy";
|
||||
z.optional(z.string()).def.type satisfies "optional";
|
||||
z._default(z.string(), "default").def.type satisfies "default";
|
||||
z.templateLiteral([z.literal("a"), z.literal("b")]).def.type satisfies "template_literal";
|
||||
z.custom<string>((val) => typeof val === "string").def.type satisfies "custom";
|
||||
z.transform((val) => val as string).def.type satisfies "transform";
|
||||
z.nonoptional(z.string()).def.type satisfies "nonoptional";
|
||||
z.readonly(z.unknown()).def.type satisfies "readonly";
|
||||
z.nan().def.type satisfies "nan";
|
||||
z.pipe(z.unknown(), z.number()).def.type satisfies "pipe";
|
||||
z.success(z.string()).def.type satisfies "success";
|
||||
z.catch(z.string(), "fallback").def.type satisfies "catch";
|
||||
z.file().def.type satisfies "file";
|
||||
});
|
||||
|
||||
test("defaulted object schema returns shallow clone", () => {
|
||||
const schema = z._default(
|
||||
z.object({
|
||||
a: z.string(),
|
||||
}),
|
||||
{ a: "x" }
|
||||
);
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
expect(result1).not.toBe(result2);
|
||||
expect(result1).toEqual(result2);
|
||||
});
|
||||
|
||||
test("runtime type property exists and returns correct values", () => {
|
||||
const stringSchema = z.string();
|
||||
expect(stringSchema.type).toBe("string");
|
||||
});
|
||||
|
||||
test("type narrowing works with type property", () => {
|
||||
type ArrayOrRecord = z.ZodMiniArray<z.ZodMiniString> | z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniAny>;
|
||||
const arraySchema = z.array(z.string()) as ArrayOrRecord;
|
||||
|
||||
if (arraySchema.type === "array") {
|
||||
expectTypeOf(arraySchema).toEqualTypeOf<z.ZodMiniArray<z.ZodMiniString<unknown>>>();
|
||||
expect(arraySchema.def.element).toBeDefined();
|
||||
}
|
||||
});
|
||||
95
node_modules/zod/src/v4/mini/tests/number.test.ts
generated
vendored
Normal file
95
node_modules/zod/src/v4/mini/tests/number.test.ts
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
test("z.number", () => {
|
||||
const a = z.number();
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(z.parse(a, 123.45)).toEqual(123.45);
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
|
||||
type a = z.infer<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<number>();
|
||||
});
|
||||
|
||||
test("z.number async", async () => {
|
||||
const a = z.number().check(z.refine(async (_) => _ > 0));
|
||||
await expect(z.parseAsync(a, 123)).resolves.toEqual(123);
|
||||
await expect(() => z.parseAsync(a, -123)).rejects.toThrow();
|
||||
await expect(() => z.parseAsync(a, "123")).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("z.int", () => {
|
||||
const a = z.int();
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(() => z.parse(a, 123.45)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
});
|
||||
|
||||
test("z.float32", () => {
|
||||
const a = z.float32();
|
||||
expect(z.parse(a, 123.45)).toEqual(123.45);
|
||||
expect(() => z.parse(a, "123.45")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
// -3.4028234663852886e38, 3.4028234663852886e38;
|
||||
expect(() => z.parse(a, 3.4028234663852886e38 * 2)).toThrow(); // Exceeds max
|
||||
expect(() => z.parse(a, -3.4028234663852886e38 * 2)).toThrow(); // Exceeds min
|
||||
});
|
||||
|
||||
test("z.float64", () => {
|
||||
const a = z.float64();
|
||||
expect(z.parse(a, 123.45)).toEqual(123.45);
|
||||
expect(() => z.parse(a, "123.45")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
expect(() => z.parse(a, 1.7976931348623157e308 * 2)).toThrow(); // Exceeds max
|
||||
expect(() => z.parse(a, -1.7976931348623157e308 * 2)).toThrow(); // Exceeds min
|
||||
});
|
||||
|
||||
test("z.int32", () => {
|
||||
const a = z.int32();
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(() => z.parse(a, 123.45)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
expect(() => z.parse(a, 2147483648)).toThrow(); // Exceeds max
|
||||
expect(() => z.parse(a, -2147483649)).toThrow(); // Exceeds min
|
||||
});
|
||||
|
||||
test("z.uint32", () => {
|
||||
const a = z.uint32();
|
||||
expect(z.parse(a, 123)).toEqual(123);
|
||||
expect(() => z.parse(a, -123)).toThrow();
|
||||
expect(() => z.parse(a, 123.45)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
expect(() => z.parse(a, 4294967296)).toThrow(); // Exceeds max
|
||||
expect(() => z.parse(a, -1)).toThrow(); // Below min
|
||||
});
|
||||
|
||||
test("z.int64", () => {
|
||||
const a = z.int64();
|
||||
expect(z.parse(a, BigInt(123))).toEqual(BigInt(123));
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, 123.45)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
expect(() => z.parse(a, BigInt("9223372036854775808"))).toThrow();
|
||||
expect(() => z.parse(a, BigInt("-9223372036854775809"))).toThrow();
|
||||
// expect(() => z.parse(a, BigInt("9223372036854775808"))).toThrow(); // Exceeds max
|
||||
// expect(() => z.parse(a, BigInt("-9223372036854775809"))).toThrow(); // Exceeds min
|
||||
});
|
||||
|
||||
test("z.uint64", () => {
|
||||
const a = z.uint64();
|
||||
expect(z.parse(a, BigInt(123))).toEqual(BigInt(123));
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, -123)).toThrow();
|
||||
expect(() => z.parse(a, 123.45)).toThrow();
|
||||
expect(() => z.parse(a, "123")).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
expect(() => z.parse(a, BigInt("18446744073709551616"))).toThrow(); // Exceeds max
|
||||
expect(() => z.parse(a, BigInt("-1"))).toThrow(); // Below min
|
||||
// expect(() => z.parse(a, BigInt("18446744073709551616"))).toThrow(); // Exceeds max
|
||||
// expect(() => z.parse(a, BigInt("-1"))).toThrow(); // Below min
|
||||
});
|
||||
227
node_modules/zod/src/v4/mini/tests/object.test.ts
generated
vendored
Normal file
227
node_modules/zod/src/v4/mini/tests/object.test.ts
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
test("z.object", () => {
|
||||
const a = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
points: z.optional(z.number()),
|
||||
"test?": z.boolean(),
|
||||
});
|
||||
|
||||
a._zod.def.shape["test?"];
|
||||
a._zod.def.shape.points._zod.optin;
|
||||
|
||||
type a = z.output<typeof a>;
|
||||
|
||||
expectTypeOf<a>().toEqualTypeOf<{
|
||||
name: string;
|
||||
age: number;
|
||||
points?: number | undefined;
|
||||
"test?": boolean;
|
||||
}>();
|
||||
expect(z.parse(a, { name: "john", age: 30, "test?": true })).toEqual({
|
||||
name: "john",
|
||||
age: 30,
|
||||
"test?": true,
|
||||
});
|
||||
// "test?" is required in ZodObject
|
||||
expect(() => z.parse(a, { name: "john", age: "30" })).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
|
||||
// null prototype
|
||||
const schema = z.object({ a: z.string() });
|
||||
const obj = Object.create(null);
|
||||
obj.a = "foo";
|
||||
expect(schema.parse(obj)).toEqual({ a: "foo" });
|
||||
});
|
||||
|
||||
test("z.object().check()", () => {
|
||||
const a = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
points: z.optional(z.number()),
|
||||
"test?": z.boolean(),
|
||||
});
|
||||
|
||||
type a = z.output<typeof a>;
|
||||
|
||||
a.check(({ value }) => {
|
||||
expectTypeOf(value).toEqualTypeOf<a>();
|
||||
});
|
||||
});
|
||||
|
||||
test("z.strictObject", () => {
|
||||
const a = z.strictObject({
|
||||
name: z.string(),
|
||||
});
|
||||
expect(z.parse(a, { name: "john" })).toEqual({ name: "john" });
|
||||
expect(() => z.parse(a, { name: "john", age: 30 })).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
test("z.looseObject", () => {
|
||||
const a = z.looseObject({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
});
|
||||
expect(z.parse(a, { name: "john", age: 30 })).toEqual({
|
||||
name: "john",
|
||||
age: 30,
|
||||
});
|
||||
expect(z.parse(a, { name: "john", age: 30, extra: true })).toEqual({
|
||||
name: "john",
|
||||
age: 30,
|
||||
extra: true,
|
||||
});
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
const userSchema = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
email: z.optional(z.string()),
|
||||
});
|
||||
|
||||
test("z.keyof", () => {
|
||||
// z.keyof returns an enum schema of the keys of an object schema
|
||||
const userKeysSchema = z.keyof(userSchema);
|
||||
type UserKeys = z.infer<typeof userKeysSchema>;
|
||||
expectTypeOf<UserKeys>().toEqualTypeOf<"name" | "age" | "email">();
|
||||
expect(userKeysSchema).toBeDefined();
|
||||
expect(userKeysSchema._zod.def.type).toBe("enum");
|
||||
expect(userKeysSchema._zod.def.entries).toEqual({
|
||||
name: "name",
|
||||
age: "age",
|
||||
email: "email",
|
||||
});
|
||||
expect(z.safeParse(userKeysSchema, "name").success).toBe(true);
|
||||
expect(z.safeParse(userKeysSchema, "age").success).toBe(true);
|
||||
expect(z.safeParse(userKeysSchema, "email").success).toBe(true);
|
||||
expect(z.safeParse(userKeysSchema, "isAdmin").success).toBe(false);
|
||||
});
|
||||
|
||||
test("z.extend", () => {
|
||||
const extendedSchema = z.extend(userSchema, {
|
||||
isAdmin: z.boolean(),
|
||||
});
|
||||
type ExtendedUser = z.infer<typeof extendedSchema>;
|
||||
expectTypeOf<ExtendedUser>().toEqualTypeOf<{
|
||||
name: string;
|
||||
age: number;
|
||||
email?: string | undefined;
|
||||
isAdmin: boolean;
|
||||
}>();
|
||||
expect(extendedSchema).toBeDefined();
|
||||
expect(z.safeParse(extendedSchema, { name: "John", age: 30, isAdmin: true }).success).toBe(true);
|
||||
});
|
||||
|
||||
test("z.safeExtend", () => {
|
||||
const extended = z.safeExtend(userSchema, { name: z.string() });
|
||||
expect(z.safeParse(extended, { name: "John", age: 30 }).success).toBe(true);
|
||||
type Extended = z.infer<typeof extended>;
|
||||
expectTypeOf<Extended>().toEqualTypeOf<{ name: string; age: number; email?: string | undefined }>();
|
||||
// @ts-expect-error
|
||||
z.safeExtend(userSchema, { name: z.number() });
|
||||
});
|
||||
|
||||
test("z.pick", () => {
|
||||
const pickedSchema = z.pick(userSchema, { name: true, email: true });
|
||||
type PickedUser = z.infer<typeof pickedSchema>;
|
||||
expectTypeOf<PickedUser>().toEqualTypeOf<{ name: string; email?: string | undefined }>();
|
||||
expect(pickedSchema).toBeDefined();
|
||||
expect(z.safeParse(pickedSchema, { name: "John", email: "john@example.com" }).success).toBe(true);
|
||||
});
|
||||
|
||||
test("z.omit", () => {
|
||||
const omittedSchema = z.omit(userSchema, { age: true });
|
||||
type OmittedUser = z.infer<typeof omittedSchema>;
|
||||
expectTypeOf<OmittedUser>().toEqualTypeOf<{
|
||||
name: string;
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
expect(omittedSchema).toBeDefined();
|
||||
expect(Reflect.ownKeys(omittedSchema._zod.def.shape)).toEqual(["name", "email"]);
|
||||
expect(z.safeParse(omittedSchema, { name: "John", email: "john@example.com" }).success).toBe(true);
|
||||
});
|
||||
|
||||
test("z.partial", () => {
|
||||
const partialSchema = z.partial(userSchema);
|
||||
type PartialUser = z.infer<typeof partialSchema>;
|
||||
expectTypeOf<PartialUser>().toEqualTypeOf<{
|
||||
name?: string | undefined;
|
||||
age?: number | undefined;
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
expect(z.safeParse(partialSchema, { name: "John" }).success).toBe(true);
|
||||
});
|
||||
|
||||
test("z.partial with mask", () => {
|
||||
const partialSchemaWithMask = z.partial(userSchema, { name: true });
|
||||
type PartialUserWithMask = z.infer<typeof partialSchemaWithMask>;
|
||||
expectTypeOf<PartialUserWithMask>().toEqualTypeOf<{
|
||||
name?: string | undefined;
|
||||
age: number;
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
expect(z.safeParse(partialSchemaWithMask, { age: 30 }).success).toBe(true);
|
||||
expect(z.safeParse(partialSchemaWithMask, { name: "John" }).success).toBe(false);
|
||||
});
|
||||
|
||||
test("z.pick/omit/partial/required - do not allow unknown keys", () => {
|
||||
const schema = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
});
|
||||
|
||||
// Mixed valid + invalid keys - throws at parse time (lazy evaluation)
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.pick(schema, { name: true, asdf: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.omit(schema, { name: true, asdf: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.partial(schema, { name: true, asdf: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.required(schema, { name: true, asdf: true }), {})).toThrow();
|
||||
|
||||
// Only invalid keys
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.pick(schema, { $unknown: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.omit(schema, { $unknown: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.partial(schema, { $unknown: true }), {})).toThrow();
|
||||
// @ts-expect-error
|
||||
expect(() => z.parse(z.required(schema, { $unknown: true }), {})).toThrow();
|
||||
});
|
||||
|
||||
test("z.catchall", () => {
|
||||
// z.catchall()
|
||||
const schema = z.catchall(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
// age: z.number(),
|
||||
}),
|
||||
z.string()
|
||||
);
|
||||
|
||||
type schemaIn = z.input<typeof schema>;
|
||||
type schemaOut = z.output<typeof schema>;
|
||||
expectTypeOf<schemaIn>().toEqualTypeOf<{
|
||||
name: string;
|
||||
[key: string]: string;
|
||||
}>();
|
||||
|
||||
expectTypeOf<schemaOut>().toEqualTypeOf<{
|
||||
name: string;
|
||||
[key: string]: string;
|
||||
}>();
|
||||
|
||||
schema.parse({
|
||||
name: "john",
|
||||
age: "30",
|
||||
extra: "extra value",
|
||||
});
|
||||
|
||||
expect(() => schema.parse({ name: "john", age: 30 })).toThrow();
|
||||
});
|
||||
43
node_modules/zod/src/v4/mini/tests/prototypes.test.ts
generated
vendored
Normal file
43
node_modules/zod/src/v4/mini/tests/prototypes.test.ts
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
declare module "zod/v4/core" {
|
||||
interface $ZodType {
|
||||
/** @deprecated */
|
||||
_core(): string;
|
||||
}
|
||||
}
|
||||
|
||||
test("prototype extension", () => {
|
||||
z.core.$ZodType.prototype._core = function () {
|
||||
return "_core";
|
||||
};
|
||||
|
||||
// should pass
|
||||
const result = z.string()._core();
|
||||
expect(result).toBe("_core");
|
||||
// expectTypeOf<typeof result>().toEqualTypeOf<string>();
|
||||
|
||||
// clean up
|
||||
z.ZodMiniType.prototype._core = undefined;
|
||||
});
|
||||
|
||||
declare module "zod/v4/mini" {
|
||||
interface ZodMiniType {
|
||||
/** @deprecated */
|
||||
_mini(): string;
|
||||
}
|
||||
}
|
||||
|
||||
test("prototype extension", () => {
|
||||
z.ZodMiniType.prototype._mini = function () {
|
||||
return "_mini";
|
||||
};
|
||||
|
||||
// should pass
|
||||
const result = z.string()._mini();
|
||||
expect(result).toBe("_mini");
|
||||
|
||||
// clean up
|
||||
z.ZodMiniType.prototype._mini = undefined;
|
||||
});
|
||||
325
node_modules/zod/src/v4/mini/tests/recursive-types.test.ts
generated
vendored
Normal file
325
node_modules/zod/src/v4/mini/tests/recursive-types.test.ts
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import { z } from "zod/mini";
|
||||
|
||||
test("recursion with z.lazy", () => {
|
||||
const data = {
|
||||
name: "I",
|
||||
subcategories: [
|
||||
{
|
||||
name: "A",
|
||||
subcategories: [
|
||||
{
|
||||
name: "1",
|
||||
subcategories: [
|
||||
{
|
||||
name: "a",
|
||||
subcategories: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const Category = z.object({
|
||||
name: z.string(),
|
||||
get subcategories(): z.ZodMiniOptional<z.ZodMiniArray<typeof Category>> {
|
||||
return z.optional(z.array(Category));
|
||||
},
|
||||
});
|
||||
Category.parse(data);
|
||||
|
||||
type Category = z.infer<typeof Category>;
|
||||
interface _Category {
|
||||
name: string;
|
||||
subcategories?: _Category[] | undefined;
|
||||
}
|
||||
expectTypeOf<Category>().toEqualTypeOf<_Category>();
|
||||
});
|
||||
|
||||
test("recursion involving union type", () => {
|
||||
const data = {
|
||||
value: 1,
|
||||
next: {
|
||||
value: 2,
|
||||
next: {
|
||||
value: 3,
|
||||
next: {
|
||||
value: 4,
|
||||
next: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const LL = z.object({
|
||||
value: z.number(),
|
||||
get next(): z.ZodMiniNullable<typeof LL> {
|
||||
return z.nullable(LL);
|
||||
},
|
||||
});
|
||||
|
||||
LL.parse(data);
|
||||
type LL = z.infer<typeof LL>;
|
||||
type _LL = {
|
||||
value: number;
|
||||
next: _LL | null;
|
||||
};
|
||||
expectTypeOf<LL>().toEqualTypeOf<_LL>();
|
||||
});
|
||||
|
||||
test("mutual recursion - native", () => {
|
||||
const Alazy = z.object({
|
||||
val: z.number(),
|
||||
get b() {
|
||||
return z.optional(Blazy);
|
||||
},
|
||||
});
|
||||
|
||||
const Blazy = z.object({
|
||||
val: z.number(),
|
||||
get a() {
|
||||
return z.optional(Alazy);
|
||||
},
|
||||
});
|
||||
const testData = {
|
||||
val: 1,
|
||||
b: {
|
||||
val: 5,
|
||||
a: {
|
||||
val: 3,
|
||||
b: {
|
||||
val: 4,
|
||||
a: {
|
||||
val: 2,
|
||||
b: {
|
||||
val: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Alazy.parse(testData);
|
||||
Blazy.parse(testData.b);
|
||||
|
||||
type Alazy = z.infer<typeof Alazy>;
|
||||
type Blazy = z.infer<typeof Blazy>;
|
||||
interface _Alazy {
|
||||
val: number;
|
||||
b?: _Blazy | undefined;
|
||||
}
|
||||
interface _Blazy {
|
||||
val: number;
|
||||
a?: _Alazy | undefined;
|
||||
}
|
||||
expectTypeOf<Alazy>().toEqualTypeOf<_Alazy>();
|
||||
expectTypeOf<Blazy>().toEqualTypeOf<_Blazy>();
|
||||
|
||||
expect(() => Alazy.parse({ val: "asdf" })).toThrow();
|
||||
});
|
||||
|
||||
test("pick and omit with getter", () => {
|
||||
const Category = z.strictObject({
|
||||
name: z.string(),
|
||||
get subcategories() {
|
||||
return z.array(Category);
|
||||
},
|
||||
});
|
||||
|
||||
type Category = z.infer<typeof Category>;
|
||||
interface _Category {
|
||||
name: string;
|
||||
subcategories: _Category[];
|
||||
}
|
||||
expectTypeOf<Category>().toEqualTypeOf<_Category>();
|
||||
|
||||
const PickedCategory = z.pick(Category, { name: true });
|
||||
const OmittedCategory = z.omit(Category, { subcategories: true });
|
||||
type PickedCategory = z.infer<typeof PickedCategory>;
|
||||
type OmittedCategory = z.infer<typeof OmittedCategory>;
|
||||
interface _PickedCategory {
|
||||
name: string;
|
||||
}
|
||||
interface _OmittedCategory {
|
||||
name: string;
|
||||
}
|
||||
expectTypeOf<PickedCategory>().toEqualTypeOf<_PickedCategory>();
|
||||
expectTypeOf<OmittedCategory>().toEqualTypeOf<_OmittedCategory>();
|
||||
|
||||
const picked = { name: "test" };
|
||||
const omitted = { name: "test" };
|
||||
|
||||
PickedCategory.parse(picked);
|
||||
OmittedCategory.parse(omitted);
|
||||
|
||||
expect(() => PickedCategory.parse({ name: "test", subcategories: [] })).toThrow();
|
||||
expect(() => OmittedCategory.parse({ name: "test", subcategories: [] })).toThrow();
|
||||
});
|
||||
|
||||
test("deferred self-recursion", () => {
|
||||
const Feature = z.object({
|
||||
title: z.string(),
|
||||
get features(): z.ZodMiniOptional<z.ZodMiniArray<typeof Feature>> {
|
||||
return z.optional(z.array(Feature)); //.optional();
|
||||
},
|
||||
});
|
||||
type Feature = z.infer<typeof Feature>;
|
||||
|
||||
const Output = z.object({
|
||||
id: z.int(), //.nonnegative(),
|
||||
name: z.string(),
|
||||
features: z.array(Feature), //.array(), // <—
|
||||
});
|
||||
|
||||
type Output = z.output<typeof Output>;
|
||||
|
||||
type _Feature = {
|
||||
title: string;
|
||||
features?: _Feature[] | undefined;
|
||||
};
|
||||
|
||||
type _Output = {
|
||||
id: number;
|
||||
name: string;
|
||||
features: _Feature[];
|
||||
};
|
||||
|
||||
expectTypeOf<Feature>().toEqualTypeOf<_Feature>();
|
||||
expectTypeOf<Output>().toEqualTypeOf<_Output>();
|
||||
});
|
||||
|
||||
test("recursion compatibility", () => {
|
||||
// array
|
||||
const A = z.object({
|
||||
get subcategories() {
|
||||
return z.array(A);
|
||||
},
|
||||
});
|
||||
// tuple
|
||||
const B = z.object({
|
||||
get subcategories() {
|
||||
return z.tuple([B, B]);
|
||||
},
|
||||
});
|
||||
// object
|
||||
const C = z.object({
|
||||
get subcategories() {
|
||||
return z.object({
|
||||
subcategories: C,
|
||||
});
|
||||
},
|
||||
});
|
||||
// union
|
||||
const D = z.object({
|
||||
get subcategories() {
|
||||
return z.union([D, z.string()]);
|
||||
},
|
||||
});
|
||||
// intersection
|
||||
const E = z.object({
|
||||
get subcategories() {
|
||||
return z.intersection(E, E);
|
||||
},
|
||||
});
|
||||
// record
|
||||
const F = z.object({
|
||||
get subcategories() {
|
||||
return z.record(z.string(), F);
|
||||
},
|
||||
});
|
||||
// map
|
||||
const G = z.object({
|
||||
get subcategories() {
|
||||
return z.map(z.string(), G);
|
||||
},
|
||||
});
|
||||
// set
|
||||
const H = z.object({
|
||||
get subcategories() {
|
||||
return z.set(H);
|
||||
},
|
||||
});
|
||||
// optional
|
||||
const I = z.object({
|
||||
get subcategories() {
|
||||
return z.optional(I);
|
||||
},
|
||||
});
|
||||
// nullable
|
||||
const J = z.object({
|
||||
get subcategories() {
|
||||
return z.nullable(J);
|
||||
},
|
||||
});
|
||||
// optional
|
||||
const L = z.object({
|
||||
get subcategories() {
|
||||
return z.optional(L);
|
||||
},
|
||||
});
|
||||
// nullable
|
||||
const M = z.object({
|
||||
get subcategories() {
|
||||
return z.nullable(M);
|
||||
},
|
||||
});
|
||||
// nonoptional
|
||||
const N = z.object({
|
||||
get subcategories() {
|
||||
return z.nonoptional(N);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("shape stays writeable through object/strictObject/looseObject/extend with getters", () => {
|
||||
const Cat = z.object({
|
||||
name: z.string(),
|
||||
get sub(): z.ZodMiniArray<typeof Cat> {
|
||||
return z.array(Cat);
|
||||
},
|
||||
});
|
||||
type CatShape = (typeof Cat)["shape"];
|
||||
expectTypeOf<CatShape>().toEqualTypeOf<{
|
||||
name: z.ZodMiniString<string>;
|
||||
sub: z.ZodMiniArray<typeof Cat>;
|
||||
}>();
|
||||
|
||||
const StrictCat = z.strictObject({
|
||||
name: z.string(),
|
||||
get sub(): z.ZodMiniArray<typeof StrictCat> {
|
||||
return z.array(StrictCat);
|
||||
},
|
||||
});
|
||||
type StrictShape = (typeof StrictCat)["shape"];
|
||||
expectTypeOf<StrictShape>().toEqualTypeOf<{
|
||||
name: z.ZodMiniString<string>;
|
||||
sub: z.ZodMiniArray<typeof StrictCat>;
|
||||
}>();
|
||||
|
||||
const LooseCat = z.looseObject({
|
||||
name: z.string(),
|
||||
get sub(): z.ZodMiniArray<typeof LooseCat> {
|
||||
return z.array(LooseCat);
|
||||
},
|
||||
});
|
||||
type LooseShape = (typeof LooseCat)["shape"];
|
||||
expectTypeOf<LooseShape>().toEqualTypeOf<{
|
||||
name: z.ZodMiniString<string>;
|
||||
sub: z.ZodMiniArray<typeof LooseCat>;
|
||||
}>();
|
||||
|
||||
const Base = z.object({ name: z.string() });
|
||||
const Extended = z.extend(Base, {
|
||||
get sub(): z.ZodMiniArray<typeof Extended> {
|
||||
return z.array(Extended);
|
||||
},
|
||||
});
|
||||
type ExtendedShape = (typeof Extended)["shape"];
|
||||
expectTypeOf<ExtendedShape>().toEqualTypeOf<{
|
||||
name: z.ZodMiniString<string>;
|
||||
sub: z.ZodMiniArray<typeof Extended>;
|
||||
}>();
|
||||
});
|
||||
50
node_modules/zod/src/v4/mini/tests/standard-schema.test.ts
generated
vendored
Normal file
50
node_modules/zod/src/v4/mini/tests/standard-schema.test.ts
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import { expect, test } from "vitest";
|
||||
import type { StandardSchemaWithJSON } from "../../core/standard-schema.js";
|
||||
import * as z from "../index.js";
|
||||
|
||||
function acceptSchema(schema: StandardSchemaWithJSON) {
|
||||
return schema;
|
||||
}
|
||||
|
||||
test("Zod Mini schemas are NOT assignable to StandardJSONSchema", () => {
|
||||
const schema = z.string();
|
||||
|
||||
// @ts-expect-error
|
||||
const _standard: StandardSchemaWithJSON["~standard"] = schema;
|
||||
|
||||
// @ts-expect-error
|
||||
acceptSchema(schema);
|
||||
});
|
||||
|
||||
test("toJSONSchema result ~standard.jsonSchema works with objects", () => {
|
||||
const schema = z.object({
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
});
|
||||
|
||||
const jsonSchema = z.toJSONSchema(schema);
|
||||
|
||||
// Call ~standard.jsonSchema.input - this should not throw
|
||||
const inputSchema = jsonSchema["~standard"].jsonSchema.input({ target: "draft-07" });
|
||||
|
||||
expect(inputSchema).toMatchObject({
|
||||
type: "object",
|
||||
properties: {
|
||||
firstName: { type: "string" },
|
||||
lastName: { type: "string" },
|
||||
},
|
||||
required: ["firstName", "lastName"],
|
||||
});
|
||||
|
||||
// Call ~standard.jsonSchema.output - this should not throw
|
||||
const outputSchema = jsonSchema["~standard"].jsonSchema.output({ target: "draft-07" });
|
||||
|
||||
expect(outputSchema).toMatchObject({
|
||||
type: "object",
|
||||
properties: {
|
||||
firstName: { type: "string" },
|
||||
lastName: { type: "string" },
|
||||
},
|
||||
required: ["firstName", "lastName"],
|
||||
});
|
||||
});
|
||||
352
node_modules/zod/src/v4/mini/tests/string.test.ts
generated
vendored
Normal file
352
node_modules/zod/src/v4/mini/tests/string.test.ts
generated
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
const FAIL = { success: false };
|
||||
|
||||
test("z.string", async () => {
|
||||
const a = z.string();
|
||||
expect(z.parse(a, "hello")).toEqual("hello");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
expect(() => z.parse(a, false)).toThrow();
|
||||
type a = z.infer<typeof a>;
|
||||
expectTypeOf<a>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
// test("z.string with description", () => {
|
||||
// const a = z.string({ description: "string description" });
|
||||
// a._def;
|
||||
// expect(a._def.description).toEqual("string description");
|
||||
// });
|
||||
|
||||
test("z.string with custom error", () => {
|
||||
const a = z.string({ error: () => "BAD" });
|
||||
expect(z.safeParse(a, 123).error!.issues[0].message).toEqual("BAD");
|
||||
});
|
||||
|
||||
test("inference in checks", () => {
|
||||
const a = z.string().check(z.refine((val) => val.length));
|
||||
z.parse(a, "___");
|
||||
expect(() => z.parse(a, "")).toThrow();
|
||||
const b = z.string().check(z.refine((val) => val.length));
|
||||
z.parse(b, "___");
|
||||
expect(() => z.parse(b, "")).toThrow();
|
||||
const c = z.string().check(z.refine((val) => val.length));
|
||||
z.parse(c, "___");
|
||||
expect(() => z.parse(c, "")).toThrow();
|
||||
const d = z.string().check(z.refine((val) => val.length));
|
||||
z.parse(d, "___");
|
||||
expect(() => z.parse(d, "")).toThrow();
|
||||
});
|
||||
|
||||
test("z.string async", async () => {
|
||||
// async
|
||||
const a = z.string().check(z.refine(async (val) => val.length));
|
||||
expect(await z.parseAsync(a, "___")).toEqual("___");
|
||||
await expect(() => z.parseAsync(a, "")).rejects.toThrowError();
|
||||
});
|
||||
|
||||
test("z.uuid", () => {
|
||||
const a = z.uuid();
|
||||
// parse uuid
|
||||
z.parse(a, "550e8400-e29b-41d4-a716-446655440000");
|
||||
z.parse(a, "550e8400-e29b-61d4-a716-446655440000");
|
||||
|
||||
// bad uuid
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
|
||||
const b = z.uuidv4();
|
||||
z.parse(b, "550e8400-e29b-41d4-a716-446655440000");
|
||||
expect(z.safeParse(b, "550e8400-e29b-61d4-a716-446655440000")).toMatchObject(FAIL);
|
||||
|
||||
const c = z.uuidv6();
|
||||
z.parse(c, "550e8400-e29b-61d4-a716-446655440000");
|
||||
expect(z.safeParse(c, "550e8400-e29b-41d4-a716-446655440000")).toMatchObject(FAIL);
|
||||
|
||||
const d = z.uuidv7();
|
||||
z.parse(d, "550e8400-e29b-71d4-a716-446655440000");
|
||||
expect(z.safeParse(d, "550e8400-e29b-41d4-a716-446655440000")).toMatchObject(FAIL);
|
||||
expect(z.safeParse(d, "550e8400-e29b-61d4-a716-446655440000")).toMatchObject(FAIL);
|
||||
});
|
||||
|
||||
test("z.email", () => {
|
||||
const a = z.email();
|
||||
expect(z.parse(a, "test@test.com")).toEqual("test@test.com");
|
||||
expect(() => z.parse(a, "test")).toThrow();
|
||||
expect(z.safeParse(a, "bad email", { error: () => "bad email" }).error!.issues[0].message).toEqual("bad email");
|
||||
|
||||
const b = z.email("bad email");
|
||||
expect(z.safeParse(b, "bad email").error!.issues[0].message).toEqual("bad email");
|
||||
|
||||
const c = z.email({ error: "bad email" });
|
||||
expect(z.safeParse(c, "bad email").error!.issues[0].message).toEqual("bad email");
|
||||
|
||||
const d = z.email({ error: () => "bad email" });
|
||||
expect(z.safeParse(d, "bad email").error!.issues[0].message).toEqual("bad email");
|
||||
});
|
||||
|
||||
test("z.url", () => {
|
||||
const a = z.url();
|
||||
// valid URLs
|
||||
expect(a.parse("http://example.com")).toEqual("http://example.com");
|
||||
expect(a.parse("https://example.com")).toEqual("https://example.com");
|
||||
expect(a.parse("ftp://example.com")).toEqual("ftp://example.com");
|
||||
expect(a.parse("http://sub.example.com")).toEqual("http://sub.example.com");
|
||||
expect(a.parse("https://example.com/path?query=123#fragment")).toEqual("https://example.com/path?query=123#fragment");
|
||||
expect(a.parse("http://localhost")).toEqual("http://localhost");
|
||||
expect(a.parse("https://localhost")).toEqual("https://localhost");
|
||||
expect(a.parse("http://localhost:3000")).toEqual("http://localhost:3000");
|
||||
expect(a.parse("https://localhost:3000")).toEqual("https://localhost:3000");
|
||||
|
||||
// test trimming
|
||||
expect(a.parse(" http://example.com ")).toEqual("http://example.com");
|
||||
expect(a.parse(" http://example.com/")).toEqual("http://example.com/");
|
||||
expect(a.parse(" http://example.com")).toEqual("http://example.com");
|
||||
expect(a.parse(" http://example.com//")).toEqual("http://example.com//");
|
||||
|
||||
// invalid URLs
|
||||
expect(() => a.parse("not-a-url")).toThrow();
|
||||
// expect(() => a.parse("http:/example.com")).toThrow();
|
||||
expect(() => a.parse("://example.com")).toThrow();
|
||||
expect(() => a.parse("http://")).toThrow();
|
||||
expect(() => a.parse("example.com")).toThrow();
|
||||
|
||||
// wrong type
|
||||
expect(() => a.parse(123)).toThrow();
|
||||
expect(() => a.parse(null)).toThrow();
|
||||
expect(() => a.parse(undefined)).toThrow();
|
||||
});
|
||||
|
||||
test("z.url with optional hostname regex", () => {
|
||||
const a = z.url({ hostname: /example\.com$/ });
|
||||
expect(a.parse("http://example.com")).toEqual("http://example.com");
|
||||
expect(a.parse("https://sub.example.com")).toEqual("https://sub.example.com");
|
||||
expect(() => a.parse("http://examples.com")).toThrow();
|
||||
expect(() => a.parse("http://example.org")).toThrow();
|
||||
expect(() => a.parse("asdf")).toThrow();
|
||||
});
|
||||
|
||||
test("z.url - file urls", () => {
|
||||
// file URLs
|
||||
const a = z.url({ hostname: /.*/ }); // allow any hostname
|
||||
expect(a.parse("file:///path/to/file.txt")).toEqual("file:///path/to/file.txt");
|
||||
expect(a.parse("file:///C:/path/to/file.txt")).toEqual("file:///C:/path/to/file.txt");
|
||||
expect(a.parse("file:///C:/path/to/file.txt?query=123#fragment")).toEqual(
|
||||
"file:///C:/path/to/file.txt?query=123#fragment"
|
||||
);
|
||||
});
|
||||
test("z.url with optional protocol regex", () => {
|
||||
const a = z.url({ protocol: /^https?$/ });
|
||||
expect(a.parse("http://example.com")).toEqual("http://example.com");
|
||||
expect(a.parse("https://example.com")).toEqual("https://example.com");
|
||||
expect(() => a.parse("ftp://example.com")).toThrow();
|
||||
expect(() => a.parse("mailto:example@example.com")).toThrow();
|
||||
expect(() => a.parse("asdf")).toThrow();
|
||||
});
|
||||
|
||||
test("z.url with both hostname and protocol regexes", () => {
|
||||
const a = z.url({ hostname: /example\.com$/, protocol: /^https$/ });
|
||||
expect(a.parse("https://example.com")).toEqual("https://example.com");
|
||||
expect(a.parse("https://sub.example.com")).toEqual("https://sub.example.com");
|
||||
expect(() => a.parse("http://example.com")).toThrow();
|
||||
expect(() => a.parse("https://example.org")).toThrow();
|
||||
expect(() => a.parse("ftp://example.com")).toThrow();
|
||||
expect(() => a.parse("asdf")).toThrow();
|
||||
});
|
||||
|
||||
test("z.url with invalid regex patterns", () => {
|
||||
const a = z.url({ hostname: /a+$/, protocol: /^ftp$/ });
|
||||
a.parse("ftp://a");
|
||||
a.parse("ftp://aaaaaaaa");
|
||||
expect(() => a.parse("http://aaa")).toThrow();
|
||||
expect(() => a.parse("https://example.com")).toThrow();
|
||||
expect(() => a.parse("ftp://asdfasdf")).toThrow();
|
||||
expect(() => a.parse("ftp://invalid")).toThrow();
|
||||
});
|
||||
|
||||
test("z.emoji", () => {
|
||||
const a = z.emoji();
|
||||
expect(z.parse(a, "😀")).toEqual("😀");
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
});
|
||||
|
||||
test("z.nanoid", () => {
|
||||
const a = z.nanoid();
|
||||
expect(z.parse(a, "8FHZpIxleEK3axQRBNNjN")).toEqual("8FHZpIxleEK3axQRBNNjN");
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.cuid", () => {
|
||||
const a = z.cuid();
|
||||
expect(z.parse(a, "cixs7y0c0000f7x3b1z6m3w6r")).toEqual("cixs7y0c0000f7x3b1z6m3w6r");
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.cuid2", () => {
|
||||
const a = z.cuid2();
|
||||
expect(z.parse(a, "cixs7y0c0000f7x3b1z6m3w6r")).toEqual("cixs7y0c0000f7x3b1z6m3w6r");
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.ulid", () => {
|
||||
const a = z.ulid();
|
||||
expect(z.parse(a, "01ETGRM9QYVX6S9V2F3B6JXG4N")).toEqual("01ETGRM9QYVX6S9V2F3B6JXG4N");
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.xid", () => {
|
||||
const a = z.xid();
|
||||
expect(z.parse(a, "9m4e2mr0ui3e8a215n4g")).toEqual("9m4e2mr0ui3e8a215n4g");
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
test("z.ksuid", () => {
|
||||
const a = z.ksuid();
|
||||
expect(z.parse(a, "2naeRjTrrHJAkfd3tOuEjw90WCA")).toEqual("2naeRjTrrHJAkfd3tOuEjw90WCA");
|
||||
expect(() => z.parse(a, "abc")).toThrow();
|
||||
});
|
||||
|
||||
// test("z.ip", () => {
|
||||
// const a = z.ip();
|
||||
// expect(z.parse(a, "127.0.0.1")).toEqual("127.0.0.1");
|
||||
// expect(z.parse(a, "2001:0db8:85a3:0000:0000:8a2e:0370:7334")).toEqual("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
|
||||
// expect(() => z.parse(a, "abc")).toThrow();
|
||||
// });
|
||||
|
||||
test("z.ipv4", () => {
|
||||
const a = z.ipv4();
|
||||
// valid ipv4
|
||||
expect(z.parse(a, "192.168.1.1")).toEqual("192.168.1.1");
|
||||
expect(z.parse(a, "255.255.255.255")).toEqual("255.255.255.255");
|
||||
// invalid ipv4
|
||||
expect(() => z.parse(a, "999.999.999.999")).toThrow();
|
||||
expect(() => z.parse(a, "256.256.256.256")).toThrow();
|
||||
expect(() => z.parse(a, "192.168.1")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.ipv6", () => {
|
||||
const a = z.ipv6();
|
||||
// valid ipv6
|
||||
expect(z.parse(a, "2001:0db8:85a3:0000:0000:8a2e:0370:7334")).toEqual("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
|
||||
expect(z.parse(a, "::1")).toEqual("::1");
|
||||
// invalid ipv6
|
||||
expect(() => z.parse(a, "2001:db8::85a3::8a2e:370:7334")).toThrow();
|
||||
expect(() => z.parse(a, "2001:db8:85a3:0:0:8a2e:370g:7334")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.mac", () => {
|
||||
const a = z.mac();
|
||||
// valid mac
|
||||
expect(z.parse(a, "00:1A:2B:3C:4D:5E")).toEqual("00:1A:2B:3C:4D:5E");
|
||||
// invalid mac (dash delimiter not accepted by default)
|
||||
expect(() => z.parse(a, "01-23-45-67-89-AB")).toThrow();
|
||||
expect(() => z.parse(a, "00:1A:2B::4D:5E")).toThrow();
|
||||
expect(() => z.parse(a, "00:1a-2B:3c-4D:5e")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.mac with custom delimiter", () => {
|
||||
const a = z.mac({ delimiter: ":" });
|
||||
// valid mac with colon
|
||||
expect(z.parse(a, "00:1A:2B:3C:4D:5E")).toEqual("00:1A:2B:3C:4D:5E");
|
||||
// invalid mac with dash
|
||||
expect(() => z.parse(a, "00-1A-2B-3C-4D-5E")).toThrow();
|
||||
|
||||
const b = z.mac({ delimiter: "-" });
|
||||
// valid mac with dash
|
||||
expect(z.parse(b, "00-1A-2B-3C-4D-5E")).toEqual("00-1A-2B-3C-4D-5E");
|
||||
// invalid mac with colon
|
||||
expect(() => z.parse(b, "00:1A:2B:3C:4D:5E")).toThrow();
|
||||
|
||||
const c = z.mac({ delimiter: ":" });
|
||||
// colon-only mac
|
||||
expect(z.parse(c, "00:1A:2B:3C:4D:5E")).toEqual("00:1A:2B:3C:4D:5E");
|
||||
expect(() => z.parse(c, "00-1A-2B-3C-4D-5E")).toThrow();
|
||||
});
|
||||
|
||||
test("z.base64", () => {
|
||||
const a = z.base64();
|
||||
// valid base64
|
||||
expect(z.parse(a, "SGVsbG8gd29ybGQ=")).toEqual("SGVsbG8gd29ybGQ=");
|
||||
expect(z.parse(a, "U29tZSBvdGhlciBzdHJpbmc=")).toEqual("U29tZSBvdGhlciBzdHJpbmc=");
|
||||
// invalid base64
|
||||
expect(() => z.parse(a, "SGVsbG8gd29ybGQ")).toThrow();
|
||||
expect(() => z.parse(a, "U29tZSBvdGhlciBzdHJpbmc")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// whitespace is not allowed (atob would otherwise strip it)
|
||||
expect(() => z.parse(a, "123 ")).toThrow();
|
||||
expect(() => z.parse(a, "SGVsbG8gd29ybGQ= ")).toThrow();
|
||||
expect(() => z.parse(a, "SGVsbG8gd29ybGQ=\n")).toThrow();
|
||||
expect(() => z.parse(a, "SGVs bG8gd29ybGQ=")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
// test("z.jsonString", () => {
|
||||
// const a = z.jsonString();
|
||||
// // valid JSON string
|
||||
// expect(z.parse(a, '{"key":"value"}')).toEqual('{"key":"value"}');
|
||||
// expect(z.parse(a, '["item1", "item2"]')).toEqual('["item1", "item2"]');
|
||||
// // invalid JSON string
|
||||
// expect(() => z.parse(a, '{"key":value}')).toThrow();
|
||||
// expect(() => z.parse(a, '["item1", "item2"')).toThrow();
|
||||
// expect(() => z.parse(a, "hello")).toThrow();
|
||||
// // wrong type
|
||||
// expect(() => z.parse(a, 123)).toThrow();
|
||||
// });
|
||||
|
||||
test("z.e164", () => {
|
||||
const a = z.e164();
|
||||
// valid e164
|
||||
expect(z.parse(a, "+1234567890")).toEqual("+1234567890");
|
||||
expect(z.parse(a, "+19876543210")).toEqual("+19876543210");
|
||||
// invalid e164
|
||||
expect(() => z.parse(a, "1234567890")).toThrow();
|
||||
expect(() => z.parse(a, "+12345")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.jwt", () => {
|
||||
const a = z.jwt();
|
||||
// valid jwt
|
||||
expect(
|
||||
z.parse(
|
||||
a,
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
||||
)
|
||||
).toEqual(
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
||||
);
|
||||
// invalid jwt
|
||||
expect(() => z.parse(a, "invalid.jwt.token")).toThrow();
|
||||
expect(() => z.parse(a, "hello")).toThrow();
|
||||
// wrong type
|
||||
expect(() => z.parse(a, 123)).toThrow();
|
||||
});
|
||||
|
||||
test("z.hash generic format", () => {
|
||||
expect(z.hash("sha256").parse("a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3")).toBe(
|
||||
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"
|
||||
);
|
||||
|
||||
// --- Type-level checks (ensure the literal format string is encoded in the return type)
|
||||
expectTypeOf(z.hash("md5")).toEqualTypeOf<z.ZodMiniCustomStringFormat<"md5_hex">>();
|
||||
expectTypeOf(z.hash("sha1")).toEqualTypeOf<z.ZodMiniCustomStringFormat<"sha1_hex">>();
|
||||
expectTypeOf(z.hash("sha256", { enc: "base64" as const })).toEqualTypeOf<
|
||||
z.ZodMiniCustomStringFormat<"sha256_base64">
|
||||
>();
|
||||
expectTypeOf(z.hash("sha384", { enc: "base64url" as const })).toEqualTypeOf<
|
||||
z.ZodMiniCustomStringFormat<"sha384_base64url">
|
||||
>();
|
||||
});
|
||||
Reference in New Issue
Block a user