kdu-router 3.4.0-beta.0 → 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 -9
  3. package/dist/composables.js +253 -0
  4. package/dist/composables.mjs +244 -0
  5. package/dist/kdu-router.common.js +2682 -2572
  6. package/dist/kdu-router.esm.browser.js +2677 -2563
  7. package/dist/kdu-router.esm.browser.min.js +5 -5
  8. package/dist/kdu-router.esm.js +2685 -2572
  9. package/dist/kdu-router.js +2682 -2573
  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 -111
  14. package/src/components/link.js +224 -197
  15. package/src/components/view.js +155 -149
  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 -200
  22. package/src/create-route-map.js +220 -205
  23. package/src/entries/cjs.js +3 -0
  24. package/src/entries/esm.js +12 -0
  25. package/src/history/abstract.js +72 -68
  26. package/src/history/base.js +379 -400
  27. package/src/history/hash.js +152 -163
  28. package/src/history/html5.js +99 -94
  29. package/src/index.js +3 -277
  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 -85
  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 -96
  41. package/src/util/resolve-components.js +109 -109
  42. package/src/util/route.js +151 -132
  43. package/src/util/scroll.js +175 -165
  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 -17
  48. package/types/kdu.d.ts +22 -22
  49. package/types/router.d.ts +564 -170
package/src/util/dom.js CHANGED
@@ -1,3 +1,3 @@
1
- /* @flow */
2
-
3
- export const inBrowser = typeof window !== 'undefined'
1
+ /* @flow */
2
+
3
+ export const inBrowser = typeof window !== 'undefined'
@@ -1,85 +1,86 @@
1
- export const NavigationFailureType = {
2
- redirected: 2,
3
- aborted: 4,
4
- cancelled: 8,
5
- duplicated: 16
6
- }
7
-
8
- export function createNavigationRedirectedError (from, to) {
9
- return createRouterError(
10
- from,
11
- to,
12
- NavigationFailureType.redirected,
13
- `Redirected when going from "${from.fullPath}" to "${stringifyRoute(
14
- to
15
- )}" via a navigation guard.`
16
- )
17
- }
18
-
19
- export function createNavigationDuplicatedError (from, to) {
20
- const error = createRouterError(
21
- from,
22
- to,
23
- NavigationFailureType.duplicated,
24
- `Avoided redundant navigation to current location: "${from.fullPath}".`
25
- )
26
- // backwards compatible with the first introduction of Errors
27
- error.name = 'NavigationDuplicated'
28
- return error
29
- }
30
-
31
- export function createNavigationCancelledError (from, to) {
32
- return createRouterError(
33
- from,
34
- to,
35
- NavigationFailureType.cancelled,
36
- `Navigation cancelled from "${from.fullPath}" to "${
37
- to.fullPath
38
- }" with a new navigation.`
39
- )
40
- }
41
-
42
- export function createNavigationAbortedError (from, to) {
43
- return createRouterError(
44
- from,
45
- to,
46
- NavigationFailureType.aborted,
47
- `Navigation aborted from "${from.fullPath}" to "${
48
- to.fullPath
49
- }" via a navigation guard.`
50
- )
51
- }
52
-
53
- function createRouterError (from, to, type, message) {
54
- const error = new Error(message)
55
- error._isRouter = true
56
- error.from = from
57
- error.to = to
58
- error.type = type
59
-
60
- return error
61
- }
62
-
63
- const propertiesToLog = ['params', 'query', 'hash']
64
-
65
- function stringifyRoute (to) {
66
- if (typeof to === 'string') return to
67
- if ('path' in to) return to.path
68
- const location = {}
69
- propertiesToLog.forEach(key => {
70
- if (key in to) location[key] = to[key]
71
- })
72
- return JSON.stringify(location, null, 2)
73
- }
74
-
75
- export function isError (err) {
76
- return Object.prototype.toString.call(err).indexOf('Error') > -1
77
- }
78
-
79
- export function isNavigationFailure (err, errorType) {
80
- return (
81
- isError(err) &&
82
- err._isRouter &&
83
- (errorType == null || err.type === errorType)
84
- )
85
- }
1
+ // When changing thing, also edit router.d.ts
2
+ export const NavigationFailureType = {
3
+ redirected: 2,
4
+ aborted: 4,
5
+ cancelled: 8,
6
+ duplicated: 16
7
+ }
8
+
9
+ export function createNavigationRedirectedError (from, to) {
10
+ return createRouterError(
11
+ from,
12
+ to,
13
+ NavigationFailureType.redirected,
14
+ `Redirected when going from "${from.fullPath}" to "${stringifyRoute(
15
+ to
16
+ )}" via a navigation guard.`
17
+ )
18
+ }
19
+
20
+ export function createNavigationDuplicatedError (from, to) {
21
+ const error = createRouterError(
22
+ from,
23
+ to,
24
+ NavigationFailureType.duplicated,
25
+ `Avoided redundant navigation to current location: "${from.fullPath}".`
26
+ )
27
+ // backwards compatible with the first introduction of Errors
28
+ error.name = 'NavigationDuplicated'
29
+ return error
30
+ }
31
+
32
+ export function createNavigationCancelledError (from, to) {
33
+ return createRouterError(
34
+ from,
35
+ to,
36
+ NavigationFailureType.cancelled,
37
+ `Navigation cancelled from "${from.fullPath}" to "${
38
+ to.fullPath
39
+ }" with a new navigation.`
40
+ )
41
+ }
42
+
43
+ export function createNavigationAbortedError (from, to) {
44
+ return createRouterError(
45
+ from,
46
+ to,
47
+ NavigationFailureType.aborted,
48
+ `Navigation aborted from "${from.fullPath}" to "${
49
+ to.fullPath
50
+ }" via a navigation guard.`
51
+ )
52
+ }
53
+
54
+ function createRouterError (from, to, type, message) {
55
+ const error = new Error(message)
56
+ error._isRouter = true
57
+ error.from = from
58
+ error.to = to
59
+ error.type = type
60
+
61
+ return error
62
+ }
63
+
64
+ const propertiesToLog = ['params', 'query', 'hash']
65
+
66
+ function stringifyRoute (to) {
67
+ if (typeof to === 'string') return to
68
+ if ('path' in to) return to.path
69
+ const location = {}
70
+ propertiesToLog.forEach(key => {
71
+ if (key in to) location[key] = to[key]
72
+ })
73
+ return JSON.stringify(location, null, 2)
74
+ }
75
+
76
+ export function isError (err) {
77
+ return Object.prototype.toString.call(err).indexOf('Error') > -1
78
+ }
79
+
80
+ export function isNavigationFailure (err, errorType) {
81
+ return (
82
+ isError(err) &&
83
+ err._isRouter &&
84
+ (errorType == null || err.type === errorType)
85
+ )
86
+ }
@@ -1,69 +1,69 @@
1
- /* @flow */
2
-
3
- import type KduRouter from '../index'
4
- import { parsePath, resolvePath } from './path'
5
- import { resolveQuery } from './query'
6
- import { fillParams } from './params'
7
- import { warn } from './warn'
8
- import { extend } from './misc'
9
-
10
- export function normalizeLocation (
11
- raw: RawLocation,
12
- current: ?Route,
13
- append: ?boolean,
14
- router: ?KduRouter
15
- ): Location {
16
- let next: Location = typeof raw === 'string' ? { path: raw } : raw
17
- // named target
18
- if (next._normalized) {
19
- return next
20
- } else if (next.name) {
21
- next = extend({}, raw)
22
- const params = next.params
23
- if (params && typeof params === 'object') {
24
- next.params = extend({}, params)
25
- }
26
- return next
27
- }
28
-
29
- // relative params
30
- if (!next.path && next.params && current) {
31
- next = extend({}, next)
32
- next._normalized = true
33
- const params: any = extend(extend({}, current.params), next.params)
34
- if (current.name) {
35
- next.name = current.name
36
- next.params = params
37
- } else if (current.matched.length) {
38
- const rawPath = current.matched[current.matched.length - 1].path
39
- next.path = fillParams(rawPath, params, `path ${current.path}`)
40
- } else if (process.env.NODE_ENV !== 'production') {
41
- warn(false, `relative params navigation requires a current route.`)
42
- }
43
- return next
44
- }
45
-
46
- const parsedPath = parsePath(next.path || '')
47
- const basePath = (current && current.path) || '/'
48
- const path = parsedPath.path
49
- ? resolvePath(parsedPath.path, basePath, append || next.append)
50
- : basePath
51
-
52
- const query = resolveQuery(
53
- parsedPath.query,
54
- next.query,
55
- router && router.options.parseQuery
56
- )
57
-
58
- let hash = next.hash || parsedPath.hash
59
- if (hash && hash.charAt(0) !== '#') {
60
- hash = `#${hash}`
61
- }
62
-
63
- return {
64
- _normalized: true,
65
- path,
66
- query,
67
- hash
68
- }
69
- }
1
+ /* @flow */
2
+
3
+ import type KduRouter from '../index'
4
+ import { parsePath, resolvePath } from './path'
5
+ import { resolveQuery } from './query'
6
+ import { fillParams } from './params'
7
+ import { warn } from './warn'
8
+ import { extend } from './misc'
9
+
10
+ export function normalizeLocation (
11
+ raw: RawLocation,
12
+ current: ?Route,
13
+ append: ?boolean,
14
+ router: ?KduRouter
15
+ ): Location {
16
+ let next: Location = typeof raw === 'string' ? { path: raw } : raw
17
+ // named target
18
+ if (next._normalized) {
19
+ return next
20
+ } else if (next.name) {
21
+ next = extend({}, raw)
22
+ const params = next.params
23
+ if (params && typeof params === 'object') {
24
+ next.params = extend({}, params)
25
+ }
26
+ return next
27
+ }
28
+
29
+ // relative params
30
+ if (!next.path && next.params && current) {
31
+ next = extend({}, next)
32
+ next._normalized = true
33
+ const params: any = extend(extend({}, current.params), next.params)
34
+ if (current.name) {
35
+ next.name = current.name
36
+ next.params = params
37
+ } else if (current.matched.length) {
38
+ const rawPath = current.matched[current.matched.length - 1].path
39
+ next.path = fillParams(rawPath, params, `path ${current.path}`)
40
+ } else if (process.env.NODE_ENV !== 'production') {
41
+ warn(false, `relative params navigation requires a current route.`)
42
+ }
43
+ return next
44
+ }
45
+
46
+ const parsedPath = parsePath(next.path || '')
47
+ const basePath = (current && current.path) || '/'
48
+ const path = parsedPath.path
49
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
50
+ : basePath
51
+
52
+ const query = resolveQuery(
53
+ parsedPath.query,
54
+ next.query,
55
+ router && router.options.parseQuery
56
+ )
57
+
58
+ let hash = next.hash || parsedPath.hash
59
+ if (hash && hash.charAt(0) !== '#') {
60
+ hash = `#${hash}`
61
+ }
62
+
63
+ return {
64
+ _normalized: true,
65
+ path,
66
+ query,
67
+ hash
68
+ }
69
+ }
package/src/util/misc.js CHANGED
@@ -1,6 +1,6 @@
1
- export function extend (a, b) {
2
- for (const key in b) {
3
- a[key] = b[key]
4
- }
5
- return a
6
- }
1
+ export function extend (a, b) {
2
+ for (const key in b) {
3
+ a[key] = b[key]
4
+ }
5
+ return a
6
+ }
@@ -1,37 +1,37 @@
1
- /* @flow */
2
-
3
- import { warn } from './warn'
4
- import Regexp from 'path-to-regexp'
5
-
6
- // $flow-disable-line
7
- const regexpCompileCache: {
8
- [key: string]: Function
9
- } = Object.create(null)
10
-
11
- export function fillParams (
12
- path: string,
13
- params: ?Object,
14
- routeMsg: string
15
- ): string {
16
- params = params || {}
17
- try {
18
- const filler =
19
- regexpCompileCache[path] ||
20
- (regexpCompileCache[path] = Regexp.compile(path))
21
-
22
- // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
23
- // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string
24
- if (typeof params.pathMatch === 'string') params[0] = params.pathMatch
25
-
26
- return filler(params, { pretty: true })
27
- } catch (e) {
28
- if (process.env.NODE_ENV !== 'production') {
29
- // Fix #3072 no warn if `pathMatch` is string
30
- warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`)
31
- }
32
- return ''
33
- } finally {
34
- // delete the 0 if it was added
35
- delete params[0]
36
- }
37
- }
1
+ /* @flow */
2
+
3
+ import { warn } from './warn'
4
+ import Regexp from 'path-to-regexp'
5
+
6
+ // $flow-disable-line
7
+ const regexpCompileCache: {
8
+ [key: string]: Function
9
+ } = Object.create(null)
10
+
11
+ export function fillParams (
12
+ path: string,
13
+ params: ?Object,
14
+ routeMsg: string
15
+ ): string {
16
+ params = params || {}
17
+ try {
18
+ const filler =
19
+ regexpCompileCache[path] ||
20
+ (regexpCompileCache[path] = Regexp.compile(path))
21
+
22
+ // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
23
+ // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string
24
+ if (typeof params.pathMatch === 'string') params[0] = params.pathMatch
25
+
26
+ return filler(params, { pretty: true })
27
+ } catch (e) {
28
+ if (process.env.NODE_ENV !== 'production') {
29
+ // Fix #3072 no warn if `pathMatch` is string
30
+ warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`)
31
+ }
32
+ return ''
33
+ } finally {
34
+ // delete the 0 if it was added
35
+ delete params[0]
36
+ }
37
+ }
package/src/util/path.js CHANGED
@@ -1,74 +1,74 @@
1
- /* @flow */
2
-
3
- export function resolvePath (
4
- relative: string,
5
- base: string,
6
- append?: boolean
7
- ): string {
8
- const firstChar = relative.charAt(0)
9
- if (firstChar === '/') {
10
- return relative
11
- }
12
-
13
- if (firstChar === '?' || firstChar === '#') {
14
- return base + relative
15
- }
16
-
17
- const stack = base.split('/')
18
-
19
- // remove trailing segment if:
20
- // - not appending
21
- // - appending to trailing slash (last segment is empty)
22
- if (!append || !stack[stack.length - 1]) {
23
- stack.pop()
24
- }
25
-
26
- // resolve relative path
27
- const segments = relative.replace(/^\//, '').split('/')
28
- for (let i = 0; i < segments.length; i++) {
29
- const segment = segments[i]
30
- if (segment === '..') {
31
- stack.pop()
32
- } else if (segment !== '.') {
33
- stack.push(segment)
34
- }
35
- }
36
-
37
- // ensure leading slash
38
- if (stack[0] !== '') {
39
- stack.unshift('')
40
- }
41
-
42
- return stack.join('/')
43
- }
44
-
45
- export function parsePath (path: string): {
46
- path: string;
47
- query: string;
48
- hash: string;
49
- } {
50
- let hash = ''
51
- let query = ''
52
-
53
- const hashIndex = path.indexOf('#')
54
- if (hashIndex >= 0) {
55
- hash = path.slice(hashIndex)
56
- path = path.slice(0, hashIndex)
57
- }
58
-
59
- const queryIndex = path.indexOf('?')
60
- if (queryIndex >= 0) {
61
- query = path.slice(queryIndex + 1)
62
- path = path.slice(0, queryIndex)
63
- }
64
-
65
- return {
66
- path,
67
- query,
68
- hash
69
- }
70
- }
71
-
72
- export function cleanPath (path: string): string {
73
- return path.replace(/\/\//g, '/')
74
- }
1
+ /* @flow */
2
+
3
+ export function resolvePath (
4
+ relative: string,
5
+ base: string,
6
+ append?: boolean
7
+ ): string {
8
+ const firstChar = relative.charAt(0)
9
+ if (firstChar === '/') {
10
+ return relative
11
+ }
12
+
13
+ if (firstChar === '?' || firstChar === '#') {
14
+ return base + relative
15
+ }
16
+
17
+ const stack = base.split('/')
18
+
19
+ // remove trailing segment if:
20
+ // - not appending
21
+ // - appending to trailing slash (last segment is empty)
22
+ if (!append || !stack[stack.length - 1]) {
23
+ stack.pop()
24
+ }
25
+
26
+ // resolve relative path
27
+ const segments = relative.replace(/^\//, '').split('/')
28
+ for (let i = 0; i < segments.length; i++) {
29
+ const segment = segments[i]
30
+ if (segment === '..') {
31
+ stack.pop()
32
+ } else if (segment !== '.') {
33
+ stack.push(segment)
34
+ }
35
+ }
36
+
37
+ // ensure leading slash
38
+ if (stack[0] !== '') {
39
+ stack.unshift('')
40
+ }
41
+
42
+ return stack.join('/')
43
+ }
44
+
45
+ export function parsePath (path: string): {
46
+ path: string;
47
+ query: string;
48
+ hash: string;
49
+ } {
50
+ let hash = ''
51
+ let query = ''
52
+
53
+ const hashIndex = path.indexOf('#')
54
+ if (hashIndex >= 0) {
55
+ hash = path.slice(hashIndex)
56
+ path = path.slice(0, hashIndex)
57
+ }
58
+
59
+ const queryIndex = path.indexOf('?')
60
+ if (queryIndex >= 0) {
61
+ query = path.slice(queryIndex + 1)
62
+ path = path.slice(0, queryIndex)
63
+ }
64
+
65
+ return {
66
+ path,
67
+ query,
68
+ hash
69
+ }
70
+ }
71
+
72
+ export function cleanPath (path: string): string {
73
+ return path.replace(/\/(?:\s*\/)+/g, '/')
74
+ }
@@ -1,46 +1,46 @@
1
- /* @flow */
2
-
3
- import { inBrowser } from './dom'
4
- import { saveScrollPosition } from './scroll'
5
- import { genStateKey, setStateKey, getStateKey } from './state-key'
6
- import { extend } from './misc'
7
-
8
- export const supportsPushState =
9
- inBrowser &&
10
- (function () {
11
- const ua = window.navigator.userAgent
12
-
13
- if (
14
- (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
15
- ua.indexOf('Mobile Safari') !== -1 &&
16
- ua.indexOf('Chrome') === -1 &&
17
- ua.indexOf('Windows Phone') === -1
18
- ) {
19
- return false
20
- }
21
-
22
- return window.history && typeof window.history.pushState === 'function'
23
- })()
24
-
25
- export function pushState (url?: string, replace?: boolean) {
26
- saveScrollPosition()
27
- // try...catch the pushState call to get around Safari
28
- // DOM Exception 18 where it limits to 100 pushState calls
29
- const history = window.history
30
- try {
31
- if (replace) {
32
- // preserve existing history state as it could be overriden by the user
33
- const stateCopy = extend({}, history.state)
34
- stateCopy.key = getStateKey()
35
- history.replaceState(stateCopy, '', url)
36
- } else {
37
- history.pushState({ key: setStateKey(genStateKey()) }, '', url)
38
- }
39
- } catch (e) {
40
- window.location[replace ? 'replace' : 'assign'](url)
41
- }
42
- }
43
-
44
- export function replaceState (url?: string) {
45
- pushState(url, true)
46
- }
1
+ /* @flow */
2
+
3
+ import { inBrowser } from './dom'
4
+ import { saveScrollPosition } from './scroll'
5
+ import { genStateKey, setStateKey, getStateKey } from './state-key'
6
+ import { extend } from './misc'
7
+
8
+ export const supportsPushState =
9
+ inBrowser &&
10
+ (function () {
11
+ const ua = window.navigator.userAgent
12
+
13
+ if (
14
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
15
+ ua.indexOf('Mobile Safari') !== -1 &&
16
+ ua.indexOf('Chrome') === -1 &&
17
+ ua.indexOf('Windows Phone') === -1
18
+ ) {
19
+ return false
20
+ }
21
+
22
+ return window.history && typeof window.history.pushState === 'function'
23
+ })()
24
+
25
+ export function pushState (url?: string, replace?: boolean) {
26
+ saveScrollPosition()
27
+ // try...catch the pushState call to get around Safari
28
+ // DOM Exception 18 where it limits to 100 pushState calls
29
+ const history = window.history
30
+ try {
31
+ if (replace) {
32
+ // preserve existing history state as it could be overriden by the user
33
+ const stateCopy = extend({}, history.state)
34
+ stateCopy.key = getStateKey()
35
+ history.replaceState(stateCopy, '', url)
36
+ } else {
37
+ history.pushState({ key: setStateKey(genStateKey()) }, '', url)
38
+ }
39
+ } catch (e) {
40
+ window.location[replace ? 'replace' : 'assign'](url)
41
+ }
42
+ }
43
+
44
+ export function replaceState (url?: string) {
45
+ pushState(url, true)
46
+ }