Skip to content

Commit 7a250b3

Browse files
committed
feat: add from argument to redirect
1 parent cd91848 commit 7a250b3

File tree

3 files changed

+33
-67
lines changed

3 files changed

+33
-67
lines changed

packages/router/src/experimental/router.ts

Lines changed: 18 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
warn,
1616
type App,
1717
} from 'vue'
18-
import { RouterLink } from '../RouterLink'
18+
import { type RouterLink } from '../RouterLink'
1919
import {
2020
NavigationType,
2121
type HistoryState,
@@ -60,11 +60,7 @@ import {
6060
RouteMeta,
6161
} from '../types'
6262
import { useCallbacks } from '../utils/callbacks'
63-
import {
64-
isSameRouteLocation,
65-
parseURL,
66-
START_LOCATION_NORMALIZED,
67-
} from '../location'
63+
import { isSameRouteLocation, START_LOCATION_NORMALIZED } from '../location'
6864
import { assign, isArray, isBrowser, noop } from '../utils'
6965
import {
7066
extractChangingRecords,
@@ -600,7 +596,9 @@ export function experimental_createRouter(
600596
): EXPERIMENTAL_Router {
601597
const {
602598
resolver,
603-
parseQuery = originalParseQuery,
599+
// TODO: document that a custom parsing can be handled with a custom param that parses the whole query
600+
// and adds a $query property to the params added at the root record, parent of all records
601+
// parseQuery = originalParseQuery,
604602
stringifyQuery = originalStringifyQuery,
605603
history: routerHistory,
606604
} = options
@@ -627,14 +625,6 @@ export function experimental_createRouter(
627625
}
628626

629627
// TODO: replace usage with resolver.resolve()
630-
function locationAsObject(
631-
to: RouteLocationRaw | RouteLocationNormalized,
632-
currentLocation: string = currentRoute.value.path
633-
): Exclude<RouteLocationRaw, string> | RouteLocationNormalized {
634-
return typeof to === 'string'
635-
? parseURL(parseQuery, to, currentLocation)
636-
: to
637-
}
638628

639629
// NOTE: to support multiple overloads
640630
type TRecord = EXPERIMENTAL_RouteRecordNormalized
@@ -743,53 +733,16 @@ export function experimental_createRouter(
743733
const replace = (...args: _resolveArgs) =>
744734
pushWithRedirect(resolve(...args), true)
745735

746-
function handleRedirectRecord(to: RouteLocation): RouteLocationRaw | void {
736+
function handleRedirectRecord(
737+
to: RouteLocation,
738+
from: RouteLocationNormalizedLoaded
739+
): RouteLocationRaw | void {
747740
const redirect = to.matched.at(-1)?.redirect
748741
if (redirect) {
749-
let newTargetLocation =
750-
typeof redirect === 'function' ? redirect(to) : redirect
751-
752-
// TODO: we should be able to just resolve(newTargetLocation)
753-
// maybe we need a way to return the current location: return [redirect, current]
754-
// (to, from) => [redirect, from] // relative to current location
755-
// (to, from) => [redirect, to] // relative to target location
756-
if (typeof newTargetLocation === 'string') {
757-
newTargetLocation =
758-
newTargetLocation.includes('?') || newTargetLocation.includes('#')
759-
? (newTargetLocation = locationAsObject(newTargetLocation))
760-
: // force empty params
761-
{ path: newTargetLocation }
762-
// @ts-expect-error: force empty params when a string is passed to let
763-
// the router parse them again
764-
newTargetLocation.params = {}
765-
}
766-
767-
// TODO: should be removed if we use the resolve method
768-
if (
769-
__DEV__ &&
770-
newTargetLocation.path == null &&
771-
!('name' in newTargetLocation)
772-
) {
773-
warn(
774-
`Invalid redirect found:\n${JSON.stringify(
775-
newTargetLocation,
776-
null,
777-
2
778-
)}\n when navigating to "${
779-
to.fullPath
780-
}". A redirect must contain a name or path. This will break in production.`
781-
)
782-
throw new Error('Invalid redirect')
783-
}
784-
785-
return assign(
786-
{
787-
query: to.query,
788-
hash: to.hash,
789-
// avoid transferring params if the redirect has a path
790-
params: newTargetLocation.path != null ? {} : to.params,
791-
},
792-
newTargetLocation
742+
return resolve(
743+
// @ts-expect-error: TODO: allow redirect to return the first argument of resolve or a tuple consisting of the arguments?
744+
typeof redirect === 'function' ? redirect(to, from) : redirect,
745+
from
793746
)
794747
}
795748
}
@@ -805,7 +758,7 @@ export function experimental_createRouter(
805758
const data: HistoryState | undefined = (to as RouteLocationOptions).state
806759
const force: boolean | undefined = (to as RouteLocationOptions).force
807760

808-
const shouldRedirect = handleRedirectRecord(to)
761+
const shouldRedirect = handleRedirectRecord(to, from)
809762

810763
if (shouldRedirect) {
811764
return pushWithRedirect(
@@ -1134,7 +1087,10 @@ export function experimental_createRouter(
11341087
// due to dynamic routing, and to hash history with manual navigation
11351088
// (manually changing the url or calling history.hash = '#/somewhere'),
11361089
// there could be a redirect record in history
1137-
const shouldRedirect = handleRedirectRecord(toLocation)
1090+
const shouldRedirect = handleRedirectRecord(
1091+
toLocation,
1092+
router.currentRoute.value
1093+
)
11381094
if (shouldRedirect) {
11391095
pushWithRedirect(
11401096
assign(

packages/router/src/router.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,15 @@ export function createRouter(options: RouterOptions): Router {
376376
return push(assign(locationAsObject(to), { replace: true }))
377377
}
378378

379-
function handleRedirectRecord(to: RouteLocation): RouteLocationRaw | void {
379+
function handleRedirectRecord(
380+
to: RouteLocation,
381+
from: RouteLocationNormalizedLoaded
382+
): RouteLocationRaw | void {
380383
const lastMatched = to.matched[to.matched.length - 1]
381384
if (lastMatched && lastMatched.redirect) {
382385
const { redirect } = lastMatched
383386
let newTargetLocation =
384-
typeof redirect === 'function' ? redirect(to) : redirect
387+
typeof redirect === 'function' ? redirect(to, from) : redirect
385388

386389
if (typeof newTargetLocation === 'string') {
387390
newTargetLocation =
@@ -434,7 +437,7 @@ export function createRouter(options: RouterOptions): Router {
434437
// to could be a string where `replace` is a function
435438
const replace = (to as RouteLocationOptions).replace === true
436439

437-
const shouldRedirect = handleRedirectRecord(targetLocation)
440+
const shouldRedirect = handleRedirectRecord(targetLocation, from)
438441

439442
if (shouldRedirect)
440443
return pushWithRedirect(
@@ -766,7 +769,10 @@ export function createRouter(options: RouterOptions): Router {
766769
// due to dynamic routing, and to hash history with manual navigation
767770
// (manually changing the url or calling history.hash = '#/somewhere'),
768771
// there could be a redirect record in history
769-
const shouldRedirect = handleRedirectRecord(toLocation)
772+
const shouldRedirect = handleRedirectRecord(
773+
toLocation,
774+
router.currentRoute.value
775+
)
770776
if (shouldRedirect) {
771777
pushWithRedirect(
772778
assign(shouldRedirect, { replace: true, force: true }),

packages/router/src/typed-routes/route-records.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
RouteLocation,
33
RouteLocationNormalized,
4+
RouteLocationNormalizedLoaded,
45
RouteLocationRaw,
56
} from './route-location'
67
import type { RouteMap, RouteMapGeneric } from './route-map'
@@ -10,7 +11,10 @@ import type { RouteMap, RouteMapGeneric } from './route-map'
1011
*/
1112
export type RouteRecordRedirectOption =
1213
| RouteLocationRaw
13-
| ((to: RouteLocation) => RouteLocationRaw)
14+
| ((
15+
to: RouteLocation,
16+
from: RouteLocationNormalizedLoaded
17+
) => RouteLocationRaw)
1418

1519
/**
1620
* Generic version of {@link RouteRecordName}.

0 commit comments

Comments
 (0)