path-to-regexp
Advanced tools
| language: node_js | ||
| node_js: | ||
| - "0.11" | ||
| - "0.10" | ||
| - "0.8" |
+1
-1
| { | ||
| "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", |
+25
-2
@@ -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 |
+122
-37
| /** | ||
| * 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); | ||
| }; |
+7
-5
| { | ||
| "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" | ||
| } | ||
| } |
+115
-13
@@ -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. | ||
| [](https://travis-ci.org/component/path-to-regexp) | ||
| [](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 |
+772
-472
@@ -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')); | ||
| }); | ||
| }); | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
28902
67.81%8
14.29%912
108.22%136
312.12%1
Infinity%1
Infinity%