From a543559acfb21ecc509873790158ba16db4089fd Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:36:29 -0700 Subject: [PATCH] fix: avoid recursion error when tagging circular references (#16622) * fix: avoid recursion error when tagging circular references * try suggestion * add some logging * make logging clearer * more * try this * add test * tweak * fix? * fix?? --- .changeset/six-shirts-scream.md | 5 ++++ packages/svelte/src/internal/client/proxy.js | 11 +++++--- .../_config.js | 26 +++++++++++++++++++ .../main.svelte | 10 +++++++ 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 .changeset/six-shirts-scream.md create mode 100644 packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/main.svelte diff --git a/.changeset/six-shirts-scream.md b/.changeset/six-shirts-scream.md new file mode 100644 index 0000000000..ac4d183474 --- /dev/null +++ b/.changeset/six-shirts-scream.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: avoid recursion error when tagging circular references diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index 3ae4b87ed5..dae3791eb0 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -93,9 +93,11 @@ export function proxy(value) { /** Used in dev for $inspect.trace() */ var path = ''; - + let updating = false; /** @param {string} new_path */ function update_path(new_path) { + if (updating) return; + updating = true; path = new_path; tag(version, `${path} version`); @@ -104,6 +106,7 @@ export function proxy(value) { for (const [prop, source] of sources) { tag(source, get_label(path, prop)); } + updating = false; } return new Proxy(/** @type {any} */ (value), { @@ -284,13 +287,13 @@ export function proxy(value) { if (s === undefined) { if (!has || get_descriptor(target, prop)?.writable) { s = with_parent(() => source(undefined, stack)); - set(s, proxy(value)); - - sources.set(prop, s); if (DEV) { tag(s, get_label(path, prop)); } + set(s, proxy(value)); + + sources.set(prop, s); } } else { has = s.v !== UNINITIALIZED; diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/_config.js new file mode 100644 index 0000000000..ca81c7854a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; +import { normalise_trace_logs } from '../../../helpers.js'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, logs }) { + const files = { id: 1, items: [{ id: 2, items: [{ id: 3 }, { id: 4 }] }] }; + // @ts-expect-error + files.items[0].parent = files; + assert.deepEqual(normalise_trace_logs(logs), [ + { log: 'test (main.svelte:5:4)' }, + { log: '$state', highlighted: true }, + { log: 'filesState.files', highlighted: false }, + { log: files }, + { log: '$state', highlighted: true }, + { log: 'filesState.files.items[0].parent.items', highlighted: false }, + { log: files.items }, + { log: '$state', highlighted: true }, + { log: 'filesState.files.items[0].parent.items[0]', highlighted: false }, + { log: files.items[0] } + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/main.svelte new file mode 100644 index 0000000000..7640d48f77 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-circular-reference/main.svelte @@ -0,0 +1,10 @@ + \ No newline at end of file