// 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' | 'OPTIONS'; 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.call(r, req, arg, params[i]); } args.push(arg); } const res = await r[key].apply(r, args); if (res instanceof RestResponse) return res; return new RestResponse().body(await serialize(res)); } }, })); }; }