| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 | var isArray = Array.isArray || function (arr) {  return Object.prototype.toString.call(arr) == '[object Array]';};/** * Expose `pathToRegexp`. */// module.exports = pathToRegexp/** * The main path matching regexp utility. * * @type {RegExp} */var PATH_REGEXP = new RegExp([  // Match escaped characters that would otherwise appear in future matches.  // This allows the user to escape special characters that won't transform.  '(\\\\.)',  // 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 are always 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} */function attachKeys (re, keys) {  re.keys = keys;  return re;}/** * Get the flags for a regexp from the options. * * @param  {Object} options * @return {String} */function flags (options) {  return options.sensitive ? '' : 'i';}/** * Pull out keys from a regexp. * * @param  {RegExp} path * @param  {Array}  keys * @return {RegExp} */function regexpToRegexp (path, keys) {  // Use a negative lookahead to match only capturing groups.  var groups = path.source.match(/\((?!\?)/g);  if (groups) {    for (var i = 0; i < groups.length; i++) {      keys.push({        name:      i,        delimiter: null,        optional:  false,        repeat:    false      });    }  }  return attachKeys(path, keys);}/** * Transform an array into a regexp. * * @param  {Array}  path * @param  {Array}  keys * @param  {Object} options * @return {RegExp} */function arrayToRegexp (path, keys, options) {  var parts = [];  for (var i = 0; i < path.length; i++) {    parts.push(pathToRegexp(path[i], keys, options).source);  }  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));  return attachKeys(regexp, keys);}/** * Replace the specific tags with regexp strings. * * @param  {String} path * @param  {Array}  keys * @return {String} */function replacePath (path, keys) {  var index = 0;  function replace (_, escaped, prefix, key, capture, group, suffix, escape) {    if (escaped) {      return escaped;    }    if (escape) {      return '\\' + escape;    }    var repeat   = suffix === '+' || suffix === '*';    var optional = suffix === '?' || suffix === '*';    keys.push({      name:      key || index++,      delimiter: prefix || '/',      optional:  optional,      repeat:    repeat    });    prefix = prefix ? ('\\' + prefix) : '';    capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');    if (repeat) {      capture = capture + '(?:' + prefix + capture + ')*';    }    if (optional) {      return '(?:' + prefix + '(' + capture + '))?';    }    // Basic parameter support.    return prefix + '(' + capture + ')';  }  return path.replace(PATH_REGEXP, replace);}/** * Normalize the given path string, returning a regular expression. * * An empty array can be passed in for the keys, which will hold the * placeholder key descriptions. For example, using `/user/:id`, `keys` will * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`. * * @param  {(String|RegExp|Array)} path * @param  {Array}                 [keys] * @param  {Object}                [options] * @return {RegExp} */function pathToRegexp (path, keys, options) {  keys = keys || [];  if (!isArray(keys)) {    options = keys;    keys = [];  } else if (!options) {    options = {};  }  if (path instanceof RegExp) {    return regexpToRegexp(path, keys, options);  }  if (isArray(path)) {    return arrayToRegexp(path, keys, options);  }  var strict = options.strict;  var end = options.end !== false;  var route = replacePath(path, keys);  var endsWithSlash = path.charAt(path.length - 1) === '/';  // In non-strict mode we allow a slash at the end of match. If the path to  // match already ends with a slash, we remove it for consistency. The slash  // is valid at the end of a path match, not in the middle. This is important  // in non-ending mode, where "/test/" shouldn't match "/test//route".  if (!strict) {    route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?';  }  if (end) {    route += '$';  } else {    // In non-ending mode, we need the capturing groups to match as much as    // possible by using a positive lookahead to the end or next path segment.    route += strict && endsWithSlash ? '' : '(?=\\/|$)';  }  return attachKeys(new RegExp('^' + route, flags(options)), keys);}
 |