@tanstack/react-router 1.74.6 → 1.75.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
- "version": "1.74.6",
3
+ "version": "1.75.0",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/route.ts CHANGED
@@ -498,6 +498,38 @@ export interface SearchValidatorAdapter<TInput, TOutput> {
498
498
 
499
499
  export type AnySearchValidatorAdapter = SearchValidatorAdapter<any, any>
500
500
 
501
+ export interface StandardSchemaValidator<TInput, TOutput> {
502
+ readonly '~types'?: StandardSchemaValidatorTypes<TInput, TOutput> | undefined
503
+ readonly '~validate': AnyStandardSchemaValidate
504
+ }
505
+
506
+ export type AnyStandardSchemaValidator = StandardSchemaValidator<any, any>
507
+
508
+ export interface StandardSchemaValidatorTypes<TInput, TOutput> {
509
+ readonly input: TInput
510
+ readonly output: TOutput
511
+ }
512
+
513
+ export interface AnyStandardSchemaValidateSuccess {
514
+ readonly value: any
515
+ }
516
+
517
+ export interface AnyStandardSchemaValidateFailure {
518
+ readonly issues: ReadonlyArray<AnyStandardSchemaValidateIssue>
519
+ }
520
+
521
+ export interface AnyStandardSchemaValidateIssue {
522
+ readonly message: string
523
+ }
524
+
525
+ export interface AnyStandardSchemaValidateInput {
526
+ readonly value: any
527
+ }
528
+
529
+ export type AnyStandardSchemaValidate = (
530
+ input: AnyStandardSchemaValidateInput,
531
+ ) => AnyStandardSchemaValidateSuccess | AnyStandardSchemaValidateFailure
532
+
501
533
  export type AnySearchValidatorFn = SearchValidatorFn<any, any>
502
534
 
503
535
  export type SearchValidatorFn<TInput, TOutput> = (input: TInput) => TOutput
@@ -506,6 +538,7 @@ export type SearchValidator<TInput, TOutput> =
506
538
  | SearchValidatorObj<TInput, TOutput>
507
539
  | SearchValidatorFn<TInput, TOutput>
508
540
  | SearchValidatorAdapter<TInput, TOutput>
541
+ | StandardSchemaValidator<TInput, TOutput>
509
542
  | undefined
510
543
 
511
544
  export type AnySearchValidator = SearchValidator<any, any>
@@ -624,11 +657,13 @@ export type ResolveSearchSchemaFnInput<TSearchValidator> =
624
657
  : AnySearchSchema
625
658
 
626
659
  export type ResolveSearchSchemaInput<TSearchValidator> =
627
- TSearchValidator extends AnySearchValidatorAdapter
628
- ? TSearchValidator['types']['input']
629
- : TSearchValidator extends AnySearchValidatorObj
630
- ? ResolveSearchSchemaFnInput<TSearchValidator['parse']>
631
- : ResolveSearchSchemaFnInput<TSearchValidator>
660
+ TSearchValidator extends AnyStandardSchemaValidator
661
+ ? NonNullable<TSearchValidator['~types']>['input']
662
+ : TSearchValidator extends AnySearchValidatorAdapter
663
+ ? TSearchValidator['types']['input']
664
+ : TSearchValidator extends AnySearchValidatorObj
665
+ ? ResolveSearchSchemaFnInput<TSearchValidator['parse']>
666
+ : ResolveSearchSchemaFnInput<TSearchValidator>
632
667
 
633
668
  export type ResolveSearchSchemaFn<TSearchValidator> = TSearchValidator extends (
634
669
  ...args: any
@@ -639,11 +674,13 @@ export type ResolveSearchSchemaFn<TSearchValidator> = TSearchValidator extends (
639
674
  export type ResolveSearchSchema<TSearchValidator> =
640
675
  unknown extends TSearchValidator
641
676
  ? TSearchValidator
642
- : TSearchValidator extends AnySearchValidatorAdapter
643
- ? TSearchValidator['types']['output']
644
- : TSearchValidator extends AnySearchValidatorObj
645
- ? ResolveSearchSchemaFn<TSearchValidator['parse']>
646
- : ResolveSearchSchemaFn<TSearchValidator>
677
+ : TSearchValidator extends AnyStandardSchemaValidator
678
+ ? NonNullable<TSearchValidator['~types']>['output']
679
+ : TSearchValidator extends AnySearchValidatorAdapter
680
+ ? TSearchValidator['types']['output']
681
+ : TSearchValidator extends AnySearchValidatorObj
682
+ ? ResolveSearchSchemaFn<TSearchValidator['parse']>
683
+ : ResolveSearchSchemaFn<TSearchValidator>
647
684
 
648
685
  export type ResolveFullSearchSchema<
649
686
  TParentRoute extends AnyRoute,
package/src/router.ts CHANGED
@@ -43,6 +43,7 @@ import type {
43
43
  AnyRoute,
44
44
  AnyRouteWithContext,
45
45
  AnySearchSchema,
46
+ AnySearchValidator,
46
47
  BeforeLoadContextOptions,
47
48
  ErrorRouteComponent,
48
49
  LoaderFnContext,
@@ -557,6 +558,31 @@ function routeNeedsPreload(route: AnyRoute) {
557
558
  return false
558
559
  }
559
560
 
561
+ function validateSearch(
562
+ validateSearch: AnySearchValidator,
563
+ input: unknown,
564
+ ): unknown {
565
+ if (validateSearch == null) return {}
566
+
567
+ if ('~validate' in validateSearch) {
568
+ const result = validateSearch['~validate']({ value: input })
569
+
570
+ if ('value' in result) return result.value
571
+
572
+ throw new SearchParamError(JSON.stringify(result.issues, undefined, 2))
573
+ }
574
+
575
+ if ('parse' in validateSearch) {
576
+ return validateSearch.parse(input)
577
+ }
578
+
579
+ if (typeof validateSearch === 'function') {
580
+ return validateSearch(input)
581
+ }
582
+
583
+ return {}
584
+ }
585
+
560
586
  export type RouterEvents = {
561
587
  onBeforeNavigate: {
562
588
  type: 'onBeforeNavigate'
@@ -1114,12 +1140,8 @@ export class Router<
1114
1140
  const parentSearch = parentMatch?.search ?? next.search
1115
1141
 
1116
1142
  try {
1117
- const validator =
1118
- typeof route.options.validateSearch === 'object'
1119
- ? route.options.validateSearch.parse
1120
- : route.options.validateSearch
1121
-
1122
- const search = validator?.(parentSearch) ?? {}
1143
+ const search =
1144
+ validateSearch(route.options.validateSearch, parentSearch) ?? {}
1123
1145
 
1124
1146
  return [
1125
1147
  {
@@ -1444,13 +1466,12 @@ export class Router<
1444
1466
  matchedRoutesResult?.matchedRoutes.forEach((route) => {
1445
1467
  try {
1446
1468
  if (route.options.validateSearch) {
1447
- const validator =
1448
- typeof route.options.validateSearch === 'object'
1449
- ? route.options.validateSearch.parse
1450
- : route.options.validateSearch
1451
1469
  validatedSearch = {
1452
1470
  ...validatedSearch,
1453
- ...validator({ ...validatedSearch, ...search }),
1471
+ ...(validateSearch(route.options.validateSearch, {
1472
+ ...validatedSearch,
1473
+ ...search,
1474
+ }) ?? {}),
1454
1475
  }
1455
1476
  }
1456
1477
  } catch (e) {