pax_global_header00006660000000000000000000000064124000471020014500gustar00rootroot0000000000000052 comment=4c5412af6fae141f48c32e535bc931573ade99c4 path-to-regexp-1.0.1/000077500000000000000000000000001240004710200143435ustar00rootroot00000000000000path-to-regexp-1.0.1/.gitignore000066400000000000000000000000261240004710200163310ustar00rootroot00000000000000node_modules coverage path-to-regexp-1.0.1/.travis.yml000066400000000000000000000002151240004710200164520ustar00rootroot00000000000000language: node_js node_js: - "0.11" - "0.10" - "0.8" after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" path-to-regexp-1.0.1/History.md000066400000000000000000000027761240004710200163420ustar00rootroot000000000000001.0.1 / 2014-08-27 ================== * Ensure installation works correctly on 0.8 1.0.0 / 2014-08-17 ================== * No more API changes 0.2.5 / 2014-08-07 ================== * Allow keys parameter to be omitted 0.2.4 / 2014-08-02 ================== * Code coverage badge * Updated readme * Attach keys to the generated regexp 0.2.3 / 2014-07-09 ================== * Add MIT license 0.2.2 / 2014-07-06 ================== * A passed in trailing slash in non-strict mode will become optional * In non-end mode, the optional trailing slash will only match at the end 0.2.1 / 2014-06-11 ================== * Fixed a major capturing group regexp regression 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` 0.0.2 / 2013-02-10 ================== * Update to match current express * Add .license property to component.json path-to-regexp-1.0.1/LICENSE000066400000000000000000000021171240004710200153510ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. path-to-regexp-1.0.1/Readme.md000066400000000000000000000110111240004710200160540ustar00rootroot00000000000000# Path-to-RegExp Turn an Express-style path string such as `/user/:name` into a regular expression. [![NPM version][npm-image]][npm-url] [![Build status][travis-image]][travis-url] [![Test coverage][coveralls-image]][coveralls-url] ## Installation ``` npm install path-to-regexp --save ``` ## Usage ```javascript var pathToRegexp = require('path-to-regexp'); // pathToRegexp(path, keys, options); ``` - **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** - **sensitive** When `true` the route will be case sensitive. (default: `false`) - **strict** When `false` the trailing slash is optional. (default: `false`) - **end** When `false` the path will match at the beginning. (default: `true`) ```javascript var keys = []; 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 <= 4.x Path-To-RegExp breaks compatibility with Express <= 4.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*` * Strings aren't interpreted as literal regexp strings - no more non-capturing groups, lookaheads, lookbehinds or nested matching groups (but you can still pass a regexp manually) ## Live Demo You can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.com/express-route-tester/). ## License MIT [npm-image]: https://img.shields.io/npm/v/path-to-regexp.svg?style=flat [npm-url]: https://npmjs.org/package/path-to-regexp [travis-image]: https://img.shields.io/travis/component/path-to-regexp.svg?style=flat [travis-url]: https://travis-ci.org/component/path-to-regexp [coveralls-image]: https://img.shields.io/coveralls/component/path-to-regexp.svg?style=flat [coveralls-url]: https://coveralls.io/r/component/path-to-regexp?branch=master path-to-regexp-1.0.1/component.json000066400000000000000000000004071240004710200172410ustar00rootroot00000000000000{ "name": "path-to-regexp", "description": "DEPRECATED use https://github.com/pillarjs/path-to-regexp", "version": "1.0.1", "keywords": [ "express", "regexp", "route", "routing" ], "scripts": [ "index.js" ], "license": "MIT" } path-to-regexp-1.0.1/index.js000066400000000000000000000120431240004710200160100ustar00rootroot00000000000000/** * Expose `pathtoRegexp`. */ module.exports = pathtoRegexp; console.log("DEPRECATED use https://github.com/pillarjs/path-to-regexp"); /** * The main path matching regexp utility. * * @type {RegExp} */ 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'); /** * Escape the capturing group by escaping special characters and meaning. * * @param {String} group * @return {String} */ function escapeGroup (group) { return group.replace(/([=!:$\/()])/g, '\\$1'); } /** * Attach the keys as a property of the regexp. * * @param {RegExp} re * @param {Array} keys * @return {RegExp} */ var attachKeys = function (re, keys) { re.keys = keys; return re; }; /** * Normalize the given path string, returning a regular expression. * * 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} */ function pathtoRegexp (path, keys, options) { if (keys && !Array.isArray(keys)) { options = keys; keys = null; } keys = keys || []; options = options || {}; var strict = options.strict; var end = options.end !== false; var flags = options.sensitive ? '' : 'i'; var index = 0; if (path instanceof RegExp) { // Match all capturing groups of a regexp. var groups = path.source.match(/\((?!\?)/g) || []; // 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 }; })); // Return the source back to the user. return attachKeys(path, keys); } 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; }); // Generate a new regexp instance by joining all the parts together. return attachKeys(new RegExp('(?:' + path.join('|') + ')', flags), keys); } // 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; } var repeat = suffix === '+' || suffix === '*'; var optional = suffix === '?' || suffix === '*'; keys.push({ name: key || index++, delimiter: prefix || '/', optional: optional, repeat: repeat }); // 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 || '\\/') + ']+?'); // Allow parameters to be repeated more than once. if (repeat) { capture = capture + '(?:' + prefix + capture + ')*'; } // Allow a parameter to be optional. if (optional) { return '(?:' + prefix + '(' + capture + '))?'; } // Basic parameter support. return prefix + '(' + capture + ')'; }); // Check whether the path ends in a slash as it alters some match behaviour. var endsWithSlash = path[path.length - 1] === '/'; // In non-strict mode we allow an optional trailing slash in the match. If // the path to match already ended with a slash, we need to remove it for // consistency. The slash is only valid at the very end of a path match, not // anywhere in the middle. This is important for non-ending mode, otherwise // "/test/" will match "/test//route". if (!strict) { path = (endsWithSlash ? path.slice(0, -2) : path) + '(?:\\/(?=$))?'; } // In non-ending mode, we need prompt the capturing groups to match as much // as possible by using a positive lookahead for the end or next path segment. if (!end) { path += strict && endsWithSlash ? '' : '(?=\\/|$)'; } return attachKeys(new RegExp('^' + path + (end ? '$' : ''), flags), keys); }; path-to-regexp-1.0.1/package.json000066400000000000000000000010551240004710200166320ustar00rootroot00000000000000{ "name": "path-to-regexp", "description": "Express style path to RegExp utility", "version": "1.0.1", "scripts": { "test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec" }, "keywords": [ "express", "regexp", "route", "routing" ], "component": { "scripts": { "path-to-regexp": "index.js" } }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/component/path-to-regexp.git" }, "devDependencies": { "istanbul": "~0.3.0", "mocha": "~1.21.4" } } path-to-regexp-1.0.1/test.js000066400000000000000000000505561240004710200156730ustar00rootroot00000000000000var util = require('util'); var assert = require('assert'); var pathToRegexp = require('./'); /** * 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); return match && Array.prototype.slice.call(match); }; /** * 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/', ['/test/']], ['/test/', [], '/test//', null], /** * Case-sensitive paths. */ ['/test', [], '/test', ['/test'], { sensitive: true }], ['/test', [], '/TEST', null, { sensitive: true }], ['/TEST', [], '/test', null, { sensitive: true }], /** * 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 }], /** * Non-ending mode. */ ['/test', [], '/test', ['/test'], { end: false }], ['/test', [], '/test/', ['/test/'], { end: false }], ['/test', [], '/test/route', ['/test'], { end: false }], ['/test/', [], '/test/route', ['/test'], { end: false }], ['/test/', [], '/test//', ['/test'], { end: false }], ['/test/', [], '/test//route', ['/test'], { end: false }], [ '/:test', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route', ['/route', 'route'], { end: false } ], [ '/:test/', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route', ['/route', 'route'], { end: false } ], /** * 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 }], [ '/:test', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route', ['/route', 'route'], { end: false, strict: true } ], [ '/:test', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route/', ['/route', 'route'], { end: false, strict: true } ], [ '/:test/', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route/', ['/route/', 'route'], { end: false, strict: true } ], [ '/:test/', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], '/route', null, { end: false, strict: true } ], /** * Arrays of simple paths. */ [['/one', '/two'], [], '/one', ['/one']], [['/one', '/two'], [], '/two', ['/two']], [['/one', '/two'], [], '/three', null], [['/one', '/two'], [], '/one/two', null], /** * Non-ending simple path. */ ['/test', [], '/test/route', ['/test'], { end: false }], /** * 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 } ], /** * 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 } ], // 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 ], /** * 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 ], // 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'] ], /** * 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 } ], /** * 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 } ], /** * 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 } ], /** * 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 } ], /** * 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'] ], /** * 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'] ], /** * 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'] ], /** * 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'] ], /** * Ignore non-matching groups in regexps. */ [ /(?:.*)/, [], '/anything/you/want', ['/anything/you/want'] ], /** * Respect escaped characters. */ [ '/\\(testing\\)', [], '/testing', null ], [ '/\\(testing\\)', [], '/(testing)', ['/(testing)'] ], [ '/.+*?=^!:${}[]|', [], '/.+*?=^!:${}[]|', ['/.+*?=^!:${}[]|'] ], /** * Real world examples. */ [ '/:foo/:bar', [ { name: 'foo', delimiter: '/', optional: false, repeat: false }, { name: 'bar', delimiter: '/', optional: false, repeat: false } ], '/match/route', ['/match/route', 'match', 'route'] ], [ '/:remote([\\w-.]+)/:user([\\w-]+)', [ { name: 'remote', delimiter: '/', optional: false, repeat: false }, { name: 'user', delimiter: '/', optional: false, repeat: false } ], '/endpoint/user', ['/endpoint/user', 'endpoint', 'user'] ] ]; /** * Dynamically generate the entire test suite. */ describe('path-to-regexp', function () { describe('arguments', function () { it('should work without second keys', function () { var re = pathToRegexp('/user/:id', { end: false }); var params = [ { name: 'id', delimiter: '/', optional: false, repeat: false } ]; assert.deepEqual(re.keys, params); assert.deepEqual(exec(re, '/user/123/show'), ['/user/123', '123']); }); }); describe('rules', function () { TESTS.forEach(function (test) { var description = ''; var options = test[4] || {}; // Generate a base description using the test values. description += 'should ' + (test[3] ? '' : 'not ') + 'match '; description += util.inspect(test[2]) + ' against ' + util.inspect(test[0]); // 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(', '); description += ' in ' + optionsDescription + ' mode'; } // Execute the test and check each parameter is as expected. it(description, function () { var params = []; var re = pathToRegexp(test[0], params, test[4]); // Check the keys are as expected. assert.equal(re.keys, params); assert.deepEqual(params, test[1]); // Run the regexp and check the result is expected. assert.deepEqual(exec(re, test[2]), test[3]); }); }); }); });