@tanstack/router-core 0.0.1-alpha.3 → 0.0.1-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +30 -0
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -0
- package/build/cjs/packages/router-core/src/index.js +130 -98
- package/build/cjs/packages/router-core/src/index.js.map +1 -1
- package/build/esm/index.js +143 -99
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +60 -35
- package/build/types/index.d.ts +57 -38
- package/build/umd/index.development.js +139 -96
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -1
- package/src/index.ts +270 -185
- package/src/createRoutes.test.ts +0 -328
package/src/index.ts
CHANGED
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
History,
|
|
8
8
|
HashHistory,
|
|
9
9
|
} from 'history'
|
|
10
|
-
import
|
|
10
|
+
import invariant from 'tiny-invariant'
|
|
11
11
|
|
|
12
12
|
export { createHashHistory, createBrowserHistory, createMemoryHistory }
|
|
13
|
+
export { invariant }
|
|
13
14
|
|
|
14
15
|
import { decode, encode } from './qss'
|
|
15
16
|
|
|
@@ -62,6 +63,7 @@ export interface FrameworkGenerics {
|
|
|
62
63
|
|
|
63
64
|
export interface RouteConfig<
|
|
64
65
|
TId extends string = string,
|
|
66
|
+
TRouteId extends string = string,
|
|
65
67
|
TPath extends string = string,
|
|
66
68
|
TFullPath extends string = string,
|
|
67
69
|
TRouteLoaderData extends AnyLoaderData = AnyLoaderData,
|
|
@@ -80,9 +82,11 @@ export interface RouteConfig<
|
|
|
80
82
|
TKnownChildren = unknown,
|
|
81
83
|
> {
|
|
82
84
|
id: TId
|
|
85
|
+
routeId: TRouteId
|
|
83
86
|
path: NoInfer<TPath>
|
|
84
87
|
fullPath: TFullPath
|
|
85
88
|
options: RouteOptions<
|
|
89
|
+
TRouteId,
|
|
86
90
|
TPath,
|
|
87
91
|
TRouteLoaderData,
|
|
88
92
|
TLoaderData,
|
|
@@ -104,6 +108,7 @@ export interface RouteConfig<
|
|
|
104
108
|
createChildRoute: CreateRouteConfigFn<
|
|
105
109
|
false,
|
|
106
110
|
TId,
|
|
111
|
+
TFullPath,
|
|
107
112
|
TLoaderData,
|
|
108
113
|
TFullSearchSchema,
|
|
109
114
|
TAllParams
|
|
@@ -113,6 +118,7 @@ export interface RouteConfig<
|
|
|
113
118
|
: { error: 'Invalid route detected'; route: TNewChildren },
|
|
114
119
|
) => RouteConfig<
|
|
115
120
|
TId,
|
|
121
|
+
TRouteId,
|
|
116
122
|
TPath,
|
|
117
123
|
TFullPath,
|
|
118
124
|
TRouteLoaderData,
|
|
@@ -133,10 +139,12 @@ export interface RouteConfig<
|
|
|
133
139
|
type CreateRouteConfigFn<
|
|
134
140
|
TIsRoot extends boolean = false,
|
|
135
141
|
TParentId extends string = string,
|
|
142
|
+
TParentPath extends string = string,
|
|
136
143
|
TParentAllLoaderData extends AnyLoaderData = {},
|
|
137
144
|
TParentSearchSchema extends AnySearchSchema = {},
|
|
138
145
|
TParentParams extends AnyPathParams = {},
|
|
139
146
|
> = <
|
|
147
|
+
TRouteId extends string,
|
|
140
148
|
TPath extends string,
|
|
141
149
|
TRouteLoaderData extends AnyLoaderData,
|
|
142
150
|
TActionPayload,
|
|
@@ -152,10 +160,16 @@ type CreateRouteConfigFn<
|
|
|
152
160
|
? Record<ParsePathParams<TPath>, string>
|
|
153
161
|
: NoInfer<TParams>,
|
|
154
162
|
TKnownChildren extends RouteConfig[] = RouteConfig[],
|
|
163
|
+
TResolvedId extends string = string extends TRouteId
|
|
164
|
+
? string extends TPath
|
|
165
|
+
? string
|
|
166
|
+
: TPath
|
|
167
|
+
: TRouteId,
|
|
155
168
|
>(
|
|
156
169
|
options?: TIsRoot extends true
|
|
157
170
|
? Omit<
|
|
158
171
|
RouteOptions<
|
|
172
|
+
TRouteId,
|
|
159
173
|
TPath,
|
|
160
174
|
TRouteLoaderData,
|
|
161
175
|
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
|
|
@@ -171,6 +185,7 @@ type CreateRouteConfigFn<
|
|
|
171
185
|
'path'
|
|
172
186
|
> & { path?: never }
|
|
173
187
|
: RouteOptions<
|
|
188
|
+
TRouteId,
|
|
174
189
|
TPath,
|
|
175
190
|
TRouteLoaderData,
|
|
176
191
|
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
|
|
@@ -186,10 +201,12 @@ type CreateRouteConfigFn<
|
|
|
186
201
|
children?: TKnownChildren,
|
|
187
202
|
isRoot?: boolean,
|
|
188
203
|
parentId?: string,
|
|
204
|
+
parentPath?: string,
|
|
189
205
|
) => RouteConfig<
|
|
190
|
-
|
|
206
|
+
RoutePrefix<TParentId, TResolvedId>,
|
|
207
|
+
TResolvedId,
|
|
191
208
|
TPath,
|
|
192
|
-
|
|
209
|
+
string extends TPath ? '' : RoutePath<RoutePrefix<TParentPath, TPath>>,
|
|
193
210
|
TRouteLoaderData,
|
|
194
211
|
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
|
|
195
212
|
TActionPayload,
|
|
@@ -208,11 +225,10 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
|
|
|
208
225
|
children,
|
|
209
226
|
isRoot = true,
|
|
210
227
|
parentId,
|
|
228
|
+
parentPath,
|
|
211
229
|
) => {
|
|
212
230
|
if (isRoot) {
|
|
213
231
|
;(options as any).path = rootRouteId
|
|
214
|
-
} else {
|
|
215
|
-
warning(!options.path, 'Routes must have a path property.')
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
// Strip the root from parentIds
|
|
@@ -220,14 +236,16 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
|
|
|
220
236
|
parentId = ''
|
|
221
237
|
}
|
|
222
238
|
|
|
223
|
-
let path =
|
|
239
|
+
let path: undefined | string = isRoot ? rootRouteId : options.path
|
|
224
240
|
|
|
225
241
|
// If the path is anything other than an index path, trim it up
|
|
226
|
-
if (path !== '/') {
|
|
242
|
+
if (path && path !== '/') {
|
|
227
243
|
path = trimPath(path)
|
|
228
244
|
}
|
|
229
245
|
|
|
230
|
-
|
|
246
|
+
const routeId = path || (options as { id?: string }).id
|
|
247
|
+
|
|
248
|
+
let id = joinPaths([parentId, routeId])
|
|
231
249
|
|
|
232
250
|
if (path === rootRouteId) {
|
|
233
251
|
path = '/'
|
|
@@ -237,10 +255,12 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
|
|
|
237
255
|
id = joinPaths(['/', id])
|
|
238
256
|
}
|
|
239
257
|
|
|
240
|
-
const fullPath =
|
|
258
|
+
const fullPath =
|
|
259
|
+
id === rootRouteId ? '/' : trimPathRight(joinPaths([parentPath, path]))
|
|
241
260
|
|
|
242
261
|
return {
|
|
243
262
|
id: id as any,
|
|
263
|
+
routeId: routeId as any,
|
|
244
264
|
path: path as any,
|
|
245
265
|
fullPath: fullPath as any,
|
|
246
266
|
options: options as any,
|
|
@@ -249,10 +269,11 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
|
|
|
249
269
|
createRouteConfig(
|
|
250
270
|
options,
|
|
251
271
|
cb((childOptions: any) =>
|
|
252
|
-
createRouteConfig(childOptions, undefined, false, id),
|
|
272
|
+
createRouteConfig(childOptions, undefined, false, id, fullPath),
|
|
253
273
|
),
|
|
254
274
|
false,
|
|
255
275
|
parentId,
|
|
276
|
+
parentPath,
|
|
256
277
|
),
|
|
257
278
|
}
|
|
258
279
|
}
|
|
@@ -271,6 +292,8 @@ export interface AnyRouteConfig
|
|
|
271
292
|
any,
|
|
272
293
|
any,
|
|
273
294
|
any,
|
|
295
|
+
any,
|
|
296
|
+
any,
|
|
274
297
|
any
|
|
275
298
|
> {}
|
|
276
299
|
|
|
@@ -289,6 +312,7 @@ export interface AnyRouteConfigWithChildren<TChildren>
|
|
|
289
312
|
any,
|
|
290
313
|
any,
|
|
291
314
|
any,
|
|
315
|
+
any,
|
|
292
316
|
TChildren
|
|
293
317
|
> {}
|
|
294
318
|
|
|
@@ -297,7 +321,8 @@ export interface AnyAllRouteInfo {
|
|
|
297
321
|
routeInfo: AnyRouteInfo
|
|
298
322
|
routeInfoById: Record<string, AnyRouteInfo>
|
|
299
323
|
routeInfoByFullPath: Record<string, AnyRouteInfo>
|
|
300
|
-
|
|
324
|
+
routeIds: any
|
|
325
|
+
routePaths: any
|
|
301
326
|
}
|
|
302
327
|
|
|
303
328
|
export interface DefaultAllRouteInfo {
|
|
@@ -305,7 +330,8 @@ export interface DefaultAllRouteInfo {
|
|
|
305
330
|
routeInfo: RouteInfo
|
|
306
331
|
routeInfoById: Record<string, RouteInfo>
|
|
307
332
|
routeInfoByFullPath: Record<string, RouteInfo>
|
|
308
|
-
|
|
333
|
+
routeIds: string
|
|
334
|
+
routePaths: string
|
|
309
335
|
}
|
|
310
336
|
|
|
311
337
|
export interface AllRouteInfo<TRouteConfig extends AnyRouteConfig = RouteConfig>
|
|
@@ -325,20 +351,27 @@ export interface RoutesInfoInner<
|
|
|
325
351
|
any,
|
|
326
352
|
any,
|
|
327
353
|
any,
|
|
354
|
+
any,
|
|
355
|
+
any,
|
|
328
356
|
any
|
|
329
357
|
> = RouteInfo,
|
|
358
|
+
TRouteInfoById = {
|
|
359
|
+
[TInfo in TRouteInfo as TInfo['id']]: TInfo
|
|
360
|
+
},
|
|
361
|
+
TRouteInfoByFullPath = {
|
|
362
|
+
[TInfo in TRouteInfo as TInfo['fullPath'] extends RootRouteId
|
|
363
|
+
? never
|
|
364
|
+
: string extends TInfo['fullPath']
|
|
365
|
+
? never
|
|
366
|
+
: TInfo['fullPath']]: TInfo
|
|
367
|
+
},
|
|
330
368
|
> {
|
|
331
369
|
routeConfig: TRouteConfig
|
|
332
370
|
routeInfo: TRouteInfo
|
|
333
|
-
routeInfoById:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
[TInfo in TRouteInfo as TInfo['id'] extends RootRouteId
|
|
338
|
-
? never
|
|
339
|
-
: RouteIdToPath<TInfo['id']>]: TInfo
|
|
340
|
-
}
|
|
341
|
-
fullPath: RouteIdToPath<TRouteInfo['id']>
|
|
371
|
+
routeInfoById: TRouteInfoById
|
|
372
|
+
routeInfoByFullPath: TRouteInfoByFullPath
|
|
373
|
+
routeIds: keyof TRouteInfoById
|
|
374
|
+
routePaths: keyof TRouteInfoByFullPath
|
|
342
375
|
}
|
|
343
376
|
|
|
344
377
|
export interface AnyRoute extends Route<any, any> {}
|
|
@@ -356,6 +389,7 @@ export interface AnyRouteInfo
|
|
|
356
389
|
any,
|
|
357
390
|
any,
|
|
358
391
|
any,
|
|
392
|
+
any,
|
|
359
393
|
any
|
|
360
394
|
> {}
|
|
361
395
|
|
|
@@ -363,7 +397,7 @@ export interface AnyRouteInfo
|
|
|
363
397
|
// [E in T as E[TKey]]: E
|
|
364
398
|
// }
|
|
365
399
|
|
|
366
|
-
type
|
|
400
|
+
type RoutePath<T extends string> = T extends RootRouteId
|
|
367
401
|
? '/'
|
|
368
402
|
: TrimPathRight<`${T}`>
|
|
369
403
|
|
|
@@ -397,6 +431,7 @@ export type ValueKeys<O> = Extract<keyof O, PropertyKey>
|
|
|
397
431
|
|
|
398
432
|
export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
|
|
399
433
|
infer TId,
|
|
434
|
+
infer TRouteId,
|
|
400
435
|
infer TPath,
|
|
401
436
|
infer TFullPath,
|
|
402
437
|
infer TRouteLoaderData,
|
|
@@ -411,10 +446,11 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
|
|
|
411
446
|
infer TAllParams,
|
|
412
447
|
any
|
|
413
448
|
>
|
|
414
|
-
? string extends
|
|
449
|
+
? string extends TRouteId
|
|
415
450
|
? never
|
|
416
451
|
: RouteInfo<
|
|
417
452
|
TId,
|
|
453
|
+
TRouteId,
|
|
418
454
|
TPath,
|
|
419
455
|
TFullPath,
|
|
420
456
|
TRouteLoaderData,
|
|
@@ -432,8 +468,9 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
|
|
|
432
468
|
|
|
433
469
|
export interface RouteInfo<
|
|
434
470
|
TId extends string = string,
|
|
471
|
+
TRouteId extends string = string,
|
|
435
472
|
TPath extends string = string,
|
|
436
|
-
TFullPath extends
|
|
473
|
+
TFullPath extends string = string,
|
|
437
474
|
TRouteLoaderData extends AnyLoaderData = {},
|
|
438
475
|
TLoaderData extends AnyLoaderData = {},
|
|
439
476
|
TActionPayload = unknown,
|
|
@@ -449,6 +486,7 @@ export interface RouteInfo<
|
|
|
449
486
|
TAllParams extends AnyPathParams = {},
|
|
450
487
|
> {
|
|
451
488
|
id: TId
|
|
489
|
+
routeId: TRouteId
|
|
452
490
|
path: TPath
|
|
453
491
|
fullPath: TFullPath
|
|
454
492
|
routeLoaderData: TRouteLoaderData
|
|
@@ -461,6 +499,7 @@ export interface RouteInfo<
|
|
|
461
499
|
params: TParams
|
|
462
500
|
allParams: TAllParams
|
|
463
501
|
options: RouteOptions<
|
|
502
|
+
TRouteId,
|
|
464
503
|
TPath,
|
|
465
504
|
TRouteLoaderData,
|
|
466
505
|
TLoaderData,
|
|
@@ -484,14 +523,16 @@ type DeepAwaited<T> = T extends Promise<infer A>
|
|
|
484
523
|
export const rootRouteId = '__root__' as const
|
|
485
524
|
export type RootRouteId = typeof rootRouteId
|
|
486
525
|
|
|
487
|
-
type
|
|
526
|
+
type RoutePrefix<
|
|
488
527
|
TPrefix extends string,
|
|
489
|
-
|
|
490
|
-
> = string extends
|
|
528
|
+
TId extends string,
|
|
529
|
+
> = string extends TId
|
|
491
530
|
? RootRouteId
|
|
492
|
-
:
|
|
493
|
-
? '/'
|
|
494
|
-
|
|
531
|
+
: TId extends string
|
|
532
|
+
? `${TPrefix}/${TId}` extends '/'
|
|
533
|
+
? '/'
|
|
534
|
+
: `/${TrimPathLeft<`${TrimPathRight<TPrefix>}/${TrimPath<TId>}`>}`
|
|
535
|
+
: never
|
|
495
536
|
|
|
496
537
|
type CleanPath<T extends string> = T extends `${infer L}//${infer R}`
|
|
497
538
|
? CleanPath<`${CleanPath<L>}/${CleanPath<R>}`>
|
|
@@ -621,6 +662,7 @@ export type ParentParams<TParentParams> = AnyPathParams extends TParentParams
|
|
|
621
662
|
}
|
|
622
663
|
|
|
623
664
|
export type RouteOptions<
|
|
665
|
+
TRouteId extends string = string,
|
|
624
666
|
TPath extends string = string,
|
|
625
667
|
TRouteLoaderData extends AnyLoaderData = {},
|
|
626
668
|
TLoaderData extends AnyLoaderData = {},
|
|
@@ -635,9 +677,15 @@ export type RouteOptions<
|
|
|
635
677
|
string
|
|
636
678
|
>,
|
|
637
679
|
TAllParams extends AnyPathParams = {},
|
|
638
|
-
> =
|
|
639
|
-
|
|
640
|
-
|
|
680
|
+
> = (
|
|
681
|
+
| {
|
|
682
|
+
// The path to match (relative to the nearest parent `Route` component or root basepath)
|
|
683
|
+
path: TPath
|
|
684
|
+
}
|
|
685
|
+
| {
|
|
686
|
+
id: TRouteId
|
|
687
|
+
}
|
|
688
|
+
) & {
|
|
641
689
|
// If true, this route will be matched as case-sensitive
|
|
642
690
|
caseSensitive?: boolean
|
|
643
691
|
validateSearch?: SearchSchemaValidator<TSearchSchema, TParentSearchSchema>
|
|
@@ -654,20 +702,20 @@ export type RouteOptions<
|
|
|
654
702
|
// // An array of child routes
|
|
655
703
|
// children?: Route<any, any, any, any>[]
|
|
656
704
|
} & (
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
) &
|
|
705
|
+
| {
|
|
706
|
+
parseParams?: never
|
|
707
|
+
stringifyParams?: never
|
|
708
|
+
}
|
|
709
|
+
| {
|
|
710
|
+
// Parse params optionally receives path params as strings and returns them in a parsed format (like a number or boolean)
|
|
711
|
+
parseParams: (
|
|
712
|
+
rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
|
|
713
|
+
) => TParams
|
|
714
|
+
stringifyParams: (
|
|
715
|
+
params: TParams,
|
|
716
|
+
) => Record<ParsePathParams<TPath>, string>
|
|
717
|
+
}
|
|
718
|
+
) &
|
|
671
719
|
RouteLoaders<
|
|
672
720
|
// Route Loaders (see below) can be inline on the route, or resolved async
|
|
673
721
|
TRouteLoaderData,
|
|
@@ -779,7 +827,8 @@ export interface RouterState {
|
|
|
779
827
|
matches: RouteMatch[]
|
|
780
828
|
lastUpdated: number
|
|
781
829
|
loaderData: unknown
|
|
782
|
-
|
|
830
|
+
currentAction?: ActionState
|
|
831
|
+
latestAction?: ActionState
|
|
783
832
|
actions: Record<string, Action>
|
|
784
833
|
pending?: PendingState
|
|
785
834
|
}
|
|
@@ -900,7 +949,8 @@ export interface Action<
|
|
|
900
949
|
// TError = unknown,
|
|
901
950
|
> {
|
|
902
951
|
submit: (submission?: TPayload) => Promise<TResponse>
|
|
903
|
-
|
|
952
|
+
current?: ActionState<TPayload, TResponse>
|
|
953
|
+
latest?: ActionState<TPayload, TResponse>
|
|
904
954
|
pending: ActionState<TPayload, TResponse>[]
|
|
905
955
|
}
|
|
906
956
|
|
|
@@ -924,7 +974,7 @@ type RoutesById<TAllRouteInfo extends AnyAllRouteInfo> = {
|
|
|
924
974
|
}
|
|
925
975
|
|
|
926
976
|
// type RoutesByPath<TAllRouteInfo extends AnyAllRouteInfo> = {
|
|
927
|
-
// [K in TAllRouteInfo['
|
|
977
|
+
// [K in TAllRouteInfo['routePaths']]: Route<
|
|
928
978
|
// TAllRouteInfo,
|
|
929
979
|
// TAllRouteInfo['routeInfoByFullPath'][K]
|
|
930
980
|
// >
|
|
@@ -934,16 +984,16 @@ export type ValidFromPath<
|
|
|
934
984
|
TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
|
|
935
985
|
> =
|
|
936
986
|
| undefined
|
|
937
|
-
| (string extends TAllRouteInfo['
|
|
987
|
+
| (string extends TAllRouteInfo['routePaths']
|
|
938
988
|
? string
|
|
939
|
-
: TAllRouteInfo['
|
|
989
|
+
: TAllRouteInfo['routePaths'])
|
|
940
990
|
|
|
941
991
|
// type ValidToPath<
|
|
942
992
|
// TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
|
|
943
993
|
// TFrom = undefined,
|
|
944
994
|
// > = TFrom extends undefined
|
|
945
|
-
// ? TAllRouteInfo['
|
|
946
|
-
// : LooseAutocomplete<'.' | TAllRouteInfo['
|
|
995
|
+
// ? TAllRouteInfo['routePaths'] | `...unsafe-relative-path (cast "as any")`
|
|
996
|
+
// : LooseAutocomplete<'.' | TAllRouteInfo['routePaths']>
|
|
947
997
|
|
|
948
998
|
export interface Router<
|
|
949
999
|
TRouteConfig extends AnyRouteConfig = RouteConfig,
|
|
@@ -965,6 +1015,7 @@ export interface Router<
|
|
|
965
1015
|
routeTree: Route<TAllRouteInfo, RouteInfo>
|
|
966
1016
|
routesById: RoutesById<TAllRouteInfo>
|
|
967
1017
|
navigationPromise: Promise<void>
|
|
1018
|
+
removeActionQueue: { action: Action; actionState: ActionState }[]
|
|
968
1019
|
startedLoadingAt: number
|
|
969
1020
|
destroy: () => void
|
|
970
1021
|
resolveNavigation: () => void
|
|
@@ -1051,6 +1102,7 @@ export function createRouter<
|
|
|
1051
1102
|
let router: Router<TRouteConfig, TAllRouteInfo> = {
|
|
1052
1103
|
options: originalOptions,
|
|
1053
1104
|
listeners: [],
|
|
1105
|
+
removeActionQueue: [],
|
|
1054
1106
|
// Resolved after construction
|
|
1055
1107
|
basepath: '',
|
|
1056
1108
|
routeTree: undefined!,
|
|
@@ -1201,7 +1253,7 @@ export function createRouter<
|
|
|
1201
1253
|
|
|
1202
1254
|
const toMatches = router.matchRoutes(pathname)
|
|
1203
1255
|
|
|
1204
|
-
const prevParams = last(fromMatches)?.params
|
|
1256
|
+
const prevParams = { ...last(fromMatches)?.params }
|
|
1205
1257
|
|
|
1206
1258
|
let nextParams =
|
|
1207
1259
|
(dest.params ?? true) === true
|
|
@@ -1213,7 +1265,7 @@ export function createRouter<
|
|
|
1213
1265
|
.map((d) => d.options.stringifyParams)
|
|
1214
1266
|
.filter(Boolean)
|
|
1215
1267
|
.forEach((fn) => {
|
|
1216
|
-
Object.assign(nextParams!, fn!(nextParams!))
|
|
1268
|
+
Object.assign({}, nextParams!, fn!(nextParams!))
|
|
1217
1269
|
})
|
|
1218
1270
|
}
|
|
1219
1271
|
|
|
@@ -1358,10 +1410,23 @@ export function createRouter<
|
|
|
1358
1410
|
router.startedLoadingAt = id
|
|
1359
1411
|
|
|
1360
1412
|
if (next) {
|
|
1413
|
+
// If the location.href has changed
|
|
1414
|
+
|
|
1361
1415
|
// Ingest the new location
|
|
1362
1416
|
router.location = next
|
|
1363
1417
|
}
|
|
1364
1418
|
|
|
1419
|
+
// Clear out old actions
|
|
1420
|
+
router.removeActionQueue.forEach(({ action, actionState }) => {
|
|
1421
|
+
if (router.state.currentAction === actionState) {
|
|
1422
|
+
router.state.currentAction = undefined
|
|
1423
|
+
}
|
|
1424
|
+
if (action.current === actionState) {
|
|
1425
|
+
action.current = undefined
|
|
1426
|
+
}
|
|
1427
|
+
})
|
|
1428
|
+
router.removeActionQueue = []
|
|
1429
|
+
|
|
1365
1430
|
// Cancel any pending matches
|
|
1366
1431
|
router.cancelMatches()
|
|
1367
1432
|
|
|
@@ -1370,14 +1435,6 @@ export function createRouter<
|
|
|
1370
1435
|
strictParseParams: true,
|
|
1371
1436
|
})
|
|
1372
1437
|
|
|
1373
|
-
unloadedMatches.forEach((match, index) => {
|
|
1374
|
-
const parent = unloadedMatches[index - 1]
|
|
1375
|
-
const child = unloadedMatches[index + 1]
|
|
1376
|
-
|
|
1377
|
-
if (parent) match.__.setParentMatch(parent)
|
|
1378
|
-
if (child) match.__.addChildMatch(child)
|
|
1379
|
-
})
|
|
1380
|
-
|
|
1381
1438
|
router.state = {
|
|
1382
1439
|
...router.state,
|
|
1383
1440
|
pending: {
|
|
@@ -1506,69 +1563,95 @@ export function createRouter<
|
|
|
1506
1563
|
...(router.state.pending?.matches ?? []),
|
|
1507
1564
|
]
|
|
1508
1565
|
|
|
1509
|
-
const recurse = async (
|
|
1510
|
-
|
|
1511
|
-
parentMatch?: RouteMatch,
|
|
1512
|
-
): Promise<void> => {
|
|
1566
|
+
const recurse = async (routes: Route<any, any>[]): Promise<void> => {
|
|
1567
|
+
const parentMatch = last(matches)
|
|
1513
1568
|
let params = parentMatch?.params ?? {}
|
|
1514
1569
|
|
|
1515
1570
|
const filteredRoutes = router.options.filterRoutes?.(routes) ?? routes
|
|
1516
1571
|
|
|
1517
|
-
|
|
1518
|
-
const fuzzy = !!(route.routePath !== '/' || route.childRoutes?.length)
|
|
1519
|
-
const matchParams = matchPathname(pathname, {
|
|
1520
|
-
to: route.fullPath,
|
|
1521
|
-
fuzzy,
|
|
1522
|
-
caseSensitive:
|
|
1523
|
-
route.options.caseSensitive ?? router.options.caseSensitive,
|
|
1524
|
-
})
|
|
1572
|
+
let foundRoutes: Route[] = []
|
|
1525
1573
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1574
|
+
const findMatchInRoutes = (parentRoutes: Route[], routes: Route[]) => {
|
|
1575
|
+
routes.some((route) => {
|
|
1576
|
+
if (!route.routePath && route.childRoutes?.length) {
|
|
1577
|
+
return findMatchInRoutes(
|
|
1578
|
+
[...foundRoutes, route],
|
|
1579
|
+
route.childRoutes,
|
|
1580
|
+
)
|
|
1581
|
+
}
|
|
1528
1582
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1583
|
+
const fuzzy = !!(
|
|
1584
|
+
route.routePath !== '/' || route.childRoutes?.length
|
|
1585
|
+
)
|
|
1586
|
+
|
|
1587
|
+
const matchParams = matchPathname(pathname, {
|
|
1588
|
+
to: route.fullPath,
|
|
1589
|
+
fuzzy,
|
|
1590
|
+
caseSensitive:
|
|
1591
|
+
route.options.caseSensitive ?? router.options.caseSensitive,
|
|
1592
|
+
})
|
|
1593
|
+
|
|
1594
|
+
if (matchParams) {
|
|
1595
|
+
let parsedParams
|
|
1596
|
+
|
|
1597
|
+
try {
|
|
1598
|
+
parsedParams =
|
|
1599
|
+
route.options.parseParams?.(matchParams!) ?? matchParams
|
|
1600
|
+
} catch (err) {
|
|
1601
|
+
if (opts?.strictParseParams) {
|
|
1602
|
+
throw err
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
params = {
|
|
1607
|
+
...params,
|
|
1608
|
+
...parsedParams,
|
|
1535
1609
|
}
|
|
1536
1610
|
}
|
|
1537
1611
|
|
|
1538
|
-
|
|
1539
|
-
...
|
|
1540
|
-
...parsedParams,
|
|
1612
|
+
if (!!matchParams) {
|
|
1613
|
+
foundRoutes = [...parentRoutes, route]
|
|
1541
1614
|
}
|
|
1542
|
-
}
|
|
1543
1615
|
|
|
1544
|
-
|
|
1545
|
-
|
|
1616
|
+
return !!foundRoutes.length
|
|
1617
|
+
})
|
|
1618
|
+
|
|
1619
|
+
return !!foundRoutes.length
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
findMatchInRoutes([], filteredRoutes)
|
|
1546
1623
|
|
|
1547
|
-
if (!
|
|
1624
|
+
if (!foundRoutes.length) {
|
|
1548
1625
|
return
|
|
1549
1626
|
}
|
|
1550
1627
|
|
|
1551
|
-
|
|
1552
|
-
|
|
1628
|
+
foundRoutes.forEach((foundRoute) => {
|
|
1629
|
+
const interpolatedPath = interpolatePath(foundRoute.routePath, params)
|
|
1630
|
+
const matchId = interpolatePath(foundRoute.routeId, params, true)
|
|
1553
1631
|
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1632
|
+
const match =
|
|
1633
|
+
existingMatches.find((d) => d.matchId === matchId) ||
|
|
1634
|
+
router.preloadCache[matchId]?.match ||
|
|
1635
|
+
createRouteMatch(router, foundRoute, {
|
|
1636
|
+
matchId,
|
|
1637
|
+
params,
|
|
1638
|
+
pathname: joinPaths([pathname, interpolatedPath]),
|
|
1639
|
+
})
|
|
1562
1640
|
|
|
1563
|
-
|
|
1641
|
+
matches.push(match)
|
|
1642
|
+
})
|
|
1643
|
+
|
|
1644
|
+
const foundRoute = last(foundRoutes)!
|
|
1564
1645
|
|
|
1565
|
-
if (
|
|
1566
|
-
recurse(
|
|
1646
|
+
if (foundRoute.childRoutes?.length) {
|
|
1647
|
+
recurse(foundRoute.childRoutes)
|
|
1567
1648
|
}
|
|
1568
1649
|
}
|
|
1569
1650
|
|
|
1570
1651
|
recurse([router.routeTree])
|
|
1571
1652
|
|
|
1653
|
+
cascadeLoaderData(matches)
|
|
1654
|
+
|
|
1572
1655
|
return matches
|
|
1573
1656
|
},
|
|
1574
1657
|
|
|
@@ -1690,14 +1773,10 @@ export function createRouter<
|
|
|
1690
1773
|
isExternal = true
|
|
1691
1774
|
} catch (e) {}
|
|
1692
1775
|
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
)
|
|
1698
|
-
}
|
|
1699
|
-
return
|
|
1700
|
-
}
|
|
1776
|
+
invariant(
|
|
1777
|
+
!isExternal,
|
|
1778
|
+
'Attempting to navigate to external url with router.navigate!',
|
|
1779
|
+
)
|
|
1701
1780
|
|
|
1702
1781
|
return router._navigate({
|
|
1703
1782
|
from: fromString,
|
|
@@ -1867,6 +1946,7 @@ export interface Route<
|
|
|
1867
1946
|
TRouteInfo extends AnyRouteInfo = RouteInfo,
|
|
1868
1947
|
> {
|
|
1869
1948
|
routeId: TRouteInfo['id']
|
|
1949
|
+
routeRouteId: TRouteInfo['routeId']
|
|
1870
1950
|
routePath: TRouteInfo['path']
|
|
1871
1951
|
fullPath: TRouteInfo['fullPath']
|
|
1872
1952
|
parentRoute?: AnyRoute
|
|
@@ -1874,23 +1954,21 @@ export interface Route<
|
|
|
1874
1954
|
options: RouteOptions
|
|
1875
1955
|
router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo>
|
|
1876
1956
|
buildLink: <TTo extends string = '.'>(
|
|
1877
|
-
options:
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
// > &
|
|
1882
|
-
Omit<LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
|
|
1957
|
+
options: Omit<
|
|
1958
|
+
LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
|
|
1959
|
+
'from'
|
|
1960
|
+
>,
|
|
1883
1961
|
) => LinkInfo
|
|
1884
1962
|
matchRoute: <
|
|
1885
1963
|
TTo extends string = '.',
|
|
1886
1964
|
TResolved extends string = ResolveRelativePath<TRouteInfo['id'], TTo>,
|
|
1887
1965
|
>(
|
|
1888
|
-
matchLocation:
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1966
|
+
matchLocation: CheckRelativePath<
|
|
1967
|
+
TAllRouteInfo,
|
|
1968
|
+
TRouteInfo['fullPath'],
|
|
1969
|
+
NoInfer<TTo>
|
|
1970
|
+
> &
|
|
1971
|
+
Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
|
|
1894
1972
|
opts?: MatchRouteOptions,
|
|
1895
1973
|
) => RouteInfoByPath<TAllRouteInfo, TResolved>['allParams']
|
|
1896
1974
|
navigate: <TTo extends string = '.'>(
|
|
@@ -1921,12 +1999,12 @@ export function createRoute<
|
|
|
1921
1999
|
// ]).replace(new RegExp(`^${rootRouteId}`), '')
|
|
1922
2000
|
// ) as TRouteInfo['id']
|
|
1923
2001
|
|
|
1924
|
-
const { id
|
|
2002
|
+
const { id, routeId, path: routePath, fullPath } = routeConfig
|
|
1925
2003
|
|
|
1926
2004
|
const action =
|
|
1927
|
-
router.state.actions[
|
|
2005
|
+
router.state.actions[id] ||
|
|
1928
2006
|
(() => {
|
|
1929
|
-
router.state.actions[
|
|
2007
|
+
router.state.actions[id] = {
|
|
1930
2008
|
pending: [],
|
|
1931
2009
|
submit: async <T, U>(
|
|
1932
2010
|
submission: T,
|
|
@@ -1944,12 +2022,14 @@ export function createRoute<
|
|
|
1944
2022
|
submission,
|
|
1945
2023
|
}
|
|
1946
2024
|
|
|
2025
|
+
action.current = actionState
|
|
1947
2026
|
action.latest = actionState
|
|
1948
2027
|
action.pending.push(actionState)
|
|
1949
2028
|
|
|
1950
2029
|
router.state = {
|
|
1951
2030
|
...router.state,
|
|
1952
|
-
|
|
2031
|
+
currentAction: actionState,
|
|
2032
|
+
latestAction: actionState,
|
|
1953
2033
|
}
|
|
1954
2034
|
|
|
1955
2035
|
router.notify()
|
|
@@ -1969,18 +2049,17 @@ export function createRoute<
|
|
|
1969
2049
|
actionState.status = 'error'
|
|
1970
2050
|
} finally {
|
|
1971
2051
|
action.pending = action.pending.filter((d) => d !== actionState)
|
|
1972
|
-
|
|
1973
|
-
router.state.action = undefined
|
|
1974
|
-
}
|
|
2052
|
+
router.removeActionQueue.push({ action, actionState })
|
|
1975
2053
|
router.notify()
|
|
1976
2054
|
}
|
|
1977
2055
|
},
|
|
1978
2056
|
}
|
|
1979
|
-
return router.state.actions[
|
|
2057
|
+
return router.state.actions[id]!
|
|
1980
2058
|
})()
|
|
1981
2059
|
|
|
1982
2060
|
let route: Route<TAllRouteInfo, TRouteInfo> = {
|
|
1983
|
-
routeId,
|
|
2061
|
+
routeId: id,
|
|
2062
|
+
routeRouteId: routeId,
|
|
1984
2063
|
routePath,
|
|
1985
2064
|
fullPath,
|
|
1986
2065
|
options,
|
|
@@ -2099,7 +2178,8 @@ export type ToOptions<
|
|
|
2099
2178
|
from?: TFrom
|
|
2100
2179
|
// // When using relative route paths, this option forces resolution from the current path, instead of the route API's path or `from` path
|
|
2101
2180
|
// fromCurrent?: boolean
|
|
2102
|
-
} &
|
|
2181
|
+
} & CheckPath<TAllRouteInfo, NoInfer<TResolvedTo>> &
|
|
2182
|
+
SearchParamOptions<TAllRouteInfo, TFrom, TResolvedTo> &
|
|
2103
2183
|
PathParamOptions<TAllRouteInfo, TFrom, TResolvedTo>
|
|
2104
2184
|
|
|
2105
2185
|
export type ToPathOption<
|
|
@@ -2109,7 +2189,7 @@ export type ToPathOption<
|
|
|
2109
2189
|
> =
|
|
2110
2190
|
| TTo
|
|
2111
2191
|
| RelativeToPathAutoComplete<
|
|
2112
|
-
TAllRouteInfo['
|
|
2192
|
+
TAllRouteInfo['routePaths'],
|
|
2113
2193
|
NoInfer<TFrom> extends string ? NoInfer<TFrom> : '',
|
|
2114
2194
|
NoInfer<TTo> & string
|
|
2115
2195
|
>
|
|
@@ -2121,7 +2201,7 @@ export type ToIdOption<
|
|
|
2121
2201
|
> =
|
|
2122
2202
|
| TTo
|
|
2123
2203
|
| RelativeToPathAutoComplete<
|
|
2124
|
-
TAllRouteInfo['
|
|
2204
|
+
TAllRouteInfo['routeIds'],
|
|
2125
2205
|
NoInfer<TFrom> extends string ? NoInfer<TFrom> : '',
|
|
2126
2206
|
NoInfer<TTo> & string
|
|
2127
2207
|
>
|
|
@@ -2151,23 +2231,33 @@ export type CheckRelativePath<
|
|
|
2151
2231
|
TTo,
|
|
2152
2232
|
> = TTo extends string
|
|
2153
2233
|
? TFrom extends string
|
|
2154
|
-
? ResolveRelativePath<TFrom, TTo> extends TAllRouteInfo['
|
|
2234
|
+
? ResolveRelativePath<TFrom, TTo> extends TAllRouteInfo['routePaths']
|
|
2155
2235
|
? {}
|
|
2156
2236
|
: {
|
|
2157
2237
|
Error: `${TFrom} + ${TTo} resolves to ${ResolveRelativePath<
|
|
2158
2238
|
TFrom,
|
|
2159
2239
|
TTo
|
|
2160
2240
|
>}, which is not a valid route path.`
|
|
2161
|
-
'Valid Route Paths': TAllRouteInfo['
|
|
2241
|
+
'Valid Route Paths': TAllRouteInfo['routePaths']
|
|
2162
2242
|
}
|
|
2163
2243
|
: {}
|
|
2164
2244
|
: {}
|
|
2165
2245
|
|
|
2166
|
-
export type
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2246
|
+
export type CheckPath<TAllRouteInfo extends AnyAllRouteInfo, TPath> = Exclude<
|
|
2247
|
+
TPath,
|
|
2248
|
+
TAllRouteInfo['routePaths']
|
|
2249
|
+
> extends never
|
|
2250
|
+
? {}
|
|
2251
|
+
: CheckPathError<TAllRouteInfo, Exclude<TPath, TAllRouteInfo['routePaths']>>
|
|
2252
|
+
|
|
2253
|
+
export type CheckPathError<TAllRouteInfo extends AnyAllRouteInfo, TInvalids> = {
|
|
2254
|
+
Error: `${TInvalids extends string
|
|
2255
|
+
? TInvalids
|
|
2256
|
+
: never} is not a valid route path.`
|
|
2257
|
+
'Valid Route Paths': TAllRouteInfo['routePaths']
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
export type ResolveRelativePath<TFrom, TTo = '.'> = TFrom extends string
|
|
2171
2261
|
? TTo extends string
|
|
2172
2262
|
? TTo extends '.'
|
|
2173
2263
|
? TFrom
|
|
@@ -2215,21 +2305,19 @@ type SearchParamOptions<
|
|
|
2215
2305
|
TTo,
|
|
2216
2306
|
TFromSchema = RouteInfoByPath<TAllRouteInfo, TFrom>['fullSearchSchema'],
|
|
2217
2307
|
TToSchema = RouteInfoByPath<TAllRouteInfo, TTo>['fullSearchSchema'],
|
|
2218
|
-
> =
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
search: SearchReducer<TFromSchema, TToSchema>
|
|
2232
|
-
}
|
|
2308
|
+
> = StartsWith<TFrom, TTo> extends true // If the next route search extend or cover the from route, params will be optional
|
|
2309
|
+
? {
|
|
2310
|
+
search?: SearchReducer<TFromSchema, TToSchema>
|
|
2311
|
+
}
|
|
2312
|
+
: // Optional search params? Allow it
|
|
2313
|
+
keyof PickRequired<TToSchema> extends never
|
|
2314
|
+
? {
|
|
2315
|
+
search?: SearchReducer<TFromSchema, TToSchema>
|
|
2316
|
+
}
|
|
2317
|
+
: {
|
|
2318
|
+
// Must have required search params, enforce it
|
|
2319
|
+
search: SearchReducer<TFromSchema, TToSchema>
|
|
2320
|
+
}
|
|
2233
2321
|
|
|
2234
2322
|
type SearchReducer<TFrom, TTo> = TTo | ((current: TFrom) => TTo)
|
|
2235
2323
|
|
|
@@ -2297,8 +2385,8 @@ export interface RouteMatch<
|
|
|
2297
2385
|
}) => void)
|
|
2298
2386
|
abortController: AbortController
|
|
2299
2387
|
latestId: string
|
|
2300
|
-
setParentMatch: (parentMatch: RouteMatch) => void
|
|
2301
|
-
addChildMatch: (childMatch: RouteMatch) => void
|
|
2388
|
+
// setParentMatch: (parentMatch: RouteMatch) => void
|
|
2389
|
+
// addChildMatch: (childMatch: RouteMatch) => void
|
|
2302
2390
|
validate: () => void
|
|
2303
2391
|
startPending: () => void
|
|
2304
2392
|
cancelPending: () => void
|
|
@@ -2373,18 +2461,18 @@ export function createRouteMatch<
|
|
|
2373
2461
|
clearTimeout(routeMatch.__.pendingMinTimeout)
|
|
2374
2462
|
delete routeMatch.__.pendingMinPromise
|
|
2375
2463
|
},
|
|
2376
|
-
setParentMatch: (parentMatch?: RouteMatch) => {
|
|
2377
|
-
|
|
2378
|
-
},
|
|
2379
|
-
addChildMatch: (childMatch: RouteMatch) => {
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
},
|
|
2464
|
+
// setParentMatch: (parentMatch?: RouteMatch) => {
|
|
2465
|
+
// routeMatch.parentMatch = parentMatch
|
|
2466
|
+
// },
|
|
2467
|
+
// addChildMatch: (childMatch: RouteMatch) => {
|
|
2468
|
+
// if (
|
|
2469
|
+
// routeMatch.childMatches.find((d) => d.matchId === childMatch.matchId)
|
|
2470
|
+
// ) {
|
|
2471
|
+
// return
|
|
2472
|
+
// }
|
|
2473
|
+
|
|
2474
|
+
// routeMatch.childMatches.push(childMatch)
|
|
2475
|
+
// },
|
|
2388
2476
|
validate: () => {
|
|
2389
2477
|
// Validate the search params and stabilize them
|
|
2390
2478
|
const parentSearch =
|
|
@@ -2513,7 +2601,6 @@ export function createRouteMatch<
|
|
|
2513
2601
|
data,
|
|
2514
2602
|
)
|
|
2515
2603
|
|
|
2516
|
-
cascadeLoaderData(routeMatch)
|
|
2517
2604
|
routeMatch.error = undefined
|
|
2518
2605
|
routeMatch.status = 'success'
|
|
2519
2606
|
routeMatch.updatedAt = Date.now()
|
|
@@ -2571,19 +2658,17 @@ export function createRouteMatch<
|
|
|
2571
2658
|
return routeMatch
|
|
2572
2659
|
}
|
|
2573
2660
|
|
|
2574
|
-
function cascadeLoaderData(
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
...routeMatch.parentMatch.loaderData,
|
|
2578
|
-
...routeMatch.routeLoaderData,
|
|
2579
|
-
})
|
|
2580
|
-
}
|
|
2661
|
+
function cascadeLoaderData(matches: RouteMatch<any, any>[]) {
|
|
2662
|
+
matches.forEach((match, index) => {
|
|
2663
|
+
const parent = matches[index - 1]
|
|
2581
2664
|
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2665
|
+
if (parent) {
|
|
2666
|
+
match.loaderData = replaceEqualDeep(match.loaderData, {
|
|
2667
|
+
...parent.loaderData,
|
|
2668
|
+
...match.routeLoaderData,
|
|
2669
|
+
})
|
|
2670
|
+
}
|
|
2671
|
+
})
|
|
2587
2672
|
}
|
|
2588
2673
|
|
|
2589
2674
|
export function matchPathname(
|