From d6bfd5017372dcc5be6a61dd7814daf08d351504 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Mon, 26 Jun 2023 17:16:44 +0300 Subject: [PATCH] some more code splitting --- src/routers/UserRouter.ts | 3 +- src/server/Router.ts | 77 ++++------------------------------ src/server/decorators.ts | 3 +- src/server/decorators/rest.ts | 60 ++++++++++++++++++++++++++ src/server/decorators/route.ts | 10 +++++ 5 files changed, 81 insertions(+), 72 deletions(-) create mode 100644 src/server/decorators/rest.ts create mode 100644 src/server/decorators/route.ts diff --git a/src/routers/UserRouter.ts b/src/routers/UserRouter.ts index f3ac353..0cd9c4d 100644 --- a/src/routers/UserRouter.ts +++ b/src/routers/UserRouter.ts @@ -1,8 +1,7 @@ import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts"; import HttpError from "../server/HttpError.ts"; import User from "../models/User.ts"; -import { rest } from "../server/Router.ts"; -import { body, schema } from "../server/decorators.ts"; +import { body, rest, schema } from "../server/decorators.ts"; import AppRouter from "./AppRouter.ts"; import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts"; diff --git a/src/server/Router.ts b/src/server/Router.ts index 421f363..6fb786d 100644 --- a/src/server/Router.ts +++ b/src/server/Router.ts @@ -1,4 +1,3 @@ -// deno-lint-ignore-file no-explicit-any ban-types import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts"; import serialize from "./serialize.ts"; import HttpError from "./HttpError.ts"; @@ -7,8 +6,6 @@ import RestRequest from "./RestRequest.ts"; export type HandlerRes = Promise | RestResponse | undefined; -export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE'; - export interface Handler { handle(req: RestRequest): HandlerRes; } @@ -16,13 +13,18 @@ export interface RestOptions { route?: string; } -type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise | unknown; -type Base = Router & { [X in KeyT]: Function; }; +export type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise | unknown; -interface RouterHandler { +export interface RouterHandler { path: string; handler: Handler; } +export function addMetaQuery(target: T, ...handlers: ((r: T) => RouterHandler)[]) { + let props = Reflect.getOwnMetadata('router:queries', target); + if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target); + + props.push(...handlers); +} export function makeParameterModifier(func: ProcessFunc) { return (target: Router, key: string, index: number) => { @@ -36,69 +38,6 @@ export function makeParameterModifier(func: ProcessFunc) { } -function addMetaQuery(target: any, ...handlers: ((r: Router) => RouterHandler)[]) { - let props = Reflect.getOwnMetadata('router:queries', target); - if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target); - - props.push(...handlers); -} - -export function rest>(method: HttpMethod, route?: string) { - return (target: T, key: KeyT) => { - const path = route ?? key; - - addMetaQuery(target, (r: any) => ({ - path, handler: { - async handle(req) { - if (method !== '*' && req.method.toUpperCase() !== method) return undefined; - - const params: string[] = []; - const func = (r as T)[key]; - const args: any[] = []; - const allMods: ([ProcessFunc, ...ProcessFunc[]] | undefined)[] = []; - - let signature = (target[key] as Function).toString(); - signature = signature.substring(signature.indexOf('(') + 1, signature.indexOf(')')); - params.push(...signature.split(',').map(v => v.trim()).filter(v => v !== '')); - - for (let proto = target; proto instanceof Router; proto = Object.getPrototypeOf(proto)) { - const data = Reflect.getOwnMetadata('router:params', proto, key); - if (!data) continue; - for (let i = 0; i < data.length; i++) { - allMods[i] ??= [] as any; - if (data[i]) allMods[i]!.push(...data[i]); - } - } - - for (let i = 0; i < params.length; i++) { - const param = params[i]; - - let arg: any = req.params[param]; - - for (const mod of allMods[i] ?? []) { - arg = await mod(req, arg, params[i]); - } - - args.push(arg); - } - - const res = func.apply(r, args); - if (res instanceof RestResponse) return res; - return new RestResponse().body(await serialize(res)); - } - }, - })); - }; -} -export function route(path?: string) { - return (target: T, key: KeyT) => { - addMetaQuery(target, (r: any) => ({ - handler: r[key], - path: path ?? key, - })); - }; -} - export default class Router { private _handlers?: RouterHandler[]; public defaultHandler?: Handler; diff --git a/src/server/decorators.ts b/src/server/decorators.ts index 4fd65ed..335991c 100644 --- a/src/server/decorators.ts +++ b/src/server/decorators.ts @@ -1,5 +1,6 @@ -import { rest, route } from "./Router.ts"; import body from "./decorators/body.ts"; +import rest from "./decorators/rest.ts"; +import route from "./decorators/route.ts"; import schema from "./decorators/schema.ts"; export { body, schema, rest, route }; \ No newline at end of file diff --git a/src/server/decorators/rest.ts b/src/server/decorators/rest.ts new file mode 100644 index 0000000..190af43 --- /dev/null +++ b/src/server/decorators/rest.ts @@ -0,0 +1,60 @@ +// deno-lint-ignore-file ban-types +import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts"; + +import RestResponse from "../RestResponse.ts"; +import Router, { ProcessFunc, addMetaQuery } from "../Router.ts"; +import serialize from "../serialize.ts"; + +export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE'; + +type Base = Router & { [X in KeyT]: Function; }; +type ModArray = ([ProcessFunc, ...ProcessFunc[]] | undefined)[]; + +export default function rest>(method: HttpMethod, route?: string) { + return (target: T, key: KeyT) => { + const path = route ?? key; + + addMetaQuery(target, (r) => ({ + path, handler: { + async handle(req) { + if (method !== '*' && req.method.toUpperCase() !== method) return undefined; + + const params: string[] = []; + const args: unknown[] = []; + const allMods: ModArray = []; + + let signature = r[key].toString(); + signature = signature.substring(signature.indexOf('(') + 1, signature.indexOf(')')); + params.push(...signature.split(',').map(v => v.trim()).filter(v => v !== '')); + + for (let proto = r; proto instanceof Router; proto = Object.getPrototypeOf(proto)) { + const data = Reflect.getOwnMetadata('router:params', proto, key) as ModArray; + if (!data) continue; + for (let i = 0; i < data.length; i++) { + if (data[i] === undefined) continue; + + if (allMods[i]) allMods[i]!.push(...data[i]!); + else allMods[i] ??= [...data[i]!]; + } + } + + for (let i = 0; i < params.length; i++) { + const param = params[i]; + + let arg: unknown = req.params[param]; + + for (const mod of allMods[i] ?? []) { + arg = await mod(req, arg, params[i]); + } + + args.push(arg); + } + + const res = r[key].apply(r, args); + if (res instanceof RestResponse) return res; + return new RestResponse().body(await serialize(res)); + } + }, + })); + }; +} \ No newline at end of file diff --git a/src/server/decorators/route.ts b/src/server/decorators/route.ts new file mode 100644 index 0000000..e1e35a6 --- /dev/null +++ b/src/server/decorators/route.ts @@ -0,0 +1,10 @@ +import Router, { Handler, addMetaQuery } from "../Router.ts"; + +export default function route(path?: string) { + return (target: T, key: KeyT) => { + addMetaQuery(target, r => ({ + handler: r[key], + path: path ?? key, + })); + }; +} \ No newline at end of file