Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tiny-request-router

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tiny-request-router - npm Package Compare versions

Comparing version 1.1.2 to 1.2.2

612

dist/router.browser.js

@@ -34,346 +34,279 @@ (function (global, factory) {

/**
* Expose `pathToRegexp`.
* Tokenize input string.
*/
var pathToRegexp_1 = pathToRegexp;
var parse_1 = parse;
var compile_1 = compile;
var tokensToFunction_1 = tokensToFunction;
var tokensToRegExp_1 = tokensToRegExp;
/**
* Default configs.
*/
var DEFAULT_DELIMITER = '/';
/**
* 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, "?"]
// "(\\d+)" => [undefined, undefined, "\d+", undefined]
'(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'
].join('|'), 'g');
/**
* Parse a string for the raw tokens.
*
* @param {string} str
* @param {Object=} options
* @return {!Array}
*/
function parse (str, options) {
var tokens = [];
var key = 0;
var index = 0;
var path = '';
var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER;
var whitelist = (options && options.whitelist) || undefined;
var pathEscaped = false;
var res;
while ((res = PATH_REGEXP.exec(str)) !== null) {
var m = res[0];
var escaped = res[1];
var offset = res.index;
path += str.slice(index, offset);
index = offset + m.length;
// Ignore already escaped sequences.
if (escaped) {
path += escaped[1];
pathEscaped = true;
continue
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++] });
}
var prev = '';
var name = res[2];
var capture = res[3];
var group = res[4];
var modifier = res[5];
if (!pathEscaped && path.length) {
var k = path.length - 1;
var c = path[k];
var matches = whitelist ? whitelist.indexOf(c) > -1 : true;
if (matches) {
prev = c;
path = path.slice(0, k);
}
}
// Push the current path onto the tokens.
if (path) {
tokens.push(path);
path = '';
pathEscaped = false;
}
var repeat = modifier === '+' || modifier === '*';
var optional = modifier === '?' || modifier === '*';
var pattern = capture || group;
var delimiter = prev || defaultDelimiter;
tokens.push({
name: name || key++,
prefix: prev,
delimiter: delimiter,
optional: optional,
repeat: repeat,
pattern: pattern
? escapeGroup(pattern)
: '[^' + escapeString(delimiter === defaultDelimiter ? delimiter : (delimiter + defaultDelimiter)) + ']+?'
});
}
// Push any remaining characters.
if (path || index < str.length) {
tokens.push(path + str.substr(index));
}
return tokens
tokens.push({ type: "END", index: i, value: "" });
return tokens;
}
/**
* Compile a string to a template function for the path.
*
* @param {string} str
* @param {Object=} options
* @return {!function(Object=, Object=)}
* Parse a string for the raw tokens.
*/
function compile (str, options) {
return tokensToFunction(parse(str, options), options)
}
/**
* Expose a method for transforming tokens into the path function.
*/
function tokensToFunction (tokens, options) {
// Compile all the tokens into regexps.
var matches = new Array(tokens.length);
// Compile all the patterns before compilation.
for (var i = 0; i < tokens.length; i++) {
if (typeof tokens[i] === 'object') {
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));
}
}
return function (data, options) {
var path = '';
var encode = (options && options.encode) || encodeURIComponent;
var validate = options ? options.validate !== false : true;
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 segment;
if (Array.isArray(value)) {
if (!token.repeat) {
throw new TypeError('Expected "' + token.name + '" to not repeat, but got array')
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;
}
if (value.length === 0) {
if (token.optional) continue
throw new TypeError('Expected "' + token.name + '" to not be empty')
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;
}
for (var j = 0; j < value.length; j++) {
segment = encode(value[j], token);
if (validate && !matches[i].test(segment)) {
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"')
}
path += (j === 0 ? token.prefix : token.delimiter) + segment;
var value = char || tryConsume("ESCAPED_CHAR");
if (value) {
path += value;
continue;
}
continue
}
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
segment = encode(String(value), token);
if (validate && !matches[i].test(segment)) {
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"')
if (path) {
result.push(path);
path = "";
}
path += token.prefix + segment;
continue
}
if (token.optional) continue
throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
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 path
}
return result;
}
/**
* Escape a regular expression string.
*
* @param {string} str
* @return {string}
*/
function escapeString (str) {
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
function escapeString(str) {
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
}
/**
* Escape the capturing group by escaping special characters and meaning.
*
* @param {string} group
* @return {string}
*/
function escapeGroup (group) {
return group.replace(/([=!:$/()])/g, '\\$1')
}
/**
* Get the flags for a regexp from the options.
*
* @param {Object} options
* @return {string}
*/
function flags (options) {
return options && options.sensitive ? '' : 'i'
function flags(options) {
return options && options.sensitive ? "" : "i";
}
/**
* Pull out keys from a regexp.
*
* @param {!RegExp} path
* @param {Array=} keys
* @return {!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: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
});
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
return path;
}
/**
* 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);
}
return new RegExp('(?:' + parts.join('|') + ')', flags(options))
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.
*
* @param {string} path
* @param {Array=} keys
* @param {Object=} options
* @return {!RegExp}
*/
function stringToRegexp (path, keys, options) {
return tokensToRegExp(parse(path, options), keys, options)
function stringToRegexp(path, keys, options) {
return tokensToRegexp(parse(path, options), keys, options);
}
/**
* Expose a function for taking tokens and returning a RegExp.
*
* @param {!Array} tokens
* @param {Array=} keys
* @param {Object=} options
* @return {!RegExp}
*/
function tokensToRegExp (tokens, keys, options) {
options = options || {};
var strict = options.strict;
var start = options.start !== false;
var end = options.end !== false;
var delimiter = options.delimiter || DEFAULT_DELIMITER;
var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|');
var route = start ? '^' : '';
// Iterate over the tokens and create our regexp string.
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (typeof token === 'string') {
route += escapeString(token);
} else {
var capture = token.repeat
? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
: token.pattern;
if (keys) keys.push(token);
if (token.optional) {
if (!token.prefix) {
route += '(' + capture + ')?';
} else {
route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?';
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 {
route += escapeString(token.prefix) + '(' + capture + ')';
}
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 += '(?:' + escapeString(delimiter) + ')?';
route += endsWith === '$' ? '$' : '(?=' + endsWith + ')';
} else {
var endToken = tokens[tokens.length - 1];
var isEndDelimited = typeof endToken === 'string'
? endToken[endToken.length - 1] === delimiter
: endToken === undefined;
if (!strict) route += '(?:' + escapeString(delimiter) + '(?=' + endsWith + '))?';
if (!isEndDelimited) route += '(?=' + escapeString(delimiter) + '|' + endsWith + ')';
}
return new RegExp(route, flags(options))
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));
}
/**

@@ -385,28 +318,28 @@ * Normalize the given path string, returning a regular expression.

* 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) {
if (path instanceof RegExp) {
return regexpToRegexp(path, keys)
}
if (Array.isArray(path)) {
return arrayToRegexp(/** @type {!Array} */ (path), keys, options)
}
return stringToRegexp(/** @type {string} */ (path), keys, options)
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);
}
pathToRegexp_1.parse = parse_1;
pathToRegexp_1.compile = compile_1;
pathToRegexp_1.tokensToFunction = tokensToFunction_1;
pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
/**
* Tiny request router. Allows overloading of handler type to be fully type safe.
*
* @example
* import { Router, Method, Params } from 'tiny-request-router'
*
* // Let the router know that handlers are async functions returning a Response
* type Handler = (params: Params) => Promise<Response>
*
* const router = new Router<Handler>()
*/
var Router = /** @class */ (function () {
function Router() {
/** List of all registered routes. */
this.routes = [];
}
/** Add a route that matches any method. */
Router.prototype.all = function (path, handler, options) {

@@ -416,2 +349,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the GET method. */
Router.prototype.get = function (path, handler, options) {

@@ -421,2 +355,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the POST method. */
Router.prototype.post = function (path, handler, options) {

@@ -426,2 +361,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the PUT method. */
Router.prototype.put = function (path, handler, options) {

@@ -431,2 +367,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the PATCH method. */
Router.prototype.patch = function (path, handler, options) {

@@ -436,2 +373,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the DELETE method. */
Router.prototype["delete"] = function (path, handler, options) {

@@ -441,2 +379,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the HEAD method. */
Router.prototype.head = function (path, handler, options) {

@@ -446,2 +385,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the OPTIONS method. */
Router.prototype.options = function (path, handler, options) {

@@ -451,2 +391,15 @@ if (options === void 0) { options = {}; }

};
/**
* Match the provided method and path against the list of registered routes.
*
* @example
* router.get('/foobar', async () => new Response('Hello'))
*
* const match = router.match('GET', '/foobar')
* if (match) {
* // Call the async function of that match
* const response = await match.handler()
* console.log(response) // => Response('Hello')
* }
*/
Router.prototype.match = function (method, path) {

@@ -459,3 +412,3 @@ for (var _i = 0, _a = this.routes; _i < _a.length; _i++) {

// Speed optimizations for catch all wildcard routes
if (route.path === '*' || route.path === '(.*)') {
if (route.path === '(.*)') {
return __assign(__assign({}, route), { params: { '0': route.path } });

@@ -476,3 +429,6 @@ }

var keys = [];
var regexp = pathToRegexp_1(path, keys, options);
if (path === '*') {
path = '(.*)';
}
var regexp = pathToRegexp(path, keys, options);
this.routes.push({ method: method, path: path, handler: handler, keys: keys, options: options, regexp: regexp });

@@ -498,3 +454,3 @@ return this;

exports.Router = Router;
exports.pathToRegexp = pathToRegexp_1;
exports.pathToRegexp = pathToRegexp;

@@ -501,0 +457,0 @@ Object.defineProperty(exports, '__esModule', { value: true });

/*!
* tiny-request-router v1.1.2 by berstend
* tiny-request-router v1.2.2 by berstend
* https://github.com/berstend/tiny-request-router#readme

@@ -37,346 +37,279 @@ * @license MIT

/**
* Expose `pathToRegexp`.
* Tokenize input string.
*/
var pathToRegexp_1 = pathToRegexp;
var parse_1 = parse;
var compile_1 = compile;
var tokensToFunction_1 = tokensToFunction;
var tokensToRegExp_1 = tokensToRegExp;
/**
* Default configs.
*/
var DEFAULT_DELIMITER = '/';
/**
* 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, "?"]
// "(\\d+)" => [undefined, undefined, "\d+", undefined]
'(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'
].join('|'), 'g');
/**
* Parse a string for the raw tokens.
*
* @param {string} str
* @param {Object=} options
* @return {!Array}
*/
function parse (str, options) {
var tokens = [];
var key = 0;
var index = 0;
var path = '';
var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER;
var whitelist = (options && options.whitelist) || undefined;
var pathEscaped = false;
var res;
while ((res = PATH_REGEXP.exec(str)) !== null) {
var m = res[0];
var escaped = res[1];
var offset = res.index;
path += str.slice(index, offset);
index = offset + m.length;
// Ignore already escaped sequences.
if (escaped) {
path += escaped[1];
pathEscaped = true;
continue
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++] });
}
var prev = '';
var name = res[2];
var capture = res[3];
var group = res[4];
var modifier = res[5];
if (!pathEscaped && path.length) {
var k = path.length - 1;
var c = path[k];
var matches = whitelist ? whitelist.indexOf(c) > -1 : true;
if (matches) {
prev = c;
path = path.slice(0, k);
}
}
// Push the current path onto the tokens.
if (path) {
tokens.push(path);
path = '';
pathEscaped = false;
}
var repeat = modifier === '+' || modifier === '*';
var optional = modifier === '?' || modifier === '*';
var pattern = capture || group;
var delimiter = prev || defaultDelimiter;
tokens.push({
name: name || key++,
prefix: prev,
delimiter: delimiter,
optional: optional,
repeat: repeat,
pattern: pattern
? escapeGroup(pattern)
: '[^' + escapeString(delimiter === defaultDelimiter ? delimiter : (delimiter + defaultDelimiter)) + ']+?'
});
}
// Push any remaining characters.
if (path || index < str.length) {
tokens.push(path + str.substr(index));
}
return tokens
tokens.push({ type: "END", index: i, value: "" });
return tokens;
}
/**
* Compile a string to a template function for the path.
*
* @param {string} str
* @param {Object=} options
* @return {!function(Object=, Object=)}
* Parse a string for the raw tokens.
*/
function compile (str, options) {
return tokensToFunction(parse(str, options), options)
}
/**
* Expose a method for transforming tokens into the path function.
*/
function tokensToFunction (tokens, options) {
// Compile all the tokens into regexps.
var matches = new Array(tokens.length);
// Compile all the patterns before compilation.
for (var i = 0; i < tokens.length; i++) {
if (typeof tokens[i] === 'object') {
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));
}
}
return function (data, options) {
var path = '';
var encode = (options && options.encode) || encodeURIComponent;
var validate = options ? options.validate !== false : true;
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 segment;
if (Array.isArray(value)) {
if (!token.repeat) {
throw new TypeError('Expected "' + token.name + '" to not repeat, but got array')
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;
}
if (value.length === 0) {
if (token.optional) continue
throw new TypeError('Expected "' + token.name + '" to not be empty')
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;
}
for (var j = 0; j < value.length; j++) {
segment = encode(value[j], token);
if (validate && !matches[i].test(segment)) {
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"')
}
path += (j === 0 ? token.prefix : token.delimiter) + segment;
var value = char || tryConsume("ESCAPED_CHAR");
if (value) {
path += value;
continue;
}
continue
}
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
segment = encode(String(value), token);
if (validate && !matches[i].test(segment)) {
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"')
if (path) {
result.push(path);
path = "";
}
path += token.prefix + segment;
continue
}
if (token.optional) continue
throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
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 path
}
return result;
}
/**
* Escape a regular expression string.
*
* @param {string} str
* @return {string}
*/
function escapeString (str) {
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
function escapeString(str) {
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
}
/**
* Escape the capturing group by escaping special characters and meaning.
*
* @param {string} group
* @return {string}
*/
function escapeGroup (group) {
return group.replace(/([=!:$/()])/g, '\\$1')
}
/**
* Get the flags for a regexp from the options.
*
* @param {Object} options
* @return {string}
*/
function flags (options) {
return options && options.sensitive ? '' : 'i'
function flags(options) {
return options && options.sensitive ? "" : "i";
}
/**
* Pull out keys from a regexp.
*
* @param {!RegExp} path
* @param {Array=} keys
* @return {!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: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
});
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
return path;
}
/**
* 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);
}
return new RegExp('(?:' + parts.join('|') + ')', flags(options))
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.
*
* @param {string} path
* @param {Array=} keys
* @param {Object=} options
* @return {!RegExp}
*/
function stringToRegexp (path, keys, options) {
return tokensToRegExp(parse(path, options), keys, options)
function stringToRegexp(path, keys, options) {
return tokensToRegexp(parse(path, options), keys, options);
}
/**
* Expose a function for taking tokens and returning a RegExp.
*
* @param {!Array} tokens
* @param {Array=} keys
* @param {Object=} options
* @return {!RegExp}
*/
function tokensToRegExp (tokens, keys, options) {
options = options || {};
var strict = options.strict;
var start = options.start !== false;
var end = options.end !== false;
var delimiter = options.delimiter || DEFAULT_DELIMITER;
var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|');
var route = start ? '^' : '';
// Iterate over the tokens and create our regexp string.
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (typeof token === 'string') {
route += escapeString(token);
} else {
var capture = token.repeat
? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
: token.pattern;
if (keys) keys.push(token);
if (token.optional) {
if (!token.prefix) {
route += '(' + capture + ')?';
} else {
route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?';
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 {
route += escapeString(token.prefix) + '(' + capture + ')';
}
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 += '(?:' + escapeString(delimiter) + ')?';
route += endsWith === '$' ? '$' : '(?=' + endsWith + ')';
} else {
var endToken = tokens[tokens.length - 1];
var isEndDelimited = typeof endToken === 'string'
? endToken[endToken.length - 1] === delimiter
: endToken === undefined;
if (!strict) route += '(?:' + escapeString(delimiter) + '(?=' + endsWith + '))?';
if (!isEndDelimited) route += '(?=' + escapeString(delimiter) + '|' + endsWith + ')';
}
return new RegExp(route, flags(options))
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));
}
/**

@@ -388,28 +321,28 @@ * Normalize the given path string, returning a regular expression.

* 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) {
if (path instanceof RegExp) {
return regexpToRegexp(path, keys)
}
if (Array.isArray(path)) {
return arrayToRegexp(/** @type {!Array} */ (path), keys, options)
}
return stringToRegexp(/** @type {string} */ (path), keys, options)
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);
}
pathToRegexp_1.parse = parse_1;
pathToRegexp_1.compile = compile_1;
pathToRegexp_1.tokensToFunction = tokensToFunction_1;
pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
/**
* Tiny request router. Allows overloading of handler type to be fully type safe.
*
* @example
* import { Router, Method, Params } from 'tiny-request-router'
*
* // Let the router know that handlers are async functions returning a Response
* type Handler = (params: Params) => Promise<Response>
*
* const router = new Router<Handler>()
*/
var Router = /** @class */ (function () {
function Router() {
/** List of all registered routes. */
this.routes = [];
}
/** Add a route that matches any method. */
Router.prototype.all = function (path, handler, options) {

@@ -419,2 +352,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the GET method. */
Router.prototype.get = function (path, handler, options) {

@@ -424,2 +358,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the POST method. */
Router.prototype.post = function (path, handler, options) {

@@ -429,2 +364,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the PUT method. */
Router.prototype.put = function (path, handler, options) {

@@ -434,2 +370,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the PATCH method. */
Router.prototype.patch = function (path, handler, options) {

@@ -439,2 +376,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the DELETE method. */
Router.prototype["delete"] = function (path, handler, options) {

@@ -444,2 +382,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the HEAD method. */
Router.prototype.head = function (path, handler, options) {

@@ -449,2 +388,3 @@ if (options === void 0) { options = {}; }

};
/** Add a route that matches the OPTIONS method. */
Router.prototype.options = function (path, handler, options) {

@@ -454,2 +394,15 @@ if (options === void 0) { options = {}; }

};
/**
* Match the provided method and path against the list of registered routes.
*
* @example
* router.get('/foobar', async () => new Response('Hello'))
*
* const match = router.match('GET', '/foobar')
* if (match) {
* // Call the async function of that match
* const response = await match.handler()
* console.log(response) // => Response('Hello')
* }
*/
Router.prototype.match = function (method, path) {

@@ -462,3 +415,3 @@ for (var _i = 0, _a = this.routes; _i < _a.length; _i++) {

// Speed optimizations for catch all wildcard routes
if (route.path === '*' || route.path === '(.*)') {
if (route.path === '(.*)') {
return __assign(__assign({}, route), { params: { '0': route.path } });

@@ -479,3 +432,6 @@ }

var keys = [];
var regexp = pathToRegexp_1(path, keys, options);
if (path === '*') {
path = '(.*)';
}
var regexp = pathToRegexp(path, keys, options);
this.routes.push({ method: method, path: path, handler: handler, keys: keys, options: options, regexp: regexp });

@@ -501,3 +457,3 @@ return this;

exports.Router = Router;
exports.pathToRegexp = pathToRegexp_1;
exports.pathToRegexp = pathToRegexp;
//# sourceMappingURL=router.js.map
/*!
* tiny-request-router v1.1.2 by berstend
* tiny-request-router v1.2.2 by berstend
* https://github.com/berstend/tiny-request-router#readme

@@ -20,3 +20,3 @@ * @license MIT

and limitations under the License.
***************************************************************************** */var t=function(){return(t=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var o in t=arguments[r])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e}).apply(this,arguments)},r=v,n=f,o=function(e,t){return s(f(e,t),t)},i=s,p=d,a="/",u=new RegExp(["(\\\\.)","(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?"].join("|"),"g");function f(e,t){for(var r,n=[],o=0,i=0,p="",f=t&&t.delimiter||a,s=t&&t.whitelist||void 0,l=!1;null!==(r=u.exec(e));){var d=r[0],v=r[1],g=r.index;if(p+=e.slice(i,g),i=g+d.length,v)p+=v[1],l=!0;else{var y="",m=r[2],x=r[3],E=r[4],w=r[5];if(!l&&p.length){var T=p.length-1,b=p[T];(!s||s.indexOf(b)>-1)&&(y=b,p=p.slice(0,T))}p&&(n.push(p),p="",l=!1);var R="+"===w||"*"===w,_="?"===w||"*"===w,A=x||E,j=y||f;n.push({name:m||o++,prefix:y,delimiter:j,optional:_,repeat:R,pattern:A?c(A):"[^"+h(j===f?j:j+f)+"]+?"})}}return(p||i<e.length)&&n.push(p+e.substr(i)),n}function s(e,t){for(var r=new Array(e.length),n=0;n<e.length;n++)"object"==typeof e[n]&&(r[n]=new RegExp("^(?:"+e[n].pattern+")$",l(t)));return function(t,n){for(var o="",i=n&&n.encode||encodeURIComponent,p=!n||!1!==n.validate,a=0;a<e.length;a++){var u=e[a];if("string"!=typeof u){var f,s=t?t[u.name]:void 0;if(Array.isArray(s)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but got array');if(0===s.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var h=0;h<s.length;h++){if(f=i(s[h],u),p&&!r[a].test(f))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'"');o+=(0===h?u.prefix:u.delimiter)+f}}else if("string"!=typeof s&&"number"!=typeof s&&"boolean"!=typeof s){if(!u.optional)throw new TypeError('Expected "'+u.name+'" to be '+(u.repeat?"an array":"a string"))}else{if(f=i(String(s),u),p&&!r[a].test(f))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but got "'+f+'"');o+=u.prefix+f}}else o+=u}return o}}function h(e){return e.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$/()])/g,"\\$1")}function l(e){return e&&e.sensitive?"":"i"}function d(e,t,r){for(var n=(r=r||{}).strict,o=!1!==r.start,i=!1!==r.end,p=r.delimiter||a,u=[].concat(r.endsWith||[]).map(h).concat("$").join("|"),f=o?"^":"",s=0;s<e.length;s++){var c=e[s];if("string"==typeof c)f+=h(c);else{var d=c.repeat?"(?:"+c.pattern+")(?:"+h(c.delimiter)+"(?:"+c.pattern+"))*":c.pattern;t&&t.push(c),c.optional?c.prefix?f+="(?:"+h(c.prefix)+"("+d+"))?":f+="("+d+")?":f+=h(c.prefix)+"("+d+")"}}if(i)n||(f+="(?:"+h(p)+")?"),f+="$"===u?"$":"(?="+u+")";else{var v=e[e.length-1],g="string"==typeof v?v[v.length-1]===p:void 0===v;n||(f+="(?:"+h(p)+"(?="+u+"))?"),g||(f+="(?="+h(p)+"|"+u+")")}return new RegExp(f,l(r))}function v(e,t,r){return e instanceof RegExp?function(e,t){if(!t)return e;var r=e.source.match(/\((?!\?)/g);if(r)for(var n=0;n<r.length;n++)t.push({name:n,prefix:null,delimiter:null,optional:!1,repeat:!1,pattern:null});return e}(e,t):Array.isArray(e)?function(e,t,r){for(var n=[],o=0;o<e.length;o++)n.push(v(e[o],t,r).source);return new RegExp("(?:"+n.join("|")+")",l(r))}(e,t,r):function(e,t,r){return d(f(e,r),t,r)}(e,t,r)}r.parse=n,r.compile=o,r.tokensToFunction=i,r.tokensToRegExp=p;var g=function(){function e(){this.routes=[]}return e.prototype.all=function(e,t,r){return void 0===r&&(r={}),this._push("ALL",e,t,r)},e.prototype.get=function(e,t,r){return void 0===r&&(r={}),this._push("GET",e,t,r)},e.prototype.post=function(e,t,r){return void 0===r&&(r={}),this._push("POST",e,t,r)},e.prototype.put=function(e,t,r){return void 0===r&&(r={}),this._push("PUT",e,t,r)},e.prototype.patch=function(e,t,r){return void 0===r&&(r={}),this._push("PATCH",e,t,r)},e.prototype.delete=function(e,t,r){return void 0===r&&(r={}),this._push("DELETE",e,t,r)},e.prototype.head=function(e,t,r){return void 0===r&&(r={}),this._push("HEAD",e,t,r)},e.prototype.options=function(e,t,r){return void 0===r&&(r={}),this._push("OPTIONS",e,t,r)},e.prototype.match=function(e,r){for(var n=0,o=this.routes;n<o.length;n++){var i=o[n];if(i.method===e||"ALL"===i.method){if("*"===i.path||"(.*)"===i.path)return t(t({},i),{params:{0:i.path}});if("/"===i.path&&!1===i.options.end)return t(t({},i),{params:{}});var p=i.regexp.exec(r);if(p&&p.length)return t(t({},i),{matches:p,params:y(p,i.keys)})}}return null},e.prototype._push=function(e,t,n,o){var i=[],p=r(t,i,o);return this.routes.push({method:e,path:t,handler:n,keys:i,options:o,regexp:p}),this},e}(),y=function(e,t){for(var r={},n=1;n<e.length;n++){var o=t[n-1].name,i=e[n];void 0!==i&&(r[o]=i)}return r};e.Router=g,e.pathToRegexp=r,Object.defineProperty(e,"__esModule",{value:!0})}));
***************************************************************************** */var t=function(){return(t=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var i in t=arguments[r])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};function r(e,t){void 0===t&&(t={});for(var r=function(e){for(var t=[],r=0;r<e.length;){var n=e[r];if("*"!==n&&"+"!==n&&"?"!==n)if("\\"!==n)if("{"!==n)if("}"!==n)if(":"!==n)if("("!==n)t.push({type:"CHAR",index:r,value:e[r++]});else{var i=1,o="";if("?"===e[p=r+1])throw new TypeError('Pattern cannot start with "?" at '+p);for(;p<e.length;)if("\\"!==e[p]){if(")"===e[p]){if(0===--i){p++;break}}else if("("===e[p]&&(i++,"?"!==e[p+1]))throw new TypeError("Capturing groups are not allowed at "+p);o+=e[p++]}else o+=e[p++]+e[p++];if(i)throw new TypeError("Unbalanced pattern at "+r);if(!o)throw new TypeError("Missing pattern at "+r);t.push({type:"PATTERN",index:r,value:o}),r=p}else{for(var u="",p=r+1;p<e.length;){var f=e.charCodeAt(p);if(!(f>=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||95===f))break;u+=e[p++]}if(!u)throw new TypeError("Missing parameter name at "+r);t.push({type:"NAME",index:r,value:u}),r=p}else t.push({type:"CLOSE",index:r,value:e[r++]});else t.push({type:"OPEN",index:r,value:e[r++]});else t.push({type:"ESCAPED_CHAR",index:r++,value:e[r++]});else t.push({type:"MODIFIER",index:r,value:e[r++]})}return t.push({type:"END",index:r,value:""}),t}(e),i=t.prefixes,o=void 0===i?"./":i,u="[^"+n(t.delimiter||"/#?")+"]+?",p=[],f=0,a=0,s="",h=function(e){if(a<r.length&&r[a].type===e)return r[a++].value},d=function(e){var t=h(e);if(void 0!==t)return t;var n=r[a],i=n.type,o=n.index;throw new TypeError("Unexpected "+i+" at "+o+", expected "+e)},v=function(){for(var e,t="";e=h("CHAR")||h("ESCAPED_CHAR");)t+=e;return t};a<r.length;){var l=h("CHAR"),c=h("NAME"),y=h("PATTERN");if(c||y){var E=l||"";-1===o.indexOf(E)&&(s+=E,E=""),s&&(p.push(s),s=""),p.push({name:c||f++,prefix:E,suffix:"",pattern:y||u,modifier:h("MODIFIER")||""})}else{var x=l||h("ESCAPED_CHAR");if(x)s+=x;else if(s&&(p.push(s),s=""),h("OPEN")){E=v();var g=h("NAME")||"",m=h("PATTERN")||"",A=v();d("CLOSE"),p.push({name:g||(m?f++:""),pattern:g&&!m?u:m,prefix:E,suffix:A,modifier:h("MODIFIER")||""})}else d("END")}}return p}function n(e){return e.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1")}function i(e){return e&&e.sensitive?"":"i"}function o(e,t,o){return function(e,t,r){void 0===r&&(r={});for(var o=r.strict,u=void 0!==o&&o,p=r.start,f=void 0===p||p,a=r.end,s=void 0===a||a,h=r.encode,d=void 0===h?function(e){return e}:h,v="["+n(r.endsWith||"")+"]|$",l="["+n(r.delimiter||"/#?")+"]",c=f?"^":"",y=0,E=e;y<E.length;y++){var x=E[y];if("string"==typeof x)c+=n(d(x));else{var g=n(d(x.prefix)),m=n(d(x.suffix));if(x.pattern)if(t&&t.push(x),g||m)if("+"===x.modifier||"*"===x.modifier){var A="*"===x.modifier?"?":"";c+="(?:"+g+"((?:"+x.pattern+")(?:"+m+g+"(?:"+x.pattern+"))*)"+m+")"+A}else c+="(?:"+g+"("+x.pattern+")"+m+")"+x.modifier;else c+="("+x.pattern+")"+x.modifier;else c+="(?:"+g+m+")"+x.modifier}}if(s)u||(c+=l+"?"),c+=r.endsWith?"(?="+v+")":"$";else{var T=e[e.length-1],R="string"==typeof T?l.indexOf(T[T.length-1])>-1:void 0===T;u||(c+="(?:"+l+"(?="+v+"))?"),R||(c+="(?="+l+"|"+v+")")}return new RegExp(c,i(r))}(r(e,o),t,o)}function u(e,t,r){return e instanceof RegExp?function(e,t){if(!t)return e;var r=e.source.match(/\((?!\?)/g);if(r)for(var n=0;n<r.length;n++)t.push({name:n,prefix:"",suffix:"",modifier:"",pattern:""});return e}(e,t):Array.isArray(e)?function(e,t,r){var n=e.map((function(e){return u(e,t,r).source}));return new RegExp("(?:"+n.join("|")+")",i(r))}(e,t,r):o(e,t,r)}var p=function(){function e(){this.routes=[]}return e.prototype.all=function(e,t,r){return void 0===r&&(r={}),this._push("ALL",e,t,r)},e.prototype.get=function(e,t,r){return void 0===r&&(r={}),this._push("GET",e,t,r)},e.prototype.post=function(e,t,r){return void 0===r&&(r={}),this._push("POST",e,t,r)},e.prototype.put=function(e,t,r){return void 0===r&&(r={}),this._push("PUT",e,t,r)},e.prototype.patch=function(e,t,r){return void 0===r&&(r={}),this._push("PATCH",e,t,r)},e.prototype.delete=function(e,t,r){return void 0===r&&(r={}),this._push("DELETE",e,t,r)},e.prototype.head=function(e,t,r){return void 0===r&&(r={}),this._push("HEAD",e,t,r)},e.prototype.options=function(e,t,r){return void 0===r&&(r={}),this._push("OPTIONS",e,t,r)},e.prototype.match=function(e,r){for(var n=0,i=this.routes;n<i.length;n++){var o=i[n];if(o.method===e||"ALL"===o.method){if("(.*)"===o.path)return t(t({},o),{params:{0:o.path}});if("/"===o.path&&!1===o.options.end)return t(t({},o),{params:{}});var u=o.regexp.exec(r);if(u&&u.length)return t(t({},o),{matches:u,params:f(u,o.keys)})}}return null},e.prototype._push=function(e,t,r,n){var i=[];"*"===t&&(t="(.*)");var o=u(t,i,n);return this.routes.push({method:e,path:t,handler:r,keys:i,options:n,regexp:o}),this},e}(),f=function(e,t){for(var r={},n=1;n<e.length;n++){var i=t[n-1].name,o=e[n];void 0!==o&&(r[i]=o)}return r};e.Router=p,e.pathToRegexp=u,Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=router.min.js.map

@@ -1,3 +0,36 @@

import pathToRegexp, { Key, RegExpOptions } from 'path-to-regexp';
import { Key as TokenKey, pathToRegexp, TokensToRegexpOptions } from 'path-to-regexp';
export { pathToRegexp };
/** Valid HTTP methods for matching. */
export declare type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
export declare type MethodWildcard = 'ALL';
export interface Params {
[key: string]: string;
}
/**
* Optional route options.
*
* @example
* // When `true` the regexp will be case sensitive. (default: `false`)
* sensitive?: boolean;
*
* // When `true` the regexp allows an optional trailing delimiter to match. (default: `false`)
* strict?: boolean;
*
* // When `true` the regexp will match to the end of the string. (default: `true`)
* end?: boolean;
*
* // When `true` the regexp will match from the beginning of the string. (default: `true`)
* start?: boolean;
*
* // Sets the final character for non-ending optimistic matches. (default: `/`)
* delimiter?: string;
*
* // List of characters that can also be "end" characters.
* endsWith?: string;
*
* // Encode path tokens for use in the `RegExp`.
* encode?: (value: string) => string;
*/
export interface RouteOptions extends TokensToRegexpOptions {
}
export interface Route<HandlerType> {

@@ -11,2 +44,19 @@ method: Method | MethodWildcard;

}
/**
* The object returned when a route matches.
*
* The handler can then be used to execute the relevant function.
*
* @example
* {
* params: Params
* matches?: RegExpExecArray
* method: Method | MethodWildcard
* path: string
* regexp: RegExp
* options: RouteOptions
* keys: Keys
* handler: HandlerType
* }
*/
export interface RouteMatch<HandlerType> extends Route<HandlerType> {

@@ -16,23 +66,49 @@ params: Params;

}
export declare type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
export declare type MethodWildcard = 'ALL';
export interface Params {
[key: string]: string;
}
export interface RouteOptions extends RegExpOptions {
}
export declare type Key = Key;
export declare type Key = TokenKey;
export declare type Keys = Array<Key>;
/**
* Tiny request router. Allows overloading of handler type to be fully type safe.
*
* @example
* import { Router, Method, Params } from 'tiny-request-router'
*
* // Let the router know that handlers are async functions returning a Response
* type Handler = (params: Params) => Promise<Response>
*
* const router = new Router<Handler>()
*/
export declare class Router<HandlerType = any> {
/** List of all registered routes. */
routes: Array<Route<HandlerType>>;
/** Add a route that matches any method. */
all(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the GET method. */
get(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the POST method. */
post(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the PUT method. */
put(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the PATCH method. */
patch(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the DELETE method. */
delete(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the HEAD method. */
head(path: string, handler: HandlerType, options?: RouteOptions): this;
/** Add a route that matches the OPTIONS method. */
options(path: string, handler: HandlerType, options?: RouteOptions): this;
/**
* Match the provided method and path against the list of registered routes.
*
* @example
* router.get('/foobar', async () => new Response('Hello'))
*
* const match = router.match('GET', '/foobar')
* if (match) {
* // Call the async function of that match
* const response = await match.handler()
* console.log(response) // => Response('Hello')
* }
*/
match(method: Method, path: string): RouteMatch<HandlerType> | null;
private _push;
}
{
"name": "tiny-request-router",
"version": "1.1.2",
"version": "1.2.2",
"description": "Fast, generic and type safe router (match method and path).",

@@ -28,3 +28,4 @@ "author": "berstend",

"test": "ava-ts -v",
"prepublish": "npm run build"
"prepublish": "npm run build",
"docs": "documentation readme --quiet --shallow --github --markdown-theme transitivebs --readme-file readme.md --section API ./src/router.ts && npx prettier --write readme.md && npx prettier --write readme.md"
},

@@ -51,7 +52,8 @@ "prettier": {

"devDependencies": {
"@types/node": "^12.11.7",
"@types/node": "^12.12.14",
"ava": "^2.4.0",
"ava-ts": "^0.25.1",
"documentation-markdown-themes": "^12.1.5",
"rimraf": "^3.0.0",
"rollup": "^1.25.2",
"rollup": "^1.27.5",
"rollup-plugin-commonjs": "^10.1.0",

@@ -61,11 +63,11 @@ "rollup-plugin-node-resolve": "^5.2.0",

"rollup-plugin-typescript": "^1.0.1",
"ts-node": "^8.4.1",
"tslint": "^5.11.0",
"ts-node": "^8.5.4",
"tslint": "^5.20.1",
"tslint-config-prettier": "^1.15.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.0.3"
"tslint-config-standard": "^9.0.0",
"typescript": "^3.7.2"
},
"dependencies": {
"path-to-regexp": "^3.1.0"
"path-to-regexp": "^6.1.0"
}
}

@@ -7,14 +7,14 @@ # tiny-request-router [![ ](https://travis-ci.org/berstend/tiny-request-router.svg?branch=master)](https://travis-ci.org/berstend/tiny-request-router) [![ ](https://img.shields.io/npm/v/tiny-request-router.svg)](https://www.npmjs.com/package/tiny-request-router)

* Minimal and opinionless router, can be used in any script and environment.
* Matches a request method (e.g. `GET`) and a path (e.g. `/foobar`) against a list of routes
* Uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp), which is used by express and therefore familiar
* Allows wildcards (e.g. `/user/(.*)/age`) and named parameters (e.g. `/info/:username/:age`)
* Will not call your handlers automatically, as it only cares about matching
* No magic, no assumptions, no fluff, tested
- Minimal and opinionless router, can be used in any script and environment.
- Matches a request method (e.g. `GET`) and a path (e.g. `/foobar`) against a list of routes
- Uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp), which is used by express and therefore familiar
- Allows wildcards (e.g. `/user/(.*)/age`) and named parameters (e.g. `/info/:username/:age`)
- Will not call your handlers automatically, as it only cares about matching
- Battle hardened in production ([Cloudflare Worker](https://www.cloudflare.com/products/cloudflare-workers/) with 10M requests per day)
- No magic, no assumptions, no fluff, type safe, tested
### Route testing
* You can use the [Express Route Tester](https://forbeslindesay.github.io/express-route-tester/) (select `2.0.0`) to debug your path patterns quickly
- You can use the [Express Route Tester](https://forbeslindesay.github.io/express-route-tester/) (select `2.0.0`) to debug your path patterns quickly
## Installation

@@ -75,5 +75,5 @@

const router = new Router()
router.get("/worker", async () => new Response('Hi from worker!'))
router.get("/hello/:name", async (params) => new Response(`Hello ${params.name}!`))
router.post("/test", async () => new Response('Post received!'))
router.get('/worker', async () => new Response('Hi from worker!'))
router.get('/hello/:name', async params => new Response(`Hello ${params.name}!`))
router.post('/test', async () => new Response('Post received!'))

@@ -90,11 +90,226 @@ // Main entry point in workers

})
```
---
## API
The API is extremely minimal and what you would expect (`.get()`, `.all()`, etc). Please check out the [tiny source code](src/router.ts) or [tests](test/functionality.ts) for more info.
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
#### Table of Contents
- [Method()](#method)
- [RouteOptions()](#routeoptions)
- [RouteMatch()](#routematch)
- [class: Router](#class-router)
- [.routes](#routes)
- [.all(path, handler, options)](#allpath-handler-options)
- [.get(path, handler, options)](#getpath-handler-options)
- [.post(path, handler, options)](#postpath-handler-options)
- [.put(path, handler, options)](#putpath-handler-options)
- [.patch(path, handler, options)](#patchpath-handler-options)
- [.delete(path, handler, options)](#deletepath-handler-options)
- [.head(path, handler, options)](#headpath-handler-options)
- [.options(path, handler, options)](#optionspath-handler-options)
- [.match(method, path)](#matchmethod-path)
### [Method()](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L6-L6)
Type: **(`"GET"` \| `"POST"` \| `"PUT"` \| `"PATCH"` \| `"DELETE"` \| `"HEAD"` \| `"OPTIONS"`)**
Valid HTTP methods for matching.
---
### [RouteOptions()](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L39-L39)
**Extends: TokensToRegexpOptions**
Optional route options.
Example:
```javascript
// When `true` the regexp will be case sensitive. (default: `false`)
sensitive?: boolean;
// When `true` the regexp allows an optional trailing delimiter to match. (default: `false`)
strict?: boolean;
// When `true` the regexp will match to the end of the string. (default: `true`)
end?: boolean;
// When `true` the regexp will match from the beginning of the string. (default: `true`)
start?: boolean;
// Sets the final character for non-ending optimistic matches. (default: `/`)
delimiter?: string;
// List of characters that can also be "end" characters.
endsWith?: string;
// Encode path tokens for use in the `RegExp`.
encode?: (value: string) => string;
```
---
### [RouteMatch()](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L67-L70)
**Extends: Route&lt;HandlerType>**
The object returned when a route matches.
The handler can then be used to execute the relevant function.
Example:
```javascript
{
params: Params
matches?: RegExpExecArray
method: Method | MethodWildcard
path: string
regexp: RegExp
options: RouteOptions
keys: Keys
handler: HandlerType
}
```
---
### class: [Router](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L86-L168)
Tiny request router. Allows overloading of handler type to be fully type safe.
Example:
```javascript
import { Router, Method, Params } from 'tiny-request-router'
// Let the router know that handlers are async functions returning a Response
type Handler = (params: Params) => Promise<Response>
const router = new Router<Handler>()
```
---
#### .[routes](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L88-L88)
List of all registered routes.
---
#### .[all(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L91-L93)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches any method.
---
#### .[get(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L95-L97)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the GET method.
---
#### .[post(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L99-L101)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the POST method.
---
#### .[put(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L103-L105)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the PUT method.
---
#### .[patch(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L107-L109)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the PATCH method.
---
#### .[delete(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L111-L113)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the DELETE method.
---
#### .[head(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L115-L117)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the HEAD method.
---
#### .[options(path, handler, options)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L119-L121)
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `handler` **HandlerType**
- `options` **[RouteOptions](#routeoptions)** (optional, default `{}`)
Add a route that matches the OPTIONS method.
---
#### .[match(method, path)](https://github.com/berstend/tiny-request-router/blob/5e7d69be1e37a6d2d14c611efe77ba2ef6ea9f83/src/router.ts#L135-L152)
- `method` **[Method](#method)**
- `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
Returns: **([RouteMatch](#routematch)&lt;HandlerType> | null)**
Match the provided method and path against the list of registered routes.
Example:
```javascript
router.get('/foobar', async () => new Response('Hello'))
const match = router.match('GET', '/foobar')
if (match) {
// Call the async function of that match
const response = await match.handler()
console.log(response) // => Response('Hello')
}
```
---
## More info
Please check out the [tiny source code](src/router.ts) or [tests](test/functionality.ts) for more info.
## License
MIT

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc