@tanstack/router-core 0.0.1-beta.19 → 0.0.1-beta.191

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