Skip to content
16 changes: 16 additions & 0 deletions examples/redirect/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const WithParams = { template: '<div>{{ $route.params.id }}</div>' }
const Foobar = { template: '<div>foobar</div>' }
const FooBar = { template: '<div>FooBar</div>' }

const router = new VueRouter({
mode: 'history',
Expand Down Expand Up @@ -50,6 +52,12 @@ const router = new VueRouter({
// redirect with params
{ path: '/redirect-with-params/:id', redirect: '/with-params/:id' },

// redirect with caseSensitive
{ path: '/foobar', component: Foobar, caseSensitive: true },

// redirect with pathToRegexpOptions
{ path: '/FooBar', component: FooBar, pathToRegexpOptions: { sensitive: true }},

// catch all redirect
{ path: '*', redirect: '/' }
]
Expand Down Expand Up @@ -97,6 +105,14 @@ new Vue({
/redirect-with-params/123 (redirects to /with-params/123)
</router-link></li>

<li><router-link to="/foobar">
/foobar
</router-link></li>

<li><router-link to="/FooBar">
/FooBar
</router-link></li>

<li><router-link to="/not-found">
/not-found (redirects to /)
</router-link></li>
Expand Down
10 changes: 9 additions & 1 deletion flow/declarations.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ declare class RouteRegExp extends RegExp {
keys: Array<{ name: string, optional: boolean }>;
}

declare type PathToRegexpOptions = {
sensitive?: boolean,
strict?: boolean,
end?: boolean
}

declare module 'path-to-regexp' {
declare var exports: {
(path: string, keys?: Array<?{ name: string }>): RouteRegExp;
(path: string, keys?: Array<?{ name: string }>, options?: PathToRegexpOptions): RouteRegExp;
compile: (path: string) => (params: Object) => string;
}
}
Expand Down Expand Up @@ -48,6 +54,8 @@ declare type RouteConfig = {
beforeEnter?: NavigationGuard;
meta?: any;
props?: boolean | Object | Function;
caseSensitive?: boolean;
pathToRegexpOptions?: PathToRegexpOptions;
}

declare type RouteRecord = {
Expand Down
12 changes: 9 additions & 3 deletions src/create-route-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ function addRouteRecord (
}

const normalizedPath = normalizePath(path, parent)
const pathToRegexpOptions: PathToRegexpOptions = route.pathToRegexpOptions || {}

if (typeof route.caseSensitive === 'boolean') {
pathToRegexpOptions.sensitive = route.caseSensitive
}

const record: RouteRecord = {
path: normalizedPath,
regex: compileRouteRegex(normalizedPath),
regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
components: route.components || { default: route.component },
instances: {},
name,
Expand Down Expand Up @@ -136,8 +142,8 @@ function addRouteRecord (
}
}

function compileRouteRegex (path: string): RouteRegExp {
const regex = Regexp(path)
function compileRouteRegex (path: string, pathToRegexpOptions: PathToRegexpOptions): RouteRegExp {
const regex = Regexp(path, [], pathToRegexpOptions)
if (process.env.NODE_ENV !== 'production') {
const keys: any = {}
regex.keys.forEach(key => {
Expand Down
24 changes: 22 additions & 2 deletions test/e2e/specs/redirect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {
browser
.url('http://localhost:8080/redirect/')
.waitForElementVisible('#app', 1000)
.assert.count('li a', 10)
.assert.count('li a', 12)
// assert correct href with base
.assert.attributeContains('li:nth-child(1) a', 'href', '/redirect/relative-redirect')
.assert.attributeContains('li:nth-child(2) a', 'href', '/redirect/relative-redirect?foo=bar')
Expand All @@ -14,7 +14,9 @@ module.exports = {
.assert.attributeContains('li:nth-child(7) a', 'href', '/redirect/dynamic-redirect#baz')
.assert.attributeContains('li:nth-child(8) a', 'href', '/redirect/named-redirect')
.assert.attributeContains('li:nth-child(9) a', 'href', '/redirect/redirect-with-params/123')
.assert.attributeContains('li:nth-child(10) a', 'href', '/not-found')
.assert.attributeContains('li:nth-child(10) a', 'href', '/redirect/foobar')
.assert.attributeContains('li:nth-child(11) a', 'href', '/redirect/FooBar')
.assert.attributeContains('li:nth-child(12) a', 'href', '/not-found')

.assert.containsText('.view', 'default')

Expand Down Expand Up @@ -55,6 +57,14 @@ module.exports = {
.assert.containsText('.view', '123')

.click('li:nth-child(10) a')
.assert.urlEquals('http://localhost:8080/redirect/foobar')
.assert.containsText('.view', 'foobar')

.click('li:nth-child(11) a')
.assert.urlEquals('http://localhost:8080/redirect/FooBar')
.assert.containsText('.view', 'FooBar')

.click('li:nth-child(12) a')
.assert.urlEquals('http://localhost:8080/redirect/')
.assert.containsText('.view', 'default')

Expand Down Expand Up @@ -104,6 +114,16 @@ module.exports = {
.assert.urlEquals('http://localhost:8080/redirect/with-params/123')
.assert.containsText('.view', '123')

.url('http://localhost:8080/redirect/foobar')
.waitForElementVisible('#app', 1000)
.assert.urlEquals('http://localhost:8080/redirect/foobar')
.assert.containsText('.view', 'foobar')

.url('http://localhost:8080/redirect/FooBar')
.waitForElementVisible('#app', 1000)
.assert.urlEquals('http://localhost:8080/redirect/FooBar')
.assert.containsText('.view', 'FooBar')

.url('http://localhost:8080/redirect/not-found')
.waitForElementVisible('#app', 1000)
.assert.urlEquals('http://localhost:8080/redirect/')
Expand Down
1 change: 0 additions & 1 deletion test/e2e/specs/route-matching.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ module.exports = {
})
)
}, null, '/optional-group/foo/bar')

.end()
}
}
59 changes: 59 additions & 0 deletions test/unit/specs/create-map.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { createRouteMap } from '../../../src/create-route-map'

const Home = { template: '<div>This is Home</div>' }
const Foo = { template: '<div>This is Foo</div>' }
const FooBar = { template: '<div>This is FooBar</div>' }
const Foobar = { template: '<div>This is foobar</div>' }
const Bar = { template: '<div>This is Bar <router-view></router-view></div>' }
const Baz = { template: '<div>This is Baz</div>' }

Expand Down Expand Up @@ -74,4 +76,61 @@ describe('Creating Route Map', function () {
expect(console.warn).toHaveBeenCalled()
expect(console.warn.calls.argsFor(0)[0]).toMatch('vue-router] Duplicate param keys in route with path: "/foo/:id/bar/:id"')
})

describe('path-to-regexp options', function () {
const routes = [
{ path: '/foo', name: 'foo', component: Foo },
{ path: '/bar', name: 'bar', component: Bar, caseSensitive: false },
{ path: '/FooBar', name: 'FooBar', component: FooBar, caseSensitive: true },
{ path: '/foobar', name: 'foobar', component: Foobar, caseSensitive: true }
]

it('caseSensitive option in route', function () {
const { nameMap } = createRouteMap(routes)

expect(nameMap.FooBar.regex.ignoreCase).toBe(false)
expect(nameMap.bar.regex.ignoreCase).toBe(true)
expect(nameMap.foo.regex.ignoreCase).toBe(true)
})

it('pathToRegexpOptions option in route', function () {
const { nameMap } = createRouteMap([
{
name: 'foo',
path: '/foo',
component: Foo,
pathToRegexpOptions: {
sensitive: true
}
},
{
name: 'bar',
path: '/bar',
component: Bar,
pathToRegexpOptions: {
sensitive: false
}
}
])

expect(nameMap.foo.regex.ignoreCase).toBe(false)
expect(nameMap.bar.regex.ignoreCase).toBe(true)
})

it('caseSensitive over pathToRegexpOptions in route', function () {
const { nameMap } = createRouteMap([
{
name: 'foo',
path: '/foo',
component: Foo,
caseSensitive: true,
pathToRegexpOptions: {
sensitive: false
}
}
])

expect(nameMap.foo.regex.ignoreCase).toBe(false)
})
})
})
8 changes: 8 additions & 0 deletions types/router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export interface RouterOptions {

type RoutePropsFunction = (route: Route) => Object;

export interface PathToRegexpOptions {
sensitive?: boolean;
strict?: boolean;
end?: boolean;
}

export interface RouteConfig {
path: string;
name?: string;
Expand All @@ -71,6 +77,8 @@ export interface RouteConfig {
meta?: any;
beforeEnter?: NavigationGuard;
props?: boolean | Object | RoutePropsFunction;
caseSensitive?: boolean;
pathToRegexpOptions?: PathToRegexpOptions;
}

export interface RouteRecord {
Expand Down