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 { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||||
import HttpError from "../server/HttpError.ts";
|
import HttpError from "../server/HttpError.ts";
|
||||||
import User from "../models/User.ts";
|
import User from "../models/User.ts";
|
||||||
import { rest } from "../server/Router.ts";
|
import { body, rest, schema } from "../server/decorators.ts";
|
||||||
import { body, schema } from "../server/decorators.ts";
|
|
||||||
import AppRouter from "./AppRouter.ts";
|
import AppRouter from "./AppRouter.ts";
|
||||||
import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.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 { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts";
|
||||||
import serialize from "./serialize.ts";
|
import serialize from "./serialize.ts";
|
||||||
import HttpError from "./HttpError.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 HandlerRes = Promise<RestResponse | undefined> | RestResponse | undefined;
|
||||||
|
|
||||||
export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE';
|
|
||||||
|
|
||||||
export interface Handler {
|
export interface Handler {
|
||||||
handle(req: RestRequest): HandlerRes;
|
handle(req: RestRequest): HandlerRes;
|
||||||
}
|
}
|
||||||
@ -16,13 +13,18 @@ export interface RestOptions {
|
|||||||
route?: string;
|
route?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
|
export type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
|
||||||
type Base<KeyT extends string> = Router & { [X in KeyT]: Function; };
|
|
||||||
|
|
||||||
interface RouterHandler {
|
export interface RouterHandler {
|
||||||
path: string;
|
path: string;
|
||||||
handler: Handler;
|
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) {
|
export function makeParameterModifier(func: ProcessFunc) {
|
||||||
return (target: Router, key: string, index: number) => {
|
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 {
|
export default class Router {
|
||||||
private _handlers?: RouterHandler[];
|
private _handlers?: RouterHandler[];
|
||||||
public defaultHandler?: Handler;
|
public defaultHandler?: Handler;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { rest, route } from "./Router.ts";
|
|
||||||
import body from "./decorators/body.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";
|
import schema from "./decorators/schema.ts";
|
||||||
|
|
||||||
export { body, schema, rest, route };
|
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