@tanstack/react-router 1.97.20 → 1.97.21
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/dist/cjs/Match.cjs +4 -5
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Matches.cjs +0 -10
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +3 -30
- package/dist/cjs/RouterProvider.cjs.map +1 -1
- package/dist/cjs/RouterProvider.d.cts +2 -2
- package/dist/cjs/Transitioner.cjs +2 -2
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/awaited.cjs +6 -6
- package/dist/cjs/awaited.cjs.map +1 -1
- package/dist/cjs/awaited.d.cts +1 -1
- package/dist/cjs/fileRoute.cjs.map +1 -1
- package/dist/cjs/fileRoute.d.cts +2 -3
- package/dist/cjs/index.cjs +136 -42
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +12 -26
- package/dist/cjs/link.cjs +8 -9
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/link.d.cts +2 -49
- package/dist/cjs/redirects.cjs.map +1 -1
- package/dist/cjs/redirects.d.cts +1 -1
- package/dist/cjs/route.cjs +14 -15
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +2 -149
- package/dist/cjs/routeInfo.d.cts +2 -3
- package/dist/cjs/router.cjs +51 -70
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +4 -19
- package/dist/cjs/routerContext.d.cts +1 -1
- package/dist/cjs/scroll-restoration.cjs +2 -2
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +1 -1
- package/dist/cjs/structuralSharing.d.cts +1 -4
- package/dist/cjs/typePrimitives.d.cts +1 -1
- package/dist/cjs/useLoaderData.cjs.map +1 -1
- package/dist/cjs/useLoaderData.d.cts +2 -1
- package/dist/cjs/useLoaderDeps.cjs.map +1 -1
- package/dist/cjs/useLoaderDeps.d.cts +2 -1
- package/dist/cjs/useMatch.cjs.map +1 -1
- package/dist/cjs/useMatch.d.cts +2 -1
- package/dist/cjs/useParams.cjs.map +1 -1
- package/dist/cjs/useParams.d.cts +2 -1
- package/dist/cjs/useRouteContext.cjs.map +1 -1
- package/dist/cjs/useRouteContext.d.cts +2 -1
- package/dist/cjs/useRouterState.cjs +2 -2
- package/dist/cjs/useRouterState.cjs.map +1 -1
- package/dist/cjs/useSearch.cjs.map +1 -1
- package/dist/cjs/useSearch.d.cts +2 -1
- package/dist/cjs/utils.cjs +0 -152
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -81
- package/dist/esm/Match.js +1 -2
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.d.ts +3 -30
- package/dist/esm/Matches.js +0 -10
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.d.ts +2 -2
- package/dist/esm/RouterProvider.js.map +1 -1
- package/dist/esm/Transitioner.js +1 -1
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/awaited.d.ts +1 -1
- package/dist/esm/awaited.js +1 -1
- package/dist/esm/awaited.js.map +1 -1
- package/dist/esm/fileRoute.d.ts +2 -3
- package/dist/esm/fileRoute.js.map +1 -1
- package/dist/esm/index.d.ts +12 -26
- package/dist/esm/index.js +5 -10
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/link.d.ts +2 -49
- package/dist/esm/link.js +2 -3
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/redirects.d.ts +1 -1
- package/dist/esm/redirects.js.map +1 -1
- package/dist/esm/route.d.ts +2 -149
- package/dist/esm/route.js +1 -2
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/routeInfo.d.ts +2 -3
- package/dist/esm/router.d.ts +4 -19
- package/dist/esm/router.js +1 -20
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/routerContext.d.ts +1 -1
- package/dist/esm/scroll-restoration.d.ts +1 -1
- package/dist/esm/scroll-restoration.js +1 -1
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/structuralSharing.d.ts +1 -4
- package/dist/esm/typePrimitives.d.ts +1 -1
- package/dist/esm/useLoaderData.d.ts +2 -1
- package/dist/esm/useLoaderData.js.map +1 -1
- package/dist/esm/useLoaderDeps.d.ts +2 -1
- package/dist/esm/useLoaderDeps.js.map +1 -1
- package/dist/esm/useMatch.d.ts +2 -1
- package/dist/esm/useMatch.js.map +1 -1
- package/dist/esm/useParams.d.ts +2 -1
- package/dist/esm/useParams.js.map +1 -1
- package/dist/esm/useRouteContext.d.ts +2 -1
- package/dist/esm/useRouteContext.js.map +1 -1
- package/dist/esm/useRouterState.js +1 -1
- package/dist/esm/useRouterState.js.map +1 -1
- package/dist/esm/useSearch.d.ts +2 -1
- package/dist/esm/useSearch.js.map +1 -1
- package/dist/esm/utils.d.ts +1 -81
- package/dist/esm/utils.js +0 -152
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -2
- package/src/Match.tsx +5 -2
- package/src/Matches.tsx +8 -101
- package/src/RouterProvider.tsx +4 -2
- package/src/Transitioner.tsx +1 -1
- package/src/awaited.tsx +2 -2
- package/src/fileRoute.ts +6 -3
- package/src/index.tsx +128 -128
- package/src/link.tsx +27 -155
- package/src/redirects.ts +1 -1
- package/src/route.ts +41 -315
- package/src/routeInfo.ts +7 -3
- package/src/router.ts +32 -52
- package/src/scroll-restoration.tsx +2 -3
- package/src/structuralSharing.ts +5 -7
- package/src/typePrimitives.ts +1 -1
- package/src/useLoaderData.tsx +2 -1
- package/src/useLoaderDeps.tsx +2 -1
- package/src/useMatch.tsx +2 -1
- package/src/useParams.tsx +2 -1
- package/src/useRouteContext.ts +2 -1
- package/src/useRouterState.tsx +1 -1
- package/src/useSearch.tsx +2 -1
- package/src/utils.ts +1 -405
- package/dist/cjs/defer.cjs +0 -25
- package/dist/cjs/defer.cjs.map +0 -1
- package/dist/cjs/defer.d.cts +0 -20
- package/dist/cjs/location.d.cts +0 -12
- package/dist/cjs/manifest.d.cts +0 -24
- package/dist/cjs/path.cjs +0 -289
- package/dist/cjs/path.cjs.map +0 -1
- package/dist/cjs/path.d.cts +0 -34
- package/dist/cjs/qss.cjs +0 -51
- package/dist/cjs/qss.cjs.map +0 -1
- package/dist/cjs/qss.d.cts +0 -27
- package/dist/cjs/root.cjs +0 -5
- package/dist/cjs/root.cjs.map +0 -1
- package/dist/cjs/root.d.cts +0 -2
- package/dist/cjs/searchMiddleware.cjs +0 -42
- package/dist/cjs/searchMiddleware.cjs.map +0 -1
- package/dist/cjs/searchMiddleware.d.cts +0 -5
- package/dist/cjs/searchParams.cjs +0 -61
- package/dist/cjs/searchParams.cjs.map +0 -1
- package/dist/cjs/searchParams.d.cts +0 -7
- package/dist/cjs/serializer.d.cts +0 -15
- package/dist/cjs/validators.d.cts +0 -51
- package/dist/esm/defer.d.ts +0 -20
- package/dist/esm/defer.js +0 -25
- package/dist/esm/defer.js.map +0 -1
- package/dist/esm/location.d.ts +0 -12
- package/dist/esm/manifest.d.ts +0 -24
- package/dist/esm/path.d.ts +0 -34
- package/dist/esm/path.js +0 -289
- package/dist/esm/path.js.map +0 -1
- package/dist/esm/qss.d.ts +0 -27
- package/dist/esm/qss.js +0 -51
- package/dist/esm/qss.js.map +0 -1
- package/dist/esm/root.d.ts +0 -2
- package/dist/esm/root.js +0 -5
- package/dist/esm/root.js.map +0 -1
- package/dist/esm/searchMiddleware.d.ts +0 -5
- package/dist/esm/searchMiddleware.js +0 -42
- package/dist/esm/searchMiddleware.js.map +0 -1
- package/dist/esm/searchParams.d.ts +0 -7
- package/dist/esm/searchParams.js +0 -61
- package/dist/esm/searchParams.js.map +0 -1
- package/dist/esm/serializer.d.ts +0 -15
- package/dist/esm/validators.d.ts +0 -51
- package/src/defer.ts +0 -52
- package/src/location.ts +0 -13
- package/src/manifest.ts +0 -32
- package/src/path.ts +0 -427
- package/src/qss.ts +0 -91
- package/src/root.ts +0 -2
- package/src/searchMiddleware.ts +0 -54
- package/src/searchParams.ts +0 -77
- package/src/serializer.ts +0 -24
- package/src/validators.ts +0 -121
package/src/path.ts
DELETED
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { last } from './utils'
|
|
2
|
-
import type { MatchLocation } from './RouterProvider'
|
|
3
|
-
import type { AnyPathParams } from './route'
|
|
4
|
-
|
|
5
|
-
export interface Segment {
|
|
6
|
-
type: 'pathname' | 'param' | 'wildcard'
|
|
7
|
-
value: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function joinPaths(paths: Array<string | undefined>) {
|
|
11
|
-
return cleanPath(
|
|
12
|
-
paths
|
|
13
|
-
.filter((val) => {
|
|
14
|
-
return val !== undefined
|
|
15
|
-
})
|
|
16
|
-
.join('/'),
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function cleanPath(path: string) {
|
|
21
|
-
// remove double slashes
|
|
22
|
-
return path.replace(/\/{2,}/g, '/')
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function trimPathLeft(path: string) {
|
|
26
|
-
return path === '/' ? path : path.replace(/^\/{1,}/, '')
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function trimPathRight(path: string) {
|
|
30
|
-
return path === '/' ? path : path.replace(/\/{1,}$/, '')
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function trimPath(path: string) {
|
|
34
|
-
return trimPathRight(trimPathLeft(path))
|
|
35
|
-
}
|
|
36
|
-
|
|
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)
|
|
102
|
-
|
|
103
|
-
let baseSegments = parsePathname(base)
|
|
104
|
-
const toSegments = parsePathname(to)
|
|
105
|
-
|
|
106
|
-
if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
|
|
107
|
-
baseSegments.pop()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
toSegments.forEach((toSegment, index) => {
|
|
111
|
-
if (toSegment.value === '/') {
|
|
112
|
-
if (!index) {
|
|
113
|
-
// Leading slash
|
|
114
|
-
baseSegments = [toSegment]
|
|
115
|
-
} else if (index === toSegments.length - 1) {
|
|
116
|
-
// Trailing Slash
|
|
117
|
-
baseSegments.push(toSegment)
|
|
118
|
-
} else {
|
|
119
|
-
// ignore inter-slashes
|
|
120
|
-
}
|
|
121
|
-
} else if (toSegment.value === '..') {
|
|
122
|
-
baseSegments.pop()
|
|
123
|
-
} else if (toSegment.value === '.') {
|
|
124
|
-
// ignore
|
|
125
|
-
} else {
|
|
126
|
-
baseSegments.push(toSegment)
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
|
|
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
|
-
}
|
|
139
|
-
|
|
140
|
-
const joined = joinPaths([basepath, ...baseSegments.map((d) => d.value)])
|
|
141
|
-
return cleanPath(joined)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function parsePathname(pathname?: string): Array<Segment> {
|
|
145
|
-
if (!pathname) {
|
|
146
|
-
return []
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
pathname = cleanPath(pathname)
|
|
150
|
-
|
|
151
|
-
const segments: Array<Segment> = []
|
|
152
|
-
|
|
153
|
-
if (pathname.slice(0, 1) === '/') {
|
|
154
|
-
pathname = pathname.substring(1)
|
|
155
|
-
segments.push({
|
|
156
|
-
type: 'pathname',
|
|
157
|
-
value: '/',
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (!pathname) {
|
|
162
|
-
return segments
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Remove empty segments and '.' segments
|
|
166
|
-
const split = pathname.split('/').filter(Boolean)
|
|
167
|
-
|
|
168
|
-
segments.push(
|
|
169
|
-
...split.map((part): Segment => {
|
|
170
|
-
if (part === '$' || part === '*') {
|
|
171
|
-
return {
|
|
172
|
-
type: 'wildcard',
|
|
173
|
-
value: part,
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (part.charAt(0) === '$') {
|
|
178
|
-
return {
|
|
179
|
-
type: 'param',
|
|
180
|
-
value: part,
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
type: 'pathname',
|
|
186
|
-
value: decodeURI(part),
|
|
187
|
-
}
|
|
188
|
-
}),
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
if (pathname.slice(-1) === '/') {
|
|
192
|
-
pathname = pathname.substring(1)
|
|
193
|
-
segments.push({
|
|
194
|
-
type: 'pathname',
|
|
195
|
-
value: '/',
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return segments
|
|
200
|
-
}
|
|
201
|
-
|
|
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) {
|
|
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
|
-
}
|
|
233
|
-
|
|
234
|
-
return joinPaths(
|
|
235
|
-
interpolatedPathSegments.map((segment) => {
|
|
236
|
-
if (segment.type === 'wildcard') {
|
|
237
|
-
const value = encodedParams._splat
|
|
238
|
-
if (leaveWildcards) return `${segment.value}${value ?? ''}`
|
|
239
|
-
return value
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (segment.type === 'param') {
|
|
243
|
-
if (leaveParams) {
|
|
244
|
-
const value = encodedParams[segment.value]
|
|
245
|
-
return `${segment.value}${value ?? ''}`
|
|
246
|
-
}
|
|
247
|
-
return encodedParams![segment.value.substring(1)] ?? 'undefined'
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return segment.value
|
|
251
|
-
}),
|
|
252
|
-
)
|
|
253
|
-
}
|
|
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
|
-
|
|
265
|
-
export function matchPathname(
|
|
266
|
-
basepath: string,
|
|
267
|
-
currentPathname: string,
|
|
268
|
-
matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>,
|
|
269
|
-
): AnyPathParams | undefined {
|
|
270
|
-
const pathParams = matchByPath(basepath, currentPathname, matchLocation)
|
|
271
|
-
// const searchMatched = matchBySearch(location.search, matchLocation)
|
|
272
|
-
|
|
273
|
-
if (matchLocation.to && !pathParams) {
|
|
274
|
-
return
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return pathParams ?? {}
|
|
278
|
-
}
|
|
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
|
-
|
|
321
|
-
export function matchByPath(
|
|
322
|
-
basepath: string,
|
|
323
|
-
from: string,
|
|
324
|
-
matchLocation: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,
|
|
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
|
|
340
|
-
const baseSegments = parsePathname(from)
|
|
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
|
-
}
|
|
356
|
-
|
|
357
|
-
const params: Record<string, string> = {}
|
|
358
|
-
|
|
359
|
-
const isMatch = (() => {
|
|
360
|
-
for (
|
|
361
|
-
let i = 0;
|
|
362
|
-
i < Math.max(baseSegments.length, routeSegments.length);
|
|
363
|
-
i++
|
|
364
|
-
) {
|
|
365
|
-
const baseSegment = baseSegments[i]
|
|
366
|
-
const routeSegment = routeSegments[i]
|
|
367
|
-
|
|
368
|
-
const isLastBaseSegment = i >= baseSegments.length - 1
|
|
369
|
-
const isLastRouteSegment = i >= routeSegments.length - 1
|
|
370
|
-
|
|
371
|
-
if (routeSegment) {
|
|
372
|
-
if (routeSegment.type === 'wildcard') {
|
|
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
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (routeSegment.type === 'pathname') {
|
|
383
|
-
if (routeSegment.value === '/' && !baseSegment?.value) {
|
|
384
|
-
return true
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (baseSegment) {
|
|
388
|
-
if (matchLocation.caseSensitive) {
|
|
389
|
-
if (routeSegment.value !== baseSegment.value) {
|
|
390
|
-
return false
|
|
391
|
-
}
|
|
392
|
-
} else if (
|
|
393
|
-
routeSegment.value.toLowerCase() !==
|
|
394
|
-
baseSegment.value.toLowerCase()
|
|
395
|
-
) {
|
|
396
|
-
return false
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (!baseSegment) {
|
|
402
|
-
return false
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (routeSegment.type === 'param') {
|
|
406
|
-
if (baseSegment.value === '/') {
|
|
407
|
-
return false
|
|
408
|
-
}
|
|
409
|
-
if (baseSegment.value.charAt(0) !== '$') {
|
|
410
|
-
params[routeSegment.value.substring(1)] = decodeURIComponent(
|
|
411
|
-
baseSegment.value,
|
|
412
|
-
)
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (!isLastBaseSegment && isLastRouteSegment) {
|
|
418
|
-
params['**'] = joinPaths(baseSegments.slice(i + 1).map((d) => d.value))
|
|
419
|
-
return !!matchLocation.fuzzy && routeSegment?.value !== '/'
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return true
|
|
424
|
-
})()
|
|
425
|
-
|
|
426
|
-
return isMatch ? params : undefined
|
|
427
|
-
}
|
package/src/qss.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
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
|
-
*/
|
|
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,
|
|
20
|
-
i,
|
|
21
|
-
tmp,
|
|
22
|
-
str = ''
|
|
23
|
-
|
|
24
|
-
for (k in obj) {
|
|
25
|
-
if ((tmp = obj[k]) !== void 0) {
|
|
26
|
-
if (Array.isArray(tmp)) {
|
|
27
|
-
for (i = 0; i < tmp.length; i++) {
|
|
28
|
-
str && (str += '&')
|
|
29
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i])
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
str && (str += '&')
|
|
33
|
-
str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return (pfx || '') + str
|
|
39
|
-
}
|
|
40
|
-
|
|
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) {
|
|
50
|
-
if (!mix) return ''
|
|
51
|
-
const str = decodeURIComponent(mix)
|
|
52
|
-
if (str === 'false') return false
|
|
53
|
-
if (str === 'true') return true
|
|
54
|
-
return +str * 0 === 0 && +str + '' === str ? +str : str
|
|
55
|
-
}
|
|
56
|
-
|
|
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('&')
|
|
70
|
-
|
|
71
|
-
while ((tmp = arr.shift())) {
|
|
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
|
-
}
|
|
83
|
-
} else {
|
|
84
|
-
k = tmp
|
|
85
|
-
k = decodeURIComponent(k)
|
|
86
|
-
out[k] = ''
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return out
|
|
91
|
-
}
|
package/src/root.ts
DELETED
package/src/searchMiddleware.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { deepEqual } from './utils'
|
|
2
|
-
import type { NoInfer, PickOptional } from './utils'
|
|
3
|
-
import type { SearchMiddleware } from './route'
|
|
4
|
-
import type { IsRequiredParams } from './link'
|
|
5
|
-
|
|
6
|
-
export function retainSearchParams<TSearchSchema extends object>(
|
|
7
|
-
keys: Array<keyof TSearchSchema> | true,
|
|
8
|
-
): SearchMiddleware<TSearchSchema> {
|
|
9
|
-
return ({ search, next }) => {
|
|
10
|
-
const result = next(search)
|
|
11
|
-
if (keys === true) {
|
|
12
|
-
return { ...search, ...result }
|
|
13
|
-
}
|
|
14
|
-
// add missing keys from search to result
|
|
15
|
-
keys.forEach((key) => {
|
|
16
|
-
if (!(key in result)) {
|
|
17
|
-
result[key] = search[key]
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
return result
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function stripSearchParams<
|
|
25
|
-
TSearchSchema,
|
|
26
|
-
TOptionalProps = PickOptional<NoInfer<TSearchSchema>>,
|
|
27
|
-
const TValues =
|
|
28
|
-
| Partial<NoInfer<TOptionalProps>>
|
|
29
|
-
| Array<keyof TOptionalProps>,
|
|
30
|
-
const TInput = IsRequiredParams<TSearchSchema> extends never
|
|
31
|
-
? TValues | true
|
|
32
|
-
: TValues,
|
|
33
|
-
>(input: NoInfer<TInput>): SearchMiddleware<TSearchSchema> {
|
|
34
|
-
return ({ search, next }) => {
|
|
35
|
-
if (input === true) {
|
|
36
|
-
return {}
|
|
37
|
-
}
|
|
38
|
-
const result = next(search) as Record<string, unknown>
|
|
39
|
-
if (Array.isArray(input)) {
|
|
40
|
-
input.forEach((key) => {
|
|
41
|
-
delete result[key]
|
|
42
|
-
})
|
|
43
|
-
} else {
|
|
44
|
-
Object.entries(input as Record<string, unknown>).forEach(
|
|
45
|
-
([key, value]) => {
|
|
46
|
-
if (deepEqual(result[key], value)) {
|
|
47
|
-
delete result[key]
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
return result as any
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/searchParams.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { decode, encode } from './qss'
|
|
2
|
-
import type { AnySchema } from './validators'
|
|
3
|
-
|
|
4
|
-
export const defaultParseSearch = parseSearchWith(JSON.parse)
|
|
5
|
-
export const defaultStringifySearch = stringifySearchWith(
|
|
6
|
-
JSON.stringify,
|
|
7
|
-
JSON.parse,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
export function parseSearchWith(parser: (str: string) => any) {
|
|
11
|
-
return (searchStr: string): AnySchema => {
|
|
12
|
-
if (searchStr.substring(0, 1) === '?') {
|
|
13
|
-
searchStr = searchStr.substring(1)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const query: Record<string, unknown> = decode(searchStr)
|
|
17
|
-
|
|
18
|
-
// Try to parse any query params that might be json
|
|
19
|
-
for (const key in query) {
|
|
20
|
-
const value = query[key]
|
|
21
|
-
if (typeof value === 'string') {
|
|
22
|
-
try {
|
|
23
|
-
query[key] = parser(value)
|
|
24
|
-
} catch (err) {
|
|
25
|
-
//
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return query
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function stringifySearchWith(
|
|
35
|
-
stringify: (search: any) => string,
|
|
36
|
-
parser?: (str: string) => any,
|
|
37
|
-
) {
|
|
38
|
-
function stringifyValue(val: any) {
|
|
39
|
-
if (typeof val === 'object' && val !== null) {
|
|
40
|
-
try {
|
|
41
|
-
return stringify(val)
|
|
42
|
-
} catch (err) {
|
|
43
|
-
// silent
|
|
44
|
-
}
|
|
45
|
-
} else if (typeof val === 'string' && typeof parser === 'function') {
|
|
46
|
-
try {
|
|
47
|
-
// Check if it's a valid parseable string.
|
|
48
|
-
// If it is, then stringify it again.
|
|
49
|
-
parser(val)
|
|
50
|
-
return stringify(val)
|
|
51
|
-
} catch (err) {
|
|
52
|
-
// silent
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return val
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return (search: Record<string, any>) => {
|
|
59
|
-
search = { ...search }
|
|
60
|
-
|
|
61
|
-
Object.keys(search).forEach((key) => {
|
|
62
|
-
const val = search[key]
|
|
63
|
-
if (typeof val === 'undefined' || val === undefined) {
|
|
64
|
-
delete search[key]
|
|
65
|
-
} else {
|
|
66
|
-
search[key] = stringifyValue(val)
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const searchStr = encode(search as Record<string, string>).toString()
|
|
71
|
-
|
|
72
|
-
return searchStr ? `?${searchStr}` : ''
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export type SearchSerializer = (searchObj: Record<string, any>) => string
|
|
77
|
-
export type SearchParser = (searchStr: string) => Record<string, any>
|
package/src/serializer.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface StartSerializer {
|
|
2
|
-
stringify: (obj: unknown) => string
|
|
3
|
-
parse: (str: string) => unknown
|
|
4
|
-
encode: <T>(value: T) => T
|
|
5
|
-
decode: <T>(value: T) => T
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type SerializerStringifyBy<T, TSerializable> = T extends TSerializable
|
|
9
|
-
? T
|
|
10
|
-
: T extends (...args: Array<any>) => any
|
|
11
|
-
? 'Function is not serializable'
|
|
12
|
-
: { [K in keyof T]: SerializerStringifyBy<T[K], TSerializable> }
|
|
13
|
-
|
|
14
|
-
export type SerializerParseBy<T, TSerializable> = T extends TSerializable
|
|
15
|
-
? T
|
|
16
|
-
: T extends React.JSX.Element
|
|
17
|
-
? ReadableStream
|
|
18
|
-
: { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }
|
|
19
|
-
|
|
20
|
-
export type Serializable = Date | undefined | Error | FormData
|
|
21
|
-
|
|
22
|
-
export type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>
|
|
23
|
-
|
|
24
|
-
export type SerializerParse<T> = SerializerParseBy<T, Serializable>
|