name: 'name',
})
- expect(record).toEqual({
+ expect(record).toMatchObject({
aliasOf: undefined,
components: {},
meta: { foo: true },
path: '/inc-query-hash',
})
})
+
+ it('allows a redirect with children', async () => {
+ const history = createMemoryHistory()
+ const router = createRouter({
+ history,
+ routes: [
+ {
+ path: '/parent',
+ redirect: { name: 'child' },
+ component: components.Home,
+ name: 'parent',
+ children: [{ name: 'child', path: '', component: components.Home }],
+ },
+ ],
+ })
+ await expect(router.push({ name: 'parent' })).resolves.toEqual(undefined)
+ const loc = router.currentRoute.value
+ expect(loc.name).toBe('child')
+ expect(loc.path).toBe('/parent')
+ expect(loc.redirectedFrom).toMatchObject({
+ name: 'parent',
+ path: '/parent',
+ })
+ })
})
describe('base', () => {
isRouteName,
RouteRecordName,
_RouteRecordProps,
- RouteRecordSingleView,
- RouteRecordMultipleViews,
} from '../types'
import { createRouterError, ErrorTypes, MatcherError } from '../errors'
import { createRouteRecordMatcher, RouteRecordMatcher } from './pathMatcher'
-import { RouteRecordRedirect, RouteRecordNormalized } from './types'
+import { RouteRecordNormalized } from './types'
import {
PathParams,
comparePathParserScore,
removeRoute(record.name)
}
- // only non redirect records have children
if ('children' in mainNormalizedRecord) {
let children = mainNormalizedRecord.children
for (let i = 0; i < children.length; i++) {
}
/**
- * Normalizes a RouteRecordRaw. Transforms the `redirect` option into a
- * `beforeEnter`. This function creates a copy
+ * Normalizes a RouteRecordRaw. Creates a copy
+ *
* @param record
* @returns the normalized version
*/
export function normalizeRouteRecord(
record: RouteRecordRaw
-): RouteRecordNormalized | RouteRecordRedirect {
- const commonInitialValues = {
+): RouteRecordNormalized {
+ return {
path: record.path,
+ redirect: record.redirect,
name: record.name,
meta: record.meta || {},
aliasOf: undefined,
- components: {},
- }
-
- if ('redirect' in record) {
- return assign(commonInitialValues, { redirect: record.redirect })
- } else {
- const components =
- 'components' in record ? record.components : { default: record.component }
- return assign(commonInitialValues, {
- beforeEnter: record.beforeEnter,
- props: normalizeRecordProps(record),
- children: record.children || [],
- instances: {},
- leaveGuards: [],
- updateGuards: [],
- components,
- })
+ beforeEnter: record.beforeEnter,
+ props: normalizeRecordProps(record),
+ children: record.children || [],
+ instances: {},
+ leaveGuards: [],
+ updateGuards: [],
+ components:
+ 'components' in record
+ ? record.components || {}
+ : { default: record.component! },
}
}
* @param record
*/
function normalizeRecordProps(
- record: RouteRecordSingleView | RouteRecordMultipleViews
+ record: RouteRecordRaw
): Record<string, _RouteRecordProps> {
const propsObject = {} as Record<string, _RouteRecordProps>
- const props = record.props || false
+ // props does not exist on redirect records but we can set false directly
+ const props = (record as any).props || false
if ('component' in record) {
propsObject.default = props
} else {
RouteRecordMultipleViews,
NavigationGuard,
_RouteRecordBase,
- RouteRecordRedirectRaw,
_RouteRecordProps,
} from '../types'
import { ComponentPublicInstance } from 'vue'
// normalize component/components into components and make every property always present
export interface RouteRecordNormalized {
path: RouteRecordMultipleViews['path']
+ redirect: _RouteRecordBase['redirect'] | undefined
name: RouteRecordMultipleViews['name']
components: RouteRecordMultipleViews['components']
children: Exclude<RouteRecordMultipleViews['children'], void>
aliasOf: RouteRecordNormalized | undefined
}
-export interface RouteRecordRedirect {
- path: RouteRecordMultipleViews['path']
- name: RouteRecordMultipleViews['name']
- redirect: RouteRecordRedirectRaw['redirect']
- // can only be of of the same type as this record
- aliasOf: RouteRecordRedirect | undefined
- meta: Exclude<RouteRecordMultipleViews['meta'], void>
- // this object will always be empty but it simplifies things
- components: RouteRecordMultipleViews['components']
-}
-
-export type RouteRecord = RouteRecordNormalized | RouteRecordRedirect
+export type RouteRecord = RouteRecordNormalized
const lastMatched =
targetLocation.matched[targetLocation.matched.length - 1]
- if (lastMatched && 'redirect' in lastMatched) {
+ if (lastMatched && lastMatched.redirect) {
const { redirect } = lastMatched
// transform it into an object to pass the original RouteLocaleOptions
let newTargetLocation = locationAsObject(
* another record.
*/
path: string
+ /**
+ * Where to redirect if the route is directly matched. The redirection happens
+ * before any navigation guard and triggers a new navigation with the new
+ * target location.
+ */
+ redirect?: RouteRecordRedirectOption
+ /**
+ * Array of nested routes.
+ */
+ children?: RouteRecordRaw[]
/**
* Aliases for the record. Allows defining extra paths that will behave like a
* copy of the record. Allows having paths shorthands like `/users/:id` and
export type RouteRecordRedirectOption =
| RouteLocationRaw
| ((to: RouteLocation) => RouteLocationRaw)
-export interface RouteRecordRedirectRaw extends _RouteRecordBase {
- redirect: RouteRecordRedirectOption
- beforeEnter?: never
- component?: never
- components?: never
-}
export interface RouteRecordSingleView extends _RouteRecordBase {
+ /**
+ * Component to display when the URL matches this route.
+ */
component: RawRouteComponent
- children?: RouteRecordRaw[]
/**
* Allow passing down params as props to the component rendered by `router-view`.
*/
}
export interface RouteRecordMultipleViews extends _RouteRecordBase {
+ /**
+ * Components to display when the URL matches this route. Allow using named views.
+ */
components: Record<string, RawRouteComponent>
- children?: RouteRecordRaw[]
/**
* Allow passing down params as props to the component rendered by
* `router-view`. Should be an object with the same keys as `components` or a
props?: Record<string, _RouteRecordProps> | boolean
}
+export interface RouteRecordRedirect extends _RouteRecordBase {
+ /**
+ * @inheritdoc
+ */
+ redirect: RouteRecordRedirectOption
+ component?: never
+ components?: never
+ children?: never
+}
+
+export interface RouteRecordRedirectWithChildren extends _RouteRecordBase {
+ component?: never
+ children: Exclude<_RouteRecordBase['children'], undefined>
+}
+
export type RouteRecordRaw =
| RouteRecordSingleView
| RouteRecordMultipleViews
- | RouteRecordRedirectRaw
+ | RouteRecordRedirect
export const START_LOCATION_NORMALIZED: RouteLocationNormalizedLoaded = {
path: '/',