"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const http_1 = require("../utils/http"); const crypto_md5_1 = __importDefault(require("crypto-md5")); const url_1 = require("../utils/url"); const lodash_1 = require("lodash"); const PARAM_RE = /^{(\S+)}$/; function buildRouteParamsMap(routeMatch, paramNames) { return paramNames.reduce((params, paramName, i) => { params[paramName] = routeMatch[i + 1]; return params; }, {}); } class Router { constructor(options = {}) { this.routes = new Map(); this.routesWithParams = []; this.options = options; } _registerRoute(route, method, handler) { const tokens = route.split('/'); const isRouteWithParams = tokens.some(token => PARAM_RE.test(token)); if (isRouteWithParams && typeof handler === 'function') this._registerRouteWithParams(tokens, method, handler); else { const routeName = `${method} ${route}`; if (typeof handler !== 'function') { this._processStaticContent(handler); handler.etag = (0, crypto_md5_1.default)(handler.content); this.routes.set(routeName, { handler, isStatic: true }); } else this.routes.set(routeName, { handler, isStatic: false }); } } _prepareParamInfo(tokens, method) { const paramNames = []; const reParts = tokens.map(token => { const paramMatch = token.match(PARAM_RE); if (paramMatch) { paramNames.push(paramMatch[1]); return '(\\S+?)'; } return token; }); return { paramNames, re: new RegExp(`^${method} ${reParts.join('/')}$`), }; } _registerRouteWithParams(tokens, method, handler) { const { paramNames, re } = this._prepareParamInfo(tokens, method); this.routesWithParams.push({ handler, paramNames, re }); } _unregisterRouteWithParams(tokens, method) { const { paramNames, re } = this._prepareParamInfo(tokens, method); const routeIndex = this.routesWithParams.findIndex(routeWithParam => { return (0, lodash_1.isEqual)(routeWithParam.re, re) && (0, lodash_1.isEqual)(routeWithParam.paramNames, paramNames); }); if (routeIndex !== -1) this.routesWithParams.splice(routeIndex, 1); } _route(req, res, serverInfo) { const routerQuery = `${req.method} ${(0, url_1.getPathname)(req.url || '')}`; const route = this.routes.get(routerQuery); if (route) { if (route.isStatic) (0, http_1.respondStatic)(req, res, route.handler, this.options.staticContentCaching); else route.handler(req, res, serverInfo); return true; } for (const routeWithParams of this.routesWithParams) { const routeMatch = routerQuery.match(routeWithParams.re); if (routeMatch) { const params = buildRouteParamsMap(routeMatch, routeWithParams.paramNames); routeWithParams.handler(req, res, serverInfo, params); return true; } } return false; } // API GET(route, handler) { this._registerRoute(route, 'GET', handler); } POST(route, handler) { this._registerRoute(route, 'POST', handler); } OPTIONS(route, handler) { this._registerRoute(route, 'OPTIONS', handler); } unRegisterRoute(route, method) { const tokens = route.split('/'); const isRouteWithParams = tokens.some(token => PARAM_RE.test(token)); if (isRouteWithParams) this._unregisterRouteWithParams(tokens, method); const routeName = `${method} ${route}`; this.routes.delete(routeName); } } exports.default = Router;module.exports = exports.default;