"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.zodDeepPartial = zodDeepPartial; const zod_1 = require("zod"); /** * Internal recursive implementation of zodDeepPartial. * * This function traverses a Zod schema and recursively makes all properties optional * at every level of nesting. It handles all Zod schema types including objects, arrays, * unions, intersections, records, tuples, lazy schemas, discriminated unions, sets, * promises, readonly, catch, pipe, nonoptional, and prefault. * * For discriminated unions, the discriminator field is preserved as required to maintain * the discriminator's functionality, while all other fields become optional. * * @template T - The Zod schema type being processed * @param schema - The Zod schema to process * @param isTopLevel - Whether this is the top-level call (used to apply strict mode only at root) * @returns A new Zod schema with all properties made optional recursively * * @internal This is an internal function. Use `zodDeepPartial` instead. */ function zodDeepPartialInternal(schema, isTopLevel = false) { // Handle optional schemas by unwrapping and re-applying optional if (schema instanceof zod_1.z.ZodOptional) { return zodDeepPartialInternal(schema.unwrap(), false).optional(); } // Handle nullable schemas by unwrapping and re-applying nullable if (schema instanceof zod_1.z.ZodNullable) { return zodDeepPartialInternal(schema.unwrap(), false).nullable(); } // Handle default schemas by unwrapping and re-applying default if (schema instanceof zod_1.z.ZodDefault) { const innerResult = zodDeepPartialInternal(schema.unwrap(), false); return innerResult.default(schema.def.defaultValue); } // Handle catch schemas by unwrapping and re-applying catch if (schema instanceof zod_1.z.ZodCatch) { const innerResult = zodDeepPartialInternal(schema.def.innerType, false); return innerResult.catch(schema.def.catchValue); } // Handle prefault schemas by unwrapping and re-applying prefault if (schema instanceof zod_1.z.ZodPrefault) { const innerResult = zodDeepPartialInternal(schema.def.innerType, false); return innerResult.prefault(schema.def.defaultValue); } // Handle nonoptional schemas by unwrapping and re-applying nonoptional if (schema instanceof zod_1.z.ZodNonOptional) { const innerResult = zodDeepPartialInternal(schema.def.innerType, false); return innerResult.nonoptional(); } // Handle readonly schemas by unwrapping and re-applying readonly if (schema instanceof zod_1.z.ZodReadonly) { return zodDeepPartialInternal(schema.def.innerType, false).readonly(); } // Handle object schemas - the most common case // Recursively process each property and make them optional if (schema instanceof zod_1.z.ZodObject) { const shape = schema.shape; const newShape = {}; // Process each property in the object schema for (const key in shape) { newShape[key] = zodDeepPartialInternal(shape[key], false).optional(); } // Create new object with processed shape and apply partial() let result = zod_1.z.object(newShape).partial(); // Apply strict mode only at top level to prevent unknown properties if (isTopLevel) { result = result.strict(); } return result; } // Handle array schemas - recursively process element type if (schema instanceof zod_1.z.ZodArray) { return zod_1.z .array(zodDeepPartialInternal(schema.def.element, false)) .optional(); } // Handle map schemas - recursively process both key and value types if (schema instanceof zod_1.z.ZodMap) { return zod_1.z .map(zodDeepPartialInternal(schema.def.keyType, false), zodDeepPartialInternal(schema.def.valueType, false)) .optional(); } // Handle set schemas - recursively process value type if (schema instanceof zod_1.z.ZodSet) { return zod_1.z .set(zodDeepPartialInternal(schema.def.valueType, false)) .optional(); } // Handle promise schemas - recursively process inner type if (schema instanceof zod_1.z.ZodPromise) { return zod_1.z .promise(zodDeepPartialInternal(schema.def.innerType, false)) .optional(); } // Handle union schemas - recursively process each option if (schema instanceof zod_1.z.ZodUnion) { return zod_1.z .union(schema.options.map((opt) => zodDeepPartialInternal(opt, false))) .optional(); } // Handle intersection schemas - recursively process both left and right sides if (schema instanceof zod_1.z.ZodIntersection) { return zod_1.z .intersection(zodDeepPartialInternal(schema.def.left, false), zodDeepPartialInternal(schema.def.right, false)) .optional(); } // Handle record schemas - recursively process value type (keys remain unchanged) if (schema instanceof zod_1.z.ZodRecord) { return zod_1.z .record(zodDeepPartialInternal(schema.def.keyType, false), zodDeepPartialInternal(schema.def.valueType, false)) .optional(); } // Handle tuple schemas - recursively process each item in the tuple if (schema instanceof zod_1.z.ZodTuple) { return zod_1.z .tuple(schema.def.items.map((item) => zodDeepPartialInternal(item, false))) .optional(); } // Handle lazy schemas - recursively process the lazy getter function if (schema instanceof zod_1.z.ZodLazy) { return zod_1.z .lazy(() => zodDeepPartialInternal(schema.def.getter(), false)) .optional(); } // Handle discriminated unions - special case that preserves the discriminator field as required // This ensures the union can still be properly discriminated even when other fields are optional if (schema instanceof zod_1.z.ZodDiscriminatedUnion) { const options = schema.options.map((option) => { if (option instanceof zod_1.z.ZodObject) { const shape = option.shape; const newShape = {}; // Process each field in the discriminated union option for (const key in shape) { if (key === schema.def.discriminator) { // Keep discriminator field required to maintain discriminator functionality newShape[key] = shape[key]; } else { // Make all other fields optional newShape[key] = zodDeepPartialInternal(shape[key], false).optional(); } } return zod_1.z.object(newShape); } return zodDeepPartialInternal(option, false); }); return zod_1.z.discriminatedUnion(schema.def.discriminator, options); } // Handle pipe schemas - preserve both input and output types as-is // Note: We don't deep-partial the input of pipes because transforms/refinements // have specific input requirements. The parent object's .optional() handles optionality. if (schema instanceof zod_1.z.ZodPipe) { return schema; } // Fallback for any other schema types - simply make them optional return schema.optional(); } /** * Recursively makes all properties in a Zod schema optional at all levels. * * This is the main entry point for creating deeply partial Zod schemas. It transforms * a Zod schema so that every property, at every level of nesting, becomes optional. * This is useful for: * - Creating partial update schemas * - Handling incomplete data structures * - Building flexible API request/response validators * - Implementing patch operations * * The function preserves type safety and works with all Zod schema types including: * - Objects (with nested objects) * - Arrays * - Unions * - Intersections * - Records * - Tuples * - Lazy/recursive schemas * - Discriminated unions (preserves discriminator as required) * * @template T - The Zod schema type * @param schema - The Zod schema to make deeply partial * @returns A new Zod schema where all properties are optional at all levels * * @example * ```typescript * import { z } from "zod"; * import { zodDeepPartial } from "zod-deep-partial"; * * const userSchema = z.object({ * name: z.string(), * email: z.email(), * profile: z.object({ * bio: z.string(), * avatar: z.url(), * }), * }); * * const partialUserSchema = zodDeepPartial(userSchema); * * // All of these are now valid: * partialUserSchema.parse({}); * partialUserSchema.parse({ name: "John" }); * partialUserSchema.parse({ profile: { bio: "Developer" } }); * ``` */ function zodDeepPartial(schema) { return zodDeepPartialInternal(schema, true); } //# sourceMappingURL=index.js.map