import { valueEqual } from '@react-force/utils' ; import Debug from 'debug' ; import { RouterState } from './RouterState' ; import { RouterStore , Route } from './RouterStore' ; const debug = Debug ( 'msr:TransitionState' ) ; export class TransitionState { private transitions : number = 0 ; private readonly fromRoute : Route ; private readonly transitionsThreshold : number = 100 ; constructor ( private routerStore , private readonly fromState ) { this . fromRoute = Object . assign ( { } , this . routerStore . getRoute ( this . fromState . routeName ) ) ; } resolve ( toState ) { return this . transition ( toState ) ; } private async transition ( toState ) { debug ( 'transition from %o to %o)' , this . fromState , toState ) ; if ( this . transitions >= this . transitionsThreshold ) { throw new Error ( `Detected loop involving ${ this . fromState . routeName } -> ${ toState . routeName } transition.` ) ; } this . transitions ++ ; if ( valueEqual ( this . fromState , toState ) ) { debug ( 'states are equal, skipping' ) ; return toState ; } const toRoute = this . routerStore . getRoute ( toState . routeName ) ; if ( ! this . fromRoute || ! toRoute ) { this . routerStore . setRouterState ( this . routerStore . notFoundState ) ; return toState ; } let redirectState ; if ( this . fromRoute . beforeExit ) { redirectState = await this . fromRoute . beforeExit ( this . fromState , toState , this . routerStore ) ; this . fromRoute . beforeExit = undefined ; if ( redirectState && ! valueEqual ( redirectState , toState ) ) { return this . transition ( redirectState ) ; } } if ( toRoute . beforeEnter ) { redirectState = await toRoute . beforeEnter ( this . fromState , toState , this . routerStore ) ; if ( redirectState && ! valueEqual ( redirectState , toState ) ) { return this . transition ( redirectState ) ; } } if ( this . fromRoute . onExit ) { redirectState = await this . fromRoute . onExit ( this . fromState , toState , this . routerStore ) ; this . fromRoute . onExit = undefined ; if ( redirectState && ! valueEqual ( redirectState , toState ) ) { return this . transition ( redirectState ) ; } } if ( toRoute . onEnter ) { redirectState = await toRoute . onEnter ( this . fromState , toState , this . routerStore ) ; if ( redirectState && ! valueEqual ( redirectState , toState ) ) { return this . transition ( redirectState ) ; } } this . routerStore . setRouterState ( toState ) ; return toState ; } }