kdu-router 3.5.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +11 -11
  3. package/dist/composables.js +253 -0
  4. package/dist/composables.mjs +244 -0
  5. package/dist/kdu-router.common.js +2668 -2665
  6. package/dist/kdu-router.esm.browser.js +2676 -2670
  7. package/dist/kdu-router.esm.browser.min.js +5 -5
  8. package/dist/kdu-router.esm.js +2680 -2674
  9. package/dist/kdu-router.js +2675 -2672
  10. package/dist/kdu-router.min.js +5 -5
  11. package/ketur/attributes.json +38 -38
  12. package/ketur/tags.json +20 -20
  13. package/package.json +115 -90
  14. package/src/components/link.js +224 -224
  15. package/src/components/view.js +155 -155
  16. package/src/composables/globals.js +34 -0
  17. package/src/composables/guards.js +68 -0
  18. package/src/composables/index.js +3 -0
  19. package/src/composables/useLink.js +113 -0
  20. package/src/composables/utils.js +11 -0
  21. package/src/create-matcher.js +226 -226
  22. package/src/create-route-map.js +220 -220
  23. package/src/entries/cjs.js +3 -0
  24. package/src/entries/esm.js +12 -0
  25. package/src/history/abstract.js +72 -72
  26. package/src/history/base.js +379 -379
  27. package/src/history/hash.js +152 -152
  28. package/src/history/html5.js +99 -99
  29. package/src/index.js +3 -293
  30. package/src/install.js +52 -52
  31. package/src/router.js +293 -0
  32. package/src/util/async.js +18 -18
  33. package/src/util/dom.js +3 -3
  34. package/src/util/errors.js +86 -86
  35. package/src/util/location.js +69 -69
  36. package/src/util/misc.js +6 -6
  37. package/src/util/params.js +37 -37
  38. package/src/util/path.js +74 -74
  39. package/src/util/push-state.js +46 -46
  40. package/src/util/query.js +113 -113
  41. package/src/util/resolve-components.js +109 -109
  42. package/src/util/route.js +151 -151
  43. package/src/util/scroll.js +175 -175
  44. package/src/util/state-key.js +22 -22
  45. package/src/util/warn.js +14 -14
  46. package/types/composables.d.ts +53 -0
  47. package/types/index.d.ts +25 -21
  48. package/types/kdu.d.ts +22 -22
  49. package/types/router.d.ts +564 -211
@@ -1,379 +1,379 @@
1
- /* @flow */
2
-
3
- import { _Kdu } from '../install'
4
- import type Router from '../index'
5
- import { inBrowser } from '../util/dom'
6
- import { runQueue } from '../util/async'
7
- import { warn } from '../util/warn'
8
- import { START, isSameRoute, handleRouteEntered } from '../util/route'
9
- import {
10
- flatten,
11
- flatMapComponents,
12
- resolveAsyncComponents
13
- } from '../util/resolve-components'
14
- import {
15
- createNavigationDuplicatedError,
16
- createNavigationCancelledError,
17
- createNavigationRedirectedError,
18
- createNavigationAbortedError,
19
- isError,
20
- isNavigationFailure,
21
- NavigationFailureType
22
- } from '../util/errors'
23
- import { handleScroll } from '../util/scroll'
24
-
25
- export class History {
26
- router: Router
27
- base: string
28
- current: Route
29
- pending: ?Route
30
- cb: (r: Route) => void
31
- ready: boolean
32
- readyCbs: Array<Function>
33
- readyErrorCbs: Array<Function>
34
- errorCbs: Array<Function>
35
- listeners: Array<Function>
36
- cleanupListeners: Function
37
-
38
- // implemented by sub-classes
39
- +go: (n: number) => void
40
- +push: (loc: RawLocation, onComplete?: Function, onAbort?: Function) => void
41
- +replace: (
42
- loc: RawLocation,
43
- onComplete?: Function,
44
- onAbort?: Function
45
- ) => void
46
- +ensureURL: (push?: boolean) => void
47
- +getCurrentLocation: () => string
48
- +setupListeners: Function
49
-
50
- constructor (router: Router, base: ?string) {
51
- this.router = router
52
- this.base = normalizeBase(base)
53
- // start with a route object that stands for "nowhere"
54
- this.current = START
55
- this.pending = null
56
- this.ready = false
57
- this.readyCbs = []
58
- this.readyErrorCbs = []
59
- this.errorCbs = []
60
- this.listeners = []
61
- }
62
-
63
- listen (cb: Function) {
64
- this.cb = cb
65
- }
66
-
67
- onReady (cb: Function, errorCb: ?Function) {
68
- if (this.ready) {
69
- cb()
70
- } else {
71
- this.readyCbs.push(cb)
72
- if (errorCb) {
73
- this.readyErrorCbs.push(errorCb)
74
- }
75
- }
76
- }
77
-
78
- onError (errorCb: Function) {
79
- this.errorCbs.push(errorCb)
80
- }
81
-
82
- transitionTo (
83
- location: RawLocation,
84
- onComplete?: Function,
85
- onAbort?: Function
86
- ) {
87
- let route
88
- // catch redirect option
89
- try {
90
- route = this.router.match(location, this.current)
91
- } catch (e) {
92
- this.errorCbs.forEach(cb => {
93
- cb(e)
94
- })
95
- // Exception should still be thrown
96
- throw e
97
- }
98
- const prev = this.current
99
- this.confirmTransition(
100
- route,
101
- () => {
102
- this.updateRoute(route)
103
- onComplete && onComplete(route)
104
- this.ensureURL()
105
- this.router.afterHooks.forEach(hook => {
106
- hook && hook(route, prev)
107
- })
108
-
109
- // fire ready cbs once
110
- if (!this.ready) {
111
- this.ready = true
112
- this.readyCbs.forEach(cb => {
113
- cb(route)
114
- })
115
- }
116
- },
117
- err => {
118
- if (onAbort) {
119
- onAbort(err)
120
- }
121
- if (err && !this.ready) {
122
- // Initial redirection should not mark the history as ready yet
123
- // because it's triggered by the redirection instead
124
- if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {
125
- this.ready = true
126
- this.readyErrorCbs.forEach(cb => {
127
- cb(err)
128
- })
129
- }
130
- }
131
- }
132
- )
133
- }
134
-
135
- confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
136
- const current = this.current
137
- this.pending = route
138
- const abort = err => {
139
- // changed after adding errors
140
- // before that change, redirect and aborted navigation would produce an err == null
141
- if (!isNavigationFailure(err) && isError(err)) {
142
- if (this.errorCbs.length) {
143
- this.errorCbs.forEach(cb => {
144
- cb(err)
145
- })
146
- } else {
147
- if (process.env.NODE_ENV !== 'production') {
148
- warn(false, 'uncaught error during route navigation:')
149
- }
150
- console.error(err)
151
- }
152
- }
153
- onAbort && onAbort(err)
154
- }
155
- const lastRouteIndex = route.matched.length - 1
156
- const lastCurrentIndex = current.matched.length - 1
157
- if (
158
- isSameRoute(route, current) &&
159
- // in the case the route map has been dynamically appended to
160
- lastRouteIndex === lastCurrentIndex &&
161
- route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]
162
- ) {
163
- this.ensureURL()
164
- if (route.hash) {
165
- handleScroll(this.router, current, route, false)
166
- }
167
- return abort(createNavigationDuplicatedError(current, route))
168
- }
169
-
170
- const { updated, deactivated, activated } = resolveQueue(
171
- this.current.matched,
172
- route.matched
173
- )
174
-
175
- const queue: Array<?NavigationGuard> = [].concat(
176
- // in-component leave guards
177
- extractLeaveGuards(deactivated),
178
- // global before hooks
179
- this.router.beforeHooks,
180
- // in-component update hooks
181
- extractUpdateHooks(updated),
182
- // in-config enter guards
183
- activated.map(m => m.beforeEnter),
184
- // async components
185
- resolveAsyncComponents(activated)
186
- )
187
-
188
- const iterator = (hook: NavigationGuard, next) => {
189
- if (this.pending !== route) {
190
- return abort(createNavigationCancelledError(current, route))
191
- }
192
- try {
193
- hook(route, current, (to: any) => {
194
- if (to === false) {
195
- // next(false) -> abort navigation, ensure current URL
196
- this.ensureURL(true)
197
- abort(createNavigationAbortedError(current, route))
198
- } else if (isError(to)) {
199
- this.ensureURL(true)
200
- abort(to)
201
- } else if (
202
- typeof to === 'string' ||
203
- (typeof to === 'object' &&
204
- (typeof to.path === 'string' || typeof to.name === 'string'))
205
- ) {
206
- // next('/') or next({ path: '/' }) -> redirect
207
- abort(createNavigationRedirectedError(current, route))
208
- if (typeof to === 'object' && to.replace) {
209
- this.replace(to)
210
- } else {
211
- this.push(to)
212
- }
213
- } else {
214
- // confirm transition and pass on the value
215
- next(to)
216
- }
217
- })
218
- } catch (e) {
219
- abort(e)
220
- }
221
- }
222
-
223
- runQueue(queue, iterator, () => {
224
- // wait until async components are resolved before
225
- // extracting in-component enter guards
226
- const enterGuards = extractEnterGuards(activated)
227
- const queue = enterGuards.concat(this.router.resolveHooks)
228
- runQueue(queue, iterator, () => {
229
- if (this.pending !== route) {
230
- return abort(createNavigationCancelledError(current, route))
231
- }
232
- this.pending = null
233
- onComplete(route)
234
- if (this.router.app) {
235
- this.router.app.$nextTick(() => {
236
- handleRouteEntered(route)
237
- })
238
- }
239
- })
240
- })
241
- }
242
-
243
- updateRoute (route: Route) {
244
- this.current = route
245
- this.cb && this.cb(route)
246
- }
247
-
248
- setupListeners () {
249
- // Default implementation is empty
250
- }
251
-
252
- teardown () {
253
- // clean up event listeners
254
- this.listeners.forEach(cleanupListener => {
255
- cleanupListener()
256
- })
257
- this.listeners = []
258
-
259
- // reset current history route
260
- this.current = START
261
- this.pending = null
262
- }
263
- }
264
-
265
- function normalizeBase (base: ?string): string {
266
- if (!base) {
267
- if (inBrowser) {
268
- // respect <base> tag
269
- const baseEl = document.querySelector('base')
270
- base = (baseEl && baseEl.getAttribute('href')) || '/'
271
- // strip full URL origin
272
- base = base.replace(/^https?:\/\/[^\/]+/, '')
273
- } else {
274
- base = '/'
275
- }
276
- }
277
- // make sure there's the starting slash
278
- if (base.charAt(0) !== '/') {
279
- base = '/' + base
280
- }
281
- // remove trailing slash
282
- return base.replace(/\/$/, '')
283
- }
284
-
285
- function resolveQueue (
286
- current: Array<RouteRecord>,
287
- next: Array<RouteRecord>
288
- ): {
289
- updated: Array<RouteRecord>,
290
- activated: Array<RouteRecord>,
291
- deactivated: Array<RouteRecord>
292
- } {
293
- let i
294
- const max = Math.max(current.length, next.length)
295
- for (i = 0; i < max; i++) {
296
- if (current[i] !== next[i]) {
297
- break
298
- }
299
- }
300
- return {
301
- updated: next.slice(0, i),
302
- activated: next.slice(i),
303
- deactivated: current.slice(i)
304
- }
305
- }
306
-
307
- function extractGuards (
308
- records: Array<RouteRecord>,
309
- name: string,
310
- bind: Function,
311
- reverse?: boolean
312
- ): Array<?Function> {
313
- const guards = flatMapComponents(records, (def, instance, match, key) => {
314
- const guard = extractGuard(def, name)
315
- if (guard) {
316
- return Array.isArray(guard)
317
- ? guard.map(guard => bind(guard, instance, match, key))
318
- : bind(guard, instance, match, key)
319
- }
320
- })
321
- return flatten(reverse ? guards.reverse() : guards)
322
- }
323
-
324
- function extractGuard (
325
- def: Object | Function,
326
- key: string
327
- ): NavigationGuard | Array<NavigationGuard> {
328
- if (typeof def !== 'function') {
329
- // extend now so that global mixins are applied.
330
- def = _Kdu.extend(def)
331
- }
332
- return def.options[key]
333
- }
334
-
335
- function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
336
- return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
337
- }
338
-
339
- function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
340
- return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
341
- }
342
-
343
- function bindGuard (guard: NavigationGuard, instance: ?_Kdu): ?NavigationGuard {
344
- if (instance) {
345
- return function boundRouteGuard () {
346
- return guard.apply(instance, arguments)
347
- }
348
- }
349
- }
350
-
351
- function extractEnterGuards (
352
- activated: Array<RouteRecord>
353
- ): Array<?Function> {
354
- return extractGuards(
355
- activated,
356
- 'beforeRouteEnter',
357
- (guard, _, match, key) => {
358
- return bindEnterGuard(guard, match, key)
359
- }
360
- )
361
- }
362
-
363
- function bindEnterGuard (
364
- guard: NavigationGuard,
365
- match: RouteRecord,
366
- key: string
367
- ): NavigationGuard {
368
- return function routeEnterGuard (to, from, next) {
369
- return guard(to, from, cb => {
370
- if (typeof cb === 'function') {
371
- if (!match.enteredCbs[key]) {
372
- match.enteredCbs[key] = []
373
- }
374
- match.enteredCbs[key].push(cb)
375
- }
376
- next(cb)
377
- })
378
- }
379
- }
1
+ /* @flow */
2
+
3
+ import { _Kdu } from '../install'
4
+ import type Router from '../index'
5
+ import { inBrowser } from '../util/dom'
6
+ import { runQueue } from '../util/async'
7
+ import { warn } from '../util/warn'
8
+ import { START, isSameRoute, handleRouteEntered } from '../util/route'
9
+ import {
10
+ flatten,
11
+ flatMapComponents,
12
+ resolveAsyncComponents
13
+ } from '../util/resolve-components'
14
+ import {
15
+ createNavigationDuplicatedError,
16
+ createNavigationCancelledError,
17
+ createNavigationRedirectedError,
18
+ createNavigationAbortedError,
19
+ isError,
20
+ isNavigationFailure,
21
+ NavigationFailureType
22
+ } from '../util/errors'
23
+ import { handleScroll } from '../util/scroll'
24
+
25
+ export class History {
26
+ router: Router
27
+ base: string
28
+ current: Route
29
+ pending: ?Route
30
+ cb: (r: Route) => void
31
+ ready: boolean
32
+ readyCbs: Array<Function>
33
+ readyErrorCbs: Array<Function>
34
+ errorCbs: Array<Function>
35
+ listeners: Array<Function>
36
+ cleanupListeners: Function
37
+
38
+ // implemented by sub-classes
39
+ +go: (n: number) => void
40
+ +push: (loc: RawLocation, onComplete?: Function, onAbort?: Function) => void
41
+ +replace: (
42
+ loc: RawLocation,
43
+ onComplete?: Function,
44
+ onAbort?: Function
45
+ ) => void
46
+ +ensureURL: (push?: boolean) => void
47
+ +getCurrentLocation: () => string
48
+ +setupListeners: Function
49
+
50
+ constructor (router: Router, base: ?string) {
51
+ this.router = router
52
+ this.base = normalizeBase(base)
53
+ // start with a route object that stands for "nowhere"
54
+ this.current = START
55
+ this.pending = null
56
+ this.ready = false
57
+ this.readyCbs = []
58
+ this.readyErrorCbs = []
59
+ this.errorCbs = []
60
+ this.listeners = []
61
+ }
62
+
63
+ listen (cb: Function) {
64
+ this.cb = cb
65
+ }
66
+
67
+ onReady (cb: Function, errorCb: ?Function) {
68
+ if (this.ready) {
69
+ cb()
70
+ } else {
71
+ this.readyCbs.push(cb)
72
+ if (errorCb) {
73
+ this.readyErrorCbs.push(errorCb)
74
+ }
75
+ }
76
+ }
77
+
78
+ onError (errorCb: Function) {
79
+ this.errorCbs.push(errorCb)
80
+ }
81
+
82
+ transitionTo (
83
+ location: RawLocation,
84
+ onComplete?: Function,
85
+ onAbort?: Function
86
+ ) {
87
+ let route
88
+ // catch redirect option
89
+ try {
90
+ route = this.router.match(location, this.current)
91
+ } catch (e) {
92
+ this.errorCbs.forEach(cb => {
93
+ cb(e)
94
+ })
95
+ // Exception should still be thrown
96
+ throw e
97
+ }
98
+ const prev = this.current
99
+ this.confirmTransition(
100
+ route,
101
+ () => {
102
+ this.updateRoute(route)
103
+ onComplete && onComplete(route)
104
+ this.ensureURL()
105
+ this.router.afterHooks.forEach(hook => {
106
+ hook && hook(route, prev)
107
+ })
108
+
109
+ // fire ready cbs once
110
+ if (!this.ready) {
111
+ this.ready = true
112
+ this.readyCbs.forEach(cb => {
113
+ cb(route)
114
+ })
115
+ }
116
+ },
117
+ err => {
118
+ if (onAbort) {
119
+ onAbort(err)
120
+ }
121
+ if (err && !this.ready) {
122
+ // Initial redirection should not mark the history as ready yet
123
+ // because it's triggered by the redirection instead
124
+ if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {
125
+ this.ready = true
126
+ this.readyErrorCbs.forEach(cb => {
127
+ cb(err)
128
+ })
129
+ }
130
+ }
131
+ }
132
+ )
133
+ }
134
+
135
+ confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
136
+ const current = this.current
137
+ this.pending = route
138
+ const abort = err => {
139
+ // changed after adding errors
140
+ // before that change, redirect and aborted navigation would produce an err == null
141
+ if (!isNavigationFailure(err) && isError(err)) {
142
+ if (this.errorCbs.length) {
143
+ this.errorCbs.forEach(cb => {
144
+ cb(err)
145
+ })
146
+ } else {
147
+ if (process.env.NODE_ENV !== 'production') {
148
+ warn(false, 'uncaught error during route navigation:')
149
+ }
150
+ console.error(err)
151
+ }
152
+ }
153
+ onAbort && onAbort(err)
154
+ }
155
+ const lastRouteIndex = route.matched.length - 1
156
+ const lastCurrentIndex = current.matched.length - 1
157
+ if (
158
+ isSameRoute(route, current) &&
159
+ // in the case the route map has been dynamically appended to
160
+ lastRouteIndex === lastCurrentIndex &&
161
+ route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]
162
+ ) {
163
+ this.ensureURL()
164
+ if (route.hash) {
165
+ handleScroll(this.router, current, route, false)
166
+ }
167
+ return abort(createNavigationDuplicatedError(current, route))
168
+ }
169
+
170
+ const { updated, deactivated, activated } = resolveQueue(
171
+ this.current.matched,
172
+ route.matched
173
+ )
174
+
175
+ const queue: Array<?NavigationGuard> = [].concat(
176
+ // in-component leave guards
177
+ extractLeaveGuards(deactivated),
178
+ // global before hooks
179
+ this.router.beforeHooks,
180
+ // in-component update hooks
181
+ extractUpdateHooks(updated),
182
+ // in-config enter guards
183
+ activated.map(m => m.beforeEnter),
184
+ // async components
185
+ resolveAsyncComponents(activated)
186
+ )
187
+
188
+ const iterator = (hook: NavigationGuard, next) => {
189
+ if (this.pending !== route) {
190
+ return abort(createNavigationCancelledError(current, route))
191
+ }
192
+ try {
193
+ hook(route, current, (to: any) => {
194
+ if (to === false) {
195
+ // next(false) -> abort navigation, ensure current URL
196
+ this.ensureURL(true)
197
+ abort(createNavigationAbortedError(current, route))
198
+ } else if (isError(to)) {
199
+ this.ensureURL(true)
200
+ abort(to)
201
+ } else if (
202
+ typeof to === 'string' ||
203
+ (typeof to === 'object' &&
204
+ (typeof to.path === 'string' || typeof to.name === 'string'))
205
+ ) {
206
+ // next('/') or next({ path: '/' }) -> redirect
207
+ abort(createNavigationRedirectedError(current, route))
208
+ if (typeof to === 'object' && to.replace) {
209
+ this.replace(to)
210
+ } else {
211
+ this.push(to)
212
+ }
213
+ } else {
214
+ // confirm transition and pass on the value
215
+ next(to)
216
+ }
217
+ })
218
+ } catch (e) {
219
+ abort(e)
220
+ }
221
+ }
222
+
223
+ runQueue(queue, iterator, () => {
224
+ // wait until async components are resolved before
225
+ // extracting in-component enter guards
226
+ const enterGuards = extractEnterGuards(activated)
227
+ const queue = enterGuards.concat(this.router.resolveHooks)
228
+ runQueue(queue, iterator, () => {
229
+ if (this.pending !== route) {
230
+ return abort(createNavigationCancelledError(current, route))
231
+ }
232
+ this.pending = null
233
+ onComplete(route)
234
+ if (this.router.app) {
235
+ this.router.app.$nextTick(() => {
236
+ handleRouteEntered(route)
237
+ })
238
+ }
239
+ })
240
+ })
241
+ }
242
+
243
+ updateRoute (route: Route) {
244
+ this.current = route
245
+ this.cb && this.cb(route)
246
+ }
247
+
248
+ setupListeners () {
249
+ // Default implementation is empty
250
+ }
251
+
252
+ teardown () {
253
+ // clean up event listeners
254
+ this.listeners.forEach(cleanupListener => {
255
+ cleanupListener()
256
+ })
257
+ this.listeners = []
258
+
259
+ // reset current history route
260
+ this.current = START
261
+ this.pending = null
262
+ }
263
+ }
264
+
265
+ function normalizeBase (base: ?string): string {
266
+ if (!base) {
267
+ if (inBrowser) {
268
+ // respect <base> tag
269
+ const baseEl = document.querySelector('base')
270
+ base = (baseEl && baseEl.getAttribute('href')) || '/'
271
+ // strip full URL origin
272
+ base = base.replace(/^https?:\/\/[^\/]+/, '')
273
+ } else {
274
+ base = '/'
275
+ }
276
+ }
277
+ // make sure there's the starting slash
278
+ if (base.charAt(0) !== '/') {
279
+ base = '/' + base
280
+ }
281
+ // remove trailing slash
282
+ return base.replace(/\/$/, '')
283
+ }
284
+
285
+ function resolveQueue (
286
+ current: Array<RouteRecord>,
287
+ next: Array<RouteRecord>
288
+ ): {
289
+ updated: Array<RouteRecord>,
290
+ activated: Array<RouteRecord>,
291
+ deactivated: Array<RouteRecord>
292
+ } {
293
+ let i
294
+ const max = Math.max(current.length, next.length)
295
+ for (i = 0; i < max; i++) {
296
+ if (current[i] !== next[i]) {
297
+ break
298
+ }
299
+ }
300
+ return {
301
+ updated: next.slice(0, i),
302
+ activated: next.slice(i),
303
+ deactivated: current.slice(i)
304
+ }
305
+ }
306
+
307
+ function extractGuards (
308
+ records: Array<RouteRecord>,
309
+ name: string,
310
+ bind: Function,
311
+ reverse?: boolean
312
+ ): Array<?Function> {
313
+ const guards = flatMapComponents(records, (def, instance, match, key) => {
314
+ const guard = extractGuard(def, name)
315
+ if (guard) {
316
+ return Array.isArray(guard)
317
+ ? guard.map(guard => bind(guard, instance, match, key))
318
+ : bind(guard, instance, match, key)
319
+ }
320
+ })
321
+ return flatten(reverse ? guards.reverse() : guards)
322
+ }
323
+
324
+ function extractGuard (
325
+ def: Object | Function,
326
+ key: string
327
+ ): NavigationGuard | Array<NavigationGuard> {
328
+ if (typeof def !== 'function') {
329
+ // extend now so that global mixins are applied.
330
+ def = _Kdu.extend(def)
331
+ }
332
+ return def.options[key]
333
+ }
334
+
335
+ function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
336
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
337
+ }
338
+
339
+ function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
340
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
341
+ }
342
+
343
+ function bindGuard (guard: NavigationGuard, instance: ?_Kdu): ?NavigationGuard {
344
+ if (instance) {
345
+ return function boundRouteGuard () {
346
+ return guard.apply(instance, arguments)
347
+ }
348
+ }
349
+ }
350
+
351
+ function extractEnterGuards (
352
+ activated: Array<RouteRecord>
353
+ ): Array<?Function> {
354
+ return extractGuards(
355
+ activated,
356
+ 'beforeRouteEnter',
357
+ (guard, _, match, key) => {
358
+ return bindEnterGuard(guard, match, key)
359
+ }
360
+ )
361
+ }
362
+
363
+ function bindEnterGuard (
364
+ guard: NavigationGuard,
365
+ match: RouteRecord,
366
+ key: string
367
+ ): NavigationGuard {
368
+ return function routeEnterGuard (to, from, next) {
369
+ return guard(to, from, cb => {
370
+ if (typeof cb === 'function') {
371
+ if (!match.enteredCbs[key]) {
372
+ match.enteredCbs[key] = []
373
+ }
374
+ match.enteredCbs[key].push(cb)
375
+ }
376
+ next(cb)
377
+ })
378
+ }
379
+ }