From: Eduardo San Martin Morote Date: Mon, 6 May 2019 10:09:42 +0000 (+0200) Subject: feat: throw with invalid redirect X-Git-Tag: v4.0.0-alpha.0~394 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0c6902d671460a0f64d5f7c4e97b026d842b16f;p=thirdparty%2Fvuejs%2Frouter.git feat: throw with invalid redirect --- diff --git a/__tests__/matcher.spec.js b/__tests__/matcher.spec.js index f9209839..42a0b9a4 100644 --- a/__tests__/matcher.spec.js +++ b/__tests__/matcher.spec.js @@ -358,6 +358,48 @@ describe('Router Matcher', () => { ) }) + 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 = [ diff --git a/src/errors.ts b/src/errors.ts index 923794b7..f7038b49 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -7,6 +7,21 @@ export class NoRouteMatchError extends Error { } } +/** + * 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 @@ -30,5 +45,5 @@ export class RedirectError extends Error { 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) } diff --git a/src/matcher.ts b/src/matcher.ts index 3385f53a..46baa6a3 100644 --- a/src/matcher.ts +++ b/src/matcher.ts @@ -6,7 +6,7 @@ import { MatcherLocationNormalized, MatcherLocationRedirect, } from './types/index' -import { NoRouteMatchError } from './errors' +import { NoRouteMatchError, InvalidRouteMatch } from './errors' interface RouteMatcher { re: RegExp @@ -86,12 +86,6 @@ export class RouterMatcher { 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 @@ -111,7 +105,19 @@ export class RouterMatcher { 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] @@ -136,7 +142,10 @@ export class RouterMatcher { } 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]