Skip to content

Commit

Permalink
leave more characters unescaped for segments (#75)
Browse files Browse the repository at this point in the history
treat `;,:@&=+$-_.!~*()` characters as safe to be part of segment
  • Loading branch information
Guria authored and blakeembrey committed May 8, 2016
1 parent e06109e commit 30decc1
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 10 deletions.
5 changes: 4 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ toPath({ id: 123 }) //=> "/user/123"
toPath({ id: 'café' }) //=> "/user/caf%C3%A9"
toPath({ id: '/' }) //=> "/user/%2F"

toPath({ id: ':' }) //=> "/user/%3A"
toPath({ id: ':' }, { pretty: true }) //=> "/user/:"

var toPathRepeated = pathToRegexp.compile('/:segment+')

toPathRepeated({ segment: 'foo' }) //=> "/foo"
Expand All @@ -194,7 +197,7 @@ var toPathRegexp = pathToRegexp.compile('/user/:id(\\d+)')

toPathRegexp({ id: 123 }) //=> "/user/123"
toPathRegexp({ id: '123' }) //=> "/user/123"
toPathRegexp({ id: 'abc' }) //=> throws TypeError
toPathRegexp({ id: 'abc' }) //=> Throws `TypeError`.
```

**Note:** The generated function will throw on invalid input. It will do all necessary checks to ensure the generated path is valid. This method only works with strings.
Expand Down
6 changes: 5 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ declare namespace pathToRegexp {
pattern: string;
}

interface PathFunctionOptions {
pretty?: boolean;
}

export type Token = string | Key;
export type Path = string | RegExp | Array<string | RegExp>;
export type PathFunction = (data?: Object) => string;
export type PathFunction = (data?: Object, options?: PathFunctionOptions) => string;
}

export = pathToRegexp;
22 changes: 18 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,24 @@ function parse (str) {
* Compile a string to a template function for the path.
*
* @param {string} str
* @return {!function(Object=)}
* @return {!function(Object=, Object=)}
*/
function compile (str) {
return tokensToFunction(parse(str))
}

/**
* Encode characters for segment that could cause trouble for parsing.
*
* @param {string}
* @return {string}
*/
function encodeURIComponentPretty (str) {
return encodeURI(str).replace(/[/?#'"]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
})
}

/**
* Expose a method for transforming tokens into the path function.
*/
Expand All @@ -125,9 +137,11 @@ function tokensToFunction (tokens) {
}
}

return function (obj) {
return function (obj, opts) {
var path = ''
var data = obj || {}
var options = opts || {}
var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent

for (var i = 0; i < tokens.length; i++) {
var token = tokens[i]
Expand Down Expand Up @@ -163,7 +177,7 @@ function tokensToFunction (tokens) {
}

for (var j = 0; j < value.length; j++) {
segment = encodeURIComponent(value[j])
segment = encode(value[j])

if (!matches[i].test(segment)) {
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
Expand All @@ -175,7 +189,7 @@ function tokensToFunction (tokens) {
continue
}

segment = encodeURIComponent(value)
segment = encode(value)

if (!matches[i].test(segment)) {
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
Expand Down
23 changes: 19 additions & 4 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,14 @@ var TESTS: Test[] = [
['/another', ['/another', 'another']],
['/something/else', null],
['/route.json', ['/route.json', 'route.json']],
['/something%2Felse', ['/something%2Felse', 'something%2Felse']]
['/something%2Felse', ['/something%2Felse', 'something%2Felse']],
['/something%2Felse%2Fmore', ['/something%2Felse%2Fmore', 'something%2Felse%2Fmore']],
['/;,:@&=+$-_.!~*()', ['/;,:@&=+$-_.!~*()', ';,:@&=+$-_.!~*()']]
],
[
[{ test: 'route' }, '/route'],
[{ test: 'something/else' }, '/something%2Felse']
[{ test: 'something/else' }, '/something%2Felse'],
[{ test: 'something/else/more' }, '/something%2Felse%2Fmore']
]
],
[
Expand Down Expand Up @@ -799,12 +802,14 @@ var TESTS: Test[] = [
}
],
[
['/anything/goes/here', ['/anything/goes/here', 'anything/goes/here']]
['/anything/goes/here', ['/anything/goes/here', 'anything/goes/here']],
['/;,:@&=/+$-_.!/~*()', ['/;,:@&=/+$-_.!/~*()', ';,:@&=/+$-_.!/~*()']]
],
[
[{ test: '' }, '/'],
[{ test: 'abc' }, '/abc'],
[{ test: 'abc/123' }, '/abc%2F123']
[{ test: 'abc/123' }, '/abc%2F123'],
[{ test: 'abc/123/456' }, '/abc%2F123%2F456']
]
],
[
Expand Down Expand Up @@ -1981,6 +1986,16 @@ describe('path-to-regexp', function () {
})
})

describe('compile', function () {
it('should allow pretty option', function () {
var value = ';,:@&=+$-_.!~*()'
var toPath = pathToRegexp.compile('/:value')
var path = toPath({ value }, { pretty: true })

expect(path).to.equal(`/${value}`)
})
})

describe('compile errors', function () {
it('should throw when a required param is undefined', function () {
var toPath = pathToRegexp.compile('/a/:b/c')
Expand Down

0 comments on commit 30decc1

Please sign in to comment.