@tanstack/router-core 0.0.1-beta.9 → 1.97.24
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 -0
- package/README.md +5 -0
- package/dist/cjs/Matches.cjs +13 -0
- package/dist/cjs/Matches.cjs.map +1 -0
- package/dist/cjs/Matches.d.cts +28 -0
- package/dist/cjs/RouterProvider.d.cts +18 -0
- package/dist/cjs/defer.cjs +25 -0
- package/dist/cjs/defer.cjs.map +1 -0
- package/dist/cjs/defer.d.cts +20 -0
- package/dist/cjs/index.cjs +50 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +25 -0
- package/dist/cjs/link.cjs +5 -0
- package/dist/cjs/link.cjs.map +1 -0
- package/dist/cjs/link.d.cts +51 -0
- package/dist/cjs/location.d.cts +12 -0
- package/dist/cjs/manifest.d.cts +24 -0
- package/dist/cjs/path.cjs +289 -0
- package/dist/cjs/path.cjs.map +1 -0
- package/dist/cjs/path.d.cts +34 -0
- package/dist/cjs/qss.cjs +51 -0
- package/dist/cjs/qss.cjs.map +1 -0
- package/dist/cjs/qss.d.cts +27 -0
- package/dist/cjs/root.cjs +5 -0
- package/dist/cjs/root.cjs.map +1 -0
- package/dist/cjs/root.d.cts +2 -0
- package/dist/cjs/route.d.cts +148 -0
- package/dist/cjs/router.cjs +19 -0
- package/dist/cjs/router.cjs.map +1 -0
- package/dist/cjs/router.d.cts +31 -0
- package/dist/cjs/searchMiddleware.cjs +42 -0
- package/dist/cjs/searchMiddleware.cjs.map +1 -0
- package/dist/cjs/searchMiddleware.d.cts +5 -0
- package/dist/cjs/searchParams.cjs +61 -0
- package/dist/cjs/searchParams.cjs.map +1 -0
- package/dist/cjs/searchParams.d.cts +7 -0
- package/dist/cjs/serializer.d.cts +15 -0
- package/dist/cjs/structuralSharing.d.cts +4 -0
- package/dist/cjs/utils.cjs +155 -0
- package/dist/cjs/utils.cjs.map +1 -0
- package/dist/cjs/utils.d.cts +81 -0
- package/dist/cjs/validators.d.cts +51 -0
- package/dist/esm/Matches.d.ts +28 -0
- package/dist/esm/Matches.js +13 -0
- package/dist/esm/Matches.js.map +1 -0
- package/dist/esm/RouterProvider.d.ts +18 -0
- package/dist/esm/defer.d.ts +20 -0
- package/dist/esm/defer.js +25 -0
- package/dist/esm/defer.js.map +1 -0
- package/dist/esm/index.d.ts +25 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/link.d.ts +51 -0
- package/dist/esm/link.js +5 -0
- package/dist/esm/link.js.map +1 -0
- package/dist/esm/location.d.ts +12 -0
- package/dist/esm/manifest.d.ts +24 -0
- package/dist/esm/path.d.ts +34 -0
- package/dist/esm/path.js +289 -0
- package/dist/esm/path.js.map +1 -0
- package/dist/esm/qss.d.ts +27 -0
- package/dist/esm/qss.js +51 -0
- package/dist/esm/qss.js.map +1 -0
- package/dist/esm/root.d.ts +2 -0
- package/dist/esm/root.js +5 -0
- package/dist/esm/root.js.map +1 -0
- package/dist/esm/route.d.ts +148 -0
- package/dist/esm/router.d.ts +31 -0
- package/dist/esm/router.js +19 -0
- package/dist/esm/router.js.map +1 -0
- package/dist/esm/searchMiddleware.d.ts +5 -0
- package/dist/esm/searchMiddleware.js +42 -0
- package/dist/esm/searchMiddleware.js.map +1 -0
- package/dist/esm/searchParams.d.ts +7 -0
- package/dist/esm/searchParams.js +61 -0
- package/dist/esm/searchParams.js.map +1 -0
- package/dist/esm/serializer.d.ts +15 -0
- package/dist/esm/structuralSharing.d.ts +4 -0
- package/dist/esm/utils.d.ts +81 -0
- package/dist/esm/utils.js +155 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/validators.d.ts +51 -0
- package/package.json +35 -32
- package/src/Matches.ts +94 -0
- package/src/RouterProvider.ts +20 -0
- package/src/defer.ts +52 -0
- package/src/index.ts +206 -19
- package/src/link.ts +122 -300
- package/src/location.ts +13 -0
- package/src/manifest.ts +32 -0
- package/src/path.ts +238 -47
- package/src/qss.ts +56 -19
- package/src/root.ts +2 -0
- package/src/route.ts +296 -223
- package/src/router.ts +34 -1281
- package/src/searchMiddleware.ts +54 -0
- package/src/searchParams.ts +43 -20
- package/src/serializer.ts +24 -0
- package/src/structuralSharing.ts +7 -0
- package/src/utils.ts +314 -75
- package/src/validators.ts +121 -0
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -33
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
- package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
- package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
- package/build/cjs/node_modules/history/index.js +0 -815
- package/build/cjs/node_modules/history/index.js.map +0 -1
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
- package/build/cjs/packages/router-core/src/index.js +0 -58
- package/build/cjs/packages/router-core/src/index.js.map +0 -1
- package/build/cjs/packages/router-core/src/path.js +0 -222
- package/build/cjs/packages/router-core/src/path.js.map +0 -1
- package/build/cjs/packages/router-core/src/qss.js +0 -71
- package/build/cjs/packages/router-core/src/qss.js.map +0 -1
- package/build/cjs/packages/router-core/src/route.js +0 -150
- package/build/cjs/packages/router-core/src/route.js.map +0 -1
- package/build/cjs/packages/router-core/src/routeConfig.js +0 -69
- package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
- package/build/cjs/packages/router-core/src/routeMatch.js +0 -266
- package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
- package/build/cjs/packages/router-core/src/router.js +0 -822
- package/build/cjs/packages/router-core/src/router.js.map +0 -1
- package/build/cjs/packages/router-core/src/searchParams.js +0 -70
- package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
- package/build/cjs/packages/router-core/src/utils.js +0 -125
- package/build/cjs/packages/router-core/src/utils.js.map +0 -1
- package/build/esm/index.js +0 -2481
- package/build/esm/index.js.map +0 -1
- package/build/stats-html.html +0 -4034
- package/build/stats-react.json +0 -493
- package/build/types/index.d.ts +0 -618
- package/build/umd/index.development.js +0 -2514
- package/build/umd/index.development.js.map +0 -1
- package/build/umd/index.production.js +0 -12
- package/build/umd/index.production.js.map +0 -1
- package/src/frameworks.ts +0 -12
- package/src/routeConfig.ts +0 -495
- package/src/routeInfo.ts +0 -228
- package/src/routeMatch.ts +0 -374
package/src/path.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { AnyPathParams } from './routeConfig'
|
|
2
|
-
import { MatchLocation } from './router'
|
|
3
1
|
import { last } from './utils'
|
|
2
|
+
import type { MatchLocation } from './RouterProvider'
|
|
3
|
+
import type { AnyPathParams } from './route'
|
|
4
4
|
|
|
5
5
|
export interface Segment {
|
|
6
6
|
type: 'pathname' | 'param' | 'wildcard'
|
|
7
7
|
value: string
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function joinPaths(paths:
|
|
11
|
-
return cleanPath(
|
|
10
|
+
export function joinPaths(paths: Array<string | undefined>) {
|
|
11
|
+
return cleanPath(
|
|
12
|
+
paths
|
|
13
|
+
.filter((val) => {
|
|
14
|
+
return val !== undefined
|
|
15
|
+
})
|
|
16
|
+
.join('/'),
|
|
17
|
+
)
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export function cleanPath(path: string) {
|
|
@@ -28,13 +34,79 @@ export function trimPath(path: string) {
|
|
|
28
34
|
return trimPathRight(trimPathLeft(path))
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
export function
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
export function removeTrailingSlash(value: string, basepath: string): string {
|
|
38
|
+
if (value.endsWith('/') && value !== '/' && value !== `${basepath}/`) {
|
|
39
|
+
return value.slice(0, -1)
|
|
40
|
+
}
|
|
41
|
+
return value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// intended to only compare path name
|
|
45
|
+
// see the usage in the isActive under useLinkProps
|
|
46
|
+
// /sample/path1 = /sample/path1/
|
|
47
|
+
// /sample/path1/some <> /sample/path1
|
|
48
|
+
export function exactPathTest(
|
|
49
|
+
pathName1: string,
|
|
50
|
+
pathName2: string,
|
|
51
|
+
basepath: string,
|
|
52
|
+
): boolean {
|
|
53
|
+
return (
|
|
54
|
+
removeTrailingSlash(pathName1, basepath) ===
|
|
55
|
+
removeTrailingSlash(pathName2, basepath)
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// When resolving relative paths, we treat all paths as if they are trailing slash
|
|
60
|
+
// documents. All trailing slashes are removed after the path is resolved.
|
|
61
|
+
// Here are a few examples:
|
|
62
|
+
//
|
|
63
|
+
// /a/b/c + ./d = /a/b/c/d
|
|
64
|
+
// /a/b/c + ../d = /a/b/d
|
|
65
|
+
// /a/b/c + ./d/ = /a/b/c/d
|
|
66
|
+
// /a/b/c + ../d/ = /a/b/d
|
|
67
|
+
// /a/b/c + ./ = /a/b/c
|
|
68
|
+
//
|
|
69
|
+
// Absolute paths that start with `/` short circuit the resolution process to the root
|
|
70
|
+
// path.
|
|
71
|
+
//
|
|
72
|
+
// Here are some examples:
|
|
73
|
+
//
|
|
74
|
+
// /a/b/c + /d = /d
|
|
75
|
+
// /a/b/c + /d/ = /d
|
|
76
|
+
// /a/b/c + / = /
|
|
77
|
+
//
|
|
78
|
+
// Non-.-prefixed paths are still treated as relative paths, resolved like `./`
|
|
79
|
+
//
|
|
80
|
+
// Here are some examples:
|
|
81
|
+
//
|
|
82
|
+
// /a/b/c + d = /a/b/c/d
|
|
83
|
+
// /a/b/c + d/ = /a/b/c/d
|
|
84
|
+
// /a/b/c + d/e = /a/b/c/d/e
|
|
85
|
+
interface ResolvePathOptions {
|
|
86
|
+
basepath: string
|
|
87
|
+
base: string
|
|
88
|
+
to: string
|
|
89
|
+
trailingSlash?: 'always' | 'never' | 'preserve'
|
|
90
|
+
caseSensitive?: boolean
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function resolvePath({
|
|
94
|
+
basepath,
|
|
95
|
+
base,
|
|
96
|
+
to,
|
|
97
|
+
trailingSlash = 'never',
|
|
98
|
+
caseSensitive,
|
|
99
|
+
}: ResolvePathOptions) {
|
|
100
|
+
base = removeBasepath(basepath, base, caseSensitive)
|
|
101
|
+
to = removeBasepath(basepath, to, caseSensitive)
|
|
34
102
|
|
|
35
103
|
let baseSegments = parsePathname(base)
|
|
36
104
|
const toSegments = parsePathname(to)
|
|
37
105
|
|
|
106
|
+
if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
|
|
107
|
+
baseSegments.pop()
|
|
108
|
+
}
|
|
109
|
+
|
|
38
110
|
toSegments.forEach((toSegment, index) => {
|
|
39
111
|
if (toSegment.value === '/') {
|
|
40
112
|
if (!index) {
|
|
@@ -47,31 +119,36 @@ export function resolvePath(basepath: string, base: string, to: string) {
|
|
|
47
119
|
// ignore inter-slashes
|
|
48
120
|
}
|
|
49
121
|
} else if (toSegment.value === '..') {
|
|
50
|
-
// Extra trailing slash? pop it off
|
|
51
|
-
if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
|
|
52
|
-
baseSegments.pop()
|
|
53
|
-
}
|
|
54
122
|
baseSegments.pop()
|
|
55
123
|
} else if (toSegment.value === '.') {
|
|
56
|
-
|
|
124
|
+
// ignore
|
|
57
125
|
} else {
|
|
58
126
|
baseSegments.push(toSegment)
|
|
59
127
|
}
|
|
60
128
|
})
|
|
61
129
|
|
|
62
|
-
|
|
130
|
+
if (baseSegments.length > 1) {
|
|
131
|
+
if (last(baseSegments)?.value === '/') {
|
|
132
|
+
if (trailingSlash === 'never') {
|
|
133
|
+
baseSegments.pop()
|
|
134
|
+
}
|
|
135
|
+
} else if (trailingSlash === 'always') {
|
|
136
|
+
baseSegments.push({ type: 'pathname', value: '/' })
|
|
137
|
+
}
|
|
138
|
+
}
|
|
63
139
|
|
|
140
|
+
const joined = joinPaths([basepath, ...baseSegments.map((d) => d.value)])
|
|
64
141
|
return cleanPath(joined)
|
|
65
142
|
}
|
|
66
143
|
|
|
67
|
-
export function parsePathname(pathname?: string): Segment
|
|
144
|
+
export function parsePathname(pathname?: string): Array<Segment> {
|
|
68
145
|
if (!pathname) {
|
|
69
146
|
return []
|
|
70
147
|
}
|
|
71
148
|
|
|
72
149
|
pathname = cleanPath(pathname)
|
|
73
150
|
|
|
74
|
-
const segments: Segment
|
|
151
|
+
const segments: Array<Segment> = []
|
|
75
152
|
|
|
76
153
|
if (pathname.slice(0, 1) === '/') {
|
|
77
154
|
pathname = pathname.substring(1)
|
|
@@ -90,14 +167,14 @@ export function parsePathname(pathname?: string): Segment[] {
|
|
|
90
167
|
|
|
91
168
|
segments.push(
|
|
92
169
|
...split.map((part): Segment => {
|
|
93
|
-
if (part
|
|
170
|
+
if (part === '$' || part === '*') {
|
|
94
171
|
return {
|
|
95
172
|
type: 'wildcard',
|
|
96
173
|
value: part,
|
|
97
174
|
}
|
|
98
175
|
}
|
|
99
176
|
|
|
100
|
-
if (part.charAt(0) === '
|
|
177
|
+
if (part.charAt(0) === '$') {
|
|
101
178
|
return {
|
|
102
179
|
type: 'param',
|
|
103
180
|
value: part,
|
|
@@ -106,7 +183,7 @@ export function parsePathname(pathname?: string): Segment[] {
|
|
|
106
183
|
|
|
107
184
|
return {
|
|
108
185
|
type: 'pathname',
|
|
109
|
-
value: part,
|
|
186
|
+
value: decodeURI(part),
|
|
110
187
|
}
|
|
111
188
|
}),
|
|
112
189
|
)
|
|
@@ -122,21 +199,52 @@ export function parsePathname(pathname?: string): Segment[] {
|
|
|
122
199
|
return segments
|
|
123
200
|
}
|
|
124
201
|
|
|
125
|
-
|
|
126
|
-
path
|
|
127
|
-
params:
|
|
128
|
-
|
|
129
|
-
|
|
202
|
+
interface InterpolatePathOptions {
|
|
203
|
+
path?: string
|
|
204
|
+
params: Record<string, unknown>
|
|
205
|
+
leaveWildcards?: boolean
|
|
206
|
+
leaveParams?: boolean
|
|
207
|
+
// Map of encoded chars to decoded chars (e.g. '%40' -> '@') that should remain decoded in path params
|
|
208
|
+
decodeCharMap?: Map<string, string>
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function interpolatePath({
|
|
212
|
+
path,
|
|
213
|
+
params,
|
|
214
|
+
leaveWildcards,
|
|
215
|
+
leaveParams,
|
|
216
|
+
decodeCharMap,
|
|
217
|
+
}: InterpolatePathOptions) {
|
|
130
218
|
const interpolatedPathSegments = parsePathname(path)
|
|
219
|
+
const encodedParams: any = {}
|
|
220
|
+
|
|
221
|
+
for (const [key, value] of Object.entries(params)) {
|
|
222
|
+
const isValueString = typeof value === 'string'
|
|
223
|
+
|
|
224
|
+
if (['*', '_splat'].includes(key)) {
|
|
225
|
+
// the splat/catch-all routes shouldn't have the '/' encoded out
|
|
226
|
+
encodedParams[key] = isValueString ? encodeURI(value) : value
|
|
227
|
+
} else {
|
|
228
|
+
encodedParams[key] = isValueString
|
|
229
|
+
? encodePathParam(value, decodeCharMap)
|
|
230
|
+
: value
|
|
231
|
+
}
|
|
232
|
+
}
|
|
131
233
|
|
|
132
234
|
return joinPaths(
|
|
133
235
|
interpolatedPathSegments.map((segment) => {
|
|
134
|
-
if (segment.
|
|
135
|
-
|
|
236
|
+
if (segment.type === 'wildcard') {
|
|
237
|
+
const value = encodedParams._splat
|
|
238
|
+
if (leaveWildcards) return `${segment.value}${value ?? ''}`
|
|
239
|
+
return value
|
|
136
240
|
}
|
|
137
241
|
|
|
138
242
|
if (segment.type === 'param') {
|
|
139
|
-
|
|
243
|
+
if (leaveParams) {
|
|
244
|
+
const value = encodedParams[segment.value]
|
|
245
|
+
return `${segment.value}${value ?? ''}`
|
|
246
|
+
}
|
|
247
|
+
return encodedParams![segment.value.substring(1)] ?? 'undefined'
|
|
140
248
|
}
|
|
141
249
|
|
|
142
250
|
return segment.value
|
|
@@ -144,34 +252,111 @@ export function interpolatePath(
|
|
|
144
252
|
)
|
|
145
253
|
}
|
|
146
254
|
|
|
255
|
+
function encodePathParam(value: string, decodeCharMap?: Map<string, string>) {
|
|
256
|
+
let encoded = encodeURIComponent(value)
|
|
257
|
+
if (decodeCharMap) {
|
|
258
|
+
for (const [encodedChar, char] of decodeCharMap) {
|
|
259
|
+
encoded = encoded.replaceAll(encodedChar, char)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return encoded
|
|
263
|
+
}
|
|
264
|
+
|
|
147
265
|
export function matchPathname(
|
|
266
|
+
basepath: string,
|
|
148
267
|
currentPathname: string,
|
|
149
268
|
matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>,
|
|
150
269
|
): AnyPathParams | undefined {
|
|
151
|
-
const pathParams = matchByPath(currentPathname, matchLocation)
|
|
152
|
-
// const searchMatched = matchBySearch(
|
|
270
|
+
const pathParams = matchByPath(basepath, currentPathname, matchLocation)
|
|
271
|
+
// const searchMatched = matchBySearch(location.search, matchLocation)
|
|
153
272
|
|
|
154
273
|
if (matchLocation.to && !pathParams) {
|
|
155
274
|
return
|
|
156
275
|
}
|
|
157
276
|
|
|
158
|
-
// if (matchLocation.search && !searchMatched) {
|
|
159
|
-
// return
|
|
160
|
-
// }
|
|
161
|
-
|
|
162
277
|
return pathParams ?? {}
|
|
163
278
|
}
|
|
164
279
|
|
|
280
|
+
export function removeBasepath(
|
|
281
|
+
basepath: string,
|
|
282
|
+
pathname: string,
|
|
283
|
+
caseSensitive: boolean = false,
|
|
284
|
+
) {
|
|
285
|
+
// normalize basepath and pathname for case-insensitive comparison if needed
|
|
286
|
+
const normalizedBasepath = caseSensitive ? basepath : basepath.toLowerCase()
|
|
287
|
+
const normalizedPathname = caseSensitive ? pathname : pathname.toLowerCase()
|
|
288
|
+
|
|
289
|
+
switch (true) {
|
|
290
|
+
// default behaviour is to serve app from the root - pathname
|
|
291
|
+
// left untouched
|
|
292
|
+
case normalizedBasepath === '/':
|
|
293
|
+
return pathname
|
|
294
|
+
|
|
295
|
+
// shortcut for removing the basepath if it matches the pathname
|
|
296
|
+
case normalizedPathname === normalizedBasepath:
|
|
297
|
+
return ''
|
|
298
|
+
|
|
299
|
+
// in case pathname is shorter than basepath - there is
|
|
300
|
+
// nothing to remove
|
|
301
|
+
case pathname.length < basepath.length:
|
|
302
|
+
return pathname
|
|
303
|
+
|
|
304
|
+
// avoid matching partial segments - strict equality handled
|
|
305
|
+
// earlier, otherwise, basepath separated from pathname with
|
|
306
|
+
// separator, therefore lack of separator means partial
|
|
307
|
+
// segment match (`/app` should not match `/application`)
|
|
308
|
+
case normalizedPathname[normalizedBasepath.length] !== '/':
|
|
309
|
+
return pathname
|
|
310
|
+
|
|
311
|
+
// remove the basepath from the pathname if it starts with it
|
|
312
|
+
case normalizedPathname.startsWith(normalizedBasepath):
|
|
313
|
+
return pathname.slice(basepath.length)
|
|
314
|
+
|
|
315
|
+
// otherwise, return the pathname as is
|
|
316
|
+
default:
|
|
317
|
+
return pathname
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
165
321
|
export function matchByPath(
|
|
322
|
+
basepath: string,
|
|
166
323
|
from: string,
|
|
167
324
|
matchLocation: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,
|
|
168
325
|
): Record<string, string> | undefined {
|
|
326
|
+
// check basepath first
|
|
327
|
+
if (basepath !== '/' && !from.startsWith(basepath)) {
|
|
328
|
+
return undefined
|
|
329
|
+
}
|
|
330
|
+
// Remove the base path from the pathname
|
|
331
|
+
from = removeBasepath(basepath, from, matchLocation.caseSensitive)
|
|
332
|
+
// Default to to $ (wildcard)
|
|
333
|
+
const to = removeBasepath(
|
|
334
|
+
basepath,
|
|
335
|
+
`${matchLocation.to ?? '$'}`,
|
|
336
|
+
matchLocation.caseSensitive,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
// Parse the from and to
|
|
169
340
|
const baseSegments = parsePathname(from)
|
|
170
|
-
const routeSegments = parsePathname(
|
|
341
|
+
const routeSegments = parsePathname(to)
|
|
342
|
+
|
|
343
|
+
if (!from.startsWith('/')) {
|
|
344
|
+
baseSegments.unshift({
|
|
345
|
+
type: 'pathname',
|
|
346
|
+
value: '/',
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!to.startsWith('/')) {
|
|
351
|
+
routeSegments.unshift({
|
|
352
|
+
type: 'pathname',
|
|
353
|
+
value: '/',
|
|
354
|
+
})
|
|
355
|
+
}
|
|
171
356
|
|
|
172
357
|
const params: Record<string, string> = {}
|
|
173
358
|
|
|
174
|
-
|
|
359
|
+
const isMatch = (() => {
|
|
175
360
|
for (
|
|
176
361
|
let i = 0;
|
|
177
362
|
i < Math.max(baseSegments.length, routeSegments.length);
|
|
@@ -180,16 +365,18 @@ export function matchByPath(
|
|
|
180
365
|
const baseSegment = baseSegments[i]
|
|
181
366
|
const routeSegment = routeSegments[i]
|
|
182
367
|
|
|
183
|
-
const
|
|
184
|
-
const
|
|
368
|
+
const isLastBaseSegment = i >= baseSegments.length - 1
|
|
369
|
+
const isLastRouteSegment = i >= routeSegments.length - 1
|
|
185
370
|
|
|
186
371
|
if (routeSegment) {
|
|
187
372
|
if (routeSegment.type === 'wildcard') {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
373
|
+
const _splat = decodeURI(
|
|
374
|
+
joinPaths(baseSegments.slice(i).map((d) => d.value)),
|
|
375
|
+
)
|
|
376
|
+
// TODO: Deprecate *
|
|
377
|
+
params['*'] = _splat
|
|
378
|
+
params['_splat'] = _splat
|
|
379
|
+
return true
|
|
193
380
|
}
|
|
194
381
|
|
|
195
382
|
if (routeSegment.type === 'pathname') {
|
|
@@ -216,21 +403,25 @@ export function matchByPath(
|
|
|
216
403
|
}
|
|
217
404
|
|
|
218
405
|
if (routeSegment.type === 'param') {
|
|
219
|
-
if (baseSegment
|
|
406
|
+
if (baseSegment.value === '/') {
|
|
220
407
|
return false
|
|
221
408
|
}
|
|
222
|
-
if (
|
|
223
|
-
params[routeSegment.value.substring(1)] =
|
|
409
|
+
if (baseSegment.value.charAt(0) !== '$') {
|
|
410
|
+
params[routeSegment.value.substring(1)] = decodeURIComponent(
|
|
411
|
+
baseSegment.value,
|
|
412
|
+
)
|
|
224
413
|
}
|
|
225
414
|
}
|
|
226
415
|
}
|
|
227
416
|
|
|
228
|
-
if (
|
|
229
|
-
|
|
417
|
+
if (!isLastBaseSegment && isLastRouteSegment) {
|
|
418
|
+
params['**'] = joinPaths(baseSegments.slice(i + 1).map((d) => d.value))
|
|
419
|
+
return !!matchLocation.fuzzy && routeSegment?.value !== '/'
|
|
230
420
|
}
|
|
231
421
|
}
|
|
422
|
+
|
|
232
423
|
return true
|
|
233
424
|
})()
|
|
234
425
|
|
|
235
|
-
return isMatch ?
|
|
426
|
+
return isMatch ? params : undefined
|
|
236
427
|
}
|
package/src/qss.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Program uses a modified version of the `qss` package:
|
|
3
|
+
* Copyright (c) Luke Edwards luke.edwards05@gmail.com, MIT License
|
|
4
|
+
* https://github.com/lukeed/qss/blob/master/license.md
|
|
5
|
+
*/
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Encodes an object into a query string.
|
|
9
|
+
* @param obj - The object to encode into a query string.
|
|
10
|
+
* @param [pfx] - An optional prefix to add before the query string.
|
|
11
|
+
* @returns The encoded query string.
|
|
12
|
+
* @example
|
|
13
|
+
* ```
|
|
14
|
+
* // Example input: encode({ token: 'foo', key: 'value' })
|
|
15
|
+
* // Expected output: "token=foo&key=value"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function encode(obj: any, pfx?: string) {
|
|
19
|
+
let k,
|
|
7
20
|
i,
|
|
8
21
|
tmp,
|
|
9
22
|
str = ''
|
|
@@ -25,28 +38,52 @@ export function encode(obj, pfx?: string) {
|
|
|
25
38
|
return (pfx || '') + str
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Converts a string value to its appropriate type (string, number, boolean).
|
|
43
|
+
* @param mix - The string value to convert.
|
|
44
|
+
* @returns The converted value.
|
|
45
|
+
* @example
|
|
46
|
+
* // Example input: toValue("123")
|
|
47
|
+
* // Expected output: 123
|
|
48
|
+
*/
|
|
49
|
+
function toValue(mix: any) {
|
|
29
50
|
if (!mix) return ''
|
|
30
|
-
|
|
51
|
+
const str = decodeURIComponent(mix)
|
|
31
52
|
if (str === 'false') return false
|
|
32
53
|
if (str === 'true') return true
|
|
33
|
-
|
|
34
|
-
return +str * 0 === 0 ? +str : str
|
|
54
|
+
return +str * 0 === 0 && +str + '' === str ? +str : str
|
|
35
55
|
}
|
|
36
56
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Decodes a query string into an object.
|
|
59
|
+
* @param str - The query string to decode.
|
|
60
|
+
* @param [pfx] - An optional prefix to filter out from the query string.
|
|
61
|
+
* @returns The decoded key-value pairs in an object format.
|
|
62
|
+
* @example
|
|
63
|
+
* // Example input: decode("token=foo&key=value")
|
|
64
|
+
* // Expected output: { "token": "foo", "key": "value" }
|
|
65
|
+
*/
|
|
66
|
+
export function decode(str: any, pfx?: string) {
|
|
67
|
+
let tmp, k
|
|
68
|
+
const out: any = {},
|
|
69
|
+
arr = (pfx ? str.substr(pfx.length) : str).split('&')
|
|
42
70
|
|
|
43
71
|
while ((tmp = arr.shift())) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
const equalIndex = tmp.indexOf('=')
|
|
73
|
+
if (equalIndex !== -1) {
|
|
74
|
+
k = tmp.slice(0, equalIndex)
|
|
75
|
+
k = decodeURIComponent(k)
|
|
76
|
+
const value = tmp.slice(equalIndex + 1)
|
|
77
|
+
if (out[k] !== void 0) {
|
|
78
|
+
// @ts-expect-error
|
|
79
|
+
out[k] = [].concat(out[k], toValue(value))
|
|
80
|
+
} else {
|
|
81
|
+
out[k] = toValue(value)
|
|
82
|
+
}
|
|
48
83
|
} else {
|
|
49
|
-
|
|
84
|
+
k = tmp
|
|
85
|
+
k = decodeURIComponent(k)
|
|
86
|
+
out[k] = ''
|
|
50
87
|
}
|
|
51
88
|
}
|
|
52
89
|
|
package/src/root.ts
ADDED