kdu-router 3.4.0-beta.0 → 3.5.4

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.
@@ -5,7 +5,7 @@ import type Router from '../index'
5
5
  import { inBrowser } from '../util/dom'
6
6
  import { runQueue } from '../util/async'
7
7
  import { warn } from '../util/warn'
8
- import { START, isSameRoute } from '../util/route'
8
+ import { START, isSameRoute, handleRouteEntered } from '../util/route'
9
9
  import {
10
10
  flatten,
11
11
  flatMapComponents,
@@ -20,6 +20,7 @@ import {
20
20
  isNavigationFailure,
21
21
  NavigationFailureType
22
22
  } from '../util/errors'
23
+ import { handleScroll } from '../util/scroll'
23
24
 
24
25
  export class History {
25
26
  router: Router
@@ -84,6 +85,7 @@ export class History {
84
85
  onAbort?: Function
85
86
  ) {
86
87
  let route
88
+ // catch redirect option
87
89
  try {
88
90
  route = this.router.match(location, this.current)
89
91
  } catch (e) {
@@ -93,10 +95,10 @@ export class History {
93
95
  // Exception should still be thrown
94
96
  throw e
95
97
  }
98
+ const prev = this.current
96
99
  this.confirmTransition(
97
100
  route,
98
101
  () => {
99
- const prev = this.current
100
102
  this.updateRoute(route)
101
103
  onComplete && onComplete(route)
102
104
  this.ensureURL()
@@ -117,16 +119,13 @@ export class History {
117
119
  onAbort(err)
118
120
  }
119
121
  if (err && !this.ready) {
120
- this.ready = true
121
- // Initial redirection should still trigger the onReady onSuccess
122
- if (!isNavigationFailure(err, NavigationFailureType.redirected)) {
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
123
126
  this.readyErrorCbs.forEach(cb => {
124
127
  cb(err)
125
128
  })
126
- } else {
127
- this.readyCbs.forEach(cb => {
128
- cb(route)
129
- })
130
129
  }
131
130
  }
132
131
  }
@@ -135,16 +134,19 @@ export class History {
135
134
 
136
135
  confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
137
136
  const current = this.current
137
+ this.pending = route
138
138
  const abort = err => {
139
- // changed after adding errors before that change,
140
- // redirect and aborted navigation would produce an err == null
139
+ // changed after adding errors
140
+ // before that change, redirect and aborted navigation would produce an err == null
141
141
  if (!isNavigationFailure(err) && isError(err)) {
142
142
  if (this.errorCbs.length) {
143
143
  this.errorCbs.forEach(cb => {
144
144
  cb(err)
145
145
  })
146
146
  } else {
147
- warn(false, 'uncaught error during route navigation:')
147
+ if (process.env.NODE_ENV !== 'production') {
148
+ warn(false, 'uncaught error during route navigation:')
149
+ }
148
150
  console.error(err)
149
151
  }
150
152
  }
@@ -159,6 +161,9 @@ export class History {
159
161
  route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]
160
162
  ) {
161
163
  this.ensureURL()
164
+ if (route.hash) {
165
+ handleScroll(this.router, current, route, false)
166
+ }
162
167
  return abort(createNavigationDuplicatedError(current, route))
163
168
  }
164
169
 
@@ -180,7 +185,6 @@ export class History {
180
185
  resolveAsyncComponents(activated)
181
186
  )
182
187
 
183
- this.pending = route
184
188
  const iterator = (hook: NavigationGuard, next) => {
185
189
  if (this.pending !== route) {
186
190
  return abort(createNavigationCancelledError(current, route))
@@ -217,11 +221,9 @@ export class History {
217
221
  }
218
222
 
219
223
  runQueue(queue, iterator, () => {
220
- const postEnterCbs = []
221
- const isValid = () => this.current === route
222
224
  // wait until async components are resolved before
223
225
  // extracting in-component enter guards
224
- const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
226
+ const enterGuards = extractEnterGuards(activated)
225
227
  const queue = enterGuards.concat(this.router.resolveHooks)
226
228
  runQueue(queue, iterator, () => {
227
229
  if (this.pending !== route) {
@@ -231,9 +233,7 @@ export class History {
231
233
  onComplete(route)
232
234
  if (this.router.app) {
233
235
  this.router.app.$nextTick(() => {
234
- postEnterCbs.forEach(cb => {
235
- cb()
236
- })
236
+ handleRouteEntered(route)
237
237
  })
238
238
  }
239
239
  })
@@ -249,11 +249,16 @@ export class History {
249
249
  // Default implementation is empty
250
250
  }
251
251
 
252
- teardownListeners () {
252
+ teardown () {
253
+ // clean up event listeners
253
254
  this.listeners.forEach(cleanupListener => {
254
255
  cleanupListener()
255
256
  })
256
257
  this.listeners = []
258
+
259
+ // reset current history route
260
+ this.current = START
261
+ this.pending = null
257
262
  }
258
263
  }
259
264
 
@@ -344,15 +349,13 @@ function bindGuard (guard: NavigationGuard, instance: ?_Kdu): ?NavigationGuard {
344
349
  }
345
350
 
346
351
  function extractEnterGuards (
347
- activated: Array<RouteRecord>,
348
- cbs: Array<Function>,
349
- isValid: () => boolean
352
+ activated: Array<RouteRecord>
350
353
  ): Array<?Function> {
351
354
  return extractGuards(
352
355
  activated,
353
356
  'beforeRouteEnter',
354
357
  (guard, _, match, key) => {
355
- return bindEnterGuard(guard, match, key, cbs, isValid)
358
+ return bindEnterGuard(guard, match, key)
356
359
  }
357
360
  )
358
361
  }
@@ -360,41 +363,17 @@ function extractEnterGuards (
360
363
  function bindEnterGuard (
361
364
  guard: NavigationGuard,
362
365
  match: RouteRecord,
363
- key: string,
364
- cbs: Array<Function>,
365
- isValid: () => boolean
366
+ key: string
366
367
  ): NavigationGuard {
367
368
  return function routeEnterGuard (to, from, next) {
368
369
  return guard(to, from, cb => {
369
370
  if (typeof cb === 'function') {
370
- cbs.push(() => {
371
- // #750
372
- // if a router-view is wrapped with an out-in transition,
373
- // the instance may not have been registered at this time.
374
- // we will need to poll for registration until current route
375
- // is no longer valid.
376
- poll(cb, match.instances, key, isValid)
377
- })
371
+ if (!match.enteredCbs[key]) {
372
+ match.enteredCbs[key] = []
373
+ }
374
+ match.enteredCbs[key].push(cb)
378
375
  }
379
376
  next(cb)
380
377
  })
381
378
  }
382
379
  }
383
-
384
- function poll (
385
- cb: any, // somehow flow cannot infer this is a function
386
- instances: Object,
387
- key: string,
388
- isValid: () => boolean
389
- ) {
390
- if (
391
- instances[key] &&
392
- !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
393
- ) {
394
- cb(instances[key])
395
- } else if (isValid()) {
396
- setTimeout(() => {
397
- poll(cb, instances, key, isValid)
398
- }, 16)
399
- }
400
- }
@@ -124,17 +124,6 @@ export function getHash (): string {
124
124
  if (index < 0) return ''
125
125
 
126
126
  href = href.slice(index + 1)
127
- // decode the hash but not the search or hash
128
- // as search(query) is already decoded
129
- const searchIndex = href.indexOf('?')
130
- if (searchIndex < 0) {
131
- const hashIndex = href.indexOf('#')
132
- if (hashIndex > -1) {
133
- href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex)
134
- } else href = decodeURI(href)
135
- } else {
136
- href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex)
137
- }
138
127
 
139
128
  return href
140
129
  }
@@ -86,8 +86,13 @@ export class HTML5History extends History {
86
86
  }
87
87
 
88
88
  export function getLocation (base: string): string {
89
- let path = decodeURI(window.location.pathname)
90
- if (base && path.toLowerCase().indexOf(base.toLowerCase()) === 0) {
89
+ let path = window.location.pathname
90
+ const pathLowerCase = path.toLowerCase()
91
+ const baseLowerCase = base.toLowerCase()
92
+ // base="/a" shouldn't turn path="/app" into "/a/pp"
93
+ // so we ensure the trailing slash in the base
94
+ if (base && ((pathLowerCase === baseLowerCase) ||
95
+ (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {
91
96
  path = path.slice(base.length)
92
97
  }
93
98
  return (path || '/') + window.location.search + window.location.hash
package/src/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { install } from './install'
4
4
  import { START } from './util/route'
5
- import { assert } from './util/warn'
5
+ import { assert, warn } from './util/warn'
6
6
  import { inBrowser } from './util/dom'
7
7
  import { cleanPath } from './util/path'
8
8
  import { createMatcher } from './create-matcher'
@@ -23,6 +23,7 @@ export default class KduRouter {
23
23
  static version: string
24
24
  static isNavigationFailure: Function
25
25
  static NavigationFailureType: any
26
+ static START_LOCATION: Route
26
27
 
27
28
  app: any
28
29
  apps: Array<any>
@@ -38,6 +39,9 @@ export default class KduRouter {
38
39
  afterHooks: Array<?AfterNavigationHook>
39
40
 
40
41
  constructor (options: RouterOptions = {}) {
42
+ if (process.env.NODE_ENV !== 'production') {
43
+ warn(this instanceof KduRouter, `Router must be called with the new operator.`)
44
+ }
41
45
  this.app = null
42
46
  this.apps = []
43
47
  this.options = options
@@ -101,10 +105,7 @@ export default class KduRouter {
101
105
  // we do not release the router so it can be reused
102
106
  if (this.app === app) this.app = this.apps[0] || null
103
107
 
104
- if (!this.app) {
105
- // clean up event listeners
106
- this.history.teardownListeners()
107
- }
108
+ if (!this.app) this.history.teardown()
108
109
  })
109
110
 
110
111
  // main app previously initialized
@@ -246,7 +247,21 @@ export default class KduRouter {
246
247
  }
247
248
  }
248
249
 
250
+ getRoutes () {
251
+ return this.matcher.getRoutes()
252
+ }
253
+
254
+ addRoute (parentOrRoute: string | RouteConfig, route?: RouteConfig) {
255
+ this.matcher.addRoute(parentOrRoute, route)
256
+ if (this.history.current !== START) {
257
+ this.history.transitionTo(this.history.getCurrentLocation())
258
+ }
259
+ }
260
+
249
261
  addRoutes (routes: Array<RouteConfig>) {
262
+ if (process.env.NODE_ENV !== 'production') {
263
+ warn(false, 'router.addRoutes() is deprecated and has been removed in Kdu Router 4. Use router.addRoute() instead.')
264
+ }
250
265
  this.matcher.addRoutes(routes)
251
266
  if (this.history.current !== START) {
252
267
  this.history.transitionTo(this.history.getCurrentLocation())
@@ -271,6 +286,7 @@ KduRouter.install = install
271
286
  KduRouter.version = '__VERSION__'
272
287
  KduRouter.isNavigationFailure = isNavigationFailure
273
288
  KduRouter.NavigationFailureType = NavigationFailureType
289
+ KduRouter.START_LOCATION = START
274
290
 
275
291
  if (inBrowser && window.Kdu) {
276
292
  window.Kdu.use(KduRouter)
@@ -1,3 +1,4 @@
1
+ // When changing thing, also edit router.d.ts
1
2
  export const NavigationFailureType = {
2
3
  redirected: 2,
3
4
  aborted: 4,
package/src/util/path.js CHANGED
@@ -70,5 +70,5 @@ export function parsePath (path: string): {
70
70
  }
71
71
 
72
72
  export function cleanPath (path: string): string {
73
- return path.replace(/\/\//g, '/')
73
+ return path.replace(/\/(?:\s*\/)+/g, '/')
74
74
  }
package/src/util/query.js CHANGED
@@ -9,11 +9,21 @@ const commaRE = /%2C/g
9
9
  // fixed encodeURIComponent which is more conformant to RFC3986:
10
10
  // - escapes [!'()*]
11
11
  // - preserve commas
12
- const encode = str => encodeURIComponent(str)
13
- .replace(encodeReserveRE, encodeReserveReplacer)
14
- .replace(commaRE, ',')
12
+ const encode = str =>
13
+ encodeURIComponent(str)
14
+ .replace(encodeReserveRE, encodeReserveReplacer)
15
+ .replace(commaRE, ',')
15
16
 
16
- const decode = decodeURIComponent
17
+ export function decode (str: string) {
18
+ try {
19
+ return decodeURIComponent(str)
20
+ } catch (err) {
21
+ if (process.env.NODE_ENV !== 'production') {
22
+ warn(false, `Error decoding "${str}". Leaving it intact.`)
23
+ }
24
+ }
25
+ return str
26
+ }
17
27
 
18
28
  export function resolveQuery (
19
29
  query: ?string,
@@ -30,11 +40,15 @@ export function resolveQuery (
30
40
  }
31
41
  for (const key in extraQuery) {
32
42
  const value = extraQuery[key]
33
- parsedQuery[key] = Array.isArray(value) ? value.map(v => '' + v) : '' + value
43
+ parsedQuery[key] = Array.isArray(value)
44
+ ? value.map(castQueryParamValue)
45
+ : castQueryParamValue(value)
34
46
  }
35
47
  return parsedQuery
36
48
  }
37
49
 
50
+ const castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value))
51
+
38
52
  function parseQuery (query: string): Dictionary<string> {
39
53
  const res = {}
40
54
 
@@ -47,9 +61,7 @@ function parseQuery (query: string): Dictionary<string> {
47
61
  query.split('&').forEach(param => {
48
62
  const parts = param.replace(/\+/g, ' ').split('=')
49
63
  const key = decode(parts.shift())
50
- const val = parts.length > 0
51
- ? decode(parts.join('='))
52
- : null
64
+ const val = parts.length > 0 ? decode(parts.join('=')) : null
53
65
 
54
66
  if (res[key] === undefined) {
55
67
  res[key] = val
@@ -64,33 +76,38 @@ function parseQuery (query: string): Dictionary<string> {
64
76
  }
65
77
 
66
78
  export function stringifyQuery (obj: Dictionary<string>): string {
67
- const res = obj ? Object.keys(obj).map(key => {
68
- const val = obj[key]
69
-
70
- if (val === undefined) {
71
- return ''
72
- }
79
+ const res = obj
80
+ ? Object.keys(obj)
81
+ .map(key => {
82
+ const val = obj[key]
73
83
 
74
- if (val === null) {
75
- return encode(key)
76
- }
84
+ if (val === undefined) {
85
+ return ''
86
+ }
77
87
 
78
- if (Array.isArray(val)) {
79
- const result = []
80
- val.forEach(val2 => {
81
- if (val2 === undefined) {
82
- return
88
+ if (val === null) {
89
+ return encode(key)
83
90
  }
84
- if (val2 === null) {
85
- result.push(encode(key))
86
- } else {
87
- result.push(encode(key) + '=' + encode(val2))
91
+
92
+ if (Array.isArray(val)) {
93
+ const result = []
94
+ val.forEach(val2 => {
95
+ if (val2 === undefined) {
96
+ return
97
+ }
98
+ if (val2 === null) {
99
+ result.push(encode(key))
100
+ } else {
101
+ result.push(encode(key) + '=' + encode(val2))
102
+ }
103
+ })
104
+ return result.join('&')
88
105
  }
89
- })
90
- return result.join('&')
91
- }
92
106
 
93
- return encode(key) + '=' + encode(val)
94
- }).filter(x => x.length > 0).join('&') : null
107
+ return encode(key) + '=' + encode(val)
108
+ })
109
+ .filter(x => x.length > 0)
110
+ .join('&')
111
+ : null
95
112
  return res ? `?${res}` : ''
96
113
  }
package/src/util/route.js CHANGED
@@ -70,23 +70,23 @@ function getFullPath (
70
70
  return (path || '/') + stringify(query) + hash
71
71
  }
72
72
 
73
- export function isSameRoute (a: Route, b: ?Route): boolean {
73
+ export function isSameRoute (a: Route, b: ?Route, onlyPath: ?boolean): boolean {
74
74
  if (b === START) {
75
75
  return a === b
76
76
  } else if (!b) {
77
77
  return false
78
78
  } else if (a.path && b.path) {
79
- return (
80
- a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
79
+ return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||
81
80
  a.hash === b.hash &&
82
- isObjectEqual(a.query, b.query)
83
- )
81
+ isObjectEqual(a.query, b.query))
84
82
  } else if (a.name && b.name) {
85
83
  return (
86
84
  a.name === b.name &&
87
- a.hash === b.hash &&
85
+ (onlyPath || (
86
+ a.hash === b.hash &&
88
87
  isObjectEqual(a.query, b.query) &&
89
- isObjectEqual(a.params, b.params)
88
+ isObjectEqual(a.params, b.params))
89
+ )
90
90
  )
91
91
  } else {
92
92
  return false
@@ -96,14 +96,18 @@ export function isSameRoute (a: Route, b: ?Route): boolean {
96
96
  function isObjectEqual (a = {}, b = {}): boolean {
97
97
  // handle null value #1566
98
98
  if (!a || !b) return a === b
99
- const aKeys = Object.keys(a)
100
- const bKeys = Object.keys(b)
99
+ const aKeys = Object.keys(a).sort()
100
+ const bKeys = Object.keys(b).sort()
101
101
  if (aKeys.length !== bKeys.length) {
102
102
  return false
103
103
  }
104
- return aKeys.every(key => {
104
+ return aKeys.every((key, i) => {
105
105
  const aVal = a[key]
106
+ const bKey = bKeys[i]
107
+ if (bKey !== key) return false
106
108
  const bVal = b[key]
109
+ // query values can be null and undefined
110
+ if (aVal == null || bVal == null) return aVal === bVal
107
111
  // check nested equality
108
112
  if (typeof aVal === 'object' && typeof bVal === 'object') {
109
113
  return isObjectEqual(aVal, bVal)
@@ -130,3 +134,18 @@ function queryIncludes (current: Dictionary<string>, target: Dictionary<string>)
130
134
  }
131
135
  return true
132
136
  }
137
+
138
+ export function handleRouteEntered (route: Route) {
139
+ for (let i = 0; i < route.matched.length; i++) {
140
+ const record = route.matched[i]
141
+ for (const name in record.instances) {
142
+ const instance = record.instances[name]
143
+ const cbs = record.enteredCbs[name]
144
+ if (!instance || !cbs) continue
145
+ delete record.enteredCbs[name]
146
+ for (let i = 0; i < cbs.length; i++) {
147
+ if (!instance._isBeingDestroyed) cbs[i](instance)
148
+ }
149
+ }
150
+ }
151
+ }
@@ -160,6 +160,16 @@ function scrollToPosition (shouldScroll, position) {
160
160
  }
161
161
 
162
162
  if (position) {
163
- window.scrollTo(position.x, position.y)
163
+ // $flow-disable-line
164
+ if ('scrollBehavior' in document.documentElement.style) {
165
+ window.scrollTo({
166
+ left: position.x,
167
+ top: position.y,
168
+ // $flow-disable-line
169
+ behavior: shouldScroll.behavior
170
+ })
171
+ } else {
172
+ window.scrollTo(position.x, position.y)
173
+ }
164
174
  }
165
175
  }
package/src/util/warn.js CHANGED
@@ -7,7 +7,7 @@ export function assert (condition: any, message: string) {
7
7
  }
8
8
 
9
9
  export function warn (condition: any, message: string) {
10
- if (process.env.NODE_ENV !== 'production' && !condition) {
10
+ if (!condition) {
11
11
  typeof console !== 'undefined' && console.warn(`[kdu-router] ${message}`)
12
12
  }
13
13
  }
package/types/index.d.ts CHANGED
@@ -5,13 +5,17 @@ export default KduRouter
5
5
 
6
6
  export {
7
7
  RouterMode,
8
+ RouteMeta,
8
9
  RawLocation,
9
10
  RedirectOption,
10
11
  RouterOptions,
11
12
  RouteConfig,
12
13
  RouteRecord,
14
+ RouteRecordPublic,
13
15
  Location,
14
16
  Route,
15
17
  NavigationGuard,
16
- NavigationGuardNext
18
+ NavigationGuardNext,
19
+ NavigationFailureType,
20
+ NavigationFailure
17
21
  } from './router'
package/types/router.d.ts CHANGED
@@ -21,7 +21,7 @@ export declare class KduRouter {
21
21
  constructor(options?: RouterOptions)
22
22
 
23
23
  app: Kdu
24
- options: RouterOptions;
24
+ options: RouterOptions
25
25
  mode: RouterMode
26
26
  currentRoute: Route
27
27
 
@@ -43,10 +43,16 @@ export declare class KduRouter {
43
43
  go(n: number): void
44
44
  back(): void
45
45
  forward(): void
46
+ match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route
46
47
  getMatchedComponents(to?: RawLocation | Route): Component[]
47
48
  onReady(cb: Function, errorCb?: ErrorHandler): void
48
49
  onError(cb: ErrorHandler): void
49
50
  addRoutes(routes: RouteConfig[]): void
51
+
52
+ addRoute(parent: string, route: RouteConfig): void
53
+ addRoute(route: RouteConfig): void
54
+ getRoutes(): RouteRecordPublic[]
55
+
50
56
  resolve(
51
57
  to: RawLocation,
52
58
  current?: Route,
@@ -63,19 +69,32 @@ export declare class KduRouter {
63
69
  static install: PluginFunction<never>
64
70
  static version: string
65
71
 
66
- static isNavigationFailure: (error: any, type?: NavigationFailureTypeE) => error is Error
67
- static NavigationFailureType: NavigationFailureTypeE
72
+ static isNavigationFailure: (
73
+ error: any,
74
+ type?: number
75
+ ) => error is NavigationFailure
76
+ static NavigationFailureType: {
77
+ [k in keyof typeof NavigationFailureType]: NavigationFailureType
78
+ }
79
+
80
+ static START_LOCATION: Route
68
81
  }
69
82
 
70
- export enum NavigationFailureTypeE {
71
- redirected = 1,
72
- aborted = 2,
73
- cancelled = 3,
74
- duplicated = 4
83
+ export enum NavigationFailureType {
84
+ redirected = 2,
85
+ aborted = 4,
86
+ cancelled = 8,
87
+ duplicated = 16
88
+ }
89
+
90
+ export interface NavigationFailure extends Error {
91
+ to: Route
92
+ from: Route
93
+ type: number
75
94
  }
76
95
 
77
96
  type Position = { x: number; y: number }
78
- type PositionResult = Position | { selector: string; offset?: Position } | void
97
+ type PositionResult = Position | { selector: string; offset?: Position, behavior?: ScrollBehavior } | void
79
98
 
80
99
  export interface RouterOptions {
81
100
  routes?: RouteConfig[]
@@ -107,7 +126,7 @@ interface _RouteConfigBase {
107
126
  children?: RouteConfig[]
108
127
  redirect?: RedirectOption
109
128
  alias?: string | string[]
110
- meta?: any
129
+ meta?: RouteMeta
111
130
  beforeEnter?: NavigationGuard
112
131
  caseSensitive?: boolean
113
132
  pathToRegexpOptions?: PathToRegexpOptions
@@ -134,6 +153,25 @@ export interface RouteRecord {
134
153
  parent?: RouteRecord
135
154
  redirect?: RedirectOption
136
155
  matchAs?: string
156
+ meta: RouteMeta
157
+ beforeEnter?: (
158
+ route: Route,
159
+ redirect: (location: RawLocation) => void,
160
+ next: () => void
161
+ ) => any
162
+ props:
163
+ | boolean
164
+ | Object
165
+ | RoutePropsFunction
166
+ | Dictionary<boolean | Object | RoutePropsFunction>
167
+ }
168
+
169
+ export interface RouteRecordPublic {
170
+ path: string
171
+ components: Dictionary<Component>
172
+ instances: Dictionary<Kdu>
173
+ name?: string
174
+ redirect?: RedirectOption
137
175
  meta: any
138
176
  beforeEnter?: (
139
177
  route: Route,
@@ -147,6 +185,7 @@ export interface RouteRecord {
147
185
  | Dictionary<boolean | Object | RoutePropsFunction>
148
186
  }
149
187
 
188
+
150
189
  export interface Location {
151
190
  name?: string
152
191
  path?: string
@@ -166,5 +205,7 @@ export interface Route {
166
205
  fullPath: string
167
206
  matched: RouteRecord[]
168
207
  redirectedFrom?: string
169
- meta?: any
208
+ meta?: RouteMeta
170
209
  }
210
+
211
+ export interface RouteMeta extends Record<string | number | symbol, any> {}