Socket
Socket
Sign inDemoInstall

path-to-regexp

Package Overview
Dependencies
0
Maintainers
26
Versions
56
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.2 to 0.2.0

.travis.yml

2

component.json
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "0.1.0",
"version": "0.2.0",
"keywords": [

@@ -6,0 +6,0 @@ "express",

@@ -0,6 +1,29 @@

0.2.0 / 2014-06-09
==================
* Improved support for arrays
* Improved support for regexps
* Better support for non-ending strict mode matches with a trailing slash
* Travis CI support
* Block using regexp special characters in the path
* Removed support for the asterisk to match all
* New support for parameter suffixes - `*`, `+` and `?`
* Updated readme
* Provide delimiter information with keys array
0.1.2 / 2014-03-10
==================
* Move testing dependencies to `devDependencies`
0.1.1 / 2014-03-10
==================
* Match entire substring with `options.end`
* Properly handle ending and non-ending matches
0.1.0 / 2014-03-06
==================
* add options.end
* Add `options.end`

@@ -11,2 +34,2 @@ 0.0.2 / 2013-02-10

* Update to match current express
* add .license property to component.json
* Add .license property to component.json
/**
* Expose `pathtoRegexp`.
*/
module.exports = pathtoRegexp;
var PATH_REGEXP = new RegExp([
// Match already escaped characters that would otherwise incorrectly appear
// in future matches. This allows the user to escape special characters that
// shouldn't be transformed.
'(\\\\.)',
// Match Express-style parameters and un-named parameters with a prefix
// and optional suffixes. Matches appear as:
//
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
'([\\/.])?(?:\\:(\\w+)(?:\\((.+)\\))?|\\((.+)\\))([+*?])?',
// Match regexp special characters that should always be escaped.
'([.+*?=^!:${}()[\\]|\\/])'
].join('|'), 'g');
/**
* Normalize the given path string,
* returning a regular expression.
* Escape the capturing group by escaping special characters and meaning.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
* @param {String} group
* @return {String}
*/
function escapeGroup (group) {
return group.replace(/([=!:$\/()])/g, '\\$1');
}
/**
* Normalize the given path string, returning a regular expression.
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Object} options
* An empty array should be passed in, which will contain the placeholder key
* names. For example `/user/:id` will then contain `["id"]`.
*
* @param {(String|RegExp|Array)} path
* @param {Array} keys
* @param {Object} options
* @return {RegExp}
* @api private
*/
function pathtoRegexp (path, keys, options) {
keys = keys || [];
options = options || {};
function pathtoRegexp(path, keys, options) {
options = options || {};
var sensitive = options.sensitive;
var strict = options.strict;
var end = options.end !== false;
keys = keys || [];
var flags = options.sensitive ? '' : 'i';
var index = 0;
if (path instanceof RegExp) return path;
if (path instanceof Array) path = '(' + path.join('|') + ')';
if (path instanceof RegExp) {
// Match all capturing groups of a regexp.
var groups = path.source.match(/\((?!\?)/g) || [];
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '/(?:')
.replace(/([\/\.])/g, '\\$1')
.replace(/(\\\/)?(\\\.)?:(\w+)(\(.*?\))?(\*)?(\?)?/g, function (match, slash, format, key, capture, star, optional) {
slash = slash || '';
format = format || '';
capture = capture || '([^/' + format + ']+?)';
optional = optional || '';
// Map all the matches to their numeric keys and push into the keys.
keys.push.apply(keys, groups.map(function (match, index) {
return {
name: index,
delimiter: null,
optional: false,
repeat: false
};
}));
keys.push({ name: key, optional: !!optional });
// Return the source back to the user.
return path;
}
return ''
+ (optional ? '' : slash)
+ '(?:'
+ format + (optional ? slash : '') + capture
+ (star ? '((?:[\\/' + format + '].+?)?)' : '')
+ ')'
+ optional;
})
.replace(/\*/g, '(.*)');
if (Array.isArray(path)) {
// Map array parts into regexps and return their source. We also pass
// the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together.
path = path.map(function (value) {
return pathtoRegexp(value, keys, options).source;
});
return new RegExp('^' + path + (end ? '$' : '(?=\/|$)'), sensitive ? '' : 'i');
// Generate a new regexp instance by joining all the parts together.
return new RegExp('(?:' + path.join('|') + ')', flags);
}
// Alter the path string into a usable regexp.
path = path.replace(PATH_REGEXP, function (match, escaped, prefix, key, capture, group, suffix, escape) {
// Avoiding re-escaping escaped characters.
if (escaped) {
return escaped;
}
// Escape regexp special characters.
if (escape) {
return '\\' + escape;
}
keys.push({
name: key || index++,
delimiter: prefix || '/',
optional: suffix === '?' || suffix === '*',
repeat: suffix === '+' || suffix === '*'
});
// Escape the prefix character.
prefix = prefix ? '\\' + prefix : '';
// Match using the custom capturing group, or fallback to capturing
// everything up to the next slash (or next period if the param was
// prefixed with a period).
capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');
// More complex regexp is required for suffix support.
if (suffix) {
if (suffix === '+') {
return prefix + '(' + capture + '(?:' + prefix + capture + ')*)'
}
if (suffix === '*') {
return '(?:' + prefix + '(' + capture + '(?:' + prefix + capture + ')*|' + capture + '))?';
}
return '(?:' + prefix + '(' + capture + '))?';
}
// Basic parameter support.
return prefix + '(' + capture + ')';
});
if (path[path.length - 1] !== '/') {
// If we are doing a non-ending match, we need to prompt the matching groups
// to match as much as possible. To do this, we add a positive lookahead for
// the next path fragment or the end. However, if the regexp already ends
// in a path fragment, we'll run into problems.
if (!end) {
path += '(?=\\/|$)';
}
// Allow trailing slashes to be matched in non-strict, ending mode.
if (end && !strict) {
path += '\\/?';
}
}
return new RegExp('^' + path + (end ? '$' : ''), flags);
};
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "0.1.2",
"version": "0.2.0",
"scripts": {
"test": "istanbul cover _mocha -- -R spec"
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec"
},
"keywords": [
"express",
"regexp"
"regexp",
"route",
"routing"
],

@@ -22,5 +24,5 @@ "component": {

"devDependencies": {
"mocha": "^1.17.1",
"istanbul": "^0.2.6"
"istanbul": "~0.2.6",
"mocha": "~1.18.2"
}
}

@@ -1,6 +0,8 @@

# Path-to-RegExp
Turn an Express-style path string such as `/user/:name` into a regular expression.
Turn an Express-style path string such as `/user/:name` into a regular expression.
[![Build Status](https://img.shields.io/travis/component/path-to-regexp/master.svg)](https://travis-ci.org/component/path-to-regexp)
[![NPM version](https://img.shields.io/npm/v/path-to-regexp.svg)](https://www.npmjs.org/package/path-to-regexp)
## Usage

@@ -10,19 +12,119 @@

var pathToRegexp = require('path-to-regexp');
// pathToRegexp(path, keys, options);
```
### pathToRegexp(path, keys, options)
- **path** A string in the express format, an array of such strings, or a regular expression
- **keys** An array to be populated with the keys present in the url. Once the function completes, this will be an array of strings.
- **options**
- **options.sensitive** Defaults to false, set this to true to make routes case sensitive
- **options.strict** Defaults to false, set this to true to make the trailing slash matter.
- **options.end** Defaults to true, set this to false to only match the prefix of the URL.
- **path** A string in the express format, an array of strings, or a regular expression.
- **keys** An array to be populated with the keys present in the url.
- **options**
- **options.sensitive** When set to `true` the route will be case sensitive.
- **options.strict** When set to `true` a slash is allowed to be trailing the path.
- **options.end** When set to `false` the path will match at the beginning.
```javascript
var keys = [];
var exp = pathToRegexp('/foo/:bar', keys);
//keys = ['bar']
//exp = /^\/foo\/(?:([^\/]+?))\/?$/i
var re = pathToRegexp('/foo/:bar', keys);
// re = /^\/foo\/([^\/]+?)\/?$/i
// keys = [{ name: 'bar', delimiter: '/', repeat: false, optional: false }]
```
### Parameters
The path has the ability to define parameters and automatically populate the keys array.
#### Named Parameters
Named parameters are defined by prefixing a colon to the parameter name (`:foo`). By default, this parameter will match up to the next path segment.
```js
var re = pathToRegexp('/:foo/:bar', keys);
// keys = [{ name: 'foo', ... }, { name: 'bar', ... }]
re.exec('/test/route');
//=> ['/test/route', 'test', 'route']
```
#### Suffixed Parameters
##### Optional
Parameters can be suffixed with a question mark (`?`) to make the entire parameter optional. This will also make any prefixed path delimiter optional (`/` or `.`).
```js
var re = pathToRegexp('/:foo/:bar?', keys);
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
re.exec('/test');
//=> ['/test', 'test', undefined]
re.exec('/test/route');
//=> ['/test', 'test', 'route']
```
##### Zero or more
Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter match. The prefixed path delimiter is also taken into account for the match.
```js
var re = pathToRegexp('/:foo*', keys);
// keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
re.exec('/');
//=> ['/', undefined]
re.exec('/bar/baz');
//=> ['/bar/baz', 'bar/baz']
```
##### One or more
Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameters match. The prefixed path delimiter is included in the match.
```js
var re = pathToRegexp('/:foo+', keys);
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
re.exec('/');
//=> null
re.exec('/bar/baz');
//=> ['/bar/baz', 'bar/baz']
```
#### Custom Match Parameters
All parameters can be provided a custom matching regexp and override the default. Please note: Backslashes need to be escaped in strings.
```js
var re = pathToRegexp('/:foo(\\d+)', keys);
// keys = [{ name: 'foo', ... }]
re.exec('/123');
//=> ['/123', '123']
re.exec('/abc');
//=> null
```
#### Unnamed Parameters
It is possible to write an unnamed parameter that is only a matching group. It works the same as a named parameter, except it will be numerically indexed.
```js
var re = pathToRegexp('/:foo/(.*)', keys);
// keys = [{ name: 'foo', ... }, { name: '0', ... }]
re.exec('/test/route');
//=> ['/test/route', 'test', 'route']
```
## Compatibility with Express 3.x
Path-To-RegExp breaks compatibility with Express 3.x in a few ways:
* RegExp special characters can now be used in the regular path. E.g. `/user[(\\d+)]`
* All RegExp special characters can now be used inside the custom match. E.g. `/:user(.*)`
* No more support for asterisk matching - use an explicit parameter instead. E.g. `/(.*)`
* Parameters can have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*`
## Live Demo

@@ -34,2 +136,2 @@

MIT
MIT

@@ -1,510 +0,810 @@

var pathToRegExp = require('./');
var util = require('util');
var assert = require('assert');
var pathToRegexp = require('./');
describe('path-to-regexp', function () {
describe('strings', function () {
it('should match simple paths', function () {
var params = [];
var m = pathToRegExp('/test', params).exec('/test');
/**
* Execute a regular expression and return a flat array for comparison.
*
* @param {RegExp} re
* @param {String} str
* @return {Array}
*/
var exec = function (re, str) {
var match = re.exec(str);
assert.equal(params.length, 0);
return match && Array.prototype.slice.call(match);
};
assert.equal(m.length, 1);
assert.equal(m[0], '/test');
});
/**
* An array of test cases with expected inputs and outputs. The format of each
* array item is:
*
* ["path", "expected params", "route", "expected output", "options"]
*
* @type {Array}
*/
var TESTS = [
/**
* Simple paths.
*/
['/', [], '/', ['/']],
['/test', [], '/test', ['/test']],
['/test', [], '/route', null],
['/test', [], '/test/route', null],
['/test', [], '/test/', ['/test/']],
['/test/', [], '/test/', ['/test/']],
['/test/', [], '/test//', null],
it('should match express format params', function () {
var params = [];
var m = pathToRegExp('/:test', params).exec('/pathname');
/**
* Case-sensitive paths.
*/
['/test', [], '/test', ['/test'], { sensitive: true }],
['/test', [], '/TEST', null, { sensitive: true }],
['/TEST', [], '/test', null, { sensitive: true }],
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
/**
* Strict mode.
*/
['/test', [], '/test', ['/test'], { strict: true }],
['/test', [], '/test/', null, { strict: true }],
['/test/', [], '/test', null, { strict: true }],
['/test/', [], '/test/', ['/test/'], { strict: true }],
['/test/', [], '/test//', null, { strict: true }],
assert.equal(m.length, 2);
assert.equal(m[0], '/pathname');
assert.equal(m[1], 'pathname');
});
/**
* Non-ending mode.
*/
['/test', [], '/test', ['/test'], { end: false }],
['/test', [], '/test/route', ['/test'], { end: false }],
it('should do strict matches', function () {
var params = [];
var re = pathToRegExp('/:test', params, { strict: true });
var m;
/**
* Combine modes.
*/
['/test', [], '/test', ['/test'], { end: false, strict: true }],
['/test', [], '/test/', ['/test'], { end: false, strict: true }],
['/test', [], '/test/route', ['/test'], { end: false, strict: true }],
['/test/', [], '/test', null, { end: false, strict: true }],
['/test/', [], '/test/', ['/test/'], { end: false, strict: true }],
['/test/', [], '/test//', ['/test/'], { end: false, strict: true }],
['/test/', [], '/test/route', ['/test/'], { end: false, strict: true }],
['/test.json', [], '/test.json', ['/test.json'], { end: false, strict: true }],
['/test.json', [], '/test.json.hbs', null, { end: false, strict: true }],
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
/**
* Arrays of simple paths.
*/
[['/one', '/two'], [], '/one', ['/one']],
[['/one', '/two'], [], '/two', ['/two']],
[['/one', '/two'], [], '/three', null],
[['/one', '/two'], [], '/one/two', null],
m = re.exec('/route');
/**
* Non-ending simple path.
*/
['/test', [], '/test/route', ['/test'], { end: false }],
assert.equal(m.length, 2);
assert.equal(m[0], '/route');
assert.equal(m[1], 'route');
/**
* Single named parameter.
*/
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route',
['/route', 'route']
],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/another',
['/another', 'another']
],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/something/else',
null
],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json',
['/route.json', 'route.json']
],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route',
['/route', 'route'],
{ strict: true }],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route/',
null,
{ strict: true }
],
[
'/:test/',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route/',
['/route/', 'route'],
{ strict: true }
],
[
'/:test/',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route//',
null,
{ strict: true }
],
[
'/:test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json',
['/route.json', 'route.json'],
{ end: false }
],
m = re.exec('/route/');
/**
* Optional named parameter.
*/
[
'/:test?',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/route',
['/route', 'route']
],
[
'/:test?',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/route/nested',
null
],
[
'/:test?',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/',
['/', undefined]
],
[
'/:test?',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/route',
['/route', 'route'],
{ strict: true }
],
[
'/:test?',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/',
null, // Questionable behaviour.
{ strict: true }
],
[
'/:test?/',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'/',
['/', undefined],
{ strict: true }
],
[
'/:test?/',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'//',
null
],
[
'/:test?/',
[{ name: 'test', delimiter: '/', optional: true, repeat: false }],
'//',
null,
{ strict: true }
],
assert.ok(!m);
});
// Repeated once or more times parameters.
[
'/:test+',
[{ name: 'test', delimiter: '/', optional: false, repeat: true }],
'/',
null
],
[
'/:test+',
[{ name: 'test', delimiter: '/', optional: false, repeat: true }],
'/route',
['/route', 'route']
],
[
'/:test+',
[{ name: 'test', delimiter: '/', optional: false, repeat: true }],
'/some/basic/route',
['/some/basic/route', 'some/basic/route']
],
[
'/:test(\\d+)+',
[{ name: 'test', delimiter: '/', optional: false, repeat: true }],
'/abc/456/789',
null
],
[
'/:test(\\d+)+',
[{ name: 'test', delimiter: '/', optional: false, repeat: true }],
'/123/456/789',
['/123/456/789', '123/456/789']
],
[
'/route.:ext(json|xml)+',
[{ name: 'ext', delimiter: '.', optional: false, repeat: true }],
'/route.json',
['/route.json', 'json']
],
[
'/route.:ext(json|xml)+',
[{ name: 'ext', delimiter: '.', optional: false, repeat: true }],
'/route.xml.json',
['/route.xml.json', 'xml.json']
],
[
'/route.:ext(json|xml)+',
[{ name: 'ext', delimiter: '.', optional: false, repeat: true }],
'/route.html',
null
],
it('should allow optional express format params', function () {
var params = [];
var re = pathToRegExp('/:test?', params);
var m;
/**
* Repeated zero or more times parameters.
*/
[
'/:test*',
[{ name: 'test', delimiter: '/', optional: true, repeat: true }],
'/',
['/', undefined]
],
[
'/:test*',
[{ name: 'test', delimiter: '/', optional: true, repeat: true }],
'//',
null
],
[
'/:test*',
[{ name: 'test', delimiter: '/', optional: true, repeat: true }],
'/route',
['/route', 'route']
],
[
'/:test*',
[{ name: 'test', delimiter: '/', optional: true, repeat: true }],
'/some/basic/route',
['/some/basic/route', 'some/basic/route']
],
[
'/route.:ext([a-z]+)*',
[{ name: 'ext', delimiter: '.', optional: true, repeat: true }],
'/route',
['/route', undefined]
],
[
'/route.:ext([a-z]+)*',
[{ name: 'ext', delimiter: '.', optional: true, repeat: true }],
'/route.json',
['/route.json', 'json']
],
[
'/route.:ext([a-z]+)*',
[{ name: 'ext', delimiter: '.', optional: true, repeat: true }],
'/route.xml.json',
['/route.xml.json', 'xml.json']
],
[
'/route.:ext([a-z]+)*',
[{ name: 'ext', delimiter: '.', optional: true, repeat: true }],
'/route.123',
null
],
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, true);
// Custom named parameters.
[
'/:test(\\d+)',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/123',
['/123', '123']
],
[
'/:test(\\d+)',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/abc',
null
],
[
'/:test(\\d+)',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/123/abc',
null
],
[
'/:test(\\d+)',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/123/abc',
['/123', '123'],
{ end: false }
],
[
'/:test(.*)',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/anything/goes/here',
['/anything/goes/here', 'anything/goes/here']
],
[
'/:route([a-z]+)',
[{ name: 'route', delimiter: '/', optional: false, repeat: false }],
'/abcde',
['/abcde', 'abcde']
],
[
'/:route([a-z]+)',
[{ name: 'route', delimiter: '/', optional: false, repeat: false }],
'/12345',
null
],
[
'/:route(this|that)',
[{ name: 'route', delimiter: '/', optional: false, repeat: false }],
'/this',
['/this', 'this']
],
[
'/:route(this|that)',
[{ name: 'route', delimiter: '/', optional: false, repeat: false }],
'/that',
['/that', 'that']
],
m = re.exec('/route');
/**
* Prefixed slashes could be omitted.
*/
[
'test',
[],
'test',
['test']
],
[
':test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'route',
['route', 'route']
],
[
':test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route',
null
],
[
':test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'route/',
['route/', 'route']
],
[
':test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'route/',
null,
{ strict: true }
],
[
':test',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'route/',
['route', 'route'],
{ end: false }
],
assert.equal(m.length, 2);
assert.equal(m[0], '/route');
assert.equal(m[1], 'route');
/**
* Formats.
*/
[
'/test.json',
[],
'/test.json',
['/test.json']
],
[
'/test.json',
[],
'/route.json',
null
],
[
'/:test.json',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json',
['/route.json', 'route']
],
[
'/:test.json',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json.json',
['/route.json.json', 'route.json']
],
[
'/:test.json',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json',
['/route.json', 'route'],
{ end: false }
],
[
'/:test.json',
[{ name: 'test', delimiter: '/', optional: false, repeat: false }],
'/route.json.json',
['/route.json.json', 'route.json'],
{ end: false }
],
m = re.exec('/');
/**
* Format params.
*/
[
'/test.:format',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.html',
['/test.html', 'html']
],
[
'/test.:format',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.hbs.html',
null
],
[
'/test.:format.:format',
[
{ name: 'format', delimiter: '.', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: false, repeat: false }
],
'/test.hbs.html',
['/test.hbs.html', 'hbs', 'html']
],
[
'/test.:format+',
[
{ name: 'format', delimiter: '.', optional: false, repeat: true }
],
'/test.hbs.html',
['/test.hbs.html', 'hbs.html']
],
[
'/test.:format',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.hbs.html',
null,
{ end: false }
],
[
'/test.:format.',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.hbs.html',
null,
{ end: false }
],
assert.equal(m.length, 2);
assert.equal(m[0], '/');
assert.equal(m[1], undefined);
});
/**
* Format and path params.
*/
[
'/:test.:format',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: false, repeat: false }
],
'/route.html',
['/route.html', 'route', 'html']
],
[
'/:test.:format',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: false, repeat: false }
],
'/route',
null
],
[
'/:test.:format',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: false, repeat: false }
],
'/route',
null
],
[
'/:test.:format?',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: true, repeat: false }
],
'/route',
['/route', 'route', undefined]
],
[
'/:test.:format?',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: true, repeat: false }
],
'/route.json',
['/route.json', 'route', 'json']
],
[
'/:test.:format?',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: true, repeat: false }
],
'/route',
['/route', 'route', undefined],
{ end: false }
],
[
'/:test.:format?',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: true, repeat: false }
],
'/route.json',
['/route.json', 'route', 'json'],
{ end: false }
],
[
'/:test.:format?',
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'format', delimiter: '.', optional: true, repeat: false }
],
'/route.json.html',
['/route.json.html', 'route.json', 'html'],
{ end: false }
],
[
'/test.:format(.*)z',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.abc',
null,
{ end: false }
],
[
'/test.:format(.*)z',
[{ name: 'format', delimiter: '.', optional: false, repeat: false }],
'/test.abcz',
['/test.abcz', 'abc'],
{ end: false }
],
it('should allow express format param regexps', function () {
var params = [];
var m = pathToRegExp('/:page(\\d+)', params).exec('/56');
/**
* Unnamed params.
*/
[
'/(\\d+)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/123',
['/123', '123']
],
[
'/(\\d+)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/abc',
null
],
[
'/(\\d+)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/123/abc',
null
],
[
'/(\\d+)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/123/abc',
['/123', '123'],
{ end: false }
],
[
'/(\\d+)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/abc',
null,
{ end: false }
],
[
'/(\\d+)?',
[{ name: '0', delimiter: '/', optional: true, repeat: false }],
'/',
['/', undefined]
],
[
'/(\\d+)?',
[{ name: '0', delimiter: '/', optional: true, repeat: false }],
'/123',
['/123', '123']
],
[
'/(.*)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/route',
['/route', 'route']
],
[
'/(.*)',
[{ name: '0', delimiter: '/', optional: false, repeat: false }],
'/route/nested',
['/route/nested', 'route/nested']
],
assert.equal(params.length, 1);
assert.equal(params[0].name, 'page');
assert.equal(params[0].optional, false);
/**
* Regexps.
*/
[
/.*/,
[],
'/match/anything',
['/match/anything']
],
[
/(.*)/,
[{ name: '0', delimiter: null, optional: false, repeat: false }],
'/match/anything',
['/match/anything', '/match/anything']
],
[
/\/(\d+)/,
[{ name: '0', delimiter: null, optional: false, repeat: false }],
'/123',
['/123', '123']
],
assert.equal(m.length, 2);
assert.equal(m[0], '/56');
assert.equal(m[1], '56');
});
/**
* Mixed arrays.
*/
[
['/test', /\/(\d+)/],
[{ name: '0', delimiter: null, optional: false, repeat: false }],
'/test',
['/test', undefined]
],
[
['/:test(\\d+)', /(.*)/],
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: '0', delimiter: null, optional: false, repeat: false }
],
'/123',
['/123', '123', undefined]
],
[
['/:test(\\d+)', /(.*)/],
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: '0', delimiter: null, optional: false, repeat: false }
],
'/abc',
['/abc', undefined, '/abc']
],
it('should match without a prefixed slash', function () {
var params = [];
var m = pathToRegExp(':test', params).exec('string');
/**
* Correct names and indexes.
*/
[
['/:test', '/route/:test'],
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'test', delimiter: '/', optional: false, repeat: false }
],
'/test',
['/test', 'test', undefined]
],
[
['/:test', '/route/:test'],
[
{ name: 'test', delimiter: '/', optional: false, repeat: false },
{ name: 'test', delimiter: '/', optional: false, repeat: false }
],
'/route/test',
['/route/test', undefined, 'test']
],
[
[/^\/([^\/]+)$/, /^\/route\/([^\/]+)$/],
[
{ name: '0', delimiter: null, optional: false, repeat: false },
{ name: '0', delimiter: null, optional: false, repeat: false }
],
'/test',
['/test', 'test', undefined]
],
[
[/^\/([^\/]+)$/, /^\/route\/([^\/]+)$/],
[
{ name: '0', delimiter: null, optional: false, repeat: false },
{ name: '0', delimiter: null, optional: false, repeat: false }
],
'/route/test',
['/route/test', undefined, 'test']
],
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
/**
* Ignore non-matching groups in regexps.
*/
[
/(?:.*)/,
[],
'/anything/you/want',
['/anything/you/want']
],
assert.equal(m.length, 2);
assert.equal(m[0], 'string');
assert.equal(m[1], 'string');
});
/**
* Respect escaped characters.
*/
[
'/\\(testing\\)',
[],
'/testing',
null
],
[
'/\\(testing\\)',
[],
'/(testing)',
['/(testing)']
],
[
'/.+*?=^!:${}[]|',
[],
'/.+*?=^!:${}[]|',
['/.+*?=^!:${}[]|']
]
];
it('should not match format parts', function () {
var params = [];
var m = pathToRegExp('/:test.json', params).exec('/route.json');
/**
* Dynamically generate the entire test suite.
*/
describe('path-to-regexp', function () {
it('should not break when keys aren\'t provided', function () {
var re = pathToRegexp('/:foo/:bar');
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.deepEqual(exec(re, '/test/route'), ['/test/route', 'test', 'route']);
});
assert.equal(m.length, 2);
assert.equal(m[0], '/route.json');
assert.equal(m[1], 'route');
});
TESTS.forEach(function (test) {
var description = '';
var options = test[4] || {};
it('should match format parts', function () {
var params = [];
var re = pathToRegExp('/:test.:format', params);
var m;
// Generate a base description using the test values.
description += 'should ' + (test[3] ? '' : 'not ') + 'match ';
description += util.inspect(test[2]) + ' against ' + util.inspect(test[0]);
assert.equal(params.length, 2);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params[1].name, 'format');
assert.equal(params[1].optional, false);
// If additional options have been defined, we should render the options
// in the test descriptions.
if (Object.keys(options).length) {
var optionsDescription = Object.keys(options).map(function (key) {
return (options[key] === false ? 'non-' : '') + key;
}).join(', ');
m = re.exec('/route.json');
description += ' in ' + optionsDescription + ' mode';
}
assert.equal(m.length, 3);
assert.equal(m[0], '/route.json');
assert.equal(m[1], 'route');
assert.equal(m[2], 'json');
m = re.exec('/route');
assert.ok(!m);
});
it('should match route parts with a trailing format', function () {
// Execute the test and check each parameter is as expected.
it(description, function () {
var params = [];
var m = pathToRegExp('/:test.json', params).exec('/route.json');
var re = pathToRegexp(test[0], params, test[4]);
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
// Check the params are as expected.
assert.deepEqual(params, test[1]);
assert.equal(m.length, 2);
assert.equal(m[0], '/route.json');
assert.equal(m[1], 'route');
// Run the regexp and check the result is expected.
assert.deepEqual(exec(re, test[2]), test[3]);
});
it('should match optional trailing routes', function () {
var params = [];
var m = pathToRegExp('/test*', params).exec('/test/route');
assert.equal(params.length, 0);
assert.equal(m.length, 2);
assert.equal(m[0], '/test/route');
assert.equal(m[1], '/route');
});
it('should match optional trailing routes after a param', function () {
var params = [];
var re = pathToRegExp('/:test*', params);
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/test/route');
assert.equal(m.length, 3);
assert.equal(m[0], '/test/route');
assert.equal(m[1], 'test');
assert.equal(m[2], '/route');
m = re.exec('/testing');
assert.equal(m.length, 3);
assert.equal(m[0], '/testing');
assert.equal(m[1], 'testing');
assert.equal(m[2], '');
});
it('should match optional trailing routes before a format', function () {
var params = [];
var re = pathToRegExp('/test*.json', params);
var m;
assert.equal(params.length, 0);
m = re.exec('/test.json');
assert.equal(m.length, 2);
assert.equal(m[0], '/test.json');
assert.equal(m[1], '');
m = re.exec('/testing.json');
assert.equal(m.length, 2);
assert.equal(m[0], '/testing.json');
assert.equal(m[1], 'ing');
m = re.exec('/test/route.json');
assert.equal(m.length, 2);
assert.equal(m[0], '/test/route.json');
assert.equal(m[1], '/route');
});
it('should match optional trailing routes after a param and before a format', function () {
var params = [];
var re = pathToRegExp('/:test*.json', params);
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/testing.json');
assert.equal(m.length, 3);
assert.equal(m[0], '/testing.json');
assert.equal(m[1], 'testing');
assert.equal(m[2], '');
m = re.exec('/test/route.json');
assert.equal(m.length, 3);
assert.equal(m[0], '/test/route.json');
assert.equal(m[1], 'test');
assert.equal(m[2], '/route');
m = re.exec('.json');
assert.ok(!m);
});
it('should match optional trailing routes between a normal param and a format param', function () {
var params = [];
var re = pathToRegExp('/:test*.:format', params);
var m;
assert.equal(params.length, 2);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params[1].name, 'format');
assert.equal(params[1].optional, false);
m = re.exec('/testing.json');
assert.equal(m.length, 4);
assert.equal(m[0], '/testing.json');
assert.equal(m[1], 'testing');
assert.equal(m[2], '');
assert.equal(m[3], 'json');
m = re.exec('/test/route.json');
assert.equal(m.length, 4);
assert.equal(m[0], '/test/route.json');
assert.equal(m[1], 'test');
assert.equal(m[2], '/route');
assert.equal(m[3], 'json');
m = re.exec('/test');
assert.ok(!m);
m = re.exec('.json');
assert.ok(!m);
});
it('should match optional trailing routes after a param and before an optional format param', function () {
var params = [];
var re = pathToRegExp('/:test*.:format?', params);
var m;
assert.equal(params.length, 2);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params[1].name, 'format');
assert.equal(params[1].optional, true);
m = re.exec('/testing.json');
assert.equal(m.length, 4);
assert.equal(m[0], '/testing.json');
assert.equal(m[1], 'testing');
assert.equal(m[2], '');
assert.equal(m[3], 'json');
m = re.exec('/test/route.json');
assert.equal(m.length, 4);
assert.equal(m[0], '/test/route.json');
assert.equal(m[1], 'test');
assert.equal(m[2], '/route');
assert.equal(m[3], 'json');
m = re.exec('/test');
assert.equal(m.length, 4);
assert.equal(m[0], '/test');
assert.equal(m[1], 'test');
assert.equal(m[2], '');
assert.equal(m[3], undefined);
m = re.exec('.json');
assert.ok(!m);
});
it('should match optional trailing routes inside optional express param', function () {
var params = [];
var re = pathToRegExp('/:test*?', params);
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, true);
m = re.exec('/test/route');
assert.equal(m.length, 3);
assert.equal(m[0], '/test/route');
assert.equal(m[1], 'test');
assert.equal(m[2], '/route');
m = re.exec('/test');
assert.equal(m.length, 3);
assert.equal(m[0], '/test');
assert.equal(m[1], 'test');
assert.equal(m[2], '');
m = re.exec('/');
assert.equal(m.length, 3);
assert.equal(m[0], '/');
assert.equal(m[1], undefined);
assert.equal(m[2], undefined);
});
it('should do case insensitive matches', function () {
var m = pathToRegExp('/test').exec('/TEST');
assert.equal(m[0], '/TEST');
});
it('should do case sensitive matches', function () {
var re = pathToRegExp('/test', null, { sensitive: true });
var m;
m = re.exec('/test');
assert.equal(m.length, 1);
assert.equal(m[0], '/test');
m = re.exec('/TEST');
assert.ok(!m);
});
it('should do non-ending matches', function () {
var params = [];
var m = pathToRegExp('/:test', params, { end: false }).exec('/test/route');
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(m.length, 2);
assert.equal(m[0], '/test');
assert.equal(m[1], 'test');
});
it('should match trailing slashes in non-ending non-strict mode', function () {
var params = [];
var re = pathToRegExp('/:test', params, { end: false });
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/test/');
assert.equal(m.length, 2);
assert.equal(m[0], '/test/');
assert.equal(m[1], 'test');
});
it('should not match trailing slashes in non-ending strict mode', function () {
var params = [];
var re = pathToRegExp('/:test', params, { end: false, strict: true });
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/test/');
assert.equal(m.length, 2);
assert.equal(m[0], '/test');
assert.equal(m[1], 'test');
});
it('should match text after an express param', function () {
var params = [];
var re = pathToRegExp('/(:test)route', params);
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/route');
assert.ok(!m);
m = re.exec('/testroute');
assert.equal(m.length, 2);
assert.equal(m[0], '/testroute');
assert.equal(m[1], 'test');
m = re.exec('testroute');
assert.ok(!m);
});
it('should match text after an optional express param', function () {
var params = [];
var re = pathToRegExp('/(:test?)route', params);
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, true);
m = re.exec('/route');
assert.equal(m.length, 2);
assert.equal(m[0], '/route');
assert.equal(m[1], undefined);
m = re.exec('/testroute');
assert.equal(m.length, 2);
assert.equal(m[0], '/testroute');
assert.equal(m[1], 'test');
m = re.exec('route');
assert.ok(!m);
});
it('should match optional formats', function () {
var params = [];
var re = pathToRegExp('/:test.:format?', params);
var m;
assert.equal(params.length, 2);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params[1].name, 'format');
assert.equal(params[1].optional, true);
m = re.exec('/route');
assert.equal(m.length, 3);
assert.equal(m[0], '/route');
assert.equal(m[1], 'route');
assert.equal(m[2], undefined);
m = re.exec('/route.json');
assert.equal(m.length, 3);
assert.equal(m[0], '/route.json');
assert.equal(m[1], 'route');
assert.equal(m[2], 'json');
});
it('should match full paths with format by default', function () {
var params = [];
var m = pathToRegExp('/:test', params).exec('/test.json');
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(m.length, 2);
assert.equal(m[0], '/test.json');
assert.equal(m[1], 'test.json');
});
});
describe('regexps', function () {
it('should return the regexp', function () {
assert.deepEqual(pathToRegExp(/.*/), /.*/);
});
});
describe('arrays', function () {
it('should join arrays parts', function () {
var re = pathToRegExp(['/test', '/route']);
assert.ok(re.exec('/test'));
assert.ok(re.exec('/route'));
assert.ok(!re.exec('/else'));
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc