Skip to content

Case Sensitive Option for Routes #1214 #1215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 16, 2017
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