diff --git a/packages/svelte/src/reactivity/set.js b/packages/svelte/src/reactivity/set.js index d7c2deeaae..9e5e6ab6a2 100644 --- a/packages/svelte/src/reactivity/set.js +++ b/packages/svelte/src/reactivity/set.js @@ -2,7 +2,8 @@ import { DEV } from 'esm-env'; import { source, set, state, increment } from '../internal/client/reactivity/sources.js'; import { label, tag } from '../internal/client/dev/tracing.js'; -import { get, update_version } from '../internal/client/runtime.js'; +import { active_effect, get, untrack, update_version } from '../internal/client/runtime.js'; +import { async_mode_flag } from '../internal/flags/index.js'; var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf']; var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union']; @@ -47,8 +48,8 @@ var inited = false; export class SvelteSet extends Set { /** @type {Map>} */ #sources = new Map(); - #version = state(0); - #size = state(0); + /** @type {Source>} */ + #items = state(new Set()); #update_version = update_version || -1; /** @@ -57,19 +58,10 @@ export class SvelteSet extends Set { constructor(value) { super(); - if (DEV) { - // If the value is invalid then the native exception will fire here - value = new Set(value); - - tag(this.#version, 'SvelteSet version'); - tag(this.#size, 'SvelteSet.size'); - } + this.#items = state(new Set(value)) - if (value) { - for (var element of value) { - super.add(element); - } - this.#size.v = super.size; + if (DEV) { + tag(this.#items, 'SvelteSet items'); } if (!inited) this.#init(); @@ -98,7 +90,7 @@ export class SvelteSet extends Set { for (const method of read_methods) { // @ts-ignore proto[method] = function (...v) { - get(this.#version); + get(this.#items); // @ts-ignore return set_proto[method].apply(this, v); }; @@ -107,7 +99,7 @@ export class SvelteSet extends Set { for (const method of set_like_methods) { // @ts-ignore proto[method] = function (...v) { - get(this.#version); + get(this.#items); // @ts-ignore var set = /** @type {Set} */ (set_proto[method].apply(this, v)); return new SvelteSet(set); @@ -117,19 +109,18 @@ export class SvelteSet extends Set { /** @param {T} value */ has(value) { - var has = super.has(value); var sources = this.#sources; var s = sources.get(value); if (s === undefined) { - if (!has) { + if (active_effect === null && (!async_mode_flag || !untrack(() => get(this.#items)).has(value))) { // If the value doesn't exist, track the version in case it's added later // but don't create sources willy-nilly to track all possible values - get(this.#version); + get(this.#items); return false; } - s = this.#source(true); + s = this.#source((get(this.#items)).has(value)); if (DEV) { tag(s, `SvelteSet has(${label(value)})`); @@ -138,16 +129,22 @@ export class SvelteSet extends Set { sources.set(value, s); } - get(s); - return has; + return get(s); } /** @param {T} value */ add(value) { - if (!super.has(value)) { - super.add(value); - set(this.#size, super.size); - increment(this.#version); + if (!get(this.#items).has(value)) { + const clone = new Set(get(this.#items)); + clone.add(value); + + set(this.#items, clone); + } + + var s = this.#sources.get(value); + + if (s !== undefined) { + set(s, true); } return this; @@ -155,7 +152,7 @@ export class SvelteSet extends Set { /** @param {T} value */ delete(value) { - var deleted = super.delete(value); + var has = get(this.#items).has(value); var sources = this.#sources; var s = sources.get(value); @@ -164,20 +161,24 @@ export class SvelteSet extends Set { set(s, false); } - if (deleted) { - set(this.#size, super.size); - increment(this.#version); + if (has) { + const clone = new Set(get(this.#items)); + clone.delete(value); + + set(this.#items, clone); } - return deleted; + return has; } clear() { - if (super.size === 0) { + if (get(this.#items).size === 0) { return; } + // Clear first, so we get nice console.log outputs with $inspect - super.clear(); + set(this.#items, new Set()); + var sources = this.#sources; for (var s of sources.values()) { @@ -185,8 +186,6 @@ export class SvelteSet extends Set { } sources.clear(); - set(this.#size, 0); - increment(this.#version); } keys() { @@ -194,20 +193,18 @@ export class SvelteSet extends Set { } values() { - get(this.#version); - return super.values(); + return get(this.#items).values(); } entries() { - get(this.#version); - return super.entries(); + return get(this.#items).entries(); } [Symbol.iterator]() { - return this.keys(); + return this.values(); } get size() { - return get(this.#size); + return get(this.#items).size; } }