| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- // src/router/reg-exp-router/router.ts
- import {
- MESSAGE_MATCHER_IS_ALREADY_BUILT,
- METHOD_NAME_ALL,
- UnsupportedPathError
- } from "../../router.js";
- import { checkOptionalParameter } from "../../utils/url.js";
- import { match, emptyParam } from "./matcher.js";
- import { PATH_ERROR } from "./node.js";
- import { Trie } from "./trie.js";
- var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
- var 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 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 === PATH_ERROR ? new 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;
- }
- var RegExpRouter = class {
- name = "RegExpRouter";
- #middleware;
- #routes;
- constructor() {
- this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
- this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
- }
- add(method, path, handler) {
- const middleware = this.#middleware;
- const routes = this.#routes;
- if (!middleware || !routes) {
- throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
- }
- if (!middleware[method]) {
- ;
- [middleware, routes].forEach((handlerMap) => {
- handlerMap[method] = /* @__PURE__ */ Object.create(null);
- Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
- handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
- });
- });
- }
- if (path === "/*") {
- path = "*";
- }
- const paramCount = (path.match(/\/:/g) || []).length;
- if (/\*$/.test(path)) {
- const re = buildWildcardRegExp(path);
- if (method === METHOD_NAME_ALL) {
- Object.keys(middleware).forEach((m) => {
- middleware[m][path] ||= findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
- });
- } else {
- middleware[method][path] ||= findMiddleware(middleware[method], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
- }
- Object.keys(middleware).forEach((m) => {
- if (method === 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 === METHOD_NAME_ALL || method === m) {
- Object.keys(routes[m]).forEach(
- (p) => re.test(p) && routes[m][p].push([handler, paramCount])
- );
- }
- });
- return;
- }
- const paths = checkOptionalParameter(path) || [path];
- for (let i = 0, len = paths.length; i < len; i++) {
- const path2 = paths[i];
- Object.keys(routes).forEach((m) => {
- if (method === METHOD_NAME_ALL || method === m) {
- routes[m][path2] ||= [
- ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
- ];
- routes[m][path2].push([handler, paramCount - len + i + 1]);
- }
- });
- }
- }
- match = match;
- buildAllMatchers() {
- const matchers = /* @__PURE__ */ Object.create(null);
- Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
- matchers[method] ||= this.#buildMatcher(method);
- });
- this.#middleware = this.#routes = void 0;
- clearWildcardRegExpCache();
- return matchers;
- }
- #buildMatcher(method) {
- const routes = [];
- let hasOwnRoute = method === 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 !== METHOD_NAME_ALL) {
- routes.push(
- ...Object.keys(r[METHOD_NAME_ALL]).map((path) => [path, r[METHOD_NAME_ALL][path]])
- );
- }
- });
- if (!hasOwnRoute) {
- return null;
- } else {
- return buildMatcherFromPreprocessedRoutes(routes);
- }
- }
- };
- export {
- RegExpRouter
- };
|