@ -29,8 +29,7 @@ import {
ROOT _EFFECT ,
LEGACY _DERIVED _PROP ,
DISCONNECTED ,
STATE _FROZEN _SYMBOL ,
INSPECT _EFFECT
STATE _FROZEN _SYMBOL
} from './constants.js' ;
import { flush _tasks } from './dom/task.js' ;
import { add _owner } from './dev/ownership.js' ;
@ -63,8 +62,6 @@ export function set_is_destroying_effect(value) {
is _destroying _effect = value ;
}
export let inspect _effects = new Set ( ) ;
// Handle effect queues
/** @type {import('#client').Effect[]} */
@ -164,77 +161,44 @@ export function is_runes() {
* /
export function check _dirtiness ( reaction ) {
var flags = reaction . f ;
var is _dirty = ( flags & DIRTY ) !== 0 ;
if ( is _dirty ) {
if ( ( flags & DIRTY ) !== 0 ) {
return true ;
}
var is _unowned = ( flags & UNOWNED ) !== 0 ;
var is _disconnected = ( flags & DISCONNECTED ) !== 0 ;
if ( ( flags & MAYBE _DIRTY ) !== 0 ) {
var dependencies = reaction . deps ;
if ( dependencies !== null ) {
var length = dependencies . length ;
var reactions ;
var is _unowned = ( flags & UNOWNED ) !== 0 ;
for ( var i = 0 ; i < length; i ++ ) {
for ( var i = 0 ; i < dependencies. length; i ++ ) {
var dependency = dependencies [ i ] ;
if ( ! is _dirty && check _dirtiness ( /** @type {import('#client').Derived} */ ( dependency ) ) ) {
update _derived ( /** @type {import('#client').Derived} * * / ( dependency ) ) ;
if ( check _dirtiness ( /** @type {import('#client').Derived} */ ( dependency ) ) ) {
update _derived ( /** @type {import('#client').Derived} * / ( dependency ) ) ;
}
if ( ( reaction . f & DIRTY ) !== 0 ) {
// `reaction` might now be dirty, as a result of calling `update_derived`
if ( dependency . version > reaction . version ) {
return true ;
}
if ( is _unowned ) {
// If we're working with an unowned derived signal, then we need to check
// if our dependency write version is higher. If it is then we can assume
// that state has changed to a newer version and thus this unowned signal
// is also dirty.
if ( dependency . version > /** @type {import('#client').Derived} */ ( reaction ) . version ) {
return true ;
}
// TODO is there a more logical place to do this work?
if ( ! current _skip _reaction && ! dependency ? . reactions ? . includes ( reaction ) ) {
// If we are working with an unowned signal as part of an effect (due to !current_skip_reaction)
// and the version hasn't changed, we still need to check that this reaction
// if linked to the dependency source – otherwise future updates will not be caught.
( dependency . reactions ? ? = [ ] ) . push ( reaction ) ;
}
} else if ( is _disconnected ) {
// It might be that the derived was was dereferenced from its dependencies but has now come alive again.
// In thise case, we need to re-attach it to the graph and mark it dirty if any of its dependencies have
// changed since.
if ( dependency . version > /** @type {import('#client').Derived} */ ( reaction ) . version ) {
is _dirty = true ;
}
reactions = dependency . reactions ;
if ( reactions === null ) {
dependency . reactions = [ reaction ] ;
} else if ( ! reactions . includes ( reaction ) ) {
reactions . push ( reaction ) ;
}
}
}
}
// Unowned signals are always maybe dirty, as we instead check their dependency versions.
if ( ! is _unowned ) {
set _signal _status ( reaction , CLEAN ) ;
}
if ( is _disconnected ) {
reaction . f ^= DISCONNECTED ;
}
}
return is _dirty ;
return false ;
}
/ * *
@ -490,6 +454,8 @@ export function update_effect(effect) {
execute _effect _teardown ( effect ) ;
var teardown = update _reaction ( effect ) ;
effect . teardown = typeof teardown === 'function' ? teardown : null ;
effect . version = current _version ;
} catch ( error ) {
handle _error ( /** @type {Error} */ ( error ) , effect , current _component _context ) ;
} finally {
@ -798,11 +764,31 @@ export function get(signal) {
}
}
if (
( flags & DERIVED ) !== 0 &&
check _dirtiness ( /** @type {import('#client').Derived} */ ( signal ) )
) {
update _derived ( /** @type {import('#client').Derived} **/ ( signal ) ) ;
if ( ( flags & DERIVED ) !== 0 ) {
var derived = /** @type {import('#client').Derived} */ ( signal ) ;
if ( check _dirtiness ( derived ) ) {
update _derived ( derived ) ;
}
if ( ( flags & DISCONNECTED ) !== 0 ) {
// reconnect to the graph
deps = derived . deps ;
if ( deps !== null ) {
for ( var i = 0 ; i < deps . length ; i ++ ) {
var dep = deps [ i ] ;
var reactions = dep . reactions ;
if ( reactions === null ) {
dep . reactions = [ derived ] ;
} else if ( ! reactions . includes ( derived ) ) {
reactions . push ( derived ) ;
}
}
}
derived . f ^= DISCONNECTED ;
}
}
return signal . v ;
@ -845,52 +831,6 @@ export function invalidate_inner_signals(fn) {
}
}
/ * *
* @ param { import ( '#client' ) . Value } signal
* @ param { number } status should be DIRTY or MAYBE _DIRTY
* @ param { boolean } force _schedule
* @ returns { void }
* /
export function mark _reactions ( signal , status , force _schedule ) {
var reactions = signal . reactions ;
if ( reactions === null ) return ;
var runes = is _runes ( ) ;
var length = reactions . length ;
for ( var i = 0 ; i < length ; i ++ ) {
var reaction = reactions [ i ] ;
var flags = reaction . f ;
if ( DEV && ( flags & INSPECT _EFFECT ) !== 0 ) {
inspect _effects . add ( reaction ) ;
continue ;
}
// We skip any effects that are already dirty. Additionally, we also
// skip if the reaction is the same as the current effect (except if we're not in runes or we
// are in force schedule mode).
if ( ( flags & DIRTY ) !== 0 || ( ( ! force _schedule || ! runes ) && reaction === current _effect ) ) {
continue ;
}
set _signal _status ( reaction , status ) ;
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ( ( flags & ( CLEAN | UNOWNED ) ) !== 0 ) {
if ( ( flags & DERIVED ) !== 0 ) {
mark _reactions (
/** @type {import('#client').Derived} */ ( reaction ) ,
MAYBE _DIRTY ,
force _schedule
) ;
} else {
schedule _effect ( /** @type {import('#client').Effect} */ ( reaction ) ) ;
}
}
}
}
/ * *
* Use ` untrack ` to prevent something from being treated as an ` $ effect ` / ` $ derived ` dependency .
*