Skip to content

Commit

Permalink
Add native match function to library
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed Nov 11, 2019
1 parent dd966ea commit 0e0dce9
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 36 deletions.
16 changes: 14 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ npm install path-to-regexp --save
const pathToRegexp = require('path-to-regexp')

// pathToRegexp(path, keys?, options?)
// pathToRegexp.match(path)
// pathToRegexp.parse(path)
// pathToRegexp.compile(path)
```
Expand Down Expand Up @@ -150,9 +151,20 @@ regexpWord.exec('/users')

**Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.

### Match

The `match` function will return a function for transforming paths into parameters:

```js
const match = pathToRegexp.match('/user/:id')

match('/user/123') //=> { path: '/user/123', index: 0, params: { id: '123' } }
match('/invalid') //=> false
```

### Parse

The parse function is exposed via `pathToRegexp.parse`. This will return an array of strings and keys.
The `parse` function will return a list of strings and keys from a path string:

```js
const tokens = pathToRegexp.parse('/route/:foo/(.*)')
Expand All @@ -171,7 +183,7 @@ console.log(tokens[2])

### Compile ("Reverse" Path-To-RegExp)

Path-To-RegExp exposes a compile function for transforming a string into a valid path.
The `compile` function will return a function for transforming parameters into a valid path:

```js
const toPath = pathToRegexp.compile('/user/:id')
Expand Down
26 changes: 26 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ declare namespace pathToRegexp {
*/
export function parse (path: string, options?: ParseOptions): Token[];

/**
* Create path match function from `path-to-regexp` spec.
*/
export function match <P extends object = object> (path: string, options?: ParseOptions): MatchFunction<P>;

/**
* Create a path match function from `path-to-regexp` output.
*/
export function regexpToFunction <P extends object = object> (re: RegExp, keys: Key[]): MatchFunction<P>;

/**
* Transforming an Express-style path into a valid path.
*/
Expand Down Expand Up @@ -86,9 +96,25 @@ declare namespace pathToRegexp {
validate?: boolean;
}

interface MatchFunctionOptions {
/**
* Function for decoding strings for params.
*/
decode?: (value: string, token: Key) => string;
}

interface MatchResult <P extends object = object> {
path: string;
index: number;
params: P;
}

type Match <P extends object = object> = false | MatchResult<P>;

export type Token = string | Key;
export type Path = string | RegExp | Array<string | RegExp>;
export type PathFunction <P extends object = object> = (data?: P, options?: PathFunctionOptions) => string;
export type MatchFunction <P extends object = object> = (path: string, options?: MatchFunctionOptions) => Match<P>;
}

export = pathToRegexp;
42 changes: 42 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Expose `pathToRegexp`.
*/
module.exports = pathToRegexp
module.exports.match = match
module.exports.regexpToFunction = regexpToFunction
module.exports.parse = parse
module.exports.compile = compile
module.exports.tokensToFunction = tokensToFunction
Expand Down Expand Up @@ -120,6 +122,46 @@ function compile (str, options) {
return tokensToFunction(parse(str, options), options)
}

/**
* Create path match function from `path-to-regexp` spec.
*/
function match (str, options) {
var keys = []
var re = pathToRegexp(str, keys, options)
return regexpToFunction(re, keys)
}

/**
* Create a path match function from `path-to-regexp` output.
*/
function regexpToFunction (re, keys) {
return function (pathname, options) {
var m = re.exec(pathname)
if (!m) return false

var path = m[0]
var index = m.index
var params = {}
var decode = (options && options.decode) || decodeURIComponent

for (var i = 1; i < m.length; i++) {
if (m[i] === undefined) continue

var key = keys[i - 1]

if (key.repeat) {
params[key.name] = m[i].split(key.delimiter).map(function (value) {
return decode(value, key)
})
} else {
params[key.name] = decode(m[i], key)
}
}

return { path: path, index: index, params: params }
}
}

/**
* Expose a method for transforming tokens into the path function.
*/
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@
"nyc": "^14.1.1",
"standard": "^14.1.0",
"ts-node": "^8.3.0",
"typescript": "^3.0.1"
"typescript": "^3.7.2"
}
}
70 changes: 40 additions & 30 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Test = [
pathToRegexp.Path,
pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions,
pathToRegexp.Token[],
Array<[string, string[]]>,
Array<[string, string[], pathToRegexp.Match?]>,
Array<[any, string] | [any, string, pathToRegexp.PathFunctionOptions]>
]

Expand All @@ -30,8 +30,8 @@ var TESTS: Test[] = [
'/'
],
[
['/', ['/']],
['/route', null]
['/', ['/'], { path: '/', index: 0, params: {} }],
['/route', null, false]
],
[
[null, '/'],
Expand All @@ -46,10 +46,10 @@ var TESTS: Test[] = [
'/test'
],
[
['/test', ['/test']],
['/route', null],
['/test/route', null],
['/test/', ['/test/']]
['/test', ['/test'], { path: '/test', index: 0, params: {} }],
['/route', null, false],
['/test/route', null, false],
['/test/', ['/test/'], { path: '/test/', index: 0, params: {} }]
],
[
[null, '/test'],
Expand Down Expand Up @@ -201,7 +201,7 @@ var TESTS: Test[] = [
}
],
[
['/route', ['/route', 'route']]
['/route', ['/route', 'route'], { path: '/route', index: 0, params: { test: 'route' } }]
],
[
[{}, null],
Expand Down Expand Up @@ -734,9 +734,9 @@ var TESTS: Test[] = [
}
],
[
['/route', ['/route', 'route']],
['/route/nested', null],
['/', ['/', undefined]],
['/route', ['/route', 'route'], { path: '/route', index: 0, params: { test: 'route' } }],
['/route/nested', null, false],
['/', ['/', undefined], { path: '/', index: 0, params: {} }],
['//', null]
],
[
Expand Down Expand Up @@ -885,10 +885,10 @@ var TESTS: Test[] = [
}
],
[
['/', null],
['/route', ['/route', 'route']],
['/some/basic/route', ['/some/basic/route', 'some/basic/route']],
['//', null]
['/', null, false],
['/route', ['/route', 'route'], { path: '/route', index: 0, params: { test: ['route'] } }],
['/some/basic/route', ['/some/basic/route', 'some/basic/route'], { path: '/some/basic/route', index: 0, params: { test: ['some', 'basic', 'route'] } }],
['//', null, false]
],
[
[{}, null],
Expand Down Expand Up @@ -988,13 +988,14 @@ var TESTS: Test[] = [
}
],
[
['/', ['/', undefined]],
['//', null],
['/route', ['/route', 'route']],
['/some/basic/route', ['/some/basic/route', 'some/basic/route']]
['/', ['/', undefined], { path: '/', index: 0, params: {} }],
['//', null, false],
['/route', ['/route', 'route'], { path: '/route', index: 0, params: { test: ['route'] } }],
['/some/basic/route', ['/some/basic/route', 'some/basic/route'], { path: '/some/basic/route', index: 0, params: { test: ['some', 'basic', 'route'] } }]
],
[
[{}, ''],
[{ test: [] }, ''],
[{ test: 'foobar' }, '/foobar'],
[{ test: ['foo', 'bar'] }, '/foo/bar']
]
Expand Down Expand Up @@ -2782,18 +2783,18 @@ describe('path-to-regexp', function () {
var toPath = pathToRegexp.compile(path as string, opts)

compileCases.forEach(function (io) {
var input = io[0]
var output = io[1]
var params = io[0]
var path = io[1]
var options = io[2]

if (output != null) {
it('should compile using ' + util.inspect(input), function () {
expect(toPath(input, options)).to.equal(output)
if (path != null) {
it('should compile using ' + util.inspect(params), function () {
expect(toPath(params, options)).to.equal(path)
})
} else {
it('should not compile using ' + util.inspect(input), function () {
it('should not compile using ' + util.inspect(params), function () {
expect(function () {
toPath(input, options)
toPath(params, options)
}).to.throw(TypeError)
})
}
Expand All @@ -2809,13 +2810,22 @@ describe('path-to-regexp', function () {

describe('match' + (opts ? ' using ' + util.inspect(opts) : ''), function () {
matchCases.forEach(function (io) {
var input = io[0]
var output = io[1]
var message = 'should' + (output ? ' ' : ' not ') + 'match ' + util.inspect(input)
var pathname = io[0]
var matches = io[1]
var params = io[2]
var message = 'should' + (matches ? ' ' : ' not ') + 'match ' + util.inspect(pathname)

it(message, function () {
expect(exec(re, input)).to.deep.equal(output)
expect(exec(re, pathname)).to.deep.equal(matches)
})

if (typeof path === "string" && params !== undefined) {
var match = pathToRegexp.match(path)

it(message + ' params', function () {
expect(match(pathname)).to.deep.equal(params)
})
}
})
})
})
Expand Down

0 comments on commit 0e0dce9

Please sign in to comment.