Socket
Socket
Sign inDemoInstall

path-to-regexp

Package Overview
Dependencies
Maintainers
33
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

path-to-regexp - npm Package Compare versions

Comparing version 1.0.3 to 1.1.0

308

index.js

@@ -1,2 +0,2 @@

var isArray = require('isarray');
var isarray = require('isarray')

@@ -6,3 +6,5 @@ /**

*/
module.exports = pathToRegexp;
module.exports = pathToRegexp
module.exports.parse = parse
module.exports.compile = compile

@@ -23,8 +25,156 @@ /**

// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
'([\\/.])?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^)])*)\\))?|\\(((?:\\\\.|[^)])*)\\))([+*?])?',
// Match regexp special characters that are always escaped.
'([.+*?=^!:${}()[\\]|\\/])'
].join('|'), 'g');
'([\\/.])?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^)])*)\\))?|\\(((?:\\\\.|[^)])*)\\))([+*?])?'
].join('|'), 'g')
/**
* Parse a string for the raw tokens.
*
* @param {String} str
* @return {Array}
*/
function parse (str) {
var tokens = []
var key = 0
var index = 0
var path = ''
var res
while ((res = PATH_REGEXP.exec(str)) != null) {
var m = res[0]
var escaped = res[1]
var offset = res.index
path += str.slice(index, offset)
index = offset + m.length
// Ignore already escaped sequences.
if (escaped) {
path += escaped[1]
continue
}
// Push the current path onto the tokens.
if (path) {
tokens.push(path)
path = ''
}
var prefix = res[2]
var name = res[3]
var capture = res[4]
var group = res[5]
var suffix = res[6]
var repeat = suffix === '+' || suffix === '*'
var optional = suffix === '?' || suffix === '*'
var delimiter = prefix || '/'
tokens.push({
name: name || key++,
prefix: prefix || '',
delimiter: delimiter,
optional: optional,
repeat: repeat,
pattern: escapeGroup(capture || group || '[^' + delimiter + ']+?')
})
}
// Match any characters still remaining.
if (index < str.length) {
path += str.substr(index)
}
// If the path exists, push it onto the end.
if (path) {
tokens.push(path)
}
return tokens
}
/**
* Compile a string to a template function for the path.
*
* @param {String} str
* @return {Function}
*/
function compile (str) {
var keys = parse(str)
// Compile all the patterns before compilation.
for (var i = 0; i < keys.length; i++) {
if (typeof keys[i] === 'object') {
keys[i].regexp = new RegExp('^' + keys[i].pattern + '$')
}
}
return function (obj) {
var path = ''
obj = obj || {}
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
if (typeof key === 'string') {
path += key
continue
}
var value = obj[key.name]
if (value == null) {
if (key.optional) {
continue
} else {
throw new TypeError('Expected "' + key.name + '" to be defined')
}
}
if (isarray(value)) {
if (!key.repeat) {
throw new TypeError('Expected "' + key.name + '" to not repeat')
}
if (value.length === 0) {
if (key.optional) {
continue
} else {
throw new TypeError('Expected "' + key.name + '" to not be empty')
}
}
for (var j = 0; j < value.length; j++) {
if (!key.regexp.test(value[j])) {
throw new TypeError('Expected all "' + key.name + '" to match "' + key.pattern + '"')
}
path += (j === 0 ? key.prefix : key.delimiter) + encodeURIComponent(value[j])
}
continue
}
if (!key.regexp.test(value)) {
throw new TypeError('Expected "' + key.name + '" to match "' + key.pattern + '"')
}
path += key.prefix + encodeURIComponent(value)
}
return path
}
}
/**
* Escape a regular expression string.
*
* @param {String} str
* @return {String}
*/
function escapeString (str) {
return str.replace(/([.+*?=^!:${}()[\]|\/])/g, '\\$1')
}
/**
* Escape the capturing group by escaping special characters and meaning.

@@ -36,3 +186,3 @@ *

function escapeGroup (group) {
return group.replace(/([=!:$\/()])/g, '\\$1');
return group.replace(/([=!:$\/()])/g, '\\$1')
}

@@ -48,4 +198,4 @@

function attachKeys (re, keys) {
re.keys = keys;
return re;
re.keys = keys
return re
}

@@ -60,3 +210,3 @@

function flags (options) {
return options.sensitive ? '' : 'i';
return options.sensitive ? '' : 'i'
}

@@ -73,3 +223,3 @@

// Use a negative lookahead to match only capturing groups.
var groups = path.source.match(/\((?!\?)/g);
var groups = path.source.match(/\((?!\?)/g)

@@ -79,11 +229,13 @@ if (groups) {

keys.push({
name: i,
name: i,
prefix: null,
delimiter: null,
optional: false,
repeat: false
});
optional: false,
repeat: false,
pattern: null
})
}
}
return attachKeys(path, keys);
return attachKeys(path, keys)
}

@@ -100,57 +252,76 @@

function arrayToRegexp (path, keys, options) {
var parts = [];
var parts = []
for (var i = 0; i < path.length; i++) {
parts.push(pathToRegexp(path[i], keys, options).source);
parts.push(pathToRegexp(path[i], keys, options).source)
}
var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
return attachKeys(regexp, keys);
var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options))
return attachKeys(regexp, keys)
}
/**
* Replace the specific tags with regexp strings.
* Create a path regexp from string input.
*
* @param {String} path
* @param {Array} keys
* @return {String}
* @param {Object} options
* @return {RegExp}
*/
function replacePath (path, keys) {
var index = 0;
function stringToRegexp (path, keys, options) {
var strict = options.strict
var end = options.end !== false
var route = ''
var endsWithSlash = path.charAt(path.length - 1) === '/'
var tokens = parse(path)
function replace (_, escaped, prefix, key, capture, group, suffix, escape) {
if (escaped) {
return escaped;
}
// Iterate over the tokens and create our regexp string.
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i]
if (escape) {
return '\\' + escape;
}
if (typeof token === 'string') {
route += escapeString(token)
} else {
var prefix = escapeString(token.prefix)
var capture = token.pattern
var repeat = suffix === '+' || suffix === '*';
var optional = suffix === '?' || suffix === '*';
// Push non-string tokens into the keys array.
keys.push(token)
keys.push({
name: key || index++,
delimiter: prefix || '/',
optional: optional,
repeat: repeat
});
if (token.repeat) {
capture += '(?:' + prefix + capture + ')*'
}
prefix = prefix ? ('\\' + prefix) : '';
capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');
if (token.optional) {
if (prefix) {
capture = '(?:' + prefix + '(' + capture + '))?'
} else {
capture = '(' + capture + ')?'
}
} else {
capture = prefix + '(' + capture + ')'
}
if (repeat) {
capture = capture + '(?:' + prefix + capture + ')*';
route += capture
}
}
if (optional) {
return '(?:' + prefix + '(' + capture + '))?';
}
// In non-strict mode we allow a slash at the end of match. If the path to
// match already ends with a slash, we remove it for consistency. The slash
// is valid at the end of a path match, not in the middle. This is important
// in non-ending mode, where "/test/" shouldn't match "/test//route".
if (!strict) {
route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?'
}
// Basic parameter support.
return prefix + '(' + capture + ')';
if (end) {
route += '$'
} else {
// In non-ending mode, we need the capturing groups to match as much as
// possible by using a positive lookahead to the end or next path segment.
route += strict && endsWithSlash ? '' : '(?=\\/|$)'
}
return path.replace(PATH_REGEXP, replace);
return attachKeys(new RegExp('^' + route, flags(options)), keys)
}

@@ -171,41 +342,20 @@

function pathToRegexp (path, keys, options) {
keys = keys || [];
keys = keys || []
if (!isArray(keys)) {
options = keys;
keys = [];
if (!isarray(keys)) {
options = keys
keys = []
} else if (!options) {
options = {};
options = {}
}
if (path instanceof RegExp) {
return regexpToRegexp(path, keys, options);
return regexpToRegexp(path, keys, options)
}
if (isArray(path)) {
return arrayToRegexp(path, keys, options);
if (isarray(path)) {
return arrayToRegexp(path, keys, options)
}
var strict = options.strict;
var end = options.end !== false;
var route = replacePath(path, keys);
var endsWithSlash = path.charAt(path.length - 1) === '/';
// In non-strict mode we allow a slash at the end of match. If the path to
// match already ends with a slash, we remove it for consistency. The slash
// is valid at the end of a path match, not in the middle. This is important
// in non-ending mode, where "/test/" shouldn't match "/test//route".
if (!strict) {
route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?';
}
if (end) {
route += '$';
} else {
// In non-ending mode, we need the capturing groups to match as much as
// possible by using a positive lookahead to the end or next path segment.
route += strict && endsWithSlash ? '' : '(?=\\/|$)';
}
return attachKeys(new RegExp('^' + route, flags(options)), keys);
return stringToRegexp(path, keys, options)
}
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "1.0.3",
"version": "1.1.0",
"files": [

@@ -10,3 +10,6 @@ "index.js",

"scripts": {
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec"
"lint": "standard",
"test-spec": "mocha -R spec --bail",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec",
"test": "npm run lint && npm run test-cov"
},

@@ -30,4 +33,7 @@ "keywords": [

"devDependencies": {
"chai": "^2.3.0",
"istanbul": "~0.3.0",
"mocha": "~1.21.4"
"mocha": "~2.2.4",
"pre-commit": "~1.0.5",
"standard": "~3.7.3"
},

@@ -34,0 +40,0 @@ "dependencies": {

# 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.

@@ -21,5 +21,7 @@ [![NPM version][npm-image]][npm-url]

```javascript
var pathToRegexp = require('path-to-regexp');
var pathToRegexp = require('path-to-regexp')
// pathToRegexp(path, keys, options);
// pathToRegexp(path, keys, options)
// pathToRegexp.parse(path)
// pathToRegexp.compile(path)
```

@@ -35,6 +37,6 @@

```javascript
var keys = [];
var re = pathToRegexp('/foo/:bar', keys);
var keys = []
var re = pathToRegexp('/foo/:bar', keys)
// re = /^\/foo\/([^\/]+?)\/?$/i
// keys = [{ name: 'bar', delimiter: '/', repeat: false, optional: false }]
// keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }]
```

@@ -51,6 +53,6 @@

```js
var re = pathToRegexp('/:foo/:bar', keys);
var re = pathToRegexp('/:foo/:bar', keys)
// keys = [{ name: 'foo', ... }, { name: 'bar', ... }]
re.exec('/test/route');
re.exec('/test/route')
//=> ['/test/route', 'test', 'route']

@@ -66,9 +68,9 @@ ```

```js
var re = pathToRegexp('/:foo/:bar?', keys);
var re = pathToRegexp('/:foo/:bar?', keys)
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
re.exec('/test');
re.exec('/test')
//=> ['/test', 'test', undefined]
re.exec('/test/route');
re.exec('/test/route')
//=> ['/test', 'test', 'route']

@@ -82,9 +84,9 @@ ```

```js
var re = pathToRegexp('/:foo*', keys);
var re = pathToRegexp('/:foo*', keys)
// keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
re.exec('/');
re.exec('/')
//=> ['/', undefined]
re.exec('/bar/baz');
re.exec('/bar/baz')
//=> ['/bar/baz', 'bar/baz']

@@ -98,9 +100,9 @@ ```

```js
var re = pathToRegexp('/:foo+', keys);
var re = pathToRegexp('/:foo+', keys)
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
re.exec('/');
re.exec('/')
//=> null
re.exec('/bar/baz');
re.exec('/bar/baz')
//=> ['/bar/baz', 'bar/baz']

@@ -114,9 +116,9 @@ ```

```js
var re = pathToRegexp('/:foo(\\d+)', keys);
var re = pathToRegexp('/:foo(\\d+)', keys)
// keys = [{ name: 'foo', ... }]
re.exec('/123');
re.exec('/123')
//=> ['/123', '123']
re.exec('/abc');
re.exec('/abc')
//=> null

@@ -130,9 +132,43 @@ ```

```js
var re = pathToRegexp('/:foo/(.*)', keys);
var re = pathToRegexp('/:foo/(.*)', keys)
// keys = [{ name: 'foo', ... }, { name: '0', ... }]
re.exec('/test/route');
re.exec('/test/route')
//=> ['/test/route', 'test', 'route']
```
### Parse
The parse function is exposed via `pathToRegexp.parse`. This will yield an array of strings and keys.
```js
var tokens = pathToRegexp.parse('/route/:foo/(.*)')
console.log(tokens[0])
//=> "/route"
console.log(tokens[1])
//=> { name: 'foo', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }
console.log(tokens[2])
//=> { name: 0, prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '.*' }
```
**Note:** This method only works with strings.
### Compile ("Reverse" Path-To-RegExp)
Path-To-RegExp exposes a compile function for transforming an express path into valid path. Confusing enough? This example will straighten everything out for you.
```js
var toPath = pathToRegexp.compile('/user/:id')
var result = toPath({ id: 123 })
console.log(result)
//=> "/user/123"
```
**Note:** The generated function will throw on any invalid input. It will execute all necessary checks to ensure the generated path is valid. This method only works with strings.
## Compatibility with Express <= 4.x

@@ -142,3 +178,3 @@

* RegExp special characters can now be used in the regular path. E.g. `/user[(\\d+)]`
* 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(.*)`

@@ -145,0 +181,0 @@ * No more support for asterisk matching - use an explicit parameter instead. E.g. `/(.*)`

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc