gitea push
This commit is contained in:
+1
-18
@@ -31,23 +31,6 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h2 align="center">Featured sponsor: Jazz</h2>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://jazz.tools/?utm_source=zod">
|
||||
<picture width="85%" >
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/garden-co/jazz/938f6767e46cdfded60e50d99bf3b533f4809c68/homepage/homepage/public/Zod%20sponsor%20message.png">
|
||||
<img alt="jazz logo" src="https://raw.githubusercontent.com/garden-co/jazz/938f6767e46cdfded60e50d99bf3b533f4809c68/homepage/homepage/public/Zod%20sponsor%20message.png" width="85%">
|
||||
</picture>
|
||||
</a>
|
||||
<br/>
|
||||
<p><sub>Learn more about <a target="_blank" rel="noopener noreferrer" href="mailto:sponsorship@colinhacks.com">featured sponsorships</a></sub></p>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
### [Read the docs →](https://zod.dev/api)
|
||||
|
||||
<br/>
|
||||
@@ -169,7 +152,7 @@ if (!result.success) {
|
||||
}
|
||||
```
|
||||
|
||||
**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](#refine) or [transforms](#transform), you'll need to use the `.safeParseAsync()` method instead.
|
||||
**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](https://zod.dev/api#refinements) or [transforms](https://zod.dev/api#transforms), you'll need to use the `.safeParseAsync()` method instead.
|
||||
|
||||
```ts
|
||||
const schema = z.string().refine(async (val) => val.length <= 8);
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zod",
|
||||
"version": "4.3.6",
|
||||
"version": "4.4.3",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"author": "Colin McDonnell <zod@colinhacks.com>",
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@ type TestFormErrors = z.inferFlattenedErrors<typeof Test>;
|
||||
test("default flattened errors type inference", () => {
|
||||
type TestTypeErrors = {
|
||||
formErrors: string[];
|
||||
fieldErrors: { [P in keyof z.TypeOf<typeof Test>]?: string[] | undefined };
|
||||
fieldErrors: { [P in keyof z.TypeOf<typeof Test>]?: string[] };
|
||||
};
|
||||
|
||||
util.assertEqual<z.inferFlattenedErrors<typeof Test>, TestTypeErrors>(true);
|
||||
@@ -28,7 +28,7 @@ test("custom flattened errors type inference", () => {
|
||||
type TestTypeErrors = {
|
||||
formErrors: ErrorType[];
|
||||
fieldErrors: {
|
||||
[P in keyof z.TypeOf<typeof Test>]?: ErrorType[] | undefined;
|
||||
[P in keyof z.TypeOf<typeof Test>]?: ErrorType[];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -40,7 +40,7 @@ test("custom flattened errors type inference", () => {
|
||||
test("form errors type inference", () => {
|
||||
type TestTypeErrors = {
|
||||
formErrors: string[];
|
||||
fieldErrors: { [P in keyof z.TypeOf<typeof Test>]?: string[] | undefined };
|
||||
fieldErrors: { [P in keyof z.TypeOf<typeof Test>]?: string[] };
|
||||
};
|
||||
|
||||
util.assertEqual<z.inferFlattenedErrors<typeof Test>, TestTypeErrors>(true);
|
||||
|
||||
+5
-5
@@ -212,9 +212,9 @@ test("inferred merged object type with optional properties", async () => {
|
||||
.object({ a: z.string(), b: z.string().optional() })
|
||||
.merge(z.object({ a: z.string().optional(), b: z.string() }));
|
||||
type Merged = z.infer<typeof Merged>;
|
||||
util.assertEqual<Merged, { a?: string; b: string }>(true);
|
||||
util.assertEqual<Merged, { a?: string | undefined; b: string }>(true);
|
||||
// todo
|
||||
// util.assertEqual<Merged, { a?: string; b: string }>(true);
|
||||
// util.assertEqual<Merged, { a?: string | undefined; b: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred unioned object type with optional properties", async () => {
|
||||
@@ -223,7 +223,7 @@ test("inferred unioned object type with optional properties", async () => {
|
||||
z.object({ a: z.string().optional(), b: z.string() }),
|
||||
]);
|
||||
type Unioned = z.infer<typeof Unioned>;
|
||||
util.assertEqual<Unioned, { a: string; b?: string } | { a?: string; b: string }>(true);
|
||||
util.assertEqual<Unioned, { a: string; b?: string | undefined } | { a?: string | undefined; b: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred enum type", async () => {
|
||||
@@ -245,13 +245,13 @@ test("inferred enum type", async () => {
|
||||
test("inferred partial object type with optional properties", async () => {
|
||||
const Partial = z.object({ a: z.string(), b: z.string().optional() }).partial();
|
||||
type Partial = z.infer<typeof Partial>;
|
||||
util.assertEqual<Partial, { a?: string; b?: string }>(true);
|
||||
util.assertEqual<Partial, { a?: string | undefined; b?: string | undefined }>(true);
|
||||
});
|
||||
|
||||
test("inferred picked object type with optional properties", async () => {
|
||||
const Picked = z.object({ a: z.string(), b: z.string().optional() }).pick({ b: true });
|
||||
type Picked = z.infer<typeof Picked>;
|
||||
util.assertEqual<Picked, { b?: string }>(true);
|
||||
util.assertEqual<Picked, { b?: string | undefined }>(true);
|
||||
});
|
||||
|
||||
test("inferred type for unknown/any keys", () => {
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ test("shallow inference", () => {
|
||||
name?: string | undefined;
|
||||
age?: number | undefined;
|
||||
outer?: { inner: string } | undefined;
|
||||
array?: { asdf: string }[];
|
||||
array?: { asdf: string }[] | undefined;
|
||||
};
|
||||
util.assertEqual<shallow, correct>(true);
|
||||
});
|
||||
@@ -41,7 +41,7 @@ test("deep partial inference", () => {
|
||||
asdf.parse("asdf");
|
||||
type deep = z.infer<typeof deep>;
|
||||
type correct = {
|
||||
array?: { asdf?: string }[];
|
||||
array?: { asdf?: string | undefined }[] | undefined;
|
||||
name?: string | undefined;
|
||||
age?: number | undefined;
|
||||
outer?: { inner?: string | undefined } | undefined;
|
||||
@@ -118,7 +118,7 @@ test("deep partial inference", () => {
|
||||
asdf?: string | undefined;
|
||||
}[]
|
||||
| undefined;
|
||||
tuple?: [{ value?: string }] | undefined;
|
||||
tuple?: [{ value?: string | undefined }] | undefined;
|
||||
};
|
||||
util.assertEqual<expected, partialed>(true);
|
||||
});
|
||||
|
||||
+2
-2
@@ -61,8 +61,8 @@ const initializer = (inst: ZodError, issues: core.$ZodIssue[]) => {
|
||||
// },
|
||||
// });
|
||||
};
|
||||
export const ZodError: core.$constructor<ZodError> = core.$constructor("ZodError", initializer);
|
||||
export const ZodRealError: core.$constructor<ZodError> = core.$constructor("ZodError", initializer, {
|
||||
export const ZodError: core.$constructor<ZodError> = /*@__PURE__*/ core.$constructor("ZodError", initializer);
|
||||
export const ZodRealError: core.$constructor<ZodError> = /*@__PURE__*/ core.$constructor("ZodError", initializer, {
|
||||
Parent: Error,
|
||||
});
|
||||
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ import en from "../locales/en.js";
|
||||
config(en());
|
||||
|
||||
export type { infer, output, input } from "../core/index.js";
|
||||
export type { JSONType } from "../core/util.js";
|
||||
export {
|
||||
globalRegistry,
|
||||
type GlobalMeta,
|
||||
|
||||
+39
-23
@@ -29,7 +29,7 @@ interface ConversionContext {
|
||||
}
|
||||
|
||||
// Keys that are recognized and handled by the conversion logic
|
||||
const RECOGNIZED_KEYS = new Set([
|
||||
const RECOGNIZED_KEYS = /*@__PURE__*/ new Set([
|
||||
// Schema identification
|
||||
"$schema",
|
||||
"$ref",
|
||||
@@ -478,10 +478,10 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
||||
}
|
||||
// Apply minItems/maxItems constraints to tuples
|
||||
if (typeof schema.minItems === "number") {
|
||||
zodSchema = (zodSchema as any).check(z.minLength(schema.minItems));
|
||||
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
zodSchema = (zodSchema as any).check(z.maxLength(schema.maxItems));
|
||||
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
||||
}
|
||||
} else if (Array.isArray(items)) {
|
||||
// Tuple with items array (draft-7)
|
||||
@@ -497,10 +497,10 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
||||
}
|
||||
// Apply minItems/maxItems constraints to tuples
|
||||
if (typeof schema.minItems === "number") {
|
||||
zodSchema = (zodSchema as any).check(z.minLength(schema.minItems));
|
||||
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
zodSchema = (zodSchema as any).check(z.maxLength(schema.maxItems));
|
||||
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
||||
}
|
||||
} else if (items !== undefined) {
|
||||
// Regular array
|
||||
@@ -509,10 +509,10 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
||||
|
||||
// Apply constraints
|
||||
if (typeof schema.minItems === "number") {
|
||||
arraySchema = (arraySchema as any).min(schema.minItems);
|
||||
arraySchema = arraySchema.min(schema.minItems);
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
arraySchema = (arraySchema as any).max(schema.maxItems);
|
||||
arraySchema = arraySchema.max(schema.maxItems);
|
||||
}
|
||||
|
||||
zodSchema = arraySchema;
|
||||
@@ -527,14 +527,6 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
||||
throw new Error(`Unsupported type: ${type}`);
|
||||
}
|
||||
|
||||
// Apply metadata
|
||||
if (schema.description) {
|
||||
zodSchema = zodSchema.describe(schema.description);
|
||||
}
|
||||
if (schema.default !== undefined) {
|
||||
zodSchema = (zodSchema as any).default(schema.default);
|
||||
}
|
||||
|
||||
return zodSchema;
|
||||
}
|
||||
|
||||
@@ -586,10 +578,18 @@ function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionC
|
||||
baseSchema = z.readonly(baseSchema);
|
||||
}
|
||||
|
||||
// Collect metadata: core schema keywords and unrecognized keys
|
||||
// Apply `default` so it wraps the fully-composed schema. This ensures
|
||||
// `parse(undefined) -> default` works regardless of which branch of
|
||||
// `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.).
|
||||
if (schema.default !== undefined) {
|
||||
baseSchema = baseSchema.default(schema.default);
|
||||
}
|
||||
|
||||
// Collect non-description annotation metadata into the user-supplied
|
||||
// registry. Description is handled separately below via `.describe()` to
|
||||
// preserve the contract that `schema.description` reads from globalRegistry.
|
||||
const extraMeta: Record<string, unknown> = {};
|
||||
|
||||
// Core schema keywords that should be captured as metadata
|
||||
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
||||
for (const key of coreMetadataKeys) {
|
||||
if (key in schema) {
|
||||
@@ -597,7 +597,6 @@ function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionC
|
||||
}
|
||||
}
|
||||
|
||||
// Content keywords - store as metadata
|
||||
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
||||
for (const key of contentMetadataKeys) {
|
||||
if (key in schema) {
|
||||
@@ -605,7 +604,6 @@ function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionC
|
||||
}
|
||||
}
|
||||
|
||||
// Unrecognized keys (custom metadata)
|
||||
for (const key of Object.keys(schema)) {
|
||||
if (!RECOGNIZED_KEYS.has(key)) {
|
||||
extraMeta[key] = schema[key];
|
||||
@@ -616,6 +614,13 @@ function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionC
|
||||
ctx.registry.add(baseSchema, extraMeta);
|
||||
}
|
||||
|
||||
// Apply description last. `.describe()` clones the schema and sets
|
||||
// `_zod.parent` on the clone, so registry lookups on the returned reference
|
||||
// still resolve `extraMeta` via parent inheritance.
|
||||
if (schema.description) {
|
||||
baseSchema = baseSchema.describe(schema.description);
|
||||
}
|
||||
|
||||
return baseSchema;
|
||||
}
|
||||
|
||||
@@ -627,17 +632,28 @@ export function fromJSONSchema(schema: JSONSchema.JSONSchema | boolean, params?:
|
||||
return schema ? z.any() : z.never();
|
||||
}
|
||||
|
||||
const version = detectVersion(schema, params?.defaultTarget);
|
||||
const defs = (schema.$defs || schema.definitions || {}) as Record<string, JSONSchema.JSONSchema>;
|
||||
// Normalize input via a JSON round-trip. This guarantees the converter
|
||||
// walks a plain, finite, JSON-valid object graph: cyclic inputs fail here,
|
||||
// getter/Proxy-based properties are materialized into static values, and
|
||||
// class instances collapse to plain objects.
|
||||
let normalized: JSONSchema.JSONSchema;
|
||||
try {
|
||||
normalized = JSON.parse(JSON.stringify(schema));
|
||||
} catch {
|
||||
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
||||
}
|
||||
|
||||
const version = detectVersion(normalized, params?.defaultTarget);
|
||||
const defs = (normalized.$defs || normalized.definitions || {}) as Record<string, JSONSchema.JSONSchema>;
|
||||
|
||||
const ctx: ConversionContext = {
|
||||
version,
|
||||
defs,
|
||||
refs: new Map(),
|
||||
processing: new Set(),
|
||||
rootSchema: schema,
|
||||
rootSchema: normalized,
|
||||
registry: params?.registry ?? globalRegistry,
|
||||
};
|
||||
|
||||
return convertSchema(schema, ctx);
|
||||
return convertSchema(normalized, ctx);
|
||||
}
|
||||
|
||||
+6
-6
@@ -10,14 +10,14 @@ export const parse: <T extends core.$ZodType>(
|
||||
value: unknown,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>,
|
||||
_params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass }
|
||||
) => core.output<T> = /* @__PURE__ */ core._parse(ZodRealError) as any;
|
||||
) => core.output<T> = /* @__PURE__ */ core._parse(ZodRealError);
|
||||
|
||||
export const parseAsync: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
value: unknown,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>,
|
||||
_params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass }
|
||||
) => Promise<core.output<T>> = /* @__PURE__ */ core._parseAsync(ZodRealError) as any;
|
||||
) => Promise<core.output<T>> = /* @__PURE__ */ core._parseAsync(ZodRealError);
|
||||
|
||||
export const safeParse: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
@@ -37,25 +37,25 @@ export const encode: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
value: core.output<T>,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>
|
||||
) => core.input<T> = /* @__PURE__ */ core._encode(ZodRealError) as any;
|
||||
) => core.input<T> = /* @__PURE__ */ core._encode(ZodRealError);
|
||||
|
||||
export const decode: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
value: core.input<T>,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>
|
||||
) => core.output<T> = /* @__PURE__ */ core._decode(ZodRealError) as any;
|
||||
) => core.output<T> = /* @__PURE__ */ core._decode(ZodRealError);
|
||||
|
||||
export const encodeAsync: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
value: core.output<T>,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>
|
||||
) => Promise<core.input<T>> = /* @__PURE__ */ core._encodeAsync(ZodRealError) as any;
|
||||
) => Promise<core.input<T>> = /* @__PURE__ */ core._encodeAsync(ZodRealError);
|
||||
|
||||
export const decodeAsync: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
value: core.input<T>,
|
||||
_ctx?: core.ParseContext<core.$ZodIssue>
|
||||
) => Promise<core.output<T>> = /* @__PURE__ */ core._decodeAsync(ZodRealError) as any;
|
||||
) => Promise<core.output<T>> = /* @__PURE__ */ core._decodeAsync(ZodRealError);
|
||||
|
||||
export const safeEncode: <T extends core.$ZodType>(
|
||||
schema: T,
|
||||
|
||||
+414
-151
@@ -8,6 +8,65 @@ import * as checks from "./checks.js";
|
||||
import * as iso from "./iso.js";
|
||||
import * as parse from "./parse.js";
|
||||
|
||||
// Lazy-bind builder methods.
|
||||
//
|
||||
// Builder methods (`.optional`, `.array`, `.refine`, ...) live as
|
||||
// non-enumerable getters on each concrete schema constructor's
|
||||
// prototype. On first access from an instance the getter allocates
|
||||
// `fn.bind(this)` and caches it as an own property on that instance,
|
||||
// so detached usage (`const m = schema.optional; m()`) still works
|
||||
// and the per-instance allocation only happens for methods actually
|
||||
// touched.
|
||||
//
|
||||
// One install per (prototype, group), memoized by `_installedGroups`.
|
||||
const _installedGroups = /* @__PURE__ */ new WeakMap<object, Set<string>>();
|
||||
|
||||
/**
|
||||
* Methods of `T` reshaped so each body has `this: T` and matches the
|
||||
* declared (args, return) of the corresponding interface method. Allows
|
||||
* us to type-check inline method-shorthand bodies against the
|
||||
* `ZodType` / `_ZodString` / etc. interface declarations.
|
||||
*/
|
||||
type _LazyMethodsOf<T> = Partial<{
|
||||
[K in keyof T]: T[K] extends (...args: infer A) => infer R ? (this: T, ...args: A) => R : never;
|
||||
}>;
|
||||
|
||||
function _installLazyMethods<T extends object>(inst: T, group: string, methods: _LazyMethodsOf<T>): void {
|
||||
const proto = Object.getPrototypeOf(inst);
|
||||
let installed = _installedGroups.get(proto);
|
||||
if (!installed) {
|
||||
installed = new Set();
|
||||
_installedGroups.set(proto, installed);
|
||||
}
|
||||
if (installed.has(group)) return;
|
||||
installed.add(group);
|
||||
for (const key in methods) {
|
||||
const fn = methods[key]!;
|
||||
Object.defineProperty(proto, key, {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
get(this: any) {
|
||||
const bound = fn.bind(this);
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: bound,
|
||||
});
|
||||
return bound;
|
||||
},
|
||||
set(this: any, v: unknown) {
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: v,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
///////////////////////////////////////////
|
||||
//////////// ////////////
|
||||
@@ -94,7 +153,8 @@ export interface ZodType<
|
||||
params?: string | core.$ZodCustomParams
|
||||
): Ch extends (arg: any) => arg is infer R ? this & ZodType<R, core.input<this>> : this;
|
||||
superRefine(
|
||||
refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>
|
||||
refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>,
|
||||
params?: core.$ZodSuperRefineParams
|
||||
): this;
|
||||
overwrite(fn: (x: core.output<this>) => core.output<this>): this;
|
||||
|
||||
@@ -167,38 +227,16 @@ export const ZodType: core.$constructor<ZodType> = /*@__PURE__*/ core.$construct
|
||||
inst.type = def.type;
|
||||
Object.defineProperty(inst, "_def", { value: def });
|
||||
|
||||
// base methods
|
||||
inst.check = (...checks) => {
|
||||
return inst.clone(
|
||||
util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...checks.map((ch) =>
|
||||
typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch
|
||||
),
|
||||
],
|
||||
}),
|
||||
{
|
||||
parent: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
inst.with = inst.check;
|
||||
inst.clone = (def, params) => core.clone(inst, def, params);
|
||||
inst.brand = () => inst as any;
|
||||
inst.register = ((reg: any, meta: any) => {
|
||||
reg.add(inst, meta);
|
||||
return inst;
|
||||
}) as any;
|
||||
|
||||
// parsing
|
||||
// Parse-family is intentionally kept as per-instance closures: these are
|
||||
// the hot path AND the most-detached methods (`arr.map(schema.parse)`,
|
||||
// `const { parse } = schema`, etc.). Eager closures here mean callers pay
|
||||
// ~12 closure allocations per schema but get monomorphic call sites and
|
||||
// detached usage that "just works".
|
||||
inst.parse = (data, params) => parse.parse(inst, data, params, { callee: inst.parse });
|
||||
inst.safeParse = (data, params) => parse.safeParse(inst, data, params);
|
||||
inst.parseAsync = async (data, params) => parse.parseAsync(inst, data, params, { callee: inst.parseAsync });
|
||||
inst.safeParseAsync = async (data, params) => parse.safeParseAsync(inst, data, params);
|
||||
inst.spa = inst.safeParseAsync;
|
||||
|
||||
// encoding/decoding
|
||||
inst.encode = (data, params) => parse.encode(inst, data, params);
|
||||
inst.decode = (data, params) => parse.decode(inst, data, params);
|
||||
inst.encodeAsync = async (data, params) => parse.encodeAsync(inst, data, params);
|
||||
@@ -208,53 +246,122 @@ export const ZodType: core.$constructor<ZodType> = /*@__PURE__*/ core.$construct
|
||||
inst.safeEncodeAsync = async (data, params) => parse.safeEncodeAsync(inst, data, params);
|
||||
inst.safeDecodeAsync = async (data, params) => parse.safeDecodeAsync(inst, data, params);
|
||||
|
||||
// refinements
|
||||
inst.refine = (check, params) => inst.check(refine(check, params)) as never;
|
||||
inst.superRefine = (refinement) => inst.check(superRefine(refinement));
|
||||
inst.overwrite = (fn) => inst.check(checks.overwrite(fn));
|
||||
|
||||
// wrappers
|
||||
inst.optional = () => optional(inst);
|
||||
inst.exactOptional = () => exactOptional(inst);
|
||||
inst.nullable = () => nullable(inst);
|
||||
inst.nullish = () => optional(nullable(inst));
|
||||
inst.nonoptional = (params) => nonoptional(inst, params);
|
||||
inst.array = () => array(inst);
|
||||
inst.or = (arg) => union([inst, arg]);
|
||||
inst.and = (arg) => intersection(inst, arg);
|
||||
inst.transform = (tx) => pipe(inst, transform(tx as any)) as never;
|
||||
inst.default = (def) => _default(inst, def);
|
||||
inst.prefault = (def) => prefault(inst, def);
|
||||
// inst.coalesce = (def, params) => coalesce(inst, def, params);
|
||||
inst.catch = (params) => _catch(inst, params);
|
||||
inst.pipe = (target) => pipe(inst, target);
|
||||
inst.readonly = () => readonly(inst);
|
||||
|
||||
// meta
|
||||
inst.describe = (description) => {
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
};
|
||||
// All builder methods are placed on the internal prototype as lazy-bind
|
||||
// getters. On first access per-instance, a bound thunk is allocated and
|
||||
// cached as an own property; subsequent accesses skip the getter. This
|
||||
// means: no per-instance allocation for unused methods, full
|
||||
// detachability preserved (`const m = schema.optional; m()` works), and
|
||||
// shared underlying function references across all instances.
|
||||
_installLazyMethods(inst, "ZodType", {
|
||||
check(...chks) {
|
||||
const def = this.def;
|
||||
return this.clone(
|
||||
util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...chks.map((ch) =>
|
||||
typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch
|
||||
),
|
||||
],
|
||||
}),
|
||||
{ parent: true }
|
||||
);
|
||||
},
|
||||
with(...chks) {
|
||||
return this.check(...chks);
|
||||
},
|
||||
clone(def, params) {
|
||||
return core.clone(this, def, params);
|
||||
},
|
||||
brand() {
|
||||
return this;
|
||||
},
|
||||
register(reg, meta) {
|
||||
reg.add(this, meta);
|
||||
return this;
|
||||
},
|
||||
refine(check, params) {
|
||||
return this.check(refine(check, params));
|
||||
},
|
||||
superRefine(refinement, params) {
|
||||
return this.check(superRefine(refinement, params));
|
||||
},
|
||||
overwrite(fn) {
|
||||
return this.check(checks.overwrite(fn));
|
||||
},
|
||||
optional() {
|
||||
return optional(this);
|
||||
},
|
||||
exactOptional() {
|
||||
return exactOptional(this);
|
||||
},
|
||||
nullable() {
|
||||
return nullable(this);
|
||||
},
|
||||
nullish() {
|
||||
return optional(nullable(this));
|
||||
},
|
||||
nonoptional(params) {
|
||||
return nonoptional(this, params);
|
||||
},
|
||||
array() {
|
||||
return array(this);
|
||||
},
|
||||
or(arg) {
|
||||
return union([this, arg]);
|
||||
},
|
||||
and(arg) {
|
||||
return intersection(this, arg);
|
||||
},
|
||||
transform(tx) {
|
||||
return pipe(this, transform(tx));
|
||||
},
|
||||
default(d) {
|
||||
return _default(this, d);
|
||||
},
|
||||
prefault(d) {
|
||||
return prefault(this, d);
|
||||
},
|
||||
catch(params) {
|
||||
return _catch(this, params);
|
||||
},
|
||||
pipe(target) {
|
||||
return pipe(this, target);
|
||||
},
|
||||
readonly() {
|
||||
return readonly(this);
|
||||
},
|
||||
describe(description) {
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
},
|
||||
meta(...args: any[]): any {
|
||||
// overloaded: meta() returns the registered metadata, meta(data)
|
||||
// returns a clone with `data` registered. The mapped type picks
|
||||
// up the second overload, so we accept variadic any-args and
|
||||
// return `any` to satisfy both at runtime.
|
||||
if (args.length === 0) return core.globalRegistry.get(this);
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl;
|
||||
},
|
||||
isOptional() {
|
||||
return this.safeParse(undefined).success;
|
||||
},
|
||||
isNullable() {
|
||||
return this.safeParse(null).success;
|
||||
},
|
||||
apply(fn) {
|
||||
return fn(this);
|
||||
},
|
||||
});
|
||||
Object.defineProperty(inst, "description", {
|
||||
get() {
|
||||
return core.globalRegistry.get(inst)?.description;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
inst.meta = (...args: any) => {
|
||||
if (args.length === 0) {
|
||||
return core.globalRegistry.get(inst);
|
||||
}
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl as any;
|
||||
};
|
||||
|
||||
// helpers
|
||||
inst.isOptional = () => inst.safeParse(undefined).success;
|
||||
inst.isNullable = () => inst.safeParse(null).success;
|
||||
inst.apply = (fn) => fn(inst);
|
||||
return inst;
|
||||
});
|
||||
|
||||
@@ -297,24 +404,53 @@ export const _ZodString: core.$constructor<_ZodString> = /*@__PURE__*/ core.$con
|
||||
inst.minLength = bag.minimum ?? null;
|
||||
inst.maxLength = bag.maximum ?? null;
|
||||
|
||||
// validations
|
||||
inst.regex = (...args) => inst.check(checks.regex(...args));
|
||||
inst.includes = (...args) => inst.check(checks.includes(...args));
|
||||
inst.startsWith = (...args) => inst.check(checks.startsWith(...args));
|
||||
inst.endsWith = (...args) => inst.check(checks.endsWith(...args));
|
||||
inst.min = (...args) => inst.check(checks.minLength(...args));
|
||||
inst.max = (...args) => inst.check(checks.maxLength(...args));
|
||||
inst.length = (...args) => inst.check(checks.length(...args));
|
||||
inst.nonempty = (...args) => inst.check(checks.minLength(1, ...args));
|
||||
inst.lowercase = (params) => inst.check(checks.lowercase(params));
|
||||
inst.uppercase = (params) => inst.check(checks.uppercase(params));
|
||||
|
||||
// transforms
|
||||
inst.trim = () => inst.check(checks.trim());
|
||||
inst.normalize = (...args) => inst.check(checks.normalize(...args));
|
||||
inst.toLowerCase = () => inst.check(checks.toLowerCase());
|
||||
inst.toUpperCase = () => inst.check(checks.toUpperCase());
|
||||
inst.slugify = () => inst.check(checks.slugify());
|
||||
_installLazyMethods(inst, "_ZodString", {
|
||||
regex(...args) {
|
||||
return this.check((checks.regex as any)(...args));
|
||||
},
|
||||
includes(...args) {
|
||||
return this.check((checks.includes as any)(...args));
|
||||
},
|
||||
startsWith(...args) {
|
||||
return this.check((checks.startsWith as any)(...args));
|
||||
},
|
||||
endsWith(...args) {
|
||||
return this.check((checks.endsWith as any)(...args));
|
||||
},
|
||||
min(...args) {
|
||||
return this.check((checks.minLength as any)(...args));
|
||||
},
|
||||
max(...args) {
|
||||
return this.check((checks.maxLength as any)(...args));
|
||||
},
|
||||
length(...args) {
|
||||
return this.check((checks.length as any)(...args));
|
||||
},
|
||||
nonempty(...args) {
|
||||
return this.check((checks.minLength as any)(1, ...args));
|
||||
},
|
||||
lowercase(params) {
|
||||
return this.check(checks.lowercase(params));
|
||||
},
|
||||
uppercase(params) {
|
||||
return this.check(checks.uppercase(params));
|
||||
},
|
||||
trim() {
|
||||
return this.check(checks.trim());
|
||||
},
|
||||
normalize(...args) {
|
||||
return this.check(checks.normalize(...args));
|
||||
},
|
||||
toLowerCase() {
|
||||
return this.check(checks.toLowerCase());
|
||||
},
|
||||
toUpperCase() {
|
||||
return this.check(checks.toUpperCase());
|
||||
},
|
||||
slugify() {
|
||||
return this.check(checks.slugify());
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export interface ZodString extends _ZodString<core.$ZodStringInternals<string>> {
|
||||
@@ -342,7 +478,11 @@ export interface ZodString extends _ZodString<core.$ZodStringInternals<string>>
|
||||
nanoid(params?: string | core.$ZodCheckNanoIDParams): this;
|
||||
/** @deprecated Use `z.guid()` instead. */
|
||||
guid(params?: string | core.$ZodCheckGUIDParams): this;
|
||||
/** @deprecated Use `z.cuid()` instead. */
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use `z.cuid2()` instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
cuid(params?: string | core.$ZodCheckCUIDParams): this;
|
||||
/** @deprecated Use `z.cuid2()` instead. */
|
||||
cuid2(params?: string | core.$ZodCheckCUID2Params): this;
|
||||
@@ -428,7 +568,7 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
|
||||
export function string(params?: string | core.$ZodStringParams): ZodString;
|
||||
export function string<T extends string>(params?: string | core.$ZodStringParams): core.$ZodType<T, T>;
|
||||
export function string(params?: string | core.$ZodStringParams): ZodString {
|
||||
return core._string(ZodString, params) as any;
|
||||
return core._string(ZodString, params);
|
||||
}
|
||||
|
||||
// ZodStringFormat
|
||||
@@ -516,7 +656,7 @@ export function url(params?: string | core.$ZodURLParams): ZodURL {
|
||||
|
||||
export function httpUrl(params?: string | Omit<core.$ZodURLParams, "protocol" | "hostname">): ZodURL {
|
||||
return core._url(ZodURL, {
|
||||
protocol: /^https?$/,
|
||||
protocol: core.regexes.httpProtocol,
|
||||
hostname: core.regexes.domain,
|
||||
...util.normalizeParams(params),
|
||||
});
|
||||
@@ -551,15 +691,32 @@ export function nanoid(params?: string | core.$ZodNanoIDParams): ZodNanoID {
|
||||
}
|
||||
|
||||
// ZodCUID
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface ZodCUID extends ZodStringFormat<"cuid"> {
|
||||
_zod: core.$ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const ZodCUID: core.$constructor<ZodCUID> = /*@__PURE__*/ core.$constructor("ZodCUID", (inst, def) => {
|
||||
// ZodStringFormat.init(inst, def);
|
||||
core.$ZodCUID.init(inst, def);
|
||||
ZodStringFormat.init(inst, def);
|
||||
});
|
||||
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export function cuid(params?: string | core.$ZodCUIDParams): ZodCUID {
|
||||
return core._cuid(ZodCUID, params);
|
||||
}
|
||||
@@ -845,23 +1002,53 @@ export const ZodNumber: core.$constructor<ZodNumber> = /*@__PURE__*/ core.$const
|
||||
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.numberProcessor(inst, ctx, json, params);
|
||||
|
||||
inst.gt = (value, params) => inst.check(checks.gt(value, params));
|
||||
inst.gte = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.min = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.lt = (value, params) => inst.check(checks.lt(value, params));
|
||||
inst.lte = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.max = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.int = (params) => inst.check(int(params));
|
||||
inst.safe = (params) => inst.check(int(params));
|
||||
inst.positive = (params) => inst.check(checks.gt(0, params));
|
||||
inst.nonnegative = (params) => inst.check(checks.gte(0, params));
|
||||
inst.negative = (params) => inst.check(checks.lt(0, params));
|
||||
inst.nonpositive = (params) => inst.check(checks.lte(0, params));
|
||||
inst.multipleOf = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
inst.step = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
|
||||
// inst.finite = (params) => inst.check(core.finite(params));
|
||||
inst.finite = () => inst;
|
||||
_installLazyMethods(inst, "ZodNumber", {
|
||||
gt(value, params) {
|
||||
return this.check(checks.gt(value, params));
|
||||
},
|
||||
gte(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
min(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
lt(value, params) {
|
||||
return this.check(checks.lt(value, params));
|
||||
},
|
||||
lte(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
max(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
int(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
safe(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
positive(params) {
|
||||
return this.check(checks.gt(0, params));
|
||||
},
|
||||
nonnegative(params) {
|
||||
return this.check(checks.gte(0, params));
|
||||
},
|
||||
negative(params) {
|
||||
return this.check(checks.lt(0, params));
|
||||
},
|
||||
nonpositive(params) {
|
||||
return this.check(checks.lte(0, params));
|
||||
},
|
||||
multipleOf(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
step(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
finite() {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
const bag = inst._zod.bag;
|
||||
inst.minValue =
|
||||
@@ -874,7 +1061,7 @@ export const ZodNumber: core.$constructor<ZodNumber> = /*@__PURE__*/ core.$const
|
||||
});
|
||||
|
||||
export function number(params?: string | core.$ZodNumberParams): ZodNumber {
|
||||
return core._number(ZodNumber, params) as any;
|
||||
return core._number(ZodNumber, params);
|
||||
}
|
||||
|
||||
// ZodNumberFormat
|
||||
@@ -929,7 +1116,7 @@ export const ZodBoolean: core.$constructor<ZodBoolean> = /*@__PURE__*/ core.$con
|
||||
});
|
||||
|
||||
export function boolean(params?: string | core.$ZodBooleanParams): ZodBoolean {
|
||||
return core._boolean(ZodBoolean, params) as any;
|
||||
return core._boolean(ZodBoolean, params);
|
||||
}
|
||||
|
||||
// bigint
|
||||
@@ -980,7 +1167,7 @@ export const ZodBigInt: core.$constructor<ZodBigInt> = /*@__PURE__*/ core.$const
|
||||
});
|
||||
|
||||
export function bigint(params?: string | core.$ZodBigIntParams): ZodBigInt {
|
||||
return core._bigint(ZodBigInt, params) as any;
|
||||
return core._bigint(ZodBigInt, params);
|
||||
}
|
||||
// bigint formats
|
||||
|
||||
@@ -1143,13 +1330,24 @@ export const ZodArray: core.$constructor<ZodArray> = /*@__PURE__*/ core.$constru
|
||||
ZodType.init(inst, def);
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.arrayProcessor(inst, ctx, json, params);
|
||||
|
||||
inst.element = def.element as any;
|
||||
inst.min = (minLength, params) => inst.check(checks.minLength(minLength, params));
|
||||
inst.nonempty = (params) => inst.check(checks.minLength(1, params));
|
||||
inst.max = (maxLength, params) => inst.check(checks.maxLength(maxLength, params));
|
||||
inst.length = (len, params) => inst.check(checks.length(len, params));
|
||||
|
||||
inst.unwrap = () => inst.element;
|
||||
inst.element = def.element;
|
||||
_installLazyMethods(inst, "ZodArray", {
|
||||
min(n, params) {
|
||||
return this.check(checks.minLength(n, params));
|
||||
},
|
||||
nonempty(params) {
|
||||
return this.check(checks.minLength(1, params));
|
||||
},
|
||||
max(n, params) {
|
||||
return this.check(checks.maxLength(n, params));
|
||||
},
|
||||
length(n, params) {
|
||||
return this.check(checks.length(n, params));
|
||||
},
|
||||
unwrap() {
|
||||
return this.element;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export function array<T extends core.SomeType>(element: T, params?: string | core.$ZodArrayParams): ZodArray<T> {
|
||||
@@ -1198,11 +1396,11 @@ export interface ZodObject<
|
||||
/** This is the default behavior. This method call is likely unnecessary. */
|
||||
strip(): ZodObject<Shape, core.$strip>;
|
||||
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
|
||||
safeExtend<U extends core.$ZodLooseShape>(
|
||||
shape: SafeExtendShape<Shape, U> & Partial<Record<keyof Shape, core.SomeType>>
|
||||
): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
|
||||
/**
|
||||
* @deprecated Use [`A.extend(B.shape)`](https://zod.dev/api?id=extend) instead.
|
||||
@@ -1219,7 +1417,7 @@ export interface ZodObject<
|
||||
|
||||
partial(): ZodObject<
|
||||
{
|
||||
[k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
},
|
||||
Config
|
||||
>;
|
||||
@@ -1227,7 +1425,7 @@ export interface ZodObject<
|
||||
mask: M & Record<Exclude<keyof M, keyof Shape>, never>
|
||||
): ZodObject<
|
||||
{
|
||||
[k in keyof Shape]: k extends keyof M
|
||||
-readonly [k in keyof Shape]: k extends keyof M
|
||||
? // Shape[k] extends OptionalInSchema
|
||||
// ? Shape[k]
|
||||
// :
|
||||
@@ -1240,7 +1438,7 @@ export interface ZodObject<
|
||||
// required
|
||||
required(): ZodObject<
|
||||
{
|
||||
[k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
},
|
||||
Config
|
||||
>;
|
||||
@@ -1248,7 +1446,7 @@ export interface ZodObject<
|
||||
mask: M & Record<Exclude<keyof M, keyof Shape>, never>
|
||||
): ZodObject<
|
||||
{
|
||||
[k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
-readonly [k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
},
|
||||
Config
|
||||
>;
|
||||
@@ -1263,24 +1461,47 @@ export const ZodObject: core.$constructor<ZodObject> = /*@__PURE__*/ core.$const
|
||||
return def.shape;
|
||||
});
|
||||
|
||||
inst.keyof = () => _enum(Object.keys(inst._zod.def.shape)) as any;
|
||||
inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall as any as core.$ZodType }) as any;
|
||||
inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.strict = () => inst.clone({ ...inst._zod.def, catchall: never() });
|
||||
inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
|
||||
|
||||
inst.extend = (incoming: any) => {
|
||||
return util.extend(inst, incoming);
|
||||
};
|
||||
inst.safeExtend = (incoming: any) => {
|
||||
return util.safeExtend(inst, incoming);
|
||||
};
|
||||
inst.merge = (other) => util.merge(inst, other);
|
||||
inst.pick = (mask) => util.pick(inst, mask);
|
||||
inst.omit = (mask) => util.omit(inst, mask);
|
||||
inst.partial = (...args: any[]) => util.partial(ZodOptional, inst, args[0] as object);
|
||||
inst.required = (...args: any[]) => util.required(ZodNonOptional, inst, args[0] as object);
|
||||
_installLazyMethods(inst, "ZodObject", {
|
||||
keyof() {
|
||||
return _enum(Object.keys(this._zod.def.shape));
|
||||
},
|
||||
catchall(catchall) {
|
||||
return this.clone({ ...this._zod.def, catchall: catchall as any });
|
||||
},
|
||||
passthrough() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
loose() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
strict() {
|
||||
return this.clone({ ...this._zod.def, catchall: never() });
|
||||
},
|
||||
strip() {
|
||||
return this.clone({ ...this._zod.def, catchall: undefined });
|
||||
},
|
||||
extend(incoming) {
|
||||
return util.extend(this, incoming);
|
||||
},
|
||||
safeExtend(incoming) {
|
||||
return util.safeExtend(this, incoming);
|
||||
},
|
||||
merge(other) {
|
||||
return util.merge(this, other);
|
||||
},
|
||||
pick(mask) {
|
||||
return util.pick(this, mask);
|
||||
},
|
||||
omit(mask) {
|
||||
return util.omit(this, mask);
|
||||
},
|
||||
partial(...args) {
|
||||
return util.partial(ZodOptional, this, args[0]);
|
||||
},
|
||||
required(...args) {
|
||||
return util.required(ZodNonOptional, this, args[0]);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export function object<T extends core.$ZodLooseShape = Partial<Record<never, core.SomeType>>>(
|
||||
@@ -1300,7 +1521,7 @@ export function object<T extends core.$ZodLooseShape = Partial<Record<never, cor
|
||||
export function strictObject<T extends core.$ZodLooseShape>(
|
||||
shape: T,
|
||||
params?: string | core.$ZodObjectParams
|
||||
): ZodObject<T, core.$strict> {
|
||||
): ZodObject<util.Writeable<T>, core.$strict> {
|
||||
return new ZodObject({
|
||||
type: "object",
|
||||
shape,
|
||||
@@ -1314,7 +1535,7 @@ export function strictObject<T extends core.$ZodLooseShape>(
|
||||
export function looseObject<T extends core.$ZodLooseShape>(
|
||||
shape: T,
|
||||
params?: string | core.$ZodObjectParams
|
||||
): ZodObject<T, core.$loose> {
|
||||
): ZodObject<util.Writeable<T>, core.$loose> {
|
||||
return new ZodObject({
|
||||
type: "object",
|
||||
shape,
|
||||
@@ -1396,7 +1617,7 @@ export const ZodDiscriminatedUnion: core.$constructor<ZodDiscriminatedUnion> = /
|
||||
);
|
||||
|
||||
export function discriminatedUnion<
|
||||
Types extends readonly [core.$ZodTypeDiscriminable, ...core.$ZodTypeDiscriminable[]],
|
||||
Types extends readonly [core.$ZodTypeDiscriminable<Disc>, ...core.$ZodTypeDiscriminable<Disc>[]],
|
||||
Disc extends string,
|
||||
>(
|
||||
discriminator: Disc,
|
||||
@@ -1508,6 +1729,15 @@ export function record<Key extends core.$ZodRecordKey, Value extends core.SomeTy
|
||||
valueType: Value,
|
||||
params?: string | core.$ZodRecordParams
|
||||
): ZodRecord<Key, Value> {
|
||||
// v3-compat: z.record(valueType, params?) — defaults keyType to z.string()
|
||||
if (!valueType || !(valueType as any)._zod) {
|
||||
return new ZodRecord({
|
||||
type: "record",
|
||||
keyType: string() as any,
|
||||
valueType: keyType as any as core.$ZodType,
|
||||
...util.normalizeParams(valueType as string | core.$ZodRecordParams | undefined),
|
||||
}) as any;
|
||||
}
|
||||
return new ZodRecord({
|
||||
type: "record",
|
||||
keyType,
|
||||
@@ -1702,7 +1932,7 @@ export function nativeEnum<T extends util.EnumLike>(entries: T, params?: string
|
||||
type: "enum",
|
||||
entries,
|
||||
...util.normalizeParams(params),
|
||||
}) as any as ZodEnum<T>;
|
||||
}) as ZodEnum<T>;
|
||||
}
|
||||
|
||||
// ZodLiteral
|
||||
@@ -1804,17 +2034,19 @@ export const ZodTransform: core.$constructor<ZodTransform> = /*@__PURE__*/ core.
|
||||
if (output instanceof Promise) {
|
||||
return output.then((output) => {
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
});
|
||||
}
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export function transform<I = unknown, O = I>(
|
||||
fn: (input: I, ctx: core.ParsePayload) => O
|
||||
fn: (input: I, ctx: core.$RefinementCtx) => O
|
||||
): ZodTransform<Awaited<O>, I> {
|
||||
return new ZodTransform({
|
||||
type: "transform",
|
||||
@@ -2120,6 +2352,33 @@ export function codec<const A extends core.SomeType, B extends core.SomeType = c
|
||||
}) as any;
|
||||
}
|
||||
|
||||
export function invertCodec<A extends core.SomeType, B extends core.SomeType>(codec: ZodCodec<A, B>): ZodCodec<B, A> {
|
||||
const def = codec._zod.def;
|
||||
return new ZodCodec({
|
||||
type: "pipe",
|
||||
in: def.out as any,
|
||||
out: def.in as any,
|
||||
transform: def.reverseTransform as any,
|
||||
reverseTransform: def.transform as any,
|
||||
}) as any;
|
||||
}
|
||||
|
||||
// ZodPreprocess
|
||||
export interface ZodPreprocess<B extends core.SomeType = core.$ZodType>
|
||||
extends ZodPipe<core.$ZodTransform, B>,
|
||||
core.$ZodPreprocess<B> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
_zod: core.$ZodPreprocessInternals<B>;
|
||||
def: core.$ZodPreprocessDef<B>;
|
||||
}
|
||||
export const ZodPreprocess: core.$constructor<ZodPreprocess> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodPreprocess",
|
||||
(inst, def) => {
|
||||
ZodPipe.init(inst, def);
|
||||
core.$ZodPreprocess.init(inst, def);
|
||||
}
|
||||
);
|
||||
|
||||
// ZodReadonly
|
||||
export interface ZodReadonly<T extends core.SomeType = core.$ZodType>
|
||||
extends _ZodType<core.$ZodReadonlyInternals<T>>,
|
||||
@@ -2321,9 +2580,10 @@ export function refine<T>(
|
||||
|
||||
// superRefine
|
||||
export function superRefine<T>(
|
||||
fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>
|
||||
fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>,
|
||||
params?: core.$ZodSuperRefineParams
|
||||
): core.$ZodCheck<T> {
|
||||
return core._superRefine(fn);
|
||||
return core._superRefine(fn, params);
|
||||
}
|
||||
|
||||
// Re-export describe and meta from core
|
||||
@@ -2400,10 +2660,13 @@ export function json(params?: string | core.$ZodCustomParams): ZodJSONSchema {
|
||||
|
||||
// preprocess
|
||||
|
||||
// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */
|
||||
export function preprocess<A, U extends core.SomeType, B = unknown>(
|
||||
fn: (arg: B, ctx: core.$RefinementCtx) => A,
|
||||
schema: U
|
||||
): ZodPipe<ZodTransform<A, B>, U> {
|
||||
return pipe(transform(fn as any), schema as any) as any;
|
||||
): ZodPreprocess<U> {
|
||||
return new ZodPreprocess({
|
||||
type: "pipe",
|
||||
in: transform(fn as any) as any as core.$ZodTransform,
|
||||
out: schema as any as core.$ZodType,
|
||||
}) as any;
|
||||
}
|
||||
|
||||
+6
@@ -143,6 +143,12 @@ test("assignability", () => {
|
||||
z.unknown().pipe(z.number()) satisfies z.core.$ZodPipe;
|
||||
z.unknown().pipe(z.number()) satisfies z.ZodPipe;
|
||||
|
||||
// $ZodPreprocess
|
||||
z.preprocess((v) => v, z.number()) satisfies z.core.$ZodPreprocess;
|
||||
z.preprocess((v) => v, z.number()) satisfies z.ZodPreprocess;
|
||||
z.preprocess((v) => v, z.number()) satisfies z.core.$ZodPipe<z.core.$ZodTransform, z.ZodNumber>;
|
||||
z.preprocess((v) => v, z.number()) satisfies z.ZodPipe<z.core.$ZodTransform, z.ZodNumber>;
|
||||
|
||||
// $ZodSuccess
|
||||
z.success(z.string()) satisfies z.core.$ZodSuccess;
|
||||
z.success(z.string()) satisfies z.ZodSuccess;
|
||||
|
||||
+50
@@ -128,7 +128,9 @@ test("native enum", () => {
|
||||
fruit: z.nativeEnum(Fruits).catch(Fruits.apple),
|
||||
});
|
||||
|
||||
// Absent keys flow through to the catch handler.
|
||||
expect(schema.parse({})).toEqual({ fruit: Fruits.apple });
|
||||
expect(schema.parse({}, { jitless: true })).toEqual({ fruit: Fruits.apple });
|
||||
expect(schema.parse({ fruit: 15 })).toEqual({ fruit: Fruits.apple });
|
||||
});
|
||||
|
||||
@@ -138,6 +140,7 @@ test("enum", () => {
|
||||
});
|
||||
|
||||
expect(schema.parse({})).toEqual({ fruit: "apple" });
|
||||
expect(schema.parse({}, { jitless: true })).toEqual({ fruit: "apple" });
|
||||
expect(schema.parse({ fruit: true })).toEqual({ fruit: "apple" });
|
||||
expect(schema.parse({ fruit: 15 })).toEqual({ fruit: "apple" });
|
||||
});
|
||||
@@ -274,3 +277,50 @@ test("direction-aware catch", () => {
|
||||
// But valid values should still work in reverse
|
||||
expect(z.encode(schema, "world")).toBe("world");
|
||||
});
|
||||
|
||||
test("optional clobbers catch through pipe boundaries", () => {
|
||||
expect(
|
||||
z
|
||||
.string()
|
||||
.catch("X")
|
||||
.transform((s) => s + "!")
|
||||
.optional()
|
||||
.parse(undefined)
|
||||
).toBeUndefined();
|
||||
expect(z.string().catch("X").pipe(z.string()).optional().parse(undefined)).toBeUndefined();
|
||||
expect(
|
||||
z
|
||||
.string()
|
||||
.catch("X")
|
||||
.transform((s) => s + "!")
|
||||
.transform((s) => s.toLowerCase())
|
||||
.optional()
|
||||
.parse(undefined)
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
z
|
||||
.object({
|
||||
a: z
|
||||
.string()
|
||||
.catch("X")
|
||||
.transform((s) => s + "!")
|
||||
.optional(),
|
||||
})
|
||||
.parse({})
|
||||
).toEqual({});
|
||||
|
||||
expect(
|
||||
z
|
||||
.string()
|
||||
.catch("X")
|
||||
.transform((s) => s + "!")
|
||||
.parse("hi")
|
||||
).toBe("hi!");
|
||||
expect(
|
||||
z
|
||||
.string()
|
||||
.catch("X")
|
||||
.transform((s) => s + "!")
|
||||
.parse(123)
|
||||
).toBe("X!");
|
||||
});
|
||||
|
||||
+142
-1
@@ -1,4 +1,4 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import { describe, expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
const isoDateCodec = z.codec(
|
||||
@@ -560,3 +560,144 @@ test("async codec functionality", async () => {
|
||||
const mixedResult = await z.decodeAsync(mixedCodec, "123");
|
||||
expect(mixedResult).toBe(123);
|
||||
});
|
||||
|
||||
test("invertCodec basic", () => {
|
||||
const inverted = z.invertCodec(isoDateCodec);
|
||||
|
||||
const testDate = new Date("2024-01-15T10:30:00.000Z");
|
||||
const decoded = z.decode(inverted, testDate);
|
||||
expect(typeof decoded).toBe("string");
|
||||
expect(decoded).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");
|
||||
});
|
||||
|
||||
test("invertCodec round trip", () => {
|
||||
const inverted = z.invertCodec(isoDateCodec);
|
||||
const testDate = new Date("2024-06-01T12:00:00.000Z");
|
||||
|
||||
const toStr = z.decode(inverted, testDate);
|
||||
const backToDate = z.encode(inverted, toStr);
|
||||
expect(backToDate.toISOString()).toBe(testDate.toISOString());
|
||||
});
|
||||
|
||||
test("invertCodec types", () => {
|
||||
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>();
|
||||
});
|
||||
|
||||
test("invertCodec is its own inverse", () => {
|
||||
const doubleInverted = z.invertCodec(z.invertCodec(isoDateCodec));
|
||||
const testIsoString = "2024-03-10T08:00:00.000Z";
|
||||
|
||||
const decoded = z.decode(doubleInverted, testIsoString);
|
||||
expect(decoded).toBeInstanceOf(Date);
|
||||
expect(decoded.toISOString()).toBe(testIsoString);
|
||||
|
||||
const encoded = z.encode(doubleInverted, decoded);
|
||||
expect(encoded).toBe(testIsoString);
|
||||
});
|
||||
|
||||
test("invertCodec with custom codec", () => {
|
||||
const intToString = z.codec(z.int(), z.string().regex(/^\d+$/), {
|
||||
decode: (num) => num.toString(),
|
||||
encode: (str) => Number.parseInt(str, 10),
|
||||
});
|
||||
|
||||
const stringToInt = z.invertCodec(intToString);
|
||||
const result = z.decode(stringToInt, "42");
|
||||
expect(result).toBe(42);
|
||||
|
||||
const back = z.encode(stringToInt, 42);
|
||||
expect(back).toBe("42");
|
||||
});
|
||||
|
||||
describe("context immutability", () => {
|
||||
test("decode/encode", () => {
|
||||
const stringToDateCodec = z.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
});
|
||||
|
||||
const ctx = { reportInput: true } as const;
|
||||
|
||||
const result1 = z.decode(stringToDateCodec, "2024-01-15T10:30:00.000Z", ctx);
|
||||
expect(result1).toBeInstanceOf(Date);
|
||||
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
const result2 = z.decode(stringToDateCodec, "2024-12-25T15:45:30.123Z", ctx);
|
||||
expect(result2).toBeInstanceOf(Date);
|
||||
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
z.encode(stringToDateCodec, new Date("2024-01-01T00:00:00.000Z"), ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
z.safeEncode(stringToDateCodec, new Date("2024-01-01T00:00:00.000Z"), ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("direction" in ctx).toBe(false);
|
||||
});
|
||||
|
||||
test("parse functions", () => {
|
||||
const schema = z.string().min(1);
|
||||
const ctx = { reportInput: true } as const;
|
||||
|
||||
z.parse(schema, "asdf", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
|
||||
z.safeParse(schema, "asdf", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
});
|
||||
|
||||
test("async functions", async () => {
|
||||
const stringToDateCodec = z.codec(z.iso.datetime(), z.date(), {
|
||||
decode: (isoString) => new Date(isoString),
|
||||
encode: (date) => date.toISOString(),
|
||||
});
|
||||
|
||||
const ctx = { reportInput: true } as const;
|
||||
|
||||
const schema = z.string();
|
||||
await z.parseAsync(schema, "asdf", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
|
||||
await z.safeParseAsync(schema, "asdf", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
|
||||
await z.decodeAsync(stringToDateCodec, "2024-01-15T10:30:00.000Z", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
await z.encodeAsync(stringToDateCodec, new Date("2024-01-01T00:00:00.000Z"), ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
await z.safeDecodeAsync(stringToDateCodec, "2024-01-15T10:30:00.000Z", ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
|
||||
await z.safeEncodeAsync(stringToDateCodec, new Date("2024-01-01T00:00:00.000Z"), ctx);
|
||||
expect(ctx).toEqual({ reportInput: true });
|
||||
expect("async" in ctx).toBe(false);
|
||||
expect("direction" in ctx).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -274,7 +274,7 @@ test("continuability", () => {
|
||||
"message": "Invalid cuid",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[cC][^\\s-]{8,}$/",
|
||||
"pattern": "/^[cC][0-9a-z]{6,}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
|
||||
+1
-1
@@ -299,4 +299,4 @@ test("redos checker", () => {
|
||||
const result = checkSync(schema._zod.pattern.source, "");
|
||||
if (result.status !== "safe") throw Error("ReDoS issue");
|
||||
}
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
+44
@@ -332,6 +332,50 @@ test("defaulted array schema returns shallow clone", () => {
|
||||
expect(result1).toEqual(result2);
|
||||
});
|
||||
|
||||
test("defaulted Map schema returns shallow clone", () => {
|
||||
const schema = z.map(z.string(), z.number()).default(new Map([["a", 1]]));
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
expect(result1).not.toBe(result2);
|
||||
expect(result1).toEqual(result2);
|
||||
});
|
||||
|
||||
test("defaulted Set schema returns shallow clone", () => {
|
||||
const schema = z.set(z.string()).default(new Set(["x"]));
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
expect(result1).not.toBe(result2);
|
||||
expect(result1).toEqual(result2);
|
||||
});
|
||||
|
||||
test("mutations on defaulted Map do not affect subsequent parses", () => {
|
||||
const schema = z.map(z.string(), z.number()).default(new Map());
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
result1.set("key1", 1);
|
||||
result2.set("key2", 2);
|
||||
expect(result1.size).toBe(1);
|
||||
expect(result1.get("key1")).toBe(1);
|
||||
expect(result1.has("key2")).toBe(false);
|
||||
expect(result2.size).toBe(1);
|
||||
expect(result2.get("key2")).toBe(2);
|
||||
expect(result2.has("key1")).toBe(false);
|
||||
});
|
||||
|
||||
test("mutations on defaulted Set do not affect subsequent parses", () => {
|
||||
const schema = z.set(z.string()).default(new Set());
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
result1.add("item1");
|
||||
result2.add("item2");
|
||||
expect(result1.size).toBe(1);
|
||||
expect(result1.has("item1")).toBe(true);
|
||||
expect(result1.has("item2")).toBe(false);
|
||||
expect(result2.size).toBe(1);
|
||||
expect(result2.has("item2")).toBe(true);
|
||||
expect(result2.has("item1")).toBe(false);
|
||||
});
|
||||
|
||||
test("direction-aware defaults", () => {
|
||||
const schema = z.string().default("hello");
|
||||
|
||||
|
||||
+34
-1
@@ -158,10 +158,14 @@ test("invalid discriminator value", () => {
|
||||
"errors": [],
|
||||
"note": "No matching discriminator",
|
||||
"discriminator": "type",
|
||||
"options": [
|
||||
"a",
|
||||
"b"
|
||||
],
|
||||
"path": [
|
||||
"type"
|
||||
],
|
||||
"message": "Invalid input"
|
||||
"message": "Invalid discriminator value. Expected 'a' | 'b'"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
@@ -260,6 +264,9 @@ test("valid discriminator value, invalid data", () => {
|
||||
});
|
||||
|
||||
test("wrong schema - missing discriminator", () => {
|
||||
// @ts-expect-error missing discriminator property
|
||||
z.discriminatedUnion("type", [z.object({ value: z.string() })]);
|
||||
|
||||
try {
|
||||
z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal("a"), a: z.string() }),
|
||||
@@ -659,3 +666,29 @@ test("def", () => {
|
||||
expect(schema.def.discriminator).toEqual("type");
|
||||
expect(schema.def.unionFallback).toEqual(true);
|
||||
});
|
||||
|
||||
test("encode with codec discriminator", () => {
|
||||
const codec1 = z.codec(z.literal(1), z.literal("one"), {
|
||||
decode: () => "one" as const,
|
||||
encode: () => 1 as const,
|
||||
});
|
||||
|
||||
const codec2 = z.codec(z.literal(2), z.literal("two"), {
|
||||
decode: () => "two" as const,
|
||||
encode: () => 2 as const,
|
||||
});
|
||||
|
||||
const schema = z.discriminatedUnion("type", [
|
||||
z.object({ type: codec1, value: z.string() }),
|
||||
z.object({ type: codec2, value: z.number() }),
|
||||
]);
|
||||
|
||||
// decode (forward) should work
|
||||
const decoded = schema.decode({ type: 1, value: "hello" });
|
||||
expect(decoded).toEqual({ type: "one", value: "hello" });
|
||||
|
||||
// encode (backward) should also work — the discriminator values differ
|
||||
// between forward (1, 2) and backward ("one", "two") directions
|
||||
const encoded = z.encode(schema, { type: "one", value: "hello" });
|
||||
expect(encoded).toEqual({ type: 1, value: "hello" });
|
||||
});
|
||||
|
||||
+214
-2
@@ -80,7 +80,10 @@ test(".flatten()", () => {
|
||||
|
||||
test("custom .flatten()", () => {
|
||||
type ErrorType = { message: string; code: number };
|
||||
const flattened = parsed.error!.flatten((iss) => ({ message: iss.message, code: 1234 }));
|
||||
const flattened = parsed.error!.flatten((iss) => ({
|
||||
message: iss.message,
|
||||
code: 1234,
|
||||
}));
|
||||
expectTypeOf(flattened).toMatchTypeOf<{
|
||||
formErrors: ErrorType[];
|
||||
fieldErrors: {
|
||||
@@ -160,7 +163,10 @@ test(".format()", () => {
|
||||
|
||||
test("custom .format()", () => {
|
||||
type ErrorType = { message: string; code: number };
|
||||
const formatted = parsed.error!.format((iss) => ({ message: iss.message, code: 1234 }));
|
||||
const formatted = parsed.error!.format((iss) => ({
|
||||
message: iss.message,
|
||||
code: 1234,
|
||||
}));
|
||||
expectTypeOf(formatted).toMatchTypeOf<{
|
||||
_errors: ErrorType[];
|
||||
f2?: { _errors: ErrorType[] };
|
||||
@@ -593,3 +599,209 @@ test("update message after adding issues", () => {
|
||||
]"
|
||||
`);
|
||||
});
|
||||
|
||||
test("z.formatError nested union preserves parent path", () => {
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["parent"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: {},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["child"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "number",
|
||||
path: [],
|
||||
message: "Expected number",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const formatted: any = z.formatError(syntheticError);
|
||||
|
||||
// "child" must be nested under "parent", not at root
|
||||
expect(formatted).not.toHaveProperty("child");
|
||||
expect(formatted).toHaveProperty("parent");
|
||||
expect(formatted.parent).toHaveProperty("child");
|
||||
expect(formatted.parent.child._errors).toContain("Expected string");
|
||||
expect(formatted.parent.child._errors).toContain("Expected number");
|
||||
expect(formatted.parent._errors).toContain("Expected string");
|
||||
});
|
||||
test("z.treeifyError nested union preserves parent path", () => {
|
||||
// When a nested invalid_union appears inside another invalid_union,
|
||||
// the inner errors must stay nested under their parent path, not flatten to root.
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["parent"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: {},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["child"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "number",
|
||||
path: [],
|
||||
message: "Expected number",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const tree: any = z.treeifyError(syntheticError);
|
||||
|
||||
// "child" must be nested under "parent", not at root
|
||||
expect(tree.properties).not.toHaveProperty("child");
|
||||
expect(tree.properties).toHaveProperty("parent");
|
||||
expect(tree.properties.parent.properties).toHaveProperty("child");
|
||||
expect(tree.properties.parent.properties.child.errors).toContain("Expected string");
|
||||
expect(tree.properties.parent.properties.child.errors).toContain("Expected number");
|
||||
expect(tree.properties.parent.errors).toContain("Expected string");
|
||||
});
|
||||
|
||||
test("z.treeifyError deeply nested union (4 levels) preserves full path", () => {
|
||||
// a > b > c > d — each level wrapped in an invalid_union
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["a"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["b"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["c"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: ["d"],
|
||||
message: "Expected string",
|
||||
input: 123,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const tree: any = z.treeifyError(syntheticError);
|
||||
|
||||
// The full path must be preserved: a.b.c.d
|
||||
expect(tree.properties).toHaveProperty("a");
|
||||
expect(tree.properties).not.toHaveProperty("b");
|
||||
expect(tree.properties).not.toHaveProperty("c");
|
||||
|
||||
const lvlA = tree.properties.a;
|
||||
expect(lvlA.properties).toHaveProperty("b");
|
||||
|
||||
const lvlB = lvlA.properties.b;
|
||||
expect(lvlB.properties).toHaveProperty("c");
|
||||
|
||||
const lvlC = lvlB.properties.c;
|
||||
expect(lvlC.properties).toHaveProperty("d");
|
||||
expect(lvlC.properties.d.errors).toContain("Expected string");
|
||||
});
|
||||
|
||||
test("z.treeifyError nested union with real schema", () => {
|
||||
const innerUnion = z.union([
|
||||
z.object({ type: z.literal("a"), value: z.string() }),
|
||||
z.object({ type: z.literal("b"), value: z.number() }),
|
||||
]);
|
||||
|
||||
const schema = z.string().or(
|
||||
z.object({
|
||||
settings: z.object({ name: z.string() }).and(innerUnion),
|
||||
})
|
||||
);
|
||||
|
||||
const result = schema.safeParse({
|
||||
settings: { name: 123, type: "x", value: true },
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
if (!result.success) {
|
||||
const tree: any = z.treeifyError(result.error);
|
||||
|
||||
// All settings-related errors should be under "settings", not at root
|
||||
expect(tree.properties).toHaveProperty("settings");
|
||||
const settingsProperties = tree.properties.settings.properties ?? {};
|
||||
for (const key of Object.keys(settingsProperties)) {
|
||||
// Every sub-property under settings should NOT also appear at root
|
||||
if (key !== "settings") {
|
||||
expect(tree.properties).not.toHaveProperty(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+161
@@ -732,3 +732,164 @@ test("contentEncoding and contentMediaType are stored as metadata", () => {
|
||||
expect(meta?.contentEncoding).toBe("base64");
|
||||
expect(meta?.contentMediaType).toBe("image/png");
|
||||
});
|
||||
|
||||
test("description on enum schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
enum: ["red", "green", "blue"],
|
||||
description: "A color value",
|
||||
});
|
||||
expect(schema.description).toBe("A color value");
|
||||
expect(schema.parse("red")).toBe("red");
|
||||
});
|
||||
|
||||
test("description on const schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
const: "hello",
|
||||
description: "A greeting",
|
||||
});
|
||||
expect(schema.description).toBe("A greeting");
|
||||
expect(schema.parse("hello")).toBe("hello");
|
||||
});
|
||||
|
||||
test("description on not: {} (never) schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
not: {},
|
||||
description: "A never schema",
|
||||
});
|
||||
expect(schema.description).toBe("A never schema");
|
||||
expect(() => schema.parse("anything")).toThrow();
|
||||
});
|
||||
|
||||
test("default on enum schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
enum: ["red", "green", "blue"],
|
||||
default: "red",
|
||||
});
|
||||
expect(schema.parse(undefined)).toBe("red");
|
||||
});
|
||||
|
||||
test("default on const schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
const: "hello",
|
||||
default: "hello",
|
||||
});
|
||||
expect(schema.parse(undefined)).toBe("hello");
|
||||
});
|
||||
|
||||
test("description and default on enum schema are both applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
enum: ["red", "green", "blue"],
|
||||
description: "A color value",
|
||||
default: "red",
|
||||
});
|
||||
expect(schema.description).toBe("A color value");
|
||||
expect(schema.parse(undefined)).toBe("red");
|
||||
expect(schema.parse("green")).toBe("green");
|
||||
});
|
||||
|
||||
test("description on type-array schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
type: ["string", "number"],
|
||||
description: "A string or number",
|
||||
} as any);
|
||||
expect(schema.description).toBe("A string or number");
|
||||
expect(schema.parse("hello")).toBe("hello");
|
||||
expect(schema.parse(42)).toBe(42);
|
||||
});
|
||||
|
||||
test("default on type-array schema is applied", () => {
|
||||
const schema = fromJSONSchema({
|
||||
type: ["string", "number"],
|
||||
default: "fallback",
|
||||
} as any);
|
||||
expect(schema.parse(undefined)).toBe("fallback");
|
||||
expect(schema.parse("hello")).toBe("hello");
|
||||
expect(schema.parse(42)).toBe(42);
|
||||
});
|
||||
|
||||
test("description on schema with anyOf is applied to the outer schema", () => {
|
||||
const schema = fromJSONSchema({
|
||||
description: "Either a string or a number",
|
||||
anyOf: [{ type: "string" }, { type: "number" }],
|
||||
});
|
||||
expect(schema.description).toBe("Either a string or a number");
|
||||
expect(schema.parse("hello")).toBe("hello");
|
||||
expect(schema.parse(42)).toBe(42);
|
||||
});
|
||||
|
||||
test("default on schema with anyOf is applied to the outer schema", () => {
|
||||
const schema = fromJSONSchema({
|
||||
default: "fallback",
|
||||
anyOf: [{ type: "string" }, { type: "number" }],
|
||||
});
|
||||
expect(schema.parse(undefined)).toBe("fallback");
|
||||
expect(schema.parse(42)).toBe(42);
|
||||
});
|
||||
|
||||
test("description and unrecognized metadata coexist on the same schema", () => {
|
||||
const customRegistry = z.registry<{ "x-custom"?: string; description?: string }>();
|
||||
const schema = fromJSONSchema(
|
||||
{
|
||||
type: "string",
|
||||
description: "A custom string",
|
||||
"x-custom": "value",
|
||||
},
|
||||
{ registry: customRegistry }
|
||||
);
|
||||
expect(schema.description).toBe("A custom string");
|
||||
expect(customRegistry.get(schema)?.["x-custom"]).toBe("value");
|
||||
});
|
||||
|
||||
test("circular input throws a clear error", () => {
|
||||
const person: any = {
|
||||
type: "object",
|
||||
properties: { name: { type: "string" } },
|
||||
required: ["name"],
|
||||
};
|
||||
person.properties.bestFriend = person;
|
||||
expect(() => fromJSONSchema(person)).toThrow(/not valid JSON/);
|
||||
});
|
||||
|
||||
test("getter-based input that synthesizes a cycle throws", () => {
|
||||
const root: any = { type: "object", properties: { name: { type: "string" } } };
|
||||
Object.defineProperty(root.properties, "self", {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return root;
|
||||
},
|
||||
});
|
||||
expect(() => fromJSONSchema(root)).toThrow(/not valid JSON/);
|
||||
});
|
||||
|
||||
test("BigInt in input throws", () => {
|
||||
const input: any = { type: "integer", minimum: 1n };
|
||||
expect(() => fromJSONSchema(input)).toThrow(/not valid JSON/);
|
||||
});
|
||||
|
||||
test("class-instance input is normalized to a plain object", () => {
|
||||
class StringSchema {
|
||||
type = "string" as const;
|
||||
minLength = 2;
|
||||
}
|
||||
const schema = fromJSONSchema(new StringSchema() as any);
|
||||
expect(schema.parse("hi")).toBe("hi");
|
||||
expect(() => schema.parse("h")).toThrow();
|
||||
});
|
||||
|
||||
test("getter-based properties are materialized", () => {
|
||||
const input: any = { type: "object", properties: {}, required: [] };
|
||||
Object.defineProperty(input.properties, "name", {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return { type: "string" };
|
||||
},
|
||||
});
|
||||
const schema = fromJSONSchema(input);
|
||||
expect(schema.parse({ name: "Alice" })).toEqual({ name: "Alice" });
|
||||
});
|
||||
|
||||
test("Date default is coerced to its JSON string form", () => {
|
||||
const date = new Date("2026-01-02T03:04:05.000Z");
|
||||
const schema = fromJSONSchema({ type: "string", default: date as any });
|
||||
expect(schema.parse(undefined)).toBe(date.toISOString());
|
||||
});
|
||||
|
||||
+6
-6
@@ -186,12 +186,12 @@ test("input validation error", () => {
|
||||
expect(e.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"message": "Invalid input: expected string, received undefined",
|
||||
"path": [
|
||||
0,
|
||||
],
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=1 items",
|
||||
"minimum": 1,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
+2
-2
@@ -247,7 +247,7 @@ test("z.tuple", () => {
|
||||
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[]]>();
|
||||
expectTypeOf<b>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
const datas = [
|
||||
["hello", 123],
|
||||
["hello", 123, "world"],
|
||||
@@ -265,7 +265,7 @@ test("z.tuple", () => {
|
||||
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[]]>();
|
||||
expectTypeOf<c>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
// type c = z.output<typeof c>;
|
||||
});
|
||||
|
||||
|
||||
+55
@@ -153,6 +153,36 @@ test(".multipleOf() with negative divisor", () => {
|
||||
expect(() => schema.parse(7.5)).toThrow();
|
||||
});
|
||||
|
||||
test(".multipleOf() with scientific notation (multi-digit exponents)", () => {
|
||||
// Regression test for https://github.com/colinhacks/zod/pull/5687
|
||||
// The regex was using \d? which only matches single-digit exponents
|
||||
const schema = z.number().multipleOf(1e-10);
|
||||
|
||||
// These should all pass - they are valid multiples of 1e-10
|
||||
expect(schema.parse(1e-10)).toEqual(1e-10);
|
||||
expect(schema.parse(5e-10)).toEqual(5e-10);
|
||||
expect(schema.parse(1e-9)).toEqual(1e-9); // 10 * 1e-10
|
||||
|
||||
// Test with 1e-15 (exponent = 15, two digits)
|
||||
const schema15 = z.number().multipleOf(1e-15);
|
||||
expect(schema15.parse(1e-15)).toEqual(1e-15);
|
||||
expect(schema15.parse(3e-15)).toEqual(3e-15);
|
||||
});
|
||||
|
||||
test(".multipleOf() with small floats / scientific notation (#5792)", () => {
|
||||
const schema = z.number().multipleOf(1e-7);
|
||||
|
||||
// Valid multiples (integer * 1e-7)
|
||||
expect(schema.safeParse(0).success).toBe(true);
|
||||
expect(schema.safeParse(1e-7).success).toBe(true);
|
||||
expect(schema.safeParse(2e-7).success).toBe(true);
|
||||
expect(schema.safeParse(3e-7).success).toBe(true);
|
||||
|
||||
// Invalid — 2.5 and 1.5 are not integers
|
||||
expect(schema.safeParse(2.5e-7).success).toBe(false);
|
||||
expect(schema.safeParse(1.5e-7).success).toBe(false);
|
||||
});
|
||||
|
||||
test(".step() validation", () => {
|
||||
const schemaPointOne = z.number().step(0.1);
|
||||
const schemaPointZeroZeroZeroOne = z.number().step(0.0001);
|
||||
@@ -264,6 +294,31 @@ test("string format methods", () => {
|
||||
expect(() => a.parse(1)).toThrow();
|
||||
});
|
||||
|
||||
test("negative zero edge case", () => {
|
||||
const schema = z.number();
|
||||
const negativeZero = -0;
|
||||
const positiveZero = 0;
|
||||
|
||||
// Both -0 and 0 should be valid (parse succeeds)
|
||||
expect(schema.safeParse(negativeZero).success).toBe(true);
|
||||
expect(schema.safeParse(positiveZero).success).toBe(true);
|
||||
// Note: -0 is normalized to 0 after parsing
|
||||
expect(schema.parse(negativeZero) === 0).toBe(true);
|
||||
expect(schema.parse(positiveZero)).toEqual(0);
|
||||
|
||||
// With positive() constraint, both should be invalid (0 is not positive)
|
||||
const positiveSchema = z.number().positive();
|
||||
expect(() => positiveSchema.parse(negativeZero)).toThrow();
|
||||
expect(() => positiveSchema.parse(positiveZero)).toThrow();
|
||||
|
||||
// With nonnegative(), both should be valid (0 is non-negative)
|
||||
const nonnegativeSchema = z.number().nonnegative();
|
||||
expect(nonnegativeSchema.safeParse(negativeZero).success).toBe(true);
|
||||
expect(nonnegativeSchema.safeParse(positiveZero).success).toBe(true);
|
||||
expect(nonnegativeSchema.parse(negativeZero) === 0).toBe(true);
|
||||
expect(nonnegativeSchema.parse(positiveZero)).toEqual(0);
|
||||
});
|
||||
|
||||
test("error customization", () => {
|
||||
z.number().gte(5, { error: (iss) => "Min: " + iss.minimum.valueOf() });
|
||||
z.number().lte(5, { error: (iss) => "Max: " + iss.maximum.valueOf() });
|
||||
|
||||
+83
-6
@@ -1,4 +1,4 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import { describe, expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
import * as core from "zod/v4/core";
|
||||
|
||||
@@ -232,8 +232,7 @@ test("inferred merged object type with optional properties", async () => {
|
||||
.object({ a: z.string(), b: z.string().optional() })
|
||||
.merge(z.object({ a: z.string().optional(), b: z.string() }));
|
||||
type Merged = z.infer<typeof Merged>;
|
||||
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string; b: string }>();
|
||||
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string; b: string }>();
|
||||
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string | undefined; b: string }>();
|
||||
});
|
||||
|
||||
test("inferred unioned object type with optional properties", async () => {
|
||||
@@ -242,7 +241,9 @@ test("inferred unioned object type with optional properties", async () => {
|
||||
z.object({ a: z.string().optional(), b: z.string() }),
|
||||
]);
|
||||
type Unioned = z.infer<typeof Unioned>;
|
||||
expectTypeOf<Unioned>().toEqualTypeOf<{ a: string; b?: string } | { a?: string; b: string }>();
|
||||
expectTypeOf<Unioned>().toEqualTypeOf<
|
||||
{ a: string; b?: string | undefined } | { a?: string | undefined; b: string }
|
||||
>();
|
||||
});
|
||||
|
||||
test("inferred enum type", async () => {
|
||||
@@ -279,13 +280,13 @@ test("z.keyof returns enum", () => {
|
||||
test("inferred partial object type with optional properties", async () => {
|
||||
const Partial = z.object({ a: z.string(), b: z.string().optional() }).partial();
|
||||
type Partial = z.infer<typeof Partial>;
|
||||
expectTypeOf<Partial>().toEqualTypeOf<{ a?: string; b?: string }>();
|
||||
expectTypeOf<Partial>().toEqualTypeOf<{ a?: string | undefined; b?: string | undefined }>();
|
||||
});
|
||||
|
||||
test("inferred picked object type with optional properties", async () => {
|
||||
const Picked = z.object({ a: z.string(), b: z.string().optional() }).pick({ b: true });
|
||||
type Picked = z.infer<typeof Picked>;
|
||||
expectTypeOf<Picked>().toEqualTypeOf<{ b?: string }>();
|
||||
expectTypeOf<Picked>().toEqualTypeOf<{ b?: string | undefined }>();
|
||||
});
|
||||
|
||||
test("inferred type for unknown/any keys", () => {
|
||||
@@ -405,6 +406,36 @@ test("unknownkeys merging", () => {
|
||||
expect(c._zod.def.catchall).toBeInstanceOf(core.$ZodNever);
|
||||
});
|
||||
|
||||
test("merge() throws when receiver has refinements", () => {
|
||||
const a = z
|
||||
.object({
|
||||
password: z.string(),
|
||||
confirmPassword: z.string(),
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword);
|
||||
|
||||
const b = z.object({ email: z.string() });
|
||||
|
||||
expect(() => a.merge(b)).toThrow(".merge() cannot be used on object schemas containing refinements");
|
||||
});
|
||||
|
||||
test("merge() throws when receiver has superRefine", () => {
|
||||
const a = z.object({ x: z.string() }).superRefine(() => {});
|
||||
const b = z.object({ y: z.number() });
|
||||
|
||||
expect(() => a.merge(b)).toThrow(".merge() cannot be used on object schemas containing refinements");
|
||||
});
|
||||
|
||||
test("merge() preserves refinements on the second schema", () => {
|
||||
const a = z.object({ name: z.string() });
|
||||
const b = z.object({ age: z.number() }).refine((data) => data.age >= 18, { message: "Must be 18+" });
|
||||
|
||||
const merged = a.merge(b);
|
||||
|
||||
expect(merged.parse({ name: "n", age: 21 })).toEqual({ name: "n", age: 21 });
|
||||
expect(() => merged.parse({ name: "n", age: 12 })).toThrow("Must be 18+");
|
||||
});
|
||||
|
||||
const personToExtend = z.object({
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
@@ -638,3 +669,49 @@ test("safeExtend() on object with refinements should not throw", () => {
|
||||
|
||||
expect(() => schema.safeExtend({ b: z.string() })).not.toThrow();
|
||||
});
|
||||
|
||||
// __proto__ in input must not replace the prototype of the parsed object via
|
||||
// the assignment setter on the result {}.
|
||||
// https://github.com/colinhacks/zod/security/advisories/GHSA-r34p-xfmx-58wv
|
||||
// https://github.com/colinhacks/zod/security/advisories/GHSA-84jv-fqfx-wxhr
|
||||
describe("__proto__ in object catchall paths", () => {
|
||||
const protoInput = () => JSON.parse('{"__proto__":{"isAdmin":true},"name":"alice"}');
|
||||
|
||||
test("looseObject drops __proto__ and preserves Object.prototype", () => {
|
||||
const schema = z.looseObject({ name: z.string() });
|
||||
const parsed = schema.parse(protoInput());
|
||||
expect(Object.keys(parsed)).toEqual(["name"]);
|
||||
expect((parsed as any).isAdmin).toBeUndefined();
|
||||
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
||||
});
|
||||
|
||||
test("passthrough drops __proto__", () => {
|
||||
const schema = z.object({ name: z.string() }).passthrough();
|
||||
const parsed = schema.parse(protoInput());
|
||||
expect((parsed as any).isAdmin).toBeUndefined();
|
||||
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
||||
});
|
||||
|
||||
test("catchall(unknown) drops __proto__", () => {
|
||||
const schema = z.object({ name: z.string() }).catchall(z.unknown());
|
||||
const parsed = schema.parse(protoInput());
|
||||
expect((parsed as any).isAdmin).toBeUndefined();
|
||||
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
||||
});
|
||||
|
||||
test("safeParseAsync + jitless drops __proto__", async () => {
|
||||
const schema = z.looseObject({ name: z.string() });
|
||||
const result = await schema.safeParseAsync(protoInput(), { jitless: true } as any);
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect((result.data as any).isAdmin).toBeUndefined();
|
||||
expect(Object.getPrototypeOf(result.data)).toBe(Object.prototype);
|
||||
}
|
||||
});
|
||||
|
||||
test("strict does not surface __proto__ as unrecognized", () => {
|
||||
const schema = z.object({ name: z.string() }).strict();
|
||||
const result = schema.safeParse(protoInput());
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
+114
-4
@@ -40,15 +40,15 @@ test("optionality", () => {
|
||||
|
||||
// z.undefined should NOT be optional
|
||||
const f = z.undefined();
|
||||
expect(f._zod.optin).toEqual("optional");
|
||||
expect(f._zod.optout).toEqual("optional");
|
||||
expect(f._zod.optin).toEqual(undefined);
|
||||
expect(f._zod.optout).toEqual(undefined);
|
||||
expectTypeOf<typeof f._zod.optin>().toEqualTypeOf<"optional" | undefined>();
|
||||
expectTypeOf<typeof f._zod.optout>().toEqualTypeOf<"optional" | undefined>();
|
||||
|
||||
// z.union should be optional if any of the types are optional
|
||||
const g = z.union([z.string(), z.undefined()]);
|
||||
expect(g._zod.optin).toEqual("optional");
|
||||
expect(g._zod.optout).toEqual("optional");
|
||||
expect(g._zod.optin).toEqual(undefined);
|
||||
expect(g._zod.optout).toEqual(undefined);
|
||||
expectTypeOf<typeof g._zod.optin>().toEqualTypeOf<"optional" | undefined>();
|
||||
expectTypeOf<typeof g._zod.optout>().toEqualTypeOf<"optional" | undefined>();
|
||||
|
||||
@@ -135,6 +135,52 @@ test("optional prop with pipe", () => {
|
||||
schema.parse({}, { jitless: true });
|
||||
});
|
||||
|
||||
test("object absent keys require optin optional", () => {
|
||||
const valueUndefined = z.object({
|
||||
value: z.undefined(),
|
||||
union: z.union([z.string(), z.undefined()]),
|
||||
});
|
||||
|
||||
expect(valueUndefined.safeParse({}).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "nonoptional",
|
||||
"message": "Invalid input: expected nonoptional, received undefined",
|
||||
"path": [
|
||||
"value",
|
||||
],
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "nonoptional",
|
||||
"message": "Invalid input: expected nonoptional, received undefined",
|
||||
"path": [
|
||||
"union",
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(valueUndefined.safeParse({}, { jitless: true }).success).toEqual(false);
|
||||
expect(valueUndefined.parse({ value: undefined, union: undefined })).toEqual({
|
||||
value: undefined,
|
||||
union: undefined,
|
||||
});
|
||||
|
||||
const optionalOutOnly = z.object({
|
||||
value: z
|
||||
.string()
|
||||
.transform((val) => (Math.random() ? val : undefined))
|
||||
.pipe(z.string().optional()),
|
||||
});
|
||||
expect(optionalOutOnly.safeParse({}).success).toEqual(false);
|
||||
expect(optionalOutOnly.safeParse({}, { jitless: true }).success).toEqual(false);
|
||||
|
||||
const defaulted = z.object({ value: z.string().default("fallback") });
|
||||
expect(defaulted.parse({})).toEqual({ value: "fallback" });
|
||||
expect(defaulted.parse({}, { jitless: true })).toEqual({ value: "fallback" });
|
||||
});
|
||||
|
||||
// exactOptional tests
|
||||
test(".exactOptional()", () => {
|
||||
const schema = z.string().exactOptional();
|
||||
@@ -221,3 +267,67 @@ test("exactOptional vs optional comparison", () => {
|
||||
// exactOptional() rejects explicit undefined
|
||||
expect(exactOptionalSchema.safeParse({ a: undefined }).success).toEqual(false);
|
||||
});
|
||||
|
||||
// Defensive inference coverage: every schema that propagates `optout` participates
|
||||
// in object-key optionality inference. If anyone ever changes the set of values that
|
||||
// `optout` can take (or how OptionalOutSchema matches them), these assertions must
|
||||
// continue to hold or downstream `z.infer<typeof obj>` types silently flip required keys.
|
||||
test("object key optionality through optout propagation", () => {
|
||||
const direct = z.object({ k: z.string().optional() });
|
||||
expectTypeOf<z.infer<typeof direct>>().toEqualTypeOf<{ k?: string | undefined }>();
|
||||
|
||||
const exact = z.object({ k: z.string().exactOptional() });
|
||||
expectTypeOf<z.infer<typeof exact>>().toEqualTypeOf<{ k?: string }>();
|
||||
|
||||
// nullable() preserves the inner type's optout
|
||||
const nullableOpt = z.object({ k: z.string().optional().nullable() });
|
||||
expectTypeOf<z.infer<typeof nullableOpt>>().toEqualTypeOf<{ k?: string | null | undefined }>();
|
||||
|
||||
// optional() wrapping nullable() — still optional out
|
||||
const optNullable = z.object({ k: z.string().nullable().optional() });
|
||||
expectTypeOf<z.infer<typeof optNullable>>().toEqualTypeOf<{ k?: string | null | undefined }>();
|
||||
|
||||
// union containing an optional member must mark the key as optional
|
||||
const unionWithOpt = z.object({ k: z.union([z.string(), z.string().optional()]) });
|
||||
expectTypeOf<z.infer<typeof unionWithOpt>>().toEqualTypeOf<{ k?: string | undefined }>();
|
||||
|
||||
// pipe ending in optional()
|
||||
const pipedToOpt = z.object({
|
||||
k: z
|
||||
.string()
|
||||
.transform((v) => (Math.random() ? v : undefined))
|
||||
.pipe(z.string().optional()),
|
||||
});
|
||||
expectTypeOf<z.output<typeof pipedToOpt>>().toEqualTypeOf<{ k?: string | undefined }>();
|
||||
|
||||
// mixed shape pinning required vs optional keys end-to-end
|
||||
const mixed = z.object({
|
||||
req: z.string(),
|
||||
opt: z.string().optional(),
|
||||
exact: z.string().exactOptional(),
|
||||
def: z.string().default("x"),
|
||||
nullableOpt: z.string().optional().nullable(),
|
||||
});
|
||||
expectTypeOf<z.output<typeof mixed>>().toEqualTypeOf<{
|
||||
req: string;
|
||||
opt?: string | undefined;
|
||||
exact?: string;
|
||||
def: string;
|
||||
nullableOpt?: string | null | undefined;
|
||||
}>();
|
||||
});
|
||||
|
||||
// Defensive: tuple optional-tail inference also reads optout. The PR that introduced
|
||||
// `"includeUndefined"` had to update TupleOutputTypeWithOptionals; pin the result so
|
||||
// any future flag change has to keep this contract.
|
||||
test("tuple tail optionality through optout propagation", () => {
|
||||
const trailingOptional = z.tuple([z.string(), z.number().optional()]);
|
||||
expectTypeOf<z.output<typeof trailingOptional>>().toEqualTypeOf<[string, (number | undefined)?]>();
|
||||
|
||||
const trailingExact = z.tuple([z.string(), z.number().exactOptional()]);
|
||||
expectTypeOf<z.output<typeof trailingExact>>().toEqualTypeOf<[string, number?]>();
|
||||
|
||||
// Interior optional must NOT make the tail optional
|
||||
const interiorOptional = z.tuple([z.string(), z.number().optional(), z.string()]);
|
||||
expectTypeOf<z.output<typeof interiorOptional>>().toEqualTypeOf<[string, number | undefined, string]>();
|
||||
});
|
||||
|
||||
+24
-1
@@ -156,6 +156,10 @@ test("catch/prefault/default", () => {
|
||||
f: z.string().prefault("prefault value"),
|
||||
});
|
||||
|
||||
// Catch (d) and default/prefault (b, c, e, f) handle absent keys gracefully.
|
||||
// `a: catch().optional()` short-circuits to undefined when the original
|
||||
// input was undefined, so the property is omitted from the output. All
|
||||
// other catch/default/prefault keys produce their fallback values.
|
||||
expect(mySchema.parse({})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"b": "default value",
|
||||
@@ -165,7 +169,6 @@ test("catch/prefault/default", () => {
|
||||
"f": "prefault value",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(mySchema.parse({}, { jitless: true })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"b": "default value",
|
||||
@@ -175,6 +178,26 @@ test("catch/prefault/default", () => {
|
||||
"f": "prefault value",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(mySchema.parse({ d: undefined })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"b": "default value",
|
||||
"c": "prefault value",
|
||||
"d": "catch value",
|
||||
"e": "default value",
|
||||
"f": "prefault value",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(mySchema.parse({ d: undefined }, { jitless: true })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"b": "default value",
|
||||
"c": "prefault value",
|
||||
"d": "catch value",
|
||||
"e": "default value",
|
||||
"f": "prefault value",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("handleOptionalObjectResult branches", () => {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ test("object schema with prefault should return shallow clone", () => {
|
||||
.object({
|
||||
a: z.string(),
|
||||
})
|
||||
.default({ a: "x" });
|
||||
.prefault({ a: "x" });
|
||||
const result1 = schema.parse(undefined);
|
||||
const result2 = schema.parse(undefined);
|
||||
expect(result1).not.toBe(result2);
|
||||
|
||||
+69
@@ -280,3 +280,72 @@ test("perform transform with non-fatal issues", () => {
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("preprocess accepts absent object keys (4.3 parity)", () => {
|
||||
const schema = z.object({ a: z.preprocess((v) => v ?? "X", z.string()) });
|
||||
expect(schema.parse({})).toEqual({ a: "X" });
|
||||
expect(schema.parse({ a: "hi" })).toEqual({ a: "hi" });
|
||||
expect(schema.parse({ a: undefined })).toEqual({ a: "X" });
|
||||
|
||||
// Outer optional clobbers preprocess output on undefined input
|
||||
expect(
|
||||
z
|
||||
.preprocess((v) => v ?? "X", z.string())
|
||||
.optional()
|
||||
.parse(undefined)
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
z
|
||||
.preprocess((v) => v ?? "X", z.string())
|
||||
.optional()
|
||||
.parse("hi")
|
||||
).toBe("hi");
|
||||
expect(z.object({ a: z.preprocess((v) => v ?? "X", z.string()).optional() }).parse({})).toEqual({});
|
||||
|
||||
// Top-level direct call unchanged
|
||||
expect(z.preprocess((v) => v ?? "X", z.string()).parse(undefined)).toBe("X");
|
||||
});
|
||||
|
||||
// https://github.com/colinhacks/zod/issues/5917
|
||||
test("optional propagates through preprocess inside object", () => {
|
||||
const outer = z.object({ x: z.preprocess((v) => v, z.number()).optional() });
|
||||
const inner = z.object({ x: z.preprocess((v) => v, z.number().optional()) });
|
||||
|
||||
expect(outer.safeParse({}).success).toBe(true);
|
||||
expect(inner.safeParse({}).success).toBe(true);
|
||||
|
||||
expect(outer.safeParse({ x: 1 })).toEqual({ success: true, data: { x: 1 } });
|
||||
expect(inner.safeParse({ x: 1 })).toEqual({ success: true, data: { x: 1 } });
|
||||
|
||||
expect(inner._zod.def.shape.x._zod.optin).toBe("optional");
|
||||
expect(inner._zod.def.shape.x._zod.optout).toBe("optional");
|
||||
});
|
||||
|
||||
test("preprocess is a structural subtype of ZodPipe", () => {
|
||||
const schema = z.preprocess((v) => v, z.string());
|
||||
expect(schema).toBeInstanceOf(z.ZodPipe);
|
||||
expect(schema).toBeInstanceOf(z.ZodPreprocess);
|
||||
expect(schema._zod.def.type).toBe("pipe");
|
||||
});
|
||||
|
||||
test("preprocess does not propagate values/propValues from inner schema", () => {
|
||||
const inner = z.preprocess((v) => v, z.literal("test"));
|
||||
expect(inner._zod.values).toBeUndefined();
|
||||
expect(inner._zod.propValues).toBeUndefined();
|
||||
});
|
||||
|
||||
test("preprocess as discriminator throws at construction (no propValues to inherit)", () => {
|
||||
const schema = z.discriminatedUnion("kind", [
|
||||
z.object({ kind: z.preprocess((v: any) => String(v).toUpperCase(), z.literal("A")), a: z.string() }),
|
||||
z.object({ kind: z.preprocess((v: any) => String(v).toUpperCase(), z.literal("B")), b: z.number() }),
|
||||
]);
|
||||
expect(() => schema.parse({ kind: "a", a: "x" })).toThrow(/Invalid discriminated union option/);
|
||||
});
|
||||
|
||||
test("preprocess as record key does not restrict accepted keys", () => {
|
||||
const schema = z.record(
|
||||
z.preprocess((v: any) => String(v).toLowerCase(), z.enum(["a", "b"])),
|
||||
z.string()
|
||||
);
|
||||
expect(schema.safeParse({ A: "x", B: "y" })).toEqual({ success: true, data: { a: "x", b: "y" } });
|
||||
});
|
||||
|
||||
+85
@@ -272,6 +272,67 @@ test("union exhaustiveness", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("applies transforms on the key schema (#5296)", () => {
|
||||
const single = z.record(
|
||||
z.literal("a").transform(() => "b" as const),
|
||||
z.string()
|
||||
);
|
||||
expect(single.parse({ a: "John" })).toEqual({ b: "John" });
|
||||
|
||||
const multi = z.record(
|
||||
z.literal(["a", "b"]).transform((k) => k.toUpperCase()),
|
||||
z.number()
|
||||
);
|
||||
expect(multi.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
||||
|
||||
// required-key semantics still hold when the keyType has a known value set
|
||||
expect(multi.safeParse({ a: 1 }).success).toBe(false);
|
||||
|
||||
const en = z.record(
|
||||
z.enum(["a", "b"]).transform((k) => k.toUpperCase()),
|
||||
z.number()
|
||||
);
|
||||
expect(en.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
||||
|
||||
// matches partialRecord, which already applied transforms
|
||||
const part = z.partialRecord(
|
||||
z.literal("a").transform(() => "b" as const),
|
||||
z.string()
|
||||
);
|
||||
expect(part.parse({ a: "John" })).toEqual({ b: "John" });
|
||||
});
|
||||
|
||||
test("surfaces key schema refinement failures as invalid_key", () => {
|
||||
// refine rejects "b" but it's still in the literal's value set
|
||||
const schema = z.record(
|
||||
z.literal(["a", "b"]).refine((k) => k === "a", { message: "only 'a' is allowed" }),
|
||||
z.string()
|
||||
);
|
||||
|
||||
expect(schema.safeParse({ a: "ok", b: "nope" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"code": "invalid_key",
|
||||
"origin": "record",
|
||||
"issues": [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "only 'a' is allowed"
|
||||
}
|
||||
],
|
||||
"path": [
|
||||
"b"
|
||||
],
|
||||
"message": "Invalid key in record"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("string record parse - pass", () => {
|
||||
const schema = z.record(z.string(), z.boolean());
|
||||
schema.parse({
|
||||
@@ -630,3 +691,27 @@ test("numeric string keys", () => {
|
||||
);
|
||||
expect(transformedSchema.parse({ 5: "five", 10: "ten" })).toEqual({ 10: "five", 20: "ten" });
|
||||
});
|
||||
|
||||
test("v3-compat single-arg form: z.record(valueType)", () => {
|
||||
// single arg should default keyType to z.string() and use the arg as valueType
|
||||
const schema = (z.record as any)(z.number());
|
||||
expect(schema.keyType._zod.def.type).toEqual("string");
|
||||
expect(schema.valueType._zod.def.type).toEqual("number");
|
||||
|
||||
expect(schema.parse({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
||||
expect(schema.safeParse({ a: "x" }).success).toBe(false);
|
||||
|
||||
// params still flow through in the single-arg form
|
||||
const withMessage = (z.record as any)(z.number(), "must be a number record");
|
||||
expect(withMessage.keyType._zod.def.type).toEqual("string");
|
||||
expect(withMessage.valueType._zod.def.type).toEqual("number");
|
||||
|
||||
// toJSONSchema should produce a well-formed schema (regression: previously produced
|
||||
// additionalProperties from undefined valueType, crashing process())
|
||||
const json = z.toJSONSchema(schema);
|
||||
expect(json).toMatchObject({
|
||||
type: "object",
|
||||
propertyNames: { type: "string" },
|
||||
additionalProperties: { type: "number" },
|
||||
});
|
||||
});
|
||||
|
||||
+49
@@ -135,6 +135,11 @@ test("pick and omit with getter", () => {
|
||||
}
|
||||
expectTypeOf<Category>().toEqualTypeOf<_Category>();
|
||||
|
||||
// Shape should not surface `readonly` modifiers from getter-defined keys.
|
||||
// object/strictObject/looseObject all pass shape through util.Writeable<T>.
|
||||
type Shape = (typeof Category)["shape"];
|
||||
expectTypeOf<Shape>().toEqualTypeOf<{ name: z.ZodString; subcategories: z.ZodArray<typeof Category> }>();
|
||||
|
||||
const PickedCategory = Category.pick({ name: true });
|
||||
const OmittedCategory = Category.omit({ subcategories: true });
|
||||
|
||||
@@ -148,6 +153,50 @@ test("pick and omit with getter", () => {
|
||||
expect(() => OmittedCategory.parse({ name: "test", subcategories: [] })).toThrow();
|
||||
});
|
||||
|
||||
test("shape stays writeable through extend/safeExtend/partial/required", () => {
|
||||
const Base = z.object({ name: z.string() });
|
||||
|
||||
const Extended = Base.extend({
|
||||
get sub() {
|
||||
return z.array(Extended);
|
||||
},
|
||||
});
|
||||
type ExtendedShape = (typeof Extended)["shape"];
|
||||
expectTypeOf<ExtendedShape>().toEqualTypeOf<{
|
||||
name: z.ZodString;
|
||||
sub: z.ZodArray<typeof Extended>;
|
||||
}>();
|
||||
|
||||
const SafeExt = Base.safeExtend({ extra: z.string() } as const);
|
||||
type SafeExtShape = (typeof SafeExt)["shape"];
|
||||
expectTypeOf<SafeExtShape>().toEqualTypeOf<{
|
||||
name: z.ZodString;
|
||||
extra: z.ZodString;
|
||||
}>();
|
||||
|
||||
const FromConst = Base.extend({ a: z.string(), b: z.number() } as const);
|
||||
type FromConstShape = (typeof FromConst)["shape"];
|
||||
expectTypeOf<FromConstShape>().toEqualTypeOf<{
|
||||
name: z.ZodString;
|
||||
a: z.ZodString;
|
||||
b: z.ZodNumber;
|
||||
}>();
|
||||
|
||||
const PartialExtended = Extended.partial();
|
||||
type PartialShape = (typeof PartialExtended)["shape"];
|
||||
expectTypeOf<PartialShape>().toEqualTypeOf<{
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
sub: z.ZodOptional<z.ZodArray<typeof Extended>>;
|
||||
}>();
|
||||
|
||||
const RequiredExtended = Extended.required();
|
||||
type RequiredShape = (typeof RequiredExtended)["shape"];
|
||||
expectTypeOf<RequiredShape>().toEqualTypeOf<{
|
||||
name: z.ZodNonOptional<z.ZodString>;
|
||||
sub: z.ZodNonOptional<z.ZodArray<typeof Extended>>;
|
||||
}>();
|
||||
});
|
||||
|
||||
test("deferred self-recursion", () => {
|
||||
const Feature = z.object({
|
||||
title: z.string(),
|
||||
|
||||
+63
@@ -414,6 +414,69 @@ describe("chained refinements", () => {
|
||||
};
|
||||
expect(objectSchema.parse(validData)).toEqual(validData);
|
||||
});
|
||||
|
||||
test("should run superRefine validation even when base schema validation fails when 'when' is defined and returns true", () => {
|
||||
const baseSchema = z.object({
|
||||
foo: z.number(),
|
||||
bar: z.number(),
|
||||
});
|
||||
|
||||
const schema = baseSchema.superRefine(
|
||||
(data, ctx) => {
|
||||
if (data.foo > 10) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "foo must be less than 10",
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
when: ({ value }) => baseSchema.pick({ foo: true }).safeParse(value).success,
|
||||
}
|
||||
);
|
||||
|
||||
const result = schema.safeParse({
|
||||
foo: 11,
|
||||
});
|
||||
expect(result.success).toEqual(false);
|
||||
|
||||
if (!result.success) {
|
||||
expect(result.error.issues.length).toEqual(2);
|
||||
expect(result.error.issues[0].message).toEqual("Invalid input: expected number, received undefined");
|
||||
expect(result.error.issues[1].message).toEqual("foo must be less than 10");
|
||||
}
|
||||
});
|
||||
|
||||
test("should not run superRefine validation when 'when' is defined and returns false", () => {
|
||||
const baseSchema = z.object({
|
||||
foo: z.number(),
|
||||
bar: z.number(),
|
||||
});
|
||||
|
||||
const schema = baseSchema.superRefine(
|
||||
(data, ctx) => {
|
||||
if (data.foo > 10) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "foo must be less than 10",
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
when: ({ value }) => baseSchema.safeParse(value).success,
|
||||
}
|
||||
);
|
||||
|
||||
const result = schema.safeParse({
|
||||
foo: 11,
|
||||
});
|
||||
expect(result.success).toEqual(false);
|
||||
|
||||
if (!result.success) {
|
||||
expect(result.error.issues.length).toEqual(1);
|
||||
expect(result.error.issues[0].message).toEqual("Invalid input: expected number, received undefined");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("type refinement with type guards", () => {
|
||||
|
||||
+50
-1
@@ -217,6 +217,16 @@ test("base64 validations", () => {
|
||||
"?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?'
|
||||
".MTIzND2Nzg5MC4=", // Invalid character '.'
|
||||
"QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // Missing padding
|
||||
// Whitespace is not part of canonical base64 (RFC 4648 §3.3) — atob() strips
|
||||
// whitespace internally before validating, so the length check alone would
|
||||
// accept "123 " etc.
|
||||
"123 ", // bypasses length-mod-4 via trailing whitespace
|
||||
"SGVsbG8gV29ybGQ= ", // trailing space
|
||||
" SGVsbG8gV29ybGQ=", // leading space
|
||||
"SGVsbG8gV29ybGQ=\n", // trailing newline
|
||||
"SGVs bG8gV29ybGQ=", // internal space
|
||||
"SGVs\nbG8gV29ybGQ=", // internal newline
|
||||
"SGVs\tbG8gV29ybGQ=", // internal tab
|
||||
];
|
||||
|
||||
for (const str of invalidBase64Strings) {
|
||||
@@ -454,6 +464,12 @@ test("httpurl", () => {
|
||||
).toThrow();
|
||||
expect(() => httpUrl.parse("http://asdf.c")).toThrow();
|
||||
expect(() => httpUrl.parse("mailto:asdf@lckj.com")).toThrow();
|
||||
// missing // after protocol
|
||||
expect(() => httpUrl.parse("http:example.com")).toThrow();
|
||||
expect(() => httpUrl.parse("https:example.com")).toThrow();
|
||||
// missing one /
|
||||
expect(() => httpUrl.parse("https:/www.google.com")).toThrow();
|
||||
expect(() => httpUrl.parse("http:/example.com")).toThrow();
|
||||
});
|
||||
|
||||
test("url error overrides", () => {
|
||||
@@ -611,12 +627,26 @@ test("cuid", () => {
|
||||
"origin": "string",
|
||||
"code": "invalid_format",
|
||||
"format": "cuid",
|
||||
"pattern": "/^[cC][^\\\\s-]{8,}$/",
|
||||
"pattern": "/^[cC][0-9a-z]{6,}$/",
|
||||
"path": [],
|
||||
"message": "Invalid cuid"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
|
||||
// Strings containing non-base36 characters that the old denylist regex
|
||||
// (/^[cC][^\s-]{8,}$/) accepted. The new regex restricts the body to
|
||||
// [0-9a-z], matching the actual CUID v1 base36 format. See #3621.
|
||||
const previouslyAcceptedNonCuids = [
|
||||
"cly63t164000245zw008pggon';select1;", // SQLi-shaped (no whitespace, no hyphen)
|
||||
"c<script>alert(1)</script>aaaaaa", // XSS-shaped
|
||||
"c{};alert(1)//", // bracket / curly chars
|
||||
"C0123_45678", // underscore is not base36
|
||||
"cAAAAAAAAA", // uppercase letters in body are not base36 (CUIDs are lowercase)
|
||||
];
|
||||
for (const s of previouslyAcceptedNonCuids) {
|
||||
expect(cuid.safeParse(s).success).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
test("cuid2", () => {
|
||||
@@ -811,6 +841,25 @@ test("min max getters", () => {
|
||||
expect(z.string().maxLength).toEqual(null);
|
||||
});
|
||||
|
||||
test("boundary cases with zero length", () => {
|
||||
// Test length(0) - only empty string should pass
|
||||
const lengthZero = z.string().length(0);
|
||||
expect(lengthZero.parse("")).toEqual("");
|
||||
expect(() => lengthZero.parse("a")).toThrow();
|
||||
|
||||
// Test min(0) - all strings including empty should pass
|
||||
const minZero = z.string().min(0);
|
||||
expect(minZero.parse("")).toEqual("");
|
||||
expect(minZero.parse("a")).toEqual("a");
|
||||
expect(minZero.parse("hello")).toEqual("hello");
|
||||
|
||||
// Test max(0) - only empty string should pass
|
||||
const maxZero = z.string().max(0);
|
||||
expect(maxZero.parse("")).toEqual("");
|
||||
expect(() => maxZero.parse("a")).toThrow();
|
||||
expect(() => maxZero.parse("hello")).toThrow();
|
||||
});
|
||||
|
||||
test("trim", () => {
|
||||
expect(z.string().trim().min(2).parse(" 12 ")).toEqual("12");
|
||||
|
||||
|
||||
+4
-4
@@ -482,7 +482,7 @@ test("template literal parsing - failure - basic cases", () => {
|
||||
expect(() => nullishBruh.parse("1null")).toThrow();
|
||||
expect(() => nullishBruh.parse("undefined")).toThrow();
|
||||
expect(() => cuid.parse("bjld2cyuq0000t3rmniod1foy")).toThrow();
|
||||
expect(() => cuid.parse("cjld2cyu")).toThrow();
|
||||
expect(() => cuid.parse("cjld2")).toThrow();
|
||||
expect(() => cuid.parse("cjld2 cyu")).toThrow();
|
||||
expect(() => cuid.parse("cjld2cyuq0000t3rmniod1foy ")).toThrow();
|
||||
expect(() => cuid.parse("1cjld2cyuq0000t3rmniod1foy")).toThrow();
|
||||
@@ -555,8 +555,8 @@ test("regexes", () => {
|
||||
expect(optionalNumber._zod.pattern.source).toMatchInlineSnapshot(`"^(-?\\d+(?:\\.\\d+)?)?$"`);
|
||||
expect(nullishBruh._zod.pattern.source).toMatchInlineSnapshot(`"^(((bruh)|null))?$"`);
|
||||
expect(nullishString._zod.pattern.source).toMatchInlineSnapshot(`"^(([\\s\\S]{0,}|null))?$"`);
|
||||
expect(cuid._zod.pattern.source).toMatchInlineSnapshot(`"^[cC][^\\s-]{8,}$"`);
|
||||
expect(cuidZZZ._zod.pattern.source).toMatchInlineSnapshot(`"^[cC][^\\s-]{8,}ZZZ$"`);
|
||||
expect(cuid._zod.pattern.source).toMatchInlineSnapshot(`"^[cC][0-9a-z]{6,}$"`);
|
||||
expect(cuidZZZ._zod.pattern.source).toMatchInlineSnapshot(`"^[cC][0-9a-z]{6,}ZZZ$"`);
|
||||
expect(cuid2._zod.pattern.source).toMatchInlineSnapshot(`"^[0-9a-z]+$"`);
|
||||
expect(datetime._zod.pattern.source).toMatchInlineSnapshot(
|
||||
`"^(?:(?:\\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))$"`
|
||||
@@ -717,7 +717,7 @@ test("template literal parsing - failure - issue format", () => {
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "template_literal",
|
||||
"pattern": "^[cC][^\\\\s-]{8,}ZZZ$",
|
||||
"pattern": "^[cC][0-9a-z]{6,}ZZZ$",
|
||||
"path": [],
|
||||
"message": "Invalid input"
|
||||
}
|
||||
|
||||
+150
-15
@@ -212,7 +212,7 @@ describe("toJSONSchema", () => {
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"format": "cuid",
|
||||
"pattern": "^[cC][^\\s-]{8,}$",
|
||||
"pattern": "^[cC][0-9a-z]{6,}$",
|
||||
"type": "string",
|
||||
}
|
||||
`);
|
||||
@@ -647,6 +647,47 @@ describe("toJSONSchema", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("number constraints intersection draft-04", () => {
|
||||
// When both minimum (from .int()) and exclusiveMinimum (from .positive()) exist,
|
||||
// the more restrictive constraint should be used
|
||||
expect(z.toJSONSchema(z.number().int().positive().lte(65535), { target: "draft-04" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"exclusiveMinimum": true,
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
}
|
||||
`);
|
||||
// Same for openapi-3.0
|
||||
expect(z.toJSONSchema(z.number().int().positive().lte(65535), { target: "openapi-3.0" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exclusiveMinimum": true,
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
}
|
||||
`);
|
||||
// When inclusive minimum is more restrictive than exclusive minimum
|
||||
expect(z.toJSONSchema(z.number().gt(3).gte(10), { target: "draft-04" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"minimum": 10,
|
||||
"type": "number",
|
||||
}
|
||||
`);
|
||||
// Same logic for maximum constraints
|
||||
expect(z.toJSONSchema(z.number().int().negative(), { target: "draft-04" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"exclusiveMaximum": true,
|
||||
"maximum": 0,
|
||||
"minimum": -9007199254740991,
|
||||
"type": "integer",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("target normalization draft-04 and draft-07", () => {
|
||||
// Test that both old (draft-4, draft-7) and new (draft-04, draft-07) target formats work
|
||||
// Test draft-04 / draft-4
|
||||
@@ -1219,11 +1260,9 @@ describe("toJSONSchema", () => {
|
||||
},
|
||||
"definitions": {
|
||||
"primary": {
|
||||
"id": "primary",
|
||||
"type": "string",
|
||||
},
|
||||
"rest": {
|
||||
"id": "rest",
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
@@ -2014,11 +2053,9 @@ test("extract schemas with id", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"age": {
|
||||
"id": "age",
|
||||
"type": "number",
|
||||
},
|
||||
"name": {
|
||||
"id": "name",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
@@ -2106,7 +2143,6 @@ test("describe with id", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"jobId": {
|
||||
"id": "jobId",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
@@ -2131,6 +2167,45 @@ test("describe with id", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("id is stripped from $defs entries (draft-2020-12)", () => {
|
||||
// The `id` in `.meta()` is a registration tag — it determines the $defs key
|
||||
// but should not leak into the definition body, where it is redundant.
|
||||
const inner = z.string().meta({ id: "Inner" });
|
||||
const result = z.toJSONSchema(z.object({ a: inner, b: inner }));
|
||||
expect(result.$defs?.Inner).toEqual({ type: "string" });
|
||||
expect((result.$defs?.Inner as any).id).toBeUndefined();
|
||||
});
|
||||
|
||||
test("id is stripped from definitions entries (draft-04)", () => {
|
||||
// In draft-04, `id` is a reserved keyword that sets a base URI for the
|
||||
// subschema. Leaking Zod's registration tag here is semantically wrong, so
|
||||
// ensure it is stripped.
|
||||
const inner = z.string().meta({ id: "Inner" });
|
||||
const result = z.toJSONSchema(z.object({ a: inner, b: inner }), { target: "draft-04" }) as any;
|
||||
expect(result.definitions?.Inner).toEqual({ type: "string" });
|
||||
expect(result.definitions?.Inner?.id).toBeUndefined();
|
||||
});
|
||||
|
||||
test("id is stripped from root schema", () => {
|
||||
// The registration tag should not appear on the root either.
|
||||
const A = z.object({ name: z.string() }).meta({ id: "A" });
|
||||
const result = z.toJSONSchema(A);
|
||||
expect((result as any).id).toBeUndefined();
|
||||
});
|
||||
|
||||
test("id is observable in override callback", () => {
|
||||
// The strip happens after override callbacks run, so userland override code
|
||||
// can still read `jsonSchema.id` if it wants to.
|
||||
const inner = z.string().meta({ id: "Inner" });
|
||||
const seenIds: Array<string | undefined> = [];
|
||||
z.toJSONSchema(z.object({ a: inner }), {
|
||||
override: ({ jsonSchema }) => {
|
||||
if (jsonSchema.id !== undefined) seenIds.push(jsonSchema.id as string);
|
||||
},
|
||||
});
|
||||
expect(seenIds).toContain("Inner");
|
||||
});
|
||||
|
||||
test("describe with id on wrapper", () => {
|
||||
// Test that $ref propagation works when processor sets a different ref (readonly -> innerType)
|
||||
// but parent was extracted due to having an id
|
||||
@@ -2146,7 +2221,6 @@ test("describe with id on wrapper", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"roJobId": {
|
||||
"id": "roJobId",
|
||||
"readOnly": true,
|
||||
"type": "string",
|
||||
},
|
||||
@@ -2185,12 +2259,10 @@ test("overwrite id", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"aaa": {
|
||||
"id": "aaa",
|
||||
"type": "string",
|
||||
},
|
||||
"bbb": {
|
||||
"$ref": "#/$defs/aaa",
|
||||
"id": "bbb",
|
||||
},
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
@@ -2224,12 +2296,10 @@ test("overwrite id", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"aaa": {
|
||||
"id": "aaa",
|
||||
"type": "string",
|
||||
},
|
||||
"ccc": {
|
||||
"$ref": "#/$defs/aaa",
|
||||
"id": "ccc",
|
||||
},
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
@@ -2351,7 +2421,6 @@ test("top-level readonly", () => {
|
||||
"$defs": {
|
||||
"B": {
|
||||
"additionalProperties": false,
|
||||
"id": "B",
|
||||
"properties": {
|
||||
"a": {
|
||||
"$ref": "#",
|
||||
@@ -2370,7 +2439,6 @@ test("top-level readonly", () => {
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"additionalProperties": false,
|
||||
"id": "A",
|
||||
"properties": {
|
||||
"b": {
|
||||
"$ref": "#/$defs/B",
|
||||
@@ -2497,7 +2565,6 @@ test("_ref", () => {
|
||||
{
|
||||
"$defs": {
|
||||
"foo": {
|
||||
"id": "foo",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
@@ -2560,6 +2627,38 @@ test("defaults/prefaults", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("falsy prefaults (false, 0, empty string)", () => {
|
||||
// boolean prefault false
|
||||
const a = z.boolean().prefault(false);
|
||||
expect(z.toJSONSchema(a, { io: "input" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": false,
|
||||
"type": "boolean",
|
||||
}
|
||||
`);
|
||||
|
||||
// number prefault 0
|
||||
const b = z.number().prefault(0);
|
||||
expect(z.toJSONSchema(b, { io: "input" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": 0,
|
||||
"type": "number",
|
||||
}
|
||||
`);
|
||||
|
||||
// string prefault empty string
|
||||
const c = z.string().prefault("");
|
||||
expect(z.toJSONSchema(c, { io: "input" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "",
|
||||
"type": "string",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("input type", () => {
|
||||
const schema = z.object({
|
||||
a: z.string(),
|
||||
@@ -2632,7 +2731,6 @@ test("input type", () => {
|
||||
"required": [
|
||||
"a",
|
||||
"d",
|
||||
"f",
|
||||
"g",
|
||||
],
|
||||
"type": "object",
|
||||
@@ -2797,6 +2895,28 @@ test("use output type for preprocess", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("strip output-side examples from input JSON schema for codec", () => {
|
||||
const codec = z
|
||||
.codec(z.string(), z.number(), { decode: (s) => Number(s), encode: (n) => String(n) })
|
||||
.meta({ examples: [42] });
|
||||
|
||||
expect(z.toJSONSchema(codec, { io: "input" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
}
|
||||
`);
|
||||
expect(z.toJSONSchema(codec, { io: "output" })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"examples": [
|
||||
42,
|
||||
],
|
||||
"type": "number",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
// test("isTransforming", () => {
|
||||
// const tx = z.core.isTransforming;
|
||||
// expect(tx(z.string())).toEqual(false);
|
||||
@@ -2988,3 +3108,18 @@ test("cycle detection - mutual recursion", () => {
|
||||
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
|
||||
`);
|
||||
});
|
||||
|
||||
test("recursive lazy with describe does not stack overflow", () => {
|
||||
const NodeSchema: z.ZodType = z.lazy(() =>
|
||||
z
|
||||
.object({
|
||||
value: z.string().describe("node value"),
|
||||
children: z.array(NodeSchema.describe("child node")).optional().describe("child list"),
|
||||
})
|
||||
.describe("tree node")
|
||||
);
|
||||
|
||||
const result = z.toJSONSchema(NodeSchema, { cycles: "ref", reused: "ref" });
|
||||
expect(result).toBeDefined();
|
||||
expect(result.$defs).toBeDefined();
|
||||
});
|
||||
|
||||
+17
@@ -359,3 +359,20 @@ test("encode error", () => {
|
||||
`[ZodEncodeError: Encountered unidirectional transform during encode: ZodTransform]`
|
||||
);
|
||||
});
|
||||
|
||||
test("transform context should have addIssue", () => {
|
||||
const schema = z.transform((val, ctx) => {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Not valid",
|
||||
});
|
||||
return val;
|
||||
});
|
||||
|
||||
const result = schema.safeParse("test");
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues[0].message).toBe("Not valid");
|
||||
}
|
||||
});
|
||||
|
||||
+315
-2
@@ -107,7 +107,9 @@ test("async validation", async () => {
|
||||
|
||||
test("tuple with optional elements", () => {
|
||||
const myTuple = z.tuple([z.string(), z.number().optional(), z.string().optional()]).rest(z.boolean());
|
||||
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<[string, number?, string?, ...boolean[]]>();
|
||||
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<
|
||||
[string, (number | undefined)?, (string | undefined)?, ...boolean[]]
|
||||
>();
|
||||
|
||||
const goodData = [["asdf"], ["asdf", 1234], ["asdf", 1234, "asdf"], ["asdf", 1234, "asdf", true, false, true]];
|
||||
for (const data of goodData) {
|
||||
@@ -149,7 +151,9 @@ test("tuple with optional elements followed by required", () => {
|
||||
|
||||
test("tuple with all optional elements", () => {
|
||||
const allOptionalTuple = z.tuple([z.string().optional(), z.number().optional(), z.boolean().optional()]);
|
||||
expectTypeOf<typeof allOptionalTuple._output>().toEqualTypeOf<[string?, number?, boolean?]>();
|
||||
expectTypeOf<typeof allOptionalTuple._output>().toEqualTypeOf<
|
||||
[(string | undefined)?, (number | undefined)?, (boolean | undefined)?]
|
||||
>();
|
||||
|
||||
// Empty array should be valid (all items optional)
|
||||
expect(allOptionalTuple.parse([])).toEqual([]);
|
||||
@@ -165,6 +169,227 @@ test("tuple with all optional elements", () => {
|
||||
expect(() => allOptionalTuple.parse(["hello", 42, true, "extra"])).toThrow();
|
||||
});
|
||||
|
||||
test("tuple fills defaults for missing trailing elements", () => {
|
||||
// Issue #5229: trailing `.default()`/`.prefault()` elements should be
|
||||
// filled in when the input array is shorter than the tuple.
|
||||
const t = z.tuple([z.string(), z.string().default("bravo")]);
|
||||
expectTypeOf<typeof t._output>().toEqualTypeOf<[string, string]>();
|
||||
expectTypeOf<typeof t._input>().toEqualTypeOf<[string, (string | undefined)?]>();
|
||||
|
||||
expect(t.parse(["alpha", "charlie"])).toEqual(["alpha", "charlie"]);
|
||||
expect(t.parse(["alpha"])).toEqual(["alpha", "bravo"]);
|
||||
|
||||
// Multiple trailing defaults
|
||||
const multi = z.tuple([z.string(), z.number().default(42), z.boolean().default(true)]);
|
||||
expect(multi.parse(["hello"])).toEqual(["hello", 42, true]);
|
||||
expect(multi.parse(["hello", 100])).toEqual(["hello", 100, true]);
|
||||
expect(multi.parse(["hello", 100, false])).toEqual(["hello", 100, false]);
|
||||
|
||||
// Prefault parity
|
||||
expect(z.tuple([z.string(), z.string().prefault("delta")]).parse(["alpha"])).toEqual(["alpha", "delta"]);
|
||||
|
||||
// Defaults wrapped in modifiers: `optout` propagates through these, so the
|
||||
// fix is not type-name specific.
|
||||
expect(z.tuple([z.string(), z.string().default("x").nullable()]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").readonly()]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").catch("y")]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").pipe(z.string())]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
});
|
||||
|
||||
test("tuple fills defaults under async parse", async () => {
|
||||
const t = z.tuple([z.string(), z.string().default("zulu")]);
|
||||
await expect(t.parseAsync(["alpha"])).resolves.toEqual(["alpha", "zulu"]);
|
||||
});
|
||||
|
||||
test("tuple keeps length-1 array for missing `.optional()` elements", () => {
|
||||
// Backwards compat: a trailing `.optional()` element that is omitted from
|
||||
// the input must NOT be filled with `undefined` — the result stays length-1.
|
||||
// Only schemas that produce a defined value get materialized.
|
||||
const t = z.tuple([z.string(), z.string().optional()]);
|
||||
const out = t.parse(["alpha"]);
|
||||
expect(out).toEqual(["alpha"]);
|
||||
expect(out.length).toEqual(1);
|
||||
|
||||
// `z.undefined()` is NOT a synonym for `.optional()` — its value type is
|
||||
// *must be undefined*, so the slot is required input. Omitting it triggers
|
||||
// a single `too_small` (no element-level errors, matching v3's abort
|
||||
// semantics); passing explicit `undefined` succeeds and is preserved.
|
||||
expect(z.tuple([z.string(), z.undefined()]).safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(z.tuple([z.string(), z.undefined()]).parse(["alpha", undefined])).toHaveLength(2);
|
||||
|
||||
// `.optional().nullable()` still trims — `.optional()` propagates the
|
||||
// optin/optout flags through the nullable wrapper.
|
||||
expect(z.tuple([z.string(), z.string().optional().nullable()]).parse(["alpha"])).toHaveLength(1);
|
||||
|
||||
// Multiple trailing optionals trim the same way — we don't fill the tail
|
||||
// with literal `undefined`s.
|
||||
const many = z.tuple([z.string(), z.string().optional(), z.string().optional(), z.string().optional()]);
|
||||
expect(many.parse(["alpha"])).toEqual(["alpha"]);
|
||||
expect(many.parse(["alpha", "beta"])).toEqual(["alpha", "beta"]);
|
||||
|
||||
// Explicit `undefined` inside `input.length` IS preserved — only slots
|
||||
// past the input get trimmed.
|
||||
const r = many.parse(["alpha", undefined]);
|
||||
expect(r.length).toEqual(2);
|
||||
expect(1 in r).toEqual(true);
|
||||
|
||||
// Trailing optionals after a default that fires are still trimmed.
|
||||
expect(
|
||||
z.tuple([z.string(), z.string().default("d"), z.string().optional(), z.string().optional()]).parse(["alpha"])
|
||||
).toEqual(["alpha", "d"]);
|
||||
});
|
||||
|
||||
test("tuple result is dense when optional precedes a default", () => {
|
||||
// `.optional()` before a `.default()` must produce an explicit `undefined`
|
||||
// (not a sparse hole), otherwise `1 in r`, `JSON.stringify`, `Object.keys`,
|
||||
// and iteration all behave wrong.
|
||||
const t = z.tuple([z.string(), z.string().optional(), z.string().default("z")]);
|
||||
const r = t.parse(["alpha"]);
|
||||
expect(r).toEqual(["alpha", undefined, "z"]);
|
||||
expect(r.length).toEqual(3);
|
||||
expect(1 in r).toEqual(true);
|
||||
expect(JSON.stringify(r)).toEqual('["alpha",null,"z"]');
|
||||
|
||||
// Trailing optional after a default is still dropped (no later default
|
||||
// forces it to materialize).
|
||||
expect(z.tuple([z.string(), z.string().default("d"), z.string().optional()]).parse(["alpha"])).toEqual([
|
||||
"alpha",
|
||||
"d",
|
||||
]);
|
||||
|
||||
// Multiple interleaved optional/default — every slot up to the last
|
||||
// default must be present and dense.
|
||||
const interleaved = z.tuple([
|
||||
z.string(),
|
||||
z.string().optional(),
|
||||
z.string().default("d"),
|
||||
z.string().optional(),
|
||||
z.string().default("e"),
|
||||
]);
|
||||
const out = interleaved.parse(["alpha"]);
|
||||
expect(out).toEqual(["alpha", undefined, "d", undefined, "e"]);
|
||||
expect(1 in out && 3 in out).toEqual(true);
|
||||
});
|
||||
|
||||
test("tuple truncates absent optional rejections only when the output tail is optional", () => {
|
||||
// An absent optional-output slot can only be swallowed when every later
|
||||
// output slot is optional too. If a later default would make the output tail
|
||||
// required, truncating would violate the tuple's output type.
|
||||
const refusesUndefined = z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((s) => s !== undefined, "must not be undefined");
|
||||
|
||||
const trailingDefault = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
|
||||
const r1 = trailingDefault.safeParse(["alpha"]);
|
||||
expect(r1.success).toBe(false);
|
||||
expect(r1.error!.issues[0].path).toEqual([1]);
|
||||
|
||||
// Optional slots BEFORE the rejected one still cannot hide a later required
|
||||
// output slot.
|
||||
const beforeReject = z.tuple([z.string(), z.string().optional(), refusesUndefined, z.string().default("d")]);
|
||||
const r2 = beforeReject.safeParse(["alpha"]);
|
||||
expect(r2.success).toBe(false);
|
||||
expect(r2.error!.issues[0].path).toEqual([2]);
|
||||
|
||||
// No default after — truncate still applies, no spurious issue surfaces.
|
||||
const noTrailingDefault = z.tuple([z.string(), refusesUndefined]);
|
||||
const r3 = noTrailingDefault.safeParse(["alpha"]);
|
||||
expect(r3.success).toBe(true);
|
||||
expect(r3.data).toEqual(["alpha"]);
|
||||
});
|
||||
|
||||
test("tuple rejects absent optional before required output under async parse", async () => {
|
||||
const refusesUndefined = z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(async (s) => s !== undefined, "must not be undefined");
|
||||
|
||||
const schema = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
|
||||
const r = await schema.safeParseAsync(["alpha"]);
|
||||
expect(r.success).toBe(false);
|
||||
expect(r.error!.issues[0].path).toEqual([1]);
|
||||
});
|
||||
|
||||
test("tuple rejects absent exact optional before defaulted output", () => {
|
||||
const schema = z.tuple([z.string(), z.string().exactOptional(), z.string().default("fallback")]);
|
||||
expectTypeOf<typeof schema._output>().toEqualTypeOf<[string, string, string]>();
|
||||
|
||||
const missingExact = schema.safeParse(["alpha"]);
|
||||
expect(missingExact.success).toBe(false);
|
||||
expect(missingExact.error!.issues[0].path).toEqual([1]);
|
||||
|
||||
expect(schema.parse(["alpha", "bravo"])).toEqual(["alpha", "bravo", "fallback"]);
|
||||
expect(schema.safeParse(["alpha", undefined]).success).toBe(false);
|
||||
|
||||
// With no later required output slot, exact optional still behaves like an
|
||||
// omitted tuple tail and truncates cleanly.
|
||||
expect(z.tuple([z.string(), z.string().exactOptional(), z.string().optional()]).parse(["alpha"])).toEqual(["alpha"]);
|
||||
});
|
||||
|
||||
test("tuple preserves explicit undefined inside input even for optional-out schemas", () => {
|
||||
// The trim only runs for slots PAST `input.length`. An explicit `undefined`
|
||||
// value supplied by the caller at index < input.length must survive, even
|
||||
// when the schema produces undefined as a valid output (e.g.
|
||||
// `z.string().or(z.undefined())`, `z.string().optional()`, `z.undefined()`).
|
||||
const orUndefined = z.tuple([z.string(), z.string().or(z.undefined())]);
|
||||
const r1 = orUndefined.parse(["alpha", undefined]);
|
||||
expect(r1.length).toEqual(2);
|
||||
expect(r1[1]).toBeUndefined();
|
||||
expect(1 in r1).toEqual(true);
|
||||
expect(JSON.stringify(r1)).toEqual('["alpha",null]');
|
||||
|
||||
// Same for `.optional()`.
|
||||
const opt = z.tuple([z.string(), z.string().optional()]);
|
||||
const r2 = opt.parse(["alpha", undefined]);
|
||||
expect(r2.length).toEqual(2);
|
||||
expect(1 in r2).toEqual(true);
|
||||
|
||||
// Same for `z.undefined()` literal.
|
||||
const lit = z.tuple([z.string(), z.undefined()]);
|
||||
const r3 = lit.parse(["alpha", undefined]);
|
||||
expect(r3.length).toEqual(2);
|
||||
expect(1 in r3).toEqual(true);
|
||||
|
||||
// Mid-tuple explicit undefined surrounded by defined values is also kept.
|
||||
const mid = z.tuple([z.string(), z.string().or(z.undefined()), z.string()]);
|
||||
const r4 = mid.parse(["alpha", undefined, "gamma"]);
|
||||
expect(r4).toEqual(["alpha", undefined, "gamma"]);
|
||||
expect(r4.length).toEqual(3);
|
||||
expect(1 in r4).toEqual(true);
|
||||
});
|
||||
|
||||
test("tuple does NOT break when a required slot fails past input length", () => {
|
||||
// A required slot (no `.optional()` chain, so optout !== "optional") past
|
||||
// input length must still surface an issue rather than silently swallowing
|
||||
// it. Otherwise we'd accept arbitrarily short tuples for required-tail
|
||||
// schemas. The precheck collapses this into a single `too_small`.
|
||||
const schema = z.tuple([z.string(), z.string()]);
|
||||
expect(schema.safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("tuple with rest schema", () => {
|
||||
const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean());
|
||||
expect(myTuple.parse(["asdf", 1234, true, false, true])).toEqual(["asdf", 1234, true, false, true]);
|
||||
@@ -181,3 +406,91 @@ test("sparse array input", () => {
|
||||
const schema = z.tuple([z.string(), z.number()]);
|
||||
expect(() => schema.parse(new Array(2))).toThrow();
|
||||
});
|
||||
|
||||
test("under-length tuple emits a single too_small with optStart minimum", () => {
|
||||
const allRequired = z.tuple([z.string(), z.string()]);
|
||||
expect(allRequired.safeParse(["a"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(allRequired.safeParse([]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const trailingOptional = z.tuple([z.string(), z.number().optional()]);
|
||||
expect(trailingOptional.safeParse([]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=1 items",
|
||||
"minimum": 1,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const interiorOptional = z.tuple([z.string(), z.number().optional(), z.string()]);
|
||||
expect(interiorOptional.safeParse(["a", 1]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=3 items",
|
||||
"minimum": 3,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("too_big tuple still surfaces element-wise type errors for present indices", () => {
|
||||
const schema = z.tuple([z.string(), z.number()]);
|
||||
expect(schema.safeParse([1, "x", "extra"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_big",
|
||||
"inclusive": true,
|
||||
"maximum": 2,
|
||||
"message": "Too big: expected array to have <=2 items",
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"message": "Invalid input: expected string, received number",
|
||||
"path": [
|
||||
0,
|
||||
],
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "number",
|
||||
"message": "Invalid input: expected number, received string",
|
||||
"path": [
|
||||
1,
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
+54
@@ -217,3 +217,57 @@ test("z.xor() type inference", () => {
|
||||
type Result = z.infer<typeof schema>;
|
||||
expectTypeOf<Result>().toEqualTypeOf<string | number | boolean>();
|
||||
});
|
||||
|
||||
test("z.union([]) constructs and rejects all input", () => {
|
||||
const schema = z.union([]);
|
||||
expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<never>();
|
||||
const result = schema.safeParse("anything");
|
||||
expect(result.success).toEqual(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_union",
|
||||
"errors": [],
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
test("z.xor([]) constructs and rejects all input", () => {
|
||||
const schema = z.xor([]);
|
||||
expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<never>();
|
||||
const result = schema.safeParse("anything");
|
||||
expect(result.success).toEqual(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_union",
|
||||
"errors": [],
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
test("z.discriminatedUnion with empty options constructs and rejects", () => {
|
||||
const schema = z.discriminatedUnion("type", [] as any);
|
||||
const nonObject = schema.safeParse("nope");
|
||||
expect(nonObject.success).toEqual(false);
|
||||
if (!nonObject.success) {
|
||||
expect(nonObject.error.issues[0].code).toBe("invalid_type");
|
||||
}
|
||||
const obj = schema.safeParse({ type: "x" });
|
||||
expect(obj.success).toEqual(false);
|
||||
if (!obj.success) {
|
||||
expect(obj.error.issues[0].code).toBe("invalid_union");
|
||||
expect((obj.error.issues[0] as any).errors).toEqual([]);
|
||||
expect((obj.error.issues[0] as any).options).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
+31
-6
@@ -246,8 +246,23 @@ export function _nanoid<T extends schemas.$ZodNanoID>(
|
||||
}
|
||||
|
||||
// CUID
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCUIDParams = StringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCheckCUIDParams = CheckStringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _cuid<T extends schemas.$ZodCUID>(
|
||||
Class: util.SchemaClass<T>,
|
||||
@@ -1192,17 +1207,19 @@ export function _xor<const T extends readonly schemas.$ZodObject[]>(
|
||||
}
|
||||
|
||||
// ZodDiscriminatedUnion
|
||||
export interface $ZodTypeDiscriminableInternals extends schemas.$ZodTypeInternals {
|
||||
export interface $ZodTypeDiscriminableInternals<Disc extends string = string>
|
||||
extends schemas.$ZodTypeInternals<unknown, { [K in Disc]?: unknown }> {
|
||||
propValues: util.PropValues;
|
||||
}
|
||||
|
||||
export interface $ZodTypeDiscriminable extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals;
|
||||
export interface $ZodTypeDiscriminable<Disc extends string = string> extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals<Disc>;
|
||||
}
|
||||
|
||||
export type $ZodDiscriminatedUnionParams = TypeParams<schemas.$ZodDiscriminatedUnion, "options" | "discriminator">;
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _discriminatedUnion<
|
||||
Types extends [$ZodTypeDiscriminable, ...$ZodTypeDiscriminable[]],
|
||||
Types extends [$ZodTypeDiscriminable<Disc>, ...$ZodTypeDiscriminable<Disc>[]],
|
||||
Disc extends string,
|
||||
>(
|
||||
Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>,
|
||||
@@ -1633,8 +1650,16 @@ export interface $RefinementCtx<T = unknown> extends schemas.ParsePayload<T> {
|
||||
addIssue(arg: string | $ZodSuperRefineIssue): void;
|
||||
}
|
||||
|
||||
export interface $ZodSuperRefineParams {
|
||||
/** If provided, the refinement runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>): checks.$ZodCheck<T> {
|
||||
export function _superRefine<T>(
|
||||
fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>,
|
||||
params?: $ZodSuperRefineParams
|
||||
): checks.$ZodCheck<T> {
|
||||
const ch = _check<T>((payload) => {
|
||||
(payload as $RefinementCtx).addIssue = (issue) => {
|
||||
if (typeof issue === "string") {
|
||||
@@ -1652,7 +1677,7 @@ export function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void
|
||||
};
|
||||
|
||||
return fn(payload.value, payload as $RefinementCtx<T>);
|
||||
});
|
||||
}, params);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ export interface $ZodCheckDef {
|
||||
error?: errors.$ZodErrorMap<never> | undefined;
|
||||
/** If true, no later checks will be executed if this check fails. Default `false`. */
|
||||
abort?: boolean | undefined;
|
||||
/** If provided, this check will only be executed if the function returns `true`. Defaults to `payload => z.util.isAborted(payload)`. */
|
||||
/** If provided, the check runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
|
||||
|
||||
+17
-2
@@ -10,7 +10,7 @@ export interface $constructor<T extends ZodTrait, D = T["_zod"]["def"]> {
|
||||
}
|
||||
|
||||
/** A special constant with type `never` */
|
||||
export const NEVER: never = Object.freeze({
|
||||
export const NEVER: never = /*@__PURE__*/ Object.freeze({
|
||||
status: "aborted",
|
||||
}) as never;
|
||||
|
||||
@@ -130,7 +130,22 @@ export interface $ZodConfig {
|
||||
jitless?: boolean | undefined;
|
||||
}
|
||||
|
||||
export const globalConfig: $ZodConfig = {};
|
||||
interface GlobalThisWithConfig {
|
||||
/**
|
||||
* The globalConfig instance shared across both CommonJS and ESM builds.
|
||||
* Attached to `globalThis` (mirroring `__zod_globalRegistry`) so that a
|
||||
* single config object is used regardless of how Zod is loaded — CJS,
|
||||
* ESM, multiple bundles in a monorepo, etc. This means `z.config(...)`
|
||||
* applied against any one instance is observed by all of them, and
|
||||
* pre-populating it before Zod loads (e.g. `globalThis.__zod_globalConfig
|
||||
* = { jitless: true }` in an inline script) takes effect immediately on
|
||||
* import.
|
||||
*/
|
||||
__zod_globalConfig?: $ZodConfig;
|
||||
}
|
||||
|
||||
(globalThis as GlobalThisWithConfig).__zod_globalConfig ??= {};
|
||||
export const globalConfig: $ZodConfig = (globalThis as GlobalThisWithConfig).__zod_globalConfig!;
|
||||
|
||||
export function config(newConfig?: Partial<$ZodConfig>): $ZodConfig {
|
||||
if (newConfig) Object.assign(globalConfig, newConfig);
|
||||
|
||||
+30
-23
@@ -91,6 +91,7 @@ interface $ZodIssueInvalidUnionNoMatch extends $ZodIssueBase {
|
||||
readonly errors: $ZodIssue[][];
|
||||
readonly input?: unknown;
|
||||
readonly discriminator?: string | undefined;
|
||||
readonly options?: util.Primitive[];
|
||||
readonly inclusive?: true;
|
||||
}
|
||||
|
||||
@@ -291,32 +292,35 @@ export function formatError<T>(error: $ZodError<T>): $ZodFormattedError<T>;
|
||||
export function formatError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): $ZodFormattedError<T, U>;
|
||||
export function formatError<T, U>(error: $ZodError<T>, mapper = (issue: $ZodIssue) => issue.message as U) {
|
||||
const fieldErrors: $ZodFormattedError<T> = { _errors: [] } as any;
|
||||
const processError = (error: { issues: $ZodIssue[] }) => {
|
||||
const processError = (error: { issues: $ZodIssue[] }, path: PropertyKey[] = []) => {
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
issue.errors.map((issues) => processError({ issues }));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
} else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues });
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
} else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues });
|
||||
} else if (issue.path.length === 0) {
|
||||
(fieldErrors as any)._errors.push(mapper(issue));
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
} else {
|
||||
let curr: any = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < issue.path.length) {
|
||||
const el = issue.path[i]!;
|
||||
const terminal = i === issue.path.length - 1;
|
||||
const fullpath = [...path, ...issue.path];
|
||||
if (fullpath.length === 0) {
|
||||
(fieldErrors as any)._errors.push(mapper(issue));
|
||||
} else {
|
||||
let curr: any = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < fullpath.length) {
|
||||
const el = fullpath[i]!;
|
||||
const terminal = i === fullpath.length - 1;
|
||||
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
} else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
} else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
}
|
||||
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,7 +336,10 @@ export type $ZodErrorTree<T, U = string> = T extends util.Primitive
|
||||
: T extends any[]
|
||||
? { errors: U[]; items?: Array<$ZodErrorTree<T[number], U>> }
|
||||
: T extends object
|
||||
? { errors: U[]; properties?: { [K in keyof T]?: $ZodErrorTree<T[K], U> } }
|
||||
? {
|
||||
errors: U[];
|
||||
properties?: { [K in keyof T]?: $ZodErrorTree<T[K], U> };
|
||||
}
|
||||
: { errors: U[] };
|
||||
|
||||
export function treeifyError<T>(error: $ZodError<T>): $ZodErrorTree<T>;
|
||||
@@ -343,11 +350,11 @@ export function treeifyError<T, U>(error: $ZodError<T>, mapper = (issue: $ZodIss
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
// regular union error
|
||||
issue.errors.map((issues) => processError({ issues }, issue.path));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
} else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
} else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
} else {
|
||||
const fullpath = [...path, ...issue.path];
|
||||
if (fullpath.length === 0) {
|
||||
|
||||
+17
-18
@@ -65,36 +65,31 @@ export const numberProcessor: Processor<schemas.$ZodNumber> = (schema, ctx, _jso
|
||||
if (typeof format === "string" && format.includes("int")) json.type = "integer";
|
||||
else json.type = "number";
|
||||
|
||||
if (typeof exclusiveMinimum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
// when both minimum and exclusiveMinimum exist, pick the more restrictive one
|
||||
const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
|
||||
const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
|
||||
const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
|
||||
|
||||
if (exMin) {
|
||||
if (legacy) {
|
||||
json.minimum = exclusiveMinimum;
|
||||
json.exclusiveMinimum = true;
|
||||
} else {
|
||||
json.exclusiveMinimum = exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
if (typeof minimum === "number") {
|
||||
} else if (typeof minimum === "number") {
|
||||
json.minimum = minimum;
|
||||
if (typeof exclusiveMinimum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMinimum >= minimum) delete json.minimum;
|
||||
else delete json.exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof exclusiveMaximum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
if (exMax) {
|
||||
if (legacy) {
|
||||
json.maximum = exclusiveMaximum;
|
||||
json.exclusiveMaximum = true;
|
||||
} else {
|
||||
json.exclusiveMaximum = exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
if (typeof maximum === "number") {
|
||||
} else if (typeof maximum === "number") {
|
||||
json.maximum = maximum;
|
||||
if (typeof exclusiveMaximum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMaximum <= maximum) delete json.maximum;
|
||||
else delete json.exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
||||
@@ -286,7 +281,10 @@ export const arrayProcessor: Processor<schemas.$ZodArray> = (schema, ctx, _json,
|
||||
if (typeof maximum === "number") json.maxItems = maximum;
|
||||
|
||||
json.type = "array";
|
||||
json.items = process(def.element, ctx as any, { ...params, path: [...params.path, "items"] });
|
||||
json.items = process(def.element, ctx as any, {
|
||||
...params,
|
||||
path: [...params.path, "items"],
|
||||
});
|
||||
};
|
||||
|
||||
export const objectProcessor: Processor<schemas.$ZodObject> = (schema, ctx, _json, params) => {
|
||||
@@ -527,7 +525,8 @@ export const catchProcessor: Processor<schemas.$ZodCatch> = (schema, ctx, json,
|
||||
|
||||
export const pipeProcessor: Processor<schemas.$ZodPipe> = (schema, ctx, _json, params) => {
|
||||
const def = schema._zod.def as schemas.$ZodPipeDef;
|
||||
const innerType = ctx.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out;
|
||||
const inIsTransform = def.in._zod.traits.has("$ZodTransform");
|
||||
const innerType = ctx.io === "input" ? (inIsTransform ? def.out : def.in) : def.out;
|
||||
process(innerType, ctx as any, params);
|
||||
const seen = ctx.seen.get(schema)!;
|
||||
seen.ref = innerType;
|
||||
|
||||
+7
-7
@@ -14,7 +14,7 @@ export type $Parse = <T extends schemas.$ZodType>(
|
||||
) => core.output<T>;
|
||||
|
||||
export const _parse: (_Err: $ZodErrorClass) => $Parse = (_Err) => (schema, value, _ctx, _params) => {
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: false } : { async: false };
|
||||
const result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
throw new core.$ZodAsyncError();
|
||||
@@ -37,7 +37,7 @@ export type $ParseAsync = <T extends schemas.$ZodType>(
|
||||
) => Promise<core.output<T>>;
|
||||
|
||||
export const _parseAsync: (_Err: $ZodErrorClass) => $ParseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise) result = await result;
|
||||
if (result.issues.length) {
|
||||
@@ -79,7 +79,7 @@ export type $SafeParseAsync = <T extends schemas.$ZodType>(
|
||||
) => Promise<util.SafeParseResult<core.output<T>>>;
|
||||
|
||||
export const _safeParseAsync: (_Err: $ZodErrorClass) => $SafeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise) result = await result;
|
||||
|
||||
@@ -101,7 +101,7 @@ export type $Encode = <T extends schemas.$ZodType>(
|
||||
) => core.input<T>;
|
||||
|
||||
export const _encode: (_Err: $ZodErrorClass) => $Encode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" as const }) : { direction: "backward" as const };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" as const } : { direction: "backward" as const };
|
||||
return _parse(_Err)(schema, value, ctx as any) as any;
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ export type $EncodeAsync = <T extends schemas.$ZodType>(
|
||||
) => Promise<core.input<T>>;
|
||||
|
||||
export const _encodeAsync: (_Err: $ZodErrorClass) => $EncodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" as const }) : { direction: "backward" as const };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" as const } : { direction: "backward" as const };
|
||||
return _parseAsync(_Err)(schema, value, ctx as any) as any;
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ export type $SafeEncode = <T extends schemas.$ZodType>(
|
||||
) => util.SafeParseResult<core.input<T>>;
|
||||
|
||||
export const _safeEncode: (_Err: $ZodErrorClass) => $SafeEncode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" as const }) : { direction: "backward" as const };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" as const } : { direction: "backward" as const };
|
||||
return _safeParse(_Err)(schema, value, ctx as any) as any;
|
||||
};
|
||||
|
||||
@@ -176,7 +176,7 @@ export type $SafeEncodeAsync = <T extends schemas.$ZodType>(
|
||||
) => Promise<util.SafeParseResult<core.input<T>>>;
|
||||
|
||||
export const _safeEncodeAsync: (_Err: $ZodErrorClass) => $SafeEncodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" as const }) : { direction: "backward" as const };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" as const } : { direction: "backward" as const };
|
||||
return _safeParseAsync(_Err)(schema, value, ctx as any) as any;
|
||||
};
|
||||
|
||||
|
||||
+8
-1
@@ -1,6 +1,11 @@
|
||||
import * as util from "./util.js";
|
||||
|
||||
export const cuid: RegExp = /^[cC][^\s-]{8,}$/;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const cuid: RegExp = /^[cC][0-9a-z]{6,}$/;
|
||||
export const cuid2: RegExp = /^[0-9a-z]+$/;
|
||||
export const ulid: RegExp = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
|
||||
export const xid: RegExp = /^[0-9a-vA-V]{20}$/;
|
||||
@@ -81,6 +86,8 @@ export const hostname: RegExp =
|
||||
|
||||
export const domain: RegExp = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
||||
|
||||
export const httpProtocol: RegExp = /^https?$/;
|
||||
|
||||
// https://blog.stevenlevithan.com/archives/validate-phone-number#r4-3 (regex sans spaces)
|
||||
// E.164: leading digit must be 1-9; total digits (excluding '+') between 7-15
|
||||
export const e164: RegExp = /^\+[1-9]\d{6,14}$/;
|
||||
|
||||
+263
-71
@@ -34,8 +34,13 @@ export interface ParseContextInternal<T extends errors.$ZodIssueBase = never> ex
|
||||
export interface ParsePayload<T = unknown> {
|
||||
value: T;
|
||||
issues: errors.$ZodRawIssue[];
|
||||
/** A may to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
/** A way to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
aborted?: boolean;
|
||||
/** @internal Marks a value as a fallback that an outer wrapper (e.g.
|
||||
* $ZodOptional) may override with its own interpretation when input was
|
||||
* undefined. Set by $ZodCatch when catchValue substitutes and by every
|
||||
* $ZodTransform invocation. */
|
||||
fallback?: boolean | undefined;
|
||||
}
|
||||
|
||||
export type CheckFn<T> = (input: ParsePayload<T>) => util.MaybeAsync<void>;
|
||||
@@ -220,6 +225,7 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
|
||||
let asyncResult!: Promise<unknown> | undefined;
|
||||
for (const ch of checks) {
|
||||
if (ch._zod.def.when) {
|
||||
if (util.explicitlyAborted(payload)) continue;
|
||||
const shouldRun = ch._zod.def.when(payload);
|
||||
if (!shouldRun) continue;
|
||||
} else if (isAborted) {
|
||||
@@ -477,6 +483,23 @@ export const $ZodURL: core.$constructor<$ZodURL> = /*@__PURE__*/ core.$construct
|
||||
try {
|
||||
// Trim whitespace from input
|
||||
const trimmed = payload.value.trim();
|
||||
|
||||
// When normalize is off, require :// for http/https URLs
|
||||
// This prevents strings like "http:example.com" or "https:/path" from being silently accepted
|
||||
if (!def.normalize && def.protocol?.source === regexes.httpProtocol.source) {
|
||||
if (!/^https?:\/\//i.test(trimmed)) {
|
||||
payload.issues.push({
|
||||
code: "invalid_format",
|
||||
format: "url",
|
||||
note: "Invalid URL format",
|
||||
input: payload.value,
|
||||
inst,
|
||||
continue: !def.abort,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const url = new URL(trimmed);
|
||||
|
||||
@@ -568,13 +591,33 @@ export const $ZodNanoID: core.$constructor<$ZodNanoID> = /*@__PURE__*/ core.$con
|
||||
|
||||
////////////////////////////// ZodCUID //////////////////////////////
|
||||
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDDef extends $ZodStringFormatDef<"cuid"> {}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDInternals extends $ZodStringFormatInternals<"cuid"> {}
|
||||
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUID extends $ZodType {
|
||||
_zod: $ZodCUIDInternals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const $ZodCUID: core.$constructor<$ZodCUID> = /*@__PURE__*/ core.$constructor("$ZodCUID", (inst, def): void => {
|
||||
def.pattern ??= regexes.cuid;
|
||||
$ZodStringFormat.init(inst, def);
|
||||
@@ -869,6 +912,8 @@ export const $ZodCIDRv6: core.$constructor<$ZodCIDRv6> = /*@__PURE__*/ core.$con
|
||||
////////////////////////////// ZodBase64 //////////////////////////////
|
||||
export function isValidBase64(data: string): boolean {
|
||||
if (data === "") return true;
|
||||
// atob ignores whitespace, so reject it up front.
|
||||
if (/\s/.test(data)) return false;
|
||||
if (data.length % 4 !== 0) return false;
|
||||
try {
|
||||
// @ts-ignore
|
||||
@@ -1318,8 +1363,6 @@ export const $ZodUndefined: core.$constructor<$ZodUndefined> = /*@__PURE__*/ cor
|
||||
$ZodType.init(inst, def);
|
||||
inst._zod.pattern = regexes.undefined;
|
||||
inst._zod.values = new Set([undefined]);
|
||||
inst._zod.optin = "optional";
|
||||
inst._zod.optout = "optional";
|
||||
|
||||
inst._zod.parse = (payload, _ctx) => {
|
||||
const input = payload.value;
|
||||
@@ -1709,18 +1752,32 @@ function handlePropertyResult(
|
||||
final: ParsePayload,
|
||||
key: PropertyKey,
|
||||
input: any,
|
||||
isOptionalIn: boolean,
|
||||
isOptionalOut: boolean
|
||||
) {
|
||||
const isPresent = key in input;
|
||||
if (result.issues.length) {
|
||||
// For optional-out schemas, ignore errors on absent keys
|
||||
if (isOptionalOut && !(key in input)) {
|
||||
// For optional-in/out schemas, ignore errors on absent keys.
|
||||
if (isOptionalIn && isOptionalOut && !isPresent) {
|
||||
return;
|
||||
}
|
||||
final.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
|
||||
if (!isPresent && !isOptionalIn) {
|
||||
if (!result.issues.length) {
|
||||
final.issues.push({
|
||||
code: "invalid_type",
|
||||
expected: "nonoptional",
|
||||
input: undefined,
|
||||
path: [key],
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.value === undefined) {
|
||||
if (key in input) {
|
||||
if (isPresent) {
|
||||
(final.value as any)[key] = undefined;
|
||||
}
|
||||
} else {
|
||||
@@ -1805,12 +1862,15 @@ function handleCatchall(
|
||||
inst: $ZodObject
|
||||
) {
|
||||
const unrecognized: string[] = [];
|
||||
// iterate over input keys
|
||||
const keySet = def.keySet;
|
||||
const _catchall = def.catchall!._zod;
|
||||
const t = _catchall.def.type;
|
||||
const isOptionalIn = _catchall.optin === "optional";
|
||||
const isOptionalOut = _catchall.optout === "optional";
|
||||
for (const key in input) {
|
||||
// skip __proto__ so it can't replace the result prototype via the
|
||||
// assignment setter on the plain {} we build into
|
||||
if (key === "__proto__") continue;
|
||||
if (keySet.has(key)) continue;
|
||||
if (t === "never") {
|
||||
unrecognized.push(key);
|
||||
@@ -1819,9 +1879,9 @@ function handleCatchall(
|
||||
const r = _catchall.run({ value: input[key], issues: [] }, ctx);
|
||||
|
||||
if (r instanceof Promise) {
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut)));
|
||||
} else {
|
||||
handlePropertyResult(r, payload, key, input, isOptionalOut);
|
||||
handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1899,13 +1959,14 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con
|
||||
|
||||
for (const key of value.keys) {
|
||||
const el = shape[key]!;
|
||||
const isOptionalIn = el._zod.optin === "optional";
|
||||
const isOptionalOut = el._zod.optout === "optional";
|
||||
|
||||
const r = el._zod.run({ value: input[key], issues: [] }, ctx);
|
||||
if (r instanceof Promise) {
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut)));
|
||||
} else {
|
||||
handlePropertyResult(r, payload, key, input, isOptionalOut);
|
||||
handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1949,12 +2010,13 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$
|
||||
const id = ids[key];
|
||||
const k = util.esc(key);
|
||||
const schema = shape[key];
|
||||
const isOptionalIn = schema?._zod?.optin === "optional";
|
||||
const isOptionalOut = schema?._zod?.optout === "optional";
|
||||
|
||||
doc.write(`const ${id} = ${parseStr(key)};`);
|
||||
|
||||
if (isOptionalOut) {
|
||||
// For optional-out schemas, ignore errors on absent keys
|
||||
if (isOptionalIn && isOptionalOut) {
|
||||
// For optional-in/out schemas, ignore errors on absent keys
|
||||
doc.write(`
|
||||
if (${id}.issues.length) {
|
||||
if (${k} in input) {
|
||||
@@ -1973,6 +2035,33 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$
|
||||
newResult[${k}] = ${id}.value;
|
||||
}
|
||||
|
||||
`);
|
||||
} else if (!isOptionalIn) {
|
||||
doc.write(`
|
||||
const ${id}_present = ${k} in input;
|
||||
if (${id}.issues.length) {
|
||||
payload.issues = payload.issues.concat(${id}.issues.map(iss => ({
|
||||
...iss,
|
||||
path: iss.path ? [${k}, ...iss.path] : [${k}]
|
||||
})));
|
||||
}
|
||||
if (!${id}_present && !${id}.issues.length) {
|
||||
payload.issues.push({
|
||||
code: "invalid_type",
|
||||
expected: "nonoptional",
|
||||
input: undefined,
|
||||
path: [${k}]
|
||||
});
|
||||
}
|
||||
|
||||
if (${id}_present) {
|
||||
if (${id}.value === undefined) {
|
||||
newResult[${k}] = undefined;
|
||||
} else {
|
||||
newResult[${k}] = ${id}.value;
|
||||
}
|
||||
}
|
||||
|
||||
`);
|
||||
} else {
|
||||
doc.write(`
|
||||
@@ -2126,11 +2215,10 @@ export const $ZodUnion: core.$constructor<$ZodUnion> = /*@__PURE__*/ core.$const
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const single = def.options.length === 1;
|
||||
const first = def.options[0]._zod.run;
|
||||
const first = def.options.length === 1 ? def.options[0]._zod.run : null;
|
||||
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (single) {
|
||||
if (first) {
|
||||
return first(payload, ctx);
|
||||
}
|
||||
let async = false;
|
||||
@@ -2206,11 +2294,10 @@ export const $ZodXor: core.$constructor<$ZodXor> = /*@__PURE__*/ core.$construct
|
||||
$ZodUnion.init(inst, def);
|
||||
def.inclusive = false;
|
||||
|
||||
const single = def.options.length === 1;
|
||||
const first = def.options[0]._zod.run;
|
||||
const first = def.options.length === 1 ? def.options[0]._zod.run : null;
|
||||
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (single) {
|
||||
if (first) {
|
||||
return first(payload, ctx);
|
||||
}
|
||||
let async = false;
|
||||
@@ -2329,17 +2416,21 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
|
||||
return opt._zod.run(payload, ctx) as any;
|
||||
}
|
||||
|
||||
if (def.unionFallback) {
|
||||
// Fall back to union matching when the fast discriminator path fails:
|
||||
// - explicitly enabled via unionFallback, or
|
||||
// - during backward direction (encode), since codec-based discriminators
|
||||
// have different values in forward vs backward directions
|
||||
if (def.unionFallback || ctx.direction === "backward") {
|
||||
return _super(payload, ctx);
|
||||
}
|
||||
|
||||
// no matching discriminator
|
||||
payload.issues.push({
|
||||
code: "invalid_union",
|
||||
|
||||
errors: [],
|
||||
note: "No matching discriminator",
|
||||
discriminator: def.discriminator,
|
||||
options: Array.from(disc.value.keys()),
|
||||
input,
|
||||
path: [def.discriminator],
|
||||
inst,
|
||||
@@ -2591,70 +2682,79 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const
|
||||
payload.value = [];
|
||||
const proms: Promise<any>[] = [];
|
||||
|
||||
const reversedIndex = [...items].reverse().findIndex((item) => item._zod.optin !== "optional");
|
||||
const optStart = reversedIndex === -1 ? 0 : items.length - reversedIndex;
|
||||
const optinStart = getTupleOptStart(items, "optin");
|
||||
const optoutStart = getTupleOptStart(items, "optout");
|
||||
|
||||
if (!def.rest) {
|
||||
const tooBig = input.length > items.length;
|
||||
const tooSmall = input.length < optStart - 1;
|
||||
if (tooBig || tooSmall) {
|
||||
if (input.length < optinStart) {
|
||||
payload.issues.push({
|
||||
...(tooBig
|
||||
? { code: "too_big", maximum: items.length, inclusive: true }
|
||||
: { code: "too_small", minimum: items.length }),
|
||||
|
||||
code: "too_small",
|
||||
minimum: optinStart,
|
||||
inclusive: true,
|
||||
input,
|
||||
inst,
|
||||
origin: "array" as const,
|
||||
});
|
||||
return payload;
|
||||
}
|
||||
if (input.length > items.length) {
|
||||
payload.issues.push({
|
||||
code: "too_big",
|
||||
maximum: items.length,
|
||||
inclusive: true,
|
||||
input,
|
||||
inst,
|
||||
origin: "array" as const,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let i = -1;
|
||||
for (const item of items) {
|
||||
i++;
|
||||
if (i >= input.length) if (i >= optStart) continue;
|
||||
const result = item._zod.run(
|
||||
{
|
||||
value: input[i],
|
||||
issues: [],
|
||||
},
|
||||
ctx
|
||||
);
|
||||
|
||||
if (result instanceof Promise) {
|
||||
proms.push(result.then((result) => handleTupleResult(result, payload, i)));
|
||||
// Run every item in parallel, collecting results into an indexed
|
||||
// array. The post-processing in `handleTupleResults` walks them in
|
||||
// order so it can decide whether an absent optional-output error can
|
||||
// truncate the tail or must be reported to preserve required output.
|
||||
const itemResults: ParsePayload[] = new Array(items.length);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const r = items[i]._zod.run({ value: input[i], issues: [] }, ctx);
|
||||
if (r instanceof Promise) {
|
||||
proms.push(
|
||||
r.then((rr) => {
|
||||
itemResults[i] = rr;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
handleTupleResult(result, payload, i);
|
||||
itemResults[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (def.rest) {
|
||||
let i = items.length - 1;
|
||||
const rest = input.slice(items.length);
|
||||
for (const el of rest) {
|
||||
i++;
|
||||
const result = def.rest._zod.run(
|
||||
{
|
||||
value: el,
|
||||
issues: [],
|
||||
},
|
||||
ctx
|
||||
);
|
||||
|
||||
const result = def.rest._zod.run({ value: el, issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
proms.push(result.then((result) => handleTupleResult(result, payload, i)));
|
||||
proms.push(result.then((r) => handleTupleResult(r, payload, i)));
|
||||
} else {
|
||||
handleTupleResult(result, payload, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (proms.length) return Promise.all(proms).then(() => payload);
|
||||
return payload;
|
||||
if (proms.length) {
|
||||
return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items, input, optoutStart));
|
||||
}
|
||||
return handleTupleResults(itemResults, payload, items, input, optoutStart);
|
||||
};
|
||||
});
|
||||
|
||||
function getTupleOptStart(items: readonly $ZodType[], key: "optin" | "optout") {
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
if (items[i]._zod[key] !== "optional") return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function handleTupleResult(result: ParsePayload, final: ParsePayload<any[]>, index: number) {
|
||||
if (result.issues.length) {
|
||||
final.issues.push(...util.prefixIssues(index, result.issues));
|
||||
@@ -2662,6 +2762,45 @@ function handleTupleResult(result: ParsePayload, final: ParsePayload<any[]>, ind
|
||||
final.value[index] = result.value;
|
||||
}
|
||||
|
||||
function handleTupleResults(
|
||||
itemResults: ParsePayload[],
|
||||
final: ParsePayload<any[]>,
|
||||
items: readonly $ZodType[],
|
||||
input: unknown[],
|
||||
optoutStart: number
|
||||
) {
|
||||
// Walk results in order. Mirror $ZodObject's swallow-on-absent-optional
|
||||
// rule, but only after `optoutStart`: the first index where the output
|
||||
// tuple tail can be absent.
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const r = itemResults[i];
|
||||
const isPresent = i < input.length;
|
||||
if (r.issues.length) {
|
||||
if (!isPresent && i >= optoutStart) {
|
||||
final.value.length = i;
|
||||
break;
|
||||
}
|
||||
final.issues.push(...util.prefixIssues(i, r.issues));
|
||||
}
|
||||
final.value[i] = r.value;
|
||||
}
|
||||
|
||||
// Drop trailing slots that produced `undefined` for absent input
|
||||
// (the array analog of an absent optional key on an object). The
|
||||
// `i >= input.length` floor is critical: an explicit `undefined`
|
||||
// *inside* the input must be preserved even when the schema is
|
||||
// optional-out (e.g. `z.string().or(z.undefined())` accepting an
|
||||
// explicit undefined value).
|
||||
for (let i = final.value.length - 1; i >= input.length; i--) {
|
||||
if (items[i]._zod.optout === "optional" && final.value[i] === undefined) {
|
||||
final.value.length = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return final;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
////////// //////////
|
||||
@@ -2759,6 +2898,22 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
|
||||
for (const key of values) {
|
||||
if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
|
||||
recordKeys.add(typeof key === "number" ? key.toString() : key);
|
||||
const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
|
||||
if (keyResult instanceof Promise) {
|
||||
throw new Error("Async schemas not supported in object keys currently");
|
||||
}
|
||||
if (keyResult.issues.length) {
|
||||
payload.issues.push({
|
||||
code: "invalid_key",
|
||||
origin: "record",
|
||||
issues: keyResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
|
||||
input: key,
|
||||
path: [key],
|
||||
inst,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const outKey = keyResult.value as PropertyKey;
|
||||
const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
|
||||
|
||||
if (result instanceof Promise) {
|
||||
@@ -2767,14 +2922,14 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
|
||||
if (result.issues.length) {
|
||||
payload.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
payload.value[key] = result.value;
|
||||
payload.value[outKey] = result.value;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
if (result.issues.length) {
|
||||
payload.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
payload.value[key] = result.value;
|
||||
payload.value[outKey] = result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2797,8 +2952,10 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
|
||||
}
|
||||
} else {
|
||||
payload.value = {};
|
||||
// Reflect.ownKeys for Symbol-key support; filter non-enumerable to match z.object()
|
||||
for (const key of Reflect.ownKeys(input)) {
|
||||
if (key === "__proto__") continue;
|
||||
if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue;
|
||||
let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
|
||||
if (keyResult instanceof Promise) {
|
||||
throw new Error("Async schemas not supported in object keys currently");
|
||||
@@ -3265,6 +3422,7 @@ export const $ZodTransform: core.$constructor<$ZodTransform> = /*@__PURE__*/ cor
|
||||
"$ZodTransform",
|
||||
(inst, def) => {
|
||||
$ZodType.init(inst, def);
|
||||
inst._zod.optin = "optional";
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (ctx.direction === "backward") {
|
||||
throw new core.$ZodEncodeError(inst.constructor.name);
|
||||
@@ -3275,6 +3433,7 @@ export const $ZodTransform: core.$constructor<$ZodTransform> = /*@__PURE__*/ cor
|
||||
const output = _out instanceof Promise ? _out : Promise.resolve(_out);
|
||||
return output.then((output) => {
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
});
|
||||
}
|
||||
@@ -3284,6 +3443,7 @@ export const $ZodTransform: core.$constructor<$ZodTransform> = /*@__PURE__*/ cor
|
||||
}
|
||||
|
||||
payload.value = _out;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
};
|
||||
}
|
||||
@@ -3316,7 +3476,7 @@ export interface $ZodOptional<T extends SomeType = $ZodType> extends $ZodType {
|
||||
}
|
||||
|
||||
function handleOptionalResult(result: ParsePayload, input: unknown) {
|
||||
if (result.issues.length && input === undefined) {
|
||||
if (input === undefined && (result.issues.length || result.fallback)) {
|
||||
return { issues: [], value: undefined };
|
||||
}
|
||||
return result;
|
||||
@@ -3339,9 +3499,10 @@ export const $ZodOptional: core.$constructor<$ZodOptional> = /*@__PURE__*/ core.
|
||||
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (def.innerType._zod.optin === "optional") {
|
||||
const input = payload.value;
|
||||
const result = def.innerType._zod.run(payload, ctx);
|
||||
if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, payload.value));
|
||||
return handleOptionalResult(result, payload.value);
|
||||
if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input));
|
||||
return handleOptionalResult(result, input);
|
||||
}
|
||||
if (payload.value === undefined) {
|
||||
return payload;
|
||||
@@ -3734,7 +3895,7 @@ export interface $ZodCatch<T extends SomeType = $ZodType> extends $ZodType {
|
||||
|
||||
export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$constructor("$ZodCatch", (inst, def) => {
|
||||
$ZodType.init(inst, def);
|
||||
util.defineLazy(inst._zod, "optin", () => def.innerType._zod.optin);
|
||||
inst._zod.optin = "optional";
|
||||
util.defineLazy(inst._zod, "optout", () => def.innerType._zod.optout);
|
||||
util.defineLazy(inst._zod, "values", () => def.innerType._zod.values);
|
||||
|
||||
@@ -3757,6 +3918,7 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
|
||||
input: payload.value,
|
||||
});
|
||||
payload.issues = [];
|
||||
payload.fallback = true;
|
||||
}
|
||||
|
||||
return payload;
|
||||
@@ -3774,6 +3936,7 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
|
||||
});
|
||||
|
||||
payload.issues = [];
|
||||
payload.fallback = true;
|
||||
}
|
||||
|
||||
return payload;
|
||||
@@ -3878,7 +4041,7 @@ function handlePipeResult(left: ParsePayload, next: $ZodType, ctx: ParseContextI
|
||||
left.aborted = true;
|
||||
return left;
|
||||
}
|
||||
return next._zod.run({ value: left.value, issues: left.issues }, ctx);
|
||||
return next._zod.run({ value: left.value, issues: left.issues, fallback: left.fallback }, ctx);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
@@ -3966,6 +4129,35 @@ function handleCodecTxResult(left: ParsePayload, value: any, nextSchema: SomeTyp
|
||||
return nextSchema._zod.run({ value, issues: left.issues }, ctx);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////
|
||||
////////// //////////
|
||||
////////// $ZodPreprocess //////////
|
||||
////////// //////////
|
||||
/////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////
|
||||
export interface $ZodPreprocessDef<B extends SomeType = $ZodType> extends $ZodPipeDef<$ZodTransform, B> {
|
||||
in: $ZodTransform;
|
||||
out: B;
|
||||
}
|
||||
|
||||
export interface $ZodPreprocessInternals<B extends SomeType = $ZodType> extends $ZodPipeInternals<$ZodTransform, B> {
|
||||
def: $ZodPreprocessDef<B>;
|
||||
optin: B["_zod"]["optin"];
|
||||
optout: B["_zod"]["optout"];
|
||||
}
|
||||
|
||||
export interface $ZodPreprocess<B extends SomeType = $ZodType> extends $ZodPipe<$ZodTransform, B> {
|
||||
_zod: $ZodPreprocessInternals<B>;
|
||||
}
|
||||
|
||||
export const $ZodPreprocess: core.$constructor<$ZodPreprocess> = /*@__PURE__*/ core.$constructor(
|
||||
"$ZodPreprocess",
|
||||
(inst, def) => {
|
||||
$ZodPipe.init(inst, def);
|
||||
}
|
||||
);
|
||||
|
||||
////////////////////////////////////////////
|
||||
////////////////////////////////////////////
|
||||
////////// //////////
|
||||
@@ -4384,14 +4576,14 @@ export interface $ZodLazy<T extends SomeType = $ZodType> extends $ZodType {
|
||||
export const $ZodLazy: core.$constructor<$ZodLazy> = /*@__PURE__*/ core.$constructor("$ZodLazy", (inst, def) => {
|
||||
$ZodType.init(inst, def);
|
||||
|
||||
// let _innerType!: any;
|
||||
// util.defineLazy(def, "getter", () => {
|
||||
// if (!_innerType) {
|
||||
// _innerType = def.getter();
|
||||
// }
|
||||
// return () => _innerType;
|
||||
// });
|
||||
util.defineLazy(inst._zod, "innerType", () => def.getter() as $ZodType);
|
||||
// Cache the resolved inner type on the shared `def` so all clones of this
|
||||
// lazy (e.g. via `.describe()`/`.meta()`) share the same inner instance,
|
||||
// preserving identity for cycle detection on recursive schemas.
|
||||
util.defineLazy(inst._zod, "innerType", () => {
|
||||
const d = def as $ZodLazyDef & { _cachedInner?: $ZodType };
|
||||
if (!d._cachedInner) d._cachedInner = def.getter() as $ZodType;
|
||||
return d._cachedInner;
|
||||
});
|
||||
util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern);
|
||||
util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues);
|
||||
util.defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? undefined);
|
||||
|
||||
+22
@@ -80,4 +80,26 @@ test("locales - uz", () => {
|
||||
const invalidElement = z.array(z.string()).safeParse([1, 2, 3]);
|
||||
expect(invalidElement.error!.issues[0].code).toBe("invalid_type");
|
||||
expect(invalidElement.error!.issues[0].message).toContain("raqam");
|
||||
|
||||
const tooSmallMap = z
|
||||
.map(z.string(), z.string())
|
||||
.min(3)
|
||||
.safeParse(new Map([["a", "b"]]));
|
||||
expect(tooSmallMap.error!.issues[0].code).toBe("too_small");
|
||||
expect(tooSmallMap.error!.issues[0].message).toContain("yozuv");
|
||||
expect(tooSmallMap.error!.issues[0].message).toContain("bo‘lishi kerak");
|
||||
|
||||
const tooBigMap = z
|
||||
.map(z.string(), z.string())
|
||||
.max(2)
|
||||
.safeParse(
|
||||
new Map([
|
||||
["a", "b"],
|
||||
["c", "d"],
|
||||
["e", "f"],
|
||||
])
|
||||
);
|
||||
expect(tooBigMap.error!.issues[0].code).toBe("too_big");
|
||||
expect(tooBigMap.error!.issues[0].message).toContain("yozuv");
|
||||
expect(tooBigMap.error!.issues[0].message).toContain("bo‘lishi kerak");
|
||||
});
|
||||
|
||||
+58
@@ -65,3 +65,61 @@ test("record should work with different key types and constructor field", () =>
|
||||
const result = enumSchema.parse({ constructor: "value1", key: "value2" });
|
||||
expect(result).toEqual({ constructor: "value1", key: "value2" });
|
||||
});
|
||||
|
||||
test("record should skip non-enumerable own properties", () => {
|
||||
const schema = z.record(z.string(), z.string());
|
||||
|
||||
const input = { key: "value" };
|
||||
Object.defineProperty(input, "~standard", {
|
||||
value: { validate: () => {}, vendor: "zod", version: 1 },
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
const result = schema.safeParse(input);
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data).toEqual({ key: "value" });
|
||||
expect("~standard" in result.data).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
test("record fails on enumerable invalid values even when non-enumerable properties are present", () => {
|
||||
const schema = z.record(z.string(), z.string());
|
||||
|
||||
const input = { key: "value", bad: 123 };
|
||||
Object.defineProperty(input, "hidden", {
|
||||
value: "should be ignored",
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
const result = schema.safeParse(input);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
test("record validates enumerable Symbol keys and skips non-enumerable Symbol keys", () => {
|
||||
const enumerableSym = Symbol.for("included");
|
||||
const nonEnumerableSym = Symbol.for("hidden");
|
||||
const schema = z.record(z.symbol(), z.string());
|
||||
|
||||
const input: Record<symbol, unknown> = { [enumerableSym]: "value" };
|
||||
Object.defineProperty(input, nonEnumerableSym, {
|
||||
value: 123,
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
const result = schema.safeParse(input);
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data[enumerableSym]).toBe("value");
|
||||
expect(Object.prototype.hasOwnProperty.call(result.data, nonEnumerableSym)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
test("z.json() accepts z.toJSONSchema() output (issue #5714)", () => {
|
||||
const schema = z.object({ name: z.string() });
|
||||
const jsonSchema = z.toJSONSchema(schema);
|
||||
|
||||
expect(z.json().safeParse(jsonSchema).success).toBe(true);
|
||||
});
|
||||
|
||||
+10
-1
@@ -205,7 +205,7 @@ export function process<T extends schemas.$ZodType>(
|
||||
}
|
||||
|
||||
// set prefault as default
|
||||
if (ctx.io === "input" && result.schema._prefault) result.schema.default ??= result.schema._prefault;
|
||||
if (ctx.io === "input" && "_prefault" in result.schema) result.schema.default ??= result.schema._prefault;
|
||||
delete result.schema._prefault;
|
||||
|
||||
// pulling fresh from ctx.seen in case it was overwritten
|
||||
@@ -471,11 +471,19 @@ export function finalize<T extends schemas.$ZodType>(
|
||||
|
||||
Object.assign(result, root.def ?? root.schema);
|
||||
|
||||
// The `id` in `.meta()` is a Zod-specific registration tag used to extract
|
||||
// schemas into $defs — it is not user-facing JSON Schema metadata. Strip it
|
||||
// from the output body where it would otherwise leak. The id is preserved
|
||||
// implicitly via the $defs key (and via $ref paths).
|
||||
const rootMetaId = ctx.metadataRegistry.get(schema)?.id;
|
||||
if (rootMetaId !== undefined && result.id === rootMetaId) delete result.id;
|
||||
|
||||
// build defs object
|
||||
const defs: JSONSchema.BaseSchema["$defs"] = ctx.external?.defs ?? {};
|
||||
for (const entry of ctx.seen.entries()) {
|
||||
const seen = entry[1];
|
||||
if (seen.def && seen.defId) {
|
||||
if (seen.def.id === seen.defId) delete seen.def.id;
|
||||
defs[seen.defId] = seen.def;
|
||||
}
|
||||
}
|
||||
@@ -553,6 +561,7 @@ function isTransforming(
|
||||
return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
|
||||
}
|
||||
if (def.type === "pipe") {
|
||||
if (_schema._zod.traits.has("$ZodCodec")) return true;
|
||||
return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
|
||||
}
|
||||
|
||||
|
||||
+52
-35
@@ -1,4 +1,5 @@
|
||||
import type * as checks from "./checks.js";
|
||||
import { globalConfig } from "./core.js";
|
||||
import type { $ZodConfig } from "./core.js";
|
||||
import type * as errors from "./errors.js";
|
||||
import type * as schemas from "./schemas.js";
|
||||
@@ -245,23 +246,15 @@ export function cleanRegex(source: string): string {
|
||||
}
|
||||
|
||||
export function floatSafeRemainder(val: number, step: number): number {
|
||||
const valDecCount = (val.toString().split(".")[1] || "").length;
|
||||
const stepString = step.toString();
|
||||
let stepDecCount = (stepString.split(".")[1] || "").length;
|
||||
if (stepDecCount === 0 && /\d?e-\d?/.test(stepString)) {
|
||||
const match = stepString.match(/\d?e-(\d?)/);
|
||||
if (match?.[1]) {
|
||||
stepDecCount = Number.parseInt(match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount;
|
||||
const valInt = Number.parseInt(val.toFixed(decCount).replace(".", ""));
|
||||
const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
|
||||
return (valInt % stepInt) / 10 ** decCount;
|
||||
const ratio = val / step;
|
||||
const roundedRatio = Math.round(ratio);
|
||||
// Use a relative epsilon scaled to the magnitude of the result
|
||||
const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1);
|
||||
if (Math.abs(ratio - roundedRatio) < tolerance) return 0;
|
||||
return ratio - roundedRatio;
|
||||
}
|
||||
|
||||
const EVALUATING = Symbol("evaluating");
|
||||
const EVALUATING = /* @__PURE__*/ Symbol("evaluating");
|
||||
|
||||
export function defineLazy<T, K extends keyof T>(object: T, key: K, getter: () => T[K]): void {
|
||||
let value: T[K] | typeof EVALUATING | undefined = undefined;
|
||||
@@ -368,7 +361,13 @@ export function isObject(data: any): data is Record<PropertyKey, unknown> {
|
||||
return typeof data === "object" && data !== null && !Array.isArray(data);
|
||||
}
|
||||
|
||||
export const allowsEval: { value: boolean } = cached(() => {
|
||||
export const allowsEval: { value: boolean } = /* @__PURE__*/ cached(() => {
|
||||
// Skip the probe under `jitless`: strict CSPs report the caught `new Function`
|
||||
// as a `securitypolicyviolation` even though the throw is swallowed.
|
||||
if (globalConfig.jitless) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) {
|
||||
return false;
|
||||
@@ -407,6 +406,8 @@ export function isPlainObject(o: any): o is Record<PropertyKey, unknown> {
|
||||
export function shallowClone(o: any): any {
|
||||
if (isPlainObject(o)) return { ...o };
|
||||
if (Array.isArray(o)) return [...o];
|
||||
if (o instanceof Map) return new Map(o);
|
||||
if (o instanceof Set) return new Set(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -475,8 +476,15 @@ export const getParsedType = (data: any): ParsedTypes => {
|
||||
}
|
||||
};
|
||||
|
||||
export const propertyKeyTypes: Set<string> = new Set(["string", "number", "symbol"]);
|
||||
export const primitiveTypes: Set<string> = new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
|
||||
export const propertyKeyTypes: Set<string> = /* @__PURE__*/ new Set(["string", "number", "symbol"]);
|
||||
export const primitiveTypes: Set<string> = /* @__PURE__*/ new Set([
|
||||
"string",
|
||||
"number",
|
||||
"bigint",
|
||||
"boolean",
|
||||
"symbol",
|
||||
"undefined",
|
||||
]);
|
||||
export function escapeRegex(str: string): string {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
@@ -691,6 +699,9 @@ export function safeExtend(schema: schemas.$ZodObject, shape: schemas.$ZodShape)
|
||||
}
|
||||
|
||||
export function merge(a: schemas.$ZodObject, b: schemas.$ZodObject): any {
|
||||
if (a._zod.def.checks?.length) {
|
||||
throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");
|
||||
}
|
||||
const def = mergeDefs(a._zod.def, {
|
||||
get shape() {
|
||||
const _shape = { ...a._zod.def.shape, ...b._zod.def.shape };
|
||||
@@ -700,7 +711,7 @@ export function merge(a: schemas.$ZodObject, b: schemas.$ZodObject): any {
|
||||
get catchall() {
|
||||
return b._zod.def.catchall;
|
||||
},
|
||||
checks: [], // delete existing checks
|
||||
checks: b._zod.def.checks ?? [],
|
||||
});
|
||||
|
||||
return clone(a, def) as any;
|
||||
@@ -811,6 +822,18 @@ export function aborted(x: schemas.ParsePayload, startIndex = 0): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks for explicit abort (continue === false), as opposed to implicit abort (continue === undefined).
|
||||
// Used to respect `abort: true` in .refine() even for checks that have a `when` function.
|
||||
export function explicitlyAborted(x: schemas.ParsePayload, startIndex = 0): boolean {
|
||||
if (x.aborted === true) return true;
|
||||
for (let i = startIndex; i < x.issues.length; i++) {
|
||||
if (x.issues[i]?.continue === false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function prefixIssues(path: PropertyKey, issues: errors.$ZodRawIssue[]): errors.$ZodRawIssue[] {
|
||||
return issues.map((iss) => {
|
||||
(iss as any).path ??= [];
|
||||
@@ -828,27 +851,21 @@ export function finalizeIssue(
|
||||
ctx: schemas.ParseContextInternal | undefined,
|
||||
config: $ZodConfig
|
||||
): errors.$ZodIssue {
|
||||
const full = { ...iss, path: iss.path ?? [] } as errors.$ZodIssue;
|
||||
|
||||
// for backwards compatibility
|
||||
if (!iss.message) {
|
||||
const message =
|
||||
unwrapMessage(iss.inst?._zod.def?.error?.(iss as never)) ??
|
||||
const message = iss.message
|
||||
? iss.message
|
||||
: (unwrapMessage(iss.inst?._zod.def?.error?.(iss as never)) ??
|
||||
unwrapMessage(ctx?.error?.(iss as never)) ??
|
||||
unwrapMessage(config.customError?.(iss)) ??
|
||||
unwrapMessage(config.localeError?.(iss)) ??
|
||||
"Invalid input";
|
||||
(full as any).message = message;
|
||||
}
|
||||
"Invalid input");
|
||||
|
||||
// delete (full as any).def;
|
||||
delete (full as any).inst;
|
||||
delete (full as any).continue;
|
||||
if (!ctx?.reportInput) {
|
||||
delete (full as any).input;
|
||||
const { inst: _inst, continue: _continue, input: _input, ...rest } = iss as any;
|
||||
rest.path ??= [];
|
||||
rest.message = message;
|
||||
if (ctx?.reportInput) {
|
||||
rest.input = _input;
|
||||
}
|
||||
|
||||
return full;
|
||||
return rest;
|
||||
}
|
||||
|
||||
export function getSizableOrigin(input: any): "set" | "map" | "file" | "unknown" {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
export const version = {
|
||||
major: 4,
|
||||
minor: 3,
|
||||
patch: 6 as number,
|
||||
minor: 4,
|
||||
patch: 3 as number,
|
||||
} as const;
|
||||
|
||||
+4
@@ -103,6 +103,10 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
case "invalid_key":
|
||||
return `Invalid key in ${issue.origin}`;
|
||||
case "invalid_union":
|
||||
if (issue.options && Array.isArray(issue.options) && issue.options.length > 0) {
|
||||
const opts = issue.options.map((o) => `'${o}'`).join(" | ");
|
||||
return `Invalid discriminator value. Expected ${opts}`;
|
||||
}
|
||||
return "Invalid input";
|
||||
case "invalid_element":
|
||||
return `Invalid value in ${issue.origin}`;
|
||||
|
||||
+24
-8
@@ -50,9 +50,27 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
const TypeDictionary: {
|
||||
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
|
||||
} = {
|
||||
nan: "NaN",
|
||||
string: "chaîne",
|
||||
number: "nombre",
|
||||
int: "entier",
|
||||
boolean: "booléen",
|
||||
bigint: "grand entier",
|
||||
symbol: "symbole",
|
||||
undefined: "indéfini",
|
||||
null: "null",
|
||||
never: "jamais",
|
||||
void: "vide",
|
||||
date: "date",
|
||||
array: "tableau",
|
||||
object: "objet",
|
||||
tuple: "tuple",
|
||||
record: "enregistrement",
|
||||
map: "carte",
|
||||
set: "ensemble",
|
||||
file: "fichier",
|
||||
nonoptional: "non-optionnel",
|
||||
nan: "NaN",
|
||||
function: "fonction",
|
||||
};
|
||||
|
||||
return (issue) => {
|
||||
@@ -73,17 +91,15 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `Trop grand : ${issue.origin ?? "valeur"} doit ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "élément(s)"}`;
|
||||
return `Trop grand : ${issue.origin ?? "valeur"} doit être ${adj}${issue.maximum.toString()}`;
|
||||
return `Trop grand : ${TypeDictionary[issue.origin] ?? "valeur"} doit ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "élément(s)"}`;
|
||||
return `Trop grand : ${TypeDictionary[issue.origin] ?? "valeur"} doit être ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `Trop petit : ${issue.origin} doit ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
|
||||
return `Trop petit : ${issue.origin} doit être ${adj}${issue.minimum.toString()}`;
|
||||
if (sizing)
|
||||
return `Trop petit : ${TypeDictionary[issue.origin] ?? "valeur"} doit ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
return `Trop petit : ${TypeDictionary[issue.origin] ?? "valeur"} doit être ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue as errors.$ZodStringFormatIssues;
|
||||
|
||||
+3
@@ -6,6 +6,7 @@ export { default as ca } from "./ca.js";
|
||||
export { default as cs } from "./cs.js";
|
||||
export { default as da } from "./da.js";
|
||||
export { default as de } from "./de.js";
|
||||
export { default as el } from "./el.js";
|
||||
export { default as en } from "./en.js";
|
||||
export { default as eo } from "./eo.js";
|
||||
export { default as es } from "./es.js";
|
||||
@@ -14,6 +15,7 @@ export { default as fi } from "./fi.js";
|
||||
export { default as fr } from "./fr.js";
|
||||
export { default as frCA } from "./fr-CA.js";
|
||||
export { default as he } from "./he.js";
|
||||
export { default as hr } from "./hr.js";
|
||||
export { default as hu } from "./hu.js";
|
||||
export { default as hy } from "./hy.js";
|
||||
export { default as id } from "./id.js";
|
||||
@@ -33,6 +35,7 @@ export { default as ota } from "./ota.js";
|
||||
export { default as ps } from "./ps.js";
|
||||
export { default as pl } from "./pl.js";
|
||||
export { default as pt } from "./pt.js";
|
||||
export { default as ro } from "./ro.js";
|
||||
export { default as ru } from "./ru.js";
|
||||
export { default as sl } from "./sl.js";
|
||||
export { default as sv } from "./sv.js";
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
if (_issue.format === "ends_with") return `Stringa non valida: deve terminare con "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes") return `Stringa non valida: deve includere "${_issue.includes}"`;
|
||||
if (_issue.format === "regex") return `Stringa non valida: deve corrispondere al pattern ${_issue.pattern}`;
|
||||
return `Invalid ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
return `Input non valido: ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Numero non valido: deve essere un multiplo di ${issue.divisor}`;
|
||||
|
||||
+8
-8
@@ -39,9 +39,9 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
ipv6: "IPv6 მისამართი",
|
||||
cidrv4: "IPv4 დიაპაზონი",
|
||||
cidrv6: "IPv6 დიაპაზონი",
|
||||
base64: "base64-კოდირებული სტრინგი",
|
||||
base64url: "base64url-კოდირებული სტრინგი",
|
||||
json_string: "JSON სტრინგი",
|
||||
base64: "base64-კოდირებული ველი",
|
||||
base64url: "base64url-კოდირებული ველი",
|
||||
json_string: "JSON ველი",
|
||||
e164: "E.164 ნომერი",
|
||||
jwt: "JWT",
|
||||
template_literal: "შეყვანა",
|
||||
@@ -52,7 +52,7 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
} = {
|
||||
nan: "NaN",
|
||||
number: "რიცხვი",
|
||||
string: "სტრინგი",
|
||||
string: "ველი",
|
||||
boolean: "ბულეანი",
|
||||
function: "ფუნქცია",
|
||||
array: "მასივი",
|
||||
@@ -93,11 +93,11 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
case "invalid_format": {
|
||||
const _issue = issue as errors.$ZodStringFormatIssues;
|
||||
if (_issue.format === "starts_with") {
|
||||
return `არასწორი სტრინგი: უნდა იწყებოდეს "${_issue.prefix}"-ით`;
|
||||
return `არასწორი ველი: უნდა იწყებოდეს "${_issue.prefix}"-ით`;
|
||||
}
|
||||
if (_issue.format === "ends_with") return `არასწორი სტრინგი: უნდა მთავრდებოდეს "${_issue.suffix}"-ით`;
|
||||
if (_issue.format === "includes") return `არასწორი სტრინგი: უნდა შეიცავდეს "${_issue.includes}"-ს`;
|
||||
if (_issue.format === "regex") return `არასწორი სტრინგი: უნდა შეესაბამებოდეს შაბლონს ${_issue.pattern}`;
|
||||
if (_issue.format === "ends_with") return `არასწორი ველი: უნდა მთავრდებოდეს "${_issue.suffix}"-ით`;
|
||||
if (_issue.format === "includes") return `არასწორი ველი: უნდა შეიცავდეს "${_issue.includes}"-ს`;
|
||||
if (_issue.format === "regex") return `არასწორი ველი: უნდა შეესაბამებოდეს შაბლონს ${_issue.pattern}`;
|
||||
return `არასწორი ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
|
||||
+1
@@ -8,6 +8,7 @@ const error: () => errors.$ZodErrorMap = () => {
|
||||
file: { unit: "bayt", verb: "bo‘lishi kerak" },
|
||||
array: { unit: "element", verb: "bo‘lishi kerak" },
|
||||
set: { unit: "element", verb: "bo‘lishi kerak" },
|
||||
map: { unit: "yozuv", verb: "bo‘lishi kerak" },
|
||||
};
|
||||
|
||||
function getSizing(origin: string): { unit: string; verb: string } | null {
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ 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,
|
||||
|
||||
+56
-25
@@ -60,7 +60,11 @@ export const ZodMiniType: core.$constructor<ZodMiniType> = /*@__PURE__*/ core.$c
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...checks.map((ch) =>
|
||||
typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch
|
||||
typeof ch === "function"
|
||||
? {
|
||||
_zod: { check: ch, def: { check: "custom" }, onattach: [] },
|
||||
}
|
||||
: ch
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -200,7 +204,7 @@ export function url(params?: string | core.$ZodURLParams): ZodMiniURL {
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function httpUrl(params?: string | Omit<core.$ZodURLParams, "protocol" | "hostname">): ZodMiniURL {
|
||||
return core._url(ZodMiniURL, {
|
||||
protocol: /^https?$/,
|
||||
protocol: core.regexes.httpProtocol,
|
||||
hostname: core.regexes.domain,
|
||||
...util.normalizeParams(params),
|
||||
});
|
||||
@@ -241,9 +245,19 @@ export function nanoid(params?: string | core.$ZodNanoIDParams): ZodMiniNanoID {
|
||||
}
|
||||
|
||||
// ZodMiniCUID
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodMiniCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface ZodMiniCUID extends _ZodMiniString<core.$ZodCUIDInternals> {
|
||||
// _zod: core.$ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodMiniCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const ZodMiniCUID: core.$constructor<ZodMiniCUID> = /*@__PURE__*/ core.$constructor(
|
||||
"ZodMiniCUID",
|
||||
(inst, def) => {
|
||||
@@ -252,6 +266,13 @@ export const ZodMiniCUID: core.$constructor<ZodMiniCUID> = /*@__PURE__*/ core.$c
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function cuid(params?: string | core.$ZodCUIDParams): ZodMiniCUID {
|
||||
return core._cuid(ZodMiniCUID, params);
|
||||
@@ -833,7 +854,7 @@ export const ZodMiniObject: core.$constructor<ZodMiniObject> = /*@__PURE__*/ cor
|
||||
export function object<T extends core.$ZodLooseShape = Record<never, SomeType>>(
|
||||
shape?: T,
|
||||
params?: string | core.$ZodObjectParams
|
||||
): ZodMiniObject<T, core.$strip> {
|
||||
): ZodMiniObject<util.Writeable<T>, core.$strip> {
|
||||
const def: core.$ZodObjectDef = {
|
||||
type: "object",
|
||||
shape: shape ?? {},
|
||||
@@ -847,7 +868,7 @@ export function object<T extends core.$ZodLooseShape = Record<never, SomeType>>(
|
||||
export function strictObject<T extends core.$ZodLooseShape>(
|
||||
shape: T,
|
||||
params?: string | core.$ZodObjectParams
|
||||
): ZodMiniObject<T, core.$strict> {
|
||||
): ZodMiniObject<util.Writeable<T>, core.$strict> {
|
||||
return new ZodMiniObject({
|
||||
type: "object",
|
||||
shape,
|
||||
@@ -861,7 +882,7 @@ export function strictObject<T extends core.$ZodLooseShape>(
|
||||
export function looseObject<T extends core.$ZodLooseShape>(
|
||||
shape: T,
|
||||
params?: string | core.$ZodObjectParams
|
||||
): ZodMiniObject<T, core.$loose> {
|
||||
): ZodMiniObject<util.Writeable<T>, core.$loose> {
|
||||
return new ZodMiniObject({
|
||||
type: "object",
|
||||
shape,
|
||||
@@ -875,7 +896,7 @@ export function looseObject<T extends core.$ZodLooseShape>(
|
||||
export function extend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(
|
||||
schema: T,
|
||||
shape: U
|
||||
): ZodMiniObject<util.Extend<T["shape"], U>, T["_zod"]["config"]> {
|
||||
): ZodMiniObject<util.Extend<T["shape"], util.Writeable<U>>, T["_zod"]["config"]> {
|
||||
return util.extend(schema, shape);
|
||||
}
|
||||
|
||||
@@ -893,7 +914,7 @@ export type SafeExtendShape<Base extends core.$ZodShape, Ext extends core.$ZodLo
|
||||
export function safeExtend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(
|
||||
schema: T,
|
||||
shape: SafeExtendShape<T["shape"], U>
|
||||
): ZodMiniObject<util.Extend<T["shape"], U>, T["_zod"]["config"]> {
|
||||
): ZodMiniObject<util.Extend<T["shape"], util.Writeable<U>>, T["_zod"]["config"]> {
|
||||
return util.safeExtend(schema, shape as any);
|
||||
}
|
||||
|
||||
@@ -930,7 +951,7 @@ export function partial<T extends ZodMiniObject>(
|
||||
schema: T
|
||||
): ZodMiniObject<
|
||||
{
|
||||
[k in keyof T["shape"]]: ZodMiniOptional<T["shape"][k]>;
|
||||
-readonly [k in keyof T["shape"]]: ZodMiniOptional<T["shape"][k]>;
|
||||
},
|
||||
T["_zod"]["config"]
|
||||
>;
|
||||
@@ -940,7 +961,7 @@ export function partial<T extends ZodMiniObject, M extends util.Mask<keyof T["sh
|
||||
mask: M & Record<Exclude<keyof M, keyof T["shape"]>, never>
|
||||
): ZodMiniObject<
|
||||
{
|
||||
[k in keyof T["shape"]]: k extends keyof M ? ZodMiniOptional<T["shape"][k]> : T["shape"][k];
|
||||
-readonly [k in keyof T["shape"]]: k extends keyof M ? ZodMiniOptional<T["shape"][k]> : T["shape"][k];
|
||||
},
|
||||
T["_zod"]["config"]
|
||||
>;
|
||||
@@ -965,7 +986,7 @@ export function required<T extends ZodMiniObject>(
|
||||
schema: T
|
||||
): ZodMiniObject<
|
||||
{
|
||||
[k in keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
|
||||
-readonly [k in keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
|
||||
},
|
||||
T["_zod"]["config"]
|
||||
>;
|
||||
@@ -1062,7 +1083,7 @@ export const ZodMiniDiscriminatedUnion: core.$constructor<ZodMiniDiscriminatedUn
|
||||
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function discriminatedUnion<
|
||||
Types extends readonly [core.$ZodTypeDiscriminable, ...core.$ZodTypeDiscriminable[]],
|
||||
Types extends readonly [core.$ZodTypeDiscriminable<Disc>, ...core.$ZodTypeDiscriminable<Disc>[]],
|
||||
Disc extends string,
|
||||
>(
|
||||
discriminator: Disc,
|
||||
@@ -1162,6 +1183,15 @@ export function record<Key extends core.$ZodRecordKey, Value extends SomeType>(
|
||||
valueType: Value,
|
||||
params?: string | core.$ZodRecordParams
|
||||
): ZodMiniRecord<Key, Value> {
|
||||
// v3-compat: z.record(valueType, params?) — defaults keyType to z.string()
|
||||
if (!valueType || !(valueType as any)._zod) {
|
||||
return new ZodMiniRecord({
|
||||
type: "record",
|
||||
keyType: string() as any,
|
||||
valueType: keyType as any as core.$ZodType,
|
||||
...util.normalizeParams(valueType as string | core.$ZodRecordParams | undefined),
|
||||
}) as any;
|
||||
}
|
||||
return new ZodMiniRecord({
|
||||
type: "record",
|
||||
keyType,
|
||||
@@ -1625,14 +1655,17 @@ export function codec<const A extends SomeType, B extends core.SomeType = core.$
|
||||
}) as any;
|
||||
}
|
||||
|
||||
// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */
|
||||
// export function preprocess<A, U extends core.$ZodType>(
|
||||
// fn: (arg: unknown, ctx: core.ParsePayload) => A,
|
||||
// schema: U,
|
||||
// params?: ZodPreprocessParams
|
||||
// ): ZodPipe<ZodTransform<A, unknown>, U> {
|
||||
// return pipe(transform(fn as any, params), schema as any, params);
|
||||
// }
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function invertCodec<A extends SomeType, B extends SomeType>(codec: ZodMiniCodec<A, B>): ZodMiniCodec<B, A> {
|
||||
const def = codec._zod.def;
|
||||
return new ZodMiniCodec({
|
||||
type: "pipe",
|
||||
in: def.out as any,
|
||||
out: def.in as any,
|
||||
transform: def.reverseTransform as any,
|
||||
reverseTransform: def.transform as any,
|
||||
}) as any;
|
||||
}
|
||||
|
||||
// ZodMiniReadonly
|
||||
export interface ZodMiniReadonly<T extends SomeType = core.$ZodType>
|
||||
@@ -1770,9 +1803,10 @@ export function refine<T>(
|
||||
// superRefine
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function superRefine<T>(
|
||||
fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>
|
||||
fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>,
|
||||
params?: core.$ZodSuperRefineParams
|
||||
): core.$ZodCheck<T> {
|
||||
return core._superRefine(fn);
|
||||
return core._superRefine(fn, params);
|
||||
}
|
||||
|
||||
// Re-export describe and meta from core
|
||||
@@ -1897,10 +1931,7 @@ export function _function<const Out extends core.$ZodFunctionOut = core.$ZodFunc
|
||||
export function _function<
|
||||
In extends core.$ZodFunctionIn = core.$ZodFunctionIn,
|
||||
Out extends core.$ZodFunctionOut = core.$ZodFunctionOut,
|
||||
>(params?: {
|
||||
input: In;
|
||||
output: Out;
|
||||
}): ZodMiniFunction<In, Out>;
|
||||
>(params?: { input: In; output: Out }): ZodMiniFunction<In, Out>;
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _function(params?: {
|
||||
output?: core.$ZodFunctionOut;
|
||||
|
||||
+19
@@ -527,3 +527,22 @@ test("codec type enforcement - complex types", () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
+32
-2
@@ -228,6 +228,30 @@ test("z.union", () => {
|
||||
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 });
|
||||
@@ -247,7 +271,7 @@ test("z.tuple", () => {
|
||||
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[]]>();
|
||||
expectTypeOf<b>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
const datas = [
|
||||
["hello", 123],
|
||||
["hello", 123, "world"],
|
||||
@@ -265,7 +289,7 @@ test("z.tuple", () => {
|
||||
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[]]>();
|
||||
expectTypeOf<c>().toEqualTypeOf<[string, number, (string | undefined)?, ...boolean[]]>();
|
||||
});
|
||||
|
||||
test("z.record", () => {
|
||||
@@ -319,6 +343,12 @@ test("z.record", () => {
|
||||
[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", () => {
|
||||
|
||||
+9
-9
@@ -17,7 +17,7 @@ test("z.object", () => {
|
||||
expectTypeOf<a>().toEqualTypeOf<{
|
||||
name: string;
|
||||
age: number;
|
||||
points?: number;
|
||||
points?: number | undefined;
|
||||
"test?": boolean;
|
||||
}>();
|
||||
expect(z.parse(a, { name: "john", age: 30, "test?": true })).toEqual({
|
||||
@@ -109,7 +109,7 @@ test("z.extend", () => {
|
||||
expectTypeOf<ExtendedUser>().toEqualTypeOf<{
|
||||
name: string;
|
||||
age: number;
|
||||
email?: string;
|
||||
email?: string | undefined;
|
||||
isAdmin: boolean;
|
||||
}>();
|
||||
expect(extendedSchema).toBeDefined();
|
||||
@@ -120,7 +120,7 @@ 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 }>();
|
||||
expectTypeOf<Extended>().toEqualTypeOf<{ name: string; age: number; email?: string | undefined }>();
|
||||
// @ts-expect-error
|
||||
z.safeExtend(userSchema, { name: z.number() });
|
||||
});
|
||||
@@ -128,7 +128,7 @@ test("z.safeExtend", () => {
|
||||
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 }>();
|
||||
expectTypeOf<PickedUser>().toEqualTypeOf<{ name: string; email?: string | undefined }>();
|
||||
expect(pickedSchema).toBeDefined();
|
||||
expect(z.safeParse(pickedSchema, { name: "John", email: "john@example.com" }).success).toBe(true);
|
||||
});
|
||||
@@ -149,9 +149,9 @@ test("z.partial", () => {
|
||||
const partialSchema = z.partial(userSchema);
|
||||
type PartialUser = z.infer<typeof partialSchema>;
|
||||
expectTypeOf<PartialUser>().toEqualTypeOf<{
|
||||
name?: string;
|
||||
age?: number;
|
||||
email?: string;
|
||||
name?: string | undefined;
|
||||
age?: number | undefined;
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
expect(z.safeParse(partialSchema, { name: "John" }).success).toBe(true);
|
||||
});
|
||||
@@ -160,9 +160,9 @@ test("z.partial with mask", () => {
|
||||
const partialSchemaWithMask = z.partial(userSchema, { name: true });
|
||||
type PartialUserWithMask = z.infer<typeof partialSchemaWithMask>;
|
||||
expectTypeOf<PartialUserWithMask>().toEqualTypeOf<{
|
||||
name?: string;
|
||||
name?: string | undefined;
|
||||
age: number;
|
||||
email?: string;
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
expect(z.safeParse(partialSchemaWithMask, { age: 30 }).success).toBe(true);
|
||||
expect(z.safeParse(partialSchemaWithMask, { name: "John" }).success).toBe(false);
|
||||
|
||||
+51
-1
@@ -33,7 +33,7 @@ test("recursion with z.lazy", () => {
|
||||
type Category = z.infer<typeof Category>;
|
||||
interface _Category {
|
||||
name: string;
|
||||
subcategories?: _Category[];
|
||||
subcategories?: _Category[] | undefined;
|
||||
}
|
||||
expectTypeOf<Category>().toEqualTypeOf<_Category>();
|
||||
});
|
||||
@@ -273,3 +273,53 @@ test("recursion compatibility", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
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>;
|
||||
}>();
|
||||
});
|
||||
|
||||
+5
@@ -282,6 +282,11 @@ test("z.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();
|
||||
});
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ const initializer = (inst, issues) => {
|
||||
// },
|
||||
// });
|
||||
};
|
||||
export const ZodError = core.$constructor("ZodError", initializer);
|
||||
export const ZodRealError = core.$constructor("ZodError", initializer, {
|
||||
export const ZodError = /*@__PURE__*/ core.$constructor("ZodError", initializer);
|
||||
export const ZodRealError = /*@__PURE__*/ core.$constructor("ZodError", initializer, {
|
||||
Parent: Error,
|
||||
});
|
||||
// /** @deprecated Use `z.core.$ZodErrorMapCtx` instead. */
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ export * from "./errors.cjs";
|
||||
export * from "./parse.cjs";
|
||||
export * from "./compat.cjs";
|
||||
export type { infer, output, input } from "../core/index.cjs";
|
||||
export type { JSONType } from "../core/util.cjs";
|
||||
export { globalRegistry, type GlobalMeta, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, TimePrecision, util, NEVER, } from "../core/index.cjs";
|
||||
export { toJSONSchema } from "../core/json-schema-processors.cjs";
|
||||
export { fromJSONSchema } from "./from-json-schema.cjs";
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ export * from "./errors.js";
|
||||
export * from "./parse.js";
|
||||
export * from "./compat.js";
|
||||
export type { infer, output, input } from "../core/index.js";
|
||||
export type { JSONType } from "../core/util.js";
|
||||
export { globalRegistry, type GlobalMeta, 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 { fromJSONSchema } from "./from-json-schema.js";
|
||||
|
||||
+31
-16
@@ -35,7 +35,7 @@ const z = {
|
||||
iso: _iso,
|
||||
};
|
||||
// Keys that are recognized and handled by the conversion logic
|
||||
const RECOGNIZED_KEYS = new Set([
|
||||
const RECOGNIZED_KEYS = /*@__PURE__*/ new Set([
|
||||
// Schema identification
|
||||
"$schema",
|
||||
"$ref",
|
||||
@@ -511,13 +511,6 @@ function convertBaseSchema(schema, ctx) {
|
||||
default:
|
||||
throw new Error(`Unsupported type: ${type}`);
|
||||
}
|
||||
// Apply metadata
|
||||
if (schema.description) {
|
||||
zodSchema = zodSchema.describe(schema.description);
|
||||
}
|
||||
if (schema.default !== undefined) {
|
||||
zodSchema = zodSchema.default(schema.default);
|
||||
}
|
||||
return zodSchema;
|
||||
}
|
||||
function convertSchema(schema, ctx) {
|
||||
@@ -562,23 +555,28 @@ function convertSchema(schema, ctx) {
|
||||
if (schema.readOnly === true) {
|
||||
baseSchema = z.readonly(baseSchema);
|
||||
}
|
||||
// Collect metadata: core schema keywords and unrecognized keys
|
||||
// Apply `default` so it wraps the fully-composed schema. This ensures
|
||||
// `parse(undefined) -> default` works regardless of which branch of
|
||||
// `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.).
|
||||
if (schema.default !== undefined) {
|
||||
baseSchema = baseSchema.default(schema.default);
|
||||
}
|
||||
// Collect non-description annotation metadata into the user-supplied
|
||||
// registry. Description is handled separately below via `.describe()` to
|
||||
// preserve the contract that `schema.description` reads from globalRegistry.
|
||||
const extraMeta = {};
|
||||
// Core schema keywords that should be captured as metadata
|
||||
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
||||
for (const key of coreMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
// Content keywords - store as metadata
|
||||
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
||||
for (const key of contentMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
// Unrecognized keys (custom metadata)
|
||||
for (const key of Object.keys(schema)) {
|
||||
if (!RECOGNIZED_KEYS.has(key)) {
|
||||
extraMeta[key] = schema[key];
|
||||
@@ -587,6 +585,12 @@ function convertSchema(schema, ctx) {
|
||||
if (Object.keys(extraMeta).length > 0) {
|
||||
ctx.registry.add(baseSchema, extraMeta);
|
||||
}
|
||||
// Apply description last. `.describe()` clones the schema and sets
|
||||
// `_zod.parent` on the clone, so registry lookups on the returned reference
|
||||
// still resolve `extraMeta` via parent inheritance.
|
||||
if (schema.description) {
|
||||
baseSchema = baseSchema.describe(schema.description);
|
||||
}
|
||||
return baseSchema;
|
||||
}
|
||||
/**
|
||||
@@ -596,15 +600,26 @@ function fromJSONSchema(schema, params) {
|
||||
if (typeof schema === "boolean") {
|
||||
return schema ? z.any() : z.never();
|
||||
}
|
||||
const version = detectVersion(schema, params?.defaultTarget);
|
||||
const defs = (schema.$defs || schema.definitions || {});
|
||||
// Normalize input via a JSON round-trip. This guarantees the converter
|
||||
// walks a plain, finite, JSON-valid object graph: cyclic inputs fail here,
|
||||
// getter/Proxy-based properties are materialized into static values, and
|
||||
// class instances collapse to plain objects.
|
||||
let normalized;
|
||||
try {
|
||||
normalized = JSON.parse(JSON.stringify(schema));
|
||||
}
|
||||
catch {
|
||||
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
||||
}
|
||||
const version = detectVersion(normalized, params?.defaultTarget);
|
||||
const defs = (normalized.$defs || normalized.definitions || {});
|
||||
const ctx = {
|
||||
version,
|
||||
defs,
|
||||
refs: new Map(),
|
||||
processing: new Set(),
|
||||
rootSchema: schema,
|
||||
rootSchema: normalized,
|
||||
registry: params?.registry ?? registries_js_1.globalRegistry,
|
||||
};
|
||||
return convertSchema(schema, ctx);
|
||||
return convertSchema(normalized, ctx);
|
||||
}
|
||||
|
||||
+31
-16
@@ -9,7 +9,7 @@ const z = {
|
||||
iso: _iso,
|
||||
};
|
||||
// Keys that are recognized and handled by the conversion logic
|
||||
const RECOGNIZED_KEYS = new Set([
|
||||
const RECOGNIZED_KEYS = /*@__PURE__*/ new Set([
|
||||
// Schema identification
|
||||
"$schema",
|
||||
"$ref",
|
||||
@@ -485,13 +485,6 @@ function convertBaseSchema(schema, ctx) {
|
||||
default:
|
||||
throw new Error(`Unsupported type: ${type}`);
|
||||
}
|
||||
// Apply metadata
|
||||
if (schema.description) {
|
||||
zodSchema = zodSchema.describe(schema.description);
|
||||
}
|
||||
if (schema.default !== undefined) {
|
||||
zodSchema = zodSchema.default(schema.default);
|
||||
}
|
||||
return zodSchema;
|
||||
}
|
||||
function convertSchema(schema, ctx) {
|
||||
@@ -536,23 +529,28 @@ function convertSchema(schema, ctx) {
|
||||
if (schema.readOnly === true) {
|
||||
baseSchema = z.readonly(baseSchema);
|
||||
}
|
||||
// Collect metadata: core schema keywords and unrecognized keys
|
||||
// Apply `default` so it wraps the fully-composed schema. This ensures
|
||||
// `parse(undefined) -> default` works regardless of which branch of
|
||||
// `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.).
|
||||
if (schema.default !== undefined) {
|
||||
baseSchema = baseSchema.default(schema.default);
|
||||
}
|
||||
// Collect non-description annotation metadata into the user-supplied
|
||||
// registry. Description is handled separately below via `.describe()` to
|
||||
// preserve the contract that `schema.description` reads from globalRegistry.
|
||||
const extraMeta = {};
|
||||
// Core schema keywords that should be captured as metadata
|
||||
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
||||
for (const key of coreMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
// Content keywords - store as metadata
|
||||
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
||||
for (const key of contentMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
// Unrecognized keys (custom metadata)
|
||||
for (const key of Object.keys(schema)) {
|
||||
if (!RECOGNIZED_KEYS.has(key)) {
|
||||
extraMeta[key] = schema[key];
|
||||
@@ -561,6 +559,12 @@ function convertSchema(schema, ctx) {
|
||||
if (Object.keys(extraMeta).length > 0) {
|
||||
ctx.registry.add(baseSchema, extraMeta);
|
||||
}
|
||||
// Apply description last. `.describe()` clones the schema and sets
|
||||
// `_zod.parent` on the clone, so registry lookups on the returned reference
|
||||
// still resolve `extraMeta` via parent inheritance.
|
||||
if (schema.description) {
|
||||
baseSchema = baseSchema.describe(schema.description);
|
||||
}
|
||||
return baseSchema;
|
||||
}
|
||||
/**
|
||||
@@ -570,15 +574,26 @@ export function fromJSONSchema(schema, params) {
|
||||
if (typeof schema === "boolean") {
|
||||
return schema ? z.any() : z.never();
|
||||
}
|
||||
const version = detectVersion(schema, params?.defaultTarget);
|
||||
const defs = (schema.$defs || schema.definitions || {});
|
||||
// Normalize input via a JSON round-trip. This guarantees the converter
|
||||
// walks a plain, finite, JSON-valid object graph: cyclic inputs fail here,
|
||||
// getter/Proxy-based properties are materialized into static values, and
|
||||
// class instances collapse to plain objects.
|
||||
let normalized;
|
||||
try {
|
||||
normalized = JSON.parse(JSON.stringify(schema));
|
||||
}
|
||||
catch {
|
||||
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
||||
}
|
||||
const version = detectVersion(normalized, params?.defaultTarget);
|
||||
const defs = (normalized.$defs || normalized.definitions || {});
|
||||
const ctx = {
|
||||
version,
|
||||
defs,
|
||||
refs: new Map(),
|
||||
processing: new Set(),
|
||||
rootSchema: schema,
|
||||
rootSchema: normalized,
|
||||
registry: params?.registry ?? globalRegistry,
|
||||
};
|
||||
return convertSchema(schema, ctx);
|
||||
return convertSchema(normalized, ctx);
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+358
-119
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ZodLiteral = exports.ZodEnum = exports.ZodSet = exports.ZodMap = exports.ZodRecord = exports.ZodTuple = exports.ZodIntersection = exports.ZodDiscriminatedUnion = exports.ZodXor = exports.ZodUnion = exports.ZodObject = exports.ZodArray = exports.ZodDate = exports.ZodVoid = exports.ZodNever = exports.ZodUnknown = exports.ZodAny = exports.ZodNull = exports.ZodUndefined = exports.ZodSymbol = exports.ZodBigIntFormat = exports.ZodBigInt = exports.ZodBoolean = exports.ZodNumberFormat = exports.ZodNumber = exports.ZodCustomStringFormat = exports.ZodJWT = exports.ZodE164 = exports.ZodBase64URL = exports.ZodBase64 = exports.ZodCIDRv6 = exports.ZodCIDRv4 = exports.ZodIPv6 = exports.ZodMAC = exports.ZodIPv4 = exports.ZodKSUID = exports.ZodXID = exports.ZodULID = exports.ZodCUID2 = exports.ZodCUID = exports.ZodNanoID = exports.ZodEmoji = exports.ZodURL = exports.ZodUUID = exports.ZodGUID = exports.ZodEmail = exports.ZodStringFormat = exports.ZodString = exports._ZodString = exports.ZodType = void 0;
|
||||
exports.stringbool = exports.meta = exports.describe = exports.ZodCustom = exports.ZodFunction = exports.ZodPromise = exports.ZodLazy = exports.ZodTemplateLiteral = exports.ZodReadonly = exports.ZodCodec = exports.ZodPipe = exports.ZodNaN = exports.ZodCatch = exports.ZodSuccess = exports.ZodNonOptional = exports.ZodPrefault = exports.ZodDefault = exports.ZodNullable = exports.ZodExactOptional = exports.ZodOptional = exports.ZodTransform = exports.ZodFile = void 0;
|
||||
exports.stringbool = exports.meta = exports.describe = exports.ZodCustom = exports.ZodFunction = exports.ZodPromise = exports.ZodLazy = exports.ZodTemplateLiteral = exports.ZodReadonly = exports.ZodPreprocess = exports.ZodCodec = exports.ZodPipe = exports.ZodNaN = exports.ZodCatch = exports.ZodSuccess = exports.ZodNonOptional = exports.ZodPrefault = exports.ZodDefault = exports.ZodNullable = exports.ZodExactOptional = exports.ZodOptional = exports.ZodTransform = exports.ZodFile = void 0;
|
||||
exports.string = string;
|
||||
exports.email = email;
|
||||
exports.guid = guid;
|
||||
@@ -104,6 +104,7 @@ exports.catch = _catch;
|
||||
exports.nan = nan;
|
||||
exports.pipe = pipe;
|
||||
exports.codec = codec;
|
||||
exports.invertCodec = invertCodec;
|
||||
exports.readonly = readonly;
|
||||
exports.templateLiteral = templateLiteral;
|
||||
exports.lazy = lazy;
|
||||
@@ -126,6 +127,54 @@ const to_json_schema_js_1 = require("../core/to-json-schema.cjs");
|
||||
const checks = __importStar(require("./checks.cjs"));
|
||||
const iso = __importStar(require("./iso.cjs"));
|
||||
const parse = __importStar(require("./parse.cjs"));
|
||||
// Lazy-bind builder methods.
|
||||
//
|
||||
// Builder methods (`.optional`, `.array`, `.refine`, ...) live as
|
||||
// non-enumerable getters on each concrete schema constructor's
|
||||
// prototype. On first access from an instance the getter allocates
|
||||
// `fn.bind(this)` and caches it as an own property on that instance,
|
||||
// so detached usage (`const m = schema.optional; m()`) still works
|
||||
// and the per-instance allocation only happens for methods actually
|
||||
// touched.
|
||||
//
|
||||
// One install per (prototype, group), memoized by `_installedGroups`.
|
||||
const _installedGroups = /* @__PURE__ */ new WeakMap();
|
||||
function _installLazyMethods(inst, group, methods) {
|
||||
const proto = Object.getPrototypeOf(inst);
|
||||
let installed = _installedGroups.get(proto);
|
||||
if (!installed) {
|
||||
installed = new Set();
|
||||
_installedGroups.set(proto, installed);
|
||||
}
|
||||
if (installed.has(group))
|
||||
return;
|
||||
installed.add(group);
|
||||
for (const key in methods) {
|
||||
const fn = methods[key];
|
||||
Object.defineProperty(proto, key, {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
get() {
|
||||
const bound = fn.bind(this);
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: bound,
|
||||
});
|
||||
return bound;
|
||||
},
|
||||
set(v) {
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: v,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.ZodType = core.$constructor("ZodType", (inst, def) => {
|
||||
core.$ZodType.init(inst, def);
|
||||
Object.assign(inst["~standard"], {
|
||||
@@ -138,31 +187,16 @@ exports.ZodType = core.$constructor("ZodType", (inst, def) => {
|
||||
inst.def = def;
|
||||
inst.type = def.type;
|
||||
Object.defineProperty(inst, "_def", { value: def });
|
||||
// base methods
|
||||
inst.check = (...checks) => {
|
||||
return inst.clone(index_js_1.util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...checks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch),
|
||||
],
|
||||
}), {
|
||||
parent: true,
|
||||
});
|
||||
};
|
||||
inst.with = inst.check;
|
||||
inst.clone = (def, params) => core.clone(inst, def, params);
|
||||
inst.brand = () => inst;
|
||||
inst.register = ((reg, meta) => {
|
||||
reg.add(inst, meta);
|
||||
return inst;
|
||||
});
|
||||
// parsing
|
||||
// Parse-family is intentionally kept as per-instance closures: these are
|
||||
// the hot path AND the most-detached methods (`arr.map(schema.parse)`,
|
||||
// `const { parse } = schema`, etc.). Eager closures here mean callers pay
|
||||
// ~12 closure allocations per schema but get monomorphic call sites and
|
||||
// detached usage that "just works".
|
||||
inst.parse = (data, params) => parse.parse(inst, data, params, { callee: inst.parse });
|
||||
inst.safeParse = (data, params) => parse.safeParse(inst, data, params);
|
||||
inst.parseAsync = async (data, params) => parse.parseAsync(inst, data, params, { callee: inst.parseAsync });
|
||||
inst.safeParseAsync = async (data, params) => parse.safeParseAsync(inst, data, params);
|
||||
inst.spa = inst.safeParseAsync;
|
||||
// encoding/decoding
|
||||
inst.encode = (data, params) => parse.encode(inst, data, params);
|
||||
inst.decode = (data, params) => parse.decode(inst, data, params);
|
||||
inst.encodeAsync = async (data, params) => parse.encodeAsync(inst, data, params);
|
||||
@@ -171,50 +205,118 @@ exports.ZodType = core.$constructor("ZodType", (inst, def) => {
|
||||
inst.safeDecode = (data, params) => parse.safeDecode(inst, data, params);
|
||||
inst.safeEncodeAsync = async (data, params) => parse.safeEncodeAsync(inst, data, params);
|
||||
inst.safeDecodeAsync = async (data, params) => parse.safeDecodeAsync(inst, data, params);
|
||||
// refinements
|
||||
inst.refine = (check, params) => inst.check(refine(check, params));
|
||||
inst.superRefine = (refinement) => inst.check(superRefine(refinement));
|
||||
inst.overwrite = (fn) => inst.check(checks.overwrite(fn));
|
||||
// wrappers
|
||||
inst.optional = () => optional(inst);
|
||||
inst.exactOptional = () => exactOptional(inst);
|
||||
inst.nullable = () => nullable(inst);
|
||||
inst.nullish = () => optional(nullable(inst));
|
||||
inst.nonoptional = (params) => nonoptional(inst, params);
|
||||
inst.array = () => array(inst);
|
||||
inst.or = (arg) => union([inst, arg]);
|
||||
inst.and = (arg) => intersection(inst, arg);
|
||||
inst.transform = (tx) => pipe(inst, transform(tx));
|
||||
inst.default = (def) => _default(inst, def);
|
||||
inst.prefault = (def) => prefault(inst, def);
|
||||
// inst.coalesce = (def, params) => coalesce(inst, def, params);
|
||||
inst.catch = (params) => _catch(inst, params);
|
||||
inst.pipe = (target) => pipe(inst, target);
|
||||
inst.readonly = () => readonly(inst);
|
||||
// meta
|
||||
inst.describe = (description) => {
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
};
|
||||
// All builder methods are placed on the internal prototype as lazy-bind
|
||||
// getters. On first access per-instance, a bound thunk is allocated and
|
||||
// cached as an own property; subsequent accesses skip the getter. This
|
||||
// means: no per-instance allocation for unused methods, full
|
||||
// detachability preserved (`const m = schema.optional; m()` works), and
|
||||
// shared underlying function references across all instances.
|
||||
_installLazyMethods(inst, "ZodType", {
|
||||
check(...chks) {
|
||||
const def = this.def;
|
||||
return this.clone(index_js_1.util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...chks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch),
|
||||
],
|
||||
}), { parent: true });
|
||||
},
|
||||
with(...chks) {
|
||||
return this.check(...chks);
|
||||
},
|
||||
clone(def, params) {
|
||||
return core.clone(this, def, params);
|
||||
},
|
||||
brand() {
|
||||
return this;
|
||||
},
|
||||
register(reg, meta) {
|
||||
reg.add(this, meta);
|
||||
return this;
|
||||
},
|
||||
refine(check, params) {
|
||||
return this.check(refine(check, params));
|
||||
},
|
||||
superRefine(refinement, params) {
|
||||
return this.check(superRefine(refinement, params));
|
||||
},
|
||||
overwrite(fn) {
|
||||
return this.check(checks.overwrite(fn));
|
||||
},
|
||||
optional() {
|
||||
return optional(this);
|
||||
},
|
||||
exactOptional() {
|
||||
return exactOptional(this);
|
||||
},
|
||||
nullable() {
|
||||
return nullable(this);
|
||||
},
|
||||
nullish() {
|
||||
return optional(nullable(this));
|
||||
},
|
||||
nonoptional(params) {
|
||||
return nonoptional(this, params);
|
||||
},
|
||||
array() {
|
||||
return array(this);
|
||||
},
|
||||
or(arg) {
|
||||
return union([this, arg]);
|
||||
},
|
||||
and(arg) {
|
||||
return intersection(this, arg);
|
||||
},
|
||||
transform(tx) {
|
||||
return pipe(this, transform(tx));
|
||||
},
|
||||
default(d) {
|
||||
return _default(this, d);
|
||||
},
|
||||
prefault(d) {
|
||||
return prefault(this, d);
|
||||
},
|
||||
catch(params) {
|
||||
return _catch(this, params);
|
||||
},
|
||||
pipe(target) {
|
||||
return pipe(this, target);
|
||||
},
|
||||
readonly() {
|
||||
return readonly(this);
|
||||
},
|
||||
describe(description) {
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
},
|
||||
meta(...args) {
|
||||
// overloaded: meta() returns the registered metadata, meta(data)
|
||||
// returns a clone with `data` registered. The mapped type picks
|
||||
// up the second overload, so we accept variadic any-args and
|
||||
// return `any` to satisfy both at runtime.
|
||||
if (args.length === 0)
|
||||
return core.globalRegistry.get(this);
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl;
|
||||
},
|
||||
isOptional() {
|
||||
return this.safeParse(undefined).success;
|
||||
},
|
||||
isNullable() {
|
||||
return this.safeParse(null).success;
|
||||
},
|
||||
apply(fn) {
|
||||
return fn(this);
|
||||
},
|
||||
});
|
||||
Object.defineProperty(inst, "description", {
|
||||
get() {
|
||||
return core.globalRegistry.get(inst)?.description;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
inst.meta = (...args) => {
|
||||
if (args.length === 0) {
|
||||
return core.globalRegistry.get(inst);
|
||||
}
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl;
|
||||
};
|
||||
// helpers
|
||||
inst.isOptional = () => inst.safeParse(undefined).success;
|
||||
inst.isNullable = () => inst.safeParse(null).success;
|
||||
inst.apply = (fn) => fn(inst);
|
||||
return inst;
|
||||
});
|
||||
/** @internal */
|
||||
@@ -226,23 +328,53 @@ exports._ZodString = core.$constructor("_ZodString", (inst, def) => {
|
||||
inst.format = bag.format ?? null;
|
||||
inst.minLength = bag.minimum ?? null;
|
||||
inst.maxLength = bag.maximum ?? null;
|
||||
// validations
|
||||
inst.regex = (...args) => inst.check(checks.regex(...args));
|
||||
inst.includes = (...args) => inst.check(checks.includes(...args));
|
||||
inst.startsWith = (...args) => inst.check(checks.startsWith(...args));
|
||||
inst.endsWith = (...args) => inst.check(checks.endsWith(...args));
|
||||
inst.min = (...args) => inst.check(checks.minLength(...args));
|
||||
inst.max = (...args) => inst.check(checks.maxLength(...args));
|
||||
inst.length = (...args) => inst.check(checks.length(...args));
|
||||
inst.nonempty = (...args) => inst.check(checks.minLength(1, ...args));
|
||||
inst.lowercase = (params) => inst.check(checks.lowercase(params));
|
||||
inst.uppercase = (params) => inst.check(checks.uppercase(params));
|
||||
// transforms
|
||||
inst.trim = () => inst.check(checks.trim());
|
||||
inst.normalize = (...args) => inst.check(checks.normalize(...args));
|
||||
inst.toLowerCase = () => inst.check(checks.toLowerCase());
|
||||
inst.toUpperCase = () => inst.check(checks.toUpperCase());
|
||||
inst.slugify = () => inst.check(checks.slugify());
|
||||
_installLazyMethods(inst, "_ZodString", {
|
||||
regex(...args) {
|
||||
return this.check(checks.regex(...args));
|
||||
},
|
||||
includes(...args) {
|
||||
return this.check(checks.includes(...args));
|
||||
},
|
||||
startsWith(...args) {
|
||||
return this.check(checks.startsWith(...args));
|
||||
},
|
||||
endsWith(...args) {
|
||||
return this.check(checks.endsWith(...args));
|
||||
},
|
||||
min(...args) {
|
||||
return this.check(checks.minLength(...args));
|
||||
},
|
||||
max(...args) {
|
||||
return this.check(checks.maxLength(...args));
|
||||
},
|
||||
length(...args) {
|
||||
return this.check(checks.length(...args));
|
||||
},
|
||||
nonempty(...args) {
|
||||
return this.check(checks.minLength(1, ...args));
|
||||
},
|
||||
lowercase(params) {
|
||||
return this.check(checks.lowercase(params));
|
||||
},
|
||||
uppercase(params) {
|
||||
return this.check(checks.uppercase(params));
|
||||
},
|
||||
trim() {
|
||||
return this.check(checks.trim());
|
||||
},
|
||||
normalize(...args) {
|
||||
return this.check(checks.normalize(...args));
|
||||
},
|
||||
toLowerCase() {
|
||||
return this.check(checks.toLowerCase());
|
||||
},
|
||||
toUpperCase() {
|
||||
return this.check(checks.toUpperCase());
|
||||
},
|
||||
slugify() {
|
||||
return this.check(checks.slugify());
|
||||
},
|
||||
});
|
||||
});
|
||||
exports.ZodString = core.$constructor("ZodString", (inst, def) => {
|
||||
core.$ZodString.init(inst, def);
|
||||
@@ -328,7 +460,7 @@ function url(params) {
|
||||
}
|
||||
function httpUrl(params) {
|
||||
return core._url(exports.ZodURL, {
|
||||
protocol: /^https?$/,
|
||||
protocol: core.regexes.httpProtocol,
|
||||
hostname: core.regexes.domain,
|
||||
...index_js_1.util.normalizeParams(params),
|
||||
});
|
||||
@@ -349,11 +481,23 @@ exports.ZodNanoID = core.$constructor("ZodNanoID", (inst, def) => {
|
||||
function nanoid(params) {
|
||||
return core._nanoid(exports.ZodNanoID, params);
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
exports.ZodCUID = core.$constructor("ZodCUID", (inst, def) => {
|
||||
// ZodStringFormat.init(inst, def);
|
||||
core.$ZodCUID.init(inst, def);
|
||||
exports.ZodStringFormat.init(inst, def);
|
||||
});
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
function cuid(params) {
|
||||
return core._cuid(exports.ZodCUID, params);
|
||||
}
|
||||
@@ -485,22 +629,53 @@ exports.ZodNumber = core.$constructor("ZodNumber", (inst, def) => {
|
||||
core.$ZodNumber.init(inst, def);
|
||||
exports.ZodType.init(inst, def);
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.numberProcessor(inst, ctx, json, params);
|
||||
inst.gt = (value, params) => inst.check(checks.gt(value, params));
|
||||
inst.gte = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.min = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.lt = (value, params) => inst.check(checks.lt(value, params));
|
||||
inst.lte = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.max = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.int = (params) => inst.check(int(params));
|
||||
inst.safe = (params) => inst.check(int(params));
|
||||
inst.positive = (params) => inst.check(checks.gt(0, params));
|
||||
inst.nonnegative = (params) => inst.check(checks.gte(0, params));
|
||||
inst.negative = (params) => inst.check(checks.lt(0, params));
|
||||
inst.nonpositive = (params) => inst.check(checks.lte(0, params));
|
||||
inst.multipleOf = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
inst.step = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
// inst.finite = (params) => inst.check(core.finite(params));
|
||||
inst.finite = () => inst;
|
||||
_installLazyMethods(inst, "ZodNumber", {
|
||||
gt(value, params) {
|
||||
return this.check(checks.gt(value, params));
|
||||
},
|
||||
gte(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
min(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
lt(value, params) {
|
||||
return this.check(checks.lt(value, params));
|
||||
},
|
||||
lte(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
max(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
int(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
safe(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
positive(params) {
|
||||
return this.check(checks.gt(0, params));
|
||||
},
|
||||
nonnegative(params) {
|
||||
return this.check(checks.gte(0, params));
|
||||
},
|
||||
negative(params) {
|
||||
return this.check(checks.lt(0, params));
|
||||
},
|
||||
nonpositive(params) {
|
||||
return this.check(checks.lte(0, params));
|
||||
},
|
||||
multipleOf(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
step(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
finite() {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
const bag = inst._zod.bag;
|
||||
inst.minValue =
|
||||
Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null;
|
||||
@@ -651,11 +826,23 @@ exports.ZodArray = core.$constructor("ZodArray", (inst, def) => {
|
||||
exports.ZodType.init(inst, def);
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.arrayProcessor(inst, ctx, json, params);
|
||||
inst.element = def.element;
|
||||
inst.min = (minLength, params) => inst.check(checks.minLength(minLength, params));
|
||||
inst.nonempty = (params) => inst.check(checks.minLength(1, params));
|
||||
inst.max = (maxLength, params) => inst.check(checks.maxLength(maxLength, params));
|
||||
inst.length = (len, params) => inst.check(checks.length(len, params));
|
||||
inst.unwrap = () => inst.element;
|
||||
_installLazyMethods(inst, "ZodArray", {
|
||||
min(n, params) {
|
||||
return this.check(checks.minLength(n, params));
|
||||
},
|
||||
nonempty(params) {
|
||||
return this.check(checks.minLength(1, params));
|
||||
},
|
||||
max(n, params) {
|
||||
return this.check(checks.maxLength(n, params));
|
||||
},
|
||||
length(n, params) {
|
||||
return this.check(checks.length(n, params));
|
||||
},
|
||||
unwrap() {
|
||||
return this.element;
|
||||
},
|
||||
});
|
||||
});
|
||||
function array(element, params) {
|
||||
return core._array(exports.ZodArray, element, params);
|
||||
@@ -672,23 +859,47 @@ exports.ZodObject = core.$constructor("ZodObject", (inst, def) => {
|
||||
index_js_1.util.defineLazy(inst, "shape", () => {
|
||||
return def.shape;
|
||||
});
|
||||
inst.keyof = () => _enum(Object.keys(inst._zod.def.shape));
|
||||
inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall });
|
||||
inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.strict = () => inst.clone({ ...inst._zod.def, catchall: never() });
|
||||
inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
|
||||
inst.extend = (incoming) => {
|
||||
return index_js_1.util.extend(inst, incoming);
|
||||
};
|
||||
inst.safeExtend = (incoming) => {
|
||||
return index_js_1.util.safeExtend(inst, incoming);
|
||||
};
|
||||
inst.merge = (other) => index_js_1.util.merge(inst, other);
|
||||
inst.pick = (mask) => index_js_1.util.pick(inst, mask);
|
||||
inst.omit = (mask) => index_js_1.util.omit(inst, mask);
|
||||
inst.partial = (...args) => index_js_1.util.partial(exports.ZodOptional, inst, args[0]);
|
||||
inst.required = (...args) => index_js_1.util.required(exports.ZodNonOptional, inst, args[0]);
|
||||
_installLazyMethods(inst, "ZodObject", {
|
||||
keyof() {
|
||||
return _enum(Object.keys(this._zod.def.shape));
|
||||
},
|
||||
catchall(catchall) {
|
||||
return this.clone({ ...this._zod.def, catchall: catchall });
|
||||
},
|
||||
passthrough() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
loose() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
strict() {
|
||||
return this.clone({ ...this._zod.def, catchall: never() });
|
||||
},
|
||||
strip() {
|
||||
return this.clone({ ...this._zod.def, catchall: undefined });
|
||||
},
|
||||
extend(incoming) {
|
||||
return index_js_1.util.extend(this, incoming);
|
||||
},
|
||||
safeExtend(incoming) {
|
||||
return index_js_1.util.safeExtend(this, incoming);
|
||||
},
|
||||
merge(other) {
|
||||
return index_js_1.util.merge(this, other);
|
||||
},
|
||||
pick(mask) {
|
||||
return index_js_1.util.pick(this, mask);
|
||||
},
|
||||
omit(mask) {
|
||||
return index_js_1.util.omit(this, mask);
|
||||
},
|
||||
partial(...args) {
|
||||
return index_js_1.util.partial(exports.ZodOptional, this, args[0]);
|
||||
},
|
||||
required(...args) {
|
||||
return index_js_1.util.required(exports.ZodNonOptional, this, args[0]);
|
||||
},
|
||||
});
|
||||
});
|
||||
function object(shape, params) {
|
||||
const def = {
|
||||
@@ -799,6 +1010,15 @@ exports.ZodRecord = core.$constructor("ZodRecord", (inst, def) => {
|
||||
inst.valueType = def.valueType;
|
||||
});
|
||||
function record(keyType, valueType, params) {
|
||||
// v3-compat: z.record(valueType, params?) — defaults keyType to z.string()
|
||||
if (!valueType || !valueType._zod) {
|
||||
return new exports.ZodRecord({
|
||||
type: "record",
|
||||
keyType: string(),
|
||||
valueType: keyType,
|
||||
...index_js_1.util.normalizeParams(valueType),
|
||||
});
|
||||
}
|
||||
return new exports.ZodRecord({
|
||||
type: "record",
|
||||
keyType,
|
||||
@@ -983,10 +1203,12 @@ exports.ZodTransform = core.$constructor("ZodTransform", (inst, def) => {
|
||||
if (output instanceof Promise) {
|
||||
return output.then((output) => {
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
});
|
||||
}
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
};
|
||||
});
|
||||
@@ -1142,6 +1364,20 @@ function codec(in_, out, params) {
|
||||
reverseTransform: params.encode,
|
||||
});
|
||||
}
|
||||
function invertCodec(codec) {
|
||||
const def = codec._zod.def;
|
||||
return new exports.ZodCodec({
|
||||
type: "pipe",
|
||||
in: def.out,
|
||||
out: def.in,
|
||||
transform: def.reverseTransform,
|
||||
reverseTransform: def.transform,
|
||||
});
|
||||
}
|
||||
exports.ZodPreprocess = core.$constructor("ZodPreprocess", (inst, def) => {
|
||||
exports.ZodPipe.init(inst, def);
|
||||
core.$ZodPreprocess.init(inst, def);
|
||||
});
|
||||
exports.ZodReadonly = core.$constructor("ZodReadonly", (inst, def) => {
|
||||
core.$ZodReadonly.init(inst, def);
|
||||
exports.ZodType.init(inst, def);
|
||||
@@ -1223,8 +1459,8 @@ function refine(fn, _params = {}) {
|
||||
return core._refine(exports.ZodCustom, fn, _params);
|
||||
}
|
||||
// superRefine
|
||||
function superRefine(fn) {
|
||||
return core._superRefine(fn);
|
||||
function superRefine(fn, params) {
|
||||
return core._superRefine(fn, params);
|
||||
}
|
||||
// Re-export describe and meta from core
|
||||
exports.describe = core.describe;
|
||||
@@ -1266,7 +1502,10 @@ function json(params) {
|
||||
return jsonSchema;
|
||||
}
|
||||
// preprocess
|
||||
// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */
|
||||
function preprocess(fn, schema) {
|
||||
return pipe(transform(fn), schema);
|
||||
return new exports.ZodPreprocess({
|
||||
type: "pipe",
|
||||
in: transform(fn),
|
||||
out: schema,
|
||||
});
|
||||
}
|
||||
|
||||
+42
-14
@@ -36,7 +36,7 @@ export interface ZodType<out Output = unknown, out Input = unknown, out Internal
|
||||
safeEncodeAsync(data: core.output<this>, params?: core.ParseContext<core.$ZodIssue>): Promise<parse.ZodSafeParseResult<core.input<this>>>;
|
||||
safeDecodeAsync(data: core.input<this>, params?: core.ParseContext<core.$ZodIssue>): Promise<parse.ZodSafeParseResult<core.output<this>>>;
|
||||
refine<Ch extends (arg: core.output<this>) => unknown | Promise<unknown>>(check: Ch, params?: string | core.$ZodCustomParams): Ch extends (arg: any) => arg is infer R ? this & ZodType<R, core.input<this>> : this;
|
||||
superRefine(refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>): this;
|
||||
superRefine(refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>, params?: core.$ZodSuperRefineParams): this;
|
||||
overwrite(fn: (x: core.output<this>) => core.output<this>): this;
|
||||
optional(): ZodOptional<this>;
|
||||
exactOptional(): ZodExactOptional<this>;
|
||||
@@ -129,7 +129,11 @@ export interface ZodString extends _ZodString<core.$ZodStringInternals<string>>
|
||||
nanoid(params?: string | core.$ZodCheckNanoIDParams): this;
|
||||
/** @deprecated Use `z.guid()` instead. */
|
||||
guid(params?: string | core.$ZodCheckGUIDParams): this;
|
||||
/** @deprecated Use `z.cuid()` instead. */
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use `z.cuid2()` instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
cuid(params?: string | core.$ZodCheckCUIDParams): this;
|
||||
/** @deprecated Use `z.cuid2()` instead. */
|
||||
cuid2(params?: string | core.$ZodCheckCUID2Params): this;
|
||||
@@ -202,10 +206,27 @@ export interface ZodNanoID extends ZodStringFormat<"nanoid"> {
|
||||
}
|
||||
export declare const ZodNanoID: core.$constructor<ZodNanoID>;
|
||||
export declare function nanoid(params?: string | core.$ZodNanoIDParams): ZodNanoID;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface ZodCUID extends ZodStringFormat<"cuid"> {
|
||||
_zod: core.$ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const ZodCUID: core.$constructor<ZodCUID>;
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare function cuid(params?: string | core.$ZodCUIDParams): ZodCUID;
|
||||
export interface ZodCUID2 extends ZodStringFormat<"cuid2"> {
|
||||
_zod: core.$ZodCUID2Internals;
|
||||
@@ -444,8 +465,8 @@ out Shape extends core.$ZodShape = core.$ZodLooseShape, out Config extends core.
|
||||
strict(): ZodObject<Shape, core.$strict>;
|
||||
/** This is the default behavior. This method call is likely unnecessary. */
|
||||
strip(): ZodObject<Shape, core.$strip>;
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
safeExtend<U extends core.$ZodLooseShape>(shape: SafeExtendShape<Shape, U> & Partial<Record<keyof Shape, core.SomeType>>): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
safeExtend<U extends core.$ZodLooseShape>(shape: SafeExtendShape<Shape, U> & Partial<Record<keyof Shape, core.SomeType>>): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
/**
|
||||
* @deprecated Use [`A.extend(B.shape)`](https://zod.dev/api?id=extend) instead.
|
||||
*/
|
||||
@@ -453,22 +474,22 @@ out Shape extends core.$ZodShape = core.$ZodLooseShape, out Config extends core.
|
||||
pick<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, Config>;
|
||||
omit<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, Config>;
|
||||
partial(): ZodObject<{
|
||||
[k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
}, Config>;
|
||||
partial<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<{
|
||||
[k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
|
||||
-readonly [k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
|
||||
}, Config>;
|
||||
required(): ZodObject<{
|
||||
[k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
}, Config>;
|
||||
required<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<{
|
||||
[k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
-readonly [k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
}, Config>;
|
||||
}
|
||||
export declare const ZodObject: core.$constructor<ZodObject>;
|
||||
export declare function object<T extends core.$ZodLooseShape = Partial<Record<never, core.SomeType>>>(shape?: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$strip>;
|
||||
export declare function strictObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<T, core.$strict>;
|
||||
export declare function looseObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<T, core.$loose>;
|
||||
export declare function strictObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$strict>;
|
||||
export declare function looseObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$loose>;
|
||||
export interface ZodUnion<T extends readonly core.SomeType[] = readonly core.$ZodType[]> extends _ZodType<core.$ZodUnionInternals<T>>, core.$ZodUnion<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
options: T;
|
||||
@@ -490,7 +511,7 @@ export interface ZodDiscriminatedUnion<Options extends readonly core.SomeType[]
|
||||
def: core.$ZodDiscriminatedUnionDef<Options, Disc>;
|
||||
}
|
||||
export declare const ZodDiscriminatedUnion: core.$constructor<ZodDiscriminatedUnion>;
|
||||
export declare function discriminatedUnion<Types extends readonly [core.$ZodTypeDiscriminable, ...core.$ZodTypeDiscriminable[]], Disc extends string>(discriminator: Disc, options: Types, params?: string | core.$ZodDiscriminatedUnionParams): ZodDiscriminatedUnion<Types, Disc>;
|
||||
export declare function discriminatedUnion<Types extends readonly [core.$ZodTypeDiscriminable<Disc>, ...core.$ZodTypeDiscriminable<Disc>[]], Disc extends string>(discriminator: Disc, options: Types, params?: string | core.$ZodDiscriminatedUnionParams): ZodDiscriminatedUnion<Types, Disc>;
|
||||
export interface ZodIntersection<A extends core.SomeType = core.$ZodType, B extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodIntersectionInternals<A, B>>, core.$ZodIntersection<A, B> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
}
|
||||
@@ -575,7 +596,7 @@ export interface ZodTransform<O = unknown, I = unknown> extends _ZodType<core.$Z
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
}
|
||||
export declare const ZodTransform: core.$constructor<ZodTransform>;
|
||||
export declare function transform<I = unknown, O = I>(fn: (input: I, ctx: core.ParsePayload) => O): ZodTransform<Awaited<O>, I>;
|
||||
export declare function transform<I = unknown, O = I>(fn: (input: I, ctx: core.$RefinementCtx) => O): ZodTransform<Awaited<O>, I>;
|
||||
export interface ZodOptional<T extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodOptionalInternals<T>>, core.$ZodOptional<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
unwrap(): T;
|
||||
@@ -652,6 +673,13 @@ export declare function codec<const A extends core.SomeType, B extends core.Some
|
||||
decode: (value: core.output<A>, payload: core.ParsePayload<core.output<A>>) => core.util.MaybeAsync<core.input<B>>;
|
||||
encode: (value: core.input<B>, payload: core.ParsePayload<core.input<B>>) => core.util.MaybeAsync<core.output<A>>;
|
||||
}): ZodCodec<A, B>;
|
||||
export declare function invertCodec<A extends core.SomeType, B extends core.SomeType>(codec: ZodCodec<A, B>): ZodCodec<B, A>;
|
||||
export interface ZodPreprocess<B extends core.SomeType = core.$ZodType> extends ZodPipe<core.$ZodTransform, B>, core.$ZodPreprocess<B> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
_zod: core.$ZodPreprocessInternals<B>;
|
||||
def: core.$ZodPreprocessDef<B>;
|
||||
}
|
||||
export declare const ZodPreprocess: core.$constructor<ZodPreprocess>;
|
||||
export interface ZodReadonly<T extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodReadonlyInternals<T>>, core.$ZodReadonly<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
unwrap(): T;
|
||||
@@ -712,7 +740,7 @@ export declare const ZodCustom: core.$constructor<ZodCustom>;
|
||||
export declare function check<O = unknown>(fn: core.CheckFn<O>): core.$ZodCheck<O>;
|
||||
export declare function custom<O>(fn?: (data: unknown) => unknown, _params?: string | core.$ZodCustomParams | undefined): ZodCustom<O, O>;
|
||||
export declare function refine<T>(fn: (arg: NoInfer<T>) => util.MaybeAsync<unknown>, _params?: string | core.$ZodCustomParams): core.$ZodCheck<T>;
|
||||
export declare function superRefine<T>(fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>): core.$ZodCheck<T>;
|
||||
export declare function superRefine<T>(fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>, params?: core.$ZodSuperRefineParams): core.$ZodCheck<T>;
|
||||
export declare const describe: typeof core.describe;
|
||||
export declare const meta: typeof core.meta;
|
||||
type ZodInstanceOfParams = core.Params<ZodCustom, core.$ZodIssueCustom, "type" | "check" | "checks" | "fn" | "abort" | "error" | "params" | "path">;
|
||||
@@ -736,4 +764,4 @@ export interface ZodJSONSchema extends _ZodJSONSchema {
|
||||
_zod: ZodJSONSchemaInternals;
|
||||
}
|
||||
export declare function json(params?: string | core.$ZodCustomParams): ZodJSONSchema;
|
||||
export declare function preprocess<A, U extends core.SomeType, B = unknown>(fn: (arg: B, ctx: core.$RefinementCtx) => A, schema: U): ZodPipe<ZodTransform<A, B>, U>;
|
||||
export declare function preprocess<A, U extends core.SomeType, B = unknown>(fn: (arg: B, ctx: core.$RefinementCtx) => A, schema: U): ZodPreprocess<U>;
|
||||
|
||||
+42
-14
@@ -36,7 +36,7 @@ export interface ZodType<out Output = unknown, out Input = unknown, out Internal
|
||||
safeEncodeAsync(data: core.output<this>, params?: core.ParseContext<core.$ZodIssue>): Promise<parse.ZodSafeParseResult<core.input<this>>>;
|
||||
safeDecodeAsync(data: core.input<this>, params?: core.ParseContext<core.$ZodIssue>): Promise<parse.ZodSafeParseResult<core.output<this>>>;
|
||||
refine<Ch extends (arg: core.output<this>) => unknown | Promise<unknown>>(check: Ch, params?: string | core.$ZodCustomParams): Ch extends (arg: any) => arg is infer R ? this & ZodType<R, core.input<this>> : this;
|
||||
superRefine(refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>): this;
|
||||
superRefine(refinement: (arg: core.output<this>, ctx: core.$RefinementCtx<core.output<this>>) => void | Promise<void>, params?: core.$ZodSuperRefineParams): this;
|
||||
overwrite(fn: (x: core.output<this>) => core.output<this>): this;
|
||||
optional(): ZodOptional<this>;
|
||||
exactOptional(): ZodExactOptional<this>;
|
||||
@@ -129,7 +129,11 @@ export interface ZodString extends _ZodString<core.$ZodStringInternals<string>>
|
||||
nanoid(params?: string | core.$ZodCheckNanoIDParams): this;
|
||||
/** @deprecated Use `z.guid()` instead. */
|
||||
guid(params?: string | core.$ZodCheckGUIDParams): this;
|
||||
/** @deprecated Use `z.cuid()` instead. */
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use `z.cuid2()` instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
cuid(params?: string | core.$ZodCheckCUIDParams): this;
|
||||
/** @deprecated Use `z.cuid2()` instead. */
|
||||
cuid2(params?: string | core.$ZodCheckCUID2Params): this;
|
||||
@@ -202,10 +206,27 @@ export interface ZodNanoID extends ZodStringFormat<"nanoid"> {
|
||||
}
|
||||
export declare const ZodNanoID: core.$constructor<ZodNanoID>;
|
||||
export declare function nanoid(params?: string | core.$ZodNanoIDParams): ZodNanoID;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface ZodCUID extends ZodStringFormat<"cuid"> {
|
||||
_zod: core.$ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const ZodCUID: core.$constructor<ZodCUID>;
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare function cuid(params?: string | core.$ZodCUIDParams): ZodCUID;
|
||||
export interface ZodCUID2 extends ZodStringFormat<"cuid2"> {
|
||||
_zod: core.$ZodCUID2Internals;
|
||||
@@ -444,8 +465,8 @@ out Shape extends core.$ZodShape = core.$ZodLooseShape, out Config extends core.
|
||||
strict(): ZodObject<Shape, core.$strict>;
|
||||
/** This is the default behavior. This method call is likely unnecessary. */
|
||||
strip(): ZodObject<Shape, core.$strip>;
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
safeExtend<U extends core.$ZodLooseShape>(shape: SafeExtendShape<Shape, U> & Partial<Record<keyof Shape, core.SomeType>>): ZodObject<util.Extend<Shape, U>, Config>;
|
||||
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
safeExtend<U extends core.$ZodLooseShape>(shape: SafeExtendShape<Shape, U> & Partial<Record<keyof Shape, core.SomeType>>): ZodObject<util.Extend<Shape, util.Writeable<U>>, Config>;
|
||||
/**
|
||||
* @deprecated Use [`A.extend(B.shape)`](https://zod.dev/api?id=extend) instead.
|
||||
*/
|
||||
@@ -453,22 +474,22 @@ out Shape extends core.$ZodShape = core.$ZodLooseShape, out Config extends core.
|
||||
pick<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, Config>;
|
||||
omit<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, Config>;
|
||||
partial(): ZodObject<{
|
||||
[k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodOptional<Shape[k]>;
|
||||
}, Config>;
|
||||
partial<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<{
|
||||
[k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
|
||||
-readonly [k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
|
||||
}, Config>;
|
||||
required(): ZodObject<{
|
||||
[k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
-readonly [k in keyof Shape]: ZodNonOptional<Shape[k]>;
|
||||
}, Config>;
|
||||
required<M extends util.Mask<keyof Shape>>(mask: M & Record<Exclude<keyof M, keyof Shape>, never>): ZodObject<{
|
||||
[k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
-readonly [k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
|
||||
}, Config>;
|
||||
}
|
||||
export declare const ZodObject: core.$constructor<ZodObject>;
|
||||
export declare function object<T extends core.$ZodLooseShape = Partial<Record<never, core.SomeType>>>(shape?: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$strip>;
|
||||
export declare function strictObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<T, core.$strict>;
|
||||
export declare function looseObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<T, core.$loose>;
|
||||
export declare function strictObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$strict>;
|
||||
export declare function looseObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodObject<util.Writeable<T>, core.$loose>;
|
||||
export interface ZodUnion<T extends readonly core.SomeType[] = readonly core.$ZodType[]> extends _ZodType<core.$ZodUnionInternals<T>>, core.$ZodUnion<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
options: T;
|
||||
@@ -490,7 +511,7 @@ export interface ZodDiscriminatedUnion<Options extends readonly core.SomeType[]
|
||||
def: core.$ZodDiscriminatedUnionDef<Options, Disc>;
|
||||
}
|
||||
export declare const ZodDiscriminatedUnion: core.$constructor<ZodDiscriminatedUnion>;
|
||||
export declare function discriminatedUnion<Types extends readonly [core.$ZodTypeDiscriminable, ...core.$ZodTypeDiscriminable[]], Disc extends string>(discriminator: Disc, options: Types, params?: string | core.$ZodDiscriminatedUnionParams): ZodDiscriminatedUnion<Types, Disc>;
|
||||
export declare function discriminatedUnion<Types extends readonly [core.$ZodTypeDiscriminable<Disc>, ...core.$ZodTypeDiscriminable<Disc>[]], Disc extends string>(discriminator: Disc, options: Types, params?: string | core.$ZodDiscriminatedUnionParams): ZodDiscriminatedUnion<Types, Disc>;
|
||||
export interface ZodIntersection<A extends core.SomeType = core.$ZodType, B extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodIntersectionInternals<A, B>>, core.$ZodIntersection<A, B> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
}
|
||||
@@ -575,7 +596,7 @@ export interface ZodTransform<O = unknown, I = unknown> extends _ZodType<core.$Z
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
}
|
||||
export declare const ZodTransform: core.$constructor<ZodTransform>;
|
||||
export declare function transform<I = unknown, O = I>(fn: (input: I, ctx: core.ParsePayload) => O): ZodTransform<Awaited<O>, I>;
|
||||
export declare function transform<I = unknown, O = I>(fn: (input: I, ctx: core.$RefinementCtx) => O): ZodTransform<Awaited<O>, I>;
|
||||
export interface ZodOptional<T extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodOptionalInternals<T>>, core.$ZodOptional<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
unwrap(): T;
|
||||
@@ -652,6 +673,13 @@ export declare function codec<const A extends core.SomeType, B extends core.Some
|
||||
decode: (value: core.output<A>, payload: core.ParsePayload<core.output<A>>) => core.util.MaybeAsync<core.input<B>>;
|
||||
encode: (value: core.input<B>, payload: core.ParsePayload<core.input<B>>) => core.util.MaybeAsync<core.output<A>>;
|
||||
}): ZodCodec<A, B>;
|
||||
export declare function invertCodec<A extends core.SomeType, B extends core.SomeType>(codec: ZodCodec<A, B>): ZodCodec<B, A>;
|
||||
export interface ZodPreprocess<B extends core.SomeType = core.$ZodType> extends ZodPipe<core.$ZodTransform, B>, core.$ZodPreprocess<B> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
_zod: core.$ZodPreprocessInternals<B>;
|
||||
def: core.$ZodPreprocessDef<B>;
|
||||
}
|
||||
export declare const ZodPreprocess: core.$constructor<ZodPreprocess>;
|
||||
export interface ZodReadonly<T extends core.SomeType = core.$ZodType> extends _ZodType<core.$ZodReadonlyInternals<T>>, core.$ZodReadonly<T> {
|
||||
"~standard": ZodStandardSchemaWithJSON<this>;
|
||||
unwrap(): T;
|
||||
@@ -712,7 +740,7 @@ export declare const ZodCustom: core.$constructor<ZodCustom>;
|
||||
export declare function check<O = unknown>(fn: core.CheckFn<O>): core.$ZodCheck<O>;
|
||||
export declare function custom<O>(fn?: (data: unknown) => unknown, _params?: string | core.$ZodCustomParams | undefined): ZodCustom<O, O>;
|
||||
export declare function refine<T>(fn: (arg: NoInfer<T>) => util.MaybeAsync<unknown>, _params?: string | core.$ZodCustomParams): core.$ZodCheck<T>;
|
||||
export declare function superRefine<T>(fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>): core.$ZodCheck<T>;
|
||||
export declare function superRefine<T>(fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>, params?: core.$ZodSuperRefineParams): core.$ZodCheck<T>;
|
||||
export declare const describe: typeof core.describe;
|
||||
export declare const meta: typeof core.meta;
|
||||
type ZodInstanceOfParams = core.Params<ZodCustom, core.$ZodIssueCustom, "type" | "check" | "checks" | "fn" | "abort" | "error" | "params" | "path">;
|
||||
@@ -736,4 +764,4 @@ export interface ZodJSONSchema extends _ZodJSONSchema {
|
||||
_zod: ZodJSONSchemaInternals;
|
||||
}
|
||||
export declare function json(params?: string | core.$ZodCustomParams): ZodJSONSchema;
|
||||
export declare function preprocess<A, U extends core.SomeType, B = unknown>(fn: (arg: B, ctx: core.$RefinementCtx) => A, schema: U): ZodPipe<ZodTransform<A, B>, U>;
|
||||
export declare function preprocess<A, U extends core.SomeType, B = unknown>(fn: (arg: B, ctx: core.$RefinementCtx) => A, schema: U): ZodPreprocess<U>;
|
||||
|
||||
+356
-118
@@ -5,6 +5,54 @@ import { createStandardJSONSchemaMethod, createToJSONSchemaMethod } from "../cor
|
||||
import * as checks from "./checks.js";
|
||||
import * as iso from "./iso.js";
|
||||
import * as parse from "./parse.js";
|
||||
// Lazy-bind builder methods.
|
||||
//
|
||||
// Builder methods (`.optional`, `.array`, `.refine`, ...) live as
|
||||
// non-enumerable getters on each concrete schema constructor's
|
||||
// prototype. On first access from an instance the getter allocates
|
||||
// `fn.bind(this)` and caches it as an own property on that instance,
|
||||
// so detached usage (`const m = schema.optional; m()`) still works
|
||||
// and the per-instance allocation only happens for methods actually
|
||||
// touched.
|
||||
//
|
||||
// One install per (prototype, group), memoized by `_installedGroups`.
|
||||
const _installedGroups = /* @__PURE__ */ new WeakMap();
|
||||
function _installLazyMethods(inst, group, methods) {
|
||||
const proto = Object.getPrototypeOf(inst);
|
||||
let installed = _installedGroups.get(proto);
|
||||
if (!installed) {
|
||||
installed = new Set();
|
||||
_installedGroups.set(proto, installed);
|
||||
}
|
||||
if (installed.has(group))
|
||||
return;
|
||||
installed.add(group);
|
||||
for (const key in methods) {
|
||||
const fn = methods[key];
|
||||
Object.defineProperty(proto, key, {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
get() {
|
||||
const bound = fn.bind(this);
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: bound,
|
||||
});
|
||||
return bound;
|
||||
},
|
||||
set(v) {
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
value: v,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
export const ZodType = /*@__PURE__*/ core.$constructor("ZodType", (inst, def) => {
|
||||
core.$ZodType.init(inst, def);
|
||||
Object.assign(inst["~standard"], {
|
||||
@@ -17,31 +65,16 @@ export const ZodType = /*@__PURE__*/ core.$constructor("ZodType", (inst, def) =>
|
||||
inst.def = def;
|
||||
inst.type = def.type;
|
||||
Object.defineProperty(inst, "_def", { value: def });
|
||||
// base methods
|
||||
inst.check = (...checks) => {
|
||||
return inst.clone(util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...checks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch),
|
||||
],
|
||||
}), {
|
||||
parent: true,
|
||||
});
|
||||
};
|
||||
inst.with = inst.check;
|
||||
inst.clone = (def, params) => core.clone(inst, def, params);
|
||||
inst.brand = () => inst;
|
||||
inst.register = ((reg, meta) => {
|
||||
reg.add(inst, meta);
|
||||
return inst;
|
||||
});
|
||||
// parsing
|
||||
// Parse-family is intentionally kept as per-instance closures: these are
|
||||
// the hot path AND the most-detached methods (`arr.map(schema.parse)`,
|
||||
// `const { parse } = schema`, etc.). Eager closures here mean callers pay
|
||||
// ~12 closure allocations per schema but get monomorphic call sites and
|
||||
// detached usage that "just works".
|
||||
inst.parse = (data, params) => parse.parse(inst, data, params, { callee: inst.parse });
|
||||
inst.safeParse = (data, params) => parse.safeParse(inst, data, params);
|
||||
inst.parseAsync = async (data, params) => parse.parseAsync(inst, data, params, { callee: inst.parseAsync });
|
||||
inst.safeParseAsync = async (data, params) => parse.safeParseAsync(inst, data, params);
|
||||
inst.spa = inst.safeParseAsync;
|
||||
// encoding/decoding
|
||||
inst.encode = (data, params) => parse.encode(inst, data, params);
|
||||
inst.decode = (data, params) => parse.decode(inst, data, params);
|
||||
inst.encodeAsync = async (data, params) => parse.encodeAsync(inst, data, params);
|
||||
@@ -50,50 +83,118 @@ export const ZodType = /*@__PURE__*/ core.$constructor("ZodType", (inst, def) =>
|
||||
inst.safeDecode = (data, params) => parse.safeDecode(inst, data, params);
|
||||
inst.safeEncodeAsync = async (data, params) => parse.safeEncodeAsync(inst, data, params);
|
||||
inst.safeDecodeAsync = async (data, params) => parse.safeDecodeAsync(inst, data, params);
|
||||
// refinements
|
||||
inst.refine = (check, params) => inst.check(refine(check, params));
|
||||
inst.superRefine = (refinement) => inst.check(superRefine(refinement));
|
||||
inst.overwrite = (fn) => inst.check(checks.overwrite(fn));
|
||||
// wrappers
|
||||
inst.optional = () => optional(inst);
|
||||
inst.exactOptional = () => exactOptional(inst);
|
||||
inst.nullable = () => nullable(inst);
|
||||
inst.nullish = () => optional(nullable(inst));
|
||||
inst.nonoptional = (params) => nonoptional(inst, params);
|
||||
inst.array = () => array(inst);
|
||||
inst.or = (arg) => union([inst, arg]);
|
||||
inst.and = (arg) => intersection(inst, arg);
|
||||
inst.transform = (tx) => pipe(inst, transform(tx));
|
||||
inst.default = (def) => _default(inst, def);
|
||||
inst.prefault = (def) => prefault(inst, def);
|
||||
// inst.coalesce = (def, params) => coalesce(inst, def, params);
|
||||
inst.catch = (params) => _catch(inst, params);
|
||||
inst.pipe = (target) => pipe(inst, target);
|
||||
inst.readonly = () => readonly(inst);
|
||||
// meta
|
||||
inst.describe = (description) => {
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
};
|
||||
// All builder methods are placed on the internal prototype as lazy-bind
|
||||
// getters. On first access per-instance, a bound thunk is allocated and
|
||||
// cached as an own property; subsequent accesses skip the getter. This
|
||||
// means: no per-instance allocation for unused methods, full
|
||||
// detachability preserved (`const m = schema.optional; m()` works), and
|
||||
// shared underlying function references across all instances.
|
||||
_installLazyMethods(inst, "ZodType", {
|
||||
check(...chks) {
|
||||
const def = this.def;
|
||||
return this.clone(util.mergeDefs(def, {
|
||||
checks: [
|
||||
...(def.checks ?? []),
|
||||
...chks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch),
|
||||
],
|
||||
}), { parent: true });
|
||||
},
|
||||
with(...chks) {
|
||||
return this.check(...chks);
|
||||
},
|
||||
clone(def, params) {
|
||||
return core.clone(this, def, params);
|
||||
},
|
||||
brand() {
|
||||
return this;
|
||||
},
|
||||
register(reg, meta) {
|
||||
reg.add(this, meta);
|
||||
return this;
|
||||
},
|
||||
refine(check, params) {
|
||||
return this.check(refine(check, params));
|
||||
},
|
||||
superRefine(refinement, params) {
|
||||
return this.check(superRefine(refinement, params));
|
||||
},
|
||||
overwrite(fn) {
|
||||
return this.check(checks.overwrite(fn));
|
||||
},
|
||||
optional() {
|
||||
return optional(this);
|
||||
},
|
||||
exactOptional() {
|
||||
return exactOptional(this);
|
||||
},
|
||||
nullable() {
|
||||
return nullable(this);
|
||||
},
|
||||
nullish() {
|
||||
return optional(nullable(this));
|
||||
},
|
||||
nonoptional(params) {
|
||||
return nonoptional(this, params);
|
||||
},
|
||||
array() {
|
||||
return array(this);
|
||||
},
|
||||
or(arg) {
|
||||
return union([this, arg]);
|
||||
},
|
||||
and(arg) {
|
||||
return intersection(this, arg);
|
||||
},
|
||||
transform(tx) {
|
||||
return pipe(this, transform(tx));
|
||||
},
|
||||
default(d) {
|
||||
return _default(this, d);
|
||||
},
|
||||
prefault(d) {
|
||||
return prefault(this, d);
|
||||
},
|
||||
catch(params) {
|
||||
return _catch(this, params);
|
||||
},
|
||||
pipe(target) {
|
||||
return pipe(this, target);
|
||||
},
|
||||
readonly() {
|
||||
return readonly(this);
|
||||
},
|
||||
describe(description) {
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, { description });
|
||||
return cl;
|
||||
},
|
||||
meta(...args) {
|
||||
// overloaded: meta() returns the registered metadata, meta(data)
|
||||
// returns a clone with `data` registered. The mapped type picks
|
||||
// up the second overload, so we accept variadic any-args and
|
||||
// return `any` to satisfy both at runtime.
|
||||
if (args.length === 0)
|
||||
return core.globalRegistry.get(this);
|
||||
const cl = this.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl;
|
||||
},
|
||||
isOptional() {
|
||||
return this.safeParse(undefined).success;
|
||||
},
|
||||
isNullable() {
|
||||
return this.safeParse(null).success;
|
||||
},
|
||||
apply(fn) {
|
||||
return fn(this);
|
||||
},
|
||||
});
|
||||
Object.defineProperty(inst, "description", {
|
||||
get() {
|
||||
return core.globalRegistry.get(inst)?.description;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
inst.meta = (...args) => {
|
||||
if (args.length === 0) {
|
||||
return core.globalRegistry.get(inst);
|
||||
}
|
||||
const cl = inst.clone();
|
||||
core.globalRegistry.add(cl, args[0]);
|
||||
return cl;
|
||||
};
|
||||
// helpers
|
||||
inst.isOptional = () => inst.safeParse(undefined).success;
|
||||
inst.isNullable = () => inst.safeParse(null).success;
|
||||
inst.apply = (fn) => fn(inst);
|
||||
return inst;
|
||||
});
|
||||
/** @internal */
|
||||
@@ -105,23 +206,53 @@ export const _ZodString = /*@__PURE__*/ core.$constructor("_ZodString", (inst, d
|
||||
inst.format = bag.format ?? null;
|
||||
inst.minLength = bag.minimum ?? null;
|
||||
inst.maxLength = bag.maximum ?? null;
|
||||
// validations
|
||||
inst.regex = (...args) => inst.check(checks.regex(...args));
|
||||
inst.includes = (...args) => inst.check(checks.includes(...args));
|
||||
inst.startsWith = (...args) => inst.check(checks.startsWith(...args));
|
||||
inst.endsWith = (...args) => inst.check(checks.endsWith(...args));
|
||||
inst.min = (...args) => inst.check(checks.minLength(...args));
|
||||
inst.max = (...args) => inst.check(checks.maxLength(...args));
|
||||
inst.length = (...args) => inst.check(checks.length(...args));
|
||||
inst.nonempty = (...args) => inst.check(checks.minLength(1, ...args));
|
||||
inst.lowercase = (params) => inst.check(checks.lowercase(params));
|
||||
inst.uppercase = (params) => inst.check(checks.uppercase(params));
|
||||
// transforms
|
||||
inst.trim = () => inst.check(checks.trim());
|
||||
inst.normalize = (...args) => inst.check(checks.normalize(...args));
|
||||
inst.toLowerCase = () => inst.check(checks.toLowerCase());
|
||||
inst.toUpperCase = () => inst.check(checks.toUpperCase());
|
||||
inst.slugify = () => inst.check(checks.slugify());
|
||||
_installLazyMethods(inst, "_ZodString", {
|
||||
regex(...args) {
|
||||
return this.check(checks.regex(...args));
|
||||
},
|
||||
includes(...args) {
|
||||
return this.check(checks.includes(...args));
|
||||
},
|
||||
startsWith(...args) {
|
||||
return this.check(checks.startsWith(...args));
|
||||
},
|
||||
endsWith(...args) {
|
||||
return this.check(checks.endsWith(...args));
|
||||
},
|
||||
min(...args) {
|
||||
return this.check(checks.minLength(...args));
|
||||
},
|
||||
max(...args) {
|
||||
return this.check(checks.maxLength(...args));
|
||||
},
|
||||
length(...args) {
|
||||
return this.check(checks.length(...args));
|
||||
},
|
||||
nonempty(...args) {
|
||||
return this.check(checks.minLength(1, ...args));
|
||||
},
|
||||
lowercase(params) {
|
||||
return this.check(checks.lowercase(params));
|
||||
},
|
||||
uppercase(params) {
|
||||
return this.check(checks.uppercase(params));
|
||||
},
|
||||
trim() {
|
||||
return this.check(checks.trim());
|
||||
},
|
||||
normalize(...args) {
|
||||
return this.check(checks.normalize(...args));
|
||||
},
|
||||
toLowerCase() {
|
||||
return this.check(checks.toLowerCase());
|
||||
},
|
||||
toUpperCase() {
|
||||
return this.check(checks.toUpperCase());
|
||||
},
|
||||
slugify() {
|
||||
return this.check(checks.slugify());
|
||||
},
|
||||
});
|
||||
});
|
||||
export const ZodString = /*@__PURE__*/ core.$constructor("ZodString", (inst, def) => {
|
||||
core.$ZodString.init(inst, def);
|
||||
@@ -207,7 +338,7 @@ export function url(params) {
|
||||
}
|
||||
export function httpUrl(params) {
|
||||
return core._url(ZodURL, {
|
||||
protocol: /^https?$/,
|
||||
protocol: core.regexes.httpProtocol,
|
||||
hostname: core.regexes.domain,
|
||||
...util.normalizeParams(params),
|
||||
});
|
||||
@@ -228,11 +359,23 @@ export const ZodNanoID = /*@__PURE__*/ core.$constructor("ZodNanoID", (inst, def
|
||||
export function nanoid(params) {
|
||||
return core._nanoid(ZodNanoID, params);
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const ZodCUID = /*@__PURE__*/ core.$constructor("ZodCUID", (inst, def) => {
|
||||
// ZodStringFormat.init(inst, def);
|
||||
core.$ZodCUID.init(inst, def);
|
||||
ZodStringFormat.init(inst, def);
|
||||
});
|
||||
/**
|
||||
* Validates a CUID v1 string.
|
||||
*
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export function cuid(params) {
|
||||
return core._cuid(ZodCUID, params);
|
||||
}
|
||||
@@ -364,22 +507,53 @@ export const ZodNumber = /*@__PURE__*/ core.$constructor("ZodNumber", (inst, def
|
||||
core.$ZodNumber.init(inst, def);
|
||||
ZodType.init(inst, def);
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.numberProcessor(inst, ctx, json, params);
|
||||
inst.gt = (value, params) => inst.check(checks.gt(value, params));
|
||||
inst.gte = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.min = (value, params) => inst.check(checks.gte(value, params));
|
||||
inst.lt = (value, params) => inst.check(checks.lt(value, params));
|
||||
inst.lte = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.max = (value, params) => inst.check(checks.lte(value, params));
|
||||
inst.int = (params) => inst.check(int(params));
|
||||
inst.safe = (params) => inst.check(int(params));
|
||||
inst.positive = (params) => inst.check(checks.gt(0, params));
|
||||
inst.nonnegative = (params) => inst.check(checks.gte(0, params));
|
||||
inst.negative = (params) => inst.check(checks.lt(0, params));
|
||||
inst.nonpositive = (params) => inst.check(checks.lte(0, params));
|
||||
inst.multipleOf = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
inst.step = (value, params) => inst.check(checks.multipleOf(value, params));
|
||||
// inst.finite = (params) => inst.check(core.finite(params));
|
||||
inst.finite = () => inst;
|
||||
_installLazyMethods(inst, "ZodNumber", {
|
||||
gt(value, params) {
|
||||
return this.check(checks.gt(value, params));
|
||||
},
|
||||
gte(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
min(value, params) {
|
||||
return this.check(checks.gte(value, params));
|
||||
},
|
||||
lt(value, params) {
|
||||
return this.check(checks.lt(value, params));
|
||||
},
|
||||
lte(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
max(value, params) {
|
||||
return this.check(checks.lte(value, params));
|
||||
},
|
||||
int(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
safe(params) {
|
||||
return this.check(int(params));
|
||||
},
|
||||
positive(params) {
|
||||
return this.check(checks.gt(0, params));
|
||||
},
|
||||
nonnegative(params) {
|
||||
return this.check(checks.gte(0, params));
|
||||
},
|
||||
negative(params) {
|
||||
return this.check(checks.lt(0, params));
|
||||
},
|
||||
nonpositive(params) {
|
||||
return this.check(checks.lte(0, params));
|
||||
},
|
||||
multipleOf(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
step(value, params) {
|
||||
return this.check(checks.multipleOf(value, params));
|
||||
},
|
||||
finite() {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
const bag = inst._zod.bag;
|
||||
inst.minValue =
|
||||
Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null;
|
||||
@@ -533,11 +707,23 @@ export const ZodArray = /*@__PURE__*/ core.$constructor("ZodArray", (inst, def)
|
||||
ZodType.init(inst, def);
|
||||
inst._zod.processJSONSchema = (ctx, json, params) => processors.arrayProcessor(inst, ctx, json, params);
|
||||
inst.element = def.element;
|
||||
inst.min = (minLength, params) => inst.check(checks.minLength(minLength, params));
|
||||
inst.nonempty = (params) => inst.check(checks.minLength(1, params));
|
||||
inst.max = (maxLength, params) => inst.check(checks.maxLength(maxLength, params));
|
||||
inst.length = (len, params) => inst.check(checks.length(len, params));
|
||||
inst.unwrap = () => inst.element;
|
||||
_installLazyMethods(inst, "ZodArray", {
|
||||
min(n, params) {
|
||||
return this.check(checks.minLength(n, params));
|
||||
},
|
||||
nonempty(params) {
|
||||
return this.check(checks.minLength(1, params));
|
||||
},
|
||||
max(n, params) {
|
||||
return this.check(checks.maxLength(n, params));
|
||||
},
|
||||
length(n, params) {
|
||||
return this.check(checks.length(n, params));
|
||||
},
|
||||
unwrap() {
|
||||
return this.element;
|
||||
},
|
||||
});
|
||||
});
|
||||
export function array(element, params) {
|
||||
return core._array(ZodArray, element, params);
|
||||
@@ -554,23 +740,47 @@ export const ZodObject = /*@__PURE__*/ core.$constructor("ZodObject", (inst, def
|
||||
util.defineLazy(inst, "shape", () => {
|
||||
return def.shape;
|
||||
});
|
||||
inst.keyof = () => _enum(Object.keys(inst._zod.def.shape));
|
||||
inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall });
|
||||
inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
||||
inst.strict = () => inst.clone({ ...inst._zod.def, catchall: never() });
|
||||
inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
|
||||
inst.extend = (incoming) => {
|
||||
return util.extend(inst, incoming);
|
||||
};
|
||||
inst.safeExtend = (incoming) => {
|
||||
return util.safeExtend(inst, incoming);
|
||||
};
|
||||
inst.merge = (other) => util.merge(inst, other);
|
||||
inst.pick = (mask) => util.pick(inst, mask);
|
||||
inst.omit = (mask) => util.omit(inst, mask);
|
||||
inst.partial = (...args) => util.partial(ZodOptional, inst, args[0]);
|
||||
inst.required = (...args) => util.required(ZodNonOptional, inst, args[0]);
|
||||
_installLazyMethods(inst, "ZodObject", {
|
||||
keyof() {
|
||||
return _enum(Object.keys(this._zod.def.shape));
|
||||
},
|
||||
catchall(catchall) {
|
||||
return this.clone({ ...this._zod.def, catchall: catchall });
|
||||
},
|
||||
passthrough() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
loose() {
|
||||
return this.clone({ ...this._zod.def, catchall: unknown() });
|
||||
},
|
||||
strict() {
|
||||
return this.clone({ ...this._zod.def, catchall: never() });
|
||||
},
|
||||
strip() {
|
||||
return this.clone({ ...this._zod.def, catchall: undefined });
|
||||
},
|
||||
extend(incoming) {
|
||||
return util.extend(this, incoming);
|
||||
},
|
||||
safeExtend(incoming) {
|
||||
return util.safeExtend(this, incoming);
|
||||
},
|
||||
merge(other) {
|
||||
return util.merge(this, other);
|
||||
},
|
||||
pick(mask) {
|
||||
return util.pick(this, mask);
|
||||
},
|
||||
omit(mask) {
|
||||
return util.omit(this, mask);
|
||||
},
|
||||
partial(...args) {
|
||||
return util.partial(ZodOptional, this, args[0]);
|
||||
},
|
||||
required(...args) {
|
||||
return util.required(ZodNonOptional, this, args[0]);
|
||||
},
|
||||
});
|
||||
});
|
||||
export function object(shape, params) {
|
||||
const def = {
|
||||
@@ -681,6 +891,15 @@ export const ZodRecord = /*@__PURE__*/ core.$constructor("ZodRecord", (inst, def
|
||||
inst.valueType = def.valueType;
|
||||
});
|
||||
export function record(keyType, valueType, params) {
|
||||
// v3-compat: z.record(valueType, params?) — defaults keyType to z.string()
|
||||
if (!valueType || !valueType._zod) {
|
||||
return new ZodRecord({
|
||||
type: "record",
|
||||
keyType: string(),
|
||||
valueType: keyType,
|
||||
...util.normalizeParams(valueType),
|
||||
});
|
||||
}
|
||||
return new ZodRecord({
|
||||
type: "record",
|
||||
keyType,
|
||||
@@ -866,10 +1085,12 @@ export const ZodTransform = /*@__PURE__*/ core.$constructor("ZodTransform", (ins
|
||||
if (output instanceof Promise) {
|
||||
return output.then((output) => {
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
});
|
||||
}
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
};
|
||||
});
|
||||
@@ -1026,6 +1247,20 @@ export function codec(in_, out, params) {
|
||||
reverseTransform: params.encode,
|
||||
});
|
||||
}
|
||||
export function invertCodec(codec) {
|
||||
const def = codec._zod.def;
|
||||
return new ZodCodec({
|
||||
type: "pipe",
|
||||
in: def.out,
|
||||
out: def.in,
|
||||
transform: def.reverseTransform,
|
||||
reverseTransform: def.transform,
|
||||
});
|
||||
}
|
||||
export const ZodPreprocess = /*@__PURE__*/ core.$constructor("ZodPreprocess", (inst, def) => {
|
||||
ZodPipe.init(inst, def);
|
||||
core.$ZodPreprocess.init(inst, def);
|
||||
});
|
||||
export const ZodReadonly = /*@__PURE__*/ core.$constructor("ZodReadonly", (inst, def) => {
|
||||
core.$ZodReadonly.init(inst, def);
|
||||
ZodType.init(inst, def);
|
||||
@@ -1108,8 +1343,8 @@ export function refine(fn, _params = {}) {
|
||||
return core._refine(ZodCustom, fn, _params);
|
||||
}
|
||||
// superRefine
|
||||
export function superRefine(fn) {
|
||||
return core._superRefine(fn);
|
||||
export function superRefine(fn, params) {
|
||||
return core._superRefine(fn, params);
|
||||
}
|
||||
// Re-export describe and meta from core
|
||||
export const describe = core.describe;
|
||||
@@ -1151,7 +1386,10 @@ export function json(params) {
|
||||
return jsonSchema;
|
||||
}
|
||||
// preprocess
|
||||
// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */
|
||||
export function preprocess(fn, schema) {
|
||||
return pipe(transform(fn), schema);
|
||||
return new ZodPreprocess({
|
||||
type: "pipe",
|
||||
in: transform(fn),
|
||||
out: schema,
|
||||
});
|
||||
}
|
||||
|
||||
+7
-2
@@ -256,6 +256,11 @@ function _nanoid(Class, params) {
|
||||
...util.normalizeParams(params),
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
function _cuid(Class, params) {
|
||||
return new Class({
|
||||
@@ -1094,7 +1099,7 @@ function _refine(Class, fn, _params) {
|
||||
return schema;
|
||||
}
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
function _superRefine(fn) {
|
||||
function _superRefine(fn, params) {
|
||||
const ch = _check((payload) => {
|
||||
payload.addIssue = (issue) => {
|
||||
if (typeof issue === "string") {
|
||||
@@ -1113,7 +1118,7 @@ function _superRefine(fn) {
|
||||
}
|
||||
};
|
||||
return fn(payload.value, payload);
|
||||
});
|
||||
}, params);
|
||||
return ch;
|
||||
}
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
|
||||
+26
-5
@@ -49,8 +49,23 @@ export declare function _emoji<T extends schemas.$ZodEmoji>(Class: util.SchemaCl
|
||||
export type $ZodNanoIDParams = StringFormatParams<schemas.$ZodNanoID, "when">;
|
||||
export type $ZodCheckNanoIDParams = CheckStringFormatParams<schemas.$ZodNanoID, "when">;
|
||||
export declare function _nanoid<T extends schemas.$ZodNanoID>(Class: util.SchemaClass<T>, params?: string | $ZodNanoIDParams | $ZodCheckNanoIDParams): T;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCUIDParams = StringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCheckCUIDParams = CheckStringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare function _cuid<T extends schemas.$ZodCUID>(Class: util.SchemaClass<T>, params?: string | $ZodCUIDParams | $ZodCheckCUIDParams): T;
|
||||
export type $ZodCUID2Params = StringFormatParams<schemas.$ZodCUID2, "when">;
|
||||
export type $ZodCheckCUID2Params = CheckStringFormatParams<schemas.$ZodCUID2, "when">;
|
||||
@@ -210,14 +225,16 @@ export type $ZodUnionParams = TypeParams<schemas.$ZodUnion, "options">;
|
||||
export declare function _union<const T extends readonly schemas.$ZodObject[]>(Class: util.SchemaClass<schemas.$ZodUnion>, options: T, params?: string | $ZodUnionParams): schemas.$ZodUnion<T>;
|
||||
export type $ZodXorParams = TypeParams<schemas.$ZodXor, "options">;
|
||||
export declare function _xor<const T extends readonly schemas.$ZodObject[]>(Class: util.SchemaClass<schemas.$ZodXor>, options: T, params?: string | $ZodXorParams): schemas.$ZodXor<T>;
|
||||
export interface $ZodTypeDiscriminableInternals extends schemas.$ZodTypeInternals {
|
||||
export interface $ZodTypeDiscriminableInternals<Disc extends string = string> extends schemas.$ZodTypeInternals<unknown, {
|
||||
[K in Disc]?: unknown;
|
||||
}> {
|
||||
propValues: util.PropValues;
|
||||
}
|
||||
export interface $ZodTypeDiscriminable extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals;
|
||||
export interface $ZodTypeDiscriminable<Disc extends string = string> extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals<Disc>;
|
||||
}
|
||||
export type $ZodDiscriminatedUnionParams = TypeParams<schemas.$ZodDiscriminatedUnion, "options" | "discriminator">;
|
||||
export declare function _discriminatedUnion<Types extends [$ZodTypeDiscriminable, ...$ZodTypeDiscriminable[]], Disc extends string>(Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>, discriminator: Disc, options: Types, params?: string | $ZodDiscriminatedUnionParams): schemas.$ZodDiscriminatedUnion<Types, Disc>;
|
||||
export declare function _discriminatedUnion<Types extends [$ZodTypeDiscriminable<Disc>, ...$ZodTypeDiscriminable<Disc>[]], Disc extends string>(Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>, discriminator: Disc, options: Types, params?: string | $ZodDiscriminatedUnionParams): schemas.$ZodDiscriminatedUnion<Types, Disc>;
|
||||
export type $ZodIntersectionParams = TypeParams<schemas.$ZodIntersection, "left" | "right">;
|
||||
export declare function _intersection<T extends schemas.$ZodObject, U extends schemas.$ZodObject>(Class: util.SchemaClass<schemas.$ZodIntersection>, left: T, right: U): schemas.$ZodIntersection<T, U>;
|
||||
export type $ZodTupleParams = TypeParams<schemas.$ZodTuple, "items" | "rest">;
|
||||
@@ -282,7 +299,11 @@ type RawIssue<T extends errors.$ZodIssueBase> = T extends any ? util.Flatten<uti
|
||||
export interface $RefinementCtx<T = unknown> extends schemas.ParsePayload<T> {
|
||||
addIssue(arg: string | $ZodSuperRefineIssue): void;
|
||||
}
|
||||
export declare function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>): checks.$ZodCheck<T>;
|
||||
export interface $ZodSuperRefineParams {
|
||||
/** If provided, the refinement runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
export declare function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>, params?: $ZodSuperRefineParams): checks.$ZodCheck<T>;
|
||||
export declare function _check<O = unknown>(fn: schemas.CheckFn<O>, params?: string | $ZodCustomParams): checks.$ZodCheck<O>;
|
||||
export declare function describe<T>(description: string): checks.$ZodCheck<T>;
|
||||
export declare function meta<T>(metadata: registries.GlobalMeta): checks.$ZodCheck<T>;
|
||||
|
||||
+26
-5
@@ -49,8 +49,23 @@ export declare function _emoji<T extends schemas.$ZodEmoji>(Class: util.SchemaCl
|
||||
export type $ZodNanoIDParams = StringFormatParams<schemas.$ZodNanoID, "when">;
|
||||
export type $ZodCheckNanoIDParams = CheckStringFormatParams<schemas.$ZodNanoID, "when">;
|
||||
export declare function _nanoid<T extends schemas.$ZodNanoID>(Class: util.SchemaClass<T>, params?: string | $ZodNanoIDParams | $ZodCheckNanoIDParams): T;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCUIDParams = StringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export type $ZodCheckCUIDParams = CheckStringFormatParams<schemas.$ZodCUID, "when">;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare function _cuid<T extends schemas.$ZodCUID>(Class: util.SchemaClass<T>, params?: string | $ZodCUIDParams | $ZodCheckCUIDParams): T;
|
||||
export type $ZodCUID2Params = StringFormatParams<schemas.$ZodCUID2, "when">;
|
||||
export type $ZodCheckCUID2Params = CheckStringFormatParams<schemas.$ZodCUID2, "when">;
|
||||
@@ -210,14 +225,16 @@ export type $ZodUnionParams = TypeParams<schemas.$ZodUnion, "options">;
|
||||
export declare function _union<const T extends readonly schemas.$ZodObject[]>(Class: util.SchemaClass<schemas.$ZodUnion>, options: T, params?: string | $ZodUnionParams): schemas.$ZodUnion<T>;
|
||||
export type $ZodXorParams = TypeParams<schemas.$ZodXor, "options">;
|
||||
export declare function _xor<const T extends readonly schemas.$ZodObject[]>(Class: util.SchemaClass<schemas.$ZodXor>, options: T, params?: string | $ZodXorParams): schemas.$ZodXor<T>;
|
||||
export interface $ZodTypeDiscriminableInternals extends schemas.$ZodTypeInternals {
|
||||
export interface $ZodTypeDiscriminableInternals<Disc extends string = string> extends schemas.$ZodTypeInternals<unknown, {
|
||||
[K in Disc]?: unknown;
|
||||
}> {
|
||||
propValues: util.PropValues;
|
||||
}
|
||||
export interface $ZodTypeDiscriminable extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals;
|
||||
export interface $ZodTypeDiscriminable<Disc extends string = string> extends schemas.$ZodType {
|
||||
_zod: $ZodTypeDiscriminableInternals<Disc>;
|
||||
}
|
||||
export type $ZodDiscriminatedUnionParams = TypeParams<schemas.$ZodDiscriminatedUnion, "options" | "discriminator">;
|
||||
export declare function _discriminatedUnion<Types extends [$ZodTypeDiscriminable, ...$ZodTypeDiscriminable[]], Disc extends string>(Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>, discriminator: Disc, options: Types, params?: string | $ZodDiscriminatedUnionParams): schemas.$ZodDiscriminatedUnion<Types, Disc>;
|
||||
export declare function _discriminatedUnion<Types extends [$ZodTypeDiscriminable<Disc>, ...$ZodTypeDiscriminable<Disc>[]], Disc extends string>(Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>, discriminator: Disc, options: Types, params?: string | $ZodDiscriminatedUnionParams): schemas.$ZodDiscriminatedUnion<Types, Disc>;
|
||||
export type $ZodIntersectionParams = TypeParams<schemas.$ZodIntersection, "left" | "right">;
|
||||
export declare function _intersection<T extends schemas.$ZodObject, U extends schemas.$ZodObject>(Class: util.SchemaClass<schemas.$ZodIntersection>, left: T, right: U): schemas.$ZodIntersection<T, U>;
|
||||
export type $ZodTupleParams = TypeParams<schemas.$ZodTuple, "items" | "rest">;
|
||||
@@ -282,7 +299,11 @@ type RawIssue<T extends errors.$ZodIssueBase> = T extends any ? util.Flatten<uti
|
||||
export interface $RefinementCtx<T = unknown> extends schemas.ParsePayload<T> {
|
||||
addIssue(arg: string | $ZodSuperRefineIssue): void;
|
||||
}
|
||||
export declare function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>): checks.$ZodCheck<T>;
|
||||
export interface $ZodSuperRefineParams {
|
||||
/** If provided, the refinement runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
export declare function _superRefine<T>(fn: (arg: T, payload: $RefinementCtx<T>) => void | Promise<void>, params?: $ZodSuperRefineParams): checks.$ZodCheck<T>;
|
||||
export declare function _check<O = unknown>(fn: schemas.CheckFn<O>, params?: string | $ZodCustomParams): checks.$ZodCheck<O>;
|
||||
export declare function describe<T>(description: string): checks.$ZodCheck<T>;
|
||||
export declare function meta<T>(metadata: registries.GlobalMeta): checks.$ZodCheck<T>;
|
||||
|
||||
+7
-2
@@ -110,6 +110,11 @@ export function _nanoid(Class, params) {
|
||||
...util.normalizeParams(params),
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link _cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _cuid(Class, params) {
|
||||
return new Class({
|
||||
@@ -954,7 +959,7 @@ export function _refine(Class, fn, _params) {
|
||||
return schema;
|
||||
}
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
export function _superRefine(fn) {
|
||||
export function _superRefine(fn, params) {
|
||||
const ch = _check((payload) => {
|
||||
payload.addIssue = (issue) => {
|
||||
if (typeof issue === "string") {
|
||||
@@ -973,7 +978,7 @@ export function _superRefine(fn) {
|
||||
}
|
||||
};
|
||||
return fn(payload.value, payload);
|
||||
});
|
||||
}, params);
|
||||
return ch;
|
||||
}
|
||||
// @__NO_SIDE_EFFECTS__
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export interface $ZodCheckDef {
|
||||
error?: errors.$ZodErrorMap<never> | undefined;
|
||||
/** If true, no later checks will be executed if this check fails. Default `false`. */
|
||||
abort?: boolean | undefined;
|
||||
/** If provided, this check will only be executed if the function returns `true`. Defaults to `payload => z.util.isAborted(payload)`. */
|
||||
/** If provided, the check runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
export interface $ZodCheckInternals<T> {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export interface $ZodCheckDef {
|
||||
error?: errors.$ZodErrorMap<never> | undefined;
|
||||
/** If true, no later checks will be executed if this check fails. Default `false`. */
|
||||
abort?: boolean | undefined;
|
||||
/** If provided, this check will only be executed if the function returns `true`. Defaults to `payload => z.util.isAborted(payload)`. */
|
||||
/** If provided, the check runs only when this returns `true`. By default, it is skipped if prior parsing produced aborting issues. */
|
||||
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
||||
}
|
||||
export interface $ZodCheckInternals<T> {
|
||||
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
"use strict";
|
||||
var _a;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.globalConfig = exports.$ZodEncodeError = exports.$ZodAsyncError = exports.$brand = exports.NEVER = void 0;
|
||||
exports.$constructor = $constructor;
|
||||
@@ -75,7 +76,8 @@ class $ZodEncodeError extends Error {
|
||||
}
|
||||
}
|
||||
exports.$ZodEncodeError = $ZodEncodeError;
|
||||
exports.globalConfig = {};
|
||||
(_a = globalThis).__zod_globalConfig ?? (_a.__zod_globalConfig = {});
|
||||
exports.globalConfig = globalThis.__zod_globalConfig;
|
||||
function config(newConfig) {
|
||||
if (newConfig)
|
||||
Object.assign(exports.globalConfig, newConfig);
|
||||
|
||||
+4
-2
@@ -1,5 +1,6 @@
|
||||
var _a;
|
||||
/** A special constant with type `never` */
|
||||
export const NEVER = Object.freeze({
|
||||
export const NEVER = /*@__PURE__*/ Object.freeze({
|
||||
status: "aborted",
|
||||
});
|
||||
export /*@__NO_SIDE_EFFECTS__*/ function $constructor(name, initializer, params) {
|
||||
@@ -68,7 +69,8 @@ export class $ZodEncodeError extends Error {
|
||||
this.name = "ZodEncodeError";
|
||||
}
|
||||
}
|
||||
export const globalConfig = {};
|
||||
(_a = globalThis).__zod_globalConfig ?? (_a.__zod_globalConfig = {});
|
||||
export const globalConfig = globalThis.__zod_globalConfig;
|
||||
export function config(newConfig) {
|
||||
if (newConfig)
|
||||
Object.assign(globalConfig, newConfig);
|
||||
|
||||
+26
-23
@@ -65,35 +65,38 @@ function flattenError(error, mapper = (issue) => issue.message) {
|
||||
}
|
||||
function formatError(error, mapper = (issue) => issue.message) {
|
||||
const fieldErrors = { _errors: [] };
|
||||
const processError = (error) => {
|
||||
const processError = (error, path = []) => {
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
issue.errors.map((issues) => processError({ issues }));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
}
|
||||
else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues });
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues });
|
||||
}
|
||||
else if (issue.path.length === 0) {
|
||||
fieldErrors._errors.push(mapper(issue));
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else {
|
||||
let curr = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < issue.path.length) {
|
||||
const el = issue.path[i];
|
||||
const terminal = i === issue.path.length - 1;
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
const fullpath = [...path, ...issue.path];
|
||||
if (fullpath.length === 0) {
|
||||
fieldErrors._errors.push(mapper(issue));
|
||||
}
|
||||
else {
|
||||
let curr = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < fullpath.length) {
|
||||
const el = fullpath[i];
|
||||
const terminal = i === fullpath.length - 1;
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
}
|
||||
else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
}
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
}
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,13 +111,13 @@ function treeifyError(error, mapper = (issue) => issue.message) {
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
// regular union error
|
||||
issue.errors.map((issues) => processError({ issues }, issue.path));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
}
|
||||
else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else {
|
||||
const fullpath = [...path, ...issue.path];
|
||||
|
||||
+1
@@ -54,6 +54,7 @@ interface $ZodIssueInvalidUnionNoMatch extends $ZodIssueBase {
|
||||
readonly errors: $ZodIssue[][];
|
||||
readonly input?: unknown;
|
||||
readonly discriminator?: string | undefined;
|
||||
readonly options?: util.Primitive[];
|
||||
readonly inclusive?: true;
|
||||
}
|
||||
interface $ZodIssueInvalidUnionMultipleMatch extends $ZodIssueBase {
|
||||
|
||||
+1
@@ -54,6 +54,7 @@ interface $ZodIssueInvalidUnionNoMatch extends $ZodIssueBase {
|
||||
readonly errors: $ZodIssue[][];
|
||||
readonly input?: unknown;
|
||||
readonly discriminator?: string | undefined;
|
||||
readonly options?: util.Primitive[];
|
||||
readonly inclusive?: true;
|
||||
}
|
||||
interface $ZodIssueInvalidUnionMultipleMatch extends $ZodIssueBase {
|
||||
|
||||
+26
-23
@@ -34,35 +34,38 @@ export function flattenError(error, mapper = (issue) => issue.message) {
|
||||
}
|
||||
export function formatError(error, mapper = (issue) => issue.message) {
|
||||
const fieldErrors = { _errors: [] };
|
||||
const processError = (error) => {
|
||||
const processError = (error, path = []) => {
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
issue.errors.map((issues) => processError({ issues }));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
}
|
||||
else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues });
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues });
|
||||
}
|
||||
else if (issue.path.length === 0) {
|
||||
fieldErrors._errors.push(mapper(issue));
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else {
|
||||
let curr = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < issue.path.length) {
|
||||
const el = issue.path[i];
|
||||
const terminal = i === issue.path.length - 1;
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
const fullpath = [...path, ...issue.path];
|
||||
if (fullpath.length === 0) {
|
||||
fieldErrors._errors.push(mapper(issue));
|
||||
}
|
||||
else {
|
||||
let curr = fieldErrors;
|
||||
let i = 0;
|
||||
while (i < fullpath.length) {
|
||||
const el = fullpath[i];
|
||||
const terminal = i === fullpath.length - 1;
|
||||
if (!terminal) {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
}
|
||||
else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
}
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
curr[el] = curr[el] || { _errors: [] };
|
||||
curr[el]._errors.push(mapper(issue));
|
||||
}
|
||||
curr = curr[el];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,13 +80,13 @@ export function treeifyError(error, mapper = (issue) => issue.message) {
|
||||
for (const issue of error.issues) {
|
||||
if (issue.code === "invalid_union" && issue.errors.length) {
|
||||
// regular union error
|
||||
issue.errors.map((issues) => processError({ issues }, issue.path));
|
||||
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
|
||||
}
|
||||
else if (issue.code === "invalid_key") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else if (issue.code === "invalid_element") {
|
||||
processError({ issues: issue.issues }, issue.path);
|
||||
processError({ issues: issue.issues }, [...path, ...issue.path]);
|
||||
}
|
||||
else {
|
||||
const fullpath = [...path, ...issue.path];
|
||||
|
||||
+16
-20
@@ -58,8 +58,12 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.type = "integer";
|
||||
else
|
||||
json.type = "number";
|
||||
if (typeof exclusiveMinimum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
// when both minimum and exclusiveMinimum exist, pick the more restrictive one
|
||||
const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
|
||||
const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
|
||||
const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
|
||||
if (exMin) {
|
||||
if (legacy) {
|
||||
json.minimum = exclusiveMinimum;
|
||||
json.exclusiveMinimum = true;
|
||||
}
|
||||
@@ -67,17 +71,11 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.exclusiveMinimum = exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
if (typeof minimum === "number") {
|
||||
else if (typeof minimum === "number") {
|
||||
json.minimum = minimum;
|
||||
if (typeof exclusiveMinimum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMinimum >= minimum)
|
||||
delete json.minimum;
|
||||
else
|
||||
delete json.exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
if (typeof exclusiveMaximum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
if (exMax) {
|
||||
if (legacy) {
|
||||
json.maximum = exclusiveMaximum;
|
||||
json.exclusiveMaximum = true;
|
||||
}
|
||||
@@ -85,14 +83,8 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.exclusiveMaximum = exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
if (typeof maximum === "number") {
|
||||
else if (typeof maximum === "number") {
|
||||
json.maximum = maximum;
|
||||
if (typeof exclusiveMaximum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMaximum <= maximum)
|
||||
delete json.maximum;
|
||||
else
|
||||
delete json.exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
if (typeof multipleOf === "number")
|
||||
json.multipleOf = multipleOf;
|
||||
@@ -302,7 +294,10 @@ const arrayProcessor = (schema, ctx, _json, params) => {
|
||||
if (typeof maximum === "number")
|
||||
json.maxItems = maximum;
|
||||
json.type = "array";
|
||||
json.items = (0, to_json_schema_js_1.process)(def.element, ctx, { ...params, path: [...params.path, "items"] });
|
||||
json.items = (0, to_json_schema_js_1.process)(def.element, ctx, {
|
||||
...params,
|
||||
path: [...params.path, "items"],
|
||||
});
|
||||
};
|
||||
exports.arrayProcessor = arrayProcessor;
|
||||
const objectProcessor = (schema, ctx, _json, params) => {
|
||||
@@ -530,7 +525,8 @@ const catchProcessor = (schema, ctx, json, params) => {
|
||||
exports.catchProcessor = catchProcessor;
|
||||
const pipeProcessor = (schema, ctx, _json, params) => {
|
||||
const def = schema._zod.def;
|
||||
const innerType = ctx.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out;
|
||||
const inIsTransform = def.in._zod.traits.has("$ZodTransform");
|
||||
const innerType = ctx.io === "input" ? (inIsTransform ? def.out : def.in) : def.out;
|
||||
(0, to_json_schema_js_1.process)(innerType, ctx, params);
|
||||
const seen = ctx.seen.get(schema);
|
||||
seen.ref = innerType;
|
||||
|
||||
+16
-20
@@ -53,8 +53,12 @@ export const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.type = "integer";
|
||||
else
|
||||
json.type = "number";
|
||||
if (typeof exclusiveMinimum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
// when both minimum and exclusiveMinimum exist, pick the more restrictive one
|
||||
const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
|
||||
const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
|
||||
const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
|
||||
if (exMin) {
|
||||
if (legacy) {
|
||||
json.minimum = exclusiveMinimum;
|
||||
json.exclusiveMinimum = true;
|
||||
}
|
||||
@@ -62,17 +66,11 @@ export const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.exclusiveMinimum = exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
if (typeof minimum === "number") {
|
||||
else if (typeof minimum === "number") {
|
||||
json.minimum = minimum;
|
||||
if (typeof exclusiveMinimum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMinimum >= minimum)
|
||||
delete json.minimum;
|
||||
else
|
||||
delete json.exclusiveMinimum;
|
||||
}
|
||||
}
|
||||
if (typeof exclusiveMaximum === "number") {
|
||||
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
||||
if (exMax) {
|
||||
if (legacy) {
|
||||
json.maximum = exclusiveMaximum;
|
||||
json.exclusiveMaximum = true;
|
||||
}
|
||||
@@ -80,14 +78,8 @@ export const numberProcessor = (schema, ctx, _json, _params) => {
|
||||
json.exclusiveMaximum = exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
if (typeof maximum === "number") {
|
||||
else if (typeof maximum === "number") {
|
||||
json.maximum = maximum;
|
||||
if (typeof exclusiveMaximum === "number" && ctx.target !== "draft-04") {
|
||||
if (exclusiveMaximum <= maximum)
|
||||
delete json.maximum;
|
||||
else
|
||||
delete json.exclusiveMaximum;
|
||||
}
|
||||
}
|
||||
if (typeof multipleOf === "number")
|
||||
json.multipleOf = multipleOf;
|
||||
@@ -275,7 +267,10 @@ export const arrayProcessor = (schema, ctx, _json, params) => {
|
||||
if (typeof maximum === "number")
|
||||
json.maxItems = maximum;
|
||||
json.type = "array";
|
||||
json.items = process(def.element, ctx, { ...params, path: [...params.path, "items"] });
|
||||
json.items = process(def.element, ctx, {
|
||||
...params,
|
||||
path: [...params.path, "items"],
|
||||
});
|
||||
};
|
||||
export const objectProcessor = (schema, ctx, _json, params) => {
|
||||
const json = _json;
|
||||
@@ -492,7 +487,8 @@ export const catchProcessor = (schema, ctx, json, params) => {
|
||||
};
|
||||
export const pipeProcessor = (schema, ctx, _json, params) => {
|
||||
const def = schema._zod.def;
|
||||
const innerType = ctx.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out;
|
||||
const inIsTransform = def.in._zod.traits.has("$ZodTransform");
|
||||
const innerType = ctx.io === "input" ? (inIsTransform ? def.out : def.in) : def.out;
|
||||
process(innerType, ctx, params);
|
||||
const seen = ctx.seen.get(schema);
|
||||
seen.ref = innerType;
|
||||
|
||||
+2
-1
@@ -2,5 +2,6 @@
|
||||
"type": "module",
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.cts"
|
||||
"types": "./index.d.cts",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
+7
-7
@@ -28,7 +28,7 @@ const core = __importStar(require("./core.cjs"));
|
||||
const errors = __importStar(require("./errors.cjs"));
|
||||
const util = __importStar(require("./util.cjs"));
|
||||
const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
||||
const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
|
||||
const result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
throw new core.$ZodAsyncError();
|
||||
@@ -43,7 +43,7 @@ const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
||||
exports._parse = _parse;
|
||||
exports.parse = (0, exports._parse)(errors.$ZodRealError);
|
||||
const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise)
|
||||
result = await result;
|
||||
@@ -72,7 +72,7 @@ const _safeParse = (_Err) => (schema, value, _ctx) => {
|
||||
exports._safeParse = _safeParse;
|
||||
exports.safeParse = (0, exports._safeParse)(errors.$ZodRealError);
|
||||
const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise)
|
||||
result = await result;
|
||||
@@ -86,7 +86,7 @@ const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
exports._safeParseAsync = _safeParseAsync;
|
||||
exports.safeParseAsync = (0, exports._safeParseAsync)(errors.$ZodRealError);
|
||||
const _encode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return (0, exports._parse)(_Err)(schema, value, ctx);
|
||||
};
|
||||
exports._encode = _encode;
|
||||
@@ -97,7 +97,7 @@ const _decode = (_Err) => (schema, value, _ctx) => {
|
||||
exports._decode = _decode;
|
||||
exports.decode = (0, exports._decode)(errors.$ZodRealError);
|
||||
const _encodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return (0, exports._parseAsync)(_Err)(schema, value, ctx);
|
||||
};
|
||||
exports._encodeAsync = _encodeAsync;
|
||||
@@ -108,7 +108,7 @@ const _decodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
exports._decodeAsync = _decodeAsync;
|
||||
exports.decodeAsync = (0, exports._decodeAsync)(errors.$ZodRealError);
|
||||
const _safeEncode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return (0, exports._safeParse)(_Err)(schema, value, ctx);
|
||||
};
|
||||
exports._safeEncode = _safeEncode;
|
||||
@@ -119,7 +119,7 @@ const _safeDecode = (_Err) => (schema, value, _ctx) => {
|
||||
exports._safeDecode = _safeDecode;
|
||||
exports.safeDecode = (0, exports._safeDecode)(errors.$ZodRealError);
|
||||
const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return (0, exports._safeParseAsync)(_Err)(schema, value, ctx);
|
||||
};
|
||||
exports._safeEncodeAsync = _safeEncodeAsync;
|
||||
|
||||
+7
-7
@@ -2,7 +2,7 @@ import * as core from "./core.js";
|
||||
import * as errors from "./errors.js";
|
||||
import * as util from "./util.js";
|
||||
export const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
||||
const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
|
||||
const result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
throw new core.$ZodAsyncError();
|
||||
@@ -16,7 +16,7 @@ export const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
||||
};
|
||||
export const parse = /* @__PURE__*/ _parse(errors.$ZodRealError);
|
||||
export const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise)
|
||||
result = await result;
|
||||
@@ -43,7 +43,7 @@ export const _safeParse = (_Err) => (schema, value, _ctx) => {
|
||||
};
|
||||
export const safeParse = /* @__PURE__*/ _safeParse(errors.$ZodRealError);
|
||||
export const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
||||
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
||||
let result = schema._zod.run({ value, issues: [] }, ctx);
|
||||
if (result instanceof Promise)
|
||||
result = await result;
|
||||
@@ -56,7 +56,7 @@ export const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
};
|
||||
export const safeParseAsync = /* @__PURE__*/ _safeParseAsync(errors.$ZodRealError);
|
||||
export const _encode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return _parse(_Err)(schema, value, ctx);
|
||||
};
|
||||
export const encode = /* @__PURE__*/ _encode(errors.$ZodRealError);
|
||||
@@ -65,7 +65,7 @@ export const _decode = (_Err) => (schema, value, _ctx) => {
|
||||
};
|
||||
export const decode = /* @__PURE__*/ _decode(errors.$ZodRealError);
|
||||
export const _encodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return _parseAsync(_Err)(schema, value, ctx);
|
||||
};
|
||||
export const encodeAsync = /* @__PURE__*/ _encodeAsync(errors.$ZodRealError);
|
||||
@@ -74,7 +74,7 @@ export const _decodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
};
|
||||
export const decodeAsync = /* @__PURE__*/ _decodeAsync(errors.$ZodRealError);
|
||||
export const _safeEncode = (_Err) => (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return _safeParse(_Err)(schema, value, ctx);
|
||||
};
|
||||
export const safeEncode = /* @__PURE__*/ _safeEncode(errors.$ZodRealError);
|
||||
@@ -83,7 +83,7 @@ export const _safeDecode = (_Err) => (schema, value, _ctx) => {
|
||||
};
|
||||
export const safeDecode = /* @__PURE__*/ _safeDecode(errors.$ZodRealError);
|
||||
export const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => {
|
||||
const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" };
|
||||
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
||||
return _safeParseAsync(_Err)(schema, value, ctx);
|
||||
};
|
||||
export const safeEncodeAsync = /* @__PURE__*/ _safeEncodeAsync(errors.$ZodRealError);
|
||||
|
||||
+9
-3
@@ -23,13 +23,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sha384_hex = exports.sha256_base64url = exports.sha256_base64 = exports.sha256_hex = exports.sha1_base64url = exports.sha1_base64 = exports.sha1_hex = exports.md5_base64url = exports.md5_base64 = exports.md5_hex = exports.hex = exports.uppercase = exports.lowercase = exports.undefined = exports.null = exports.boolean = exports.number = exports.integer = exports.bigint = exports.string = exports.date = exports.e164 = exports.domain = exports.hostname = exports.base64url = exports.base64 = exports.cidrv6 = exports.cidrv4 = exports.mac = exports.ipv6 = exports.ipv4 = exports.browserEmail = exports.idnEmail = exports.unicodeEmail = exports.rfc5322Email = exports.html5Email = exports.email = exports.uuid7 = exports.uuid6 = exports.uuid4 = exports.uuid = exports.guid = exports.extendedDuration = exports.duration = exports.nanoid = exports.ksuid = exports.xid = exports.ulid = exports.cuid2 = exports.cuid = void 0;
|
||||
exports.sha512_base64url = exports.sha512_base64 = exports.sha512_hex = exports.sha384_base64url = exports.sha384_base64 = void 0;
|
||||
exports.sha256_base64url = exports.sha256_base64 = exports.sha256_hex = exports.sha1_base64url = exports.sha1_base64 = exports.sha1_hex = exports.md5_base64url = exports.md5_base64 = exports.md5_hex = exports.hex = exports.uppercase = exports.lowercase = exports.undefined = exports.null = exports.boolean = exports.number = exports.integer = exports.bigint = exports.string = exports.date = exports.e164 = exports.httpProtocol = exports.domain = exports.hostname = exports.base64url = exports.base64 = exports.cidrv6 = exports.cidrv4 = exports.mac = exports.ipv6 = exports.ipv4 = exports.browserEmail = exports.idnEmail = exports.unicodeEmail = exports.rfc5322Email = exports.html5Email = exports.email = exports.uuid7 = exports.uuid6 = exports.uuid4 = exports.uuid = exports.guid = exports.extendedDuration = exports.duration = exports.nanoid = exports.ksuid = exports.xid = exports.ulid = exports.cuid2 = exports.cuid = void 0;
|
||||
exports.sha512_base64url = exports.sha512_base64 = exports.sha512_hex = exports.sha384_base64url = exports.sha384_base64 = exports.sha384_hex = void 0;
|
||||
exports.emoji = emoji;
|
||||
exports.time = time;
|
||||
exports.datetime = datetime;
|
||||
const util = __importStar(require("./util.cjs"));
|
||||
exports.cuid = /^[cC][^\s-]{8,}$/;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
exports.cuid = /^[cC][0-9a-z]{6,}$/;
|
||||
exports.cuid2 = /^[0-9a-z]+$/;
|
||||
exports.ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
|
||||
exports.xid = /^[0-9a-vA-V]{20}$/;
|
||||
@@ -84,6 +89,7 @@ exports.base64url = /^[A-Za-z0-9_-]*$/;
|
||||
// export const hostname: RegExp = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/;
|
||||
exports.hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
||||
exports.domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
||||
exports.httpProtocol = /^https?$/;
|
||||
// https://blog.stevenlevithan.com/archives/validate-phone-number#r4-3 (regex sans spaces)
|
||||
// E.164: leading digit must be 1-9; total digits (excluding '+') between 7-15
|
||||
exports.e164 = /^\+[1-9]\d{6,14}$/;
|
||||
|
||||
+6
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const cuid: RegExp;
|
||||
export declare const cuid2: RegExp;
|
||||
export declare const ulid: RegExp;
|
||||
@@ -37,6 +42,7 @@ export declare const base64: RegExp;
|
||||
export declare const base64url: RegExp;
|
||||
export declare const hostname: RegExp;
|
||||
export declare const domain: RegExp;
|
||||
export declare const httpProtocol: RegExp;
|
||||
export declare const e164: RegExp;
|
||||
export declare const date: RegExp;
|
||||
export declare function time(args: {
|
||||
|
||||
+6
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const cuid: RegExp;
|
||||
export declare const cuid2: RegExp;
|
||||
export declare const ulid: RegExp;
|
||||
@@ -37,6 +42,7 @@ export declare const base64: RegExp;
|
||||
export declare const base64url: RegExp;
|
||||
export declare const hostname: RegExp;
|
||||
export declare const domain: RegExp;
|
||||
export declare const httpProtocol: RegExp;
|
||||
export declare const e164: RegExp;
|
||||
export declare const date: RegExp;
|
||||
export declare function time(args: {
|
||||
|
||||
+7
-1
@@ -1,5 +1,10 @@
|
||||
import * as util from "./util.js";
|
||||
export const cuid = /^[cC][^\s-]{8,}$/;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export const cuid = /^[cC][0-9a-z]{6,}$/;
|
||||
export const cuid2 = /^[0-9a-z]+$/;
|
||||
export const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
|
||||
export const xid = /^[0-9a-vA-V]{20}$/;
|
||||
@@ -52,6 +57,7 @@ export const base64url = /^[A-Za-z0-9_-]*$/;
|
||||
// export const hostname: RegExp = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/;
|
||||
export const hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
||||
export const domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
||||
export const httpProtocol = /^https?$/;
|
||||
// https://blog.stevenlevithan.com/archives/validate-phone-number#r4-3 (regex sans spaces)
|
||||
// E.164: leading digit must be 1-9; total digits (excluding '+') between 7-15
|
||||
export const e164 = /^\+[1-9]\d{6,14}$/;
|
||||
|
||||
+211
-65
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.$ZodTuple = exports.$ZodIntersection = exports.$ZodDiscriminatedUnion = exports.$ZodXor = exports.$ZodUnion = exports.$ZodObjectJIT = exports.$ZodObject = exports.$ZodArray = exports.$ZodDate = exports.$ZodVoid = exports.$ZodNever = exports.$ZodUnknown = exports.$ZodAny = exports.$ZodNull = exports.$ZodUndefined = exports.$ZodSymbol = exports.$ZodBigIntFormat = exports.$ZodBigInt = exports.$ZodBoolean = exports.$ZodNumberFormat = exports.$ZodNumber = exports.$ZodCustomStringFormat = exports.$ZodJWT = exports.$ZodE164 = exports.$ZodBase64URL = exports.$ZodBase64 = exports.$ZodCIDRv6 = exports.$ZodCIDRv4 = exports.$ZodMAC = exports.$ZodIPv6 = exports.$ZodIPv4 = exports.$ZodISODuration = exports.$ZodISOTime = exports.$ZodISODate = exports.$ZodISODateTime = exports.$ZodKSUID = exports.$ZodXID = exports.$ZodULID = exports.$ZodCUID2 = exports.$ZodCUID = exports.$ZodNanoID = exports.$ZodEmoji = exports.$ZodURL = exports.$ZodEmail = exports.$ZodUUID = exports.$ZodGUID = exports.$ZodStringFormat = exports.$ZodString = exports.clone = exports.$ZodType = void 0;
|
||||
exports.$ZodCustom = exports.$ZodLazy = exports.$ZodPromise = exports.$ZodFunction = exports.$ZodTemplateLiteral = exports.$ZodReadonly = exports.$ZodCodec = exports.$ZodPipe = exports.$ZodNaN = exports.$ZodCatch = exports.$ZodSuccess = exports.$ZodNonOptional = exports.$ZodPrefault = exports.$ZodDefault = exports.$ZodNullable = exports.$ZodExactOptional = exports.$ZodOptional = exports.$ZodTransform = exports.$ZodFile = exports.$ZodLiteral = exports.$ZodEnum = exports.$ZodSet = exports.$ZodMap = exports.$ZodRecord = void 0;
|
||||
exports.$ZodCustom = exports.$ZodLazy = exports.$ZodPromise = exports.$ZodFunction = exports.$ZodTemplateLiteral = exports.$ZodReadonly = exports.$ZodPreprocess = exports.$ZodCodec = exports.$ZodPipe = exports.$ZodNaN = exports.$ZodCatch = exports.$ZodSuccess = exports.$ZodNonOptional = exports.$ZodPrefault = exports.$ZodDefault = exports.$ZodNullable = exports.$ZodExactOptional = exports.$ZodOptional = exports.$ZodTransform = exports.$ZodFile = exports.$ZodLiteral = exports.$ZodEnum = exports.$ZodSet = exports.$ZodMap = exports.$ZodRecord = void 0;
|
||||
exports.isValidBase64 = isValidBase64;
|
||||
exports.isValidBase64URL = isValidBase64URL;
|
||||
exports.isValidJWT = isValidJWT;
|
||||
@@ -65,6 +65,8 @@ exports.$ZodType = core.$constructor("$ZodType", (inst, def) => {
|
||||
let asyncResult;
|
||||
for (const ch of checks) {
|
||||
if (ch._zod.def.when) {
|
||||
if (util.explicitlyAborted(payload))
|
||||
continue;
|
||||
const shouldRun = ch._zod.def.when(payload);
|
||||
if (!shouldRun)
|
||||
continue;
|
||||
@@ -219,6 +221,21 @@ exports.$ZodURL = core.$constructor("$ZodURL", (inst, def) => {
|
||||
try {
|
||||
// Trim whitespace from input
|
||||
const trimmed = payload.value.trim();
|
||||
// When normalize is off, require :// for http/https URLs
|
||||
// This prevents strings like "http:example.com" or "https:/path" from being silently accepted
|
||||
if (!def.normalize && def.protocol?.source === regexes.httpProtocol.source) {
|
||||
if (!/^https?:\/\//i.test(trimmed)) {
|
||||
payload.issues.push({
|
||||
code: "invalid_format",
|
||||
format: "url",
|
||||
note: "Invalid URL format",
|
||||
input: payload.value,
|
||||
inst,
|
||||
continue: !def.abort,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
const url = new URL(trimmed);
|
||||
if (def.hostname) {
|
||||
@@ -279,6 +296,11 @@ exports.$ZodNanoID = core.$constructor("$ZodNanoID", (inst, def) => {
|
||||
def.pattern ?? (def.pattern = regexes.nanoid);
|
||||
exports.$ZodStringFormat.init(inst, def);
|
||||
});
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
exports.$ZodCUID = core.$constructor("$ZodCUID", (inst, def) => {
|
||||
def.pattern ?? (def.pattern = regexes.cuid);
|
||||
exports.$ZodStringFormat.init(inst, def);
|
||||
@@ -384,6 +406,9 @@ exports.$ZodCIDRv6 = core.$constructor("$ZodCIDRv6", (inst, def) => {
|
||||
function isValidBase64(data) {
|
||||
if (data === "")
|
||||
return true;
|
||||
// atob ignores whitespace, so reject it up front.
|
||||
if (/\s/.test(data))
|
||||
return false;
|
||||
if (data.length % 4 !== 0)
|
||||
return false;
|
||||
try {
|
||||
@@ -588,8 +613,6 @@ exports.$ZodUndefined = core.$constructor("$ZodUndefined", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
inst._zod.pattern = regexes.undefined;
|
||||
inst._zod.values = new Set([undefined]);
|
||||
inst._zod.optin = "optional";
|
||||
inst._zod.optout = "optional";
|
||||
inst._zod.parse = (payload, _ctx) => {
|
||||
const input = payload.value;
|
||||
if (typeof input === "undefined")
|
||||
@@ -719,16 +742,28 @@ exports.$ZodArray = core.$constructor("$ZodArray", (inst, def) => {
|
||||
return payload; //handleArrayResultsAsync(parseResults, final);
|
||||
};
|
||||
});
|
||||
function handlePropertyResult(result, final, key, input, isOptionalOut) {
|
||||
function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) {
|
||||
const isPresent = key in input;
|
||||
if (result.issues.length) {
|
||||
// For optional-out schemas, ignore errors on absent keys
|
||||
if (isOptionalOut && !(key in input)) {
|
||||
// For optional-in/out schemas, ignore errors on absent keys.
|
||||
if (isOptionalIn && isOptionalOut && !isPresent) {
|
||||
return;
|
||||
}
|
||||
final.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
if (!isPresent && !isOptionalIn) {
|
||||
if (!result.issues.length) {
|
||||
final.issues.push({
|
||||
code: "invalid_type",
|
||||
expected: "nonoptional",
|
||||
input: undefined,
|
||||
path: [key],
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result.value === undefined) {
|
||||
if (key in input) {
|
||||
if (isPresent) {
|
||||
final.value[key] = undefined;
|
||||
}
|
||||
}
|
||||
@@ -754,12 +789,16 @@ function normalizeDef(def) {
|
||||
}
|
||||
function handleCatchall(proms, input, payload, ctx, def, inst) {
|
||||
const unrecognized = [];
|
||||
// iterate over input keys
|
||||
const keySet = def.keySet;
|
||||
const _catchall = def.catchall._zod;
|
||||
const t = _catchall.def.type;
|
||||
const isOptionalIn = _catchall.optin === "optional";
|
||||
const isOptionalOut = _catchall.optout === "optional";
|
||||
for (const key in input) {
|
||||
// skip __proto__ so it can't replace the result prototype via the
|
||||
// assignment setter on the plain {} we build into
|
||||
if (key === "__proto__")
|
||||
continue;
|
||||
if (keySet.has(key))
|
||||
continue;
|
||||
if (t === "never") {
|
||||
@@ -768,10 +807,10 @@ function handleCatchall(proms, input, payload, ctx, def, inst) {
|
||||
}
|
||||
const r = _catchall.run({ value: input[key], issues: [] }, ctx);
|
||||
if (r instanceof Promise) {
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut)));
|
||||
}
|
||||
else {
|
||||
handlePropertyResult(r, payload, key, input, isOptionalOut);
|
||||
handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
|
||||
}
|
||||
}
|
||||
if (unrecognized.length) {
|
||||
@@ -839,13 +878,14 @@ exports.$ZodObject = core.$constructor("$ZodObject", (inst, def) => {
|
||||
const shape = value.shape;
|
||||
for (const key of value.keys) {
|
||||
const el = shape[key];
|
||||
const isOptionalIn = el._zod.optin === "optional";
|
||||
const isOptionalOut = el._zod.optout === "optional";
|
||||
const r = el._zod.run({ value: input[key], issues: [] }, ctx);
|
||||
if (r instanceof Promise) {
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
||||
proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut)));
|
||||
}
|
||||
else {
|
||||
handlePropertyResult(r, payload, key, input, isOptionalOut);
|
||||
handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
|
||||
}
|
||||
}
|
||||
if (!catchall) {
|
||||
@@ -878,10 +918,11 @@ exports.$ZodObjectJIT = core.$constructor("$ZodObjectJIT", (inst, def) => {
|
||||
const id = ids[key];
|
||||
const k = util.esc(key);
|
||||
const schema = shape[key];
|
||||
const isOptionalIn = schema?._zod?.optin === "optional";
|
||||
const isOptionalOut = schema?._zod?.optout === "optional";
|
||||
doc.write(`const ${id} = ${parseStr(key)};`);
|
||||
if (isOptionalOut) {
|
||||
// For optional-out schemas, ignore errors on absent keys
|
||||
if (isOptionalIn && isOptionalOut) {
|
||||
// For optional-in/out schemas, ignore errors on absent keys
|
||||
doc.write(`
|
||||
if (${id}.issues.length) {
|
||||
if (${k} in input) {
|
||||
@@ -900,6 +941,34 @@ exports.$ZodObjectJIT = core.$constructor("$ZodObjectJIT", (inst, def) => {
|
||||
newResult[${k}] = ${id}.value;
|
||||
}
|
||||
|
||||
`);
|
||||
}
|
||||
else if (!isOptionalIn) {
|
||||
doc.write(`
|
||||
const ${id}_present = ${k} in input;
|
||||
if (${id}.issues.length) {
|
||||
payload.issues = payload.issues.concat(${id}.issues.map(iss => ({
|
||||
...iss,
|
||||
path: iss.path ? [${k}, ...iss.path] : [${k}]
|
||||
})));
|
||||
}
|
||||
if (!${id}_present && !${id}.issues.length) {
|
||||
payload.issues.push({
|
||||
code: "invalid_type",
|
||||
expected: "nonoptional",
|
||||
input: undefined,
|
||||
path: [${k}]
|
||||
});
|
||||
}
|
||||
|
||||
if (${id}_present) {
|
||||
if (${id}.value === undefined) {
|
||||
newResult[${k}] = undefined;
|
||||
} else {
|
||||
newResult[${k}] = ${id}.value;
|
||||
}
|
||||
}
|
||||
|
||||
`);
|
||||
}
|
||||
else {
|
||||
@@ -995,10 +1064,9 @@ exports.$ZodUnion = core.$constructor("$ZodUnion", (inst, def) => {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const single = def.options.length === 1;
|
||||
const first = def.options[0]._zod.run;
|
||||
const first = def.options.length === 1 ? def.options[0]._zod.run : null;
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (single) {
|
||||
if (first) {
|
||||
return first(payload, ctx);
|
||||
}
|
||||
let async = false;
|
||||
@@ -1055,10 +1123,9 @@ function handleExclusiveUnionResults(results, final, inst, ctx) {
|
||||
exports.$ZodXor = core.$constructor("$ZodXor", (inst, def) => {
|
||||
exports.$ZodUnion.init(inst, def);
|
||||
def.inclusive = false;
|
||||
const single = def.options.length === 1;
|
||||
const first = def.options[0]._zod.run;
|
||||
const first = def.options.length === 1 ? def.options[0]._zod.run : null;
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (single) {
|
||||
if (first) {
|
||||
return first(payload, ctx);
|
||||
}
|
||||
let async = false;
|
||||
@@ -1136,7 +1203,11 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
||||
if (opt) {
|
||||
return opt._zod.run(payload, ctx);
|
||||
}
|
||||
if (def.unionFallback) {
|
||||
// Fall back to union matching when the fast discriminator path fails:
|
||||
// - explicitly enabled via unionFallback, or
|
||||
// - during backward direction (encode), since codec-based discriminators
|
||||
// have different values in forward vs backward directions
|
||||
if (def.unionFallback || ctx.direction === "backward") {
|
||||
return _super(payload, ctx);
|
||||
}
|
||||
// no matching discriminator
|
||||
@@ -1145,6 +1216,7 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
||||
errors: [],
|
||||
note: "No matching discriminator",
|
||||
discriminator: def.discriminator,
|
||||
options: Array.from(disc.value.keys()),
|
||||
input,
|
||||
path: [def.discriminator],
|
||||
inst,
|
||||
@@ -1272,67 +1344,112 @@ exports.$ZodTuple = core.$constructor("$ZodTuple", (inst, def) => {
|
||||
}
|
||||
payload.value = [];
|
||||
const proms = [];
|
||||
const reversedIndex = [...items].reverse().findIndex((item) => item._zod.optin !== "optional");
|
||||
const optStart = reversedIndex === -1 ? 0 : items.length - reversedIndex;
|
||||
const optinStart = getTupleOptStart(items, "optin");
|
||||
const optoutStart = getTupleOptStart(items, "optout");
|
||||
if (!def.rest) {
|
||||
const tooBig = input.length > items.length;
|
||||
const tooSmall = input.length < optStart - 1;
|
||||
if (tooBig || tooSmall) {
|
||||
if (input.length < optinStart) {
|
||||
payload.issues.push({
|
||||
...(tooBig
|
||||
? { code: "too_big", maximum: items.length, inclusive: true }
|
||||
: { code: "too_small", minimum: items.length }),
|
||||
code: "too_small",
|
||||
minimum: optinStart,
|
||||
inclusive: true,
|
||||
input,
|
||||
inst,
|
||||
origin: "array",
|
||||
});
|
||||
return payload;
|
||||
}
|
||||
if (input.length > items.length) {
|
||||
payload.issues.push({
|
||||
code: "too_big",
|
||||
maximum: items.length,
|
||||
inclusive: true,
|
||||
input,
|
||||
inst,
|
||||
origin: "array",
|
||||
});
|
||||
}
|
||||
}
|
||||
let i = -1;
|
||||
for (const item of items) {
|
||||
i++;
|
||||
if (i >= input.length)
|
||||
if (i >= optStart)
|
||||
continue;
|
||||
const result = item._zod.run({
|
||||
value: input[i],
|
||||
issues: [],
|
||||
}, ctx);
|
||||
if (result instanceof Promise) {
|
||||
proms.push(result.then((result) => handleTupleResult(result, payload, i)));
|
||||
// Run every item in parallel, collecting results into an indexed
|
||||
// array. The post-processing in `handleTupleResults` walks them in
|
||||
// order so it can decide whether an absent optional-output error can
|
||||
// truncate the tail or must be reported to preserve required output.
|
||||
const itemResults = new Array(items.length);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const r = items[i]._zod.run({ value: input[i], issues: [] }, ctx);
|
||||
if (r instanceof Promise) {
|
||||
proms.push(r.then((rr) => {
|
||||
itemResults[i] = rr;
|
||||
}));
|
||||
}
|
||||
else {
|
||||
handleTupleResult(result, payload, i);
|
||||
itemResults[i] = r;
|
||||
}
|
||||
}
|
||||
if (def.rest) {
|
||||
let i = items.length - 1;
|
||||
const rest = input.slice(items.length);
|
||||
for (const el of rest) {
|
||||
i++;
|
||||
const result = def.rest._zod.run({
|
||||
value: el,
|
||||
issues: [],
|
||||
}, ctx);
|
||||
const result = def.rest._zod.run({ value: el, issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
proms.push(result.then((result) => handleTupleResult(result, payload, i)));
|
||||
proms.push(result.then((r) => handleTupleResult(r, payload, i)));
|
||||
}
|
||||
else {
|
||||
handleTupleResult(result, payload, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proms.length)
|
||||
return Promise.all(proms).then(() => payload);
|
||||
return payload;
|
||||
if (proms.length) {
|
||||
return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items, input, optoutStart));
|
||||
}
|
||||
return handleTupleResults(itemResults, payload, items, input, optoutStart);
|
||||
};
|
||||
});
|
||||
function getTupleOptStart(items, key) {
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
if (items[i]._zod[key] !== "optional")
|
||||
return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function handleTupleResult(result, final, index) {
|
||||
if (result.issues.length) {
|
||||
final.issues.push(...util.prefixIssues(index, result.issues));
|
||||
}
|
||||
final.value[index] = result.value;
|
||||
}
|
||||
function handleTupleResults(itemResults, final, items, input, optoutStart) {
|
||||
// Walk results in order. Mirror $ZodObject's swallow-on-absent-optional
|
||||
// rule, but only after `optoutStart`: the first index where the output
|
||||
// tuple tail can be absent.
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const r = itemResults[i];
|
||||
const isPresent = i < input.length;
|
||||
if (r.issues.length) {
|
||||
if (!isPresent && i >= optoutStart) {
|
||||
final.value.length = i;
|
||||
break;
|
||||
}
|
||||
final.issues.push(...util.prefixIssues(i, r.issues));
|
||||
}
|
||||
final.value[i] = r.value;
|
||||
}
|
||||
// Drop trailing slots that produced `undefined` for absent input
|
||||
// (the array analog of an absent optional key on an object). The
|
||||
// `i >= input.length` floor is critical: an explicit `undefined`
|
||||
// *inside* the input must be preserved even when the schema is
|
||||
// optional-out (e.g. `z.string().or(z.undefined())` accepting an
|
||||
// explicit undefined value).
|
||||
for (let i = final.value.length - 1; i >= input.length; i--) {
|
||||
if (items[i]._zod.optout === "optional" && final.value[i] === undefined) {
|
||||
final.value.length = i;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return final;
|
||||
}
|
||||
exports.$ZodRecord = core.$constructor("$ZodRecord", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
@@ -1354,20 +1471,36 @@ exports.$ZodRecord = core.$constructor("$ZodRecord", (inst, def) => {
|
||||
for (const key of values) {
|
||||
if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
|
||||
recordKeys.add(typeof key === "number" ? key.toString() : key);
|
||||
const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
|
||||
if (keyResult instanceof Promise) {
|
||||
throw new Error("Async schemas not supported in object keys currently");
|
||||
}
|
||||
if (keyResult.issues.length) {
|
||||
payload.issues.push({
|
||||
code: "invalid_key",
|
||||
origin: "record",
|
||||
issues: keyResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
|
||||
input: key,
|
||||
path: [key],
|
||||
inst,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const outKey = keyResult.value;
|
||||
const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
|
||||
if (result instanceof Promise) {
|
||||
proms.push(result.then((result) => {
|
||||
if (result.issues.length) {
|
||||
payload.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
payload.value[key] = result.value;
|
||||
payload.value[outKey] = result.value;
|
||||
}));
|
||||
}
|
||||
else {
|
||||
if (result.issues.length) {
|
||||
payload.issues.push(...util.prefixIssues(key, result.issues));
|
||||
}
|
||||
payload.value[key] = result.value;
|
||||
payload.value[outKey] = result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1389,9 +1522,12 @@ exports.$ZodRecord = core.$constructor("$ZodRecord", (inst, def) => {
|
||||
}
|
||||
else {
|
||||
payload.value = {};
|
||||
// Reflect.ownKeys for Symbol-key support; filter non-enumerable to match z.object()
|
||||
for (const key of Reflect.ownKeys(input)) {
|
||||
if (key === "__proto__")
|
||||
continue;
|
||||
if (!Object.prototype.propertyIsEnumerable.call(input, key))
|
||||
continue;
|
||||
let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
|
||||
if (keyResult instanceof Promise) {
|
||||
throw new Error("Async schemas not supported in object keys currently");
|
||||
@@ -1612,6 +1748,7 @@ exports.$ZodFile = core.$constructor("$ZodFile", (inst, def) => {
|
||||
});
|
||||
exports.$ZodTransform = core.$constructor("$ZodTransform", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
inst._zod.optin = "optional";
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (ctx.direction === "backward") {
|
||||
throw new core.$ZodEncodeError(inst.constructor.name);
|
||||
@@ -1621,6 +1758,7 @@ exports.$ZodTransform = core.$constructor("$ZodTransform", (inst, def) => {
|
||||
const output = _out instanceof Promise ? _out : Promise.resolve(_out);
|
||||
return output.then((output) => {
|
||||
payload.value = output;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
});
|
||||
}
|
||||
@@ -1628,11 +1766,12 @@ exports.$ZodTransform = core.$constructor("$ZodTransform", (inst, def) => {
|
||||
throw new core.$ZodAsyncError();
|
||||
}
|
||||
payload.value = _out;
|
||||
payload.fallback = true;
|
||||
return payload;
|
||||
};
|
||||
});
|
||||
function handleOptionalResult(result, input) {
|
||||
if (result.issues.length && input === undefined) {
|
||||
if (input === undefined && (result.issues.length || result.fallback)) {
|
||||
return { issues: [], value: undefined };
|
||||
}
|
||||
return result;
|
||||
@@ -1650,10 +1789,11 @@ exports.$ZodOptional = core.$constructor("$ZodOptional", (inst, def) => {
|
||||
});
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
if (def.innerType._zod.optin === "optional") {
|
||||
const input = payload.value;
|
||||
const result = def.innerType._zod.run(payload, ctx);
|
||||
if (result instanceof Promise)
|
||||
return result.then((r) => handleOptionalResult(r, payload.value));
|
||||
return handleOptionalResult(result, payload.value);
|
||||
return result.then((r) => handleOptionalResult(r, input));
|
||||
return handleOptionalResult(result, input);
|
||||
}
|
||||
if (payload.value === undefined) {
|
||||
return payload;
|
||||
@@ -1780,7 +1920,7 @@ exports.$ZodSuccess = core.$constructor("$ZodSuccess", (inst, def) => {
|
||||
});
|
||||
exports.$ZodCatch = core.$constructor("$ZodCatch", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
util.defineLazy(inst._zod, "optin", () => def.innerType._zod.optin);
|
||||
inst._zod.optin = "optional";
|
||||
util.defineLazy(inst._zod, "optout", () => def.innerType._zod.optout);
|
||||
util.defineLazy(inst._zod, "values", () => def.innerType._zod.values);
|
||||
inst._zod.parse = (payload, ctx) => {
|
||||
@@ -1801,6 +1941,7 @@ exports.$ZodCatch = core.$constructor("$ZodCatch", (inst, def) => {
|
||||
input: payload.value,
|
||||
});
|
||||
payload.issues = [];
|
||||
payload.fallback = true;
|
||||
}
|
||||
return payload;
|
||||
});
|
||||
@@ -1815,6 +1956,7 @@ exports.$ZodCatch = core.$constructor("$ZodCatch", (inst, def) => {
|
||||
input: payload.value,
|
||||
});
|
||||
payload.issues = [];
|
||||
payload.fallback = true;
|
||||
}
|
||||
return payload;
|
||||
};
|
||||
@@ -1861,7 +2003,7 @@ function handlePipeResult(left, next, ctx) {
|
||||
left.aborted = true;
|
||||
return left;
|
||||
}
|
||||
return next._zod.run({ value: left.value, issues: left.issues }, ctx);
|
||||
return next._zod.run({ value: left.value, issues: left.issues, fallback: left.fallback }, ctx);
|
||||
}
|
||||
exports.$ZodCodec = core.$constructor("$ZodCodec", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
@@ -1917,6 +2059,9 @@ function handleCodecTxResult(left, value, nextSchema, ctx) {
|
||||
}
|
||||
return nextSchema._zod.run({ value, issues: left.issues }, ctx);
|
||||
}
|
||||
exports.$ZodPreprocess = core.$constructor("$ZodPreprocess", (inst, def) => {
|
||||
exports.$ZodPipe.init(inst, def);
|
||||
});
|
||||
exports.$ZodReadonly = core.$constructor("$ZodReadonly", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
util.defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues);
|
||||
@@ -2074,14 +2219,15 @@ exports.$ZodPromise = core.$constructor("$ZodPromise", (inst, def) => {
|
||||
});
|
||||
exports.$ZodLazy = core.$constructor("$ZodLazy", (inst, def) => {
|
||||
exports.$ZodType.init(inst, def);
|
||||
// let _innerType!: any;
|
||||
// util.defineLazy(def, "getter", () => {
|
||||
// if (!_innerType) {
|
||||
// _innerType = def.getter();
|
||||
// }
|
||||
// return () => _innerType;
|
||||
// });
|
||||
util.defineLazy(inst._zod, "innerType", () => def.getter());
|
||||
// Cache the resolved inner type on the shared `def` so all clones of this
|
||||
// lazy (e.g. via `.describe()`/`.meta()`) share the same inner instance,
|
||||
// preserving identity for cycle detection on recursive schemas.
|
||||
util.defineLazy(inst._zod, "innerType", () => {
|
||||
const d = def;
|
||||
if (!d._cachedInner)
|
||||
d._cachedInner = def.getter();
|
||||
return d._cachedInner;
|
||||
});
|
||||
util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern);
|
||||
util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues);
|
||||
util.defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? undefined);
|
||||
|
||||
+39
-1
@@ -23,8 +23,13 @@ export interface ParseContextInternal<T extends errors.$ZodIssueBase = never> ex
|
||||
export interface ParsePayload<T = unknown> {
|
||||
value: T;
|
||||
issues: errors.$ZodRawIssue[];
|
||||
/** A may to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
/** A way to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
aborted?: boolean;
|
||||
/** @internal Marks a value as a fallback that an outer wrapper (e.g.
|
||||
* $ZodOptional) may override with its own interpretation when input was
|
||||
* undefined. Set by $ZodCatch when catchValue substitutes and by every
|
||||
* $ZodTransform invocation. */
|
||||
fallback?: boolean | undefined;
|
||||
}
|
||||
export type CheckFn<T> = (input: ParsePayload<T>) => util.MaybeAsync<void>;
|
||||
export interface $ZodTypeDef {
|
||||
@@ -182,13 +187,33 @@ export interface $ZodNanoID extends $ZodType {
|
||||
_zod: $ZodNanoIDInternals;
|
||||
}
|
||||
export declare const $ZodNanoID: core.$constructor<$ZodNanoID>;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDDef extends $ZodStringFormatDef<"cuid"> {
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDInternals extends $ZodStringFormatInternals<"cuid"> {
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUID extends $ZodType {
|
||||
_zod: $ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const $ZodCUID: core.$constructor<$ZodCUID>;
|
||||
export interface $ZodCUID2Def extends $ZodStringFormatDef<"cuid2"> {
|
||||
}
|
||||
@@ -1010,6 +1035,19 @@ export interface $ZodCodec<A extends SomeType = $ZodType, B extends SomeType = $
|
||||
_zod: $ZodCodecInternals<A, B>;
|
||||
}
|
||||
export declare const $ZodCodec: core.$constructor<$ZodCodec>;
|
||||
export interface $ZodPreprocessDef<B extends SomeType = $ZodType> extends $ZodPipeDef<$ZodTransform, B> {
|
||||
in: $ZodTransform;
|
||||
out: B;
|
||||
}
|
||||
export interface $ZodPreprocessInternals<B extends SomeType = $ZodType> extends $ZodPipeInternals<$ZodTransform, B> {
|
||||
def: $ZodPreprocessDef<B>;
|
||||
optin: B["_zod"]["optin"];
|
||||
optout: B["_zod"]["optout"];
|
||||
}
|
||||
export interface $ZodPreprocess<B extends SomeType = $ZodType> extends $ZodPipe<$ZodTransform, B> {
|
||||
_zod: $ZodPreprocessInternals<B>;
|
||||
}
|
||||
export declare const $ZodPreprocess: core.$constructor<$ZodPreprocess>;
|
||||
export interface $ZodReadonlyDef<T extends SomeType = $ZodType> extends $ZodTypeDef {
|
||||
type: "readonly";
|
||||
innerType: T;
|
||||
|
||||
+39
-1
@@ -23,8 +23,13 @@ export interface ParseContextInternal<T extends errors.$ZodIssueBase = never> ex
|
||||
export interface ParsePayload<T = unknown> {
|
||||
value: T;
|
||||
issues: errors.$ZodRawIssue[];
|
||||
/** A may to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
/** A way to mark a whole payload as aborted. Used in codecs/pipes. */
|
||||
aborted?: boolean;
|
||||
/** @internal Marks a value as a fallback that an outer wrapper (e.g.
|
||||
* $ZodOptional) may override with its own interpretation when input was
|
||||
* undefined. Set by $ZodCatch when catchValue substitutes and by every
|
||||
* $ZodTransform invocation. */
|
||||
fallback?: boolean | undefined;
|
||||
}
|
||||
export type CheckFn<T> = (input: ParsePayload<T>) => util.MaybeAsync<void>;
|
||||
export interface $ZodTypeDef {
|
||||
@@ -182,13 +187,33 @@ export interface $ZodNanoID extends $ZodType {
|
||||
_zod: $ZodNanoIDInternals;
|
||||
}
|
||||
export declare const $ZodNanoID: core.$constructor<$ZodNanoID>;
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDDef extends $ZodStringFormatDef<"cuid"> {
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUIDInternals extends $ZodStringFormatInternals<"cuid"> {
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export interface $ZodCUID extends $ZodType {
|
||||
_zod: $ZodCUIDInternals;
|
||||
}
|
||||
/**
|
||||
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
||||
* (timestamps embedded in the id). Use {@link $ZodCUID2} instead.
|
||||
* See https://github.com/paralleldrive/cuid.
|
||||
*/
|
||||
export declare const $ZodCUID: core.$constructor<$ZodCUID>;
|
||||
export interface $ZodCUID2Def extends $ZodStringFormatDef<"cuid2"> {
|
||||
}
|
||||
@@ -1010,6 +1035,19 @@ export interface $ZodCodec<A extends SomeType = $ZodType, B extends SomeType = $
|
||||
_zod: $ZodCodecInternals<A, B>;
|
||||
}
|
||||
export declare const $ZodCodec: core.$constructor<$ZodCodec>;
|
||||
export interface $ZodPreprocessDef<B extends SomeType = $ZodType> extends $ZodPipeDef<$ZodTransform, B> {
|
||||
in: $ZodTransform;
|
||||
out: B;
|
||||
}
|
||||
export interface $ZodPreprocessInternals<B extends SomeType = $ZodType> extends $ZodPipeInternals<$ZodTransform, B> {
|
||||
def: $ZodPreprocessDef<B>;
|
||||
optin: B["_zod"]["optin"];
|
||||
optout: B["_zod"]["optout"];
|
||||
}
|
||||
export interface $ZodPreprocess<B extends SomeType = $ZodType> extends $ZodPipe<$ZodTransform, B> {
|
||||
_zod: $ZodPreprocessInternals<B>;
|
||||
}
|
||||
export declare const $ZodPreprocess: core.$constructor<$ZodPreprocess>;
|
||||
export interface $ZodReadonlyDef<T extends SomeType = $ZodType> extends $ZodTypeDef {
|
||||
type: "readonly";
|
||||
innerType: T;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user