@ -1,16 +1,14 @@
import { DEV } from 'esm-env' ;
import { run _all } from '../common.js' ;
import {
array _prototype ,
get _descriptors ,
get _prototype _of ,
is _array ,
is _frozen ,
object _freeze ,
object _prototype
} from './utils.js' ;
import { unstate } from './proxy.js' ;
import { pre_effect } from './reactivity/effects.js' ;
import { destroy_effect , pre_effect } from './reactivity/effects.js' ;
import {
EACH _BLOCK ,
IF _BLOCK ,
@ -18,7 +16,6 @@ import {
PRE _EFFECT ,
RENDER _EFFECT ,
DIRTY ,
UNINITIALIZED ,
MAYBE _DIRTY ,
CLEAN ,
DERIVED ,
@ -31,8 +28,7 @@ import {
import { flush _tasks } from './dom/task.js' ;
import { add _owner } from './dev/ownership.js' ;
import { mutate , set , source } from './reactivity/sources.js' ;
const IS _EFFECT = EFFECT | PRE _EFFECT | RENDER _EFFECT ;
import { destroy _derived , update _derived } from './reactivity/deriveds.js' ;
const FLUSH _MICROTASK = 0 ;
const FLUSH _SYNC = 1 ;
@ -55,10 +51,10 @@ let current_queued_pre_and_render_effects = [];
let current _queued _effects = [ ] ;
let flush _count = 0 ;
// Handle signal reactivity tree dependencies and consumer
// Handle signal reactivity tree dependencies and rea cti ons
/** @type {null | import('./types.js').Reaction} */
export let current _ consumer = null ;
export let current _ rea cti on = null ;
/** @type {null | import('./types.js').Effect} */
export let current _effect = null ;
@ -96,8 +92,8 @@ export function set_ignore_mutation_validation(value) {
}
// If we are working with a get() chain that has no active container,
// to prevent memory leaks, we skip adding the consumer .
let current _skip _ consumer = false ;
// to prevent memory leaks, we skip adding the rea cti on.
export let current _skip _ rea cti on = false ;
// Handle collecting all signals which are read during a specific time frame
export let is _signals _recorded = false ;
let captured _signals = new Set ( ) ;
@ -116,15 +112,9 @@ export let current_block = null;
/** @type {import('./types.js').ComponentContext | null} */
export let current _component _context = null ;
export let updating _derived = false ;
/ * *
* @ param { null | import ( './types.js' ) . ComponentContext } context
* @ returns { boolean }
* /
export function is _runes ( context ) {
const component _context = context || current _component _context ;
return component _context !== null && component _context . r ;
/** @returns {boolean} */
export function is _runes ( ) {
return current _component _context !== null && current _component _context . r ;
}
/ * *
@ -160,51 +150,53 @@ export function batch_inspect(target, prop, receiver) {
}
/ * *
* @ param { import ( './types.js' ) . Signal } signal
* Determines whether a derived or effect is dirty .
* If it is MAYBE _DIRTY , will set the status to CLEAN
* @ param { import ( './types.js' ) . Reaction } reaction
* @ returns { boolean }
* /
function is _signal _dirty ( signal ) {
const flags = signal . f ;
if ( ( flags & DIRTY ) !== 0 || signal . v === UNINITIALIZED ) {
function check _dirtiness ( reaction ) {
var flags = reaction . f ;
if ( ( flags & DIRTY ) !== 0 ) {
return true ;
}
if ( ( flags & MAYBE _DIRTY ) !== 0 ) {
const dependencies = /** @type {import('./types.js').Reaction} **/ ( signal ) . d ;
var dependencies = reaction . deps ;
if ( dependencies !== null ) {
const length = dependencies . length ;
let i ;
for ( i = 0 ; i < length ; i ++ ) {
const dependency = dependencies [ i ] ;
if ( ( dependency . f & MAYBE _DIRTY ) !== 0 && ! is _signal _dirty ( dependency ) ) {
set _signal _status ( dependency , CLEAN ) ;
continue ;
}
// The flags can be marked as dirty from the above is_signal_dirty call.
if ( ( dependency . f & DIRTY ) !== 0 ) {
if ( ( dependency . f & DERIVED ) !== 0 ) {
update _derived ( /** @type {import('./types.js').Derived} **/ ( dependency ) , true ) ;
// Might have been mutated from above get.
if ( ( signal . f & DIRTY ) !== 0 ) {
return true ;
}
} else {
var length = dependencies . length ;
for ( var i = 0 ; i < length ; i ++ ) {
var dependency = dependencies [ i ] ;
if ( check _dirtiness ( /** @type {import('#client').Derived} */ ( dependency ) ) ) {
update _derived ( /** @type {import('#client').Derived} **/ ( dependency ) , true ) ;
// `signal` might now be dirty, as a result of calling `update_derived`
if ( ( reaction . f & DIRTY ) !== 0 ) {
return true ;
}
}
// If we're workig with an unowned derived signal, then we need to check
// if our dependency write version is higher. If is is then we can assume
// 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.
const is _unowned = ( flags & UNOWNED ) !== 0 ;
const write _version = signal . w ;
const dep _write _version = dependency . w ;
if ( is _unowned && dep_write _version > write _ version) {
signal . w = dep _write _ version;
var is _unowned = ( flags & UNOWNED ) !== 0 ;
var version = dependency . version ;
if ( is _unowned && version > /** @type {import('#client').Derived} */ ( reaction ) . version) {
/** @type {import('#client').Derived} */ ( reaction ) . version = version;
return true ;
}
}
}
set _signal _status ( reaction , CLEAN ) ;
}
return false ;
}
@ -213,41 +205,40 @@ function is_signal_dirty(signal) {
* @ param { import ( './types.js' ) . Reaction } signal
* @ returns { V }
* /
function execute _signal _fn ( signal ) {
const init = signal . i ;
export function execute _reaction _fn ( signal ) {
const fn = signal . fn ;
const flags = signal . f ;
const is _render _effect = ( flags & RENDER _EFFECT ) !== 0 ;
const previous _dependencies = current _dependencies ;
const previous _dependencies _index = current _dependencies _index ;
const previous _untracked _writes = current _untracked _writes ;
const previous _consumer = current _consumer ;
const previous _block = current _block ;
const previous _component _context = current _component _context ;
const previous _skip _consumer = current _skip _consumer ;
const is _render _effect = ( flags & RENDER _EFFECT ) !== 0 ;
const previous _reaction = current _reaction ;
const previous _skip _reaction = current _skip _reaction ;
const previous _untracking = current _untracking ;
current _dependencies = /** @type {null | import('./types.js').Value[]} */ ( null ) ;
current _dependencies _index = 0 ;
current _untracked _writes = null ;
current _consumer = signal ;
current _block = signal . b ;
current _component _context = signal . x ;
current _skip _consumer = ! is _flushing _effect && ( flags & UNOWNED ) !== 0 ;
current _reaction = signal ;
current _skip _reaction = ! is _flushing _effect && ( flags & UNOWNED ) !== 0 ;
current _untracking = false ;
try {
let res ;
if ( is _render _effect ) {
res =
/** @type {(block: import('./types.js').Block, signal: import('./types.js').Signal) => V} */ (
init
) (
/** @type {import('./types.js').Block} */ ( signal . b ) ,
/** @type {import('./types.js').Signal} */ ( signal )
) ;
res = /** @type {(block: import('#client').Block, signal: import('#client').Signal) => V} */ (
fn
) (
/** @type {import('#client').Block} */ (
/** @type {import('#client').Effect} */ ( signal ) . block
) ,
/** @type {import('#client').Signal} */ ( signal )
) ;
} else {
res = /** @type {() => V} */ ( init ) ( ) ;
res = /** @type {() => V} */ ( fn ) ( ) ;
}
let dependencies = /** @type {import('./types.js').Value<unknown>[]} **/ ( signal . d ) ;
let dependencies = /** @type {import('./types.js').Value<unknown>[]} **/ ( signal . d eps ) ;
if ( current _dependencies !== null ) {
let i ;
if ( dependencies !== null ) {
@ -271,7 +262,7 @@ function execute_signal_fn(signal) {
? ! full _current _dependencies _set . has ( dependency )
: ! full _current _dependencies . includes ( dependency )
) {
remove _ consumer ( signal , dependency ) ;
remove _ rea cti on( signal , dependency ) ;
}
}
}
@ -282,29 +273,29 @@ function execute_signal_fn(signal) {
dependencies [ current _dependencies _index + i ] = current _dependencies [ i ] ;
}
} else {
signal . d = /** @type {import('./types.js').Value<V>[]} **/ (
signal . d eps = /** @type {import('./types.js').Value<V>[]} **/ (
dependencies = current _dependencies
) ;
}
if ( ! current _skip _ consumer ) {
if ( ! current _skip _ rea cti on) {
for ( i = current _dependencies _index ; i < dependencies . length ; i ++ ) {
const dependency = dependencies [ i ] ;
const consumer s = dependency . c;
const rea cti ons = dependency . rea ctions ;
if ( consumer s === null ) {
dependency . c = [ signal ] ;
} else if ( consumer s[ consumer s. length - 1 ] !== signal ) {
if ( rea cti ons === null ) {
dependency . rea ctions = [ signal ] ;
} else if ( rea cti ons[ rea cti ons. length - 1 ] !== signal ) {
// TODO: should this be:
//
// } else if (! consumer s.includes(signal)) {
// } else if (! rea cti ons.includes(signal)) {
//
consumer s. push ( signal ) ;
rea cti ons. push ( signal ) ;
}
}
}
} else if ( dependencies !== null && current _dependencies _index < dependencies . length ) {
remove _ consumer s( signal , current _dependencies _index ) ;
remove _ rea cti ons( signal , current _dependencies _index ) ;
dependencies . length = current _dependencies _index ;
}
return res ;
@ -312,10 +303,8 @@ function execute_signal_fn(signal) {
current _dependencies = previous _dependencies ;
current _dependencies _index = previous _dependencies _index ;
current _untracked _writes = previous _untracked _writes ;
current _consumer = previous _consumer ;
current _block = previous _block ;
current _component _context = previous _component _context ;
current _skip _consumer = previous _skip _consumer ;
current _reaction = previous _reaction ;
current _skip _reaction = previous _skip _reaction ;
current _untracking = previous _untracking ;
}
}
@ -326,26 +315,26 @@ function execute_signal_fn(signal) {
* @ param { import ( './types.js' ) . Value < V > } dependency
* @ returns { void }
* /
function remove _ consumer ( signal , dependency ) {
const consumer s = dependency . c;
let consumer s_length = 0 ;
if ( consumer s !== null ) {
consumer s_length = consumer s. length - 1 ;
const index = consumer s. indexOf ( signal ) ;
function remove _ rea cti on( signal , dependency ) {
const rea cti ons = dependency . rea ctions ;
let rea cti ons_length = 0 ;
if ( rea cti ons !== null ) {
rea cti ons_length = rea cti ons. length - 1 ;
const index = rea cti ons. indexOf ( signal ) ;
if ( index !== - 1 ) {
if ( consumer s_length === 0 ) {
dependency . c = null ;
if ( rea cti ons_length === 0 ) {
dependency . rea ctions = null ;
} else {
// Swap with last element and then remove.
consumer s[ index ] = consumers [ consumer s_length ] ;
consumer s. pop ( ) ;
rea cti ons[ index ] = rea cti ons[ rea cti ons_length ] ;
rea cti ons. pop ( ) ;
}
}
}
if ( consumer s_length === 0 && ( dependency . f & UNOWNED ) !== 0 ) {
if ( rea cti ons_length === 0 && ( dependency . f & UNOWNED ) !== 0 ) {
// If the signal is unowned then we need to make sure to change it to dirty.
set _signal _status ( dependency , DIRTY ) ;
remove _ consumer s( /** @type {import('./types.js'). Reaction } **/ ( dependency ) , 0 ) ;
remove _ rea cti ons( /** @type {import('./types.js'). Derived } **/ ( dependency ) , 0 ) ;
}
}
@ -354,16 +343,16 @@ function remove_consumer(signal, dependency) {
* @ param { number } start _index
* @ returns { void }
* /
function remove _ consumer s( signal , start _index ) {
const dependencies = signal . d ;
export function remove _ rea cti ons( signal , start _index ) {
const dependencies = signal . d eps ;
if ( dependencies !== null ) {
const active _dependencies = start _index === 0 ? null : dependencies . slice ( 0 , start _index ) ;
let i ;
for ( i = start _index ; i < dependencies . length ; i ++ ) {
const dependency = dependencies [ i ] ;
// Avoid removing a consumer if we know that it is active (start_index will not be 0)
// Avoid removing a rea cti on if we know that it is active (start_index will not be 0)
if ( active _dependencies === null || ! active _dependencies . includes ( dependency ) ) {
remove _ consumer ( signal , dependency ) ;
remove _ rea cti on( signal , dependency ) ;
}
}
}
@ -373,28 +362,19 @@ function remove_consumers(signal, start_index) {
* @ param { import ( './types.js' ) . Reaction } signal
* @ returns { void }
* /
function destroy _references ( signal ) {
const references = signal . r ;
signal . r = null ;
if ( references !== null ) {
let i ;
for ( i = 0 ; i < references . length ; i ++ ) {
destroy _signal ( references [ i ] ) ;
export function destroy _children ( signal ) {
if ( signal . effects ) {
for ( var i = 0 ; i < signal . effects . length ; i += 1 ) {
destroy _effect ( signal . effects [ i ] ) ;
}
signal . effects = null ;
}
}
/ * *
* @ param { import ( './types.js' ) . Block } block
* @ param { unknown } error
* @ returns { void }
* /
function report _error ( block , error ) {
/** @type {import('./types.js').Block | null} */
let current _block = block ;
if ( current _block !== null ) {
throw error ;
if ( signal . deriveds ) {
for ( i = 0 ; i < signal . deriveds . length ; i += 1 ) {
destroy _derived ( signal . deriveds [ i ] ) ;
}
signal . deriveds = null ;
}
}
@ -406,30 +386,28 @@ export function execute_effect(signal) {
if ( ( signal . f & DESTROYED ) !== 0 ) {
return ;
}
const teardown = signal . v ;
const previous _effect = current _effect ;
const previous _component _context = current _component _context ;
const previous _block = current _block ;
const component _context = signal . ctx ;
current _effect = signal ;
current _component _context = component _context ;
current _block = signal . block ;
try {
destroy _references ( signal ) ;
if ( teardown !== null ) {
teardown ( ) ;
}
const possible _teardown = execute _signal _fn ( signal ) ;
if ( typeof possible _teardown === 'function' ) {
signal . v = possible _teardown ;
}
} catch ( error ) {
const block = signal . b ;
if ( block !== null ) {
report _error ( block , error ) ;
} else {
throw error ;
}
destroy _children ( signal ) ;
signal . teardown ? . ( ) ;
const teardown = execute _reaction _fn ( signal ) ;
signal . teardown = typeof teardown === 'function' ? teardown : null ;
} finally {
current _effect = previous _effect ;
current _component _context = previous _component _context ;
current _block = previous _block ;
}
const component _context = signal . x ;
if ( ( signal . f & PRE _EFFECT ) !== 0 && current _queued _pre _and _render _effects . length > 0 ) {
flush _local _pre _effects ( component _context ) ;
}
@ -454,31 +432,29 @@ function infinite_loop_guard() {
* @ returns { void }
* /
function flush _queued _effects ( effects ) {
const length = effects . length ;
if ( length > 0 ) {
infinite _loop _guard ( ) ;
const previously _flushing _effect = is _flushing _effect ;
is _flushing _effect = true ;
try {
let i ;
for ( i = 0 ; i < length ; i ++ ) {
const signal = effects [ i ] ;
const flags = signal . f ;
if ( ( flags & ( DESTROYED | INERT ) ) === 0 ) {
if ( is _signal _dirty ( signal ) ) {
set _signal _status ( signal , CLEAN ) ;
execute _effect ( signal ) ;
} else if ( ( flags & MAYBE _DIRTY ) !== 0 ) {
set _signal _status ( signal , CLEAN ) ;
}
var length = effects . length ;
if ( length === 0 ) return ;
infinite _loop _guard ( ) ;
var previously _flushing _effect = is _flushing _effect ;
is _flushing _effect = true ;
try {
for ( var i = 0 ; i < length ; i ++ ) {
var signal = effects [ i ] ;
if ( ( signal . f & ( DESTROYED | INERT ) ) === 0 ) {
if ( check _dirtiness ( signal ) ) {
set _signal _status ( signal , CLEAN ) ;
execute _effect ( signal ) ;
}
}
} finally {
is _flushing _effect = previously _flushing _effect ;
}
effects. length = 0 ;
} finally {
is_flushing _effect = previously _flushing _effect ;
}
effects . length = 0 ;
}
function process _microtask ( ) {
@ -540,7 +516,7 @@ export function schedule_effect(signal, sync) {
if ( ! should _append ) {
const target _level = signal . l ;
const target _block = signal . b ;
const target _block = signal . b lock ;
const is _pre _effect = ( flags & PRE _EFFECT ) !== 0 ;
let target _signal ;
let is _target _pre _effect ;
@ -552,7 +528,10 @@ export function schedule_effect(signal, sync) {
should _append = true ;
} else {
is _target _pre _effect = ( target _signal . f & PRE _EFFECT ) !== 0 ;
if ( target _signal . b !== target _block || ( is _target _pre _effect && ! is _pre _effect ) ) {
if (
target _signal . block !== target _block ||
( is _target _pre _effect && ! is _pre _effect )
) {
i ++ ;
}
current _queued _pre _and _render _effects . splice ( i , 0 , signal ) ;
@ -580,7 +559,7 @@ export function flush_local_render_effects() {
const effects = [ ] ;
for ( let i = 0 ; i < current _queued _pre _and _render _effects . length ; i ++ ) {
const effect = current _queued _pre _and _render _effects [ i ] ;
if ( ( effect . f & RENDER _EFFECT ) !== 0 && effect . x === current _component _context ) {
if ( ( effect . f & RENDER _EFFECT ) !== 0 && effect . ct x === current _component _context ) {
effects . push ( effect ) ;
current _queued _pre _and _render _effects . splice ( i , 1 ) ;
i -- ;
@ -597,7 +576,7 @@ export function flush_local_pre_effects(context) {
const effects = [ ] ;
for ( let i = 0 ; i < current _queued _pre _and _render _effects . length ; i ++ ) {
const effect = current _queued _pre _and _render _effects [ i ] ;
if ( ( effect . f & PRE _EFFECT ) !== 0 && effect . x === context ) {
if ( ( effect . f & PRE _EFFECT ) !== 0 && effect . ct x === context ) {
effects . push ( effect ) ;
current _queued _pre _and _render _effects . splice ( i , 1 ) ;
i -- ;
@ -670,34 +649,6 @@ export async function tick() {
flushSync ( ) ;
}
/ * *
* @ param { import ( './types.js' ) . Derived } signal
* @ param { boolean } force _schedule
* @ returns { void }
* /
function update _derived ( signal , force _schedule ) {
const previous _updating _derived = updating _derived ;
updating _derived = true ;
destroy _references ( signal ) ;
const value = execute _signal _fn ( signal ) ;
updating _derived = previous _updating _derived ;
const status =
( current _skip _consumer || ( signal . f & UNOWNED ) !== 0 ) && signal . d !== null
? MAYBE _DIRTY
: CLEAN ;
set _signal _status ( signal , status ) ;
const equals = /** @type {import('./types.js').EqualsFunctions} */ ( signal . e ) ;
if ( ! equals ( value , signal . v ) ) {
signal . v = value ;
mark _signal _consumers ( signal , DIRTY , force _schedule ) ;
// @ts-expect-error
if ( DEV && signal . inspect && force _schedule ) {
for ( const fn of /** @type {import('./types.js').ValueDebug} */ ( signal ) . inspect ) fn ( ) ;
}
}
}
/ * *
* @ template V
* @ param { import ( './types.js' ) . Value < V > } signal
@ -720,10 +671,10 @@ export function get(signal) {
captured _signals . add ( signal ) ;
}
// Register the dependency on the current consumer signal.
if ( current _ consumer !== null && ( current _ consumer . f & MANAGED ) === 0 && ! current _untracking ) {
const unowned = ( current _ consumer . f & UNOWNED ) !== 0 ;
const dependencies = current _ consumer . d ;
// Register the dependency on the current rea cti on signal.
if ( current _ rea cti on !== null && ( current _ rea cti on. f & MANAGED ) === 0 && ! current _untracking ) {
const unowned = ( current _ rea cti on. f & UNOWNED ) !== 0 ;
const dependencies = current _ rea cti on. d eps ;
if (
current _dependencies === null &&
dependencies !== null &&
@ -754,7 +705,10 @@ export function get(signal) {
}
}
if ( ( flags & DERIVED ) !== 0 && is _signal _dirty ( signal ) ) {
if (
( flags & DERIVED ) !== 0 &&
check _dirtiness ( /** @type {import('#client').Derived} */ ( signal ) )
) {
if ( DEV ) {
// we want to avoid tracking indirect dependencies
const previous _inspect _fn = inspect _fn ;
@ -797,28 +751,25 @@ export function invalidate_inner_signals(fn) {
}
/ * *
* @ param { import ( ' ./types.js') . Reaction } signal
* @ param { import ( ' #client') . Effect } signal
* @ param { boolean } inert
* @ param { Set < import ( ' ./types.js ') . Block > } [ visited _blocks ]
* @ param { Set < import ( ' #client ') . Block > } [ visited _blocks ]
* @ returns { void }
* /
function mark _subtree _children _inert ( signal , inert , visited _blocks ) {
const references = signal . r ;
if ( references !== null ) {
let i ;
for ( i = 0 ; i < references . length ; i ++ ) {
const reference = references [ i ] ;
if ( ( reference . f & IS _EFFECT ) !== 0 ) {
mark _subtree _inert ( reference , inert , visited _blocks ) ;
}
const effects = signal . effects ;
if ( effects !== null ) {
for ( var i = 0 ; i < effects . length ; i ++ ) {
const effect = effects [ i ] ;
mark _subtree _inert ( effect , inert , visited _blocks ) ;
}
}
}
/ * *
* @ param { import ( ' ./types.js') . Reaction } signal
* @ param { import ( ' #client') . Effect } signal
* @ param { boolean } inert
* @ param { Set < import ( ' ./types.js ') . Block > } [ visited _blocks ]
* @ param { Set < import ( ' #client ') . Block > } [ visited _blocks ]
* @ returns { void }
* /
export function mark _subtree _inert ( signal , inert , visited _blocks = new Set ( ) ) {
@ -826,11 +777,11 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
const is _already _inert = ( flags & INERT ) !== 0 ;
if ( is _already _inert !== inert ) {
signal . f ^= INERT ;
if ( ! inert && ( flags & IS_EFFECT ) !== 0 && ( flags & CLEAN) === 0 ) {
schedule _effect ( /** @type {import('./types.js').Effect} */ ( signal ) , false ) ;
if ( ! inert && ( flags & CLEAN) === 0 ) {
schedule _effect ( signal , false ) ;
}
// Nested if block effects
const block = signal . b ;
const block = signal . b lock ;
if ( block !== null && ! visited _blocks . has ( block ) ) {
visited _blocks . add ( block ) ;
const type = block . t ;
@ -861,65 +812,49 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
}
/ * *
* @ param { import ( ' ./types.js') . Signal } signal
* @ param { import ( ' #client') . Value } signal
* @ param { number } to _status
* @ param { boolean } force _schedule
* @ returns { void }
* /
export function mark _signal _consumers ( signal , to _status , force _schedule ) {
const runes = is _runes ( null ) ;
const consumers = signal . c ;
if ( consumers !== null ) {
const length = consumers . length ;
let i ;
for ( i = 0 ; i < length ; i ++ ) {
const consumer = consumers [ i ] ;
const flags = consumer . f ;
const unowned = ( flags & UNOWNED ) !== 0 ;
// We skip any effects that are already dirty (but not unowned). Additionally, we also
// skip if the consumer is the same as the current effect (except if we're not in runes or we
// are in force schedule mode).
if ( ( ! force _schedule || ! runes ) && consumer === current _effect ) {
continue ;
}
set _signal _status ( consumer , to _status ) ;
// If the signal is not clean, then skip over it – with the exception of unowned signals that
// are already maybe dirty. Unowned signals might be dirty because they are not captured as part of an
// effect.
const maybe _dirty = ( flags & MAYBE _DIRTY ) !== 0 ;
if ( ( flags & CLEAN ) !== 0 || ( maybe _dirty && unowned ) ) {
if ( ( consumer . f & IS _EFFECT ) !== 0 ) {
schedule _effect ( /** @type {import('./types.js').Effect} */ ( consumer ) , false ) ;
} else {
mark _signal _consumers ( consumer , MAYBE _DIRTY , force _schedule ) ;
}
}
export function mark _reactions ( signal , to _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 ] ;
// We skip any effects that are already dirty (but not unowned). 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 ( ( ! force _schedule || ! runes ) && reaction === current _effect ) {
continue ;
}
}
}
/ * *
* @ param { import ( './types.js' ) . Reaction } signal
* @ returns { void }
* /
export function destroy _signal ( signal ) {
const teardown = /** @type {null | (() => void)} */ ( signal . v ) ;
const destroy = signal . y ;
const flags = signal . f ;
destroy _references ( signal ) ;
remove _consumers ( signal , 0 ) ;
signal . i = signal . r = signal . y = signal . x = signal . b = signal . d = signal . c = null ;
set _signal _status ( signal , DESTROYED ) ;
if ( destroy !== null ) {
if ( is _array ( destroy ) ) {
run _all ( destroy ) ;
} else {
destroy ( ) ;
var flags = reaction . f ;
set _signal _status ( reaction , to _status ) ;
// If the signal is not clean, then skip over it – with the exception of unowned signals that
// are already maybe dirty. Unowned signals might be dirty because they are not captured as part of an
// effect.
var maybe _dirty = ( flags & MAYBE _DIRTY ) !== 0 ;
var unowned = ( flags & UNOWNED ) !== 0 ;
if ( ( flags & CLEAN ) !== 0 || ( maybe _dirty && unowned ) ) {
if ( ( reaction . f & DERIVED ) !== 0 ) {
mark _reactions (
/** @type {import('#client').Derived} */ ( reaction ) ,
MAYBE _DIRTY ,
force _schedule
) ;
} else {
schedule _effect ( /** @type {import('#client').Effect} */ ( reaction ) , false ) ;
}
}
}
if ( teardown !== null && ( flags & IS _EFFECT ) !== 0 ) {
teardown ( ) ;
}
}
/ * *
@ -940,22 +875,6 @@ export function untrack(fn) {
}
}
/ * *
* @ param { import ( './types.js' ) . Reaction } signal
* @ param { ( ) => void } destroy _fn
* @ returns { void }
* /
export function push _destroy _fn ( signal , destroy _fn ) {
let destroy = signal . y ;
if ( destroy === null ) {
signal . y = destroy _fn ;
} else if ( is _array ( destroy ) ) {
destroy . push ( destroy _fn ) ;
} else {
signal . y = [ destroy , destroy _fn ] ;
}
}
const STATUS _MASK = ~ ( DIRTY | MAYBE _DIRTY | CLEAN ) ;
/ * *
@ -1350,8 +1269,8 @@ export function inspect(get_value, inspect = console.log) {
/ * *
* @ template V
* @ param { V } value
* @ returns { import ( './types.js' ) . UnwrappedSignal < V > }
* @ param { V | import ( '#client' ) . Value < V > } value
* @ returns { V }
* /
export function unwrap ( value ) {
if ( is _signal ( value ) ) {