@@ -54,6 +54,8 @@ export let current_effect = null;
5454/** @type {null | import('./types.js').Signal[] } */
5555let current_dependencies = null ;
5656let current_dependencies_index = 0 ;
57+ /** @type {null | import('./types.js').Signal[] } */
58+ let current_untracked_writes = null ;
5759// Handling capturing of signals from object property getters
5860let current_should_capture_signal = false ;
5961/** If `true`, `get`ting the signal should not register it as a dependency */
@@ -282,6 +284,7 @@ function execute_signal_fn(signal) {
282284 const init = signal . i ;
283285 const previous_dependencies = current_dependencies ;
284286 const previous_dependencies_index = current_dependencies_index ;
287+ const previous_untracked_writes = current_untracked_writes ;
285288 const previous_consumer = current_consumer ;
286289 const previous_block = current_block ;
287290 const previous_component_context = current_component_context ;
@@ -290,6 +293,7 @@ function execute_signal_fn(signal) {
290293 const previous_untracking = current_untracking ;
291294 current_dependencies = /** @type {null | import('./types.js').Signal[] } */ ( null ) ;
292295 current_dependencies_index = 0 ;
296+ current_untracked_writes = null ;
293297 current_consumer = signal ;
294298 current_block = signal . b ;
295299 current_component_context = signal . x ;
@@ -347,6 +351,7 @@ function execute_signal_fn(signal) {
347351 } finally {
348352 current_dependencies = previous_dependencies ;
349353 current_dependencies_index = previous_dependencies_index ;
354+ current_untracked_writes = previous_untracked_writes ;
350355 current_consumer = previous_consumer ;
351356 current_block = previous_block ;
352357 current_component_context = previous_component_context ;
@@ -469,23 +474,27 @@ export function execute_effect(signal) {
469474 }
470475}
471476
477+ function infinite_loop_guard ( ) {
478+ if ( flush_count > 100 ) {
479+ throw new Error (
480+ 'ERR_SVELTE_TOO_MANY_UPDATES' +
481+ ( DEV
482+ ? ': Maximum update depth exceeded. This can happen when a reactive block or effect ' +
483+ 'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
484+ : '' )
485+ ) ;
486+ }
487+ flush_count ++ ;
488+ }
489+
472490/**
473491 * @param {Array<import('./types.js').EffectSignal> } effects
474492 * @returns {void }
475493 */
476494function flush_queued_effects ( effects ) {
477495 const length = effects . length ;
478496 if ( length > 0 ) {
479- if ( flush_count > 100 ) {
480- throw new Error (
481- 'ERR_SVELTE_TOO_MANY_UPDATES' +
482- ( DEV
483- ? ': Maximum update depth exceeded. This can happen when a reactive block or effect ' +
484- 'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
485- : '' )
486- ) ;
487- }
488- flush_count ++ ;
497+ infinite_loop_guard ( ) ;
489498 let i ;
490499 for ( i = 0 ; i < length ; i ++ ) {
491500 const signal = effects [ i ] ;
@@ -606,13 +615,13 @@ export function flushSync(fn) {
606615 const previous_queued_pre_and_render_effects = current_queued_pre_and_render_effects ;
607616 const previous_queued_effects = current_queued_effects ;
608617 try {
618+ infinite_loop_guard ( ) ;
609619 /** @type {import('./types.js').EffectSignal[] } */
610620 const pre_and_render_effects = [ ] ;
611621
612622 /** @type {import('./types.js').EffectSignal[] } */
613623 const effects = [ ] ;
614624 current_scheduler_mode = FLUSH_SYNC ;
615- flush_count = 0 ;
616625 current_queued_pre_and_render_effects = pre_and_render_effects ;
617626 current_queued_effects = effects ;
618627 flush_queued_effects ( previous_queued_pre_and_render_effects ) ;
@@ -626,6 +635,7 @@ export function flushSync(fn) {
626635 if ( is_task_queued ) {
627636 process_task ( ) ;
628637 }
638+ flush_count = 0 ;
629639 } finally {
630640 current_scheduler_mode = previous_scheduler_mode ;
631641 current_queued_pre_and_render_effects = previous_queued_pre_and_render_effects ;
@@ -814,6 +824,15 @@ export function get(signal) {
814824 } else if ( signal !== current_dependencies [ current_dependencies . length - 1 ] ) {
815825 current_dependencies . push ( signal ) ;
816826 }
827+ if (
828+ current_untracked_writes !== null &&
829+ current_effect !== null &&
830+ ( current_effect . f & CLEAN ) !== 0 &&
831+ current_untracked_writes . includes ( signal )
832+ ) {
833+ set_signal_status ( current_effect , DIRTY ) ;
834+ schedule_effect ( current_effect , false ) ;
835+ }
817836 }
818837
819838 if ( ( flags & DERIVED ) !== 0 && is_signal_dirty ( signal ) ) {
@@ -1024,12 +1043,18 @@ export function set_signal_value(signal, value) {
10241043 is_runes ( component_context ) &&
10251044 current_effect !== null &&
10261045 current_effect . c === null &&
1027- ( current_effect . f & CLEAN ) !== 0 &&
1028- current_dependencies !== null &&
1029- current_dependencies . includes ( signal )
1046+ ( current_effect . f & CLEAN ) !== 0
10301047 ) {
1031- set_signal_status ( current_effect , DIRTY ) ;
1032- schedule_effect ( current_effect , false ) ;
1048+ if ( current_dependencies !== null && current_dependencies . includes ( signal ) ) {
1049+ set_signal_status ( current_effect , DIRTY ) ;
1050+ schedule_effect ( current_effect , false ) ;
1051+ } else {
1052+ if ( current_untracked_writes === null ) {
1053+ current_untracked_writes = [ signal ] ;
1054+ } else {
1055+ current_untracked_writes . push ( signal ) ;
1056+ }
1057+ }
10331058 }
10341059 mark_signal_consumers ( signal , DIRTY , true ) ;
10351060 // If we have afterUpdates locally on the component, but we're within a render effect
0 commit comments