Bringing local and remote repository in line with one another again

This commit is contained in:
Alan Bridgeman 2025-04-30 14:58:07 -05:00
parent bc581f9eac
commit 332e177f99
15 changed files with 1344 additions and 222 deletions

View file

@ -2,29 +2,37 @@ import { Application, NextFunction } from 'express';
import { BaseController } from '../controllers/BaseController';
import { CHILD_CONTROLLER_METADATA_KEY } from './ChildController';
import { GET_METADATA_KEY } from './GET';
import { POST_METADATA_KEY } from './POST';
import { PUT_METADATA_KEY } from './PUT';
import { DELETE_METADATA_KEY } from './DELETE';
/**
* Class decorator to "fill in" the setup method which is called on server startup and connects the methods/functions and their desired paths in the express app.
*
*
* That is, this is largely for the convenience of controller writers/developers so that they don't have to manually create a `setup` method in their controller classes.
*
*
* @example
* The following example show how to use the Controller decorator to setup a path `/path` with a GET and POST method.
* The following example show how to use the Controller decorator to setup a path `/path` with a GET, POST, PUT and DELETE method.
* ```ts
* import { Request, Response } from 'express';
*
* import { Controller } from '../decorators/Controller';
* import { GET } from '../decorators/GET';
* import { POST } from '../decorators/POST';
*
* import { BaseController } from './BaseController';
*
*
* import { Controller, GET, POST, BaseController } from '@BridgemanAccessible/ba-web-framework';
*
* @Controller()
* export class MyController extends BaseController {
* @GET('/path')
* private myGetMethod(req: Request, res: Response) {}
*
*
* @POST('/path', express.json())
* private myPostMethod(req: Request, res: Response) {}
*
* @PUT('/path', express.json())
* private myPutMethod(req: Request, res: Response) {}
*
* @DELETE('/path', express.json())
* private myDeleteMethod(req: Request, res: Response) {}
* }
* ```
*/
@ -45,7 +53,7 @@ export function Controller<T extends { new (...args: any[]): BaseController }>()
//
// Currently, there is very little linkage between the decorated controller class and the child controller class(es).
// Though in the future this may look more like forcing these to be on sub-paths of the parent controller etc...
const childControllers = Reflect.getMetadata('ChildController', target);
const childControllers = Reflect.getMetadata(CHILD_CONTROLLER_METADATA_KEY, target);
if(typeof childControllers !== 'undefined') {
if(Array.isArray(childControllers)) {
childControllers.forEach((childController) => {
@ -61,13 +69,13 @@ export function Controller<T extends { new (...args: any[]): BaseController }>()
// Loop over all the methods in the decorated class looking for methods that use the GET decorator
Object.getOwnPropertyNames(target.prototype)
// Find all methods that have a Get metadata key (GET decorator)
.filter((method) => Reflect.getMetadata('Get', target.prototype, method))
.filter((method) => Reflect.getMetadata(GET_METADATA_KEY, target.prototype, method))
.map((method) => {
// Get the method
const fn = target.prototype[method];
// Get the path
const path = Reflect.getMetadata('Get', target.prototype, method);
const path = Reflect.getMetadata(GET_METADATA_KEY, target.prototype, method);
// Bind the method to the class instance
app.get(path, fn.bind(controller));
@ -76,19 +84,53 @@ export function Controller<T extends { new (...args: any[]): BaseController }>()
// Loop over all the methods in the decorated class looking for methods that use the POST decorator
Object.getOwnPropertyNames(target.prototype)
// Find all methods that have a Post metadata key (POST decorator)
.filter((method) => Reflect.getMetadata('Post', target.prototype, method))
.filter((method) => Reflect.getMetadata(POST_METADATA_KEY, target.prototype, method))
.map((method) => {
// Get the method
const fn = target.prototype[method];
// Get the metadata object (which contains a path and middleware)
const postRoute = Reflect.getMetadata('Post', target.prototype, method);
const postRoute = Reflect.getMetadata(POST_METADATA_KEY, target.prototype, method);
const path = postRoute.path;
const middleware: NextFunction[] = postRoute.middleware;
// Bind the method to the class instance
app.post(path, ...middleware, fn.bind(controller));
});
// Loop over all the methods in the decorated class looking for methods that use the `@PUT` decorator
Object.getOwnPropertyNames(target.prototype)
// Find all methods that have the associated metadata key (`@PUT` decorator)
.filter((method) => Reflect.getMetadata(PUT_METADATA_KEY, target.prototype, method))
.map((method) => {
// Get the method
const fn = target.prototype[method];
// Get the metadata object (which contains a path and middleware)
const putRoute = Reflect.getMetadata(PUT_METADATA_KEY, target.prototype, method);
const path = putRoute.path;
const middleware = putRoute.middleware;
// Bind the method to the class instance
app.put(path, ...middleware, fn.bind(controller));
});
// Loop over all the methods in the decorated class looking for methods that use the `@DELETE` decorator
Object.getOwnPropertyNames(target.prototype)
// Find all methods that have the associated metadata key (`@DELETE` decorator)
.filter((method) => Reflect.getMetadata(DELETE_METADATA_KEY, target.prototype, method))
.map((method) => {
// Get the method
const fn = target.prototype[method];
// Get the metadata object (which contains a path and middleware)
const deleteRoute = Reflect.getMetadata(DELETE_METADATA_KEY, target.prototype, method);
const path = deleteRoute.path;
const middleware = deleteRoute.middleware;
// Bind the method to the class instance
app.delete(path, ...middleware, fn.bind(controller));
});
}
}
}