kdu-router 3.5.4 → 3.6.1
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.
- package/LICENSE +21 -21
- package/README.md +11 -11
- package/dist/composables.js +253 -0
- package/dist/composables.mjs +244 -0
- package/dist/kdu-router.common.js +2668 -2665
- package/dist/kdu-router.esm.browser.js +2677 -2671
- package/dist/kdu-router.esm.browser.min.js +5 -5
- package/dist/kdu-router.esm.js +2672 -2666
- package/dist/kdu-router.js +2675 -2672
- package/dist/kdu-router.min.js +5 -5
- package/ketur/attributes.json +38 -38
- package/ketur/tags.json +20 -20
- package/package.json +115 -90
- package/src/components/link.js +224 -224
- package/src/components/view.js +155 -155
- package/src/composables/globals.js +34 -0
- package/src/composables/guards.js +68 -0
- package/src/composables/index.js +3 -0
- package/src/composables/useLink.js +113 -0
- package/src/composables/utils.js +11 -0
- package/src/create-matcher.js +226 -226
- package/src/create-route-map.js +220 -220
- package/src/entries/cjs.js +3 -0
- package/src/entries/esm.js +12 -0
- package/src/history/abstract.js +72 -72
- package/src/history/base.js +379 -379
- package/src/history/hash.js +152 -152
- package/src/history/html5.js +99 -99
- package/src/index.js +3 -293
- package/src/install.js +52 -52
- package/src/router.js +293 -0
- package/src/util/async.js +18 -18
- package/src/util/dom.js +3 -3
- package/src/util/errors.js +86 -86
- package/src/util/location.js +69 -69
- package/src/util/misc.js +6 -6
- package/src/util/params.js +37 -37
- package/src/util/path.js +74 -74
- package/src/util/push-state.js +46 -46
- package/src/util/query.js +113 -113
- package/src/util/resolve-components.js +109 -109
- package/src/util/route.js +151 -151
- package/src/util/scroll.js +175 -175
- package/src/util/state-key.js +22 -22
- package/src/util/warn.js +14 -14
- package/types/composables.d.ts +53 -0
- package/types/index.d.ts +25 -21
- package/types/kdu.d.ts +22 -22
- package/types/router.d.ts +564 -211
package/src/util/async.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
export function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {
|
|
4
|
-
const step = index => {
|
|
5
|
-
if (index >= queue.length) {
|
|
6
|
-
cb()
|
|
7
|
-
} else {
|
|
8
|
-
if (queue[index]) {
|
|
9
|
-
fn(queue[index], () => {
|
|
10
|
-
step(index + 1)
|
|
11
|
-
})
|
|
12
|
-
} else {
|
|
13
|
-
step(index + 1)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
step(0)
|
|
18
|
-
}
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
export function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {
|
|
4
|
+
const step = index => {
|
|
5
|
+
if (index >= queue.length) {
|
|
6
|
+
cb()
|
|
7
|
+
} else {
|
|
8
|
+
if (queue[index]) {
|
|
9
|
+
fn(queue[index], () => {
|
|
10
|
+
step(index + 1)
|
|
11
|
+
})
|
|
12
|
+
} else {
|
|
13
|
+
step(index + 1)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
step(0)
|
|
18
|
+
}
|
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'
|
package/src/util/errors.js
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
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
|
+
// 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
|
+
}
|
package/src/util/location.js
CHANGED
|
@@ -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
|
+
}
|
package/src/util/params.js
CHANGED
|
@@ -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(/\/(?:\s*\/)+/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
|
+
}
|