"use strict";
/**
 * This method is like `cloneDeep` except that it accepts customizer which
 * is invoked to produce the cloned value. If customizer returns undefined,
 * cloning is handled by the method instead.
 * Drop-in replacement for lodash/cloneDeepWith.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = cloneDeepWith;
function baseCloneDeep(value, customizer, seen) {
    // Invoke customizer first
    const customResult = customizer(value);
    if (customResult !== undefined) {
        return customResult;
    }
    // Primitives
    if (value === null || typeof value !== 'object') {
        return value;
    }
    // Circular reference detection
    if (seen.has(value)) {
        return seen.get(value);
    }
    // Date
    if (value instanceof Date) {
        return new Date(value.getTime());
    }
    // RegExp
    if (value instanceof RegExp) {
        return new RegExp(value.source, value.flags);
    }
    // Map
    if (value instanceof Map) {
        const cloned = new Map();
        seen.set(value, cloned);
        value.forEach((v, k) => {
            cloned.set(baseCloneDeep(k, customizer, seen), baseCloneDeep(v, customizer, seen));
        });
        return cloned;
    }
    // Set
    if (value instanceof Set) {
        const cloned = new Set();
        seen.set(value, cloned);
        value.forEach((v) => {
            cloned.add(baseCloneDeep(v, customizer, seen));
        });
        return cloned;
    }
    // Arrays
    if (Array.isArray(value)) {
        const cloned = [];
        seen.set(value, cloned);
        for (let i = 0; i < value.length; i++) {
            cloned[i] = baseCloneDeep(value[i], customizer, seen);
        }
        return cloned;
    }
    // Plain objects and others
    const cloned = Object.create(Object.getPrototypeOf(value));
    seen.set(value, cloned);
    const keys = Object.keys(value);
    for (const key of keys) {
        cloned[key] = baseCloneDeep(value[key], customizer, seen);
    }
    return cloned;
}
function cloneDeepWith(value, customizer) {
    return baseCloneDeep(value, customizer, new Map());
}
