@tanstack/router-core 1.132.0-alpha.12 → 1.132.0-alpha.16
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/index.cjs +5 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +3 -1
- package/dist/cjs/location.d.cts +38 -0
- package/dist/cjs/path.cjs +6 -49
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -6
- package/dist/cjs/rewrite.cjs +63 -0
- package/dist/cjs/rewrite.cjs.map +1 -0
- package/dist/cjs/rewrite.d.cts +22 -0
- package/dist/cjs/router.cjs +50 -29
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +49 -2
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +6 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/location.d.ts +38 -0
- package/dist/esm/path.d.ts +3 -6
- package/dist/esm/path.js +6 -49
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/rewrite.d.ts +22 -0
- package/dist/esm/rewrite.js +63 -0
- package/dist/esm/rewrite.js.map +1 -0
- package/dist/esm/router.d.ts +49 -2
- package/dist/esm/router.js +52 -31
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +8 -1
- package/src/location.ts +38 -0
- package/src/path.ts +5 -66
- package/src/rewrite.ts +70 -0
- package/src/router.ts +129 -49
package/src/index.ts
CHANGED
|
@@ -103,7 +103,6 @@ export {
|
|
|
103
103
|
parsePathname,
|
|
104
104
|
interpolatePath,
|
|
105
105
|
matchPathname,
|
|
106
|
-
removeBasepath,
|
|
107
106
|
matchByPath,
|
|
108
107
|
} from './path'
|
|
109
108
|
export type { Segment } from './path'
|
|
@@ -432,3 +431,11 @@ export {
|
|
|
432
431
|
} from './ssr/serializer/transformer'
|
|
433
432
|
|
|
434
433
|
export { defaultSerovalPlugins } from './ssr/serializer/seroval-plugins'
|
|
434
|
+
|
|
435
|
+
export {
|
|
436
|
+
rewriteBasepath,
|
|
437
|
+
composeRewrites,
|
|
438
|
+
executeRewriteInput,
|
|
439
|
+
executeRewriteOutput,
|
|
440
|
+
} from './rewrite'
|
|
441
|
+
export type { LocationRewrite, LocationRewriteFunction } from './router'
|
package/src/location.ts
CHANGED
|
@@ -2,12 +2,50 @@ import type { ParsedHistoryState } from '@tanstack/history'
|
|
|
2
2
|
import type { AnySchema } from './validators'
|
|
3
3
|
|
|
4
4
|
export interface ParsedLocation<TSearchObj extends AnySchema = {}> {
|
|
5
|
+
/**
|
|
6
|
+
* The full path of the location, including pathname, search, and hash.
|
|
7
|
+
* Does not include the origin. Is the equivalent of calling
|
|
8
|
+
* `url.replace(url.origin, '')`
|
|
9
|
+
*/
|
|
5
10
|
href: string
|
|
11
|
+
/**
|
|
12
|
+
* @description The pathname of the location, including the leading slash.
|
|
13
|
+
*/
|
|
6
14
|
pathname: string
|
|
15
|
+
/**
|
|
16
|
+
* The parsed search parameters of the location in object form.
|
|
17
|
+
*/
|
|
7
18
|
search: TSearchObj
|
|
19
|
+
/**
|
|
20
|
+
* The search string of the location, including the leading question mark.
|
|
21
|
+
*/
|
|
8
22
|
searchStr: string
|
|
23
|
+
/**
|
|
24
|
+
* The in-memory state of the location as it *may* exist in the browser's history.
|
|
25
|
+
*/
|
|
9
26
|
state: ParsedHistoryState
|
|
27
|
+
/**
|
|
28
|
+
* The hash of the location, including the leading hash character.
|
|
29
|
+
*/
|
|
10
30
|
hash: string
|
|
31
|
+
/**
|
|
32
|
+
* The masked location of the location.
|
|
33
|
+
*/
|
|
11
34
|
maskedLocation?: ParsedLocation<TSearchObj>
|
|
35
|
+
/**
|
|
36
|
+
* Whether to unmask the location on reload.
|
|
37
|
+
*/
|
|
12
38
|
unmaskOnReload?: boolean
|
|
39
|
+
/**
|
|
40
|
+
* @private
|
|
41
|
+
* @description The public href of the location, including the origin before any rewrites.
|
|
42
|
+
* If a rewrite is applied, the `href` property will be the rewritten URL.
|
|
43
|
+
*/
|
|
44
|
+
publicHref: string
|
|
45
|
+
/**
|
|
46
|
+
* @private
|
|
47
|
+
* @description The full URL of the location, including the origin.
|
|
48
|
+
* @private
|
|
49
|
+
*/
|
|
50
|
+
url: string
|
|
13
51
|
}
|
package/src/path.ts
CHANGED
|
@@ -97,11 +97,9 @@ export function exactPathTest(
|
|
|
97
97
|
// /a/b/c + d/ = /a/b/c/d
|
|
98
98
|
// /a/b/c + d/e = /a/b/c/d/e
|
|
99
99
|
interface ResolvePathOptions {
|
|
100
|
-
basepath: string
|
|
101
100
|
base: string
|
|
102
101
|
to: string
|
|
103
102
|
trailingSlash?: 'always' | 'never' | 'preserve'
|
|
104
|
-
caseSensitive?: boolean
|
|
105
103
|
parseCache?: ParsePathnameCache
|
|
106
104
|
}
|
|
107
105
|
|
|
@@ -151,16 +149,11 @@ function segmentToString(segment: Segment): string {
|
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
export function resolvePath({
|
|
154
|
-
basepath,
|
|
155
152
|
base,
|
|
156
153
|
to,
|
|
157
154
|
trailingSlash = 'never',
|
|
158
|
-
caseSensitive,
|
|
159
155
|
parseCache,
|
|
160
156
|
}: ResolvePathOptions) {
|
|
161
|
-
base = removeBasepath(basepath, base, caseSensitive)
|
|
162
|
-
to = removeBasepath(basepath, to, caseSensitive)
|
|
163
|
-
|
|
164
157
|
let baseSegments = parsePathname(base, parseCache).slice()
|
|
165
158
|
const toSegments = parsePathname(to, parseCache)
|
|
166
159
|
|
|
@@ -201,7 +194,8 @@ export function resolvePath({
|
|
|
201
194
|
}
|
|
202
195
|
|
|
203
196
|
const segmentValues = baseSegments.map(segmentToString)
|
|
204
|
-
const joined = joinPaths([basepath, ...segmentValues])
|
|
197
|
+
// const joined = joinPaths([basepath, ...segmentValues])
|
|
198
|
+
const joined = joinPaths(segmentValues)
|
|
205
199
|
return joined
|
|
206
200
|
}
|
|
207
201
|
|
|
@@ -491,17 +485,11 @@ function encodePathParam(value: string, decodeCharMap?: Map<string, string>) {
|
|
|
491
485
|
}
|
|
492
486
|
|
|
493
487
|
export function matchPathname(
|
|
494
|
-
basepath: string,
|
|
495
488
|
currentPathname: string,
|
|
496
489
|
matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>,
|
|
497
490
|
parseCache?: ParsePathnameCache,
|
|
498
491
|
): AnyPathParams | undefined {
|
|
499
|
-
const pathParams = matchByPath(
|
|
500
|
-
basepath,
|
|
501
|
-
currentPathname,
|
|
502
|
-
matchLocation,
|
|
503
|
-
parseCache,
|
|
504
|
-
)
|
|
492
|
+
const pathParams = matchByPath(currentPathname, matchLocation, parseCache)
|
|
505
493
|
// const searchMatched = matchBySearch(location.search, matchLocation)
|
|
506
494
|
|
|
507
495
|
if (matchLocation.to && !pathParams) {
|
|
@@ -511,49 +499,7 @@ export function matchPathname(
|
|
|
511
499
|
return pathParams ?? {}
|
|
512
500
|
}
|
|
513
501
|
|
|
514
|
-
export function removeBasepath(
|
|
515
|
-
basepath: string,
|
|
516
|
-
pathname: string,
|
|
517
|
-
caseSensitive: boolean = false,
|
|
518
|
-
) {
|
|
519
|
-
// normalize basepath and pathname for case-insensitive comparison if needed
|
|
520
|
-
const normalizedBasepath = caseSensitive ? basepath : basepath.toLowerCase()
|
|
521
|
-
const normalizedPathname = caseSensitive ? pathname : pathname.toLowerCase()
|
|
522
|
-
|
|
523
|
-
switch (true) {
|
|
524
|
-
// default behaviour is to serve app from the root - pathname
|
|
525
|
-
// left untouched
|
|
526
|
-
case normalizedBasepath === '/':
|
|
527
|
-
return pathname
|
|
528
|
-
|
|
529
|
-
// shortcut for removing the basepath if it matches the pathname
|
|
530
|
-
case normalizedPathname === normalizedBasepath:
|
|
531
|
-
return ''
|
|
532
|
-
|
|
533
|
-
// in case pathname is shorter than basepath - there is
|
|
534
|
-
// nothing to remove
|
|
535
|
-
case pathname.length < basepath.length:
|
|
536
|
-
return pathname
|
|
537
|
-
|
|
538
|
-
// avoid matching partial segments - strict equality handled
|
|
539
|
-
// earlier, otherwise, basepath separated from pathname with
|
|
540
|
-
// separator, therefore lack of separator means partial
|
|
541
|
-
// segment match (`/app` should not match `/application`)
|
|
542
|
-
case normalizedPathname[normalizedBasepath.length] !== '/':
|
|
543
|
-
return pathname
|
|
544
|
-
|
|
545
|
-
// remove the basepath from the pathname if it starts with it
|
|
546
|
-
case normalizedPathname.startsWith(normalizedBasepath):
|
|
547
|
-
return pathname.slice(basepath.length)
|
|
548
|
-
|
|
549
|
-
// otherwise, return the pathname as is
|
|
550
|
-
default:
|
|
551
|
-
return pathname
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
502
|
export function matchByPath(
|
|
556
|
-
basepath: string,
|
|
557
503
|
from: string,
|
|
558
504
|
{
|
|
559
505
|
to,
|
|
@@ -562,14 +508,7 @@ export function matchByPath(
|
|
|
562
508
|
}: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,
|
|
563
509
|
parseCache?: ParsePathnameCache,
|
|
564
510
|
): Record<string, string> | undefined {
|
|
565
|
-
|
|
566
|
-
if (basepath !== '/' && !from.startsWith(basepath)) {
|
|
567
|
-
return undefined
|
|
568
|
-
}
|
|
569
|
-
// Remove the base path from the pathname
|
|
570
|
-
from = removeBasepath(basepath, from, caseSensitive)
|
|
571
|
-
// Default to to $ (wildcard)
|
|
572
|
-
to = removeBasepath(basepath, `${to ?? '$'}`, caseSensitive)
|
|
511
|
+
const stringTo = to as string
|
|
573
512
|
|
|
574
513
|
// Parse the from and to
|
|
575
514
|
const baseSegments = parsePathname(
|
|
@@ -577,7 +516,7 @@ export function matchByPath(
|
|
|
577
516
|
parseCache,
|
|
578
517
|
)
|
|
579
518
|
const routeSegments = parsePathname(
|
|
580
|
-
|
|
519
|
+
stringTo.startsWith('/') ? stringTo : `/${stringTo}`,
|
|
581
520
|
parseCache,
|
|
582
521
|
)
|
|
583
522
|
|
package/src/rewrite.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { joinPaths, trimPath } from './path'
|
|
2
|
+
import type { LocationRewrite } from './router'
|
|
3
|
+
|
|
4
|
+
export function composeRewrites(rewrites: Array<LocationRewrite>) {
|
|
5
|
+
return {
|
|
6
|
+
input: ({ url }) => {
|
|
7
|
+
for (const rewrite of rewrites) {
|
|
8
|
+
url = executeRewriteInput(rewrite, url)
|
|
9
|
+
}
|
|
10
|
+
return url
|
|
11
|
+
},
|
|
12
|
+
output: ({ url }) => {
|
|
13
|
+
for (let i = rewrites.length - 1; i >= 0; i--) {
|
|
14
|
+
url = executeRewriteOutput(rewrites[i], url)
|
|
15
|
+
}
|
|
16
|
+
return url
|
|
17
|
+
},
|
|
18
|
+
} satisfies LocationRewrite
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function rewriteBasepath(opts: {
|
|
22
|
+
basepath: string
|
|
23
|
+
caseSensitive?: boolean
|
|
24
|
+
}) {
|
|
25
|
+
const trimmedBasepath = trimPath(opts.basepath)
|
|
26
|
+
const regex = new RegExp(
|
|
27
|
+
`^/${trimmedBasepath}/`,
|
|
28
|
+
opts.caseSensitive ? '' : 'i',
|
|
29
|
+
)
|
|
30
|
+
return {
|
|
31
|
+
input: ({ url }) => {
|
|
32
|
+
url.pathname = url.pathname.replace(regex, '/')
|
|
33
|
+
return url
|
|
34
|
+
},
|
|
35
|
+
output: ({ url }) => {
|
|
36
|
+
url.pathname = joinPaths(['/', trimmedBasepath, url.pathname])
|
|
37
|
+
return url
|
|
38
|
+
},
|
|
39
|
+
} satisfies LocationRewrite
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function executeRewriteInput(
|
|
43
|
+
rewrite: LocationRewrite | undefined,
|
|
44
|
+
url: URL,
|
|
45
|
+
): URL {
|
|
46
|
+
const res = rewrite?.input?.({ url })
|
|
47
|
+
if (res) {
|
|
48
|
+
if (typeof res === 'string') {
|
|
49
|
+
return new URL(res)
|
|
50
|
+
} else if (res instanceof URL) {
|
|
51
|
+
return res
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return url
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function executeRewriteOutput(
|
|
58
|
+
rewrite: LocationRewrite | undefined,
|
|
59
|
+
url: URL,
|
|
60
|
+
): URL {
|
|
61
|
+
const res = rewrite?.output?.({ url })
|
|
62
|
+
if (res) {
|
|
63
|
+
if (typeof res === 'string') {
|
|
64
|
+
return new URL(res)
|
|
65
|
+
} else if (res instanceof URL) {
|
|
66
|
+
return res
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return url
|
|
70
|
+
}
|
package/src/router.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Store, batch } from '@tanstack/store'
|
|
2
|
-
import {
|
|
3
|
-
createBrowserHistory,
|
|
4
|
-
createMemoryHistory,
|
|
5
|
-
parseHref,
|
|
6
|
-
} from '@tanstack/history'
|
|
2
|
+
import { createBrowserHistory, parseHref } from '@tanstack/history'
|
|
7
3
|
import invariant from 'tiny-invariant'
|
|
8
4
|
import {
|
|
9
5
|
createControlledPromise,
|
|
@@ -20,7 +16,6 @@ import {
|
|
|
20
16
|
SEGMENT_TYPE_WILDCARD,
|
|
21
17
|
cleanPath,
|
|
22
18
|
interpolatePath,
|
|
23
|
-
joinPaths,
|
|
24
19
|
matchPathname,
|
|
25
20
|
parsePathname,
|
|
26
21
|
resolvePath,
|
|
@@ -35,6 +30,12 @@ import { rootRouteId } from './root'
|
|
|
35
30
|
import { isRedirect, redirect } from './redirect'
|
|
36
31
|
import { createLRUCache } from './lru-cache'
|
|
37
32
|
import { loadMatches, loadRouteChunk, routeNeedsPreload } from './load-matches'
|
|
33
|
+
import {
|
|
34
|
+
composeRewrites,
|
|
35
|
+
executeRewriteInput,
|
|
36
|
+
executeRewriteOutput,
|
|
37
|
+
rewriteBasepath,
|
|
38
|
+
} from './rewrite'
|
|
38
39
|
import type { ParsePathnameCache, Segment } from './path'
|
|
39
40
|
import type { SearchParser, SearchSerializer } from './searchParams'
|
|
40
41
|
import type { AnyRedirect, ResolvedRedirect } from './redirect'
|
|
@@ -271,6 +272,18 @@ export interface RouterOptions<
|
|
|
271
272
|
/**
|
|
272
273
|
* The basepath for then entire router. This is useful for mounting a router instance at a subpath.
|
|
273
274
|
*
|
|
275
|
+
* @deprecated - use `rewrite.input` with the new `rewriteBasepath` utility instead:
|
|
276
|
+
* ```ts
|
|
277
|
+
* const router = createRouter({
|
|
278
|
+
* routeTree,
|
|
279
|
+
* rewrite: rewriteBasepath('/basepath')
|
|
280
|
+
* // Or wrap existing rewrite functionality
|
|
281
|
+
* rewrite: rewriteBasepath('/basepath', {
|
|
282
|
+
* output: ({ url }) => {...},
|
|
283
|
+
* input: ({ url }) => {...},
|
|
284
|
+
* })
|
|
285
|
+
* })
|
|
286
|
+
* ```
|
|
274
287
|
* @default '/'
|
|
275
288
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#basepath-property)
|
|
276
289
|
*/
|
|
@@ -438,8 +451,46 @@ export interface RouterOptions<
|
|
|
438
451
|
disableGlobalCatchBoundary?: boolean
|
|
439
452
|
|
|
440
453
|
serializationAdapters?: ReadonlyArray<AnySerializationAdapter>
|
|
454
|
+
/**
|
|
455
|
+
* Configures how the router will rewrite the location between the actual href and the internal href of the router.
|
|
456
|
+
*
|
|
457
|
+
* @default undefined
|
|
458
|
+
* @description You can provide a custom rewrite pair (in/out) or use the utilities like `rewriteBasepath` as a convenience for common use cases, or even do both!
|
|
459
|
+
* This is useful for basepath rewriting, shifting data from the origin to the path (for things like )
|
|
460
|
+
*/
|
|
461
|
+
rewrite?: LocationRewrite
|
|
462
|
+
origin?: string
|
|
441
463
|
}
|
|
442
464
|
|
|
465
|
+
export type LocationRewrite = {
|
|
466
|
+
/**
|
|
467
|
+
* A function that will be called to rewrite the URL before it is interpreted by the router from the history instance.
|
|
468
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
469
|
+
*
|
|
470
|
+
* @default undefined
|
|
471
|
+
*/
|
|
472
|
+
input?: LocationRewriteFunction
|
|
473
|
+
/**
|
|
474
|
+
* A function that will be called to rewrite the URL before it is committed to the actual history instance from the router.
|
|
475
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
476
|
+
*
|
|
477
|
+
* @default undefined
|
|
478
|
+
*/
|
|
479
|
+
output?: LocationRewriteFunction
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* A function that will be called to rewrite the URL.
|
|
484
|
+
*
|
|
485
|
+
* @param url The URL to rewrite.
|
|
486
|
+
* @returns The rewritten URL (as a URL instance or full href string) or undefined if no rewrite is needed.
|
|
487
|
+
*/
|
|
488
|
+
export type LocationRewriteFunction = ({
|
|
489
|
+
url,
|
|
490
|
+
}: {
|
|
491
|
+
url: URL
|
|
492
|
+
}) => undefined | string | URL
|
|
493
|
+
|
|
443
494
|
export interface RouterState<
|
|
444
495
|
in out TRouteTree extends AnyRoute = AnyRoute,
|
|
445
496
|
in out TRouteMatch = MakeRouteMatchUnion,
|
|
@@ -810,7 +861,10 @@ export class RouterCore<
|
|
|
810
861
|
'stringifySearch' | 'parseSearch' | 'context'
|
|
811
862
|
>
|
|
812
863
|
history!: TRouterHistory
|
|
864
|
+
rewrite?: LocationRewrite
|
|
865
|
+
origin?: string
|
|
813
866
|
latestLocation!: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
867
|
+
// @deprecated - basepath functionality is now implemented via the `rewrite` option
|
|
814
868
|
basepath!: string
|
|
815
869
|
routeTree!: TRouteTree
|
|
816
870
|
routesById!: RoutesById<TRouteTree>
|
|
@@ -874,7 +928,6 @@ export class RouterCore<
|
|
|
874
928
|
)
|
|
875
929
|
}
|
|
876
930
|
|
|
877
|
-
const previousOptions = this.options
|
|
878
931
|
this.options = {
|
|
879
932
|
...this.options,
|
|
880
933
|
...newOptions,
|
|
@@ -892,31 +945,41 @@ export class RouterCore<
|
|
|
892
945
|
: undefined
|
|
893
946
|
|
|
894
947
|
if (
|
|
895
|
-
!this.
|
|
896
|
-
(
|
|
948
|
+
!this.history ||
|
|
949
|
+
(this.options.history && this.options.history !== this.history)
|
|
897
950
|
) {
|
|
898
|
-
if (
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
) {
|
|
903
|
-
this.basepath = '/'
|
|
951
|
+
if (!this.options.history) {
|
|
952
|
+
if (!this.isServer) {
|
|
953
|
+
this.history = createBrowserHistory() as TRouterHistory
|
|
954
|
+
}
|
|
904
955
|
} else {
|
|
905
|
-
this.
|
|
956
|
+
this.history = this.options.history
|
|
906
957
|
}
|
|
907
958
|
}
|
|
959
|
+
// For backwards compatibility, we support a basepath option, which we now implement as a rewrite
|
|
960
|
+
if (this.options.basepath) {
|
|
961
|
+
const basepathRewrite = rewriteBasepath({
|
|
962
|
+
basepath: this.options.basepath,
|
|
963
|
+
})
|
|
964
|
+
if (this.options.rewrite) {
|
|
965
|
+
this.rewrite = composeRewrites([basepathRewrite, this.options.rewrite])
|
|
966
|
+
} else {
|
|
967
|
+
this.rewrite = basepathRewrite
|
|
968
|
+
}
|
|
969
|
+
} else {
|
|
970
|
+
this.rewrite = this.options.rewrite
|
|
971
|
+
}
|
|
908
972
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
(this.
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
: createBrowserHistory()) as TRouterHistory)
|
|
973
|
+
this.origin = this.options.origin
|
|
974
|
+
if (!this.origin) {
|
|
975
|
+
if (!this.isServer) {
|
|
976
|
+
this.origin = window.origin
|
|
977
|
+
} else {
|
|
978
|
+
// fallback for the server, can be overridden by calling router.update({origin}) on the server
|
|
979
|
+
this.origin = 'http://localhost'
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
if (this.history) {
|
|
920
983
|
this.updateLatestLocation()
|
|
921
984
|
}
|
|
922
985
|
|
|
@@ -925,7 +988,7 @@ export class RouterCore<
|
|
|
925
988
|
this.buildRouteTree()
|
|
926
989
|
}
|
|
927
990
|
|
|
928
|
-
if (!this.__store) {
|
|
991
|
+
if (!this.__store && this.latestLocation) {
|
|
929
992
|
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
930
993
|
onUpdate: () => {
|
|
931
994
|
this.__store.state = {
|
|
@@ -1012,20 +1075,32 @@ export class RouterCore<
|
|
|
1012
1075
|
previousLocation,
|
|
1013
1076
|
) => {
|
|
1014
1077
|
const parse = ({
|
|
1015
|
-
|
|
1016
|
-
search,
|
|
1017
|
-
hash,
|
|
1078
|
+
href,
|
|
1018
1079
|
state,
|
|
1019
1080
|
}: HistoryLocation): ParsedLocation<FullSearchSchema<TRouteTree>> => {
|
|
1020
|
-
|
|
1081
|
+
// Before we do any processing, we need to allow rewrites to modify the URL
|
|
1082
|
+
// build up the full URL by combining the href from history with the router's origin
|
|
1083
|
+
const fullUrl = new URL(href, this.origin)
|
|
1084
|
+
const url = executeRewriteInput(this.rewrite, fullUrl)
|
|
1085
|
+
|
|
1086
|
+
const parsedSearch = this.options.parseSearch(url.search)
|
|
1021
1087
|
const searchStr = this.options.stringifySearch(parsedSearch)
|
|
1088
|
+
// Make sure our final url uses the re-stringified pathname, search, and has for consistency
|
|
1089
|
+
// (We were already doing this, so just keeping it for now)
|
|
1090
|
+
url.search = searchStr
|
|
1091
|
+
|
|
1092
|
+
const fullPath = url.href.replace(url.origin, '')
|
|
1093
|
+
|
|
1094
|
+
const { pathname, hash } = url
|
|
1022
1095
|
|
|
1023
1096
|
return {
|
|
1097
|
+
href: fullPath,
|
|
1098
|
+
publicHref: href,
|
|
1099
|
+
url: url.href,
|
|
1024
1100
|
pathname,
|
|
1025
1101
|
searchStr,
|
|
1026
1102
|
search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
|
|
1027
1103
|
hash: hash.split('#').reverse()[0] ?? '',
|
|
1028
|
-
href: `${pathname}${searchStr}${hash}`,
|
|
1029
1104
|
state: replaceEqualDeep(previousLocation?.state, state),
|
|
1030
1105
|
}
|
|
1031
1106
|
}
|
|
@@ -1053,11 +1128,9 @@ export class RouterCore<
|
|
|
1053
1128
|
|
|
1054
1129
|
resolvePathWithBase = (from: string, path: string) => {
|
|
1055
1130
|
const resolvedPath = resolvePath({
|
|
1056
|
-
basepath: this.basepath,
|
|
1057
1131
|
base: from,
|
|
1058
1132
|
to: cleanPath(path),
|
|
1059
1133
|
trailingSlash: this.options.trailingSlash,
|
|
1060
|
-
caseSensitive: this.options.caseSensitive,
|
|
1061
1134
|
parseCache: this.parsePathnameCache,
|
|
1062
1135
|
})
|
|
1063
1136
|
return resolvedPath
|
|
@@ -1289,7 +1362,7 @@ export class RouterCore<
|
|
|
1289
1362
|
? replaceEqualDeep(previousMatch.params, routeParams)
|
|
1290
1363
|
: routeParams,
|
|
1291
1364
|
_strictParams: usedParams,
|
|
1292
|
-
pathname:
|
|
1365
|
+
pathname: interpolatedPath,
|
|
1293
1366
|
updatedAt: Date.now(),
|
|
1294
1367
|
search: previousMatch
|
|
1295
1368
|
? replaceEqualDeep(previousMatch.search, preMatchSearch)
|
|
@@ -1394,7 +1467,6 @@ export class RouterCore<
|
|
|
1394
1467
|
return getMatchedRoutes({
|
|
1395
1468
|
pathname,
|
|
1396
1469
|
routePathname,
|
|
1397
|
-
basepath: this.basepath,
|
|
1398
1470
|
caseSensitive: this.options.caseSensitive,
|
|
1399
1471
|
routesByPath: this.routesByPath,
|
|
1400
1472
|
routesById: this.routesById,
|
|
@@ -1583,14 +1655,25 @@ export class RouterCore<
|
|
|
1583
1655
|
// Replace the equal deep
|
|
1584
1656
|
nextState = replaceEqualDeep(currentLocation.state, nextState)
|
|
1585
1657
|
|
|
1586
|
-
//
|
|
1658
|
+
// Create the full path of the location
|
|
1659
|
+
const fullPath = `${nextPathname}${searchStr}${hashStr}`
|
|
1660
|
+
|
|
1661
|
+
// Create the new href with full origin
|
|
1662
|
+
const url = new URL(fullPath, this.origin)
|
|
1663
|
+
|
|
1664
|
+
// If a rewrite function is provided, use it to rewrite the URL
|
|
1665
|
+
const rewrittenUrl = executeRewriteOutput(this.rewrite, url)
|
|
1666
|
+
|
|
1587
1667
|
return {
|
|
1668
|
+
publicHref:
|
|
1669
|
+
rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
|
|
1670
|
+
href: fullPath,
|
|
1671
|
+
url: rewrittenUrl.href,
|
|
1588
1672
|
pathname: nextPathname,
|
|
1589
1673
|
search: nextSearch,
|
|
1590
1674
|
searchStr,
|
|
1591
1675
|
state: nextState as any,
|
|
1592
1676
|
hash: hash ?? '',
|
|
1593
|
-
href: `${nextPathname}${searchStr}${hashStr}`,
|
|
1594
1677
|
unmaskOnReload: dest.unmaskOnReload,
|
|
1595
1678
|
}
|
|
1596
1679
|
}
|
|
@@ -1608,7 +1691,6 @@ export class RouterCore<
|
|
|
1608
1691
|
|
|
1609
1692
|
const foundMask = this.options.routeMasks?.find((d) => {
|
|
1610
1693
|
const match = matchPathname(
|
|
1611
|
-
this.basepath,
|
|
1612
1694
|
next.pathname,
|
|
1613
1695
|
{
|
|
1614
1696
|
to: d.from,
|
|
@@ -1638,8 +1720,7 @@ export class RouterCore<
|
|
|
1638
1720
|
}
|
|
1639
1721
|
|
|
1640
1722
|
if (maskedNext) {
|
|
1641
|
-
|
|
1642
|
-
next.maskedLocation = maskedFinal
|
|
1723
|
+
next.maskedLocation = maskedNext
|
|
1643
1724
|
}
|
|
1644
1725
|
|
|
1645
1726
|
return next
|
|
@@ -1682,7 +1763,8 @@ export class RouterCore<
|
|
|
1682
1763
|
return isEqual
|
|
1683
1764
|
}
|
|
1684
1765
|
|
|
1685
|
-
const isSameUrl =
|
|
1766
|
+
const isSameUrl =
|
|
1767
|
+
trimPathRight(this.latestLocation.href) === trimPathRight(next.href)
|
|
1686
1768
|
|
|
1687
1769
|
const previousCommitPromise = this.commitLocationPromise
|
|
1688
1770
|
this.commitLocationPromise = createControlledPromise<void>(() => {
|
|
@@ -1731,7 +1813,7 @@ export class RouterCore<
|
|
|
1731
1813
|
this.shouldViewTransition = viewTransition
|
|
1732
1814
|
|
|
1733
1815
|
this.history[next.replace ? 'replace' : 'push'](
|
|
1734
|
-
nextHistory.
|
|
1816
|
+
nextHistory.publicHref,
|
|
1735
1817
|
nextHistory.state,
|
|
1736
1818
|
{ ignoreBlocker },
|
|
1737
1819
|
)
|
|
@@ -1793,7 +1875,7 @@ export class RouterCore<
|
|
|
1793
1875
|
if (reloadDocument) {
|
|
1794
1876
|
if (!href) {
|
|
1795
1877
|
const location = this.buildLocation({ to, ...rest } as any)
|
|
1796
|
-
href =
|
|
1878
|
+
href = location.href
|
|
1797
1879
|
}
|
|
1798
1880
|
if (rest.replace) {
|
|
1799
1881
|
window.location.replace(href)
|
|
@@ -1846,6 +1928,7 @@ export class RouterCore<
|
|
|
1846
1928
|
throw redirect({ href: nextLocation.href })
|
|
1847
1929
|
}
|
|
1848
1930
|
}
|
|
1931
|
+
|
|
1849
1932
|
// Match the routes
|
|
1850
1933
|
const pendingMatches = this.matchRoutes(this.latestLocation)
|
|
1851
1934
|
|
|
@@ -1991,6 +2074,7 @@ export class RouterCore<
|
|
|
1991
2074
|
this.latestLoadPromise = undefined
|
|
1992
2075
|
this.commitLocationPromise = undefined
|
|
1993
2076
|
}
|
|
2077
|
+
|
|
1994
2078
|
resolve()
|
|
1995
2079
|
})
|
|
1996
2080
|
})
|
|
@@ -2289,7 +2373,6 @@ export class RouterCore<
|
|
|
2289
2373
|
: this.state.resolvedLocation || this.state.location
|
|
2290
2374
|
|
|
2291
2375
|
const match = matchPathname(
|
|
2292
|
-
this.basepath,
|
|
2293
2376
|
baseLocation.pathname,
|
|
2294
2377
|
{
|
|
2295
2378
|
...opts,
|
|
@@ -2625,7 +2708,6 @@ export function processRouteTree<TRouteLike extends RouteLike>({
|
|
|
2625
2708
|
export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
2626
2709
|
pathname,
|
|
2627
2710
|
routePathname,
|
|
2628
|
-
basepath,
|
|
2629
2711
|
caseSensitive,
|
|
2630
2712
|
routesByPath,
|
|
2631
2713
|
routesById,
|
|
@@ -2634,7 +2716,6 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
|
2634
2716
|
}: {
|
|
2635
2717
|
pathname: string
|
|
2636
2718
|
routePathname?: string
|
|
2637
|
-
basepath: string
|
|
2638
2719
|
caseSensitive?: boolean
|
|
2639
2720
|
routesByPath: Record<string, TRouteLike>
|
|
2640
2721
|
routesById: Record<string, TRouteLike>
|
|
@@ -2645,7 +2726,6 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
|
2645
2726
|
const trimmedPath = trimPathRight(pathname)
|
|
2646
2727
|
const getMatchedParams = (route: TRouteLike) => {
|
|
2647
2728
|
const result = matchPathname(
|
|
2648
|
-
basepath,
|
|
2649
2729
|
trimmedPath,
|
|
2650
2730
|
{
|
|
2651
2731
|
to: route.fullPath,
|