import path from 'node:path' import type express from 'express' import { NextFunction } from 'express' export namespace Internals { export function buildRouterObject(fileRoute: string): Router.Router { const router: Router.RouterConfig = { routes: [], swaggerHide: false, httpRoute: fileRoute, mark: Object.create(null) } return new Proxy(router, { get: (targetRouter, prop) => { if (targetRouter[prop] !== undefined) { return targetRouter[prop] } if (prop === 'then') { return targetRouter } return (httpPathOrHandler: string | Router.RequestHandler, ...handlers: Router.RequestHandler[]) => { let httpPath: string | undefined = undefined if (typeof httpPathOrHandler === 'string') { httpPath = httpPathOrHandler } else { handlers = [ httpPathOrHandler, ...handlers ] } targetRouter.routes.push({ method: prop.toString(), handlers, path: httpPath }) } }, set: (targetRouter, prop, value) => { if (targetRouter[prop] !== undefined) { targetRouter[prop] = value } return true } }) as Router.Router } export const ResolveOnResponseEventQueue = async(aReq: Router.Request, aRes: Router.Response, body?: any, error?: PlataError | PlataError[]) => { if (aReq._onResponseEvent.length === 0) { return; } aReq._onResponseEvent.forEach((r) => { Plata.FastPromise(() => r(aReq, aRes, body, error)).catch(() => undefined) }) } export function buildRequestHandler(r: Router.RequestHandler | Router.RequestHandler[]): express.RequestHandler | express.RequestHandler[] { if (Array.isArray(r)) { return r.map(h => buildRequestHandler(h)) as express.RequestHandler[] } return async (req, res, next) => { const aReq = req as Router.Request const aRes = res as Router.Response if (aReq.user === undefined) { aReq.user = Object.create(null) } if (aReq.extras === undefined) { aReq.extras = Object.create(null) } if (aReq._onResponseEvent === undefined) { aReq._onResponseEvent = [] } if (aRes.addOnResponseEvent === undefined) { aRes.addOnResponseEvent = (callback) => { aReq._onResponseEvent.push(callback) } } if (aRes.oldJson === undefined) { aRes.oldJson = aRes.json } aRes.json = (body?: any) => { Plata.FastPromise(async () => { ResolveOnResponseEventQueue(aReq, aRes, body, undefined) }) return aRes.oldJson(body) } aRes.error = error => { Plata.FastPromise(async () => { ResolveOnResponseEventQueue(aReq, aRes, undefined, error)}) return aRes.oldJson(error) } return r(aReq, aRes, next) } } } export function processRoutes(routes: RequiredInterface<{default: Router.RouterBuilder}>[]): Router.RequiredRoute[] { const indexRoutes: Router.RequiredRoute[] = [] const normalRoutes: Router.RequiredRoute[] = [] for (let i = routes.length - 1; i >= 0; i--) { const route = routes[i] const r: Router.RequiredRoute = { ...route, exports: route.exports.default, httpRoute: path.normalize(route.filePath .replace('__BUILD__', '') .replace(Plata.ProjectDir.replace(/\\/g, '/'), '') .replace('routes', '') .replace(/(\.ts|\.js|\.jsc)$/, '') .replace(/index/, '') .replace(/\{(.*?)\}/g, ':$1') .replace(/\[(.*?)\]/g, ':$1?') ).replace(/\\/g, '/'), } if (r.name === 'index') { indexRoutes.push(r) continue } normalRoutes.push(r) } normalRoutes.unshift(...indexRoutes.sort((x, y) => x.httpRoute.length - y.httpRoute.length)) return normalRoutes } export async function loadRoutesFromProject(): PlataPromise { const routes: RequiredFolder<{default: Router.RouterBuilder}> = await require('@@/routes/*.*') if (routes.errorID !== undefined) { return routes } return processRoutes(routes) } export async function buildExpressRouter(requiredRoutes: Router.RequiredRoute[], eRouter: express.Router): PlataPromise { const router = eRouter as any as Router.Router router.routes = [] router.swaggerHide = false for (const r of requiredRoutes) { const v = await r.exports(Internals.buildRouterObject(r.httpRoute)) const routes = v.routes const swaggerHide = v.swaggerHide for (let i = 0; i < routes.length; i++) { const route = routes[i] let httpPath = r.httpRoute if (route.path !== undefined) { httpPath = path.normalize(`${httpPath}/${route.path}`).replace(/\\/g, '/') } router[route.method](httpPath, ...route.handlers.map(Internals.buildRequestHandler)) router.routes.push({ path: httpPath, method: route.method, handlers: [], swaggerHide: swaggerHide }) } } return router }