@ -7,111 +7,135 @@ import {
set _current _reaction ,
set _current _reaction ,
set _dev _current _component _function
set _dev _current _component _function
} from '../../runtime.js' ;
} from '../../runtime.js' ;
import { block , branch , destroy _effect , pause _effect } from '../../reactivity/effects.js' ;
import { block , branch , pause _effect , resume _effect } from '../../reactivity/effects.js' ;
import { INERT } from '../../constants.js' ;
import { DEV } from 'esm-env' ;
import { DEV } from 'esm-env' ;
import { queue _micro _task } from '../task.js' ;
import { hydrating } from '../hydration.js' ;
import { set , source } from '../../reactivity/sources.js' ;
const PENDING = 0 ;
const THEN = 1 ;
const CATCH = 2 ;
/ * *
/ * *
* @ template V
* @ template V
* @ param { Comment } anchor
* @ param { Comment } anchor
* @ param { ( ( ) => Promise < V > ) } get _input
* @ param { ( ( ) => Promise < V > ) } get _input
* @ param { null | ( ( anchor : Node ) => void ) } pending _fn
* @ param { null | ( ( anchor : Node ) => void ) } pending _fn
* @ param { null | ( ( anchor : Node , value : V ) => void ) } then _fn
* @ param { null | ( ( anchor : Node , value : import ( '#client' ) . Source < V > ) => void ) } then _fn
* @ param { null | ( ( anchor : Node , error : unknown ) => void ) } catch _fn
* @ param { null | ( ( anchor : Node , error : unknown ) => void ) } catch _fn
* @ returns { void }
* @ returns { void }
* /
* /
export function await _block ( anchor , get _input , pending _fn , then _fn , catch _fn ) {
export function await _block ( anchor , get _input , pending _fn , then _fn , catch _fn ) {
const component _context = current _component _context ;
var component _context = current _component _context ;
/** @type {any} */
let component _function ;
if ( DEV ) {
component _function = component _context ? . function ? ? null ;
}
/** @type {any} */
/** @type {any} */
let input ;
var component _function = DEV ? component _context ? . function : null ;
/** @type {V | Promise<V>} */
var input ;
/** @type {import('#client').Effect | null} */
/** @type {import('#client').Effect | null} */
let pending _effect ;
var pending _effect ;
/** @type {import('#client').Effect | null} */
/** @type {import('#client').Effect | null} */
let then _effect ;
var then _effect ;
/** @type {import('#client').Effect | null} */
/** @type {import('#client').Effect | null} */
let catch _effect ;
var catch _effect ;
var input _source = source ( /** @type {V} */ ( undefined ) ) ;
var error _source = source ( undefined ) ;
var resolved = false ;
/ * *
/ * *
* @ param { ( anchor : Comment , value : any ) => void } fn
* @ param { PENDING | THEN | CATCH } state
* @ param { any } value
* @ param { boolean } restor e
* /
* /
function create _effect ( fn , value ) {
function update ( state , restore ) {
set _current _effect ( effect ) ;
resolved = true ;
set _current _reaction ( effect ) ; // TODO do we need both?
set _current _component _context ( component _context ) ;
if ( restore ) {
if ( DEV ) {
set _current _effect ( effect ) ;
set _dev _current _component _function ( component _function ) ;
set _current _reaction ( effect ) ; // TODO do we need both?
set _current _component _context ( component _context ) ;
if ( DEV ) set _dev _current _component _function ( component _function ) ;
}
if ( state === PENDING && pending _fn ) {
if ( pending _effect ) resume _effect ( pending _effect ) ;
else pending _effect = branch ( ( ) => pending _fn ( anchor ) ) ;
}
if ( state === THEN && then _fn ) {
if ( then _effect ) resume _effect ( then _effect ) ;
else then _effect = branch ( ( ) => then _fn ( anchor , input _source ) ) ;
}
if ( state === CATCH && catch _fn ) {
if ( catch _effect ) resume _effect ( catch _effect ) ;
else catch _effect = branch ( ( ) => catch _fn ( anchor , error _source ) ) ;
}
if ( state !== PENDING && pending _effect ) {
pause _effect ( pending _effect , ( ) => ( pending _effect = null ) ) ;
}
}
var e = branch ( ( ) => fn ( anchor , value ) ) ;
if ( DEV ) {
if ( state !== THEN && then _effect ) {
set _dev _current _component _function ( null ) ;
pause _effect ( then _effect , ( ) => ( then _effect = null ) ) ;
}
if ( state !== CATCH && catch _effect ) {
pause _effect ( catch _effect , ( ) => ( catch _effect = null ) ) ;
}
}
set _current _component _context ( null ) ;
set _current _reaction ( null ) ;
set _current _effect ( null ) ;
// without this, the DOM does not update until two ticks after the promise,
if ( restore ) {
// resolves which is unexpected behaviour (and somewhat irksome to test)
if ( DEV ) set _dev _current _component _function ( null ) ;
flush _sync ( ) ;
set _current _component _context ( null ) ;
set _current _reaction ( null ) ;
set _current _effect ( null ) ;
return e ;
// without this, the DOM does not update until two ticks after the promise
// resolves, which is unexpected behaviour (and somewhat irksome to test)
flush _sync ( ) ;
}
}
}
const effect = block ( ( ) => {
var effect = block ( ( ) => {
if ( input === ( input = get _input ( ) ) ) return ;
if ( input === ( input = get _input ( ) ) ) return ;
if ( is _promise ( input ) ) {
if ( is _promise ( input ) ) {
const promise = /** @type {Promise<any>} */ ( input ) ;
var promise = input ;
if ( pending _fn ) {
resolved = false ;
if ( pending _effect && ( pending _effect . f & INERT ) === 0 ) {
destroy _effect ( pending _effect ) ;
}
pending _effect = branch ( ( ) => pending _fn ( anchor ) ) ;
}
if ( then _effect ) pause _effect ( then _effect ) ;
if ( catch _effect ) pause _effect ( catch _effect ) ;
promise . then (
promise . then (
( value ) => {
( value ) => {
if ( promise !== input ) return ;
if ( promise !== input ) return ;
if ( pending _effect ) pause _effect ( pending _effect ) ;
set ( input _source , value ) ;
update ( THEN , true ) ;
if ( then _fn ) {
then _effect = create _effect ( then _fn , value ) ;
}
} ,
} ,
( error ) => {
( error ) => {
if ( promise !== input ) return ;
if ( promise !== input ) return ;
if ( pending _effect ) pause _effect ( pending _effect ) ;
set ( error _source , error ) ;
update ( CATCH , true ) ;
if ( catch _fn ) {
catch _effect = create _effect ( catch _fn , error ) ;
}
}
}
) ;
) ;
} else {
if ( pending _effect ) pause _effect ( pending _effect ) ;
if ( catch _effect ) pause _effect ( catch _effect ) ;
if ( then_fn ) {
if ( hydrating ) {
if ( then_effect ) {
if ( pending _fn ) {
destroy_effect ( then _effect ) ;
pending_effect = branch ( ( ) => pending _fn ( anchor ) ) ;
}
}
} else {
then _effect = branch ( ( ) => then _fn ( anchor , input ) ) ;
// Wait a microtask before checking if we should show the pending state as
// the promise might have resolved by the next microtask.
queue _micro _task ( ( ) => {
if ( ! resolved ) update ( PENDING , true ) ;
} ) ;
}
}
} else {
set ( input _source , input ) ;
update ( THEN , false ) ;
}
}
// Inert effects are proactively detached from the effect tree. Returning a noop
// Inert effects are proactively detached from the effect tree. Returning a noop