some more code splitting
This commit is contained in:
parent
f7ff1605e1
commit
d6bfd50173
@ -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";
|
||||
|
||||
|
@ -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> | 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> | unknown;
|
||||
type Base<KeyT extends string> = Router & { [X in KeyT]: Function; };
|
||||
export type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
|
||||
|
||||
interface RouterHandler {
|
||||
export interface RouterHandler {
|
||||
path: string;
|
||||
handler: Handler;
|
||||
}
|
||||
export function addMetaQuery<T extends Router>(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<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: 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<KeyT extends keyof T & string, T extends Router & { [x in KeyT]: Handler }>(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;
|
||||
|
@ -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 };
|
60
src/server/decorators/rest.ts
Normal file
60
src/server/decorators/rest.ts
Normal file
@ -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<KeyT extends string> = Router & { [X in KeyT]: Function; };
|
||||
type ModArray = ([ProcessFunc, ...ProcessFunc[]] | 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 = [];
|
||||
|
||||
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));
|
||||
}
|
||||
},
|
||||
}));
|
||||
};
|
||||
}
|
10
src/server/decorators/route.ts
Normal file
10
src/server/decorators/route.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import Router, { Handler, addMetaQuery } from "../Router.ts";
|
||||
|
||||
export default function route<KeyT extends keyof T & string, T extends Router & { [x in KeyT]: Handler }>(path?: string) {
|
||||
return (target: T, key: KeyT) => {
|
||||
addMetaQuery(target, r => ({
|
||||
handler: r[key],
|
||||
path: path ?? key,
|
||||
}));
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user