@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/dist/cjs/index.cjs +43 -10
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +20 -16
- package/dist/esm/index.d.ts +20 -16
- package/dist/esm/index.js +43 -10
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.test.ts +80 -31
- package/src/index.ts +77 -30
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
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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.
|
|
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.
|
|
650
|
+
return Routes.prettify(instance)
|
|
610
651
|
}
|
|
611
652
|
|
|
612
|
-
static
|
|
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
|
|
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
|
|
655
|
-
const hydrated = 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.
|
|
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
|
|