-
Notifications
You must be signed in to change notification settings - Fork 20
/
transition.js
159 lines (142 loc) · 4.24 KB
/
transition.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
var _ = require('./dash')
var invariant = require('./invariant')
var Path = require('./path')
module.exports = function transition (options, Promise) {
options = options || {}
let router = options.router
let log = router.log
let logError = router.logError
let path = options.path
let match = options.match
let routes = match.routes
let params = match.params
let query = match.query
let id = options.id
let startTime = Date.now()
log('---')
log('Transition #' + id, 'to', path)
log('Transition #' + id, 'routes:', routes.map(r => r.name))
log('Transition #' + id, 'params:', params)
log('Transition #' + id, 'query:', query)
// create the transition promise
var resolve, reject
var promise = new Promise(function (res, rej) {
resolve = res
reject = rej
})
// 1. make transition errors loud
// 2. by adding this handler we make sure
// we don't trigger the default 'Potentially
// unhandled rejection' for cancellations
promise.then(function () {
log('Transition #' + id, 'completed in', (Date.now() - startTime) + 'ms')
}).catch(function (err) {
if (err.type !== 'TransitionRedirected' && err.type !== 'TransitionCancelled') {
log('Transition #' + id, 'FAILED')
logError(err.stack)
}
})
var cancelled = false
var transition = {
id: id,
prev: {
routes: _.clone(router.state.routes) || [],
path: router.state.path || '',
pathname: router.state.pathname || '',
params: _.clone(router.state.params) || {},
query: _.clone(router.state.query) || {}
},
routes: _.clone(routes),
path: path,
pathname: Path.withoutQuery(path),
params: _.clone(params),
query: _.clone(query),
redirectTo: function () {
return router.transitionTo.apply(router, arguments)
},
retry: function () {
return router.transitionTo(path)
},
cancel: function (err) {
if (router.state.activeTransition !== transition) {
return
}
if (transition.isCancelled) {
return
}
router.state.activeTransition = null
transition.isCancelled = true
cancelled = true
if (!err) {
err = new Error('TransitionCancelled')
err.type = 'TransitionCancelled'
}
if (err.type === 'TransitionCancelled') {
log('Transition #' + id, 'cancelled')
}
if (err.type === 'TransitionRedirected') {
log('Transition #' + id, 'redirected')
}
reject(err)
},
followRedirects: function () {
return promise['catch'](function (reason) {
if (router.state.activeTransition) {
return router.state.activeTransition.followRedirects()
}
return Promise.reject(reason)
})
},
then: promise.then.bind(promise),
catch: promise.catch.bind(promise)
}
// here we handle calls to all of the middlewares
function callNext (i, prevResult) {
var middlewareName
// if transition has been cancelled - nothing left to do
if (cancelled) {
return
}
// done
if (i < router.middleware.length) {
middlewareName = router.middleware[i].name || 'anonymous'
log('Transition #' + id, 'resolving middleware:', middlewareName)
let middlewarePromise
try {
middlewarePromise = router.middleware[i](transition, prevResult)
invariant(transition !== middlewarePromise, 'Middleware %s returned a transition which resulted in a deadlock', middlewareName)
} catch (err) {
router.state.activeTransition = null
return reject(err)
}
Promise.resolve(middlewarePromise)
.then(function (result) {
callNext(i + 1, result)
})
.catch(function (err) {
log('Transition #' + id, 'resolving middleware:', middlewareName, 'FAILED')
router.state.activeTransition = null
reject(err)
})
} else {
router.state = {
activeTransition: null,
routes: routes,
path: path,
pathname: Path.withoutQuery(path),
params: params,
query: query
}
resolve()
}
}
if (!options.noop) {
Promise.resolve().then(() => callNext(0))
} else {
resolve()
}
if (options.noop) {
transition.noop = true
}
return transition
}