This commit is contained in:
CHEVALLIER Abel
2025-11-13 16:23:22 +01:00
parent de9c515a47
commit cb235644dc
34924 changed files with 3811102 additions and 0 deletions
+32
View 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";
+22
View File
@@ -0,0 +1,22 @@
import * as core from "../core/index.js";
import * as schemas from "./schemas.js";
export function string<T = unknown>(params?: string | core.$ZodStringParams): schemas.ZodMiniString<T> {
return core._coercedString(schemas.ZodMiniString, params) as schemas.ZodMiniString<T>;
}
export function number<T = unknown>(params?: string | core.$ZodNumberParams): schemas.ZodMiniNumber<T> {
return core._coercedNumber(schemas.ZodMiniNumber, params) as schemas.ZodMiniNumber<T>;
}
export function boolean<T = unknown>(params?: string | core.$ZodBooleanParams): schemas.ZodMiniBoolean<T> {
return core._coercedBoolean(schemas.ZodMiniBoolean, params) as schemas.ZodMiniBoolean<T>;
}
export function bigint<T = unknown>(params?: string | core.$ZodBigIntParams): schemas.ZodMiniBigInt<T> {
return core._coercedBigint(schemas.ZodMiniBigInt, params) as schemas.ZodMiniBigInt<T>;
}
export function date<T = unknown>(params?: string | core.$ZodDateParams): schemas.ZodMiniDate<T> {
return core._coercedDate(schemas.ZodMiniDate, params) as schemas.ZodMiniDate<T>;
}
+40
View File
@@ -0,0 +1,40 @@
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 {
globalRegistry,
registry,
config,
$output,
$input,
$brand,
function,
clone,
regexes,
treeifyError,
prettifyError,
formatError,
flattenError,
toJSONSchema,
TimePrecision,
NEVER,
} from "../core/index.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
View File
@@ -0,0 +1,3 @@
import * as z from "./external.js";
export * from "./external.js";
export { z };
+62
View File
@@ -0,0 +1,62 @@
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(
"$ZodISODateTime",
(inst, def) => {
core.$ZodISODateTime.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
}
);
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(
"$ZodISODate",
(inst, def) => {
core.$ZodISODate.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
}
);
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(
"$ZodISOTime",
(inst, def) => {
core.$ZodISOTime.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
}
);
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(
"$ZodISODuration",
(inst, def) => {
core.$ZodISODuration.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
}
);
export function duration(params?: string | core.$ZodISODurationParams): ZodMiniISODuration {
return core._isoDuration(ZodMiniISODuration, params);
}
+1
View File
@@ -0,0 +1 @@
export { parse, safeParse, parseAsync, safeParseAsync } from "../core/index.js";
+1579
View File
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
import { test } from "vitest";
import * as z from "zod/v4-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;
});
+51
View File
@@ -0,0 +1,51 @@
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!" });
});
+144
View 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);
});
+36
View File
@@ -0,0 +1,36 @@
import { expect, test } from "vitest";
import * as z from "zod/v4-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
View File
@@ -0,0 +1,22 @@
import { expect, test } from "vitest";
import * as z from "zod/v4-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);
}
});
+43
View File
@@ -0,0 +1,43 @@
import { expect, test } from "vitest";
// import * as z from "zod/v4/core";
test("z.function", () => {
expect(true).toEqual(true);
});
// test("z.function", () => {
// const a = z.function({
// args: z.tuple([z.string()]),
// returns: z.string(),
// });
// const myFunc = a.implement((name: string | number) => `Hello, ${name}!`);
// expect(myFunc("world")).toEqual("Hello, world!");
// expect(() => myFunc(123 as any)).toThrow();
// // this won't run
// () => {
// // @ts-expect-error
// const r = myFunc(123);
// expectTypeOf(r).toEqualTypeOf<string>();
// };
// });
// test("z.function async", async () => {
// const b = z.function({
// args: z.tuple([z.string()]).$check(async (_) => {}),
// returns: z.string().$check(async (_) => {}),
// });
// const myFuncAsync = b.implementAsync(async (name) => `Hello, ${name}!`);
// expect(await myFuncAsync("world")).toEqual("Hello, world!");
// expect(myFuncAsync(123 as any)).rejects.toThrow();
// // this won't run
// () => {
// // @ts-expect-error
// const r = myFuncAsync(123);
// expectTypeOf(r).toEqualTypeOf<Promise<string>>();
// };
// });
+871
View File
@@ -0,0 +1,871 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4-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.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?, ...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?, ...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();
});
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.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<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";
});
+95
View File
@@ -0,0 +1,95 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4-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
});
+185
View File
@@ -0,0 +1,185 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4-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;
"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(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;
isAdmin: boolean;
}>();
expect(extendedSchema).toBeDefined();
expect(z.safeParse(extendedSchema, { name: "John", age: 30, isAdmin: true }).success).toBe(true);
});
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 }>();
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;
age?: number;
email?: string;
}>();
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;
age: number;
email?: string;
}>();
expect(z.safeParse(partialSchemaWithMask, { age: 30 }).success).toBe(true);
expect(z.safeParse(partialSchemaWithMask, { name: "John" }).success).toBe(false);
});
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
View File
@@ -0,0 +1,43 @@
import { expect, test } from "vitest";
import * as z from "zod/v4-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;
});
+275
View File
@@ -0,0 +1,275 @@
import { expect, expectTypeOf, test } from "vitest";
import { z } from "zod/v4-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[];
}
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);
},
});
});
+299
View File
@@ -0,0 +1,299 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4-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.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();
// 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();
});