Skip to content

Commit 04a02c0

Browse files
committed
feat(alias): warn against redundant aliases
Fix #2461, #2462
1 parent 799ceca commit 04a02c0

File tree

2 files changed

+118
-45
lines changed

2 files changed

+118
-45
lines changed

src/create-route-map.js

+57-35
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export function createRouteMap (
1010
oldPathMap?: Dictionary<RouteRecord>,
1111
oldNameMap?: Dictionary<RouteRecord>
1212
): {
13-
pathList: Array<string>;
14-
pathMap: Dictionary<RouteRecord>;
15-
nameMap: Dictionary<RouteRecord>;
13+
pathList: Array<string>,
14+
pathMap: Dictionary<RouteRecord>,
15+
nameMap: Dictionary<RouteRecord>
1616
} {
1717
// the path list is used to control path matching priority
1818
const pathList: Array<string> = oldPathList || []
@@ -54,17 +54,15 @@ function addRouteRecord (
5454
assert(path != null, `"path" is required in a route configuration.`)
5555
assert(
5656
typeof route.component !== 'string',
57-
`route config "component" for path: ${String(path || name)} cannot be a ` +
58-
`string id. Use an actual component instead.`
57+
`route config "component" for path: ${String(
58+
path || name
59+
)} cannot be a ` + `string id. Use an actual component instead.`
5960
)
6061
}
6162

62-
const pathToRegexpOptions: PathToRegexpOptions = route.pathToRegexpOptions || {}
63-
const normalizedPath = normalizePath(
64-
path,
65-
parent,
66-
pathToRegexpOptions.strict
67-
)
63+
const pathToRegexpOptions: PathToRegexpOptions =
64+
route.pathToRegexpOptions || {}
65+
const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
6866

6967
if (typeof route.caseSensitive === 'boolean') {
7068
pathToRegexpOptions.sensitive = route.caseSensitive
@@ -81,26 +79,33 @@ function addRouteRecord (
8179
redirect: route.redirect,
8280
beforeEnter: route.beforeEnter,
8381
meta: route.meta || {},
84-
props: route.props == null
85-
? {}
86-
: route.components
87-
? route.props
88-
: { default: route.props }
82+
props:
83+
route.props == null
84+
? {}
85+
: route.components
86+
? route.props
87+
: { default: route.props }
8988
}
9089

9190
if (route.children) {
9291
// Warn if route is named, does not redirect and has a default child route.
9392
// If users navigate to this route by name, the default child will
9493
// not be rendered (GH Issue #629)
9594
if (process.env.NODE_ENV !== 'production') {
96-
if (route.name && !route.redirect && route.children.some(child => /^\/?$/.test(child.path))) {
95+
if (
96+
route.name &&
97+
!route.redirect &&
98+
route.children.some(child => /^\/?$/.test(child.path))
99+
) {
97100
warn(
98101
false,
99102
`Named Route '${route.name}' has a default child route. ` +
100-
`When navigating to this named route (:to="{name: '${route.name}'"), ` +
101-
`the default child route will not be rendered. Remove the name from ` +
102-
`this route and use the name of the default child route for named ` +
103-
`links instead.`
103+
`When navigating to this named route (:to="{name: '${
104+
route.name
105+
}'"), ` +
106+
`the default child route will not be rendered. Remove the name from ` +
107+
`this route and use the name of the default child route for named ` +
108+
`links instead.`
104109
)
105110
}
106111
}
@@ -112,12 +117,24 @@ function addRouteRecord (
112117
})
113118
}
114119

120+
if (!pathMap[record.path]) {
121+
pathList.push(record.path)
122+
pathMap[record.path] = record
123+
}
124+
115125
if (route.alias !== undefined) {
116-
const aliases = Array.isArray(route.alias)
117-
? route.alias
118-
: [route.alias]
126+
const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]
127+
for (let i = 0; i < aliases.length; ++i) {
128+
const alias = aliases[i]
129+
if (process.env.NODE_ENV !== 'production' && alias === path) {
130+
warn(
131+
false,
132+
`Found an alias with the same value as the path: "${path}". You have to remove that alias. It will be ignored in development.`
133+
)
134+
// skip in dev to make it work
135+
continue
136+
}
119137

120-
aliases.forEach(alias => {
121138
const aliasRoute = {
122139
path: alias,
123140
children: route.children
@@ -130,12 +147,7 @@ function addRouteRecord (
130147
parent,
131148
record.path || '/' // matchAs
132149
)
133-
})
134-
}
135-
136-
if (!pathMap[record.path]) {
137-
pathList.push(record.path)
138-
pathMap[record.path] = record
150+
}
139151
}
140152

141153
if (name) {
@@ -145,25 +157,35 @@ function addRouteRecord (
145157
warn(
146158
false,
147159
`Duplicate named routes definition: ` +
148-
`{ name: "${name}", path: "${record.path}" }`
160+
`{ name: "${name}", path: "${record.path}" }`
149161
)
150162
}
151163
}
152164
}
153165

154-
function compileRouteRegex (path: string, pathToRegexpOptions: PathToRegexpOptions): RouteRegExp {
166+
function compileRouteRegex (
167+
path: string,
168+
pathToRegexpOptions: PathToRegexpOptions
169+
): RouteRegExp {
155170
const regex = Regexp(path, [], pathToRegexpOptions)
156171
if (process.env.NODE_ENV !== 'production') {
157172
const keys: any = Object.create(null)
158173
regex.keys.forEach(key => {
159-
warn(!keys[key.name], `Duplicate param keys in route with path: "${path}"`)
174+
warn(
175+
!keys[key.name],
176+
`Duplicate param keys in route with path: "${path}"`
177+
)
160178
keys[key.name] = true
161179
})
162180
}
163181
return regex
164182
}
165183

166-
function normalizePath (path: string, parent?: RouteRecord, strict?: boolean): string {
184+
function normalizePath (
185+
path: string,
186+
parent?: RouteRecord,
187+
strict?: boolean
188+
): string {
167189
if (!strict) path = path.replace(/\/$/, '')
168190
if (path[0] === '/') return path
169191
if (parent == null) return path

test/unit/specs/create-map.spec.js

+61-10
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,28 @@ describe('Creating Route Map', function () {
5757
})
5858

5959
it('has a pathList which places wildcards at the end', () => {
60-
expect(maps.pathList).toEqual(['', '/foo', '/bar/', '/bar', '/bar-redirect/', '/bar-redirect', '*'])
60+
expect(maps.pathList).toEqual([
61+
'',
62+
'/foo',
63+
'/bar/',
64+
'/bar',
65+
'/bar-redirect/',
66+
'/bar-redirect',
67+
'*'
68+
])
6169
})
6270

63-
it('has a nameMap object for default subroute at \'bar.baz\'', function () {
71+
it("has a nameMap object for default subroute at 'bar.baz'", function () {
6472
expect(maps.nameMap['bar.baz']).not.toBeUndefined()
6573
})
6674

6775
it('in development, has logged a warning concerning named route of parent and default subroute', function () {
6876
process.env.NODE_ENV = 'development'
6977
maps = createRouteMap(routes)
7078
expect(console.warn).toHaveBeenCalledTimes(1)
71-
expect(console.warn.calls.argsFor(0)[0]).toMatch('vue-router] Named Route \'bar\'')
79+
expect(console.warn.calls.argsFor(0)[0]).toMatch(
80+
"vue-router] Named Route 'bar'"
81+
)
7282
})
7383

7484
it('in development, throws if path is missing', function () {
@@ -87,22 +97,63 @@ describe('Creating Route Map', function () {
8797
process.env.NODE_ENV = 'development'
8898
maps = createRouteMap([
8999
{
90-
path: '/foo/:id', component: Foo,
91-
children: [
92-
{ path: 'bar/:id', component: Bar }
93-
]
100+
path: '/foo/:id',
101+
component: Foo,
102+
children: [{ path: 'bar/:id', component: Bar }]
103+
}
104+
])
105+
expect(console.warn).toHaveBeenCalled()
106+
expect(console.warn.calls.argsFor(0)[0]).toMatch(
107+
'vue-router] Duplicate param keys in route with path: "/foo/:id/bar/:id"'
108+
)
109+
})
110+
111+
it('in development, warns about alias and path having the same value', () => {
112+
process.env.NODE_ENV = 'development'
113+
maps = createRouteMap([
114+
{
115+
path: '/foo-alias',
116+
component: Foo,
117+
alias: '/foo-alias'
118+
}
119+
])
120+
expect(console.warn).toHaveBeenCalled()
121+
expect(console.warn.calls.argsFor(0)[0]).toMatch(
122+
'vue-router] Found an alias with the same value as the path: "/foo-alias"'
123+
)
124+
})
125+
126+
it('in development, warns about one alias (in an array) having the same value as the path', () => {
127+
process.env.NODE_ENV = 'development'
128+
maps = createRouteMap([
129+
{
130+
path: '/foo-alias',
131+
component: Foo,
132+
alias: ['/bar', '/foo-alias']
94133
}
95134
])
96135
expect(console.warn).toHaveBeenCalled()
97-
expect(console.warn.calls.argsFor(0)[0]).toMatch('vue-router] Duplicate param keys in route with path: "/foo/:id/bar/:id"')
136+
expect(console.warn.calls.argsFor(0)[0]).toMatch(
137+
'vue-router] Found an alias with the same value as the path: "/foo-alias"'
138+
)
98139
})
99140

100141
describe('path-to-regexp options', function () {
101142
const routes = [
102143
{ path: '/foo', name: 'foo', component: Foo },
103144
{ path: '/bar', name: 'bar', component: Bar, caseSensitive: false },
104-
{ path: '/FooBar', name: 'FooBar', component: FooBar, caseSensitive: true },
105-
{ path: '/foobar', name: 'foobar', component: Foobar, caseSensitive: true }
145+
{
146+
path: '/FooBar',
147+
name: 'FooBar',
148+
component: FooBar,
149+
caseSensitive: true
150+
},
151+
{
152+
path: '/foobar',
153+
name: 'foobar',
154+
component: Foobar,
155+
caseSensitive: true
156+
}
106157
]
107158

108159
it('caseSensitive option in route', function () {

0 commit comments

Comments
 (0)