From: Eduardo San Martin Morote Date: Tue, 28 May 2019 18:47:03 +0000 (+0200) Subject: refactor: improve matchLocation X-Git-Tag: v4.0.0-alpha.0~362 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b393282b90a3939621b4fcd372791719b619026e;p=thirdparty%2Fvuejs%2Frouter.git refactor: improve matchLocation --- diff --git a/__tests__/router.spec.js b/__tests__/router.spec.js index 6fec494d..da7bb5ba 100644 --- a/__tests__/router.spec.js +++ b/__tests__/router.spec.js @@ -19,6 +19,14 @@ const routes = [ { path: '/to-foo2', redirect: '/to-foo' }, { path: '/p/:p', component: components.Bar }, { path: '/to-p/:p', redirect: to => `/p/${to.params.p}` }, + { + path: '/inc-query-hash', + redirect: to => ({ + name: 'Foo', + query: { n: to.query.n + '-2' }, + hash: to.hash + '-2', + }), + }, ] describe('Router', () => { @@ -77,6 +85,18 @@ describe('Router', () => { }) }) + it('drops query and params on redirect if not provided', async () => { + const history = mockHistory() + const router = new Router({ history, routes }) + const loc = await router.push('/to-foo?hey=foo#fa') + expect(loc.name).toBe('Foo') + expect(loc.query).toEqual({}) + expect(loc.hash).toBe('') + expect(loc.redirectedFrom).toMatchObject({ + path: '/to-foo', + }) + }) + it('allows object in redirect', async () => { const history = mockHistory() const router = new Router({ history, routes }) @@ -87,6 +107,23 @@ describe('Router', () => { }) }) + it('can pass on query and hash when redirecting', async () => { + const history = mockHistory() + const router = new Router({ history, routes }) + const loc = await router.push('/inc-query-hash?n=3#fa') + expect(loc).toMatchObject({ + name: 'Foo', + query: { + n: '3-2', + }, + hash: '#fa-2', + }) + expect(loc.redirectedFrom).toMatchObject({ + fullPath: '/inc-query-hash?n=2#fa', + path: '/inc-query-hash', + }) + }) + it('handles multiple redirect fields in route record', async () => { const history = mockHistory() const router = new Router({ history, routes }) diff --git a/src/history/base.ts b/src/history/base.ts index 1c0580ca..7bce5356 100644 --- a/src/history/base.ts +++ b/src/history/base.ts @@ -2,18 +2,20 @@ import * as utils from './utils' import { ListenerRemover } from '../types' export type HistoryQuery = Record +export type RawHistoryQuery = Record export interface HistoryLocation { // pathname section path: string // search string parsed - query?: HistoryQuery + query?: RawHistoryQuery // hash with the # hash?: string } export interface HistoryLocationNormalized extends Required { // full path (like href) fullPath: string + query: HistoryQuery } // pushState clones the state passed and do not accept everything diff --git a/src/history/utils.ts b/src/history/utils.ts index a0aa5892..bd31dafa 100644 --- a/src/history/utils.ts +++ b/src/history/utils.ts @@ -2,8 +2,8 @@ import { HistoryLocationNormalized, HistoryQuery, HistoryLocation, + RawHistoryQuery, } from './base' -import { RouteQuery } from '../types' const PERCENT_RE = /%/g @@ -86,7 +86,7 @@ export function stringifyURL(location: HistoryLocation): string { * Stringify an object query. Works like URLSearchParams. Doesn't prepend a `?` * @param query */ -export function stringifyQuery(query: HistoryQuery): string { +export function stringifyQuery(query: RawHistoryQuery): string { let search = '' // TODO: util function? for (const key in query) { @@ -106,7 +106,7 @@ export function stringifyQuery(query: HistoryQuery): string { return search } -export function normalizeQuery(query: RouteQuery): HistoryQuery { +export function normalizeQuery(query: RawHistoryQuery): HistoryQuery { // TODO: implem return query as HistoryQuery } @@ -136,7 +136,7 @@ export function normalizeLocation( return { fullPath: stringifyURL(location), path: location.path, - query: location.query || {}, + query: location.query ? normalizeQuery(location.query) : {}, hash: location.hash || '', } } diff --git a/src/router.ts b/src/router.ts index 93147b91..6d7e6ad2 100644 --- a/src/router.ts +++ b/src/router.ts @@ -9,7 +9,6 @@ import { RouteRecord, START_LOCATION_NORMALIZED, RouteLocationNormalized, - MatcherLocationNormalized, ListenerRemover, NavigationGuard, TODO, @@ -83,7 +82,7 @@ export class Router { currentLocation: RouteLocationNormalized, redirectedFrom?: RouteLocationNormalized // ensure when returning that the redirectedFrom is a normalized location - ): MatcherLocationNormalized & { redirectedFrom?: RouteLocationNormalized } { + ): RouteLocationNormalized { const matchedRoute = this.matcher.resolve(location, currentLocation) if ('redirect' in matchedRoute) { @@ -117,6 +116,10 @@ export class Router { ) } + // TODO: should we allow partial redirects? I think we should because it's impredictable if + // there was a redirect before + // if (!('path' in newLocation) && !('name' in newLocation)) throw new Error('TODO: redirect canot be relative') + return this.matchLocation( { ...newLocation, @@ -139,8 +142,14 @@ export class Router { } } else { // add the redirectedFrom field + const url = this.history.utils.normalizeLocation({ + path: matchedRoute.path, + query: location.query, + hash: location.hash, + }) return { ...matchedRoute, + ...url, redirectedFrom, } } @@ -153,9 +162,7 @@ export class Router { */ async push(to: RouteLocation): Promise { let url: HistoryLocationNormalized - let location: MatcherLocationNormalized & { - redirectedFrom?: RouteLocationNormalized - } + let location: RouteLocationNormalized // TODO: refactor into matchLocation to return location and url if (typeof to === 'string' || 'path' in to) { url = this.history.utils.normalizeLocation(to) @@ -179,7 +186,7 @@ export class Router { // TODO: needs a proper check because order could be different if (this.currentRoute.fullPath === url.fullPath) return this.currentRoute - const toLocation: RouteLocationNormalized = { ...url, ...location } + const toLocation: RouteLocationNormalized = location // trigger all guards, throw if navigation is rejected try { await this.navigate(toLocation, this.currentRoute) diff --git a/src/types/index.ts b/src/types/index.ts index 6badf683..f925d2d6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,4 @@ -import { HistoryQuery } from '../history/base' +import { HistoryQuery, RawHistoryQuery } from '../history/base' export type Lazy = () => Promise @@ -8,10 +8,9 @@ export type ListenerRemover = () => void // TODO: support numbers for easier writing but cast them export type RouteParams = Record -export type RouteQuery = Record export interface RouteQueryAndHash { - query?: RouteQuery + query?: RawHistoryQuery hash?: string } export interface LocationAsPath {