import Debug from 'debug' ; import { action , makeObservable , observable } from 'mobx' ; import { createRouterState , RouterState } from './RouterState' ; import { TransitionState } from './TransitionState' ; const debugSetState = Debug ( 'msr:setRouterState' ) ; /**
 * A function called when transitioning from fromState to toState.
 * If it returns a RouterState, then the router redirects to that state.
 * If it returns a void, then the router proceeds to the next transition hook.
 * When no more hooks are left, it simply navigates to toState.
 */ export type TransitionHook = ( fromState : RouterState , toState : RouterState , routerStore : RouterStore ) => Promise < RouterState | void > ; /**
 * A `Route` consists of a name, a URL matching pattern and optional
 * enter/exit hooks. The `RouterStore` is initialized with an array
 * of routes which it uses to transition between states.
 *
 * Note: Don't destructure routes to allow implementing them as classes.
 * See https://github.com/nareshbhatia/mobx-state-router/issues/74
 */ export interface Route { /** route name, e.g. 'department' */ name : string ; /** route matching pattern, e.g. '/departments/:id' */ pattern : string ; /**
     * Alternate route matching patterns. These support legacy routes
     * and go one way only, from browser location to router state.
     */ altPatterns ? : Array < string > ; beforeExit ? : TransitionHook ; beforeEnter ? : TransitionHook ; onExit ? : TransitionHook ; onEnter ? : TransitionHook ; } const InitialRouteName = '__initial__' ; const InitialRoute = { name : InitialRouteName , pattern : '' } ; const InitialRouterState = createRouterState ( InitialRouteName ) ; /**
 * Holds the router state. It allows transitioning between states using
 * `goTo` methods.
 */ export class RouterStore { routes : Route [ ] ; notFoundState : RouterState ; routerState : RouterState ; options : { [ key ] : any ; } ; param routes param notFoundState param options constructor ( routes , notFoundState , options = { } ) { makeObservable ( this , { routerState : observable . ref , setRouterState : action } ) ; this . routes = routes ; this . routes . push ( InitialRoute ) ; const defaultOptions = { initialState : InitialRouterState } ; this . options = Object . assign ( defaultOptions , options ) ; this . notFoundState = notFoundState ; this . routerState = this . options . initialState ; } setRouterState ( routerState ) { debugSetState ( '%o' , routerState ) ; this . routerState = routerState ; } param routeName param options goTo ( routeName , options = { } ) { const toState = createRouterState ( routeName , options ) ; const fromState = this . routerState ; return this . transition ( fromState , toState ) ; } goToState ( toState ) { const fromState = this . routerState ; return this . transition ( fromState , toState ) ; } goToNotFound ( ) { this . setRouterState ( this . notFoundState ) ; return Promise . resolve ( this . notFoundState ) ; } getRoute ( routeName ) { return this . routes . find ( ( route ) => route . name === routeName ) ; } getCurrentRoute ( ) { return this . getRoute ( this . routerState . routeName ) ; } getNotFoundRoute ( ) { const routeName = this . notFoundState . routeName ; const route = this . getRoute ( routeName ) ; if ( ! route ) { throw new Error ( `Route ${ routeName } does not exist` ) ; } return route ; } /**
     * Requests a transition from fromState to toState. Note that the
     * actual transition may be different from the requested one
     * based on enter and exit hooks.
     */ private transition ( fromState , toState ) { const transitionState = new TransitionState ( this , fromState ) ; return transitionState . resolve ( toState ) ; } }