@tanstack/router-core 0.0.1-beta.192 → 0.0.1-beta.193

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/src/routeInfo.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AnyRoute, Route } from './route'
2
- import { UnionToIntersection } from './utils'
2
+ import { Expand, UnionToIntersection } from './utils'
3
3
 
4
4
  export type ParseRoute<TRouteTree extends AnyRoute> =
5
5
  | TRouteTree
@@ -22,6 +22,7 @@ export type ParseRouteChildren<TRouteTree extends AnyRoute> =
22
22
  any,
23
23
  any,
24
24
  any,
25
+ any,
25
26
  infer TChildren,
26
27
  any
27
28
  >
@@ -60,10 +61,14 @@ export type RoutePaths<TRouteTree extends AnyRoute> =
60
61
  | ParseRoute<TRouteTree>['fullPath']
61
62
  | '/'
62
63
 
63
- export type FullSearchSchema<TRouteTree extends AnyRoute> = UnionToIntersection<
64
- ParseRoute<TRouteTree>['types']['fullSearchSchema']
65
- > & {}
64
+ export type FullSearchSchema<TRouteTree extends AnyRoute> = Partial<
65
+ Expand<
66
+ UnionToIntersection<
67
+ ParseRoute<TRouteTree>['types']['fullSearchSchema']
68
+ > & {}
69
+ >
70
+ >
66
71
 
67
- export type AllParams<TRouteTree extends AnyRoute> = UnionToIntersection<
68
- ParseRoute<TRouteTree>['types']['allParams']
72
+ export type AllParams<TRouteTree extends AnyRoute> = Expand<
73
+ UnionToIntersection<ParseRoute<TRouteTree>['types']['allParams']>
69
74
  >
package/src/router.ts CHANGED
@@ -113,7 +113,8 @@ export interface RouteMatch<
113
113
  TRouteId extends RouteIds<TRouteTree> = ParseRoute<TRouteTree>['id'],
114
114
  > {
115
115
  id: string
116
- key?: string
116
+ // loaderContext?: RouteById<TRouteTree, TRouteId>['types']['loaderContext']
117
+ loaderContext?: any
117
118
  routeId: TRouteId
118
119
  pathname: string
119
120
  params: RouteById<TRouteTree, TRouteId>['types']['allParams']
@@ -129,7 +130,6 @@ export interface RouteMatch<
129
130
  loaderData: RouteById<TRouteTree, TRouteId>['types']['loader']
130
131
  loadPromise?: Promise<void>
131
132
  __resolveLoadPromise?: () => void
132
- routeContext: RouteById<TRouteTree, TRouteId>['types']['routeContext']
133
133
  context: RouteById<TRouteTree, TRouteId>['types']['context']
134
134
  routeSearch: RouteById<TRouteTree, TRouteId>['types']['searchSchema']
135
135
  search: FullSearchSchema<TRouteTree> &
@@ -832,17 +832,34 @@ export class Router<
832
832
 
833
833
  const matches = matchedRoutes.map((route, index) => {
834
834
  const interpolatedPath = interpolatePath(route.path, routeParams)
835
- const key = route.options.key
836
- ? route.options.key({
837
- params: routeParams,
835
+ const loaderContext = route.options.loaderContext
836
+ ? route.options.loaderContext({
838
837
  search: locationSearch,
839
- }) ?? ''
840
- : ''
841
-
842
- const stringifiedKey = key ? JSON.stringify(key) : ''
838
+ })
839
+ : undefined
843
840
 
844
- const matchId =
845
- interpolatePath(route.id, routeParams, true) + stringifiedKey
841
+ const matchId = JSON.stringify(
842
+ [interpolatePath(route.id, routeParams, true), loaderContext].filter(
843
+ (d) => d !== undefined,
844
+ ),
845
+ (key, value) => {
846
+ if (typeof value === 'function') {
847
+ console.info(route)
848
+ invariant(
849
+ false,
850
+ `Cannot return functions and other non-serializable values from routeOptions.loaderContext! Please use routeOptions.beforeLoad to do this. Route info is logged above 👆`,
851
+ )
852
+ }
853
+ if (typeof value === 'object' && value !== null) {
854
+ return Object.fromEntries(
855
+ Object.keys(value)
856
+ .sort()
857
+ .map((key) => [key, value[key]]),
858
+ )
859
+ }
860
+ return value
861
+ },
862
+ )
846
863
 
847
864
  // Waste not, want not. If we already have a match for this route,
848
865
  // reuse it. This is important for layout routes, which might stick
@@ -861,7 +878,7 @@ export class Router<
861
878
 
862
879
  const routeMatch: AnyRouteMatch = {
863
880
  id: matchId,
864
- key: stringifiedKey,
881
+ loaderContext,
865
882
  routeId: route.id,
866
883
  params: routeParams,
867
884
  pathname: joinPaths([this.basepath, interpolatedPath]),
@@ -878,7 +895,6 @@ export class Router<
878
895
  searchError: undefined,
879
896
  loaderData: undefined,
880
897
  loadPromise: Promise.resolve(),
881
- routeContext: undefined!,
882
898
  context: undefined!,
883
899
  abortController: new AbortController(),
884
900
  fetchedAt: 0,
@@ -957,7 +973,6 @@ export class Router<
957
973
  ...s,
958
974
  routeSearch: match.routeSearch,
959
975
  search: match.search,
960
- routeContext: match.routeContext,
961
976
  context: match.context,
962
977
  error: match.error,
963
978
  paramsError: match.paramsError,
@@ -1012,24 +1027,30 @@ export class Router<
1012
1027
 
1013
1028
  let didError = false
1014
1029
 
1030
+ const parentContext =
1031
+ parentMatch?.context ?? this?.options.context ?? {}
1032
+
1015
1033
  try {
1016
- const routeContext =
1034
+ const beforeLoadContext =
1017
1035
  (await route.options.beforeLoad?.({
1018
- ...match,
1036
+ abortController: match.abortController,
1037
+ params: match.params,
1019
1038
  preload: !!opts?.preload,
1020
- parentContext: parentMatch?.routeContext ?? {},
1021
- context: parentMatch?.context ?? this?.options.context ?? {},
1039
+ context: {
1040
+ ...parentContext,
1041
+ ...match.loaderContext,
1042
+ },
1022
1043
  })) ?? ({} as any)
1023
1044
 
1024
1045
  const context = {
1025
- ...(parentMatch?.context ?? this?.options.context),
1026
- ...routeContext,
1027
- } as any
1046
+ ...parentContext,
1047
+ ...match.loaderContext,
1048
+ ...beforeLoadContext,
1049
+ }
1028
1050
 
1029
1051
  this.setRouteMatch(match.id, (s) => ({
1030
1052
  ...s,
1031
1053
  context,
1032
- routeContext,
1033
1054
  }))
1034
1055
  } catch (err) {
1035
1056
  handleError(err, 'BEFORE_LOAD')
@@ -1102,9 +1123,11 @@ export class Router<
1102
1123
  )
1103
1124
 
1104
1125
  const loaderPromise = route.options.loader?.({
1105
- ...match,
1126
+ params: match.params,
1106
1127
  preload: !!opts?.preload,
1107
1128
  parentMatchPromise,
1129
+ abortController: match.abortController,
1130
+ context: match.context,
1108
1131
  })
1109
1132
 
1110
1133
  const [_, loader] = await Promise.all([
@@ -1694,7 +1717,10 @@ export class Router<
1694
1717
 
1695
1718
  // Pre filters first
1696
1719
  const preFilteredSearch = preSearchFilters?.length
1697
- ? preSearchFilters?.reduce((prev, next) => next(prev), from.search)
1720
+ ? preSearchFilters?.reduce(
1721
+ (prev, next) => next(prev) as any,
1722
+ from.search,
1723
+ )
1698
1724
  : from.search
1699
1725
 
1700
1726
  // Then the link/navigate function
package/src/utils.ts CHANGED
@@ -47,6 +47,26 @@ export type UnionToIntersection<U> = (
47
47
  // }
48
48
  // >
49
49
 
50
+ export type DeepMerge<A, B> = {
51
+ [K in keyof (A & B)]: K extends keyof B
52
+ ? B[K]
53
+ : K extends keyof A
54
+ ? A[K]
55
+ : never
56
+ } & (A extends Record<string, any>
57
+ ? Pick<A, Exclude<keyof A, keyof B>>
58
+ : never) &
59
+ (B extends Record<string, any> ? Pick<B, Exclude<keyof B, keyof A>> : never)
60
+
61
+ export type DeepMergeAll<T extends any[]> = T extends [
62
+ infer Left,
63
+ ...infer Rest,
64
+ ]
65
+ ? Rest extends any[]
66
+ ? DeepMerge<Left, DeepMergeAll<Rest>>
67
+ : Left
68
+ : {}
69
+
50
70
  export type Values<O> = O[ValueKeys<O>]
51
71
  export type ValueKeys<O> = Extract<keyof O, PropertyKey>
52
72