diff --git a/src/create-matcher.js b/src/create-matcher.js index f7d72b93e..0b8f1b7e1 100644 --- a/src/create-matcher.js +++ b/src/create-matcher.js @@ -54,7 +54,7 @@ export function createMatcher ( redirectedFrom?: Location ): Route { const location = normalizeLocation(raw, currentRoute, false, router) - const { name } = location + const { name, path } = location if (name) { const record = nameMap[name] @@ -80,12 +80,17 @@ export function createMatcher ( location.path = fillParams(record.path, location.params, `named route "${name}"`) return _createRoute(record, location, redirectedFrom) - } else if (location.path) { + } else if (path) { location.params = {} + const staticRecord = pathMap[path] + if (staticRecord) { + if (matchRoute(staticRecord.regex, path, location.params)) { + return _createRoute(staticRecord, location, redirectedFrom) + } + } for (let i = 0; i < pathList.length; i++) { - const path = pathList[i] - const record = pathMap[path] - if (matchRoute(record.regex, location.path, location.params)) { + const record = pathMap[pathList[i]] + if (matchRoute(record.regex, path, location.params)) { return _createRoute(record, location, redirectedFrom) } } diff --git a/src/create-route-map.js b/src/create-route-map.js index 93a558f8a..9315c1a8f 100644 --- a/src/create-route-map.js +++ b/src/create-route-map.js @@ -144,7 +144,10 @@ function addRouteRecord ( }) } - if (!pathMap[record.path]) { + if (!pathMap[record.path] && !pathList.some(pathItem => { + const r = pathMap[pathItem] + return r.path.indexOf('*') === -1 && record.path.match(r.regex) + })) { pathList.push(record.path) pathMap[record.path] = record } diff --git a/test/unit/specs/create-map.spec.js b/test/unit/specs/create-map.spec.js index 57c81afe1..bdd24ef2f 100644 --- a/test/unit/specs/create-map.spec.js +++ b/test/unit/specs/create-map.spec.js @@ -19,6 +19,7 @@ const routes = [ children: [ { path: '', + pathToRegexpOptions: { strict: true }, component: Baz, name: 'bar.baz' } @@ -63,7 +64,6 @@ describe('Creating Route Map', function () { '/bar/', '/bar', '/bar-redirect/', - '/bar-redirect', '*' ]) }) diff --git a/test/unit/specs/create-matcher.spec.js b/test/unit/specs/create-matcher.spec.js index fcc2587c2..2279e8d49 100644 --- a/test/unit/specs/create-matcher.spec.js +++ b/test/unit/specs/create-matcher.spec.js @@ -54,6 +54,24 @@ describe('Creating Matcher', function () { expect(matcher.match('/p/c/n').name).toBe('nested') }) + it('match default child', function () { + const component = { name: 'fake' } + const matcher = createMatcher([ + { + path: '/p', + name: 'parent', + children: [ + { path: '', name: 'parent.default', component }, + { path: 'a', name: 'parent.a', component } + ] + }, + { path: '*', name: 'not-found', component } + ]) + expect(matcher.match('/p').name).toBe('parent.default') + expect(matcher.match('/p/').name).toBe('parent.default') + expect(matcher.match('/p/a').name).toBe('parent.a') + }) + it('can get all routes', function () { const component = { name: 'fake' } const matcher = createMatcher([]) @@ -151,4 +169,163 @@ describe('Creating Matcher', function () { expect(pathForErrorRoute).toEqual('/error/') expect(pathForNotFoundRoute).toEqual('/') }) + + it('respect ordering', function () { + const matcher = createMatcher([ + { + path: '/p/staticbefore', + name: 'staticbefore', + component: { name: 'staticbefore' } + }, + { + path: '/p/:id', + name: 'dynamic', + component: { name: 'dynamic' } + }, + { + path: '/p/staticafter', + name: 'staticafter', + component: { name: 'staticafter' } + } + ]) + expect(matcher.match('/p/staticbefore').name).toBe('staticbefore') + expect(matcher.match('/p/staticafter').name).toBe('dynamic') + }) + + it('respect ordering for full dynamic', function () { + const matcher = createMatcher([ + { + path: '/before/static', + name: 'staticbefore', + component: { name: 'staticbefore' } + }, + { + path: '/:foo/static', + name: 'dynamic', + component: { name: 'dynamic' } + }, + { + path: '/after/static', + name: 'staticafter', + component: { name: 'staticafter' } + } + ]) + expect(matcher.match('/before/static').name).toBe('staticbefore') + expect(matcher.match('/after/static').name).toBe('dynamic') + }) + + it('respect ordering between full dynamic and first level static', function () { + const matcher = createMatcher([ + { + path: '/before/:foo', + name: 'staticbefore', + component: { name: 'staticbefore' } + }, + { + path: '/:foo/static', + name: 'dynamic', + component: { name: 'dynamic' } + }, + { + path: '/after/:foo', + name: 'staticafter', + component: { name: 'staticafter' } + } + ]) + expect(matcher.match('/before/static').name).toBe('staticbefore') + expect(matcher.match('/after/static').name).toBe('dynamic') + }) + + it('static can use sensitive flag', function () { + const matcher = createMatcher([ + { + path: '/p/sensitive', + name: 'sensitive', + pathToRegexpOptions: { + sensitive: true + }, + component: { name: 'sensitive' } + }, + { + path: '/p/insensitive', + name: 'insensitive', + component: { name: 'insensitive' } + }, + { + path: '*', name: 'not-found', component: { name: 'not-found ' } + } + ]) + + expect(matcher.match('/p/SENSITIVE').name).toBe('not-found') + expect(matcher.match('/p/INSENSITIVE').name).toBe('insensitive') + }) + + it('static can use strict flag', function () { + const matcher = createMatcher([ + { + path: '/p/strict', + name: 'strict', + pathToRegexpOptions: { + strict: true + }, + component: { name: 'strict' } + }, + { + path: '/p/unstrict', + name: 'unstrict', + component: { name: 'unstrict' } + }, + { + path: '*', name: 'not-found', component: { name: 'not-found ' } + } + ]) + + expect(matcher.match('/p/strict/').name).toBe('not-found') + expect(matcher.match('/p/unstrict/').name).toBe('unstrict') + }) + + it('static can use end flag', function () { + const matcher = createMatcher([ + { + path: '/p/end', + name: 'end', + component: { name: 'end' } + }, + { + path: '/p/not-end', + name: 'not-end', + pathToRegexpOptions: { + end: false + }, + component: { name: 'not-end' } + }, + { + path: '*', name: 'not-found', component: { name: 'not-found ' } + } + ]) + + expect(matcher.match('/p/end/foo').name).toBe('not-found') + expect(matcher.match('/p/not-end/foo').name).toBe('not-end') + }) + + it('first level dynamic must work', function () { + const matcher = createMatcher([ + { + path: '/:foo/b', + name: 'b', + component: { name: 'b' } + }, + { + path: '/p/c', + name: 'c', + component: { name: 'c' } + }, + { + path: '*', name: 'not-found', component: { name: 'not-found ' } + } + ]) + + expect(matcher.match('/p/b').name).toBe('b') + expect(matcher.match('/p/c').name).toBe('c') + }) })