@@ -34,9 +34,13 @@ const regex_is_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
3434/**
3535 * @template T
3636 * @param {T } value
37+ * @param {WeakSet<Source> } [owned_sources]
3738 * @returns {T }
3839 */
39- export function proxy ( value ) {
40+ export function proxy ( value , owned_sources ) {
41+ if ( DEV ) {
42+ owned_sources ??= new WeakSet ( ) ;
43+ }
4044 // if non-proxyable, or is already a proxy, return `value`
4145 if ( typeof value !== 'object' || value === null || STATE_SYMBOL in value ) {
4246 return value ;
@@ -94,8 +98,15 @@ export function proxy(value) {
9498 /** Used in dev for $inspect.trace() */
9599 var path = '' ;
96100
97- /** @param {string } new_path */
98- function update_path ( new_path ) {
101+ /**
102+ * @param {string } new_path
103+ * @param {Source } updater the source causing the path update
104+ */
105+ function update_path ( new_path , updater ) {
106+ // there's a circular reference somewhere, don't update the path to avoid recursion
107+ if ( owned_sources ?. has ( updater ) ) {
108+ return ;
109+ }
99110 path = new_path ;
100111
101112 tag ( version , `${ path } version` ) ;
@@ -127,6 +138,7 @@ export function proxy(value) {
127138 sources . set ( prop , s ) ;
128139 if ( DEV && typeof prop === 'string' ) {
129140 tag ( s , get_label ( path , prop ) ) ;
141+ owned_sources ?. add ( s ) ;
130142 }
131143 return s ;
132144 } ) ;
@@ -148,6 +160,7 @@ export function proxy(value) {
148160
149161 if ( DEV ) {
150162 tag ( s , get_label ( path , prop ) ) ;
163+ owned_sources ?. add ( s ) ;
151164 }
152165 }
153166 } else {
@@ -173,11 +186,12 @@ export function proxy(value) {
173186 // create a source, but only if it's an own property and not a prototype property
174187 if ( s === undefined && ( ! exists || get_descriptor ( target , prop ) ?. writable ) ) {
175188 s = with_parent ( ( ) => {
176- var p = proxy ( exists ? target [ prop ] : UNINITIALIZED ) ;
189+ var p = proxy ( exists ? target [ prop ] : UNINITIALIZED , DEV ? owned_sources : undefined ) ;
177190 var s = source ( p , stack ) ;
178191
179192 if ( DEV ) {
180193 tag ( s , get_label ( path , prop ) ) ;
194+ owned_sources ?. add ( s ) ;
181195 }
182196
183197 return s ;
@@ -231,11 +245,12 @@ export function proxy(value) {
231245 ) {
232246 if ( s === undefined ) {
233247 s = with_parent ( ( ) => {
234- var p = has ? proxy ( target [ prop ] ) : UNINITIALIZED ;
248+ var p = has ? proxy ( target [ prop ] , DEV ? owned_sources : undefined ) : UNINITIALIZED ;
235249 var s = source ( p , stack ) ;
236250
237251 if ( DEV ) {
238252 tag ( s , get_label ( path , prop ) ) ;
253+ owned_sources ?. add ( s ) ;
239254 }
240255
241256 return s ;
@@ -272,6 +287,7 @@ export function proxy(value) {
272287
273288 if ( DEV ) {
274289 tag ( other_s , get_label ( path , i ) ) ;
290+ owned_sources ?. add ( other_s ) ;
275291 }
276292 }
277293 }
@@ -284,18 +300,19 @@ export function proxy(value) {
284300 if ( s === undefined ) {
285301 if ( ! has || get_descriptor ( target , prop ) ?. writable ) {
286302 s = with_parent ( ( ) => source ( undefined , stack ) ) ;
287- set ( s , proxy ( value ) ) ;
303+ set ( s , proxy ( value , DEV ? owned_sources : undefined ) ) ;
288304
289305 sources . set ( prop , s ) ;
290306
291307 if ( DEV ) {
292308 tag ( s , get_label ( path , prop ) ) ;
309+ owned_sources ?. add ( s ) ;
293310 }
294311 }
295312 } else {
296313 has = s . v !== UNINITIALIZED ;
297314
298- var p = with_parent ( ( ) => proxy ( value ) ) ;
315+ var p = with_parent ( ( ) => proxy ( value , DEV ? owned_sources : undefined ) ) ;
299316 set ( s , p ) ;
300317 }
301318
0 commit comments