UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

165 lines 7.45 kB
"use strict"; /* eslint-disable @typescript-eslint/no-unused-vars */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Res = exports.Req = exports.Body = exports.Param = exports.Query = exports.Connect = exports.Trace = exports.Head = exports.Options = exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = void 0; exports.Controller = Controller; exports.Use = Use; exports.HttpCode = HttpCode; exports.Header = Header; exports.Before = Before; exports.After = After; exports.registerControllers = registerControllers; require("reflect-metadata"); // --- End sample Express interfaces --- const ROUTES_KEY = Symbol("routes"); const MIDDLEWARE_KEY = Symbol("middlewares"); const PARAMS_KEY = Symbol("params"); // ---- Route Decorators ---- function createRouteDecorator(method) { return (path) => { return (target, propertyKey, descriptor) => { const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || []; routes.push({ path, method, handlerName: propertyKey, }); Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor); }; }; } exports.Get = createRouteDecorator("get"); exports.Post = createRouteDecorator("post"); exports.Put = createRouteDecorator("put"); exports.Patch = createRouteDecorator("patch"); exports.Delete = createRouteDecorator("delete"); exports.Options = createRouteDecorator("options"); exports.Head = createRouteDecorator("head"); exports.Trace = createRouteDecorator("trace"); exports.Connect = createRouteDecorator("connect"); // ---- Controller Decorator ---- function Controller(basePath) { return (target) => { Reflect.defineMetadata("basePath", basePath, target); }; } // ---- Middleware Decorator ---- function Use(...middlewares) { return (target, propertyKey, descriptor) => { const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || []; Reflect.defineMetadata(MIDDLEWARE_KEY, [...existing, ...middlewares], target, propertyKey); }; } // ---- Parameter Decorators ---- function createParamDecorator(type, key) { return (paramKey) => { return (target, propertyKey, parameterIndex) => { const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || []; // Ensure parameters are ordered by index params.push({ index: parameterIndex, type, key: paramKey || key }); params.sort((a, b) => a.index - b.index); Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey); }; }; } exports.Query = createParamDecorator("query"); exports.Param = createParamDecorator("param"); exports.Body = createParamDecorator("body"); exports.Req = createParamDecorator("req"); exports.Res = createParamDecorator("res"); // Custom HTTP status code decorator const HTTP_CODE_KEY = Symbol("httpCode"); function HttpCode(status) { return (target, propertyKey, descriptor) => { Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey); }; } // Custom header decorator const HEADER_KEY = Symbol("headers"); function Header(name, value) { return (target, propertyKey, descriptor) => { const headers = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {}; headers[name] = value; Reflect.defineMetadata(HEADER_KEY, headers, target, propertyKey); }; } // Before/After hooks (not Express middleware, but can be used for logging, etc.) const BEFORE_KEY = Symbol("before"); const AFTER_KEY = Symbol("after"); function Before(fn) { return (target, propertyKey, descriptor) => { const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || []; hooks.push(fn); Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey); }; } function After(fn) { return (target, propertyKey, descriptor) => { const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || []; hooks.push(fn); Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey); }; } // ---- Register Controllers ---- function registerControllers(router, controllers) { controllers.forEach((ControllerClass) => { const instance = new ControllerClass(); const basePath = Reflect.getMetadata("basePath", ControllerClass) || ""; const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || []; routes.forEach(({ path, method, handlerName }) => { const middlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || []; const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || []; const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName); const headers = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {}; const beforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || []; const afterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || []; const handler = async (req, res, next) => { var _a, _b; try { for (const fn of beforeHooks) await fn(req, res); const args = []; if (params.length) { params.forEach(({ index, type, key }) => { var _a; switch (type) { case "query": args[index] = key ? req.query[key] : req.query; break; case "param": args[index] = key ? req.params[key] : req.params; break; case "body": args[index] = key ? (_a = req.body) === null || _a === void 0 ? void 0 : _a[key] : req.body; break; case "req": args[index] = req; break; case "res": args[index] = res; break; } }); } const result = instance[handlerName](...args); // Support both sync and async handlers const awaited = result instanceof Promise ? await result : result; if (!res.headersSent && typeof awaited !== "undefined") { if (httpCode) (_a = res.status) === null || _a === void 0 ? void 0 : _a.call(res, httpCode); for (const [k, v] of Object.entries(headers)) (_b = res.set) === null || _b === void 0 ? void 0 : _b.call(res, k, v); res.json(awaited); } for (const fn of afterHooks) await fn(req, res, awaited); } catch (err) { next(err); } }; router[method](basePath + path, ...middlewares, handler); }); }); } //# sourceMappingURL=decorators.utils.js.map