Skip to main content
Module

x/dinar/lib/core/router.ts

deno web framewrok maybe :<
Latest
File
import { RouteMethod } from "../constant/RouteMethods.ts";
import { ServerRequest, pathToRegexp, Key } from "../deps.ts";import { RouterDescriptor, RouterCallback, ArgumentsDescriptor, Constructor } from "../@types/types.ts";import { Context } from "./Context.ts";import { ArgumentsTypes } from "../constant/ArgumentsTypes.ts";import { ArgumentsMetadata } from "../interface/mod.ts";
export class RouterStorage { private static staticMethodMap: Map<RouteMethod, RouterMap> = (function () { const map = new Map(); for (const key in RouteMethod) { const newRouterMap: RouterMap = new Map(); map.set(RouteMethod[key as RouteMethod], newRouterMap); } return map; })(); private static patternMethodMap: Map<RouteMethod, Router[]> = (function () { const map = new Map(); for (const key in RouteMethod) { const routerArr: Router[] = []; map.set(RouteMethod[key as RouteMethod], routerArr); } return map; })();
static find(url: string, method: RouteMethod): null | Router { if (this.staticMethodMap.get(method)!.has(url)) { return this.staticMethodMap.get(method)?.get(url) ?? null; } for (const router of this.patternMethodMap.get(method)!) { if (router.regExp.test(url)) { return router; } } return null; }
static add(routerDescriptor: RouterDescriptor) { const { actionDescriptor, prefix } = routerDescriptor; const params: Key[] = []; const fullPath = this.generateRouterPath(prefix, actionDescriptor.suffix); const reg = pathToRegexp(fullPath, params as any); const isStatic = params.length === 0; const router = new Router(fullPath, routerDescriptor, reg, params); const time = new Date(); console.log(`*** [${time.getFullYear()}/${time.getMonth() + 1}/${time.getDate()}/${time.getHours()}:${time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes()}:${time.getSeconds()}] 注入路由 ${router.path}, host: ${router.hostName}@${router.callbackName}`); isStatic ? this.addStaticRouter(actionDescriptor.type, router) : this.addPatternRouter(actionDescriptor.type, router); }
static getParams(req: ServerRequest, router: Router) { const params: any = {}; const url = this.formatRouter(req.url.split("?")[0]); const captures = url.match(router.regExp)?.slice(1); if (captures !== undefined) { for (let len = captures.length, i = 0; i < len; i++) { if (router.params[i]) { const c = captures[i]; params[router.params[i].name] = c ? this.safeDecodeURIComponent(c) : c; } } } return params; }
private static safeDecodeURIComponent(text: string) { try { return decodeURIComponent(text); } catch (e) { return text; } }
private static formatRouter(url: string) { return url === "/" ? url : url.replace(/\/$/, ""); }
private static generateRouterPath(prefix: string, sub_path: string) { return this.formatRouter(`/${prefix}/${sub_path}`.replace(/[/]{2,}/g, "/")); }
private static addStaticRouter(method: RouteMethod, router: Router) { if (this.staticMethodMap.get(method)?.has(router.path)) { console.error(`*** 路由${router.path}已经存在`, `${router.hostName}@${router.callbackName}`, " it wont work***"); } else { this.staticMethodMap.get(method)!.set(router.path, router); } }
private static addPatternRouter(method: RouteMethod, router: Router) { this.patternMethodMap.get(method)!.push(router); }
static printRouter(debug?: boolean) {}}
class Router { private routerDescriptor: RouterDescriptor; path: string; regExp: RegExp; params: Key[]; private _argsMetadata: ArgumentsMetadata[] = []; constructor(path: string, routerDescriptor: RouterDescriptor, reg: RegExp, params: Key[]) { this.params = params; this.regExp = reg; this.path = path; this.routerDescriptor = routerDescriptor; this.routerDescriptor.args.map((arg, index) => {}); this._argsMetadata = []; }
async injectArugments(c: Context) { const args: object[] = []; const { body, session, cookie, query, params } = c; const argumentsMetadataArr: ArgumentsMetadata[] = []; for (const arg of this.routerDescriptor.args) { let object: any; switch (arg.type) { case ArgumentsTypes.BODY: object = arg.field ? body[arg.field] : body; break; case ArgumentsTypes.COOKIE: object = cookie; break; case ArgumentsTypes.PARAMS: object = arg.field ? params[arg.field] : params; break; case ArgumentsTypes.QUERY: object = arg.field ? query[arg.field] : query; break; case ArgumentsTypes.REQ: object = c.req; break; case ArgumentsTypes.SESSION: object = session; break; case ArgumentsTypes.CONTEXT: object = c; default: console.error("arguments can not find type,", arg.type); break; } args[arg.position] = object; argumentsMetadataArr.push({ value: object, argType: this.routerDescriptor.actionDescriptor.argsType[arg.position], metaType: arg.type, field: arg.field }); } return { args, argumentsMetadataArr }; }
parseParams(url: string) { const params: any = {}; const captures = url.match(this.regExp)?.slice(1); if (captures !== undefined) { for (let len = captures.length, i = 0; i < len; i++) { if (this.params[i]) { const c = captures[i]; params[this.params[i].name] = c ? this.safeDecodeURIComponent(c) : c; } } } return params; }
private safeDecodeURIComponent(text: string) { try { return decodeURIComponent(text); } catch (e) { return text; } }
async apply(args: any[]) { return await Reflect.apply(this.routerDescriptor.actionDescriptor.callback, this.routerDescriptor.host, [...args]); }
get callbackName() { return this.routerDescriptor.actionDescriptor.callback.name; }
get hostName() { return this.routerDescriptor.actionDescriptor.hostName; }
get argumentsMetadata() { return this._argsMetadata; }}
type RouterMap = Map<string, Router>;