"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, '__esModule', { value: true }); exports.pathToRegexp = exports.tokensToRegexp = exports.regexpToFunction = exports.match = exports.tokensToFunction = exports.compile = exports.parse = void 0; /** * 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) { // eslint-disable-next-line no-param-reassign 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 tryConsume(type) { if (i < tokens.length && tokens[i].type === type) return tokens[i++].value; }; var mustConsume = function mustConsume(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 consumeText() { 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) { // eslint-disable-next-line no-param-reassign 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) { // eslint-disable-next-line no-param-reassign 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 _loop_1(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) { // eslint-disable-next-line no-param-reassign 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;