snapshot maps

better-snapshot
Rich Harris 8 months ago
parent 05987bc714
commit ee702d153f

@ -16,3 +16,4 @@ export const EFFECT_RAN = 1 << 13;
export const EFFECT_TRANSPARENT = 1 << 14; export const EFFECT_TRANSPARENT = 1 << 14;
export const STATE_SYMBOL = Symbol('$state'); export const STATE_SYMBOL = Symbol('$state');
export const STATE_SNAPSHOT_SYMBOL = Symbol('$state.snapshot');

@ -1,4 +1,4 @@
import { STATE_SYMBOL } from '../constants.js'; import { STATE_SNAPSHOT_SYMBOL, STATE_SYMBOL } from '../constants.js';
import { array_prototype, get_prototype_of, is_array, object_prototype } from '../utils.js'; import { array_prototype, get_prototype_of, is_array, object_prototype } from '../utils.js';
/** /**
@ -13,17 +13,22 @@ export function snapshot(value, deep = false, values = new Map()) {
return value; return value;
} }
var unwrapped = /** @type {T} */ (values.get(value));
if (unwrapped !== undefined) {
return unwrapped;
}
if (STATE_SNAPSHOT_SYMBOL in value) {
// @ts-expect-error
return value[STATE_SNAPSHOT_SYMBOL](deep);
}
var proto = get_prototype_of(value); var proto = get_prototype_of(value);
if ( if (
(proto === object_prototype || proto === array_prototype) && (proto === object_prototype || proto === array_prototype) &&
(deep || STATE_SYMBOL in value) (deep || STATE_SYMBOL in value)
) { ) {
var unwrapped = /** @type {T} */ (values.get(value));
if (unwrapped !== undefined) {
return unwrapped;
}
if (is_array(value)) { if (is_array(value)) {
var length = value.length; var length = value.length;
var array = Array(length); var array = Array(length);

@ -15,7 +15,8 @@ import {
BRANCH_EFFECT, BRANCH_EFFECT,
STATE_SYMBOL, STATE_SYMBOL,
BLOCK_EFFECT, BLOCK_EFFECT,
ROOT_EFFECT ROOT_EFFECT,
STATE_SNAPSHOT_SYMBOL
} from './constants.js'; } from './constants.js';
import { flush_tasks } from './dom/task.js'; import { flush_tasks } from './dom/task.js';
import { add_owner } from './dev/ownership.js'; import { add_owner } from './dev/ownership.js';
@ -1137,6 +1138,12 @@ export function deep_read(value, visited = new Set()) {
!visited.has(value) !visited.has(value)
) { ) {
visited.add(value); visited.add(value);
if (STATE_SNAPSHOT_SYMBOL in value) {
value[STATE_SNAPSHOT_SYMBOL](true);
return;
}
for (let key in value) { for (let key in value) {
try { try {
deep_read(value[key], visited); deep_read(value[key], visited);
@ -1144,6 +1151,7 @@ export function deep_read(value, visited = new Set()) {
// continue // continue
} }
} }
const proto = get_prototype_of(value); const proto = get_prototype_of(value);
if ( if (
proto !== Object.prototype && proto !== Object.prototype &&

@ -3,6 +3,8 @@ import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { UNINITIALIZED } from '../constants.js'; import { UNINITIALIZED } from '../constants.js';
import { map } from './utils.js'; import { map } from './utils.js';
import { STATE_SNAPSHOT_SYMBOL } from '../internal/client/constants.js';
import { snapshot } from '../internal/client/reactivity/snapshot.js';
/** /**
* @template K * @template K
@ -155,4 +157,15 @@ export class ReactiveMap extends Map {
get size() { get size() {
return get(this.#size); return get(this.#size);
} }
/** @param {boolean} deep */
[STATE_SNAPSHOT_SYMBOL](deep) {
return new Map(
map(
this.#sources.entries(),
([key, source]) => /** @type {[K, V]} */ ([key, snapshot(get(source), deep)]),
'Map Iterator'
)
);
}
} }

Loading…
Cancel
Save