From b1cbfc3d386962f77566292a11a89f2b096dc271 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Jun 2024 16:14:59 -0400 Subject: [PATCH] fix: populate `this.#sources` when constructing reactive map (#11915) * fix: populate `this.#sources` when constructing reactive map * populate sources in first #read_all * use increment helper * use numbers instead of symbols * make forEach work --- .changeset/cold-beans-tease.md | 2 +- packages/svelte/src/reactivity/map.js | 43 +++++++++++++------------ packages/svelte/src/reactivity/set.js | 11 +++---- packages/svelte/src/reactivity/url.js | 15 ++++----- packages/svelte/src/reactivity/utils.js | 7 ++++ 5 files changed, 41 insertions(+), 37 deletions(-) diff --git a/.changeset/cold-beans-tease.md b/.changeset/cold-beans-tease.md index dc02ea7501..7359c27cc0 100644 --- a/.changeset/cold-beans-tease.md +++ b/.changeset/cold-beans-tease.md @@ -2,4 +2,4 @@ 'svelte': patch --- -fix: increment version when creating new source in Map.get or Map.has +fix: populate `this.#sources` when constructing reactive map diff --git a/packages/svelte/src/reactivity/map.js b/packages/svelte/src/reactivity/map.js index e473bd5292..6c5899af32 100644 --- a/packages/svelte/src/reactivity/map.js +++ b/packages/svelte/src/reactivity/map.js @@ -1,7 +1,7 @@ import { DEV } from 'esm-env'; import { source, set } from '../internal/client/reactivity/sources.js'; import { get } from '../internal/client/runtime.js'; -import { UNINITIALIZED } from '../constants.js'; +import { increment } from './utils.js'; /** * @template K @@ -9,7 +9,7 @@ import { UNINITIALIZED } from '../constants.js'; * @extends {Map} */ export class ReactiveMap extends Map { - /** @type {Map>} */ + /** @type {Map>} */ #sources = new Map(); #version = source(0); #size = source(0); @@ -31,10 +31,6 @@ export class ReactiveMap extends Map { } } - #increment_version() { - set(this.#version, this.#version.v + 1); - } - /** @param {K} key */ has(key) { var sources = this.#sources; @@ -43,9 +39,8 @@ export class ReactiveMap extends Map { if (s === undefined) { var ret = super.get(key); if (ret !== undefined) { - s = source(Symbol()); + s = source(0); sources.set(key, s); - this.#increment_version(); } else { // We should always track the version in case // the Set ever gets this value in the future. @@ -63,9 +58,8 @@ export class ReactiveMap extends Map { * @param {any} [this_arg] */ forEach(callbackfn, this_arg) { - get(this.#version); - - return super.forEach(callbackfn, this_arg); + this.#read_all(); + super.forEach(callbackfn, this_arg); } /** @param {K} key */ @@ -76,9 +70,8 @@ export class ReactiveMap extends Map { if (s === undefined) { var ret = super.get(key); if (ret !== undefined) { - s = source(Symbol()); + s = source(0); sources.set(key, s); - this.#increment_version(); } else { // We should always track the version in case // the Set ever gets this value in the future. @@ -102,11 +95,11 @@ export class ReactiveMap extends Map { var res = super.set(key, value); if (s === undefined) { - sources.set(key, source(Symbol())); + sources.set(key, source(0)); set(this.#size, super.size); - this.#increment_version(); + increment(this.#version); } else if (prev_res !== value) { - set(s, Symbol()); + increment(s); } return res; @@ -121,8 +114,8 @@ export class ReactiveMap extends Map { if (s !== undefined) { sources.delete(key); set(this.#size, super.size); - set(s, UNINITIALIZED); - this.#increment_version(); + set(s, -1); + increment(this.#version); } return res; @@ -134,9 +127,9 @@ export class ReactiveMap extends Map { if (super.size !== 0) { set(this.#size, 0); for (var s of sources.values()) { - set(s, UNINITIALIZED); + set(s, -1); } - this.#increment_version(); + increment(this.#version); sources.clear(); } super.clear(); @@ -144,6 +137,16 @@ export class ReactiveMap extends Map { #read_all() { get(this.#version); + + var sources = this.#sources; + if (this.#size.v !== sources.size) { + for (var key of super.keys()) { + if (!sources.has(key)) { + sources.set(key, source(0)); + } + } + } + for (var [, s] of this.#sources) { get(s); } diff --git a/packages/svelte/src/reactivity/set.js b/packages/svelte/src/reactivity/set.js index 809109846a..98d941a07d 100644 --- a/packages/svelte/src/reactivity/set.js +++ b/packages/svelte/src/reactivity/set.js @@ -1,6 +1,7 @@ import { DEV } from 'esm-env'; import { source, set } from '../internal/client/reactivity/sources.js'; import { get } from '../internal/client/runtime.js'; +import { increment } from './utils.js'; var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf']; var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union']; @@ -63,10 +64,6 @@ export class ReactiveSet extends Set { } } - #increment_version() { - set(this.#version, this.#version.v + 1); - } - /** @param {T} value */ has(value) { var sources = this.#sources; @@ -98,7 +95,7 @@ export class ReactiveSet extends Set { if (s === undefined) { sources.set(value, source(true)); set(this.#size, super.size); - this.#increment_version(); + increment(this.#version); } else { set(s, true); } @@ -116,7 +113,7 @@ export class ReactiveSet extends Set { sources.delete(value); set(this.#size, super.size); set(s, false); - this.#increment_version(); + increment(this.#version); } return res; @@ -130,7 +127,7 @@ export class ReactiveSet extends Set { for (var s of sources.values()) { set(s, false); } - this.#increment_version(); + increment(this.#version); sources.clear(); } super.clear(); diff --git a/packages/svelte/src/reactivity/url.js b/packages/svelte/src/reactivity/url.js index 3f11a4af37..ceb6b45fcf 100644 --- a/packages/svelte/src/reactivity/url.js +++ b/packages/svelte/src/reactivity/url.js @@ -1,5 +1,6 @@ import { source, set } from '../internal/client/reactivity/sources.js'; import { get } from '../internal/client/runtime.js'; +import { increment } from './utils.js'; const REPLACE = Symbol(); @@ -155,10 +156,6 @@ export class ReactiveURL extends URL { export class ReactiveURLSearchParams extends URLSearchParams { #version = source(0); - #increment_version() { - set(this.#version, this.#version.v + 1); - } - /** * @param {URLSearchParams} params */ @@ -171,7 +168,7 @@ export class ReactiveURLSearchParams extends URLSearchParams { super.append(key, value); } - this.#increment_version(); + increment(this.#version); } /** @@ -180,7 +177,7 @@ export class ReactiveURLSearchParams extends URLSearchParams { * @returns {void} */ append(name, value) { - this.#increment_version(); + increment(this.#version); return super.append(name, value); } @@ -190,7 +187,7 @@ export class ReactiveURLSearchParams extends URLSearchParams { * @returns {void} */ delete(name, value) { - this.#increment_version(); + increment(this.#version); return super.delete(name, value); } @@ -233,12 +230,12 @@ export class ReactiveURLSearchParams extends URLSearchParams { * @returns {void} */ set(name, value) { - this.#increment_version(); + increment(this.#version); return super.set(name, value); } sort() { - this.#increment_version(); + increment(this.#version); return super.sort(); } diff --git a/packages/svelte/src/reactivity/utils.js b/packages/svelte/src/reactivity/utils.js index cc71bf094c..5490dae7e5 100644 --- a/packages/svelte/src/reactivity/utils.js +++ b/packages/svelte/src/reactivity/utils.js @@ -1,3 +1,5 @@ +import { set } from '../internal/client/reactivity/sources.js'; + /** * @template T * @template U @@ -27,3 +29,8 @@ export function map(iterable, fn, name) { function get_this() { return this; } + +/** @param {import('#client').Source} source */ +export function increment(source) { + set(source, source.v + 1); +}