11import { Promise } from 'rsvp' ;
22import { Dict } from './core' ;
3- import InternalRouteInfo , { Continuation , Route } from './route-info' ;
3+ import InternalRouteInfo , { Route , ResolvedRouteInfo } from './route-info' ;
44import Transition from './transition' ;
55import { forEach , promiseLabel } from './utils' ;
66
77interface IParams {
88 [ key : string ] : unknown ;
99}
1010
11+ function handleError < T extends Route > (
12+ currentState : TransitionState < T > ,
13+ transition : Transition < T > ,
14+ error : Error
15+ ) : never {
16+ // This is the only possible
17+ // reject value of TransitionState#resolve
18+ let routeInfos = currentState . routeInfos ;
19+ let errorHandlerIndex =
20+ transition . resolveIndex >= routeInfos . length ? routeInfos . length - 1 : transition . resolveIndex ;
21+
22+ let wasAborted = transition . isAborted ;
23+
24+ throw new TransitionError (
25+ error ,
26+ currentState . routeInfos [ errorHandlerIndex ] . route ! ,
27+ wasAborted ,
28+ currentState
29+ ) ;
30+ }
31+
32+ function resolveOneRouteInfo < T extends Route > (
33+ currentState : TransitionState < T > ,
34+ transition : Transition < T >
35+ ) : void | Promise < void > {
36+ if ( transition . resolveIndex === currentState . routeInfos . length ) {
37+ // This is is the only possible
38+ // fulfill value of TransitionState#resolve
39+ return ;
40+ }
41+
42+ let routeInfo = currentState . routeInfos [ transition . resolveIndex ] ;
43+
44+ return routeInfo
45+ . resolve ( transition )
46+ . then ( proceed . bind ( null , currentState , transition ) , null , currentState . promiseLabel ( 'Proceed' ) ) ;
47+ }
48+
49+ function proceed < T extends Route > (
50+ currentState : TransitionState < T > ,
51+ transition : Transition < T > ,
52+ resolvedRouteInfo : ResolvedRouteInfo < T >
53+ ) : void | Promise < void > {
54+ let wasAlreadyResolved = currentState . routeInfos [ transition . resolveIndex ] . isResolved ;
55+
56+ // Swap the previously unresolved routeInfo with
57+ // the resolved routeInfo
58+ currentState . routeInfos [ transition . resolveIndex ++ ] = resolvedRouteInfo ;
59+
60+ if ( ! wasAlreadyResolved ) {
61+ // Call the redirect hook. The reason we call it here
62+ // vs. afterModel is so that redirects into child
63+ // routes don't re-run the model hooks for this
64+ // already-resolved route.
65+ let { route } = resolvedRouteInfo ;
66+ if ( route !== undefined ) {
67+ if ( route . redirect ) {
68+ route . redirect ( resolvedRouteInfo . context as Dict < unknown > , transition ) ;
69+ }
70+ }
71+ }
72+
73+ // Proceed after ensuring that the redirect hook
74+ // didn't abort this transition by transitioning elsewhere.
75+ if ( transition . isAborted ) {
76+ throw new Error ( 'Transition aborted' ) ;
77+ }
78+
79+ return resolveOneRouteInfo ( currentState , transition ) ;
80+ }
81+
1182export default class TransitionState < T extends Route > {
1283 routeInfos : InternalRouteInfo < T > [ ] = [ ] ;
1384 queryParams : Dict < unknown > = { } ;
@@ -25,7 +96,7 @@ export default class TransitionState<T extends Route> {
2596 return promiseLabel ( "'" + targetName + "': " + label ) ;
2697 }
2798
28- resolve ( shouldContinue : Continuation , transition : Transition < T > ) : Promise < TransitionState < T > > {
99+ resolve ( transition : Transition < T > ) : Promise < TransitionState < T > > {
29100 // First, calculate params for this state. This is useful
30101 // information to provide to the various route hooks.
31102 let params = this . params ;
@@ -36,87 +107,15 @@ export default class TransitionState<T extends Route> {
36107
37108 transition . resolveIndex = 0 ;
38109
39- let currentState = this ;
40- let wasAborted = false ;
41-
42110 // The prelude RSVP.resolve() async moves us into the promise land.
43111 return Promise . resolve ( null , this . promiseLabel ( 'Start transition' ) )
44- . then ( resolveOneRouteInfo , null , this . promiseLabel ( 'Resolve route' ) )
45- . catch ( handleError , this . promiseLabel ( 'Handle error' ) ) ;
46-
47- function innerShouldContinue ( ) {
48- return Promise . resolve (
49- shouldContinue ( ) ,
50- currentState . promiseLabel ( 'Check if should continue' )
51- ) . catch ( function ( reason ) {
52- // We distinguish between errors that occurred
53- // during resolution (e.g. before"Model/model/afterModel),
54- // and aborts due to a rejecting promise from shouldContinue().
55- wasAborted = true ;
56- return Promise . reject ( reason ) ;
57- } , currentState . promiseLabel ( 'Handle abort' ) ) ;
58- }
59-
60- function handleError ( error : Error ) {
61- // This is the only possible
62- // reject value of TransitionState#resolve
63- let routeInfos = currentState . routeInfos ;
64- let errorHandlerIndex =
65- transition . resolveIndex >= routeInfos . length
66- ? routeInfos . length - 1
67- : transition . resolveIndex ;
68- return Promise . reject (
69- new TransitionError (
70- error ,
71- currentState . routeInfos [ errorHandlerIndex ] . route ! ,
72- wasAborted ,
73- currentState
74- )
75- ) ;
76- }
77-
78- function proceed ( resolvedRouteInfo : InternalRouteInfo < T > ) : Promise < InternalRouteInfo < T > > {
79- let wasAlreadyResolved = currentState . routeInfos [ transition . resolveIndex ] . isResolved ;
80-
81- // Swap the previously unresolved routeInfo with
82- // the resolved routeInfo
83- currentState . routeInfos [ transition . resolveIndex ++ ] = resolvedRouteInfo ;
84-
85- if ( ! wasAlreadyResolved ) {
86- // Call the redirect hook. The reason we call it here
87- // vs. afterModel is so that redirects into child
88- // routes don't re-run the model hooks for this
89- // already-resolved route.
90- let { route } = resolvedRouteInfo ;
91- if ( route !== undefined ) {
92- if ( route . redirect ) {
93- route . redirect ( resolvedRouteInfo . context as Dict < unknown > , transition ) ;
94- }
95- }
96- }
97-
98- // Proceed after ensuring that the redirect hook
99- // didn't abort this transition by transitioning elsewhere.
100- return innerShouldContinue ( ) . then (
101- resolveOneRouteInfo ,
112+ . then (
113+ resolveOneRouteInfo . bind ( null , this , transition ) ,
102114 null ,
103- currentState . promiseLabel ( 'Resolve route' )
104- ) ;
105- }
106-
107- function resolveOneRouteInfo ( ) : TransitionState < T > | Promise < any > {
108- if ( transition . resolveIndex === currentState . routeInfos . length ) {
109- // This is is the only possible
110- // fulfill value of TransitionState#resolve
111- return currentState ;
112- }
113-
114- let routeInfo = currentState . routeInfos [ transition . resolveIndex ] ;
115-
116- return routeInfo
117- . resolve ( innerShouldContinue , transition )
118- . then ( proceed , null , currentState . promiseLabel ( 'Proceed' ) ) ;
119- }
115+ this . promiseLabel ( 'Resolve route' )
116+ )
117+ . catch ( handleError . bind ( null , this , transition ) , this . promiseLabel ( 'Handle error' ) )
118+ . then ( ( ) => this ) ;
120119 }
121120}
122121
0 commit comments