@tanstack/router-core 0.0.1-beta.3 → 0.0.1-beta.30

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 (56) hide show
  1. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -2
  2. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  3. package/build/cjs/{packages/router-core/src/index.js → index.js} +23 -7
  4. package/build/cjs/{packages/router-core/src/index.js.map → index.js.map} +1 -1
  5. package/build/cjs/{packages/router-core/src/path.js → path.js} +7 -34
  6. package/build/cjs/path.js.map +1 -0
  7. package/build/cjs/{packages/router-core/src/qss.js → qss.js} +9 -13
  8. package/build/cjs/qss.js.map +1 -0
  9. package/build/cjs/{packages/router-core/src/route.js → route.js} +15 -37
  10. package/build/cjs/route.js.map +1 -0
  11. package/build/cjs/{packages/router-core/src/routeConfig.js → routeConfig.js} +13 -12
  12. package/build/cjs/routeConfig.js.map +1 -0
  13. package/build/cjs/routeMatch.js +200 -0
  14. package/build/cjs/routeMatch.js.map +1 -0
  15. package/build/cjs/{packages/router-core/src/router.js → router.js} +246 -208
  16. package/build/cjs/router.js.map +1 -0
  17. package/build/cjs/{packages/router-core/src/searchParams.js → searchParams.js} +7 -10
  18. package/build/cjs/searchParams.js.map +1 -0
  19. package/build/cjs/{packages/router-core/src/utils.js → utils.js} +17 -30
  20. package/build/cjs/utils.js.map +1 -0
  21. package/build/esm/index.js +382 -1307
  22. package/build/esm/index.js.map +1 -1
  23. package/build/stats-html.html +59 -49
  24. package/build/stats-react.json +161 -168
  25. package/build/types/index.d.ts +228 -206
  26. package/build/umd/index.development.js +373 -481
  27. package/build/umd/index.development.js.map +1 -1
  28. package/build/umd/index.production.js +1 -1
  29. package/build/umd/index.production.js.map +1 -1
  30. package/package.json +3 -2
  31. package/src/frameworks.ts +2 -2
  32. package/src/index.ts +0 -1
  33. package/src/link.ts +8 -5
  34. package/src/path.ts +2 -6
  35. package/src/qss.ts +1 -0
  36. package/src/route.ts +24 -32
  37. package/src/routeConfig.ts +100 -77
  38. package/src/routeInfo.ts +22 -7
  39. package/src/routeMatch.ts +95 -157
  40. package/src/router.ts +346 -122
  41. package/src/utils.ts +14 -7
  42. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
  43. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
  44. package/build/cjs/node_modules/history/index.js +0 -815
  45. package/build/cjs/node_modules/history/index.js.map +0 -1
  46. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
  47. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
  48. package/build/cjs/packages/router-core/src/path.js.map +0 -1
  49. package/build/cjs/packages/router-core/src/qss.js.map +0 -1
  50. package/build/cjs/packages/router-core/src/route.js.map +0 -1
  51. package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
  52. package/build/cjs/packages/router-core/src/routeMatch.js +0 -266
  53. package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
  54. package/build/cjs/packages/router-core/src/router.js.map +0 -1
  55. package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
  56. package/build/cjs/packages/router-core/src/utils.js.map +0 -1
package/src/routeInfo.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  RouteConfig,
11
11
  RouteOptions,
12
12
  } from './routeConfig'
13
- import { IsAny, Values } from './utils'
13
+ import { IsAny, UnionToIntersection, Values } from './utils'
14
14
 
15
15
  export interface AnyAllRouteInfo {
16
16
  routeConfig: AnyRouteConfig
@@ -19,6 +19,7 @@ export interface AnyAllRouteInfo {
19
19
  routeInfoByFullPath: Record<string, AnyRouteInfo>
20
20
  routeIds: any
21
21
  routePaths: any
22
+ fullSearchSchema: Record<string, any>
22
23
  }
23
24
 
24
25
  export interface DefaultAllRouteInfo {
@@ -28,6 +29,7 @@ export interface DefaultAllRouteInfo {
28
29
  routeInfoByFullPath: Record<string, RouteInfo>
29
30
  routeIds: string
30
31
  routePaths: string
32
+ fullSearchSchema: AnySearchSchema
31
33
  }
32
34
 
33
35
  export interface AllRouteInfo<TRouteConfig extends AnyRouteConfig = RouteConfig>
@@ -58,12 +60,15 @@ type ParseRouteChild<TRouteConfig, TId> = TRouteConfig & {
58
60
  ? ParseRouteConfig<TRouteConfig>
59
61
  : never
60
62
 
63
+ // Generics!
61
64
  export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
62
65
  infer TId,
63
66
  infer TRouteId,
64
67
  infer TPath,
65
68
  infer TFullPath,
69
+ infer TParentRouteLoaderData,
66
70
  infer TRouteLoaderData,
71
+ infer TParentLoaderData,
67
72
  infer TLoaderData,
68
73
  infer TActionPayload,
69
74
  infer TActionResponse,
@@ -82,7 +87,9 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
82
87
  TRouteId,
83
88
  TPath,
84
89
  TFullPath,
90
+ TParentRouteLoaderData,
85
91
  TRouteLoaderData,
92
+ TParentLoaderData,
86
93
  TLoaderData,
87
94
  TActionPayload,
88
95
  TActionResponse,
@@ -111,12 +118,14 @@ export interface RoutesInfoInner<
111
118
  any,
112
119
  any,
113
120
  any,
121
+ any,
122
+ any,
114
123
  any
115
124
  > = RouteInfo,
116
- TRouteInfoById = {
125
+ TRouteInfoById = { '/': TRouteInfo } & {
117
126
  [TInfo in TRouteInfo as TInfo['id']]: TInfo
118
127
  },
119
- TRouteInfoByFullPath = {
128
+ TRouteInfoByFullPath = { '/': TRouteInfo } & {
120
129
  [TInfo in TRouteInfo as TInfo['fullPath'] extends RootRouteId
121
130
  ? never
122
131
  : string extends TInfo['fullPath']
@@ -130,6 +139,7 @@ export interface RoutesInfoInner<
130
139
  routeInfoByFullPath: TRouteInfoByFullPath
131
140
  routeIds: keyof TRouteInfoById
132
141
  routePaths: keyof TRouteInfoByFullPath
142
+ fullSearchSchema: Partial<UnionToIntersection<TRouteInfo['fullSearchSchema']>>
133
143
  }
134
144
 
135
145
  export interface AnyRouteInfo
@@ -147,6 +157,8 @@ export interface AnyRouteInfo
147
157
  any,
148
158
  any,
149
159
  any,
160
+ any,
161
+ any,
150
162
  any
151
163
  > {}
152
164
 
@@ -155,7 +167,9 @@ export interface RouteInfo<
155
167
  TRouteId extends string = string,
156
168
  TPath extends string = string,
157
169
  TFullPath extends string = string,
170
+ TParentRouteLoaderData extends AnyLoaderData = {},
158
171
  TRouteLoaderData extends AnyLoaderData = {},
172
+ TParentLoaderData extends AnyLoaderData = {},
159
173
  TLoaderData extends AnyLoaderData = {},
160
174
  TActionPayload = unknown,
161
175
  TActionResponse = unknown,
@@ -163,17 +177,16 @@ export interface RouteInfo<
163
177
  TSearchSchema extends AnySearchSchema = {},
164
178
  TFullSearchSchema extends AnySearchSchema = {},
165
179
  TParentParams extends AnyPathParams = {},
166
- TParams extends Record<ParsePathParams<TPath>, unknown> = Record<
167
- ParsePathParams<TPath>,
168
- string
169
- >,
180
+ TParams extends AnyPathParams = {},
170
181
  TAllParams extends AnyPathParams = {},
171
182
  > {
172
183
  id: TId
173
184
  routeId: TRouteId
174
185
  path: TPath
175
186
  fullPath: TFullPath
187
+ parentRouteLoaderData: TParentRouteLoaderData
176
188
  routeLoaderData: TRouteLoaderData
189
+ parentLoaderData: TParentLoaderData
177
190
  loaderData: TLoaderData
178
191
  actionPayload: TActionPayload
179
192
  actionResponse: TActionResponse
@@ -185,7 +198,9 @@ export interface RouteInfo<
185
198
  options: RouteOptions<
186
199
  TRouteId,
187
200
  TPath,
201
+ TParentRouteLoaderData,
188
202
  TRouteLoaderData,
203
+ TParentLoaderData,
189
204
  TLoaderData,
190
205
  TActionPayload,
191
206
  TActionResponse,
package/src/routeMatch.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { GetFrameworkGeneric } from './frameworks'
2
2
  import { Route } from './route'
3
- import { AnyPathParams } from './routeConfig'
4
3
  import {
5
4
  AnyAllRouteInfo,
6
5
  AnyRouteInfo,
@@ -8,7 +7,7 @@ import {
8
7
  RouteInfo,
9
8
  } from './routeInfo'
10
9
  import { Router } from './router'
11
- import { replaceEqualDeep, Timeout } from './utils'
10
+ import { replaceEqualDeep } from './utils'
12
11
 
13
12
  export interface RouteMatch<
14
13
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
@@ -16,7 +15,7 @@ export interface RouteMatch<
16
15
  > extends Route<TAllRouteInfo, TRouteInfo> {
17
16
  matchId: string
18
17
  pathname: string
19
- params: TRouteInfo['params']
18
+ params: TRouteInfo['allParams']
20
19
  parentMatch?: RouteMatch
21
20
  childMatches: RouteMatch[]
22
21
  routeSearch: TRouteInfo['searchSchema']
@@ -29,20 +28,14 @@ export interface RouteMatch<
29
28
  loaderData: TRouteInfo['loaderData']
30
29
  routeLoaderData: TRouteInfo['routeLoaderData']
31
30
  isFetching: boolean
32
- isPending: boolean
33
31
  invalidAt: number
34
32
  __: {
35
- element?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
36
- errorElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
37
- catchElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
38
- pendingElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
33
+ component?: GetFrameworkGeneric<'Component'>
34
+ errorComponent?: GetFrameworkGeneric<'ErrorComponent'>
35
+ pendingComponent?: GetFrameworkGeneric<'Component'>
39
36
  loadPromise?: Promise<void>
40
- loaderPromise?: Promise<void>
41
- elementsPromise?: Promise<void>
42
- dataPromise?: Promise<void>
43
- pendingTimeout?: Timeout
44
- pendingMinTimeout?: Timeout
45
- pendingMinPromise?: Promise<void>
37
+ componentsPromise?: Promise<void>
38
+ dataPromise?: Promise<TRouteInfo['routeLoaderData']>
46
39
  onExit?:
47
40
  | void
48
41
  | ((matchContext: {
@@ -54,37 +47,34 @@ export interface RouteMatch<
54
47
  // setParentMatch: (parentMatch: RouteMatch) => void
55
48
  // addChildMatch: (childMatch: RouteMatch) => void
56
49
  validate: () => void
57
- startPending: () => void
58
- cancelPending: () => void
59
50
  notify: () => void
60
51
  resolve: () => void
61
52
  }
62
53
  cancel: () => void
63
54
  load: (
64
- loaderOpts?: { withPending?: boolean } & (
55
+ loaderOpts?:
65
56
  | { preload: true; maxAge: number; gcMaxAge: number }
66
- | { preload?: false; maxAge?: never; gcMaxAge?: never }
67
- ),
57
+ | { preload?: false; maxAge?: never; gcMaxAge?: never },
68
58
  ) => Promise<TRouteInfo['routeLoaderData']>
69
59
  fetch: (opts?: { maxAge?: number }) => Promise<TRouteInfo['routeLoaderData']>
70
60
  invalidate: () => void
71
61
  hasLoaders: () => boolean
72
62
  }
73
63
 
74
- const elementTypes = [
75
- 'element',
76
- 'errorElement',
77
- 'catchElement',
78
- 'pendingElement',
64
+ const componentTypes = [
65
+ 'component',
66
+ 'errorComponent',
67
+ 'pendingComponent',
79
68
  ] as const
80
69
 
81
70
  export function createRouteMatch<
82
71
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
83
72
  TRouteInfo extends AnyRouteInfo = RouteInfo,
84
73
  >(
85
- router: Router<any, any>,
74
+ router: Router<any, any, any>,
86
75
  route: Route<TAllRouteInfo, TRouteInfo>,
87
76
  opts: {
77
+ parentMatch?: RouteMatch<any, any>
88
78
  matchId: string
89
79
  params: TRouteInfo['allParams']
90
80
  pathname: string
@@ -100,10 +90,10 @@ export function createRouteMatch<
100
90
  status: 'idle',
101
91
  routeLoaderData: {} as TRouteInfo['routeLoaderData'],
102
92
  loaderData: {} as TRouteInfo['loaderData'],
103
- isPending: false,
104
93
  isFetching: false,
105
94
  isInvalid: false,
106
95
  invalidAt: Infinity,
96
+ // pendingActions: [],
107
97
  getIsInvalid: () => {
108
98
  const now = Date.now()
109
99
  return routeMatch.isInvalid || routeMatch.invalidAt < now
@@ -116,49 +106,6 @@ export function createRouteMatch<
116
106
  routeMatch.__.resolve()
117
107
  routeMatch.router.notify()
118
108
  },
119
- startPending: () => {
120
- const pendingMs =
121
- routeMatch.options.pendingMs ?? router.options.defaultPendingMs
122
- const pendingMinMs =
123
- routeMatch.options.pendingMinMs ?? router.options.defaultPendingMinMs
124
-
125
- if (
126
- routeMatch.__.pendingTimeout ||
127
- routeMatch.status !== 'loading' ||
128
- typeof pendingMs === 'undefined'
129
- ) {
130
- return
131
- }
132
-
133
- routeMatch.__.pendingTimeout = setTimeout(() => {
134
- routeMatch.isPending = true
135
- routeMatch.__.resolve()
136
- if (typeof pendingMinMs !== 'undefined') {
137
- routeMatch.__.pendingMinPromise = new Promise(
138
- (r) =>
139
- (routeMatch.__.pendingMinTimeout = setTimeout(r, pendingMinMs)),
140
- )
141
- }
142
- }, pendingMs)
143
- },
144
- cancelPending: () => {
145
- routeMatch.isPending = false
146
- clearTimeout(routeMatch.__.pendingTimeout)
147
- clearTimeout(routeMatch.__.pendingMinTimeout)
148
- delete routeMatch.__.pendingMinPromise
149
- },
150
- // setParentMatch: (parentMatch?: RouteMatch) => {
151
- // routeMatch.parentMatch = parentMatch
152
- // },
153
- // addChildMatch: (childMatch: RouteMatch) => {
154
- // if (
155
- // routeMatch.childMatches.find((d) => d.matchId === childMatch.matchId)
156
- // ) {
157
- // return
158
- // }
159
-
160
- // routeMatch.childMatches.push(childMatch)
161
- // },
162
109
  validate: () => {
163
110
  // Validate the search params and stabilize them
164
111
  const parentSearch =
@@ -174,7 +121,7 @@ export function createRouteMatch<
174
121
 
175
122
  let nextSearch = replaceEqualDeep(
176
123
  prevSearch,
177
- validator?.(parentSearch),
124
+ validator?.(parentSearch) ?? {},
178
125
  )
179
126
 
180
127
  // Invalidate route matches when search param stability changes
@@ -188,6 +135,14 @@ export function createRouteMatch<
188
135
  ...parentSearch,
189
136
  ...nextSearch,
190
137
  })
138
+
139
+ componentTypes.map(async (type) => {
140
+ const component = routeMatch.options[type]
141
+
142
+ if (typeof routeMatch.__[type] !== 'function') {
143
+ routeMatch.__[type] = component
144
+ }
145
+ })
191
146
  } catch (err: any) {
192
147
  console.error(err)
193
148
  const error = new (Error as any)('Invalid search params found', {
@@ -203,7 +158,6 @@ export function createRouteMatch<
203
158
  },
204
159
  cancel: () => {
205
160
  routeMatch.__.abortController?.abort()
206
- routeMatch.__.cancelPending()
207
161
  },
208
162
  invalidate: () => {
209
163
  routeMatch.isInvalid = true
@@ -211,7 +165,7 @@ export function createRouteMatch<
211
165
  hasLoaders: () => {
212
166
  return !!(
213
167
  route.options.loader ||
214
- elementTypes.some((d) => typeof route.options[d] === 'function')
168
+ componentTypes.some((d) => route.options[d]?.preload)
215
169
  )
216
170
  },
217
171
  load: async (loaderOpts) => {
@@ -243,12 +197,18 @@ export function createRouteMatch<
243
197
  ) {
244
198
  const maxAge = loaderOpts?.preload ? loaderOpts?.maxAge : undefined
245
199
 
246
- routeMatch.fetch({ maxAge })
200
+ await routeMatch.fetch({ maxAge })
247
201
  }
248
202
  },
249
203
  fetch: async (opts) => {
250
- const id = '' + Date.now() + Math.random()
251
- routeMatch.__.latestId = id
204
+ const loadId = '' + Date.now() + Math.random()
205
+ routeMatch.__.latestId = loadId
206
+ const checkLatest = async () => {
207
+ if (loadId !== routeMatch.__.latestId) {
208
+ // warning(true, 'Data loader is out of date!')
209
+ return new Promise(() => {})
210
+ }
211
+ }
252
212
 
253
213
  // If the match was in an error state, set it
254
214
  // to a loading state again. Otherwise, keep it
@@ -266,103 +226,81 @@ export function createRouteMatch<
266
226
  routeMatch.isFetching = true
267
227
  routeMatch.__.resolve = resolve as () => void
268
228
 
269
- const loaderPromise = (async () => {
270
- // Load the elements and data in parallel
271
-
272
- routeMatch.__.elementsPromise = (async () => {
273
- // then run all element and data loaders in parallel
274
- // For each element type, potentially load it asynchronously
229
+ routeMatch.__.componentsPromise = (async () => {
230
+ // then run all component and data loaders in parallel
231
+ // For each component type, potentially load it asynchronously
275
232
 
276
- await Promise.all(
277
- elementTypes.map(async (type) => {
278
- const routeElement = routeMatch.options[type]
233
+ await Promise.all(
234
+ componentTypes.map(async (type) => {
235
+ const component = routeMatch.options[type]
279
236
 
280
- if (routeMatch.__[type]) {
281
- return
282
- }
283
-
284
- routeMatch.__[type] = await router.options.createElement!(
285
- routeElement,
286
- )
287
- }),
288
- )
289
- })()
290
-
291
- routeMatch.__.dataPromise = Promise.resolve().then(async () => {
292
- try {
293
- if (routeMatch.options.loader) {
294
- const data = await routeMatch.options.loader({
295
- params: routeMatch.params,
296
- search: routeMatch.routeSearch,
297
- signal: routeMatch.__.abortController.signal,
298
- })
299
- if (id !== routeMatch.__.latestId) {
300
- return routeMatch.__.loaderPromise
301
- }
302
-
303
- routeMatch.routeLoaderData = replaceEqualDeep(
304
- routeMatch.routeLoaderData,
305
- data,
237
+ if (routeMatch.__[type]?.preload) {
238
+ routeMatch.__[type] = await router.options.loadComponent!(
239
+ component,
306
240
  )
307
241
  }
242
+ }),
243
+ )
244
+ })()
308
245
 
309
- routeMatch.error = undefined
310
- routeMatch.status = 'success'
311
- routeMatch.updatedAt = Date.now()
312
- routeMatch.invalidAt =
313
- routeMatch.updatedAt +
314
- (opts?.maxAge ??
315
- routeMatch.options.loaderMaxAge ??
316
- router.options.defaultLoaderMaxAge ??
317
- 0)
318
- } catch (err) {
319
- if (id !== routeMatch.__.latestId) {
320
- return routeMatch.__.loaderPromise
321
- }
322
-
323
- if (process.env.NODE_ENV !== 'production') {
324
- console.error(err)
325
- }
326
- routeMatch.error = err
327
- routeMatch.status = 'error'
328
- routeMatch.updatedAt = Date.now()
329
- }
330
- })
331
-
246
+ routeMatch.__.dataPromise = Promise.resolve().then(async () => {
332
247
  try {
333
- await Promise.all([
334
- routeMatch.__.elementsPromise,
335
- routeMatch.__.dataPromise,
336
- ])
337
- if (id !== routeMatch.__.latestId) {
338
- return routeMatch.__.loaderPromise
248
+ if (routeMatch.options.loader) {
249
+ const data = await router.loadMatchData(routeMatch)
250
+ await checkLatest()
251
+
252
+ routeMatch.routeLoaderData = replaceEqualDeep(
253
+ routeMatch.routeLoaderData,
254
+ data,
255
+ )
339
256
  }
340
257
 
341
- if (routeMatch.__.pendingMinPromise) {
342
- await routeMatch.__.pendingMinPromise
343
- delete routeMatch.__.pendingMinPromise
258
+ routeMatch.error = undefined
259
+ routeMatch.status = 'success'
260
+ routeMatch.updatedAt = Date.now()
261
+ routeMatch.invalidAt =
262
+ routeMatch.updatedAt +
263
+ (opts?.maxAge ??
264
+ routeMatch.options.loaderMaxAge ??
265
+ router.options.defaultLoaderMaxAge ??
266
+ 0)
267
+
268
+ return routeMatch.routeLoaderData
269
+ } catch (err) {
270
+ await checkLatest()
271
+
272
+ if (process.env.NODE_ENV !== 'production') {
273
+ console.error(err)
344
274
  }
345
- } finally {
346
- if (id !== routeMatch.__.latestId) {
347
- return routeMatch.__.loaderPromise
348
- }
349
- routeMatch.__.cancelPending()
350
- routeMatch.isPending = false
351
- routeMatch.isFetching = false
352
- routeMatch.__.notify()
275
+
276
+ routeMatch.error = err
277
+ routeMatch.status = 'error'
278
+ routeMatch.updatedAt = Date.now()
279
+
280
+ throw err
353
281
  }
354
- })()
282
+ })
355
283
 
356
- routeMatch.__.loaderPromise = loaderPromise
357
- await loaderPromise
284
+ const after = async () => {
285
+ await checkLatest()
286
+ routeMatch.isFetching = false
287
+ delete routeMatch.__.loadPromise
288
+ routeMatch.__.notify()
289
+ }
358
290
 
359
- if (id !== routeMatch.__.latestId) {
360
- return routeMatch.__.loaderPromise
291
+ try {
292
+ await Promise.all([
293
+ routeMatch.__.componentsPromise,
294
+ routeMatch.__.dataPromise.catch(() => {}),
295
+ ])
296
+ after()
297
+ } catch {
298
+ after()
361
299
  }
362
- delete routeMatch.__.loaderPromise
363
300
  })
364
301
 
365
- return await routeMatch.__.loadPromise
302
+ await routeMatch.__.loadPromise
303
+ await checkLatest()
366
304
  },
367
305
  }
368
306