@ -1,4 +1,4 @@
/** @import { ComponentContext, Derived, Effect, Reaction, Signal, Source, Value } from '#client' */
/** @import { Derived, Effect, Reaction, Signal, Source, Value } from '#client' */
import { DEV } from 'esm-env' ;
import { define _property , get _descriptors , get _prototype _of , index _of } from '../shared/utils.js' ;
import {
@ -22,14 +22,13 @@ import {
ROOT _EFFECT ,
LEGACY _DERIVED _PROP ,
DISCONNECTED ,
BOUNDARY _EFFECT ,
EFFECT _IS _UPDATING
} from './constants.js' ;
import { flush _tasks } from './dom/task.js' ;
import { internal _set , old _values } from './reactivity/sources.js' ;
import { destroy _derived _effects , update _derived } from './reactivity/deriveds.js' ;
import * as e from './errors.js' ;
import { FILENAME } from '../../constants.js' ;
import { tracing _mode _flag } from '../flags/index.js' ;
import { tracing _expressions , get _stack } from './dev/tracing.js' ;
import {
@ -39,12 +38,7 @@ import {
set _component _context ,
set _dev _current _component _function
} from './context.js' ;
import { is _firefox } from './dom/operations.js' ;
// Used for DEV time error handling
/** @param {WeakSet<Error>} value */
const handled _errors = new WeakSet ( ) ;
let is _throwing _error = false ;
import { handle _error , invoke _error _boundary } from './error-handling.js' ;
let is _flushing = false ;
@ -227,131 +221,6 @@ export function check_dirtiness(reaction) {
return false ;
}
/ * *
* @ param { unknown } error
* @ param { Effect } effect
* /
function propagate _error ( error , effect ) {
/** @type {Effect | null} */
var current = effect ;
while ( current !== null ) {
if ( ( current . f & BOUNDARY _EFFECT ) !== 0 ) {
try {
// @ts-expect-error
current . fn ( error ) ;
return ;
} catch {
// Remove boundary flag from effect
current . f ^= BOUNDARY _EFFECT ;
}
}
current = current . parent ;
}
is _throwing _error = false ;
throw error ;
}
/ * *
* @ param { Effect } effect
* /
function should _rethrow _error ( effect ) {
return (
( effect . f & DESTROYED ) === 0 &&
( effect . parent === null || ( effect . parent . f & BOUNDARY _EFFECT ) === 0 )
) ;
}
export function reset _is _throwing _error ( ) {
is _throwing _error = false ;
}
/ * *
* @ param { unknown } error
* @ param { Effect } effect
* @ param { Effect | null } previous _effect
* @ param { ComponentContext | null } component _context
* /
export function handle _error ( error , effect , previous _effect , component _context ) {
if ( is _throwing _error ) {
if ( previous _effect === null ) {
is _throwing _error = false ;
}
if ( should _rethrow _error ( effect ) ) {
throw error ;
}
return ;
}
if ( previous _effect !== null ) {
is _throwing _error = true ;
}
if ( DEV && component _context !== null && error instanceof Error && ! handled _errors . has ( error ) ) {
handled _errors . add ( error ) ;
const component _stack = [ ] ;
const effect _name = effect . fn ? . name ;
if ( effect _name ) {
component _stack . push ( effect _name ) ;
}
/** @type {ComponentContext | null} */
let current _context = component _context ;
while ( current _context !== null ) {
/** @type {string} */
var filename = current _context . function ? . [ FILENAME ] ;
if ( filename ) {
const file = filename . split ( '/' ) . pop ( ) ;
component _stack . push ( file ) ;
}
current _context = current _context . p ;
}
const indent = is _firefox ? ' ' : '\t' ;
define _property ( error , 'message' , {
value :
error . message + ` \n ${ component _stack . map ( ( name ) => ` \n ${ indent } in ${ name } ` ) . join ( '' ) } \n `
} ) ;
define _property ( error , 'component_stack' , {
value : component _stack
} ) ;
const stack = error . stack ;
// Filter out internal files from callstack
if ( stack ) {
const lines = stack . split ( '\n' ) ;
const new _lines = [ ] ;
for ( let i = 0 ; i < lines . length ; i ++ ) {
const line = lines [ i ] ;
if ( line . includes ( 'svelte/src/internal' ) ) {
continue ;
}
new _lines . push ( line ) ;
}
define _property ( error , 'stack' , {
value : new _lines . join ( '\n' )
} ) ;
}
}
propagate _error ( error , effect ) ;
if ( should _rethrow _error ( effect ) ) {
throw error ;
}
}
/ * *
* @ param { Value } signal
* @ param { Effect } effect
@ -379,11 +248,7 @@ function schedule_possible_effect_self_invalidation(signal, effect, root = true)
}
}
/ * *
* @ template V
* @ param { Reaction } reaction
* @ returns { V }
* /
/** @param {Reaction} reaction */
export function update _reaction ( reaction ) {
var previous _deps = new _deps ;
var previous _skipped _deps = skipped _deps ;
@ -473,6 +338,8 @@ export function update_reaction(reaction) {
}
return result ;
} catch ( error ) {
handle _error ( error ) ;
} finally {
new _deps = previous _deps ;
skipped _deps = previous _skipped _deps ;
@ -558,7 +425,6 @@ export function update_effect(effect) {
set _signal _status ( effect , CLEAN ) ;
var previous _effect = active _effect ;
var previous _component _context = component _context ;
var was _updating _effect = is _updating _effect ;
active _effect = effect ;
@ -601,8 +467,6 @@ export function update_effect(effect) {
if ( DEV ) {
dev _effect _stack . push ( effect ) ;
}
} catch ( error ) {
handle _error ( error , effect , previous _effect , previous _component _context || effect . ctx ) ;
} finally {
is _updating _effect = was _updating _effect ;
active _effect = previous _effect ;
@ -637,14 +501,14 @@ function infinite_loop_guard() {
if ( last _scheduled _effect !== null ) {
if ( DEV ) {
try {
handle_error ( error , last _scheduled _effect , null , null ) ;
invoke_error _boundary ( error , last _scheduled _effect ) ;
} catch ( e ) {
// Only log the effect stack if the error is re-thrown
log _effect _stack ( ) ;
throw e ;
}
} else {
handle_error ( error , last _scheduled _effect , null , null ) ;
invoke_error _boundary ( error , last _scheduled _effect ) ;
}
} else {
if ( DEV ) {
@ -701,27 +565,23 @@ function flush_queued_effects(effects) {
var effect = effects [ i ] ;
if ( ( effect . f & ( DESTROYED | INERT ) ) === 0 ) {
try {
if ( check _dirtiness ( effect ) ) {
update _effect ( effect ) ;
// Effects with no dependencies or teardown do not get added to the effect tree.
// Deferred effects (e.g. `$effect(...)`) _are_ added to the tree because we
// don't know if we need to keep them until they are executed. Doing the check
// here (rather than in `update_effect`) allows us to skip the work for
// immediate effects.
if ( effect . deps === null && effect . first === null && effect . nodes _start === null ) {
if ( effect . teardown === null ) {
// remove this effect from the graph
unlink _effect ( effect ) ;
} else {
// keep the effect in the graph, but free up some memory
effect . fn = null ;
}
if ( check _dirtiness ( effect ) ) {
update _effect ( effect ) ;
// Effects with no dependencies or teardown do not get added to the effect tree.
// Deferred effects (e.g. `$effect(...)`) _are_ added to the tree because we
// don't know if we need to keep them until they are executed. Doing the check
// here (rather than in `update_effect`) allows us to skip the work for
// immediate effects.
if ( effect . deps === null && effect . first === null && effect . nodes _start === null ) {
if ( effect . teardown === null ) {
// remove this effect from the graph
unlink _effect ( effect ) ;
} else {
// keep the effect in the graph, but free up some memory
effect . fn = null ;
}
}
} catch ( error ) {
handle _error ( error , effect , null , effect . ctx ) ;
}
}
}
@ -780,12 +640,8 @@ function process_effects(root) {
} else if ( is _branch ) {
effect . f ^= CLEAN ;
} else {
try {
if ( check _dirtiness ( effect ) ) {
update _effect ( effect ) ;
}
} catch ( error ) {
handle _error ( error , effect , null , effect . ctx ) ;
if ( check _dirtiness ( effect ) ) {
update _effect ( effect ) ;
}
}
@ -832,6 +688,13 @@ export function flushSync(fn) {
flush _tasks ( ) ;
if ( queued _root _effects . length === 0 ) {
// this would be reset in `flush_queued_root_effects` but since we are early returning here,
// we need to reset it here as well in case the first time there's 0 queued root effects
is _flushing = false ;
last _scheduled _effect = null ;
if ( DEV ) {
dev _effect _stack = [ ] ;
}
return /** @type {T} */ ( result ) ;
}