import type { Request, Response } from 'express'; import type { Callable, DefAPINamespace, DeleteAPICallT, GetAPICallT, HeadAPICallT, HttpMethod, InvalidResponse, PatchAPICallT, PostAPICallT, PutAPICallT, RawArgType, ValidResponse, recoveryMethod } from '../apiStructure/defs'; import { validate, type ValidatorOptions, } from "class-validator"; import { type ClassTransformOptions, plainToInstance } from "class-transformer"; import type { InvalidProc, ProcDecorator, ProcDecoratorChain, ResolveChain } from './ProcDecorator/base.js'; import { clamp } from 'lodash-es'; export type APINamespace = { [key: string]: APINamespace // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_GET // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_POST // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_PUT // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_DELETE // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_PATCH // eslint-disable-next-line @typescript-eslint/no-explicit-any | iAPI_HEAD ; } type ValidatorType = T extends undefined ? undefined : ClassType; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyAPIExecuter = APIExecuter; interface APIExecuter { (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response): Promise; httpMethod: HttpMethod; argValidator?: ValidatorType; preDecorator: ProcDecorator[]; postDecorator: (ProcDecorator | undefined)[]; } export interface iAPI_GET extends APIExecuter { httpMethod: 'get'; } export interface iAPI_POST extends APIExecuter { httpMethod: 'post'; } export interface iAPI_PUT extends APIExecuter { httpMethod: 'put'; } export interface iAPI_DELETE extends APIExecuter { httpMethod: 'delete'; } export interface iAPI_PATCH extends APIExecuter { httpMethod: 'patch'; } export interface iAPI_HEAD extends APIExecuter { httpMethod: 'head'; } function generateAPI(httpMethod: HttpMethod, argValidator: ValidatorType | undefined, procDecoratorChain: PD, callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise, ): APIExecuter { const preDecorator: ProcDecorator[] = []; const postDecorator: (ProcDecorator | undefined)[] = []; if (procDecoratorChain) { for (const procGen of procDecoratorChain) { const proc = procGen(); if (Array.isArray(proc)) { preDecorator.push(proc[0]); postDecorator.push(undefined); } else { preDecorator.push(proc); postDecorator.push(proc); } } } return Object.assign( callback, { httpMethod, argValidator, preDecorator, postDecorator, } ); } export function GET(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'get', argValidator, procDecoratorChain, callback, ) as iAPI_GET; } } } export function POST(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'post', argValidator, procDecoratorChain, callback, ) as iAPI_POST; } } } export function PUT(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'put', argValidator, procDecoratorChain, callback, ) as iAPI_PUT; } } } export function DELETE(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'delete', argValidator, procDecoratorChain, callback, ) as iAPI_DELETE; } } } export function PATCH(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'patch', argValidator, procDecoratorChain, callback, ) as iAPI_PATCH; } } } export function HEAD(argValidator?: ValidatorType) { return (procDecoratorChain: PD) => { return (callback: (query: Q, ctx: ResolveChain, expressReq: Request, expressRes: Response) => Promise) => { return generateAPI( 'head', argValidator, procDecoratorChain, callback, ) as iAPI_HEAD; } } } export function raiseError(reason: string, recovery?: recoveryMethod): InvalidResponse { if (recovery) { return { result: false, reason, recovery, }; } return { result: false, reason, }; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ClassType = new (...args: any[]) => T; export type APIServerType = // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends GetAPICallT ? iAPI_GET : // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends PostAPICallT ? iAPI_POST : // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends PutAPICallT ? iAPI_PUT : // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends DeleteAPICallT ? iAPI_DELETE : // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends PatchAPICallT ? iAPI_PATCH : // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends HeadAPICallT ? iAPI_HEAD : never; export type APINamespaceType = { [K in keyof T]: T[K] extends Callable ? APIServerType : T[K] extends DefAPINamespace ? APINamespaceType : never; };