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
		
	
| 
											9 months ago
										 | "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
 |