All files / src/internal/shared clone.js

100% Statements 56/56
100% Branches 16/16
100% Functions 2/2
100% Lines 55/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 562x 2x 2x 2x 2x 2x 2x 2x 60x 60x 60x 60x 2x 2x 2x 2x 2x 2x 2x 185x 185x 117x 117x 112x 117x 71x 71x 71x 71x 71x 79x 79x 71x 71x 71x 41x 43x 38x 38x 38x 38x 38x 45x 45x 38x 38x 38x 3x 11x 1x 1x 117x 70x 70x 70x  
import { get_prototype_of, is_array, object_prototype } from './utils.js';
 
/**
 * @template T
 * @param {T} value
 * @returns {T}
 */
export function snapshot(value) {
	return /** @type {T} */ (
		clone(/** @type {import('#client').ProxyStateObject} */ (value), new Map())
	);
}
 
/**
 * @template {import('#client').ProxyStateObject} T
 * @param {T} value
 * @param {Map<T, Record<string | symbol, any>>} cloned
 * @returns {Record<string | symbol, any>}
 */
function clone(value, cloned) {
	if (typeof value === 'object' && value !== null) {
		const unwrapped = cloned.get(value);
		if (unwrapped !== undefined) return unwrapped;
 
		if (is_array(value)) {
			/** @type {Record<string | symbol, any>} */
			const copy = [];
			cloned.set(value, copy);
 
			for (const element of value) {
				copy.push(clone(element, cloned));
			}
 
			return copy;
		}
 
		if (get_prototype_of(value) === object_prototype) {
			/** @type {Record<string | symbol, any>} */
			const copy = {};
			cloned.set(value, copy);
 
			for (var key in value) {
				copy[key] = clone(value[key], cloned);
			}
 
			return copy;
		}
 
		if (typeof value.toJSON === 'function') {
			return clone(value.toJSON(), cloned);
		}
	}
 
	return structuredClone(value);
}