diff --git a/packages/svelte/src/internal/client/magic.js b/packages/svelte/src/internal/client/magic.js index 3349a64ebf..ff59a9e8ec 100644 --- a/packages/svelte/src/internal/client/magic.js +++ b/packages/svelte/src/internal/client/magic.js @@ -1,17 +1,17 @@ import { effect_active, get, set, increment, source } from './runtime.js'; -/** @typedef {{ p: MagicObject | null; s: Map>; v: import('./types').SourceSignal; a: boolean }} Magic */ -/** @typedef {Record & { [MAGIC_SYMBOL]: Magic }} MagicObject */ +/** @typedef {{ p: StateObject | null; s: Map>; v: import('./types').SourceSignal; a: boolean }} Metadata */ +/** @typedef {Record & { [STATE_SYMBOL]: Metadata }} StateObject */ -export const MAGIC_SYMBOL = Symbol(); -export const MAGIC_EACH_SYMBOL = Symbol(); +export const STATE_SYMBOL = Symbol(); +export const STATE_EACH_SYMBOL = Symbol(); const object_prototype = Object.prototype; const array_prototype = Array.prototype; const get_prototype_of = Object.getPrototypeOf; /** - * @template {MagicObject} T + * @template {StateObject} T * @param {T} value * @returns {T} */ @@ -20,33 +20,51 @@ export function magic(value) { } /** - * @template {MagicObject} T - * @template {MagicObject} P + * @template {StateObject} T + * @template {StateObject} P * @param {T} value * @param {P | null} parent * @returns {T} */ function wrap(value, parent) { - if (value && typeof value === 'object') { + if (value && typeof value === 'object' && !(STATE_SYMBOL in value)) { const prototype = get_prototype_of(value); // TODO handle Map and Set as well if (prototype === object_prototype || prototype === array_prototype) { - return proxy(value, parent); + // @ts-expect-error + value[STATE_SYMBOL] = init(value, parent); + + // @ts-expect-error not sure how to fix this + return new Proxy(value, handler); } } return value; } -/** @type {ProxyHandler} */ +/** + * @param {StateObject} value + * @param {StateObject | null} parent + * @returns {Metadata} + */ +function init(value, parent) { + return { + p: parent, + s: new Map(), + v: source(0), + a: Array.isArray(value) + }; +} + +/** @type {ProxyHandler} */ const handler = { get(target, prop, receiver) { - if (prop === MAGIC_EACH_SYMBOL) { + if (prop === STATE_EACH_SYMBOL) { return parent; } - const metadata = target[MAGIC_SYMBOL]; + const metadata = target[STATE_SYMBOL]; let s = metadata.s.get(prop); // if we're reading a property in a reactive context, create a source, @@ -59,7 +77,7 @@ const handler = { return s !== undefined ? get(s) : target[prop]; }, set(target, prop, value) { - const metadata = target[MAGIC_SYMBOL]; + const metadata = target[STATE_SYMBOL]; const s = metadata.s.get(prop); if (s !== undefined) set(s, wrap(value, target)); @@ -78,7 +96,7 @@ const handler = { return true; }, deleteProperty(target, prop) { - const metadata = target[MAGIC_SYMBOL]; + const metadata = target[STATE_SYMBOL]; const s = metadata.s.get(prop); if (s !== undefined) set(s, undefined); @@ -88,48 +106,17 @@ const handler = { return delete target[prop]; }, has(target, prop) { - if (prop === MAGIC_SYMBOL) return true; + if (prop === STATE_SYMBOL) return true; - const metadata = target[MAGIC_SYMBOL]; + const metadata = target[STATE_SYMBOL]; get(metadata.v); return Reflect.has(target, prop); }, ownKeys(target) { - const metadata = target[MAGIC_SYMBOL]; + const metadata = target[STATE_SYMBOL]; get(metadata.v); return Reflect.ownKeys(target); } }; - -/** - * @template {MagicObject} T - * @template {MagicObject} P - * @param {T} value - * @param {P | null} parent - * @returns {T} - */ -function proxy(value, parent) { - if (MAGIC_SYMBOL in value) return value; - - // @ts-expect-error - value[MAGIC_SYMBOL] = init(value, parent); - - // @ts-expect-error not sure how to fix this - return new Proxy(value, handler); -} - -/** - * @param {MagicObject} value - * @param {MagicObject | null} parent - * @returns {Magic} - */ -function init(value, parent) { - return { - p: parent, - s: new Map(), - v: source(0), - a: Array.isArray(value) - }; -} diff --git a/packages/svelte/src/internal/client/reconciler.js b/packages/svelte/src/internal/client/reconciler.js index f7f4908c57..17fb59b0a9 100644 --- a/packages/svelte/src/internal/client/reconciler.js +++ b/packages/svelte/src/internal/client/reconciler.js @@ -13,7 +13,7 @@ import { EACH_IS_PROXIED, EACH_ITEM_REACTIVE } from '../../constants.js'; -import { MAGIC_SYMBOL } from './magic.js'; +import { STATE_SYMBOL } from './magic.js'; const NEW_BLOCK = -1; const MOVED_BLOCK = 99999999; @@ -183,7 +183,7 @@ export function reconcile_indexed_array( flags, apply_transitions ) { - var is_proxied_array = MAGIC_SYMBOL in array; + var is_proxied_array = STATE_SYMBOL in array; var a_blocks = each_block.v; var active_transitions = each_block.s; @@ -289,7 +289,7 @@ export function reconcile_tracked_array( ) { var a_blocks = each_block.v; const is_computed_key = keys !== null; - var is_proxied_array = MAGIC_SYMBOL in array; + var is_proxied_array = STATE_SYMBOL in array; var active_transitions = each_block.s; if (is_proxied_array) {