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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 101x 23x 23x 23x 23x 23x 1x 1x 23x 2x 2x 2x 2x 2x 2x 2x 2x 2x 23x 23x 23x 78x 78x 78x 2x 2x 2x 2x 2x 2x 2x 2x 2x 393x 393x 182x 182x 177x 182x 182x 168x 182x 111x 111x 111x 111x 235x 235x 111x 111x 111x 57x 182x 47x 47x 47x 47x 47x 56x 56x 56x 47x 47x 47x 10x 178x 2x 2x 8x 178x 1x 1x 1x 1x 1x 1x 1x 182x 218x 393x 218x 218x 218x 393x 113x 113x 113x 113x 113x 113x 393x | /** @import { Snapshot } from './types' */ import { DEV } from 'esm-env'; import * as w from './warnings.js'; import { get_prototype_of, is_array, object_prototype } from './utils.js'; /** * In dev, we keep track of which properties could not be cloned. In prod * we don't bother, but we keep a dummy array around so that the * signature stays the same * @type {string[]} */ const empty = []; /** * @template T * @param {T} value * @param {boolean} [skip_warning] * @returns {Snapshot<T>} */ export function snapshot(value, skip_warning = false) { if (DEV && !skip_warning) { /** @type {string[]} */ const paths = []; const copy = clone(value, new Map(), '', paths); if (paths.length === 1 && paths[0] === '') { // value could not be cloned w.state_snapshot_uncloneable(); } else if (paths.length > 0) { // some properties could not be cloned const slice = paths.length > 10 ? paths.slice(0, 7) : paths.slice(0, 10); const excess = paths.length - slice.length; let uncloned = slice.map((path) => `- <value>${path}`).join('\n'); if (excess > 0) uncloned += `\n- ...and ${excess} more`; w.state_snapshot_uncloneable(uncloned); } return copy; } return clone(value, new Map(), '', empty); } /** * @template T * @param {T} value * @param {Map<T, Snapshot<T>>} cloned * @param {string} path * @param {string[]} paths * @returns {Snapshot<T>} */ function clone(value, cloned, path, paths) { if (typeof value === 'object' && value !== null) { const unwrapped = cloned.get(value); if (unwrapped !== undefined) return unwrapped; if (value instanceof Map) return /** @type {Snapshot<T>} */ (new Map(value)); if (value instanceof Set) return /** @type {Snapshot<T>} */ (new Set(value)); if (is_array(value)) { const copy = /** @type {Snapshot<any>} */ ([]); cloned.set(value, copy); for (let i = 0; i < value.length; i += 1) { copy.push(clone(value[i], cloned, DEV ? `${path}[${i}]` : path, paths)); } return copy; } if (get_prototype_of(value) === object_prototype) { /** @type {Snapshot<any>} */ const copy = {}; cloned.set(value, copy); for (var key in value) { // @ts-expect-error copy[key] = clone(value[key], cloned, DEV ? `${path}.${key}` : path, paths); } return copy; } if (value instanceof Date) { return /** @type {Snapshot<T>} */ (structuredClone(value)); } if (typeof (/** @type {T & { toJSON?: any } } */ (value).toJSON) === 'function') { return clone( /** @type {T & { toJSON(): any } } */ (value).toJSON(), cloned, DEV ? `${path}.toJSON()` : path, paths ); } } if (value instanceof EventTarget) { // can't be cloned return /** @type {Snapshot<T>} */ (value); } try { return /** @type {Snapshot<T>} */ (structuredClone(value)); } catch (e) { if (DEV) { paths.push(path); } return /** @type {Snapshot<T>} */ (value); } } |