path-to-regexp
Advanced tools
Comparing version 1.7.0 to 2.0.0
@@ -0,1 +1,6 @@ | ||
1.7.0 / 2016-11-08 | ||
================== | ||
* Allow a `delimiter` option to be passed in with `tokensToRegExp` which will be used for "non-ending" token match situations | ||
1.6.0 / 2016-10-03 | ||
@@ -2,0 +7,0 @@ ================== |
@@ -1,10 +0,4 @@ | ||
declare function pathToRegexp (path: pathToRegexp.Path, options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions): pathToRegexp.PathRegExp; | ||
declare function pathToRegexp (path: pathToRegexp.Path, keys?: pathToRegexp.Key[], options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions): pathToRegexp.PathRegExp; | ||
declare function pathToRegexp (path: pathToRegexp.Path, keys?: pathToRegexp.Key[], options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions): RegExp; | ||
declare namespace pathToRegexp { | ||
export interface PathRegExp extends RegExp { | ||
// An array to be populated with the keys found in the path. | ||
keys: Key[]; | ||
} | ||
export interface RegExpOptions { | ||
@@ -27,2 +21,6 @@ /** | ||
delimiter?: string; | ||
/** | ||
* List of characters that can also be "end" characters. | ||
*/ | ||
endsWith?: string | string[]; | ||
} | ||
@@ -35,2 +33,6 @@ | ||
delimiter?: string; | ||
/** | ||
* List of valid delimiter characters. (default: `'./'`) | ||
*/ | ||
delimiters?: string | string[]; | ||
} | ||
@@ -56,4 +58,3 @@ | ||
*/ | ||
export function tokensToRegExp (tokens: Token[], options?: RegExpOptions): PathRegExp; | ||
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): PathRegExp; | ||
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): RegExp; | ||
@@ -68,7 +69,9 @@ export interface Key { | ||
partial: boolean; | ||
asterisk: boolean; | ||
} | ||
interface PathFunctionOptions { | ||
pretty?: boolean; | ||
/** | ||
* Function for encoding input strings for output. | ||
*/ | ||
encode?: (value: string) => string; | ||
} | ||
@@ -75,0 +78,0 @@ |
222
index.js
@@ -1,3 +0,1 @@ | ||
var isarray = require('isarray') | ||
/** | ||
@@ -24,6 +22,5 @@ * Expose `pathToRegexp`. | ||
// | ||
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined] | ||
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined] | ||
// "/*" => ["/", undefined, undefined, undefined, undefined, "*"] | ||
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))' | ||
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"] | ||
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined] | ||
'(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?' | ||
].join('|'), 'g') | ||
@@ -43,6 +40,8 @@ | ||
var path = '' | ||
var defaultDelimiter = options && options.delimiter || '/' | ||
var defaultDelimiter = (options && options.delimiter) || '/' | ||
var delimiters = (options && options.delimiters) || './' | ||
var pathEscaped = false | ||
var res | ||
while ((res = PATH_REGEXP.exec(str)) != null) { | ||
while ((res = PATH_REGEXP.exec(str)) !== null) { | ||
var m = res[0] | ||
@@ -57,13 +56,22 @@ var escaped = res[1] | ||
path += escaped[1] | ||
pathEscaped = true | ||
continue | ||
} | ||
var prev = '' | ||
var next = str[index] | ||
var prefix = res[2] | ||
var name = res[3] | ||
var capture = res[4] | ||
var group = res[5] | ||
var modifier = res[6] | ||
var asterisk = res[7] | ||
var name = res[2] | ||
var capture = res[3] | ||
var group = res[4] | ||
var modifier = res[5] | ||
if (!pathEscaped && path.length) { | ||
var k = path.length - 1 | ||
if (delimiters.indexOf(path[k]) > -1) { | ||
prev = path[k] | ||
path = path.slice(0, k) | ||
} | ||
} | ||
// Push the current path onto the tokens. | ||
@@ -73,8 +81,9 @@ if (path) { | ||
path = '' | ||
pathEscaped = false | ||
} | ||
var partial = prefix != null && next != null && next !== prefix | ||
var partial = prev !== '' && next !== undefined && next !== prev | ||
var repeat = modifier === '+' || modifier === '*' | ||
var optional = modifier === '?' || modifier === '*' | ||
var delimiter = res[2] || defaultDelimiter | ||
var delimiter = prev || defaultDelimiter | ||
var pattern = capture || group | ||
@@ -84,3 +93,3 @@ | ||
name: name || key++, | ||
prefix: prefix || '', | ||
prefix: prev, | ||
delimiter: delimiter, | ||
@@ -90,17 +99,11 @@ optional: optional, | ||
partial: partial, | ||
asterisk: !!asterisk, | ||
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?') | ||
pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?' | ||
}) | ||
} | ||
// Match any characters still remaining. | ||
if (index < str.length) { | ||
path += str.substr(index) | ||
// Push any remaining characters. | ||
if (path || index < str.length) { | ||
tokens.push(path + str.substr(index)) | ||
} | ||
// If the path exists, push it onto the end. | ||
if (path) { | ||
tokens.push(path) | ||
} | ||
return tokens | ||
@@ -121,26 +124,2 @@ } | ||
/** | ||
* Prettier encoding of URI path segments. | ||
* | ||
* @param {string} | ||
* @return {string} | ||
*/ | ||
function encodeURIComponentPretty (str) { | ||
return encodeURI(str).replace(/[\/?#]/g, function (c) { | ||
return '%' + c.charCodeAt(0).toString(16).toUpperCase() | ||
}) | ||
} | ||
/** | ||
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes. | ||
* | ||
* @param {string} | ||
* @return {string} | ||
*/ | ||
function encodeAsterisk (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. | ||
@@ -159,7 +138,5 @@ */ | ||
return function (obj, opts) { | ||
return function (data, options) { | ||
var path = '' | ||
var data = obj || {} | ||
var options = opts || {} | ||
var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent | ||
var encode = (options && options.encode) || encodeURIComponent | ||
@@ -171,33 +148,17 @@ for (var i = 0; i < tokens.length; i++) { | ||
path += token | ||
continue | ||
} | ||
var value = data[token.name] | ||
var value = data ? data[token.name] : undefined | ||
var segment | ||
if (value == null) { | ||
if (token.optional) { | ||
// Prepend partial segment prefixes. | ||
if (token.partial) { | ||
path += token.prefix | ||
} | ||
continue | ||
} else { | ||
throw new TypeError('Expected "' + token.name + '" to be defined') | ||
} | ||
} | ||
if (isarray(value)) { | ||
if (Array.isArray(value)) { | ||
if (!token.repeat) { | ||
throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`') | ||
throw new TypeError('Expected "' + token.name + '" to not repeat, but got array') | ||
} | ||
if (value.length === 0) { | ||
if (token.optional) { | ||
continue | ||
} else { | ||
throw new TypeError('Expected "' + token.name + '" to not be empty') | ||
} | ||
if (token.optional) continue | ||
throw new TypeError('Expected "' + token.name + '" to not be empty') | ||
} | ||
@@ -209,3 +170,3 @@ | ||
if (!matches[i].test(segment)) { | ||
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`') | ||
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"') | ||
} | ||
@@ -219,9 +180,21 @@ | ||
segment = token.asterisk ? encodeAsterisk(value) : encode(value) | ||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { | ||
segment = encode(String(value)) | ||
if (!matches[i].test(segment)) { | ||
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"') | ||
if (!matches[i].test(segment)) { | ||
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"') | ||
} | ||
path += token.prefix + segment | ||
continue | ||
} | ||
path += token.prefix + segment | ||
if (token.optional) { | ||
// Prepend partial segment prefixes. | ||
if (token.partial) path += token.prefix | ||
continue | ||
} | ||
throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string')) | ||
} | ||
@@ -240,3 +213,3 @@ | ||
function escapeString (str) { | ||
return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1') | ||
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1') | ||
} | ||
@@ -251,18 +224,6 @@ | ||
function escapeGroup (group) { | ||
return group.replace(/([=!:$\/()])/g, '\\$1') | ||
return group.replace(/([=!:$/()])/g, '\\$1') | ||
} | ||
/** | ||
* Attach the keys as a property of the regexp. | ||
* | ||
* @param {!RegExp} re | ||
* @param {Array} keys | ||
* @return {!RegExp} | ||
*/ | ||
function attachKeys (re, keys) { | ||
re.keys = keys | ||
return re | ||
} | ||
/** | ||
* Get the flags for a regexp from the options. | ||
@@ -274,3 +235,3 @@ * | ||
function flags (options) { | ||
return options.sensitive ? '' : 'i' | ||
return options && options.sensitive ? '' : 'i' | ||
} | ||
@@ -282,6 +243,8 @@ | ||
* @param {!RegExp} path | ||
* @param {!Array} keys | ||
* @param {Array=} keys | ||
* @return {!RegExp} | ||
*/ | ||
function regexpToRegexp (path, keys) { | ||
if (!keys) return path | ||
// Use a negative lookahead to match only capturing groups. | ||
@@ -299,3 +262,2 @@ var groups = path.source.match(/\((?!\?)/g) | ||
partial: false, | ||
asterisk: false, | ||
pattern: null | ||
@@ -306,3 +268,3 @@ }) | ||
return attachKeys(path, keys) | ||
return path | ||
} | ||
@@ -314,4 +276,4 @@ | ||
* @param {!Array} path | ||
* @param {Array} keys | ||
* @param {!Object} options | ||
* @param {Array=} keys | ||
* @param {Object=} options | ||
* @return {!RegExp} | ||
@@ -326,5 +288,3 @@ */ | ||
var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options)) | ||
return attachKeys(regexp, keys) | ||
return new RegExp('(?:' + parts.join('|') + ')', flags(options)) | ||
} | ||
@@ -336,4 +296,4 @@ | ||
* @param {string} path | ||
* @param {!Array} keys | ||
* @param {!Object} options | ||
* @param {Array=} keys | ||
* @param {Object=} options | ||
* @return {!RegExp} | ||
@@ -348,13 +308,8 @@ */ | ||
* | ||
* @param {!Array} tokens | ||
* @param {(Array|Object)=} keys | ||
* @param {Object=} options | ||
* @param {!Array} tokens | ||
* @param {Array=} keys | ||
* @param {Object=} options | ||
* @return {!RegExp} | ||
*/ | ||
function tokensToRegExp (tokens, keys, options) { | ||
if (!isarray(keys)) { | ||
options = /** @type {!Object} */ (keys || options) | ||
keys = [] | ||
} | ||
options = options || {} | ||
@@ -364,2 +319,4 @@ | ||
var end = options.end !== false | ||
var delimiter = escapeString(options.delimiter || '/') | ||
var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|') | ||
var route = '' | ||
@@ -377,3 +334,3 @@ | ||
keys.push(token) | ||
if (keys) keys.push(token) | ||
@@ -398,22 +355,16 @@ if (token.repeat) { | ||
var delimiter = escapeString(options.delimiter || '/') | ||
var endsWithDelimiter = route.slice(-delimiter.length) === delimiter | ||
// 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". | ||
// In non-strict mode we allow a delimiter at the end of a match. | ||
if (!strict) { | ||
route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?' | ||
route += '(?:' + delimiter + '(?=' + endsWith + '))?' | ||
} | ||
if (end) { | ||
route += '$' | ||
route += endsWith === '$' ? endsWith : '(?=' + endsWith + ')' | ||
} 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 && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)' | ||
route += '(?=' + delimiter + '|' + endsWith + ')' | ||
} | ||
return attachKeys(new RegExp('^' + route, flags(options)), keys) | ||
return new RegExp('^' + route, flags(options)) | ||
} | ||
@@ -429,3 +380,3 @@ | ||
* @param {(string|RegExp|Array)} path | ||
* @param {(Array|Object)=} keys | ||
* @param {Array=} keys | ||
* @param {Object=} options | ||
@@ -435,18 +386,11 @@ * @return {!RegExp} | ||
function pathToRegexp (path, keys, options) { | ||
if (!isarray(keys)) { | ||
options = /** @type {!Object} */ (keys || options) | ||
keys = [] | ||
} | ||
options = options || {} | ||
if (path instanceof RegExp) { | ||
return regexpToRegexp(path, /** @type {!Array} */ (keys)) | ||
return regexpToRegexp(path, keys) | ||
} | ||
if (isarray(path)) { | ||
return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options) | ||
if (Array.isArray(path)) { | ||
return arrayToRegexp(/** @type {!Array} */ (path), keys, options) | ||
} | ||
return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options) | ||
return stringToRegexp(/** @type {string} */ (path), keys, options) | ||
} |
{ | ||
"name": "path-to-regexp", | ||
"description": "Express style path to RegExp utility", | ||
"version": "1.7.0", | ||
"version": "2.0.0", | ||
"main": "index.js", | ||
@@ -16,3 +16,2 @@ "typings": "index.d.ts", | ||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require ts-node/register -R spec test.ts", | ||
"prepublish": "typings install", | ||
"test": "npm run lint && npm run test-cov" | ||
@@ -37,13 +36,12 @@ }, | ||
"devDependencies": { | ||
"chai": "^2.3.0", | ||
"istanbul": "~0.3.0", | ||
"mocha": "~2.2.4", | ||
"standard": "~3.7.3", | ||
"ts-node": "^0.5.5", | ||
"typescript": "^1.8.7", | ||
"typings": "^1.0.4" | ||
}, | ||
"dependencies": { | ||
"isarray": "0.0.1" | ||
"@types/chai": "^4.0.4", | ||
"@types/mocha": "^2.2.42", | ||
"@types/node": "^8.0.24", | ||
"chai": "^4.1.1", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.5.0", | ||
"standard": "^10.0.3", | ||
"ts-node": "^3.3.0", | ||
"typescript": "^2.4.2" | ||
} | ||
} |
# Path-to-RegExp | ||
> Turn an Express-style path string such as `/user/:name` into a regular expression. | ||
> Turn a path string such as `/user/:name` into a regular expression. | ||
@@ -23,3 +23,3 @@ [![NPM version][npm-image]][npm-url] | ||
// pathToRegexp(path, keys, options) | ||
// pathToRegexp(path, keys?, options?) | ||
// pathToRegexp.parse(path) | ||
@@ -29,3 +29,3 @@ // pathToRegexp.compile(path) | ||
- **path** An Express-style string, an array of strings, or a regular expression. | ||
- **path** A string, array of strings, or a regular expression. | ||
- **keys** An array to be populated with the keys found in the path. | ||
@@ -36,3 +36,6 @@ - **options** | ||
- **end** When `false` the path will match at the beginning. (default: `true`) | ||
- **delimiter** Set the default delimiter for repeat parameters. (default: `'/'`) | ||
- Advanced options (use for non-pathname strings, e.g. host names): | ||
- **delimiter** The default delimiter for segments. (default: `'/'`) | ||
- **endsWith** Optional character, or list of characters, to treat as "end" characters. | ||
- **delimiters** List of characters to consider delimiters when parsing. (default: `'./'`) | ||
@@ -46,7 +49,7 @@ ```javascript | ||
**Please note:** The `RegExp` returned by `path-to-regexp` is intended for use with pathnames or hostnames. It can not handle the query strings or fragments of a URL. | ||
**Please note:** The `RegExp` returned by `path-to-regexp` is intended for ordered data (e.g. pathnames, hostnames). It does not handle arbitrary data (e.g. query strings, URL fragments, JSON, etc). | ||
### Parameters | ||
The path string can be used to define parameters and populate the keys. | ||
The path argument is used to define parameters and populate the list of keys. | ||
@@ -58,3 +61,3 @@ #### Named Parameters | ||
```js | ||
var re = pathToRegexp('/:foo/:bar', keys) | ||
var re = pathToRegexp('/:foo/:bar') | ||
// keys = [{ name: 'foo', prefix: '/', ... }, { name: 'bar', prefix: '/', ... }] | ||
@@ -69,3 +72,3 @@ | ||
```js | ||
var re = pathToRegexp('/(apple-)?icon-:res(\\d+).png', keys) | ||
var re = pathToRegexp('/(apple-)?icon-:res(\\d+).png') | ||
// keys = [{ name: 0, prefix: '/', ... }, { name: 'res', prefix: '', ... }] | ||
@@ -77,10 +80,10 @@ | ||
#### Modified Parameters | ||
#### Parameter Modifiers | ||
##### Optional | ||
Parameters can be suffixed with a question mark (`?`) to make the parameter optional. This will also make the prefix optional. | ||
Parameters can be suffixed with a question mark (`?`) to make the parameter optional. | ||
```js | ||
var re = pathToRegexp('/:foo/:bar?', keys) | ||
var re = pathToRegexp('/:foo/:bar?') | ||
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }] | ||
@@ -95,2 +98,4 @@ | ||
**Tip:** If the parameter is the _only_ value in the segment, the prefix is also optional. | ||
##### Zero or more | ||
@@ -101,3 +106,3 @@ | ||
```js | ||
var re = pathToRegexp('/:foo*', keys) | ||
var re = pathToRegexp('/:foo*') | ||
// keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }] | ||
@@ -117,3 +122,3 @@ | ||
```js | ||
var re = pathToRegexp('/:foo+', keys) | ||
var re = pathToRegexp('/:foo+') | ||
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }] | ||
@@ -133,3 +138,3 @@ | ||
```js | ||
var re = pathToRegexp('/:foo(\\d+)', keys) | ||
var re = pathToRegexp('/:foo(\\d+)') | ||
// keys = [{ name: 'foo', ... }] | ||
@@ -151,3 +156,3 @@ | ||
```js | ||
var re = pathToRegexp('/:foo/(.*)', keys) | ||
var re = pathToRegexp('/:foo/(.*)') | ||
// keys = [{ name: 'foo', ... }, { name: 0, ... }] | ||
@@ -159,14 +164,2 @@ | ||
#### Asterisk | ||
An asterisk can be used for matching everything. It is equivalent to an unnamed matching group of `(.*)`. | ||
```js | ||
var re = pathToRegexp('/foo/*', keys) | ||
// keys = [{ name: '0', ... }] | ||
re.exec('/foo/bar/baz') | ||
//=> ['/foo/bar/baz', 'bar/baz'] | ||
``` | ||
### Parse | ||
@@ -189,7 +182,7 @@ | ||
**Note:** This method only works with Express-style strings. | ||
**Note:** This method only works with strings. | ||
### Compile ("Reverse" Path-To-RegExp) | ||
Path-To-RegExp exposes a compile function for transforming an Express-style path into a valid path. | ||
Path-To-RegExp exposes a compile function for transforming a string into a valid path. | ||
@@ -203,4 +196,4 @@ ```js | ||
toPath({ id: ':' }) //=> "/user/%3A" | ||
toPath({ id: ':' }, { pretty: true }) //=> "/user/:" | ||
toPath({ id: ':/' }) //=> "/user/%3A%2F" | ||
toPath({ id: ':/' }, { encode: (x) => x }) //=> "/user/:/" | ||
@@ -237,3 +230,2 @@ var toPathRepeated = pathToRegexp.compile('/:segment+') | ||
* `pattern` The RegExp used to match this token (`string`) | ||
* `asterisk` Indicates the token is an `*` match (`boolean`) | ||
@@ -244,7 +236,6 @@ ## Compatibility with Express <= 4.x | ||
* No longer a direct conversion to a RegExp with sugar on top - it's a path matcher with named and unnamed matching groups | ||
* It's unlikely you previously abused this feature, it's rare and you could always use a RegExp instead | ||
* All matching RegExp special characters can be used in a matching group. E.g. `/:user(.*)` | ||
* Other RegExp features are not support - no nested matching groups, non-capturing groups or look aheads | ||
* RegExp special characters can only be used in a parameter | ||
* Express.js 4.x used all `RegExp` special characters regardless of position - this considered a bug | ||
* Parameters have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*` | ||
* No wildcard asterisk (`*`) - use parameters instead (`(.*)`) | ||
@@ -251,0 +242,0 @@ ## TypeScript |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
0
25584
9
382
249
- Removedisarray@0.0.1
- Removedisarray@0.0.1(transitive)