60 lines
2.5 KiB
TypeScript
60 lines
2.5 KiB
TypeScript
// 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<KeyT extends string> = Router & { [X in KeyT]: Function; };
|
|
type ModArray<T extends Router> = ([ProcessFunc<T>, ...ProcessFunc<T>[]] | undefined)[];
|
|
|
|
export default function rest<KeyT extends keyof T & string, T extends Base<KeyT>>(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<T> = [];
|
|
|
|
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<T>;
|
|
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));
|
|
}
|
|
},
|
|
}));
|
|
};
|
|
} |