@devp0nt/route0 1.0.0-next.26 → 1.0.0-next.28

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/src/index.ts CHANGED
@@ -494,17 +494,45 @@ export class Route0<TDefinition extends string> {
494
494
  }
495
495
 
496
496
  isChildren(other: Route0<TDefinition>): boolean {
497
- return (
498
- this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===
499
- other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')
500
- )
497
+ // this is a child of other if:
498
+ // - paths are not exactly the same
499
+ // - other's path is a prefix of this path, matching params as wildcards
500
+ const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))
501
+ const thisParts = getParts(this.pathDefinition)
502
+ const otherParts = getParts(other.pathDefinition)
503
+
504
+ // A child must be deeper
505
+ if (thisParts.length <= otherParts.length) return false
506
+
507
+ for (let i = 0; i < otherParts.length; i++) {
508
+ const otherPart = otherParts[i]
509
+ const thisPart = thisParts[i]
510
+ if (otherPart.startsWith(':')) continue
511
+ if (otherPart !== thisPart) return false
512
+ }
513
+ // Not equal (depth already ensures not equal)
514
+ return true
501
515
  }
502
516
 
503
517
  isParent(other: Route0<TDefinition>): boolean {
504
- return (
505
- other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===
506
- this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')
507
- )
518
+ // this is a parent of other if:
519
+ // - paths are not exactly the same
520
+ // - this path is a prefix of other path, matching params as wildcards
521
+ const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))
522
+ const thisParts = getParts(this.pathDefinition)
523
+ const otherParts = getParts(other.pathDefinition)
524
+
525
+ // A parent must be shallower
526
+ if (thisParts.length >= otherParts.length) return false
527
+
528
+ for (let i = 0; i < thisParts.length; i++) {
529
+ const thisPart = thisParts[i]
530
+ const otherPart = otherParts[i]
531
+ if (thisPart.startsWith(':')) continue
532
+ if (thisPart !== otherPart) return false
533
+ }
534
+ // Not equal (depth already ensures not equal)
535
+ return true
508
536
  }
509
537
 
510
538
  isConflict(other: Route0<any>): boolean {
@@ -571,10 +599,18 @@ export class Route0<TDefinition extends string> {
571
599
  }
572
600
 
573
601
  export class Routes<const T extends RoutesRecord = RoutesRecord> {
574
- readonly routes: RoutesRecordHydrated<T>
575
- readonly pathsOrdering: string[]
576
- readonly keysOrdering: string[]
577
- readonly ordered: CallabelRoute[]
602
+ private readonly routes: RoutesRecordHydrated<T>
603
+ private readonly pathsOrdering: string[]
604
+ private readonly keysOrdering: string[]
605
+ private readonly ordered: CallabelRoute[]
606
+
607
+ _: {
608
+ getLocation: Routes<T>['getLocation']
609
+ override: Routes<T>['override']
610
+ pathsOrdering: Routes<T>['pathsOrdering']
611
+ keysOrdering: Routes<T>['keysOrdering']
612
+ ordered: Routes<T>['ordered']
613
+ }
578
614
 
579
615
  private constructor({
580
616
  routes,
@@ -589,11 +625,9 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
589
625
  keysOrdering?: string[]
590
626
  ordered?: CallabelRoute[]
591
627
  }) {
592
- this.routes = (
593
- isHydrated ? (routes as RoutesRecordHydrated<T>) : Routes._hydrate(routes)
594
- ) as RoutesRecordHydrated<T>
628
+ this.routes = (isHydrated ? (routes as RoutesRecordHydrated<T>) : Routes.hydrate(routes)) as RoutesRecordHydrated<T>
595
629
  if (!pathsOrdering || !keysOrdering || !ordered) {
596
- const ordering = Routes._makeOrdering(this.routes)
630
+ const ordering = Routes.makeOrdering(this.routes)
597
631
  this.pathsOrdering = ordering.pathsOrdering
598
632
  this.keysOrdering = ordering.keysOrdering
599
633
  this.ordered = this.keysOrdering.map((key) => this.routes[key])
@@ -602,14 +636,21 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
602
636
  this.keysOrdering = keysOrdering
603
637
  this.ordered = ordered
604
638
  }
639
+ this._ = {
640
+ getLocation: this.getLocation.bind(this),
641
+ override: this.override.bind(this),
642
+ pathsOrdering: this.pathsOrdering,
643
+ keysOrdering: this.keysOrdering,
644
+ ordered: this.ordered,
645
+ }
605
646
  }
606
647
 
607
648
  static create<const T extends RoutesRecord>(routes: T): RoutesPretty<T> {
608
649
  const instance = new Routes({ routes })
609
- return Routes._prettify(instance)
650
+ return Routes.prettify(instance)
610
651
  }
611
652
 
612
- static _prettify<const T extends RoutesRecord>(instance: Routes<T>): RoutesPretty<T> {
653
+ private static prettify<const T extends RoutesRecord>(instance: Routes<T>): RoutesPretty<T> {
613
654
  Object.setPrototypeOf(instance, Routes.prototype)
614
655
  Object.defineProperty(instance, Symbol.toStringTag, {
615
656
  value: 'Routes',
@@ -621,7 +662,7 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
621
662
  return instance as unknown as RoutesPretty<T>
622
663
  }
623
664
 
624
- static _hydrate<const T extends RoutesRecord>(routes: T): RoutesRecordHydrated<T> {
665
+ private static hydrate<const T extends RoutesRecord>(routes: T): RoutesRecordHydrated<T> {
625
666
  const result = {} as RoutesRecordHydrated<T>
626
667
  for (const key in routes) {
627
668
  if (Object.prototype.hasOwnProperty.call(routes, key)) {
@@ -632,13 +673,13 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
632
673
  return result
633
674
  }
634
675
 
635
- getLocation(href: `${string}://${string}`): UnknownLocation | ExactLocation
636
- getLocation(hrefRel: `/${string}`): UnknownLocation | ExactLocation
637
- getLocation(hrefOrHrefRel: string): UnknownLocation | ExactLocation
638
- getLocation(location: AnyLocation): UnknownLocation | ExactLocation
639
- getLocation(url: URL): UnknownLocation | ExactLocation
640
- getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation
641
- getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation {
676
+ private getLocation(href: `${string}://${string}`): UnknownLocation | ExactLocation
677
+ private getLocation(hrefRel: `/${string}`): UnknownLocation | ExactLocation
678
+ private getLocation(hrefOrHrefRel: string): UnknownLocation | ExactLocation
679
+ private getLocation(location: AnyLocation): UnknownLocation | ExactLocation
680
+ private getLocation(url: URL): UnknownLocation | ExactLocation
681
+ private getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation
682
+ private getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation {
642
683
  // Find the route that exactly matches the given location
643
684
  const input = hrefOrHrefRelOrLocation
644
685
  for (const route of this.ordered) {
@@ -651,8 +692,8 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
651
692
  return typeof input === 'string' ? Route0.getLocation(input) : Route0.getLocation(input)
652
693
  }
653
694
 
654
- static _makeOrdering(routes: RoutesRecord): { pathsOrdering: string[]; keysOrdering: string[] } {
655
- const hydrated = Routes._hydrate(routes)
695
+ private static makeOrdering(routes: RoutesRecord): { pathsOrdering: string[]; keysOrdering: string[] } {
696
+ const hydrated = Routes.hydrate(routes)
656
697
  const entries = Object.entries(hydrated)
657
698
 
658
699
  const getParts = (path: string) => {
@@ -686,7 +727,7 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
686
727
  return { pathsOrdering, keysOrdering }
687
728
  }
688
729
 
689
- override(config: RouteConfigInput): RoutesPretty<T> {
730
+ private override(config: RouteConfigInput): RoutesPretty<T> {
690
731
  const newRoutes = {} as RoutesRecordHydrated<T>
691
732
  for (const key in this.routes) {
692
733
  if (Object.prototype.hasOwnProperty.call(this.routes, key)) {
@@ -700,7 +741,13 @@ export class Routes<const T extends RoutesRecord = RoutesRecord> {
700
741
  keysOrdering: this.keysOrdering,
701
742
  ordered: this.keysOrdering.map((key) => newRoutes[key]),
702
743
  })
703
- return Routes._prettify(instance)
744
+ return Routes.prettify(instance)
745
+ }
746
+
747
+ static _ = {
748
+ prettify: Routes.prettify.bind(Routes),
749
+ hydrate: Routes.hydrate.bind(Routes),
750
+ makeOrdering: Routes.makeOrdering.bind(Routes),
704
751
  }
705
752
  }
706
753