"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