data_clone-deep.js


/**
 * @module cloneDeep
 * @description Performs a deep clone of the specified variable and returns the cloned variable.
 *
 * @since 3.1.0
 *
 * @param {*} value The value to clone.
 *
 * @return {*} Returns a deep copy of the specified variable.
 *
 * @example
 * import { cloneDeep } from "@gravityforms/utils";
 *
 * function Example() {
 *   const obj = { prop: 'val' };
 *   const clone = cloneDeep( obj );
 * }
 *
 */
const cloneDeep = ( value ) => {
	return _cloneDeepSafe( value );
};

/**
 * @function _cloneDeepSafe
 * @description Performs a deep clone of the specified variable and returns the cloned variable.
 *
 * @since 3.1.0
 *
 * @param {*}       value The value to clone.
 * @param {WeakMap} seen  A WeakMap to handle circular references.
 *
 * @return {*} Returns a deep copy of the specified variable.
 *
 */
const _cloneDeepSafe = ( value, seen = new WeakMap() ) => {
	// Handle null, undefined, or primitive types
	if ( value === null || typeof value !== 'object' ) {
		return value;
	}

	// Handle circular references
	if ( seen.has( value ) ) {
		return seen.get( value );
	}

	// Handle Date objects
	if ( value instanceof Date ) {
		return new Date( value );
	}

	// Handle Arrays
	if ( Array.isArray( value ) ) {
		const copy = [];
		seen.set( value, copy );
		for ( let i = 0; i < value.length; i++ ) {
			copy[ i ] = _cloneDeepSafe( value[ i ], seen );
		}
		return copy;
	}

	// Handle Map
	if ( value instanceof Map ) {
		const copy = new Map();
		seen.set( value, copy );
		value.forEach( ( v, k ) => {
			copy.set( k, _cloneDeepSafe( v, seen ) );
		} );
		return copy;
	}

	// Handle Set
	if ( value instanceof Set ) {
		const copy = new Set();
		seen.set( value, copy );
		value.forEach( ( v ) => {
			copy.add( _cloneDeepSafe( v, seen ) );
		} );
		return copy;
	}

	// Handle RegExp
	if ( value instanceof RegExp ) {
		return new RegExp( value );
	}

	// Handle Typed Arrays
	if ( ArrayBuffer.isView( value ) ) {
		return new value.constructor( value.buffer.slice( 0 ) );
	}

	// Handle plain objects and prototypes
	if ( value instanceof Object ) {
		const copy = Object.create( Object.getPrototypeOf( value ) );
		seen.set( value, copy );

		const keys = Reflect.ownKeys( value );
		for ( const key of keys ) {
			copy[ key ] = _cloneDeepSafe( value[ key ], seen );
		}
		return copy;
	}

	// If the value is an unsupported type, return it as is (functions, etc.)
	return value;
};

export default cloneDeep;