@tanstack/router-core 0.0.1-beta.2 → 0.0.1-beta.201

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/build/cjs/defer.js +39 -0
  3. package/build/cjs/defer.js.map +1 -0
  4. package/build/cjs/fileRoute.js +29 -0
  5. package/build/cjs/fileRoute.js.map +1 -0
  6. package/build/cjs/index.js +89 -0
  7. package/build/cjs/{packages/router-core/src/index.js.map → index.js.map} +1 -1
  8. package/build/cjs/{packages/router-core/src/path.js → path.js} +45 -56
  9. package/build/cjs/path.js.map +1 -0
  10. package/build/cjs/{packages/router-core/src/qss.js → qss.js} +10 -15
  11. package/build/cjs/qss.js.map +1 -0
  12. package/build/cjs/route.js +114 -0
  13. package/build/cjs/route.js.map +1 -0
  14. package/build/cjs/router.js +1277 -0
  15. package/build/cjs/router.js.map +1 -0
  16. package/build/cjs/scroll-restoration.js +139 -0
  17. package/build/cjs/scroll-restoration.js.map +1 -0
  18. package/build/cjs/{packages/router-core/src/searchParams.js → searchParams.js} +32 -19
  19. package/build/cjs/searchParams.js.map +1 -0
  20. package/build/cjs/utils.js +132 -0
  21. package/build/cjs/utils.js.map +1 -0
  22. package/build/esm/index.js +1565 -2106
  23. package/build/esm/index.js.map +1 -1
  24. package/build/stats-html.html +59 -49
  25. package/build/stats-react.json +219 -241
  26. package/build/types/defer.d.ts +19 -0
  27. package/build/types/fileRoute.d.ts +35 -0
  28. package/build/types/index.d.ts +13 -611
  29. package/build/types/link.d.ts +96 -0
  30. package/build/types/path.d.ts +16 -0
  31. package/build/types/qss.d.ts +2 -0
  32. package/build/types/route.d.ts +261 -0
  33. package/build/types/routeInfo.d.ts +22 -0
  34. package/build/types/router.d.ts +265 -0
  35. package/build/types/scroll-restoration.d.ts +6 -0
  36. package/build/types/searchParams.d.ts +5 -0
  37. package/build/types/utils.d.ts +51 -0
  38. package/build/umd/index.development.js +1917 -2070
  39. package/build/umd/index.development.js.map +1 -1
  40. package/build/umd/index.production.js +23 -2
  41. package/build/umd/index.production.js.map +1 -1
  42. package/package.json +13 -7
  43. package/src/defer.ts +55 -0
  44. package/src/fileRoute.ts +156 -0
  45. package/src/index.ts +5 -11
  46. package/src/link.ts +149 -123
  47. package/src/path.ts +37 -17
  48. package/src/qss.ts +1 -1
  49. package/src/route.ts +861 -231
  50. package/src/routeInfo.ts +47 -205
  51. package/src/router.ts +1818 -952
  52. package/src/scroll-restoration.ts +179 -0
  53. package/src/searchParams.ts +31 -9
  54. package/src/utils.ts +106 -43
  55. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -33
  56. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  57. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
  58. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
  59. package/build/cjs/node_modules/history/index.js +0 -815
  60. package/build/cjs/node_modules/history/index.js.map +0 -1
  61. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
  62. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
  63. package/build/cjs/packages/router-core/src/index.js +0 -58
  64. package/build/cjs/packages/router-core/src/path.js.map +0 -1
  65. package/build/cjs/packages/router-core/src/qss.js.map +0 -1
  66. package/build/cjs/packages/router-core/src/route.js +0 -161
  67. package/build/cjs/packages/router-core/src/route.js.map +0 -1
  68. package/build/cjs/packages/router-core/src/routeConfig.js +0 -69
  69. package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
  70. package/build/cjs/packages/router-core/src/routeMatch.js +0 -266
  71. package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
  72. package/build/cjs/packages/router-core/src/router.js +0 -789
  73. package/build/cjs/packages/router-core/src/router.js.map +0 -1
  74. package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
  75. package/build/cjs/packages/router-core/src/utils.js +0 -118
  76. package/build/cjs/packages/router-core/src/utils.js.map +0 -1
  77. package/src/frameworks.ts +0 -12
  78. package/src/routeConfig.ts +0 -495
  79. package/src/routeMatch.ts +0 -374
package/src/route.ts CHANGED
@@ -1,243 +1,873 @@
1
+ import invariant from 'tiny-invariant'
2
+ import { RoutePaths } from './routeInfo'
3
+ import { joinPaths, trimPath } from './path'
4
+ import { AnyRouter, RouteMatch, AnyRouteMatch } from './router'
1
5
  import {
2
- CheckRelativePath,
3
- LinkInfo,
4
- LinkOptions,
5
- ResolveRelativePath,
6
- ToOptions,
7
- } from './link'
8
- import { LoaderContext, RouteConfig, RouteOptions } from './routeConfig'
9
- import {
10
- AnyAllRouteInfo,
11
- AnyRouteInfo,
12
- DefaultAllRouteInfo,
13
- RouteInfo,
14
- RouteInfoByPath,
15
- } from './routeInfo'
16
- import { RouteMatch } from './routeMatch'
17
- import {
18
- Action,
19
- ActionState,
20
- Loader,
21
- LoaderState,
22
- MatchRouteOptions,
23
- Router,
24
- } from './router'
25
- import { NoInfer, replaceEqualDeep } from './utils'
26
-
27
- export interface AnyRoute extends Route<any, any> {}
28
-
29
- export interface Route<
30
- TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
31
- TRouteInfo extends AnyRouteInfo = RouteInfo,
6
+ DeepMerge,
7
+ DeepMergeAll,
8
+ Expand,
9
+ IsAny,
10
+ NoInfer,
11
+ PickRequired,
12
+ UnionToIntersection,
13
+ } from './utils'
14
+ import { ParsePathParams, ToSubOptions } from './link'
15
+
16
+ export const rootRouteId = '__root__' as const
17
+ export type RootRouteId = typeof rootRouteId
18
+ export type AnyPathParams = {}
19
+ export type AnySearchSchema = {}
20
+ export type AnyContext = {}
21
+ export interface RouteMeta {}
22
+ export interface RouteContext {}
23
+ export interface RegisterRouteComponent<
24
+ TLoader = unknown,
25
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
26
+ TAllParams extends AnyPathParams = AnyPathParams,
27
+ TAllContext extends Record<string, any> = AnyContext,
32
28
  > {
33
- routeId: TRouteInfo['id']
34
- routeRouteId: TRouteInfo['routeId']
35
- routePath: TRouteInfo['path']
36
- fullPath: TRouteInfo['fullPath']
37
- parentRoute?: AnyRoute
38
- childRoutes?: AnyRoute[]
39
- options: RouteOptions
40
- router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo>
41
- buildLink: <TTo extends string = '.'>(
42
- options: Omit<
43
- LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
44
- 'from'
45
- >,
46
- ) => LinkInfo
47
- matchRoute: <
48
- TTo extends string = '.',
49
- TResolved extends string = ResolveRelativePath<TRouteInfo['id'], TTo>,
50
- >(
51
- matchLocation: CheckRelativePath<
52
- TAllRouteInfo,
53
- TRouteInfo['fullPath'],
54
- NoInfer<TTo>
55
- > &
56
- Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
57
- opts?: MatchRouteOptions,
58
- ) => RouteInfoByPath<TAllRouteInfo, TResolved>['allParams']
59
- navigate: <TTo extends string = '.'>(
60
- options: Omit<LinkOptions<TAllRouteInfo, TRouteInfo['id'], TTo>, 'from'>,
61
- ) => Promise<void>
62
- action: unknown extends TRouteInfo['actionResponse']
63
- ?
64
- | Action<TRouteInfo['actionPayload'], TRouteInfo['actionResponse']>
65
- | undefined
66
- : Action<TRouteInfo['actionPayload'], TRouteInfo['actionResponse']>
67
- loader: unknown extends TRouteInfo['routeLoaderData']
68
- ?
69
- | Action<
70
- LoaderContext<
71
- TRouteInfo['fullSearchSchema'],
72
- TRouteInfo['allParams']
73
- >,
74
- TRouteInfo['routeLoaderData']
75
- >
76
- | undefined
77
- : Loader<
78
- TRouteInfo['fullSearchSchema'],
79
- TRouteInfo['allParams'],
80
- TRouteInfo['routeLoaderData']
81
- >
82
- }
83
-
84
- export function createRoute<
85
- TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
86
- TRouteInfo extends AnyRouteInfo = RouteInfo,
87
- >(
88
- routeConfig: RouteConfig,
89
- options: TRouteInfo['options'],
90
- parent: undefined | Route<TAllRouteInfo, any>,
91
- router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo>,
92
- ): Route<TAllRouteInfo, TRouteInfo> {
93
- const { id, routeId, path: routePath, fullPath } = routeConfig
94
-
95
- const action =
96
- router.state.actions[id] ||
97
- (() => {
98
- router.state.actions[id] = {
99
- pending: [],
100
- submit: async <T, U>(
101
- submission: T,
102
- actionOpts?: { invalidate?: boolean },
103
- ) => {
104
- if (!route) {
105
- return
106
- }
107
-
108
- const invalidate = actionOpts?.invalidate ?? true
109
-
110
- const actionState: ActionState<T, U> = {
111
- submittedAt: Date.now(),
112
- status: 'pending',
113
- submission,
114
- }
115
-
116
- action.current = actionState
117
- action.latest = actionState
118
- action.pending.push(actionState)
119
-
120
- router.state = {
121
- ...router.state,
122
- currentAction: actionState,
123
- latestAction: actionState,
124
- }
125
-
126
- router.notify()
127
-
128
- try {
129
- const res = await route.options.action?.(submission)
130
- actionState.data = res as U
131
- if (invalidate) {
132
- router.invalidateRoute({ to: '.', fromCurrent: true })
133
- await router.reload()
134
- }
135
- actionState.status = 'success'
136
- return res
137
- } catch (err) {
138
- console.error(err)
139
- actionState.error = err
140
- actionState.status = 'error'
141
- } finally {
142
- action.pending = action.pending.filter((d) => d !== actionState)
143
- router.removeActionQueue.push({ action, actionState })
144
- router.notify()
145
- }
146
- },
29
+ // RouteComponent: unknown // This is registered by the framework
30
+ }
31
+ export interface RegisterErrorRouteComponent<
32
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
33
+ TAllParams extends AnyPathParams = AnyPathParams,
34
+ TAllContext extends Record<string, any> = AnyContext,
35
+ > {
36
+ // ErrorRouteComponent: unknown // This is registered by the framework
37
+ }
38
+ export interface RegisterPendingRouteComponent<
39
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
40
+ TAllParams extends AnyPathParams = AnyPathParams,
41
+ TAllContext extends Record<string, any> = AnyContext,
42
+ > {
43
+ // PendingRouteComponent: unknown // This is registered by the framework
44
+ }
45
+
46
+ export interface RegisterRouteProps<
47
+ TLoader = unknown,
48
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
49
+ TAllParams extends AnyPathParams = AnyPathParams,
50
+ TAllContext extends Record<string, any> = AnyContext,
51
+ > {
52
+ // RouteProps: unknown // This is registered by the framework
53
+ }
54
+ export interface RegisterErrorRouteProps<
55
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
56
+ TAllParams extends AnyPathParams = AnyPathParams,
57
+ TAllContext extends Record<string, any> = AnyContext,
58
+ > {
59
+ // ErrorRouteProps: unknown // This is registered by the framework
60
+ }
61
+
62
+ export interface RegisterPendingRouteProps<
63
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
64
+ TAllParams extends AnyPathParams = AnyPathParams,
65
+ TAllContext extends Record<string, any> = AnyContext,
66
+ > {
67
+ // PendingRouteProps: unknown // This is registered by the framework
68
+ }
69
+
70
+ export type RegisteredRouteComponent<
71
+ TLoader = unknown,
72
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
73
+ TAllParams extends AnyPathParams = AnyPathParams,
74
+ TAllContext extends Record<string, any> = AnyContext,
75
+ > = RegisterRouteComponent<
76
+ TLoader,
77
+ TFullSearchSchema,
78
+ TAllParams,
79
+ TAllContext
80
+ > extends {
81
+ RouteComponent: infer T
82
+ }
83
+ ? T
84
+ : () => unknown
85
+
86
+ export type RegisteredErrorRouteComponent<
87
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
88
+ TAllParams extends AnyPathParams = AnyPathParams,
89
+ TAllContext extends Record<string, any> = AnyContext,
90
+ > = RegisterErrorRouteComponent<
91
+ TFullSearchSchema,
92
+ TAllParams,
93
+ TAllContext
94
+ > extends {
95
+ ErrorRouteComponent: infer T
96
+ }
97
+ ? T
98
+ : () => unknown
99
+
100
+ export type RegisteredPendingRouteComponent<
101
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
102
+ TAllParams extends AnyPathParams = AnyPathParams,
103
+ TAllContext extends Record<string, any> = AnyContext,
104
+ > = RegisterPendingRouteComponent<
105
+ TFullSearchSchema,
106
+ TAllParams,
107
+ TAllContext
108
+ > extends {
109
+ PendingRouteComponent: infer T
110
+ }
111
+ ? T
112
+ : () => unknown
113
+
114
+ export type RegisteredRouteProps<
115
+ TLoader = unknown,
116
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
117
+ TAllParams extends AnyPathParams = AnyPathParams,
118
+ TAllContext extends Record<string, any> = AnyContext,
119
+ > = RegisterRouteProps<
120
+ TLoader,
121
+ TFullSearchSchema,
122
+ TAllParams,
123
+ TAllContext
124
+ > extends {
125
+ RouteProps: infer T
126
+ }
127
+ ? T
128
+ : {}
129
+
130
+ export type RegisteredErrorRouteProps<
131
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
132
+ TAllParams extends AnyPathParams = AnyPathParams,
133
+ TAllContext extends Record<string, any> = AnyContext,
134
+ > = RegisterRouteProps<TFullSearchSchema, TAllParams, TAllContext> extends {
135
+ ErrorRouteProps: infer T
136
+ }
137
+ ? T
138
+ : {}
139
+
140
+ export type RegisteredPendingRouteProps<
141
+ TFullSearchSchema extends Record<string, any> = AnySearchSchema,
142
+ TAllParams extends AnyPathParams = AnyPathParams,
143
+ TAllContext extends Record<string, any> = AnyContext,
144
+ > = RegisterRouteProps<TFullSearchSchema, TAllParams, TAllContext> extends {
145
+ PendingRouteProps: infer T
146
+ }
147
+ ? T
148
+ : {}
149
+
150
+ export type PreloadableObj = { preload?: () => Promise<void> }
151
+
152
+ export type RoutePathOptions<TCustomId, TPath> =
153
+ | {
154
+ path: TPath
155
+ }
156
+ | {
157
+ id: TCustomId
158
+ }
159
+
160
+ export type RoutePathOptionsIntersection<TCustomId, TPath> =
161
+ UnionToIntersection<RoutePathOptions<TCustomId, TPath>>
162
+
163
+ export type MetaOptions = keyof PickRequired<RouteMeta> extends never
164
+ ? {
165
+ meta?: RouteMeta
166
+ }
167
+ : {
168
+ meta: RouteMeta
169
+ }
170
+
171
+ export type AnyRouteProps = RegisteredRouteProps<any, any, any, any>
172
+
173
+ export type RouteOptions<
174
+ TParentRoute extends AnyRoute = AnyRoute,
175
+ TCustomId extends string = string,
176
+ TPath extends string = string,
177
+ TLoaderContext extends Record<string, any> = AnyContext,
178
+ TLoader = unknown,
179
+ TSearchSchema extends Record<string, any> = {},
180
+ TFullSearchSchema extends Record<string, any> = TSearchSchema,
181
+ TParams extends AnyPathParams = AnyPathParams,
182
+ TAllParams extends AnyPathParams = TParams,
183
+ TRouteContext extends RouteContext = RouteContext,
184
+ TAllContext extends Record<string, any> = AnyContext,
185
+ > = BaseRouteOptions<
186
+ TParentRoute,
187
+ TCustomId,
188
+ TPath,
189
+ TLoaderContext,
190
+ TLoader,
191
+ TSearchSchema,
192
+ TFullSearchSchema,
193
+ TParams,
194
+ TAllParams,
195
+ TRouteContext,
196
+ TAllContext
197
+ > &
198
+ UpdatableRouteOptions<TLoader, TFullSearchSchema, TAllParams, TAllContext>
199
+
200
+ export type ParamsFallback<
201
+ TPath extends string,
202
+ TParams,
203
+ > = unknown extends TParams ? Record<ParsePathParams<TPath>, string> : TParams
204
+
205
+ type Prefix<T extends string, U extends string> = U extends `${T}${infer _}`
206
+ ? U
207
+ : never
208
+
209
+ export type BaseRouteOptions<
210
+ TParentRoute extends AnyRoute = AnyRoute,
211
+ TCustomId extends string = string,
212
+ TPath extends string = string,
213
+ TLoaderContext extends Record<string, any> = AnyContext,
214
+ TLoader = unknown,
215
+ TSearchSchema extends Record<string, any> = {},
216
+ TFullSearchSchema extends Record<string, any> = TSearchSchema,
217
+ TParams extends AnyPathParams = {},
218
+ TAllParams = ParamsFallback<TPath, TParams>,
219
+ TRouteContext extends RouteContext = RouteContext,
220
+ TAllContext extends Record<string, any> = AnyContext,
221
+ > = RoutePathOptions<TCustomId, TPath> & {
222
+ getParentRoute: () => TParentRoute
223
+ validateSearch?: SearchSchemaValidator<TSearchSchema>
224
+ loaderContext?: (opts: { search: TFullSearchSchema }) => TLoaderContext
225
+ } & (keyof PickRequired<RouteContext> extends never
226
+ ? // This async function is called before a route is loaded.
227
+ // If an error is thrown here, the route's loader will not be called.
228
+ // If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onError` function.
229
+ // If thrown during a preload event, the error will be logged to the console.
230
+ {
231
+ beforeLoad?: BeforeLoadFn<
232
+ TParentRoute,
233
+ TAllParams,
234
+ NoInfer<TLoaderContext>,
235
+ TRouteContext
236
+ >
147
237
  }
148
- return router.state.actions[id]!
149
- })()
150
-
151
- const loader =
152
- router.state.loaders[id] ||
153
- (() => {
154
- router.state.loaders[id] = {
155
- pending: [],
156
- fetch: (async (loaderContext: LoaderContext<any, any>) => {
157
- if (!route) {
158
- return
159
- }
160
-
161
- const loaderState: LoaderState<any, any> = {
162
- loadedAt: Date.now(),
163
- loaderContext,
164
- }
165
-
166
- loader.current = loaderState
167
- loader.latest = loaderState
168
- loader.pending.push(loaderState)
169
-
170
- // router.state = {
171
- // ...router.state,
172
- // currentAction: loaderState,
173
- // latestAction: loaderState,
174
- // }
175
-
176
- router.notify()
177
-
178
- try {
179
- return await route.options.loader?.(loaderContext)
180
- } finally {
181
- loader.pending = loader.pending.filter((d) => d !== loaderState)
182
- // router.removeActionQueue.push({ loader, loaderState })
183
- router.notify()
184
- }
185
- }) as any,
238
+ : {
239
+ beforeLoad: BeforeLoadFn<
240
+ TParentRoute,
241
+ TAllParams,
242
+ NoInfer<TLoaderContext>,
243
+ TRouteContext
244
+ >
245
+ }) & {
246
+ loader?: LoaderFn<
247
+ TLoader,
248
+ TAllParams,
249
+ NoInfer<TLoaderContext>,
250
+ NoInfer<TAllContext>,
251
+ NoInfer<TRouteContext>
252
+ >
253
+ } & ([TLoader] extends [never]
254
+ ? {
255
+ loader: 'Loaders must return a type other than never. If you are throwing a redirect() and not returning anything, return a redirect() instead.'
186
256
  }
187
- return router.state.loaders[id]!
188
- })()
189
-
190
- let route: Route<TAllRouteInfo, TRouteInfo> = {
191
- routeId: id,
192
- routeRouteId: routeId,
193
- routePath,
194
- fullPath,
195
- options,
196
- router,
197
- childRoutes: undefined!,
198
- parentRoute: parent,
199
- action,
200
- loader: loader as any,
201
-
202
- buildLink: (options) => {
203
- return router.buildLink({
204
- ...options,
205
- from: fullPath,
206
- } as any) as any
207
- },
208
-
209
- navigate: (options) => {
210
- return router.navigate({
211
- ...options,
212
- from: fullPath,
213
- } as any) as any
214
- },
215
-
216
- matchRoute: (matchLocation, opts) => {
217
- return router.matchRoute(
218
- {
219
- ...matchLocation,
220
- from: fullPath,
221
- } as any,
222
- opts,
223
- )
224
- },
257
+ : {}) &
258
+ (
259
+ | {
260
+ // Both or none
261
+ parseParams?: (
262
+ rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
263
+ ) => TParams extends Record<ParsePathParams<TPath>, any>
264
+ ? TParams
265
+ : 'parseParams must return an object'
266
+ stringifyParams?: (
267
+ params: NoInfer<ParamsFallback<TPath, TParams>>,
268
+ ) => Record<ParsePathParams<TPath>, string>
269
+ }
270
+ | {
271
+ stringifyParams?: never
272
+ parseParams?: never
273
+ }
274
+ )
275
+
276
+ type BeforeLoadFn<
277
+ TParentRoute extends AnyRoute,
278
+ TAllParams,
279
+ TLoaderContext,
280
+ TRouteContext,
281
+ > = (opts: {
282
+ abortController: AbortController
283
+ preload: boolean
284
+ params: TAllParams
285
+ context: Expand<TParentRoute['types']['context'] & TLoaderContext>
286
+ }) => Promise<TRouteContext> | TRouteContext | void
287
+
288
+ export type UpdatableRouteOptions<
289
+ TLoader,
290
+ TFullSearchSchema extends Record<string, any>,
291
+ TAllParams extends AnyPathParams,
292
+ TAllContext extends Record<string, any>,
293
+ > = MetaOptions & {
294
+ // If true, this route will be matched as case-sensitive
295
+ caseSensitive?: boolean
296
+ // If true, this route will be forcefully wrapped in a suspense boundary
297
+ wrapInSuspense?: boolean
298
+ // The content to be rendered when the route is matched. If no component is provided, defaults to `<Outlet />`
299
+ component?: RegisteredRouteComponent<
300
+ TLoader,
301
+ TFullSearchSchema,
302
+ TAllParams,
303
+ TAllContext
304
+ >
305
+ // The content to be rendered when the route encounters an error
306
+ errorComponent?: RegisteredErrorRouteComponent<
307
+ TFullSearchSchema,
308
+ TAllParams,
309
+ TAllContext
310
+ > //
311
+ // If supported by your framework, the content to be rendered as the fallback content until the route is ready to render
312
+ pendingComponent?: RegisteredPendingRouteComponent<
313
+ TFullSearchSchema,
314
+ TAllParams,
315
+ TAllContext
316
+ >
317
+ // Filter functions that can manipulate search params *before* they are passed to links and navigate
318
+ // calls that match this route.
319
+ preSearchFilters?: SearchFilter<TFullSearchSchema>[]
320
+ // Filter functions that can manipulate search params *after* they are passed to links and navigate
321
+ // calls that match this route.
322
+ postSearchFilters?: SearchFilter<TFullSearchSchema>[]
323
+ // If set, preload matches of this route will be considered fresh for this many milliseconds.
324
+ preloadMaxAge?: number
325
+ // If set, a match of this route will be considered fresh for this many milliseconds.
326
+ maxAge?: number
327
+ // If set, a match of this route that becomes inactive (or unused) will be garbage collected after this many milliseconds
328
+ gcMaxAge?: number
329
+ onError?: (err: any) => void
330
+ // These functions are called as route matches are loaded, stick around and leave the active
331
+ // matches
332
+ onEnter?: (match: AnyRouteMatch) => void
333
+ onTransition?: (match: AnyRouteMatch) => void
334
+ onLeave?: (match: AnyRouteMatch) => void
335
+ // Set this to true or false to specifically set whether or not this route should be preloaded. If unset, will
336
+ // default to router.options.reloadOnWindowFocus
337
+ reloadOnWindowFocus?: boolean
338
+ }
339
+
340
+ export type ParseParamsOption<TPath extends string, TParams> = ParseParamsFn<
341
+ TPath,
342
+ TParams
343
+ >
344
+
345
+ export type ParseParamsFn<TPath extends string, TParams> = (
346
+ rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
347
+ ) => TParams extends Record<ParsePathParams<TPath>, any>
348
+ ? TParams
349
+ : 'parseParams must return an object'
350
+
351
+ export type ParseParamsObj<TPath extends string, TParams> = {
352
+ parse?: ParseParamsFn<TPath, TParams>
353
+ }
354
+
355
+ // The parse type here allows a zod schema to be passed directly to the validator
356
+ export type SearchSchemaValidator<TReturn> =
357
+ | SearchSchemaValidatorObj<TReturn>
358
+ | SearchSchemaValidatorFn<TReturn>
359
+
360
+ export type SearchSchemaValidatorObj<TReturn> = {
361
+ parse?: SearchSchemaValidatorFn<TReturn>
362
+ }
363
+
364
+ export type SearchSchemaValidatorFn<TReturn> = (
365
+ searchObj: Record<string, unknown>,
366
+ ) => TReturn
367
+
368
+ export type DefinedPathParamWarning =
369
+ 'Path params cannot be redefined by child routes!'
370
+
371
+ export type ParentParams<TParentParams> = AnyPathParams extends TParentParams
372
+ ? {}
373
+ : {
374
+ [Key in keyof TParentParams]?: DefinedPathParamWarning
375
+ }
376
+
377
+ export type LoaderFn<
378
+ TLoader = unknown,
379
+ TAllParams = {},
380
+ TLoaderContext extends Record<string, any> = AnyContext,
381
+ TAllContext extends Record<string, any> = AnyContext,
382
+ TRouteContext extends Record<string, any> = AnyContext,
383
+ > = (
384
+ match: LoaderContext<
385
+ TAllParams,
386
+ TLoaderContext,
387
+ TAllContext,
388
+ TRouteContext
389
+ > & {
390
+ parentMatchPromise?: Promise<void>
391
+ },
392
+ ) => Promise<TLoader> | TLoader
393
+
394
+ export interface LoaderContext<
395
+ TAllParams = {},
396
+ TLoaderContext = {},
397
+ TAllContext extends Record<string, any> = AnyContext,
398
+ TRouteContext extends Record<string, any> = AnyContext,
399
+ > {
400
+ abortController: AbortController
401
+ preload: boolean
402
+ params: TAllParams
403
+ context: Expand<DeepMergeAll<[TAllContext, TLoaderContext, TRouteContext]>>
404
+ }
405
+
406
+ export type SearchFilter<T, U = T> = (prev: T) => U
407
+
408
+ export type ResolveId<
409
+ TParentRoute,
410
+ TCustomId extends string,
411
+ TPath extends string,
412
+ > = TParentRoute extends { id: infer TParentId extends string }
413
+ ? RoutePrefix<TParentId, string extends TCustomId ? TPath : TCustomId>
414
+ : RootRouteId
415
+
416
+ export type InferFullSearchSchema<TRoute> = TRoute extends {
417
+ types: {
418
+ fullSearchSchema: infer TFullSearchSchema
225
419
  }
420
+ }
421
+ ? TFullSearchSchema
422
+ : {}
423
+
424
+ export type ResolveFullSearchSchema<TParentRoute, TSearchSchema> = Expand<
425
+ DeepMerge<InferFullSearchSchema<TParentRoute>, TSearchSchema>
426
+ >
427
+
428
+ export interface AnyRoute
429
+ extends Route<
430
+ any,
431
+ any,
432
+ any,
433
+ any,
434
+ any,
435
+ any,
436
+ any,
437
+ any,
438
+ any,
439
+ any,
440
+ any,
441
+ any,
442
+ any,
443
+ any,
444
+ any,
445
+ any
446
+ > {}
447
+
448
+ export type MergeFromFromParent<T, U> = IsAny<T, U, T & U>
449
+
450
+ export type UseLoaderResult<T> = T
451
+ // T extends Record<PropertyKey, infer U>
452
+ // ? {
453
+ // [K in keyof T]: UseLoaderResultPromise<T[K]>
454
+ // }
455
+ // : UseLoaderResultPromise<T>
226
456
 
227
- router.options.createRoute?.({ router, route })
457
+ // export type UseLoaderResultPromise<T> = T extends Promise<infer U>
458
+ // ? StreamedPromise<U>
459
+ // : T
228
460
 
229
- return route
461
+ export type StreamedPromise<T> = {
462
+ promise: Promise<T>
463
+ status: 'resolved' | 'pending'
464
+ data: T
465
+ resolve: (value: T) => void
230
466
  }
231
467
 
232
- export function cascadeLoaderData(matches: RouteMatch<any, any>[]) {
233
- matches.forEach((match, index) => {
234
- const parent = matches[index - 1]
468
+ export type ResolveAllParams<
469
+ TParentRoute extends AnyRoute,
470
+ TParams extends AnyPathParams,
471
+ > = Record<never, string> extends TParentRoute['types']['allParams']
472
+ ? TParams
473
+ : Expand<
474
+ UnionToIntersection<TParentRoute['types']['allParams'] & TParams> & {}
475
+ >
235
476
 
236
- if (parent) {
237
- match.loaderData = replaceEqualDeep(match.loaderData, {
238
- ...parent.loaderData,
239
- ...match.routeLoaderData,
240
- })
477
+ export type RouteConstraints = {
478
+ TParentRoute: AnyRoute
479
+ TPath: string
480
+ TFullPath: string
481
+ TCustomId: string
482
+ TId: string
483
+ TLoaderContext: Record<string, any>
484
+ TSearchSchema: AnySearchSchema
485
+ TFullSearchSchema: AnySearchSchema
486
+ TParams: Record<string, any>
487
+ TAllParams: Record<string, any>
488
+ TParentContext: AnyContext
489
+ TRouteContext: RouteContext
490
+ TAllContext: AnyContext
491
+ TRouterContext: AnyContext
492
+ TChildren: unknown
493
+ TRouteTree: AnyRoute
494
+ }
495
+
496
+ export class Route<
497
+ TParentRoute extends RouteConstraints['TParentRoute'] = AnyRoute,
498
+ TPath extends RouteConstraints['TPath'] = '/',
499
+ TFullPath extends RouteConstraints['TFullPath'] = ResolveFullPath<
500
+ TParentRoute,
501
+ TPath
502
+ >,
503
+ TCustomId extends RouteConstraints['TCustomId'] = string,
504
+ TId extends RouteConstraints['TId'] = ResolveId<
505
+ TParentRoute,
506
+ TCustomId,
507
+ TPath
508
+ >,
509
+ TLoaderContext extends RouteConstraints['TLoaderContext'] = {},
510
+ TLoader = unknown,
511
+ TSearchSchema extends RouteConstraints['TSearchSchema'] = {},
512
+ TFullSearchSchema extends RouteConstraints['TFullSearchSchema'] = ResolveFullSearchSchema<
513
+ TParentRoute,
514
+ TSearchSchema
515
+ >,
516
+ TParams extends RouteConstraints['TParams'] = Expand<
517
+ Record<ParsePathParams<TPath>, string>
518
+ >,
519
+ TAllParams extends RouteConstraints['TAllParams'] = ResolveAllParams<
520
+ TParentRoute,
521
+ TParams
522
+ >,
523
+ TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
524
+ TAllContext extends RouteConstraints['TAllContext'] = Expand<
525
+ DeepMergeAll<
526
+ [
527
+ IsAny<TParentRoute['types']['context'], {}>,
528
+ TLoaderContext,
529
+ TRouteContext,
530
+ ]
531
+ >
532
+ >,
533
+ TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
534
+ TChildren extends RouteConstraints['TChildren'] = unknown,
535
+ TRouteTree extends RouteConstraints['TRouteTree'] = AnyRoute,
536
+ > {
537
+ types!: {
538
+ parentRoute: TParentRoute
539
+ path: TPath
540
+ to: TrimPathRight<TFullPath>
541
+ fullPath: TFullPath
542
+ customId: TCustomId
543
+ id: TId
544
+ loader: TLoader
545
+ searchSchema: TSearchSchema
546
+ fullSearchSchema: TFullSearchSchema
547
+ params: TParams
548
+ allParams: TAllParams
549
+ routeContext: TRouteContext
550
+ context: TAllContext
551
+ children: TChildren
552
+ routeTree: TRouteTree
553
+ routerContext: TRouterContext
554
+ }
555
+ isRoot: TParentRoute extends Route<any> ? true : false
556
+ options: RouteOptions<
557
+ TParentRoute,
558
+ TCustomId,
559
+ TPath,
560
+ TLoaderContext,
561
+ TLoader,
562
+ TSearchSchema,
563
+ TFullSearchSchema,
564
+ TParams,
565
+ TAllParams,
566
+ TRouteContext,
567
+ TAllContext
568
+ >
569
+
570
+ // Set up in this.init()
571
+ parentRoute!: TParentRoute
572
+ id!: TId
573
+ // customId!: TCustomId
574
+ path!: TPath
575
+ fullPath!: TFullPath
576
+ to!: TrimPathRight<TFullPath>
577
+
578
+ // Optional
579
+ children?: TChildren
580
+ originalIndex?: number
581
+ router?: AnyRouter
582
+ rank!: number
583
+
584
+ constructor(
585
+ options: RouteOptions<
586
+ TParentRoute,
587
+ TCustomId,
588
+ TPath,
589
+ TLoaderContext,
590
+ TLoader,
591
+ TSearchSchema,
592
+ TFullSearchSchema,
593
+ TParams,
594
+ TAllParams,
595
+ TRouteContext,
596
+ TAllContext
597
+ > &
598
+ UpdatableRouteOptions<
599
+ TLoader,
600
+ TFullSearchSchema,
601
+ TAllParams,
602
+ TAllContext
603
+ >,
604
+ ) {
605
+ this.options = (options as any) || {}
606
+ this.isRoot = !options?.getParentRoute as any
607
+ Route.__onInit(this)
608
+ }
609
+
610
+ init = (opts: { originalIndex: number; router: AnyRouter }) => {
611
+ this.originalIndex = opts.originalIndex
612
+ this.router = opts.router
613
+
614
+ const options = this.options as RouteOptions<
615
+ TParentRoute,
616
+ TCustomId,
617
+ TPath,
618
+ TLoaderContext,
619
+ TLoader,
620
+ TSearchSchema,
621
+ TFullSearchSchema,
622
+ TParams,
623
+ TAllParams,
624
+ TRouteContext,
625
+ TAllContext
626
+ > &
627
+ RoutePathOptionsIntersection<TCustomId, TPath>
628
+
629
+ const isRoot = !options?.path && !options?.id
630
+
631
+ this.parentRoute = this.options?.getParentRoute?.()
632
+
633
+ if (isRoot) {
634
+ this.path = rootRouteId as TPath
635
+ } else {
636
+ invariant(
637
+ this.parentRoute,
638
+ `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`,
639
+ )
241
640
  }
242
- })
641
+
642
+ let path: undefined | string = isRoot ? rootRouteId : options.path
643
+
644
+ // If the path is anything other than an index path, trim it up
645
+ if (path && path !== '/') {
646
+ path = trimPath(path)
647
+ }
648
+
649
+ const customId = options?.id || path
650
+
651
+ // Strip the parentId prefix from the first level of children
652
+ let id = isRoot
653
+ ? rootRouteId
654
+ : joinPaths([
655
+ (this.parentRoute.id as any) === rootRouteId
656
+ ? ''
657
+ : this.parentRoute.id,
658
+ customId,
659
+ ])
660
+
661
+ if (path === rootRouteId) {
662
+ path = '/'
663
+ }
664
+
665
+ if (id !== rootRouteId) {
666
+ id = joinPaths(['/', id])
667
+ }
668
+
669
+ const fullPath =
670
+ id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path])
671
+
672
+ this.path = path as TPath
673
+ this.id = id as TId
674
+ // this.customId = customId as TCustomId
675
+ this.fullPath = fullPath as TFullPath
676
+ this.to = fullPath as TrimPathRight<TFullPath>
677
+ }
678
+
679
+ addChildren = <TNewChildren extends AnyRoute[]>(
680
+ children: TNewChildren,
681
+ ): Route<
682
+ TParentRoute,
683
+ TPath,
684
+ TFullPath,
685
+ TCustomId,
686
+ TId,
687
+ TLoaderContext,
688
+ TLoader,
689
+ TSearchSchema,
690
+ TFullSearchSchema,
691
+ TParams,
692
+ TAllParams,
693
+ TRouteContext,
694
+ TAllContext,
695
+ TRouterContext,
696
+ TNewChildren,
697
+ TRouteTree
698
+ > => {
699
+ this.children = children as any
700
+ return this as any
701
+ }
702
+
703
+ update = (
704
+ options: UpdatableRouteOptions<
705
+ TLoader,
706
+ TFullSearchSchema,
707
+ TAllParams,
708
+ TAllContext
709
+ >,
710
+ ) => {
711
+ Object.assign(this.options, options)
712
+ return this
713
+ }
714
+
715
+ static __onInit = (route: any) => {
716
+ // This is a dummy static method that should get
717
+ // replaced by a framework specific implementation if necessary
718
+ }
719
+ }
720
+
721
+ export type AnyRootRoute = RootRoute<any, any, any, any>
722
+
723
+ export class RouterContext<TRouterContext extends {}> {
724
+ constructor() {}
725
+
726
+ createRootRoute = <
727
+ TLoaderContext extends Record<string, any> = AnyContext,
728
+ TLoader = unknown,
729
+ TSearchSchema extends Record<string, any> = {},
730
+ TRouteContext extends RouteContext = RouteContext,
731
+ >(
732
+ options?: Omit<
733
+ RouteOptions<
734
+ AnyRoute, // TParentRoute
735
+ RootRouteId, // TCustomId
736
+ '', // TPath
737
+ TLoaderContext, // TLoaderContext
738
+ TLoader, // TLoader
739
+ TSearchSchema, // TSearchSchema
740
+ TSearchSchema, // TFullSearchSchema
741
+ {}, // TParams
742
+ {}, // TAllParams
743
+ TRouteContext, // TRouteContext
744
+ DeepMergeAll<[TRouterContext, TLoaderContext, TRouteContext]> // TAllContext
745
+ >,
746
+ | 'path'
747
+ | 'id'
748
+ | 'getParentRoute'
749
+ | 'caseSensitive'
750
+ | 'parseParams'
751
+ | 'stringifyParams'
752
+ >,
753
+ ): RootRoute<
754
+ TLoaderContext,
755
+ TLoader,
756
+ TSearchSchema,
757
+ TRouteContext,
758
+ TRouterContext
759
+ > => {
760
+ return new RootRoute(options) as any
761
+ }
762
+ }
763
+
764
+ export class RootRoute<
765
+ TLoaderContext extends Record<string, any> = AnyContext,
766
+ TLoader = unknown,
767
+ TSearchSchema extends Record<string, any> = {},
768
+ TRouteContext extends RouteContext = RouteContext,
769
+ TRouterContext extends {} = {},
770
+ > extends Route<
771
+ any, // TParentRoute
772
+ '/', // TPath
773
+ '/', // TFullPath
774
+ string, // TCustomId
775
+ RootRouteId, // TId
776
+ TLoaderContext, // TLoaderContext
777
+ TLoader, // TLoader
778
+ TSearchSchema, // TSearchSchema
779
+ TSearchSchema, // TFullSearchSchema
780
+ {}, // TParams
781
+ {}, // TAllParams
782
+ TRouteContext, // TRouteContext
783
+ DeepMergeAll<[TRouterContext, TLoaderContext, TRouteContext]>, // TAllContext
784
+ TRouterContext, // TRouterContext
785
+ any, // TChildren
786
+ any // TRouteTree
787
+ > {
788
+ constructor(
789
+ options?: Omit<
790
+ RouteOptions<
791
+ AnyRoute, // TParentRoute
792
+ RootRouteId, // TCustomId
793
+ '', // TPath
794
+ TLoaderContext, // TLoaderContext
795
+ TLoader, // TLoader
796
+ TSearchSchema, // TSearchSchema
797
+ TSearchSchema, // TFullSearchSchema
798
+ {}, // TParams
799
+ {}, // TAllParams
800
+ TRouteContext, // TRouteContext
801
+ DeepMergeAll<[TRouterContext, TLoaderContext, TRouteContext]> // TAllContext
802
+ >,
803
+ | 'path'
804
+ | 'id'
805
+ | 'getParentRoute'
806
+ | 'caseSensitive'
807
+ | 'parseParams'
808
+ | 'stringifyParams'
809
+ >,
810
+ ) {
811
+ super(options as any)
812
+ }
813
+ }
814
+
815
+ export type ResolveFullPath<
816
+ TParentRoute extends AnyRoute,
817
+ TPath extends string,
818
+ TPrefixed = RoutePrefix<TParentRoute['fullPath'], TPath>,
819
+ > = TPrefixed extends RootRouteId ? '/' : TPrefixed
820
+
821
+ type RoutePrefix<
822
+ TPrefix extends string,
823
+ TPath extends string,
824
+ > = string extends TPath
825
+ ? RootRouteId
826
+ : TPath extends string
827
+ ? TPrefix extends RootRouteId
828
+ ? TPath extends '/'
829
+ ? '/'
830
+ : `/${TrimPath<TPath>}`
831
+ : `${TPrefix}/${TPath}` extends '/'
832
+ ? '/'
833
+ : `/${TrimPathLeft<`${TrimPathRight<TPrefix>}/${TrimPath<TPath>}`>}`
834
+ : never
835
+
836
+ export type TrimPath<T extends string> = '' extends T
837
+ ? ''
838
+ : TrimPathRight<TrimPathLeft<T>>
839
+
840
+ export type TrimPathLeft<T extends string> =
841
+ T extends `${RootRouteId}/${infer U}`
842
+ ? TrimPathLeft<U>
843
+ : T extends `/${infer U}`
844
+ ? TrimPathLeft<U>
845
+ : T
846
+ export type TrimPathRight<T extends string> = T extends '/'
847
+ ? '/'
848
+ : T extends `${infer U}/`
849
+ ? TrimPathRight<U>
850
+ : T
851
+
852
+ export type RouteMask<TRouteTree extends AnyRoute> = {
853
+ routeTree: TRouteTree
854
+ from: RoutePaths<TRouteTree>
855
+ to?: any
856
+ params?: any
857
+ search?: any
858
+ hash?: any
859
+ state?: any
860
+ unmaskOnReload?: boolean
861
+ }
862
+
863
+ export function createRouteMask<
864
+ TRouteTree extends AnyRoute,
865
+ TFrom extends RoutePaths<TRouteTree>,
866
+ TTo extends string,
867
+ >(
868
+ opts: {
869
+ routeTree: TRouteTree
870
+ } & ToSubOptions<TRouteTree, TFrom, TTo>,
871
+ ): RouteMask<TRouteTree> {
872
+ return opts as any
243
873
  }