From 04f57a35e0720d2108082bece227a186bb9d1062 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 11 Apr 2024 14:20:54 -0400 Subject: [PATCH] WIP --- .../src/internal/client/dev/ownership.js | 52 ++++++++++++++++--- .../svelte/src/internal/client/runtime.js | 6 ++- packages/svelte/src/internal/client/utils.js | 12 +++++ 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/packages/svelte/src/internal/client/dev/ownership.js b/packages/svelte/src/internal/client/dev/ownership.js index 358b56df22..03483d5419 100644 --- a/packages/svelte/src/internal/client/dev/ownership.js +++ b/packages/svelte/src/internal/client/dev/ownership.js @@ -1,7 +1,9 @@ /** @typedef {{ file: string, line: number, column: number }} Location */ import { STATE_SYMBOL } from '../constants.js'; +import { unstate } from '../proxy.js'; import { untrack } from '../runtime.js'; +import { get_descriptors } from '../utils.js'; /** @type {Record>} */ const boundaries = {}; @@ -98,20 +100,56 @@ export function mark_module_end() { */ export function add_owner(object, owner) { untrack(() => { - add_owner_to_object(object, owner); + var previous_owner = current_owner; + current_owner = owner; + add_owner_to_object(object); + current_owner = previous_owner; }); } +/** @type {any} */ +export var current_owner = null; + /** * @param {any} object - * @param {Function} owner + * @param {Set} [seen] */ -function add_owner_to_object(object, owner) { - if (object?.[STATE_SYMBOL]?.o && !object[STATE_SYMBOL].o.has(owner)) { - object[STATE_SYMBOL].o.add(owner); +function add_owner_to_object(object, seen = new Set()) { + if (seen.has(object) || typeof object !== 'object' || object === null) { + return; + } - for (const key in object) { - add_owner_to_object(object[key], owner); + if (object?.[STATE_SYMBOL]?.o) { + object[STATE_SYMBOL].o.add(current_owner); + } else { + seen.add(object); + + for (let key in object) { + try { + add_owner_to_object(object[key], seen); + } catch (e) { + // continue + } + } + const proto = Object.getPrototypeOf(object); + if ( + proto !== Object.prototype && + proto !== Array.prototype && + proto !== Map.prototype && + proto !== Set.prototype && + proto !== Date.prototype + ) { + const descriptors = get_descriptors(proto); + for (let key in descriptors) { + const get = descriptors[key].get; + if (get) { + try { + get.call(object); + } catch (e) { + // continue + } + } + } } } } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index c1b8ee3e44..4c17295330 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -25,7 +25,7 @@ import { ROOT_EFFECT } from './constants.js'; import { flush_tasks } from './dom/task.js'; -import { add_owner } from './dev/ownership.js'; +import { add_owner, current_owner } from './dev/ownership.js'; import { mutate, set, source } from './reactivity/sources.js'; import { update_derived } from './reactivity/deriveds.js'; @@ -758,6 +758,10 @@ export function get(signal) { } } + if (current_owner !== null && signal.v?.[STATE_SYMBOL]?.o) { + signal.v[STATE_SYMBOL].o.add(current_owner); + } + return signal.v; } diff --git a/packages/svelte/src/internal/client/utils.js b/packages/svelte/src/internal/client/utils.js index 6c6b9cc546..f2df27832b 100644 --- a/packages/svelte/src/internal/client/utils.js +++ b/packages/svelte/src/internal/client/utils.js @@ -47,3 +47,15 @@ export function map_get(map, key) { export function is_function(thing) { return typeof thing === 'function'; } + +/** @param {any} object */ +export function is_exotic_object(object) { + const proto = Object.getPrototypeOf(object); + return ( + proto !== Object.prototype && + proto !== Array.prototype && + proto !== Map.prototype && + proto !== Set.prototype && + proto !== Date.prototype + ); +}