Skip to content

Commit 6fec4ac

Browse files
committed
refactor: types
1 parent 3be0abd commit 6fec4ac

File tree

4 files changed

+98
-73
lines changed

4 files changed

+98
-73
lines changed

packages/router/src/experimental/route-resolver/resolver-abstract.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import {
55
encodeParam,
66
} from '../../encoding'
77
import type { MatcherParamsFormatted } from './matchers/matcher-pattern'
8-
import { _RouteRecordProps } from '../../typed-routes'
9-
import { NEW_MatcherDynamicRecord } from './resolver-dynamic'
8+
import type { _RouteRecordProps } from '../../typed-routes'
9+
import type { NEW_MatcherDynamicRecord } from './resolver-dynamic'
10+
import type { LocationNormalized } from '../../location'
1011

1112
/**
1213
* Allowed types for a matcher name.
@@ -20,7 +21,7 @@ export type RecordName = string | symbol
2021
* - `TMatcherRecordRaw` represents the raw record type passed to {@link addMatcher}.
2122
* - `TMatcherRecord` represents the normalized record type returned by {@link getRecords}.
2223
*/
23-
export interface NEW_RouterResolver_Base<TRecord> {
24+
export interface EXPERIMENTAL_Resolver_Base<TRecord> {
2425
/**
2526
* Resolves an absolute location (like `/path/to/somewhere`).
2627
*
@@ -92,7 +93,7 @@ export interface NEW_RouterResolver_Base<TRecord> {
9293
}
9394

9495
/**
95-
* Allowed location objects to be passed to {@link NEW_RouterResolver['resolve']}
96+
* Allowed location objects to be passed to {@link EXPERIMENTAL_Resolver_Base['resolve']}
9697
*/
9798
export type MatcherLocationRaw =
9899
// | `/${string}`
@@ -103,18 +104,13 @@ export type MatcherLocationRaw =
103104
| ResolverLocationAsRelative
104105

105106
/**
106-
* Returned location object by {@link NEW_RouterResolver['resolve']}.
107+
* Returned location object by {@link EXPERIMENTAL_Resolver_Base['resolve']}.
107108
* It contains the resolved name, params, query, hash, and matched records.
108109
*/
109-
export interface ResolverLocationResolved<TMatched> {
110+
export interface ResolverLocationResolved<TMatched> extends LocationNormalized {
110111
name: RecordName
111112
params: MatcherParamsFormatted
112113

113-
fullPath: string
114-
path: string
115-
query: LocationQuery
116-
hash: string
117-
118114
matched: TMatched[]
119115
}
120116

@@ -209,10 +205,7 @@ export const NO_MATCH_LOCATION = {
209205
name: __DEV__ ? Symbol('no-match') : Symbol(),
210206
params: {},
211207
matched: [],
212-
} satisfies Omit<
213-
ResolverLocationResolved<unknown>,
214-
'path' | 'hash' | 'query' | 'fullPath'
215-
>
208+
} satisfies Omit<ResolverLocationResolved<never>, keyof LocationNormalized>
216209

217210
/**
218211
* Normalized version of a {@link NEW_MatcherRecordRaw} record.

packages/router/src/experimental/route-resolver/resolver-dynamic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { ResolverLocationAsPathRelative } from './resolver-abstract'
1212
import type { ResolverLocationAsNamed } from './resolver-abstract'
1313
import {
1414
MatcherQueryParams,
15-
NEW_RouterResolver_Base,
15+
EXPERIMENTAL_Resolver_Base,
1616
NO_MATCH_LOCATION,
1717
RecordName,
1818
ResolverLocationResolved,
@@ -34,7 +34,7 @@ import type {
3434
*/
3535

3636
export interface NEW_RouterResolver<TMatcherRecordRaw, TMatcherRecord>
37-
extends NEW_RouterResolver_Base<TMatcherRecord> {
37+
extends EXPERIMENTAL_Resolver_Base<TMatcherRecord> {
3838
/**
3939
* Add a matcher record. Previously named `addRoute()`.
4040
* @param matcher - The matcher record to add.

packages/router/src/experimental/route-resolver/resolver-static.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
RecordName,
1515
MatcherQueryParams,
1616
ResolverLocationResolved,
17-
NEW_RouterResolver_Base,
17+
EXPERIMENTAL_Resolver_Base,
1818
NO_MATCH_LOCATION,
1919
} from './resolver-abstract'
2020
import type {
@@ -84,7 +84,7 @@ export type EXPERIMENTAL_ResolverStaticRecord<T = {}> =
8484
EXPERIMENTAL_ResolverRecord<T>
8585

8686
export interface EXPERIMENTAL_ResolverStatic<TRecord>
87-
extends NEW_RouterResolver_Base<TRecord> {}
87+
extends EXPERIMENTAL_Resolver_Base<TRecord> {}
8888

8989
/**
9090
* Build the `matched` array of a record that includes all parent records from the root to the current one.

packages/router/src/experimental/router.ts

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ import type {
5454
RouteRecordNameGeneric,
5555
} from '../typed-routes'
5656
import {
57-
isRouteLocation,
5857
Lazy,
5958
RawRouteComponent,
6059
RouteLocationOptions,
@@ -84,6 +83,12 @@ import {
8483
EXPERIMENTAL_ResolverRecord_Matchable,
8584
EXPERIMENTAL_ResolverStatic,
8685
} from './route-resolver/resolver-static'
86+
import {
87+
ResolverLocationAsNamed,
88+
ResolverLocationAsPathRelative,
89+
ResolverLocationAsRelative,
90+
ResolverLocationResolved,
91+
} from './route-resolver/resolver-abstract'
8792

8893
/**
8994
* resolve, reject arguments of Promise constructor
@@ -636,38 +641,51 @@ export function experimental_createRouter(
636641
: to
637642
}
638643

644+
// NOTE: to support multiple overloads
645+
type TRecord = EXPERIMENTAL_RouteRecordNormalized
646+
type _resolveArgs =
647+
// TODO: is it worth suppoting the absolute location variants?
648+
// | [absoluteLocation: `/${string}`, currentLocation?: undefined]
649+
| [
650+
relativeLocation: string,
651+
// FIXME: use router locations
652+
currentLocation?: ResolverLocationResolved<TRecord>,
653+
]
654+
// | [
655+
// absoluteLocation: ResolverLocationAsPathAbsolute,
656+
// // Same as above
657+
// // currentLocation?: NEW_LocationResolved<TRecord> | undefined
658+
// currentLocation?: undefined,
659+
// ]
660+
| [
661+
relativeLocation: ResolverLocationAsPathRelative,
662+
currentLocation: ResolverLocationResolved<TRecord>,
663+
]
664+
| [
665+
location: ResolverLocationAsNamed,
666+
// Same as above
667+
// currentLocation?: NEW_LocationResolved<TRecord> | undefined
668+
currentLocation?: undefined,
669+
]
670+
| [
671+
relativeLocation: ResolverLocationAsRelative,
672+
currentLocation: ResolverLocationResolved<TRecord>,
673+
]
674+
| [resolvedLocation: RouteLocationResolved, currentLocation?: undefined]
675+
639676
function resolve(
640-
rawLocation: RouteLocationRaw,
641-
currentLocation?: RouteLocationNormalizedLoaded
677+
...[to, currentLocation]: _resolveArgs
642678
): RouteLocationResolved {
643679
// const resolve: Router['resolve'] = (rawLocation: RouteLocationRaw, currentLocation) => {
644680
// const objectLocation = routerLocationAsObject(rawLocation)
645681
// we create a copy to modify it later
646682
// TODO: in the experimental version, allow configuring this
647683
currentLocation =
684+
// TODO: || currentRoute.value never evaluated
648685
currentLocation && assign({}, currentLocation || currentRoute.value)
649686
// currentLocation = assign({}, currentLocation || currentRoute.value)
650687

651-
if (__DEV__) {
652-
if (!isRouteLocation(rawLocation)) {
653-
warn(
654-
`router.resolve() was passed an invalid location. This will fail in production.\n- Location:`,
655-
rawLocation
656-
)
657-
return resolve({})
658-
}
659-
660-
if (
661-
typeof rawLocation === 'object' &&
662-
rawLocation.hash?.startsWith('#')
663-
) {
664-
warn(
665-
`A \`hash\` should always start with the character "#". Replace "${rawLocation.hash}" with "#${rawLocation.hash}".`
666-
)
667-
}
668-
}
669-
670-
// FIXME: is this achieved by matchers?
688+
// FIXME: should this be achieved by matchers?
671689
// remove any nullish param
672690
// if ('params' in rawLocation) {
673691
// const targetParams = assign({}, rawLocation.params)
@@ -680,28 +698,28 @@ export function experimental_createRouter(
680698
// }
681699

682700
const matchedRoute = resolver.resolve(
683-
// FIXME: incompatible types
684-
rawLocation as any,
701+
// @ts-expect-error FIXME: incompatible types
702+
to,
685703
// FIXME: incompatible `matched` requires casting
686-
currentLocation as any
704+
currentLocation
687705
)
688706
const href = routerHistory.createHref(matchedRoute.fullPath)
689707

690708
if (__DEV__) {
691709
if (href.startsWith('//')) {
692710
warn(
693711
`Location ${JSON.stringify(
694-
rawLocation
712+
to
695713
)} resolved to "${href}". A resolved location cannot start with multiple slashes.`
696714
)
697715
}
698716
if (!matchedRoute.matched.length) {
699-
warn(`No match found for location with path "${rawLocation}"`)
717+
warn(`No match found for location with path "${to}"`)
700718
}
701719
}
702720

703721
// matchedRoute is always a new object
704-
// @ts-expect-error: the `matched` property is different
722+
// @ts-expect-error: FIXME: the `matched` property is different
705723
return assign(matchedRoute, {
706724
redirectedFrom: undefined,
707725
href,
@@ -724,13 +742,10 @@ export function experimental_createRouter(
724742
}
725743
}
726744

727-
function push(to: RouteLocationRaw) {
728-
return pushWithRedirect(to)
729-
}
745+
const push = (...args: _resolveArgs) => pushWithRedirect(resolve(...args))
730746

731-
function replace(to: RouteLocationRaw) {
732-
return pushWithRedirect(to, true)
733-
}
747+
const replace = (...args: _resolveArgs) =>
748+
pushWithRedirect(resolve(...args), true)
734749

735750
function handleRedirectRecord(to: RouteLocation): RouteLocationRaw | void {
736751
const lastMatched = to.matched[to.matched.length - 1]
@@ -780,40 +795,42 @@ export function experimental_createRouter(
780795
}
781796

782797
function pushWithRedirect(
783-
to: RouteLocationRaw | RouteLocation,
784-
_replace?: boolean,
798+
to: RouteLocationResolved,
799+
replace?: boolean,
785800
redirectedFrom?: RouteLocation
786801
): Promise<NavigationFailure | void | undefined> {
787-
const targetLocation: RouteLocation = (pendingLocation = resolve(to))
802+
replace = to.replace ?? replace
803+
pendingLocation = to
788804
const from = currentRoute.value
789805
const data: HistoryState | undefined = (to as RouteLocationOptions).state
790806
const force: boolean | undefined = (to as RouteLocationOptions).force
791-
const replace = targetLocation.replace ?? _replace
792-
console.log({ replace })
793807

794-
const shouldRedirect = handleRedirectRecord(targetLocation)
808+
const shouldRedirect = handleRedirectRecord(to)
795809

796-
if (shouldRedirect)
810+
if (shouldRedirect) {
797811
return pushWithRedirect(
798-
assign(locationAsObject(shouldRedirect), {
812+
{
813+
// @ts-expect-error: FIXME: refactor location types
814+
...resolve(shouldRedirect, currentRoute.value),
799815
state:
800816
typeof shouldRedirect === 'object'
801817
? assign({}, data, shouldRedirect.state)
802818
: data,
803819
force,
804-
}),
820+
},
805821
replace,
806822
// keep original redirectedFrom if it exists
807-
redirectedFrom || targetLocation
823+
redirectedFrom || to
808824
)
825+
}
809826

810827
// if it was a redirect we already called `pushWithRedirect` above
811-
const toLocation = targetLocation as RouteLocationNormalized
828+
const toLocation = to as RouteLocationNormalized
812829

813830
toLocation.redirectedFrom = redirectedFrom
814831
let failure: NavigationFailure | void | undefined
815832

816-
if (!force && isSameRouteLocation(stringifyQuery, from, targetLocation)) {
833+
if (!force && isSameRouteLocation(stringifyQuery, from, to)) {
817834
failure = createRouterError<NavigationFailure>(
818835
ErrorTypes.NAVIGATION_DUPLICATED,
819836
{ to: toLocation, from }
@@ -851,6 +868,7 @@ export function experimental_createRouter(
851868
// we are redirecting to the same location we were already at
852869
isSameRouteLocation(
853870
stringifyQuery,
871+
// @ts-expect-error: FIXME: failure.to should not contain relative locations
854872
resolve(failure.to),
855873
toLocation
856874
) &&
@@ -871,14 +889,15 @@ export function experimental_createRouter(
871889
}
872890

873891
return pushWithRedirect(
874-
// keep options
875-
assign(locationAsObject(failure.to), {
892+
{
893+
// @ts-expect-error: FIXME: refactor location types
894+
...resolve(shouldRedirect, currentRoute.value),
876895
state:
877896
typeof failure.to === 'object'
878897
? assign({}, data, failure.to.state)
879898
: data,
880899
force,
881-
}),
900+
},
882901
// preserve an existing replacement but allow the redirect to override it
883902
replace,
884903
// preserve the original redirectedFrom if any
@@ -1123,7 +1142,11 @@ export function experimental_createRouter(
11231142
const shouldRedirect = handleRedirectRecord(toLocation)
11241143
if (shouldRedirect) {
11251144
pushWithRedirect(
1126-
assign(shouldRedirect, { force: true }),
1145+
assign(
1146+
// @ts-expect-error: FIXME: refactor location types
1147+
resolve(shouldRedirect),
1148+
{ force: true }
1149+
),
11271150
true,
11281151
toLocation
11291152
).catch(noop)
@@ -1165,9 +1188,15 @@ export function experimental_createRouter(
11651188
// the error is already handled by router.push we just want to avoid
11661189
// logging the error
11671190
pushWithRedirect(
1168-
assign(locationAsObject((error as NavigationRedirectError).to), {
1169-
force: true,
1170-
}),
1191+
assign(
1192+
resolve(
1193+
// @ts-expect-error: to should be an absolute location
1194+
(error as NavigationRedirectError).to
1195+
),
1196+
{
1197+
force: true,
1198+
}
1199+
),
11711200
undefined,
11721201
toLocation
11731202
// avoid an uncaught rejection, let push call triggerError
@@ -1337,10 +1366,13 @@ export function experimental_createRouter(
13371366

13381367
hasRoute,
13391368
getRoutes,
1369+
// @ts-expect-error FIXME: update EXPERIMENTAL_Router types
13401370
resolve,
13411371
options,
13421372

1373+
// @ts-expect-error FIXME: update EXPERIMENTAL_Router types
13431374
push,
1375+
// @ts-expect-error FIXME: update EXPERIMENTAL_Router types
13441376
replace,
13451377
go,
13461378
back: () => go(-1),

0 commit comments

Comments
 (0)