Skip to content

Commit a543559

Browse files
authored
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??
1 parent ad19a1a commit a543559

File tree

4 files changed

+48
-4
lines changed

4 files changed

+48
-4
lines changed

.changeset/six-shirts-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: avoid recursion error when tagging circular references

packages/svelte/src/internal/client/proxy.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ export function proxy(value) {
9393

9494
/** Used in dev for $inspect.trace() */
9595
var path = '';
96-
96+
let updating = false;
9797
/** @param {string} new_path */
9898
function update_path(new_path) {
99+
if (updating) return;
100+
updating = true;
99101
path = new_path;
100102

101103
tag(version, `${path} version`);
@@ -104,6 +106,7 @@ export function proxy(value) {
104106
for (const [prop, source] of sources) {
105107
tag(source, get_label(path, prop));
106108
}
109+
updating = false;
107110
}
108111

109112
return new Proxy(/** @type {any} */ (value), {
@@ -284,13 +287,13 @@ export function proxy(value) {
284287
if (s === undefined) {
285288
if (!has || get_descriptor(target, prop)?.writable) {
286289
s = with_parent(() => source(undefined, stack));
287-
set(s, proxy(value));
288-
289-
sources.set(prop, s);
290290

291291
if (DEV) {
292292
tag(s, get_label(path, prop));
293293
}
294+
set(s, proxy(value));
295+
296+
sources.set(prop, s);
294297
}
295298
} else {
296299
has = s.v !== UNINITIALIZED;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test } from '../../test';
2+
import { normalise_trace_logs } from '../../../helpers.js';
3+
4+
export default test({
5+
compileOptions: {
6+
dev: true
7+
},
8+
9+
test({ assert, logs }) {
10+
const files = { id: 1, items: [{ id: 2, items: [{ id: 3 }, { id: 4 }] }] };
11+
// @ts-expect-error
12+
files.items[0].parent = files;
13+
assert.deepEqual(normalise_trace_logs(logs), [
14+
{ log: 'test (main.svelte:5:4)' },
15+
{ log: '$state', highlighted: true },
16+
{ log: 'filesState.files', highlighted: false },
17+
{ log: files },
18+
{ log: '$state', highlighted: true },
19+
{ log: 'filesState.files.items[0].parent.items', highlighted: false },
20+
{ log: files.items },
21+
{ log: '$state', highlighted: true },
22+
{ log: 'filesState.files.items[0].parent.items[0]', highlighted: false },
23+
{ log: files.items[0] }
24+
]);
25+
}
26+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
const filesState = $state({ files: {} });
3+
let nodes = { id: 1, items: [{ id: 2, items: [{ id: 3 }, { id: 4 }] }] };
4+
filesState.files = nodes;
5+
function test() {
6+
$inspect.trace();
7+
filesState.files.items[0].parent = filesState.files;
8+
}
9+
$effect(test);
10+
</script>

0 commit comments

Comments
 (0)