UNPKG

hono

Version:

Web framework built on Web Standards

225 lines (224 loc) 8.12 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var router_exports = {}; __export(router_exports, { RegExpRouter: () => RegExpRouter }); module.exports = __toCommonJS(router_exports); var import_router = require("../../router"); var import_url = require("../../utils/url"); var import_node = require("./node"); var import_trie = require("./trie"); const emptyParam = []; const nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)]; let wildcardRegExpCache = /* @__PURE__ */ Object.create(null); function buildWildcardRegExp(path) { return wildcardRegExpCache[path] ??= new RegExp( path === "*" ? "" : `^${path.replace( /\/\*$|([.\\+*[^\]$()])/g, (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)" )}$` ); } function clearWildcardRegExpCache() { wildcardRegExpCache = /* @__PURE__ */ Object.create(null); } function buildMatcherFromPreprocessedRoutes(routes) { const trie = new import_trie.Trie(); const handlerData = []; if (routes.length === 0) { return nullMatcher; } const routesWithStaticPathFlag = routes.map( (route) => [!/\*|\/:/.test(route[0]), ...route] ).sort( ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length ); const staticMap = /* @__PURE__ */ Object.create(null); for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) { const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i]; if (pathErrorCheckOnly) { staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam]; } else { j++; } let paramAssoc; try { paramAssoc = trie.insert(path, j, pathErrorCheckOnly); } catch (e) { throw e === import_node.PATH_ERROR ? new import_router.UnsupportedPathError(path) : e; } if (pathErrorCheckOnly) { continue; } handlerData[j] = handlers.map(([h, paramCount]) => { const paramIndexMap = /* @__PURE__ */ Object.create(null); paramCount -= 1; for (; paramCount >= 0; paramCount--) { const [key, value] = paramAssoc[paramCount]; paramIndexMap[key] = value; } return [h, paramIndexMap]; }); } const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp(); for (let i = 0, len = handlerData.length; i < len; i++) { for (let j = 0, len2 = handlerData[i].length; j < len2; j++) { const map = handlerData[i][j]?.[1]; if (!map) { continue; } const keys = Object.keys(map); for (let k = 0, len3 = keys.length; k < len3; k++) { map[keys[k]] = paramReplacementMap[map[keys[k]]]; } } } const handlerMap = []; for (const i in indexReplacementMap) { handlerMap[i] = handlerData[indexReplacementMap[i]]; } return [regexp, handlerMap, staticMap]; } function findMiddleware(middleware, path) { if (!middleware) { return void 0; } for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) { if (buildWildcardRegExp(k).test(path)) { return [...middleware[k]]; } } return void 0; } class RegExpRouter { name = "RegExpRouter"; middleware; routes; constructor() { this.middleware = { [import_router.METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; this.routes = { [import_router.METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; } add(method, path, handler) { const { middleware, routes } = this; if (!middleware || !routes) { throw new Error(import_router.MESSAGE_MATCHER_IS_ALREADY_BUILT); } if (!middleware[method]) { ; [middleware, routes].forEach((handlerMap) => { handlerMap[method] = /* @__PURE__ */ Object.create(null); Object.keys(handlerMap[import_router.METHOD_NAME_ALL]).forEach((p) => { handlerMap[method][p] = [...handlerMap[import_router.METHOD_NAME_ALL][p]]; }); }); } if (path === "/*") { path = "*"; } const paramCount = (path.match(/\/:/g) || []).length; if (/\*$/.test(path)) { const re = buildWildcardRegExp(path); if (method === import_router.METHOD_NAME_ALL) { Object.keys(middleware).forEach((m) => { middleware[m][path] ||= findMiddleware(middleware[m], path) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path) || []; }); } else { middleware[method][path] ||= findMiddleware(middleware[method], path) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path) || []; } Object.keys(middleware).forEach((m) => { if (method === import_router.METHOD_NAME_ALL || method === m) { Object.keys(middleware[m]).forEach((p) => { re.test(p) && middleware[m][p].push([handler, paramCount]); }); } }); Object.keys(routes).forEach((m) => { if (method === import_router.METHOD_NAME_ALL || method === m) { Object.keys(routes[m]).forEach( (p) => re.test(p) && routes[m][p].push([handler, paramCount]) ); } }); return; } const paths = (0, import_url.checkOptionalParameter)(path) || [path]; for (let i = 0, len = paths.length; i < len; i++) { const path2 = paths[i]; Object.keys(routes).forEach((m) => { if (method === import_router.METHOD_NAME_ALL || method === m) { routes[m][path2] ||= [ ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path2) || [] ]; routes[m][path2].push([handler, paramCount - len + i + 1]); } }); } } match(method, path) { clearWildcardRegExpCache(); const matchers = this.buildAllMatchers(); this.match = (method2, path2) => { const matcher = matchers[method2] || matchers[import_router.METHOD_NAME_ALL]; const staticMatch = matcher[2][path2]; if (staticMatch) { return staticMatch; } const match = path2.match(matcher[0]); if (!match) { return [[], emptyParam]; } const index = match.indexOf("", 1); return [matcher[1][index], match]; }; return this.match(method, path); } buildAllMatchers() { const matchers = /* @__PURE__ */ Object.create(null); [...Object.keys(this.routes), ...Object.keys(this.middleware)].forEach((method) => { matchers[method] ||= this.buildMatcher(method); }); this.middleware = this.routes = void 0; return matchers; } buildMatcher(method) { const routes = []; let hasOwnRoute = method === import_router.METHOD_NAME_ALL; [this.middleware, this.routes].forEach((r) => { const ownRoute = r[method] ? Object.keys(r[method]).map((path) => [path, r[method][path]]) : []; if (ownRoute.length !== 0) { hasOwnRoute ||= true; routes.push(...ownRoute); } else if (method !== import_router.METHOD_NAME_ALL) { routes.push( ...Object.keys(r[import_router.METHOD_NAME_ALL]).map((path) => [path, r[import_router.METHOD_NAME_ALL][path]]) ); } }); if (!hasOwnRoute) { return null; } else { return buildMatcherFromPreprocessedRoutes(routes); } } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { RegExpRouter });