@tanstack/router-core 1.132.0-alpha.4 → 1.132.0

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.
Files changed (104) hide show
  1. package/dist/cjs/Matches.cjs +2 -1
  2. package/dist/cjs/Matches.cjs.map +1 -1
  3. package/dist/cjs/Matches.d.cts +2 -2
  4. package/dist/cjs/config.cjs +10 -0
  5. package/dist/cjs/config.cjs.map +1 -0
  6. package/dist/cjs/config.d.cts +17 -0
  7. package/dist/cjs/fileRoute.d.cts +3 -2
  8. package/dist/cjs/index.cjs +9 -2
  9. package/dist/cjs/index.cjs.map +1 -1
  10. package/dist/cjs/index.d.cts +10 -5
  11. package/dist/cjs/load-matches.cjs +5 -3
  12. package/dist/cjs/load-matches.cjs.map +1 -1
  13. package/dist/cjs/location.d.cts +38 -0
  14. package/dist/cjs/path.cjs +27 -64
  15. package/dist/cjs/path.cjs.map +1 -1
  16. package/dist/cjs/path.d.cts +6 -7
  17. package/dist/cjs/process-route-tree.cjs +144 -0
  18. package/dist/cjs/process-route-tree.cjs.map +1 -0
  19. package/dist/cjs/process-route-tree.d.cts +10 -0
  20. package/dist/cjs/redirect.cjs +1 -1
  21. package/dist/cjs/redirect.cjs.map +1 -1
  22. package/dist/cjs/rewrite.cjs +63 -0
  23. package/dist/cjs/rewrite.cjs.map +1 -0
  24. package/dist/cjs/rewrite.d.cts +22 -0
  25. package/dist/cjs/route.cjs.map +1 -1
  26. package/dist/cjs/route.d.cts +62 -44
  27. package/dist/cjs/router.cjs +102 -210
  28. package/dist/cjs/router.cjs.map +1 -1
  29. package/dist/cjs/router.d.cts +81 -44
  30. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  31. package/dist/cjs/scroll-restoration.d.cts +9 -0
  32. package/dist/cjs/ssr/createRequestHandler.cjs +4 -1
  33. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
  34. package/dist/cjs/ssr/serializer/transformer.cjs +14 -12
  35. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
  36. package/dist/cjs/ssr/serializer/transformer.d.cts +55 -15
  37. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  38. package/dist/cjs/ssr/ssr-server.cjs +5 -2
  39. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  40. package/dist/cjs/ssr/ssr-server.d.cts +4 -1
  41. package/dist/cjs/utils.cjs +68 -46
  42. package/dist/cjs/utils.cjs.map +1 -1
  43. package/dist/esm/Matches.d.ts +2 -2
  44. package/dist/esm/Matches.js +2 -1
  45. package/dist/esm/Matches.js.map +1 -1
  46. package/dist/esm/config.d.ts +17 -0
  47. package/dist/esm/config.js +10 -0
  48. package/dist/esm/config.js.map +1 -0
  49. package/dist/esm/fileRoute.d.ts +3 -2
  50. package/dist/esm/index.d.ts +10 -5
  51. package/dist/esm/index.js +10 -3
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/load-matches.js +5 -3
  54. package/dist/esm/load-matches.js.map +1 -1
  55. package/dist/esm/location.d.ts +38 -0
  56. package/dist/esm/path.d.ts +6 -7
  57. package/dist/esm/path.js +27 -64
  58. package/dist/esm/path.js.map +1 -1
  59. package/dist/esm/process-route-tree.d.ts +10 -0
  60. package/dist/esm/process-route-tree.js +144 -0
  61. package/dist/esm/process-route-tree.js.map +1 -0
  62. package/dist/esm/redirect.js +1 -1
  63. package/dist/esm/redirect.js.map +1 -1
  64. package/dist/esm/rewrite.d.ts +22 -0
  65. package/dist/esm/rewrite.js +63 -0
  66. package/dist/esm/rewrite.js.map +1 -0
  67. package/dist/esm/route.d.ts +62 -44
  68. package/dist/esm/route.js.map +1 -1
  69. package/dist/esm/router.d.ts +81 -44
  70. package/dist/esm/router.js +104 -212
  71. package/dist/esm/router.js.map +1 -1
  72. package/dist/esm/scroll-restoration.d.ts +9 -0
  73. package/dist/esm/scroll-restoration.js.map +1 -1
  74. package/dist/esm/ssr/createRequestHandler.js +4 -1
  75. package/dist/esm/ssr/createRequestHandler.js.map +1 -1
  76. package/dist/esm/ssr/serializer/transformer.d.ts +55 -15
  77. package/dist/esm/ssr/serializer/transformer.js +14 -12
  78. package/dist/esm/ssr/serializer/transformer.js.map +1 -1
  79. package/dist/esm/ssr/ssr-client.js.map +1 -1
  80. package/dist/esm/ssr/ssr-server.d.ts +4 -1
  81. package/dist/esm/ssr/ssr-server.js +5 -2
  82. package/dist/esm/ssr/ssr-server.js.map +1 -1
  83. package/dist/esm/utils.js +68 -46
  84. package/dist/esm/utils.js.map +1 -1
  85. package/package.json +2 -2
  86. package/src/Matches.ts +4 -3
  87. package/src/config.ts +42 -0
  88. package/src/fileRoute.ts +25 -3
  89. package/src/index.ts +23 -6
  90. package/src/load-matches.ts +31 -21
  91. package/src/location.ts +38 -0
  92. package/src/path.ts +44 -82
  93. package/src/process-route-tree.ts +233 -0
  94. package/src/redirect.ts +1 -1
  95. package/src/rewrite.ts +70 -0
  96. package/src/route.ts +311 -74
  97. package/src/router.ts +263 -389
  98. package/src/scroll-restoration.ts +1 -1
  99. package/src/ssr/createRequestHandler.ts +4 -1
  100. package/src/ssr/serializer/transformer.ts +168 -31
  101. package/src/ssr/server.ts +6 -0
  102. package/src/ssr/ssr-client.ts +2 -2
  103. package/src/ssr/ssr-server.ts +10 -7
  104. package/src/utils.ts +83 -61
package/src/router.ts CHANGED
@@ -1,10 +1,5 @@
1
1
  import { Store, batch } from '@tanstack/store'
2
- import {
3
- createBrowserHistory,
4
- createMemoryHistory,
5
- parseHref,
6
- } from '@tanstack/history'
7
- import invariant from 'tiny-invariant'
2
+ import { createBrowserHistory, parseHref } from '@tanstack/history'
8
3
  import {
9
4
  createControlledPromise,
10
5
  deepEqual,
@@ -13,19 +8,13 @@ import {
13
8
  last,
14
9
  replaceEqualDeep,
15
10
  } from './utils'
11
+ import { processRouteTree } from './process-route-tree'
16
12
  import {
17
- SEGMENT_TYPE_OPTIONAL_PARAM,
18
- SEGMENT_TYPE_PARAM,
19
- SEGMENT_TYPE_PATHNAME,
20
- SEGMENT_TYPE_WILDCARD,
21
13
  cleanPath,
22
14
  interpolatePath,
23
- joinPaths,
24
15
  matchPathname,
25
- parsePathname,
26
16
  resolvePath,
27
17
  trimPath,
28
- trimPathLeft,
29
18
  trimPathRight,
30
19
  } from './path'
31
20
  import { isNotFound } from './not-found'
@@ -35,7 +24,13 @@ import { rootRouteId } from './root'
35
24
  import { isRedirect, redirect } from './redirect'
36
25
  import { createLRUCache } from './lru-cache'
37
26
  import { loadMatches, loadRouteChunk, routeNeedsPreload } from './load-matches'
38
- import type { ParsePathnameCache, Segment } from './path'
27
+ import {
28
+ composeRewrites,
29
+ executeRewriteInput,
30
+ executeRewriteOutput,
31
+ rewriteBasepath,
32
+ } from './rewrite'
33
+ import type { ParsePathnameCache } from './path'
39
34
  import type { SearchParser, SearchSerializer } from './searchParams'
40
35
  import type { AnyRedirect, ResolvedRedirect } from './redirect'
41
36
  import type {
@@ -46,6 +41,7 @@ import type {
46
41
  } from '@tanstack/history'
47
42
  import type {
48
43
  Awaitable,
44
+ Constrain,
49
45
  ControlledPromise,
50
46
  NoInfer,
51
47
  NonNullableUpdater,
@@ -59,6 +55,7 @@ import type {
59
55
  AnyRouteWithContext,
60
56
  MakeRemountDepsOptionsUnion,
61
57
  RouteContextOptions,
58
+ RouteLike,
62
59
  RouteMask,
63
60
  SearchMiddleware,
64
61
  } from './route'
@@ -84,6 +81,11 @@ import type { Manifest } from './manifest'
84
81
  import type { AnySchema, AnyValidator } from './validators'
85
82
  import type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
86
83
  import type { NotFoundError } from './not-found'
84
+ import type {
85
+ AnySerializationAdapter,
86
+ ValidateSerializableInput,
87
+ } from './ssr/serializer/transformer'
88
+ // import type { AnyRouterConfig } from './config'
87
89
 
88
90
  export type ControllablePromise<T = any> = Promise<T> & {
89
91
  resolve: (value: T) => void
@@ -92,15 +94,30 @@ export type ControllablePromise<T = any> = Promise<T> & {
92
94
 
93
95
  export type InjectedHtmlEntry = Promise<string>
94
96
 
95
- export interface DefaultRegister {
96
- router: AnyRouter
97
+ export interface Register {
98
+ // Lots of things on here like...
99
+ // router
100
+ // config
101
+ // ssr
97
102
  }
98
103
 
99
- export interface Register extends DefaultRegister {
100
- // router: Router
104
+ export type RegisteredRouter<TRegister = Register> = TRegister extends {
105
+ router: infer TRouter
101
106
  }
107
+ ? TRouter
108
+ : AnyRouter
102
109
 
103
- export type RegisteredRouter = Register['router']
110
+ export type RegisteredConfigType<TRegister, TKey> = TRegister extends {
111
+ config: infer TConfig
112
+ }
113
+ ? TConfig extends {
114
+ '~types': infer TTypes
115
+ }
116
+ ? TKey extends keyof TTypes
117
+ ? TTypes[TKey]
118
+ : unknown
119
+ : unknown
120
+ : unknown
104
121
 
105
122
  export type DefaultRemountDepsFn<TRouteTree extends AnyRoute> = (
106
123
  opts: MakeRemountDepsOptionsUnion<TRouteTree>,
@@ -111,13 +128,14 @@ export interface DefaultRouterOptionsExtensions {}
111
128
  export interface RouterOptionsExtensions
112
129
  extends DefaultRouterOptionsExtensions {}
113
130
 
131
+ export type SSROption = boolean | 'data-only'
132
+
114
133
  export interface RouterOptions<
115
134
  TRouteTree extends AnyRoute,
116
135
  TTrailingSlashOption extends TrailingSlashOption,
117
136
  TDefaultStructuralSharingOption extends boolean = false,
118
137
  TRouterHistory extends RouterHistory = RouterHistory,
119
- TDehydrated extends Record<string, any> = Record<string, any>,
120
- TTransformerConfig = any,
138
+ TDehydrated = undefined,
121
139
  > extends RouterOptionsExtensions {
122
140
  /**
123
141
  * The history object that will be used to manage the browser history.
@@ -262,6 +280,18 @@ export interface RouterOptions<
262
280
  /**
263
281
  * The basepath for then entire router. This is useful for mounting a router instance at a subpath.
264
282
  *
283
+ * @deprecated - use `rewrite.input` with the new `rewriteBasepath` utility instead:
284
+ * ```ts
285
+ * const router = createRouter({
286
+ * routeTree,
287
+ * rewrite: rewriteBasepath('/basepath')
288
+ * // Or wrap existing rewrite functionality
289
+ * rewrite: rewriteBasepath('/basepath', {
290
+ * output: ({ url }) => {...},
291
+ * input: ({ url }) => {...},
292
+ * })
293
+ * })
294
+ * ```
265
295
  * @default '/'
266
296
  * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#basepath-property)
267
297
  */
@@ -277,6 +307,9 @@ export interface RouterOptions<
277
307
  * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/router-context)
278
308
  */
279
309
  context?: InferRouterContext<TRouteTree>
310
+
311
+ additionalContext?: any
312
+
280
313
  /**
281
314
  * A function that will be called when the router is dehydrated.
282
315
  *
@@ -285,7 +318,10 @@ export interface RouterOptions<
285
318
  * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
286
319
  * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
287
320
  */
288
- dehydrate?: () => Awaitable<TDehydrated>
321
+ dehydrate?: () => Constrain<
322
+ TDehydrated,
323
+ ValidateSerializableInput<Register, TDehydrated>
324
+ >
289
325
  /**
290
326
  * A function that will be called when the router is hydrated.
291
327
  *
@@ -355,7 +391,7 @@ export interface RouterOptions<
355
391
  *
356
392
  * @default true
357
393
  */
358
- defaultSsr?: boolean | 'data-only'
394
+ defaultSsr?: SSROption
359
395
 
360
396
  search?: {
361
397
  /**
@@ -425,9 +461,50 @@ export interface RouterOptions<
425
461
  */
426
462
  disableGlobalCatchBoundary?: boolean
427
463
 
428
- serializationAdapters?: TTransformerConfig
464
+ serializationAdapters?: ReadonlyArray<AnySerializationAdapter>
465
+ /**
466
+ * Configures how the router will rewrite the location between the actual href and the internal href of the router.
467
+ *
468
+ * @default undefined
469
+ * @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!
470
+ * This is useful for basepath rewriting, shifting data from the origin to the path (for things like )
471
+ */
472
+ rewrite?: LocationRewrite
473
+ origin?: string
474
+ ssr?: {
475
+ nonce?: string
476
+ }
477
+ }
478
+
479
+ export type LocationRewrite = {
480
+ /**
481
+ * A function that will be called to rewrite the URL before it is interpreted by the router from the history instance.
482
+ * Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
483
+ *
484
+ * @default undefined
485
+ */
486
+ input?: LocationRewriteFunction
487
+ /**
488
+ * A function that will be called to rewrite the URL before it is committed to the actual history instance from the router.
489
+ * Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
490
+ *
491
+ * @default undefined
492
+ */
493
+ output?: LocationRewriteFunction
429
494
  }
430
495
 
496
+ /**
497
+ * A function that will be called to rewrite the URL.
498
+ *
499
+ * @param url The URL to rewrite.
500
+ * @returns The rewritten URL (as a URL instance or full href string) or undefined if no rewrite is needed.
501
+ */
502
+ export type LocationRewriteFunction = ({
503
+ url,
504
+ }: {
505
+ url: URL
506
+ }) => undefined | string | URL
507
+
431
508
  export interface RouterState<
432
509
  in out TRouteTree extends AnyRoute = AnyRoute,
433
510
  in out TRouteMatch = MakeRouteMatchUnion,
@@ -534,17 +611,15 @@ export type RouterConstructorOptions<
534
611
  TDefaultStructuralSharingOption extends boolean,
535
612
  TRouterHistory extends RouterHistory,
536
613
  TDehydrated extends Record<string, any>,
537
- TTransformerConfig,
538
614
  > = Omit<
539
615
  RouterOptions<
540
616
  TRouteTree,
541
617
  TTrailingSlashOption,
542
618
  TDefaultStructuralSharingOption,
543
619
  TRouterHistory,
544
- TDehydrated,
545
- TTransformerConfig
620
+ TDehydrated
546
621
  >,
547
- 'context'
622
+ 'context' | 'serializationAdapters' | 'defaultSsr'
548
623
  > &
549
624
  RouterContextOptions<TRouteTree>
550
625
 
@@ -602,15 +677,13 @@ export type UpdateFn<
602
677
  TDefaultStructuralSharingOption extends boolean,
603
678
  TRouterHistory extends RouterHistory,
604
679
  TDehydrated extends Record<string, any>,
605
- TTransformerConfig extends any,
606
680
  > = (
607
681
  newOptions: RouterConstructorOptions<
608
682
  TRouteTree,
609
683
  TTrailingSlashOption,
610
684
  TDefaultStructuralSharingOption,
611
685
  TRouterHistory,
612
- TDehydrated,
613
- TTransformerConfig
686
+ TDehydrated
614
687
  >,
615
688
  ) => void
616
689
 
@@ -621,8 +694,8 @@ export type InvalidateFn<TRouter extends AnyRouter> = (opts?: {
621
694
  }) => Promise<void>
622
695
 
623
696
  export type ParseLocationFn<TRouteTree extends AnyRoute> = (
697
+ locationToParse: HistoryLocation,
624
698
  previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>,
625
- locationToParse?: HistoryLocation,
626
699
  ) => ParsedLocation<FullSearchSchema<TRouteTree>>
627
700
 
628
701
  export type GetMatchRoutesFn = (
@@ -695,11 +768,10 @@ export type AnyRouterWithContext<TContext> = RouterCore<
695
768
  any,
696
769
  any,
697
770
  any,
698
- any,
699
771
  any
700
772
  >
701
773
 
702
- export type AnyRouter = RouterCore<any, any, any, any, any, any>
774
+ export type AnyRouter = RouterCore<any, any, any, any, any>
703
775
 
704
776
  export interface ViewTransitionOptions {
705
777
  types:
@@ -753,7 +825,6 @@ export type CreateRouterFn = <
753
825
  TDefaultStructuralSharingOption extends boolean = false,
754
826
  TRouterHistory extends RouterHistory = RouterHistory,
755
827
  TDehydrated extends Record<string, any> = Record<string, any>,
756
- TTransformerConfig = any,
757
828
  >(
758
829
  options: undefined extends number
759
830
  ? 'strictNullChecks must be enabled in tsconfig.json'
@@ -762,16 +833,14 @@ export type CreateRouterFn = <
762
833
  TTrailingSlashOption,
763
834
  TDefaultStructuralSharingOption,
764
835
  TRouterHistory,
765
- TDehydrated,
766
- TTransformerConfig
836
+ TDehydrated
767
837
  >,
768
838
  ) => RouterCore<
769
839
  TRouteTree,
770
840
  TTrailingSlashOption,
771
841
  TDefaultStructuralSharingOption,
772
842
  TRouterHistory,
773
- TDehydrated,
774
- TTransformerConfig
843
+ TDehydrated
775
844
  >
776
845
 
777
846
  export class RouterCore<
@@ -780,7 +849,6 @@ export class RouterCore<
780
849
  in out TDefaultStructuralSharingOption extends boolean,
781
850
  in out TRouterHistory extends RouterHistory = RouterHistory,
782
851
  in out TDehydrated extends Record<string, any> = Record<string, any>,
783
- in out TTransformerConfig = any,
784
852
  > {
785
853
  // Option-independent properties
786
854
  tempLocationKey: string | undefined = `${Math.round(
@@ -802,13 +870,15 @@ export class RouterCore<
802
870
  TTrailingSlashOption,
803
871
  TDefaultStructuralSharingOption,
804
872
  TRouterHistory,
805
- TDehydrated,
806
- TTransformerConfig
873
+ TDehydrated
807
874
  >,
808
875
  'stringifySearch' | 'parseSearch' | 'context'
809
876
  >
810
877
  history!: TRouterHistory
878
+ rewrite?: LocationRewrite
879
+ origin?: string
811
880
  latestLocation!: ParsedLocation<FullSearchSchema<TRouteTree>>
881
+ // @deprecated - basepath functionality is now implemented via the `rewrite` option
812
882
  basepath!: string
813
883
  routeTree!: TRouteTree
814
884
  routesById!: RoutesById<TRouteTree>
@@ -826,8 +896,7 @@ export class RouterCore<
826
896
  TTrailingSlashOption,
827
897
  TDefaultStructuralSharingOption,
828
898
  TRouterHistory,
829
- TDehydrated,
830
- TTransformerConfig
899
+ TDehydrated
831
900
  >,
832
901
  ) {
833
902
  this.update({
@@ -865,8 +934,7 @@ export class RouterCore<
865
934
  TTrailingSlashOption,
866
935
  TDefaultStructuralSharingOption,
867
936
  TRouterHistory,
868
- TDehydrated,
869
- TTransformerConfig
937
+ TDehydrated
870
938
  > = (newOptions) => {
871
939
  if (newOptions.notFoundRoute) {
872
940
  console.warn(
@@ -874,7 +942,6 @@ export class RouterCore<
874
942
  )
875
943
  }
876
944
 
877
- const previousOptions = this.options
878
945
  this.options = {
879
946
  ...this.options,
880
947
  ...newOptions,
@@ -892,32 +959,42 @@ export class RouterCore<
892
959
  : undefined
893
960
 
894
961
  if (
895
- !this.basepath ||
896
- (newOptions.basepath && newOptions.basepath !== previousOptions.basepath)
962
+ !this.history ||
963
+ (this.options.history && this.options.history !== this.history)
897
964
  ) {
898
- if (
899
- newOptions.basepath === undefined ||
900
- newOptions.basepath === '' ||
901
- newOptions.basepath === '/'
902
- ) {
903
- this.basepath = '/'
965
+ if (!this.options.history) {
966
+ if (!this.isServer) {
967
+ this.history = createBrowserHistory() as TRouterHistory
968
+ }
969
+ } else {
970
+ this.history = this.options.history
971
+ }
972
+ }
973
+ // For backwards compatibility, we support a basepath option, which we now implement as a rewrite
974
+ if (this.options.basepath) {
975
+ const basepathRewrite = rewriteBasepath({
976
+ basepath: this.options.basepath,
977
+ })
978
+ if (this.options.rewrite) {
979
+ this.rewrite = composeRewrites([basepathRewrite, this.options.rewrite])
904
980
  } else {
905
- this.basepath = `/${trimPath(newOptions.basepath)}`
981
+ this.rewrite = basepathRewrite
906
982
  }
983
+ } else {
984
+ this.rewrite = this.options.rewrite
907
985
  }
908
986
 
909
- if (
910
- !this.history ||
911
- (this.options.history && this.options.history !== this.history)
912
- ) {
913
- this.history =
914
- this.options.history ??
915
- ((this.isServer
916
- ? createMemoryHistory({
917
- initialEntries: [this.basepath || '/'],
918
- })
919
- : createBrowserHistory()) as TRouterHistory)
920
- this.latestLocation = this.parseLocation()
987
+ this.origin = this.options.origin
988
+ if (!this.origin) {
989
+ if (!this.isServer) {
990
+ this.origin = window.origin
991
+ } else {
992
+ // fallback for the server, can be overridden by calling router.update({origin}) on the server
993
+ this.origin = 'http://localhost'
994
+ }
995
+ }
996
+ if (this.history) {
997
+ this.updateLatestLocation()
921
998
  }
922
999
 
923
1000
  if (this.options.routeTree !== this.routeTree) {
@@ -925,7 +1002,7 @@ export class RouterCore<
925
1002
  this.buildRouteTree()
926
1003
  }
927
1004
 
928
- if (!this.__store) {
1005
+ if (!this.__store && this.latestLocation) {
929
1006
  this.__store = new Store(getInitialRouterState(this.latestLocation), {
930
1007
  onUpdate: () => {
931
1008
  this.__store.state = {
@@ -955,6 +1032,13 @@ export class RouterCore<
955
1032
  return this.__store.state
956
1033
  }
957
1034
 
1035
+ updateLatestLocation = () => {
1036
+ this.latestLocation = this.parseLocation(
1037
+ this.history.location,
1038
+ this.latestLocation,
1039
+ )
1040
+ }
1041
+
958
1042
  buildRouteTree = () => {
959
1043
  const { routesById, routesByPath, flatRoutes } = processRouteTree({
960
1044
  routeTree: this.routeTree,
@@ -1001,29 +1085,41 @@ export class RouterCore<
1001
1085
  }
1002
1086
 
1003
1087
  parseLocation: ParseLocationFn<TRouteTree> = (
1004
- previousLocation,
1005
1088
  locationToParse,
1089
+ previousLocation,
1006
1090
  ) => {
1007
1091
  const parse = ({
1008
- pathname,
1009
- search,
1010
- hash,
1092
+ href,
1011
1093
  state,
1012
1094
  }: HistoryLocation): ParsedLocation<FullSearchSchema<TRouteTree>> => {
1013
- const parsedSearch = this.options.parseSearch(search)
1095
+ // Before we do any processing, we need to allow rewrites to modify the URL
1096
+ // build up the full URL by combining the href from history with the router's origin
1097
+ const fullUrl = new URL(href, this.origin)
1098
+ const url = executeRewriteInput(this.rewrite, fullUrl)
1099
+
1100
+ const parsedSearch = this.options.parseSearch(url.search)
1014
1101
  const searchStr = this.options.stringifySearch(parsedSearch)
1102
+ // Make sure our final url uses the re-stringified pathname, search, and has for consistency
1103
+ // (We were already doing this, so just keeping it for now)
1104
+ url.search = searchStr
1105
+
1106
+ const fullPath = url.href.replace(url.origin, '')
1107
+
1108
+ const { pathname, hash } = url
1015
1109
 
1016
1110
  return {
1111
+ href: fullPath,
1112
+ publicHref: href,
1113
+ url: url.href,
1017
1114
  pathname,
1018
1115
  searchStr,
1019
1116
  search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
1020
1117
  hash: hash.split('#').reverse()[0] ?? '',
1021
- href: `${pathname}${searchStr}${hash}`,
1022
1118
  state: replaceEqualDeep(previousLocation?.state, state),
1023
1119
  }
1024
1120
  }
1025
1121
 
1026
- const location = parse(locationToParse ?? this.history.location)
1122
+ const location = parse(locationToParse)
1027
1123
 
1028
1124
  const { __tempLocation, __tempKey } = location.state
1029
1125
 
@@ -1046,11 +1142,9 @@ export class RouterCore<
1046
1142
 
1047
1143
  resolvePathWithBase = (from: string, path: string) => {
1048
1144
  const resolvedPath = resolvePath({
1049
- basepath: this.basepath,
1050
1145
  base: from,
1051
1146
  to: cleanPath(path),
1052
1147
  trailingSlash: this.options.trailingSlash,
1053
- caseSensitive: this.options.caseSensitive,
1054
1148
  parseCache: this.parsePathnameCache,
1055
1149
  })
1056
1150
  return resolvedPath
@@ -1122,33 +1216,6 @@ export class RouterCore<
1122
1216
  return rootRouteId
1123
1217
  })()
1124
1218
 
1125
- const parseErrors = matchedRoutes.map((route) => {
1126
- let parsedParamsError
1127
-
1128
- const parseParams =
1129
- route.options.params?.parse ?? route.options.parseParams
1130
-
1131
- if (parseParams) {
1132
- try {
1133
- const parsedParams = parseParams(routeParams)
1134
- // Add the parsed params to the accumulated params bag
1135
- Object.assign(routeParams, parsedParams)
1136
- } catch (err: any) {
1137
- parsedParamsError = new PathParamError(err.message, {
1138
- cause: err,
1139
- })
1140
-
1141
- if (opts?.throwOnError) {
1142
- throw parsedParamsError
1143
- }
1144
-
1145
- return parsedParamsError
1146
- }
1147
- }
1148
-
1149
- return
1150
- })
1151
-
1152
1219
  const matches: Array<AnyRouteMatch> = []
1153
1220
 
1154
1221
  const getParentContext = (parentMatch?: AnyRouteMatch) => {
@@ -1221,12 +1288,18 @@ export class RouterCore<
1221
1288
 
1222
1289
  const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : ''
1223
1290
 
1224
- const { usedParams, interpolatedPath } = interpolatePath({
1291
+ const { interpolatedPath, usedParams } = interpolatePath({
1225
1292
  path: route.fullPath,
1226
1293
  params: routeParams,
1227
1294
  decodeCharMap: this.pathParamsDecodeCharMap,
1228
1295
  })
1229
1296
 
1297
+ // Waste not, want not. If we already have a match for this route,
1298
+ // reuse it. This is important for layout routes, which might stick
1299
+ // around between navigation actions that only change leaf routes.
1300
+
1301
+ // Existing matches are matches that are already loaded along with
1302
+ // pending matches that are still loading
1230
1303
  const matchId =
1231
1304
  interpolatePath({
1232
1305
  path: route.id,
@@ -1236,18 +1309,40 @@ export class RouterCore<
1236
1309
  parseCache: this.parsePathnameCache,
1237
1310
  }).interpolatedPath + loaderDepsHash
1238
1311
 
1239
- // Waste not, want not. If we already have a match for this route,
1240
- // reuse it. This is important for layout routes, which might stick
1241
- // around between navigation actions that only change leaf routes.
1242
-
1243
- // Existing matches are matches that are already loaded along with
1244
- // pending matches that are still loading
1245
1312
  const existingMatch = this.getMatch(matchId)
1246
1313
 
1247
1314
  const previousMatch = this.state.matches.find(
1248
1315
  (d) => d.routeId === route.id,
1249
1316
  )
1250
1317
 
1318
+ const strictParams = existingMatch?._strictParams ?? usedParams
1319
+
1320
+ let paramsError: PathParamError | undefined = undefined
1321
+
1322
+ if (!existingMatch) {
1323
+ const strictParseParams =
1324
+ route.options.params?.parse ?? route.options.parseParams
1325
+
1326
+ if (strictParseParams) {
1327
+ try {
1328
+ Object.assign(
1329
+ strictParams,
1330
+ strictParseParams(strictParams as Record<string, string>),
1331
+ )
1332
+ } catch (err: any) {
1333
+ paramsError = new PathParamError(err.message, {
1334
+ cause: err,
1335
+ })
1336
+
1337
+ if (opts?.throwOnError) {
1338
+ throw paramsError
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1343
+
1344
+ Object.assign(routeParams, strictParams)
1345
+
1251
1346
  const cause = previousMatch ? 'stay' : 'enter'
1252
1347
 
1253
1348
  let match: AnyRouteMatch
@@ -1259,7 +1354,7 @@ export class RouterCore<
1259
1354
  params: previousMatch
1260
1355
  ? replaceEqualDeep(previousMatch.params, routeParams)
1261
1356
  : routeParams,
1262
- _strictParams: usedParams,
1357
+ _strictParams: strictParams,
1263
1358
  search: previousMatch
1264
1359
  ? replaceEqualDeep(previousMatch.search, preMatchSearch)
1265
1360
  : replaceEqualDeep(existingMatch.search, preMatchSearch),
@@ -1281,8 +1376,8 @@ export class RouterCore<
1281
1376
  params: previousMatch
1282
1377
  ? replaceEqualDeep(previousMatch.params, routeParams)
1283
1378
  : routeParams,
1284
- _strictParams: usedParams,
1285
- pathname: joinPaths([this.basepath, interpolatedPath]),
1379
+ _strictParams: strictParams,
1380
+ pathname: interpolatedPath,
1286
1381
  updatedAt: Date.now(),
1287
1382
  search: previousMatch
1288
1383
  ? replaceEqualDeep(previousMatch.search, preMatchSearch)
@@ -1292,7 +1387,7 @@ export class RouterCore<
1292
1387
  status,
1293
1388
  isFetching: false,
1294
1389
  error: undefined,
1295
- paramsError: parseErrors[index],
1390
+ paramsError,
1296
1391
  __routeContext: undefined,
1297
1392
  _nonReactive: {
1298
1393
  loadPromise: createControlledPromise(),
@@ -1387,7 +1482,6 @@ export class RouterCore<
1387
1482
  return getMatchedRoutes({
1388
1483
  pathname,
1389
1484
  routePathname,
1390
- basepath: this.basepath,
1391
1485
  caseSensitive: this.options.caseSensitive,
1392
1486
  routesByPath: this.routesByPath,
1393
1487
  routesById: this.routesById,
@@ -1425,50 +1519,44 @@ export class RouterCore<
1425
1519
  _buildLocation: true,
1426
1520
  })
1427
1521
 
1522
+ // Now let's find the starting pathname
1523
+ // This should default to the current location if no from is provided
1428
1524
  const lastMatch = last(allCurrentLocationMatches)!
1429
1525
 
1430
- // First let's find the starting pathname
1431
- // By default, start with the current location
1432
- let fromPath = this.resolvePathWithBase(lastMatch.fullPath, '.')
1433
- const toPath = dest.to
1434
- ? this.resolvePathWithBase(fromPath, `${dest.to}`)
1435
- : this.resolvePathWithBase(fromPath, '.')
1436
-
1437
- const routeIsChanging =
1438
- !!dest.to &&
1439
- !comparePaths(dest.to.toString(), fromPath) &&
1440
- !comparePaths(toPath, fromPath)
1441
-
1442
- // If the route is changing we need to find the relative fromPath
1443
- if (dest.unsafeRelative === 'path') {
1444
- fromPath = currentLocation.pathname
1445
- } else if (routeIsChanging && dest.from) {
1446
- fromPath = dest.from
1447
-
1448
- // do this check only on navigations during test or development
1449
- if (process.env.NODE_ENV !== 'production' && dest._isNavigate) {
1450
- const allFromMatches = this.getMatchedRoutes(
1451
- dest.from,
1452
- undefined,
1453
- ).matchedRoutes
1526
+ // check that from path exists in the current route tree
1527
+ // do this check only on navigations during test or development
1528
+ if (
1529
+ dest.from &&
1530
+ process.env.NODE_ENV !== 'production' &&
1531
+ dest._isNavigate
1532
+ ) {
1533
+ const allFromMatches = this.getMatchedRoutes(
1534
+ dest.from,
1535
+ undefined,
1536
+ ).matchedRoutes
1454
1537
 
1455
- const matchedFrom = findLast(allCurrentLocationMatches, (d) => {
1456
- return comparePaths(d.fullPath, fromPath)
1457
- })
1538
+ const matchedFrom = findLast(allCurrentLocationMatches, (d) => {
1539
+ return comparePaths(d.fullPath, dest.from!)
1540
+ })
1458
1541
 
1459
- const matchedCurrent = findLast(allFromMatches, (d) => {
1460
- return comparePaths(d.fullPath, currentLocation.pathname)
1461
- })
1542
+ const matchedCurrent = findLast(allFromMatches, (d) => {
1543
+ return comparePaths(d.fullPath, lastMatch.fullPath)
1544
+ })
1462
1545
 
1463
- // for from to be invalid it shouldn't just be unmatched to currentLocation
1464
- // but the currentLocation should also be unmatched to from
1465
- if (!matchedFrom && !matchedCurrent) {
1466
- console.warn(`Could not find match for from: ${fromPath}`)
1467
- }
1546
+ // for from to be invalid it shouldn't just be unmatched to currentLocation
1547
+ // but the currentLocation should also be unmatched to from
1548
+ if (!matchedFrom && !matchedCurrent) {
1549
+ console.warn(`Could not find match for from: ${dest.from}`)
1468
1550
  }
1469
1551
  }
1470
1552
 
1471
- fromPath = this.resolvePathWithBase(fromPath, '.')
1553
+ const defaultedFromPath =
1554
+ dest.unsafeRelative === 'path'
1555
+ ? currentLocation.pathname
1556
+ : (dest.from ?? lastMatch.fullPath)
1557
+
1558
+ // ensure this includes the basePath if set
1559
+ const fromPath = this.resolvePathWithBase(defaultedFromPath, '.')
1472
1560
 
1473
1561
  // From search should always use the current location
1474
1562
  const fromSearch = lastMatch.search
@@ -1476,6 +1564,7 @@ export class RouterCore<
1476
1564
  const fromParams = { ...lastMatch.params }
1477
1565
 
1478
1566
  // Resolve the next to
1567
+ // ensure this includes the basePath if set
1479
1568
  const nextTo = dest.to
1480
1569
  ? this.resolvePathWithBase(fromPath, `${dest.to}`)
1481
1570
  : this.resolvePathWithBase(fromPath, '.')
@@ -1581,14 +1670,25 @@ export class RouterCore<
1581
1670
  // Replace the equal deep
1582
1671
  nextState = replaceEqualDeep(currentLocation.state, nextState)
1583
1672
 
1584
- // Return the next location
1673
+ // Create the full path of the location
1674
+ const fullPath = `${nextPathname}${searchStr}${hashStr}`
1675
+
1676
+ // Create the new href with full origin
1677
+ const url = new URL(fullPath, this.origin)
1678
+
1679
+ // If a rewrite function is provided, use it to rewrite the URL
1680
+ const rewrittenUrl = executeRewriteOutput(this.rewrite, url)
1681
+
1585
1682
  return {
1683
+ publicHref:
1684
+ rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
1685
+ href: fullPath,
1686
+ url: rewrittenUrl.href,
1586
1687
  pathname: nextPathname,
1587
1688
  search: nextSearch,
1588
1689
  searchStr,
1589
1690
  state: nextState as any,
1590
1691
  hash: hash ?? '',
1591
- href: `${nextPathname}${searchStr}${hashStr}`,
1592
1692
  unmaskOnReload: dest.unmaskOnReload,
1593
1693
  }
1594
1694
  }
@@ -1606,7 +1706,6 @@ export class RouterCore<
1606
1706
 
1607
1707
  const foundMask = this.options.routeMasks?.find((d) => {
1608
1708
  const match = matchPathname(
1609
- this.basepath,
1610
1709
  next.pathname,
1611
1710
  {
1612
1711
  to: d.from,
@@ -1636,8 +1735,7 @@ export class RouterCore<
1636
1735
  }
1637
1736
 
1638
1737
  if (maskedNext) {
1639
- const maskedFinal = build(maskedDest)
1640
- next.maskedLocation = maskedFinal
1738
+ next.maskedLocation = maskedNext
1641
1739
  }
1642
1740
 
1643
1741
  return next
@@ -1680,7 +1778,8 @@ export class RouterCore<
1680
1778
  return isEqual
1681
1779
  }
1682
1780
 
1683
- const isSameUrl = this.latestLocation.href === next.href
1781
+ const isSameUrl =
1782
+ trimPathRight(this.latestLocation.href) === trimPathRight(next.href)
1684
1783
 
1685
1784
  const previousCommitPromise = this.commitLocationPromise
1686
1785
  this.commitLocationPromise = createControlledPromise<void>(() => {
@@ -1729,7 +1828,7 @@ export class RouterCore<
1729
1828
  this.shouldViewTransition = viewTransition
1730
1829
 
1731
1830
  this.history[next.replace ? 'replace' : 'push'](
1732
- nextHistory.href,
1831
+ nextHistory.publicHref,
1733
1832
  nextHistory.state,
1734
1833
  { ignoreBlocker },
1735
1834
  )
@@ -1791,7 +1890,7 @@ export class RouterCore<
1791
1890
  if (reloadDocument) {
1792
1891
  if (!href) {
1793
1892
  const location = this.buildLocation({ to, ...rest } as any)
1794
- href = this.history.createHref(location.href)
1893
+ href = location.href
1795
1894
  }
1796
1895
  if (rest.replace) {
1797
1896
  window.location.replace(href)
@@ -1814,7 +1913,7 @@ export class RouterCore<
1814
1913
  beforeLoad = () => {
1815
1914
  // Cancel any pending matches
1816
1915
  this.cancelMatches()
1817
- this.latestLocation = this.parseLocation(this.latestLocation)
1916
+ this.updateLatestLocation()
1818
1917
 
1819
1918
  if (this.isServer) {
1820
1919
  // for SPAs on the initial load, this is handled by the Transitioner
@@ -1844,6 +1943,7 @@ export class RouterCore<
1844
1943
  throw redirect({ href: nextLocation.href })
1845
1944
  }
1846
1945
  }
1946
+
1847
1947
  // Match the routes
1848
1948
  const pendingMatches = this.matchRoutes(this.latestLocation)
1849
1949
 
@@ -1989,6 +2089,7 @@ export class RouterCore<
1989
2089
  this.latestLoadPromise = undefined
1990
2090
  this.commitLocationPromise = undefined
1991
2091
  }
2092
+
1992
2093
  resolve()
1993
2094
  })
1994
2095
  })
@@ -2287,7 +2388,6 @@ export class RouterCore<
2287
2388
  : this.state.resolvedLocation || this.state.location
2288
2389
 
2289
2390
  const match = matchPathname(
2290
- this.basepath,
2291
2391
  baseLocation.pathname,
2292
2392
  {
2293
2393
  ...opts,
@@ -2397,233 +2497,9 @@ function validateSearch(validateSearch: AnyValidator, input: unknown): unknown {
2397
2497
  return {}
2398
2498
  }
2399
2499
 
2400
- interface RouteLike {
2401
- id: string
2402
- isRoot?: boolean
2403
- path?: string
2404
- fullPath: string
2405
- rank?: number
2406
- parentRoute?: RouteLike
2407
- children?: Array<RouteLike>
2408
- options?: {
2409
- caseSensitive?: boolean
2410
- }
2411
- }
2412
-
2413
- export type ProcessRouteTreeResult<TRouteLike extends RouteLike> = {
2414
- routesById: Record<string, TRouteLike>
2415
- routesByPath: Record<string, TRouteLike>
2416
- flatRoutes: Array<TRouteLike>
2417
- }
2418
-
2419
- const REQUIRED_PARAM_BASE_SCORE = 0.5
2420
- const OPTIONAL_PARAM_BASE_SCORE = 0.4
2421
- const WILDCARD_PARAM_BASE_SCORE = 0.25
2422
- const BOTH_PRESENCE_BASE_SCORE = 0.05
2423
- const PREFIX_PRESENCE_BASE_SCORE = 0.02
2424
- const SUFFIX_PRESENCE_BASE_SCORE = 0.01
2425
- const PREFIX_LENGTH_SCORE_MULTIPLIER = 0.0002
2426
- const SUFFIX_LENGTH_SCORE_MULTIPLIER = 0.0001
2427
-
2428
- function handleParam(segment: Segment, baseScore: number) {
2429
- if (segment.prefixSegment && segment.suffixSegment) {
2430
- return (
2431
- baseScore +
2432
- BOTH_PRESENCE_BASE_SCORE +
2433
- PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length +
2434
- SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length
2435
- )
2436
- }
2437
-
2438
- if (segment.prefixSegment) {
2439
- return (
2440
- baseScore +
2441
- PREFIX_PRESENCE_BASE_SCORE +
2442
- PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length
2443
- )
2444
- }
2445
-
2446
- if (segment.suffixSegment) {
2447
- return (
2448
- baseScore +
2449
- SUFFIX_PRESENCE_BASE_SCORE +
2450
- SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length
2451
- )
2452
- }
2453
-
2454
- return baseScore
2455
- }
2456
-
2457
- export function processRouteTree<TRouteLike extends RouteLike>({
2458
- routeTree,
2459
- initRoute,
2460
- }: {
2461
- routeTree: TRouteLike
2462
- initRoute?: (route: TRouteLike, index: number) => void
2463
- }): ProcessRouteTreeResult<TRouteLike> {
2464
- const routesById = {} as Record<string, TRouteLike>
2465
- const routesByPath = {} as Record<string, TRouteLike>
2466
-
2467
- const recurseRoutes = (childRoutes: Array<TRouteLike>) => {
2468
- childRoutes.forEach((childRoute, i) => {
2469
- initRoute?.(childRoute, i)
2470
-
2471
- const existingRoute = routesById[childRoute.id]
2472
-
2473
- invariant(
2474
- !existingRoute,
2475
- `Duplicate routes found with id: ${String(childRoute.id)}`,
2476
- )
2477
-
2478
- routesById[childRoute.id] = childRoute
2479
-
2480
- if (!childRoute.isRoot && childRoute.path) {
2481
- const trimmedFullPath = trimPathRight(childRoute.fullPath)
2482
- if (
2483
- !routesByPath[trimmedFullPath] ||
2484
- childRoute.fullPath.endsWith('/')
2485
- ) {
2486
- routesByPath[trimmedFullPath] = childRoute
2487
- }
2488
- }
2489
-
2490
- const children = childRoute.children as Array<TRouteLike>
2491
-
2492
- if (children?.length) {
2493
- recurseRoutes(children)
2494
- }
2495
- })
2496
- }
2497
-
2498
- recurseRoutes([routeTree])
2499
-
2500
- const scoredRoutes: Array<{
2501
- child: TRouteLike
2502
- trimmed: string
2503
- parsed: ReadonlyArray<Segment>
2504
- index: number
2505
- scores: Array<number>
2506
- hasStaticAfter: boolean
2507
- optionalParamCount: number
2508
- }> = []
2509
-
2510
- const routes: Array<TRouteLike> = Object.values(routesById)
2511
-
2512
- routes.forEach((d, i) => {
2513
- if (d.isRoot || !d.path) {
2514
- return
2515
- }
2516
-
2517
- const trimmed = trimPathLeft(d.fullPath)
2518
- let parsed = parsePathname(trimmed)
2519
-
2520
- // Removes the leading slash if it is not the only remaining segment
2521
- let skip = 0
2522
- while (parsed.length > skip + 1 && parsed[skip]?.value === '/') {
2523
- skip++
2524
- }
2525
- if (skip > 0) parsed = parsed.slice(skip)
2526
-
2527
- let optionalParamCount = 0
2528
- let hasStaticAfter = false
2529
- const scores = parsed.map((segment, index) => {
2530
- if (segment.value === '/') {
2531
- return 0.75
2532
- }
2533
-
2534
- let baseScore: number | undefined = undefined
2535
- if (segment.type === SEGMENT_TYPE_PARAM) {
2536
- baseScore = REQUIRED_PARAM_BASE_SCORE
2537
- } else if (segment.type === SEGMENT_TYPE_OPTIONAL_PARAM) {
2538
- baseScore = OPTIONAL_PARAM_BASE_SCORE
2539
- optionalParamCount++
2540
- } else if (segment.type === SEGMENT_TYPE_WILDCARD) {
2541
- baseScore = WILDCARD_PARAM_BASE_SCORE
2542
- }
2543
-
2544
- if (baseScore) {
2545
- // if there is any static segment (that is not an index) after a required / optional param,
2546
- // we will boost this param so it ranks higher than a required/optional param without a static segment after it
2547
- // JUST FOR SORTING, NOT FOR MATCHING
2548
- for (let i = index + 1; i < parsed.length; i++) {
2549
- const nextSegment = parsed[i]!
2550
- if (
2551
- nextSegment.type === SEGMENT_TYPE_PATHNAME &&
2552
- nextSegment.value !== '/'
2553
- ) {
2554
- hasStaticAfter = true
2555
- return handleParam(segment, baseScore + 0.2)
2556
- }
2557
- }
2558
-
2559
- return handleParam(segment, baseScore)
2560
- }
2561
-
2562
- return 1
2563
- })
2564
-
2565
- scoredRoutes.push({
2566
- child: d,
2567
- trimmed,
2568
- parsed,
2569
- index: i,
2570
- scores,
2571
- optionalParamCount,
2572
- hasStaticAfter,
2573
- })
2574
- })
2575
-
2576
- const flatRoutes = scoredRoutes
2577
- .sort((a, b) => {
2578
- const minLength = Math.min(a.scores.length, b.scores.length)
2579
-
2580
- // Sort by segment-by-segment score comparison ONLY for the common prefix
2581
- for (let i = 0; i < minLength; i++) {
2582
- if (a.scores[i] !== b.scores[i]) {
2583
- return b.scores[i]! - a.scores[i]!
2584
- }
2585
- }
2586
-
2587
- // If all common segments have equal scores, then consider length and specificity
2588
- if (a.scores.length !== b.scores.length) {
2589
- // If different number of optional parameters, fewer optional parameters wins (more specific)
2590
- // only if both or none of the routes has static segments after the params
2591
- if (a.optionalParamCount !== b.optionalParamCount) {
2592
- if (a.hasStaticAfter === b.hasStaticAfter) {
2593
- return a.optionalParamCount - b.optionalParamCount
2594
- } else if (a.hasStaticAfter && !b.hasStaticAfter) {
2595
- return -1
2596
- } else if (!a.hasStaticAfter && b.hasStaticAfter) {
2597
- return 1
2598
- }
2599
- }
2600
-
2601
- // If same number of optional parameters, longer path wins (for static segments)
2602
- return b.scores.length - a.scores.length
2603
- }
2604
-
2605
- // Sort by min available parsed value for alphabetical ordering
2606
- for (let i = 0; i < minLength; i++) {
2607
- if (a.parsed[i]!.value !== b.parsed[i]!.value) {
2608
- return a.parsed[i]!.value > b.parsed[i]!.value ? 1 : -1
2609
- }
2610
- }
2611
-
2612
- // Sort by original index
2613
- return a.index - b.index
2614
- })
2615
- .map((d, i) => {
2616
- d.child.rank = i
2617
- return d.child
2618
- })
2619
-
2620
- return { routesById, routesByPath, flatRoutes }
2621
- }
2622
-
2623
2500
  export function getMatchedRoutes<TRouteLike extends RouteLike>({
2624
2501
  pathname,
2625
2502
  routePathname,
2626
- basepath,
2627
2503
  caseSensitive,
2628
2504
  routesByPath,
2629
2505
  routesById,
@@ -2632,7 +2508,6 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
2632
2508
  }: {
2633
2509
  pathname: string
2634
2510
  routePathname?: string
2635
- basepath: string
2636
2511
  caseSensitive?: boolean
2637
2512
  routesByPath: Record<string, TRouteLike>
2638
2513
  routesById: Record<string, TRouteLike>
@@ -2643,7 +2518,6 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
2643
2518
  const trimmedPath = trimPathRight(pathname)
2644
2519
  const getMatchedParams = (route: TRouteLike) => {
2645
2520
  const result = matchPathname(
2646
- basepath,
2647
2521
  trimmedPath,
2648
2522
  {
2649
2523
  to: route.fullPath,