You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			406 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			406 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", { value: true });
 | |
| /**
 | |
|  * Tokenize input string.
 | |
|  */
 | |
| function lexer(str) {
 | |
|     var tokens = [];
 | |
|     var i = 0;
 | |
|     while (i < str.length) {
 | |
|         var char = str[i];
 | |
|         if (char === "*" || char === "+" || char === "?") {
 | |
|             tokens.push({ type: "MODIFIER", index: i, value: str[i++] });
 | |
|             continue;
 | |
|         }
 | |
|         if (char === "\\") {
 | |
|             tokens.push({ type: "ESCAPED_CHAR", index: i++, value: str[i++] });
 | |
|             continue;
 | |
|         }
 | |
|         if (char === "{") {
 | |
|             tokens.push({ type: "OPEN", index: i, value: str[i++] });
 | |
|             continue;
 | |
|         }
 | |
|         if (char === "}") {
 | |
|             tokens.push({ type: "CLOSE", index: i, value: str[i++] });
 | |
|             continue;
 | |
|         }
 | |
|         if (char === ":") {
 | |
|             var name = "";
 | |
|             var j = i + 1;
 | |
|             while (j < str.length) {
 | |
|                 var code = str.charCodeAt(j);
 | |
|                 if (
 | |
|                 // `0-9`
 | |
|                 (code >= 48 && code <= 57) ||
 | |
|                     // `A-Z`
 | |
|                     (code >= 65 && code <= 90) ||
 | |
|                     // `a-z`
 | |
|                     (code >= 97 && code <= 122) ||
 | |
|                     // `_`
 | |
|                     code === 95) {
 | |
|                     name += str[j++];
 | |
|                     continue;
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|             if (!name)
 | |
|                 throw new TypeError("Missing parameter name at " + i);
 | |
|             tokens.push({ type: "NAME", index: i, value: name });
 | |
|             i = j;
 | |
|             continue;
 | |
|         }
 | |
|         if (char === "(") {
 | |
|             var count = 1;
 | |
|             var pattern = "";
 | |
|             var j = i + 1;
 | |
|             if (str[j] === "?") {
 | |
|                 throw new TypeError("Pattern cannot start with \"?\" at " + j);
 | |
|             }
 | |
|             while (j < str.length) {
 | |
|                 if (str[j] === "\\") {
 | |
|                     pattern += str[j++] + str[j++];
 | |
|                     continue;
 | |
|                 }
 | |
|                 if (str[j] === ")") {
 | |
|                     count--;
 | |
|                     if (count === 0) {
 | |
|                         j++;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|                 else if (str[j] === "(") {
 | |
|                     count++;
 | |
|                     if (str[j + 1] !== "?") {
 | |
|                         throw new TypeError("Capturing groups are not allowed at " + j);
 | |
|                     }
 | |
|                 }
 | |
|                 pattern += str[j++];
 | |
|             }
 | |
|             if (count)
 | |
|                 throw new TypeError("Unbalanced pattern at " + i);
 | |
|             if (!pattern)
 | |
|                 throw new TypeError("Missing pattern at " + i);
 | |
|             tokens.push({ type: "PATTERN", index: i, value: pattern });
 | |
|             i = j;
 | |
|             continue;
 | |
|         }
 | |
|         tokens.push({ type: "CHAR", index: i, value: str[i++] });
 | |
|     }
 | |
|     tokens.push({ type: "END", index: i, value: "" });
 | |
|     return tokens;
 | |
| }
 | |
| /**
 | |
|  * Parse a string for the raw tokens.
 | |
|  */
 | |
| function parse(str, options) {
 | |
|     if (options === void 0) { options = {}; }
 | |
|     var tokens = lexer(str);
 | |
|     var _a = options.prefixes, prefixes = _a === void 0 ? "./" : _a;
 | |
|     var defaultPattern = "[^" + escapeString(options.delimiter || "/#?") + "]+?";
 | |
|     var result = [];
 | |
|     var key = 0;
 | |
|     var i = 0;
 | |
|     var path = "";
 | |
|     var tryConsume = function (type) {
 | |
|         if (i < tokens.length && tokens[i].type === type)
 | |
|             return tokens[i++].value;
 | |
|     };
 | |
|     var mustConsume = function (type) {
 | |
|         var value = tryConsume(type);
 | |
|         if (value !== undefined)
 | |
|             return value;
 | |
|         var _a = tokens[i], nextType = _a.type, index = _a.index;
 | |
|         throw new TypeError("Unexpected " + nextType + " at " + index + ", expected " + type);
 | |
|     };
 | |
|     var consumeText = function () {
 | |
|         var result = "";
 | |
|         var value;
 | |
|         // tslint:disable-next-line
 | |
|         while ((value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR"))) {
 | |
|             result += value;
 | |
|         }
 | |
|         return result;
 | |
|     };
 | |
|     while (i < tokens.length) {
 | |
|         var char = tryConsume("CHAR");
 | |
|         var name = tryConsume("NAME");
 | |
|         var pattern = tryConsume("PATTERN");
 | |
|         if (name || pattern) {
 | |
|             var prefix = char || "";
 | |
|             if (prefixes.indexOf(prefix) === -1) {
 | |
|                 path += prefix;
 | |
|                 prefix = "";
 | |
|             }
 | |
|             if (path) {
 | |
|                 result.push(path);
 | |
|                 path = "";
 | |
|             }
 | |
|             result.push({
 | |
|                 name: name || key++,
 | |
|                 prefix: prefix,
 | |
|                 suffix: "",
 | |
|                 pattern: pattern || defaultPattern,
 | |
|                 modifier: tryConsume("MODIFIER") || ""
 | |
|             });
 | |
|             continue;
 | |
|         }
 | |
|         var value = char || tryConsume("ESCAPED_CHAR");
 | |
|         if (value) {
 | |
|             path += value;
 | |
|             continue;
 | |
|         }
 | |
|         if (path) {
 | |
|             result.push(path);
 | |
|             path = "";
 | |
|         }
 | |
|         var open = tryConsume("OPEN");
 | |
|         if (open) {
 | |
|             var prefix = consumeText();
 | |
|             var name_1 = tryConsume("NAME") || "";
 | |
|             var pattern_1 = tryConsume("PATTERN") || "";
 | |
|             var suffix = consumeText();
 | |
|             mustConsume("CLOSE");
 | |
|             result.push({
 | |
|                 name: name_1 || (pattern_1 ? key++ : ""),
 | |
|                 pattern: name_1 && !pattern_1 ? defaultPattern : pattern_1,
 | |
|                 prefix: prefix,
 | |
|                 suffix: suffix,
 | |
|                 modifier: tryConsume("MODIFIER") || ""
 | |
|             });
 | |
|             continue;
 | |
|         }
 | |
|         mustConsume("END");
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| exports.parse = parse;
 | |
| /**
 | |
|  * Compile a string to a template function for the path.
 | |
|  */
 | |
| function compile(str, options) {
 | |
|     return tokensToFunction(parse(str, options), options);
 | |
| }
 | |
| exports.compile = compile;
 | |
| /**
 | |
|  * Expose a method for transforming tokens into the path function.
 | |
|  */
 | |
| function tokensToFunction(tokens, options) {
 | |
|     if (options === void 0) { options = {}; }
 | |
|     var reFlags = flags(options);
 | |
|     var _a = options.encode, encode = _a === void 0 ? function (x) { return x; } : _a, _b = options.validate, validate = _b === void 0 ? true : _b;
 | |
|     // Compile all the tokens into regexps.
 | |
|     var matches = tokens.map(function (token) {
 | |
|         if (typeof token === "object") {
 | |
|             return new RegExp("^(?:" + token.pattern + ")$", reFlags);
 | |
|         }
 | |
|     });
 | |
|     return function (data) {
 | |
|         var path = "";
 | |
|         for (var i = 0; i < tokens.length; i++) {
 | |
|             var token = tokens[i];
 | |
|             if (typeof token === "string") {
 | |
|                 path += token;
 | |
|                 continue;
 | |
|             }
 | |
|             var value = data ? data[token.name] : undefined;
 | |
|             var optional = token.modifier === "?" || token.modifier === "*";
 | |
|             var repeat = token.modifier === "*" || token.modifier === "+";
 | |
|             if (Array.isArray(value)) {
 | |
|                 if (!repeat) {
 | |
|                     throw new TypeError("Expected \"" + token.name + "\" to not repeat, but got an array");
 | |
|                 }
 | |
|                 if (value.length === 0) {
 | |
|                     if (optional)
 | |
|                         continue;
 | |
|                     throw new TypeError("Expected \"" + token.name + "\" to not be empty");
 | |
|                 }
 | |
|                 for (var j = 0; j < value.length; j++) {
 | |
|                     var segment = encode(value[j], token);
 | |
|                     if (validate && !matches[i].test(segment)) {
 | |
|                         throw new TypeError("Expected all \"" + token.name + "\" to match \"" + token.pattern + "\", but got \"" + segment + "\"");
 | |
|                     }
 | |
|                     path += token.prefix + segment + token.suffix;
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             if (typeof value === "string" || typeof value === "number") {
 | |
|                 var segment = encode(String(value), token);
 | |
|                 if (validate && !matches[i].test(segment)) {
 | |
|                     throw new TypeError("Expected \"" + token.name + "\" to match \"" + token.pattern + "\", but got \"" + segment + "\"");
 | |
|                 }
 | |
|                 path += token.prefix + segment + token.suffix;
 | |
|                 continue;
 | |
|             }
 | |
|             if (optional)
 | |
|                 continue;
 | |
|             var typeOfMessage = repeat ? "an array" : "a string";
 | |
|             throw new TypeError("Expected \"" + token.name + "\" to be " + typeOfMessage);
 | |
|         }
 | |
|         return path;
 | |
|     };
 | |
| }
 | |
| exports.tokensToFunction = tokensToFunction;
 | |
| /**
 | |
|  * Create path match function from `path-to-regexp` spec.
 | |
|  */
 | |
| function match(str, options) {
 | |
|     var keys = [];
 | |
|     var re = pathToRegexp(str, keys, options);
 | |
|     return regexpToFunction(re, keys, options);
 | |
| }
 | |
| exports.match = match;
 | |
| /**
 | |
|  * Create a path match function from `path-to-regexp` output.
 | |
|  */
 | |
| function regexpToFunction(re, keys, options) {
 | |
|     if (options === void 0) { options = {}; }
 | |
|     var _a = options.decode, decode = _a === void 0 ? function (x) { return x; } : _a;
 | |
|     return function (pathname) {
 | |
|         var m = re.exec(pathname);
 | |
|         if (!m)
 | |
|             return false;
 | |
|         var path = m[0], index = m.index;
 | |
|         var params = Object.create(null);
 | |
|         var _loop_1 = function (i) {
 | |
|             // tslint:disable-next-line
 | |
|             if (m[i] === undefined)
 | |
|                 return "continue";
 | |
|             var key = keys[i - 1];
 | |
|             if (key.modifier === "*" || key.modifier === "+") {
 | |
|                 params[key.name] = m[i].split(key.prefix + key.suffix).map(function (value) {
 | |
|                     return decode(value, key);
 | |
|                 });
 | |
|             }
 | |
|             else {
 | |
|                 params[key.name] = decode(m[i], key);
 | |
|             }
 | |
|         };
 | |
|         for (var i = 1; i < m.length; i++) {
 | |
|             _loop_1(i);
 | |
|         }
 | |
|         return { path: path, index: index, params: params };
 | |
|     };
 | |
| }
 | |
| exports.regexpToFunction = regexpToFunction;
 | |
| /**
 | |
|  * Escape a regular expression string.
 | |
|  */
 | |
| function escapeString(str) {
 | |
|     return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
 | |
| }
 | |
| /**
 | |
|  * Get the flags for a regexp from the options.
 | |
|  */
 | |
| function flags(options) {
 | |
|     return options && options.sensitive ? "" : "i";
 | |
| }
 | |
| /**
 | |
|  * Pull out keys from a regexp.
 | |
|  */
 | |
| function regexpToRegexp(path, keys) {
 | |
|     if (!keys)
 | |
|         return path;
 | |
|     // 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,
 | |
|                 prefix: "",
 | |
|                 suffix: "",
 | |
|                 modifier: "",
 | |
|                 pattern: ""
 | |
|             });
 | |
|         }
 | |
|     }
 | |
|     return path;
 | |
| }
 | |
| /**
 | |
|  * Transform an array into a regexp.
 | |
|  */
 | |
| function arrayToRegexp(paths, keys, options) {
 | |
|     var parts = paths.map(function (path) { return pathToRegexp(path, keys, options).source; });
 | |
|     return new RegExp("(?:" + parts.join("|") + ")", flags(options));
 | |
| }
 | |
| /**
 | |
|  * Create a path regexp from string input.
 | |
|  */
 | |
| function stringToRegexp(path, keys, options) {
 | |
|     return tokensToRegexp(parse(path, options), keys, options);
 | |
| }
 | |
| /**
 | |
|  * Expose a function for taking tokens and returning a RegExp.
 | |
|  */
 | |
| function tokensToRegexp(tokens, keys, options) {
 | |
|     if (options === void 0) { options = {}; }
 | |
|     var _a = options.strict, strict = _a === void 0 ? false : _a, _b = options.start, start = _b === void 0 ? true : _b, _c = options.end, end = _c === void 0 ? true : _c, _d = options.encode, encode = _d === void 0 ? function (x) { return x; } : _d;
 | |
|     var endsWith = "[" + escapeString(options.endsWith || "") + "]|$";
 | |
|     var delimiter = "[" + escapeString(options.delimiter || "/#?") + "]";
 | |
|     var route = start ? "^" : "";
 | |
|     // Iterate over the tokens and create our regexp string.
 | |
|     for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
 | |
|         var token = tokens_1[_i];
 | |
|         if (typeof token === "string") {
 | |
|             route += escapeString(encode(token));
 | |
|         }
 | |
|         else {
 | |
|             var prefix = escapeString(encode(token.prefix));
 | |
|             var suffix = escapeString(encode(token.suffix));
 | |
|             if (token.pattern) {
 | |
|                 if (keys)
 | |
|                     keys.push(token);
 | |
|                 if (prefix || suffix) {
 | |
|                     if (token.modifier === "+" || token.modifier === "*") {
 | |
|                         var mod = token.modifier === "*" ? "?" : "";
 | |
|                         route += "(?:" + prefix + "((?:" + token.pattern + ")(?:" + suffix + prefix + "(?:" + token.pattern + "))*)" + suffix + ")" + mod;
 | |
|                     }
 | |
|                     else {
 | |
|                         route += "(?:" + prefix + "(" + token.pattern + ")" + suffix + ")" + token.modifier;
 | |
|                     }
 | |
|                 }
 | |
|                 else {
 | |
|                     route += "(" + token.pattern + ")" + token.modifier;
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 route += "(?:" + prefix + suffix + ")" + token.modifier;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (end) {
 | |
|         if (!strict)
 | |
|             route += delimiter + "?";
 | |
|         route += !options.endsWith ? "$" : "(?=" + endsWith + ")";
 | |
|     }
 | |
|     else {
 | |
|         var endToken = tokens[tokens.length - 1];
 | |
|         var isEndDelimited = typeof endToken === "string"
 | |
|             ? delimiter.indexOf(endToken[endToken.length - 1]) > -1
 | |
|             : // tslint:disable-next-line
 | |
|                 endToken === undefined;
 | |
|         if (!strict) {
 | |
|             route += "(?:" + delimiter + "(?=" + endsWith + "))?";
 | |
|         }
 | |
|         if (!isEndDelimited) {
 | |
|             route += "(?=" + delimiter + "|" + endsWith + ")";
 | |
|         }
 | |
|     }
 | |
|     return new RegExp(route, flags(options));
 | |
| }
 | |
| exports.tokensToRegexp = tokensToRegexp;
 | |
| /**
 | |
|  * 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 }]`.
 | |
|  */
 | |
| function pathToRegexp(path, keys, options) {
 | |
|     if (path instanceof RegExp)
 | |
|         return regexpToRegexp(path, keys);
 | |
|     if (Array.isArray(path))
 | |
|         return arrayToRegexp(path, keys, options);
 | |
|     return stringToRegexp(path, keys, options);
 | |
| }
 | |
| exports.pathToRegexp = pathToRegexp;
 | |
| //# sourceMappingURL=index.js.map
 |