)
})
+ it('works with a named location', () => {
+ const records = [
+ { path: '/home', component },
+ { path: '/redirect', name: 'redirect', redirect: { path: 'home' } },
+ ]
+ assertRedirect(
+ records,
+ {
+ name: 'redirect',
+ },
+ {
+ redirect: { path: 'home' },
+ normalizedLocation: {
+ path: '/redirect',
+ params: {},
+ name: 'redirect',
+ matched: [],
+ },
+ }
+ )
+ })
+
+ it('throws if relative location when redirecting', () => {
+ const records = [
+ { path: '/home', component },
+ { path: '/redirect', redirect: '/home' },
+ ]
+ expect(
+ assertErrorMatch(
+ { path: '/redirect', redirect: '/home' },
+ { params: {} },
+ { path: '/redirect', params: {}, matched: [], name: undefined }
+ )
+ ).toMatchInlineSnapshot(`
+ [Error: Cannot redirect using a relative location:
+ {
+ "params": {}
+ }
+ Use the function redirect and explicitely provide a name]
+ `)
+ })
+
it('normalize a location when redirecting', () => {
const redirect = to => ({ name: 'b', params: to.params })
const records = [
}
}
+/**
+ * Error used when the matcher fails to resolve a location
+ */
+export class InvalidRouteMatch extends Error {
+ constructor(location: any) {
+ // TODO: improve the error to include currentLocation and use it for more cases
+ super(
+ `Cannot redirect using a relative location:\n${stringifyRoute(
+ location
+ )}\nUse the function redirect and explicitely provide a name`
+ )
+ Object.setPrototypeOf(this, new.target.prototype)
+ }
+}
+
/**
* Error used when rejecting a navigation because of a redirection. Contains
* information about where we where trying to go and where we are going instead
function stringifyRoute(to: RouteLocation): string {
if (typeof to === 'string') return to
if ('path' in to) return to.path
- return 'TODO'
+ return JSON.stringify(to, null, 2)
}
MatcherLocationNormalized,
MatcherLocationRedirect,
} from './types/index'
-import { NoRouteMatchError } from './errors'
+import { NoRouteMatchError, InvalidRouteMatch } from './errors'
interface RouteMatcher {
re: RegExp
params,
},
}
- // if redirect is a function we do not have enough information, so we throw
- // TODO: not use a throw
- // throw new RedirectInRecord(typeof redirect === 'function' ? {
- // redirect,
- // route: { name: matcher.record.name, path: location.path, params, matched: [] }
- // } : redirect)
}
// TODO: build up the array with children based on current location
matcher = this.matchers.find(m => m.record.name === location.name)
if (!matcher) throw new NoRouteMatchError(currentLocation, location)
- if ('redirect' in matcher.record) throw new Error('TODO')
+
+ if ('redirect' in matcher.record) {
+ const { redirect } = matcher.record
+ return {
+ redirect,
+ normalizedLocation: {
+ name: matcher.record.name,
+ path: matcher.resolve(location.params),
+ matched: [],
+ params: location.params || {}, // TODO: normalize params
+ },
+ }
+ }
// TODO: build up the array with children based on current location
const matched = [matcher.record]
}
if (!matcher) throw new NoRouteMatchError(currentLocation, location)
- if ('redirect' in matcher.record) throw new Error('TODO')
+
+ // this should never happen because it will mean that the user ended up in a route
+ // that redirects but ended up not redirecting
+ if ('redirect' in matcher.record) throw new InvalidRouteMatch(location)
// TODO: build up the array with children based on current location
const matched = [matcher.record]