@tanstack/router-core 1.171.24 → 1.171.26
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/load-client.cjs +299 -389
- package/dist/cjs/load-client.cjs.map +1 -1
- package/dist/cjs/load-client.d.cts +18 -18
- package/dist/cjs/load-server.cjs +45 -32
- package/dist/cjs/load-server.cjs.map +1 -1
- package/dist/cjs/new-process-route-tree.cjs +1 -1
- package/dist/cjs/new-process-route-tree.cjs.map +1 -1
- package/dist/cjs/path.cjs +10 -4
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/redirect.cjs +1 -1
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +1 -1
- package/dist/cjs/router.cjs +34 -30
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +3 -5
- package/dist/esm/load-client.d.ts +18 -18
- package/dist/esm/load-client.js +299 -389
- package/dist/esm/load-client.js.map +1 -1
- package/dist/esm/load-server.js +45 -32
- package/dist/esm/load-server.js.map +1 -1
- package/dist/esm/new-process-route-tree.js +1 -1
- package/dist/esm/new-process-route-tree.js.map +1 -1
- package/dist/esm/path.js +10 -4
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/redirect.d.ts +1 -1
- package/dist/esm/redirect.js +1 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/router.d.ts +3 -5
- package/dist/esm/router.js +35 -31
- package/dist/esm/router.js.map +1 -1
- package/package.json +8 -2
- package/src/load-client.ts +535 -659
- package/src/load-server.ts +97 -35
- package/src/new-process-route-tree.ts +1 -1
- package/src/path.ts +20 -6
- package/src/redirect.ts +2 -18
- package/src/router.ts +54 -78
package/src/load-server.ts
CHANGED
|
@@ -82,17 +82,51 @@ function normalize(value: unknown, rejected: boolean): LoaderOutcome {
|
|
|
82
82
|
return rejected ? [ERROR, value] : [SUCCESS, value]
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function normalizeError(
|
|
85
|
+
function normalizeError(
|
|
86
|
+
router: AnyRouter,
|
|
87
|
+
lane: { location: ParsedLocation },
|
|
88
|
+
route: AnyRoute,
|
|
89
|
+
cause: unknown,
|
|
90
|
+
signal?: AbortSignal,
|
|
91
|
+
notify = true,
|
|
92
|
+
): LoaderOutcome {
|
|
93
|
+
signal?.throwIfAborted()
|
|
86
94
|
let outcome = normalize(cause, true)
|
|
87
95
|
if (outcome[0] !== ERROR) {
|
|
88
|
-
return outcome
|
|
96
|
+
return materializeRedirect(router, lane, route, outcome, signal, notify)
|
|
89
97
|
}
|
|
90
98
|
try {
|
|
91
99
|
route.options.onError?.(outcome[1])
|
|
92
100
|
} catch (onErrorCause) {
|
|
93
101
|
outcome = normalize(onErrorCause, true)
|
|
94
102
|
}
|
|
95
|
-
|
|
103
|
+
signal?.throwIfAborted()
|
|
104
|
+
return materializeRedirect(router, lane, route, outcome, signal, notify)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function materializeRedirect(
|
|
108
|
+
router: AnyRouter,
|
|
109
|
+
lane: { location: ParsedLocation },
|
|
110
|
+
route: AnyRoute,
|
|
111
|
+
outcome: LoaderOutcome,
|
|
112
|
+
signal?: AbortSignal,
|
|
113
|
+
notify = true,
|
|
114
|
+
): LoaderOutcome {
|
|
115
|
+
if (outcome[0] !== REDIRECTED) {
|
|
116
|
+
return outcome
|
|
117
|
+
}
|
|
118
|
+
signal?.throwIfAborted()
|
|
119
|
+
try {
|
|
120
|
+
outcome[1].options._fromLocation = lane.location
|
|
121
|
+
router.resolveRedirect(outcome[1])
|
|
122
|
+
signal?.throwIfAborted()
|
|
123
|
+
return outcome
|
|
124
|
+
} catch (cause) {
|
|
125
|
+
signal?.throwIfAborted()
|
|
126
|
+
return notify
|
|
127
|
+
? normalizeError(router, lane, route, cause, signal, false)
|
|
128
|
+
: [ERROR, cause]
|
|
129
|
+
}
|
|
96
130
|
}
|
|
97
131
|
|
|
98
132
|
function maybe<TValue>(
|
|
@@ -197,7 +231,13 @@ async function contextualize(
|
|
|
197
231
|
match.ssr = await resolveSsr(router, lane, index)
|
|
198
232
|
} catch (cause) {
|
|
199
233
|
signal?.throwIfAborted()
|
|
200
|
-
failure = [
|
|
234
|
+
failure = [
|
|
235
|
+
index,
|
|
236
|
+
stampNotFound(
|
|
237
|
+
match,
|
|
238
|
+
normalizeError(router, lane, route, cause, signal),
|
|
239
|
+
),
|
|
240
|
+
]
|
|
201
241
|
end = index
|
|
202
242
|
}
|
|
203
243
|
signal?.throwIfAborted()
|
|
@@ -239,7 +279,13 @@ async function contextualize(
|
|
|
239
279
|
} catch (cause) {
|
|
240
280
|
signal?.throwIfAborted()
|
|
241
281
|
if (!failure) {
|
|
242
|
-
failure = [
|
|
282
|
+
failure = [
|
|
283
|
+
index,
|
|
284
|
+
stampNotFound(
|
|
285
|
+
match,
|
|
286
|
+
normalizeError(router, lane, route, cause, signal),
|
|
287
|
+
),
|
|
288
|
+
]
|
|
243
289
|
}
|
|
244
290
|
end = index
|
|
245
291
|
break
|
|
@@ -252,7 +298,10 @@ async function contextualize(
|
|
|
252
298
|
if (validationError !== undefined) {
|
|
253
299
|
failure = [
|
|
254
300
|
index,
|
|
255
|
-
stampNotFound(
|
|
301
|
+
stampNotFound(
|
|
302
|
+
match,
|
|
303
|
+
normalizeError(router, lane, route, validationError, signal),
|
|
304
|
+
),
|
|
256
305
|
]
|
|
257
306
|
end = index
|
|
258
307
|
break
|
|
@@ -293,7 +342,16 @@ async function contextualize(
|
|
|
293
342
|
try {
|
|
294
343
|
const beforeLoadContext = await route.options.beforeLoad(options)
|
|
295
344
|
signal?.throwIfAborted()
|
|
296
|
-
const outcome = stampNotFound(
|
|
345
|
+
const outcome = stampNotFound(
|
|
346
|
+
match,
|
|
347
|
+
materializeRedirect(
|
|
348
|
+
router,
|
|
349
|
+
lane,
|
|
350
|
+
route,
|
|
351
|
+
normalize(beforeLoadContext, false),
|
|
352
|
+
signal,
|
|
353
|
+
),
|
|
354
|
+
)
|
|
297
355
|
if (outcome[0] !== SUCCESS) {
|
|
298
356
|
failure = [index, outcome]
|
|
299
357
|
end = index
|
|
@@ -307,7 +365,13 @@ async function contextualize(
|
|
|
307
365
|
parentContext = match.context
|
|
308
366
|
} catch (cause) {
|
|
309
367
|
signal?.throwIfAborted()
|
|
310
|
-
failure = [
|
|
368
|
+
failure = [
|
|
369
|
+
index,
|
|
370
|
+
stampNotFound(
|
|
371
|
+
match,
|
|
372
|
+
normalizeError(router, lane, route, cause, signal),
|
|
373
|
+
),
|
|
374
|
+
]
|
|
311
375
|
end = index
|
|
312
376
|
break
|
|
313
377
|
}
|
|
@@ -373,14 +437,13 @@ function createLoaderTask(
|
|
|
373
437
|
(cause) => normalize(cause, true),
|
|
374
438
|
)
|
|
375
439
|
.then((result): LoaderOutcome => {
|
|
376
|
-
if (
|
|
377
|
-
result[0] !== REDIRECTED &&
|
|
378
|
-
(signal?.aborted || match.abortController.signal.reason === lane)
|
|
379
|
-
) {
|
|
440
|
+
if (signal?.aborted || match.abortController.signal.reason === lane) {
|
|
380
441
|
return [SKIPPED]
|
|
381
442
|
}
|
|
382
443
|
if (result[0] === ERROR) {
|
|
383
|
-
result = normalizeError(route, result[1])
|
|
444
|
+
result = normalizeError(router, lane, route, result[1], signal)
|
|
445
|
+
} else {
|
|
446
|
+
result = materializeRedirect(router, lane, route, result, signal)
|
|
384
447
|
}
|
|
385
448
|
return stampNotFound(match, result)
|
|
386
449
|
})
|
|
@@ -424,13 +487,13 @@ async function getNotFoundBoundary(
|
|
|
424
487
|
}
|
|
425
488
|
for (let candidate = index; candidate >= 0; candidate--) {
|
|
426
489
|
const route = getRoute(router, matches[candidate]!)
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
490
|
+
try {
|
|
491
|
+
const loading = loadRouteChunk(route, false)
|
|
492
|
+
if (loading) {
|
|
430
493
|
await loading
|
|
431
|
-
} catch {
|
|
432
|
-
signal?.throwIfAborted()
|
|
433
494
|
}
|
|
495
|
+
} catch {
|
|
496
|
+
signal?.throwIfAborted()
|
|
434
497
|
}
|
|
435
498
|
signal?.throwIfAborted()
|
|
436
499
|
if (route.options.notFoundComponent) {
|
|
@@ -450,15 +513,6 @@ function abortMatches(
|
|
|
450
513
|
}
|
|
451
514
|
}
|
|
452
515
|
|
|
453
|
-
function resolveServerRedirect(
|
|
454
|
-
router: AnyRouter,
|
|
455
|
-
location: ParsedLocation,
|
|
456
|
-
value: AnyRedirect,
|
|
457
|
-
): ServerLoadResult {
|
|
458
|
-
value.options._fromLocation = location
|
|
459
|
-
return { type: 'redirect', redirect: router.resolveRedirect(value) }
|
|
460
|
-
}
|
|
461
|
-
|
|
462
516
|
async function applyFailure(
|
|
463
517
|
router: AnyRouter,
|
|
464
518
|
lane: ContextualizedLane,
|
|
@@ -530,7 +584,10 @@ async function loadNormalChunks(
|
|
|
530
584
|
signal?.throwIfAborted()
|
|
531
585
|
return [
|
|
532
586
|
index,
|
|
533
|
-
stampNotFound(
|
|
587
|
+
stampNotFound(
|
|
588
|
+
match,
|
|
589
|
+
normalizeError(router, lane, route, cause, signal),
|
|
590
|
+
),
|
|
534
591
|
] as IndexedOutcome
|
|
535
592
|
},
|
|
536
593
|
)
|
|
@@ -540,7 +597,13 @@ async function loadNormalChunks(
|
|
|
540
597
|
}
|
|
541
598
|
} catch (cause) {
|
|
542
599
|
signal?.throwIfAborted()
|
|
543
|
-
chunks.push([
|
|
600
|
+
chunks.push([
|
|
601
|
+
index,
|
|
602
|
+
stampNotFound(
|
|
603
|
+
match,
|
|
604
|
+
normalizeError(router, lane, route, cause, signal),
|
|
605
|
+
),
|
|
606
|
+
])
|
|
544
607
|
}
|
|
545
608
|
}
|
|
546
609
|
for (const chunk of chunks) {
|
|
@@ -698,7 +761,7 @@ async function executeServerLane(
|
|
|
698
761
|
|
|
699
762
|
if (control?.[1][0] === REDIRECTED) {
|
|
700
763
|
abortMatches(lane.matches, 0, lane)
|
|
701
|
-
return
|
|
764
|
+
return { type: 'redirect', redirect: control[1][1] }
|
|
702
765
|
}
|
|
703
766
|
|
|
704
767
|
let failure = lane.failure ?? loaderFailure
|
|
@@ -742,7 +805,7 @@ async function executeServerLane(
|
|
|
742
805
|
if (requiredFailure) {
|
|
743
806
|
if (requiredFailure[1][0] === REDIRECTED) {
|
|
744
807
|
abortMatches(lane.matches)
|
|
745
|
-
return
|
|
808
|
+
return { type: 'redirect', redirect: requiredFailure[1][1] }
|
|
746
809
|
}
|
|
747
810
|
failure = requiredFailure
|
|
748
811
|
}
|
|
@@ -808,9 +871,7 @@ export async function loadServerRoute(
|
|
|
808
871
|
})
|
|
809
872
|
if (next.publicHref !== canonical.publicHref) {
|
|
810
873
|
const href = canonical.publicHref || '/'
|
|
811
|
-
throw
|
|
812
|
-
? redirect({ href })
|
|
813
|
-
: redirect({ href, _builtLocation: canonical })
|
|
874
|
+
throw redirect({ href })
|
|
814
875
|
}
|
|
815
876
|
|
|
816
877
|
const fromLocation = router.stores.resolvedLocation.get()
|
|
@@ -828,7 +889,8 @@ export async function loadServerRoute(
|
|
|
828
889
|
if (!isRedirect(cause)) {
|
|
829
890
|
throw cause
|
|
830
891
|
}
|
|
831
|
-
|
|
892
|
+
cause.options._fromLocation = next
|
|
893
|
+
result = { type: 'redirect', redirect: router.resolveRedirect(cause) }
|
|
832
894
|
}
|
|
833
895
|
|
|
834
896
|
router._serverResult = result
|
|
@@ -582,7 +582,7 @@ export function findFlatMatch<T extends Extract<RouteLike, { from: string }>>(
|
|
|
582
582
|
) {
|
|
583
583
|
path ||= '/'
|
|
584
584
|
const cached = processedTree.flatCache!.get(path)
|
|
585
|
-
if (cached) return cached
|
|
585
|
+
if (cached !== undefined) return cached
|
|
586
586
|
const result = findMatch(path, processedTree.masksTree!)
|
|
587
587
|
processedTree.flatCache!.set(path, result)
|
|
588
588
|
return result
|
package/src/path.ts
CHANGED
|
@@ -112,13 +112,25 @@ export function resolvePath({
|
|
|
112
112
|
trailingSlash = 'never',
|
|
113
113
|
cache,
|
|
114
114
|
}: ResolvePathOptions) {
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
if (to.includes('//')) {
|
|
116
|
+
to = cleanPath(to)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (to.startsWith('/')) {
|
|
120
|
+
if (to.length === 1 || trailingSlash === 'preserve') {
|
|
121
|
+
return to
|
|
122
|
+
}
|
|
123
|
+
if (trailingSlash === 'always') {
|
|
124
|
+
return to.endsWith('/') ? to : `${to}/`
|
|
125
|
+
}
|
|
126
|
+
return to.endsWith('/') ? to.slice(0, -1) : to
|
|
127
|
+
}
|
|
117
128
|
|
|
129
|
+
const isBase = to === '.'
|
|
118
130
|
let key
|
|
119
131
|
if (cache) {
|
|
120
132
|
// `trailingSlash` is static per router, so it doesn't need to be part of the cache key
|
|
121
|
-
key =
|
|
133
|
+
key = isBase ? base : base + '\0' + to
|
|
122
134
|
const cached = cache.get(key)
|
|
123
135
|
if (cached) return cached
|
|
124
136
|
}
|
|
@@ -126,9 +138,10 @@ export function resolvePath({
|
|
|
126
138
|
let baseSegments: Array<string>
|
|
127
139
|
if (isBase) {
|
|
128
140
|
baseSegments = base.split('/')
|
|
129
|
-
} else if (isAbsolute) {
|
|
130
|
-
baseSegments = to.split('/')
|
|
131
141
|
} else {
|
|
142
|
+
if (base.includes('//')) {
|
|
143
|
+
base = cleanPath(base)
|
|
144
|
+
}
|
|
132
145
|
baseSegments = base.split('/')
|
|
133
146
|
while (baseSegments.length > 1 && last(baseSegments) === '') {
|
|
134
147
|
baseSegments.pop()
|
|
@@ -171,7 +184,8 @@ export function resolvePath({
|
|
|
171
184
|
}
|
|
172
185
|
}
|
|
173
186
|
|
|
174
|
-
const
|
|
187
|
+
const joined = baseSegments.join('/')
|
|
188
|
+
const result = (isBase ? cleanPath(joined) : joined) || '/'
|
|
175
189
|
if (key && cache) cache.set(key, result)
|
|
176
190
|
return result
|
|
177
191
|
}
|
package/src/redirect.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { NavigateOptions } from './link'
|
|
2
2
|
import type { AnyRouter, RegisteredRouter } from './router'
|
|
3
|
-
import type { ParsedLocation } from './location'
|
|
4
3
|
|
|
5
4
|
export type AnyRedirect = Redirect<any, any, any, any, any>
|
|
6
5
|
|
|
@@ -14,13 +13,7 @@ export type Redirect<
|
|
|
14
13
|
TMaskFrom extends string = TFrom,
|
|
15
14
|
TMaskTo extends string = '.',
|
|
16
15
|
> = Response & {
|
|
17
|
-
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
18
|
-
/**
|
|
19
|
-
* @internal
|
|
20
|
-
* A **trusted** built location that can be used to redirect to.
|
|
21
|
-
*/
|
|
22
|
-
_builtLocation?: ParsedLocation
|
|
23
|
-
}
|
|
16
|
+
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
24
17
|
}
|
|
25
18
|
|
|
26
19
|
export type RedirectOptions<
|
|
@@ -50,11 +43,6 @@ export type RedirectOptions<
|
|
|
50
43
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RedirectType#headers-property)
|
|
51
44
|
*/
|
|
52
45
|
headers?: HeadersInit
|
|
53
|
-
/**
|
|
54
|
-
* @internal
|
|
55
|
-
* A **trusted** built location that can be used to redirect to.
|
|
56
|
-
*/
|
|
57
|
-
_builtLocation?: ParsedLocation
|
|
58
46
|
} & NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
59
47
|
|
|
60
48
|
export type ResolvedRedirect<
|
|
@@ -122,11 +110,7 @@ export function redirect<
|
|
|
122
110
|
): Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> {
|
|
123
111
|
opts.statusCode = opts.statusCode || opts.code || 307
|
|
124
112
|
|
|
125
|
-
if (
|
|
126
|
-
!opts._builtLocation &&
|
|
127
|
-
!opts.reloadDocument &&
|
|
128
|
-
typeof opts.href === 'string'
|
|
129
|
-
) {
|
|
113
|
+
if (!opts.reloadDocument && typeof opts.href === 'string') {
|
|
130
114
|
try {
|
|
131
115
|
new URL(opts.href)
|
|
132
116
|
opts.reloadDocument = true
|
package/src/router.ts
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
processRouteTree,
|
|
23
23
|
} from './new-process-route-tree'
|
|
24
24
|
import {
|
|
25
|
-
cleanPath,
|
|
26
25
|
compileDecodeCharMap,
|
|
27
26
|
interpolatePath,
|
|
28
27
|
resolvePath,
|
|
@@ -692,13 +691,7 @@ export type PreloadRouteFn<
|
|
|
692
691
|
TTo,
|
|
693
692
|
TMaskFrom,
|
|
694
693
|
TMaskTo
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* @internal
|
|
698
|
-
* A **trusted** built location that can be used to redirect to.
|
|
699
|
-
*/
|
|
700
|
-
_builtLocation?: ParsedLocation
|
|
701
|
-
},
|
|
694
|
+
>,
|
|
702
695
|
) => Promise<Array<AnyRouteMatch> | undefined>
|
|
703
696
|
|
|
704
697
|
export type MatchRouteFn<
|
|
@@ -937,10 +930,10 @@ export function runRouteLifecycle(
|
|
|
937
930
|
router: AnyRouter,
|
|
938
931
|
previous: Array<AnyRouteMatch>,
|
|
939
932
|
matches: Array<AnyRouteMatch>,
|
|
940
|
-
|
|
933
|
+
owner?: LoadTransaction,
|
|
941
934
|
): void {
|
|
942
935
|
for (const match of previous) {
|
|
943
|
-
if (
|
|
936
|
+
if (owner && router._tx !== owner) {
|
|
944
937
|
return
|
|
945
938
|
}
|
|
946
939
|
if (!matches.some((candidate) => candidate.routeId === match.routeId)) {
|
|
@@ -950,7 +943,7 @@ export function runRouteLifecycle(
|
|
|
950
943
|
}
|
|
951
944
|
}
|
|
952
945
|
for (const match of matches) {
|
|
953
|
-
if (
|
|
946
|
+
if (owner && router._tx !== owner) {
|
|
954
947
|
return
|
|
955
948
|
}
|
|
956
949
|
const route = (router.routesById as Record<string, AnyRoute>)[
|
|
@@ -1475,7 +1468,7 @@ export class RouterCore<
|
|
|
1475
1468
|
resolvePathWithBase = (from: string, path: string) => {
|
|
1476
1469
|
return resolvePath({
|
|
1477
1470
|
base: from,
|
|
1478
|
-
to: path
|
|
1471
|
+
to: path,
|
|
1479
1472
|
trailingSlash: this.options.trailingSlash,
|
|
1480
1473
|
cache: this.resolvePathCache,
|
|
1481
1474
|
})
|
|
@@ -1846,6 +1839,19 @@ export class RouterCore<
|
|
|
1846
1839
|
unmaskOnReload?: boolean
|
|
1847
1840
|
} = {},
|
|
1848
1841
|
): ParsedLocation => {
|
|
1842
|
+
if (dest.href) {
|
|
1843
|
+
const parsed = parseHref(dest.href, {} as ParsedHistoryState)
|
|
1844
|
+
dest = {
|
|
1845
|
+
...dest,
|
|
1846
|
+
to: executeRewriteInput(
|
|
1847
|
+
this.rewrite,
|
|
1848
|
+
new URL(parsed.pathname, this.origin),
|
|
1849
|
+
).pathname,
|
|
1850
|
+
search: this.options.parseSearch(parsed.search),
|
|
1851
|
+
hash: parsed.hash.slice(1),
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1849
1855
|
// We allow the caller to override the current location
|
|
1850
1856
|
const currentLocation =
|
|
1851
1857
|
dest._fromLocation || this._pendingLocation || this.latestLocation
|
|
@@ -1885,28 +1891,19 @@ export class RouterCore<
|
|
|
1885
1891
|
dest.unsafeRelative === 'path'
|
|
1886
1892
|
? currentLocation.pathname
|
|
1887
1893
|
: (dest.from ?? lightweightResult[1 /* fullPath */])
|
|
1888
|
-
const destTo = dest.to ? `${dest.to}` : undefined
|
|
1889
1894
|
|
|
1890
1895
|
// From search should always use the current location
|
|
1891
1896
|
const fromSearch = lightweightResult[2 /* search */]
|
|
1892
1897
|
// Same with params. It can't hurt to provide as many as possible
|
|
1893
|
-
const fromParams =
|
|
1894
|
-
Object.create(null),
|
|
1895
|
-
lightweightResult[3 /* params */],
|
|
1896
|
-
)
|
|
1897
|
-
|
|
1898
|
-
const isAbsoluteTo = destTo?.charCodeAt(0) === 47
|
|
1899
|
-
const sourcePath = isAbsoluteTo
|
|
1900
|
-
? '/'
|
|
1901
|
-
: this.resolvePathWithBase(defaultedFromPath, '.')
|
|
1898
|
+
const fromParams = lightweightResult[3 /* params */]
|
|
1902
1899
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
?
|
|
1906
|
-
|
|
1900
|
+
const nextTo = this.resolvePathWithBase(
|
|
1901
|
+
defaultedFromPath,
|
|
1902
|
+
dest.to ? `${dest.to}` : '.',
|
|
1903
|
+
)
|
|
1907
1904
|
|
|
1908
1905
|
// Resolve the next params
|
|
1909
|
-
|
|
1906
|
+
let nextParams = resolveNextParams(dest.params, fromParams)
|
|
1910
1907
|
|
|
1911
1908
|
const destRoute = this.routesByPath[
|
|
1912
1909
|
trimPathRight(nextTo) as keyof typeof this.routesByPath
|
|
@@ -1938,6 +1935,9 @@ export class RouterCore<
|
|
|
1938
1935
|
const fn =
|
|
1939
1936
|
route.options.params?.stringify ?? route.options.stringifyParams
|
|
1940
1937
|
if (fn) {
|
|
1938
|
+
if (nextParams === fromParams) {
|
|
1939
|
+
nextParams = Object.assign(Object.create(null), nextParams)
|
|
1940
|
+
}
|
|
1941
1941
|
try {
|
|
1942
1942
|
Object.assign(nextParams, fn(nextParams))
|
|
1943
1943
|
} catch {
|
|
@@ -2036,7 +2036,9 @@ export class RouterCore<
|
|
|
2036
2036
|
: {}
|
|
2037
2037
|
|
|
2038
2038
|
// Replace the equal deep
|
|
2039
|
-
|
|
2039
|
+
if (dest.state) {
|
|
2040
|
+
nextState = replaceEqualDeep(currentLocation.state, nextState)
|
|
2041
|
+
}
|
|
2040
2042
|
|
|
2041
2043
|
// Create the full path of the location
|
|
2042
2044
|
const fullPath = `${nextPathname}${searchStr}${hashStr}`
|
|
@@ -2216,38 +2218,12 @@ export class RouterCore<
|
|
|
2216
2218
|
hashScrollIntoView,
|
|
2217
2219
|
viewTransition,
|
|
2218
2220
|
ignoreBlocker,
|
|
2219
|
-
_redirects,
|
|
2220
|
-
href,
|
|
2221
2221
|
...rest
|
|
2222
|
-
}: BuildNextOptions &
|
|
2223
|
-
CommitLocationOptions & { _redirects?: number } = {}) => {
|
|
2224
|
-
if (href) {
|
|
2225
|
-
const currentIndex = this.history.location.state.__TSR_index
|
|
2226
|
-
|
|
2227
|
-
const parsed = parseHref(href, {
|
|
2228
|
-
__TSR_index: replace ? currentIndex : currentIndex + 1,
|
|
2229
|
-
})
|
|
2230
|
-
|
|
2231
|
-
// If the href contains the basepath, we need to strip it before setting `to`
|
|
2232
|
-
// because `buildLocation` will add the basepath back when creating the final URL.
|
|
2233
|
-
// Without this, hrefs like '/app/about' would become '/app/app/about'.
|
|
2234
|
-
const hrefUrl = new URL(parsed.pathname, this.origin)
|
|
2235
|
-
const rewrittenUrl = executeRewriteInput(this.rewrite, hrefUrl)
|
|
2236
|
-
|
|
2237
|
-
rest.to = rewrittenUrl.pathname
|
|
2238
|
-
rest.search = this.options.parseSearch(parsed.search)
|
|
2239
|
-
// remove the leading `#` from the hash
|
|
2240
|
-
rest.hash = parsed.hash.slice(1)
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2222
|
+
}: BuildNextOptions & CommitLocationOptions = {}) => {
|
|
2243
2223
|
const location = this.buildLocation({
|
|
2244
2224
|
...(rest as any),
|
|
2245
2225
|
_includeValidateSearch: true,
|
|
2246
2226
|
})
|
|
2247
|
-
if (_redirects) {
|
|
2248
|
-
;(location as typeof location & { _redirects?: number })._redirects =
|
|
2249
|
-
_redirects
|
|
2250
|
-
}
|
|
2251
2227
|
|
|
2252
2228
|
this._pendingLocation = location as ParsedLocation<
|
|
2253
2229
|
FullSearchSchema<TRouteTree>
|
|
@@ -2514,9 +2490,8 @@ export class RouterCore<
|
|
|
2514
2490
|
resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
|
|
2515
2491
|
const locationHeader = redirect.headers.get('Location')
|
|
2516
2492
|
|
|
2517
|
-
if (!redirect.options.href
|
|
2518
|
-
const location =
|
|
2519
|
-
redirect.options._builtLocation ?? this.buildLocation(redirect.options)
|
|
2493
|
+
if (!redirect.options.href) {
|
|
2494
|
+
const location = this.buildLocation(redirect.options)
|
|
2520
2495
|
const href = location.publicHref || '/'
|
|
2521
2496
|
redirect.options.href = href
|
|
2522
2497
|
redirect.headers.set('Location', href)
|
|
@@ -2535,7 +2510,6 @@ export class RouterCore<
|
|
|
2535
2510
|
|
|
2536
2511
|
if (
|
|
2537
2512
|
redirect.options.href &&
|
|
2538
|
-
!redirect.options._builtLocation &&
|
|
2539
2513
|
// Check for dangerous protocols before processing the redirect
|
|
2540
2514
|
isDangerousProtocol(redirect.options.href, this.protocolAllowlist)
|
|
2541
2515
|
) {
|
|
@@ -2611,7 +2585,8 @@ export class RouterCore<
|
|
|
2611
2585
|
TTrailingSlashOption,
|
|
2612
2586
|
TDefaultStructuralSharingOption,
|
|
2613
2587
|
TRouterHistory
|
|
2614
|
-
> = (opts
|
|
2588
|
+
> = (opts: any, builtLocation?: ParsedLocation) =>
|
|
2589
|
+
preloadClientRoute(this, opts, 0, builtLocation)
|
|
2615
2590
|
|
|
2616
2591
|
matchRoute: MatchRouteFn<
|
|
2617
2592
|
TRouteTree,
|
|
@@ -2797,24 +2772,22 @@ function applySearchMiddleware(
|
|
|
2797
2772
|
}
|
|
2798
2773
|
|
|
2799
2774
|
const routeValidateSearch = routeOptions.validateSearch
|
|
2800
|
-
if (routeValidateSearch) {
|
|
2775
|
+
if (includeValidateSearch && routeValidateSearch) {
|
|
2801
2776
|
const validate: SearchMiddleware<any> = ({ search, next, meta }) => {
|
|
2802
2777
|
const result = next(search)
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
;(meta.defaulted ||= new Map()).set(key, validated[key])
|
|
2811
|
-
}
|
|
2778
|
+
try {
|
|
2779
|
+
const validated = validateSearch(routeValidateSearch, result) as any
|
|
2780
|
+
|
|
2781
|
+
if (meta && validated) {
|
|
2782
|
+
for (const key in validated) {
|
|
2783
|
+
if (!(key in result)) {
|
|
2784
|
+
;(meta.defaulted ||= new Map()).set(key, validated[key])
|
|
2812
2785
|
}
|
|
2813
2786
|
}
|
|
2814
|
-
return { ...result, ...validated }
|
|
2815
|
-
} catch {
|
|
2816
|
-
// ignore errors here because they are already handled in matchRoutes
|
|
2817
2787
|
}
|
|
2788
|
+
return { ...result, ...validated }
|
|
2789
|
+
} catch {
|
|
2790
|
+
// ignore errors here because they are already handled in matchRoutes
|
|
2818
2791
|
}
|
|
2819
2792
|
return result
|
|
2820
2793
|
}
|
|
@@ -2884,11 +2857,14 @@ function resolveNextParams(
|
|
|
2884
2857
|
spec: unknown,
|
|
2885
2858
|
base: Record<string, unknown>,
|
|
2886
2859
|
): Record<string, unknown> {
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2860
|
+
if (spec === false || spec === null) {
|
|
2861
|
+
return Object.create(null)
|
|
2862
|
+
}
|
|
2863
|
+
if ((spec ?? true) === true) {
|
|
2864
|
+
return base
|
|
2865
|
+
}
|
|
2866
|
+
const next = Object.assign(Object.create(null), base)
|
|
2867
|
+
return Object.assign(next, functionalUpdate(spec as any, next))
|
|
2892
2868
|
}
|
|
2893
2869
|
|
|
2894
2870
|
function extractStrictParams(
|