@reflet/express
Version:
Well-defined and well-typed express decorators
90 lines (89 loc) • 2.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractApplicationClass = exports.Application = void 0;
const express = require("express");
const register_1 = require("./register");
const reflet_error_1 = require("./reflet-error");
const metadata_map_1 = require("./metadata-map");
const METAKEY_APPLICATION = Symbol('application');
/**
* Express application class to extend, to apply the decorators with a global behavior.
*
* _Constructor simply returns an express application, augmented with `register` method._
*
* @example
* ```ts
* @Send({ json: true })
* @Use(express.json())
* class App extends Application {
* @Get('/healthcheck')
* healthcheck() {
* return { success: true }
* }
* }
*
* @Router('/foo')
* class FooRouter {
* @Get()
* list() {
* return db.collection('foo').find({})
* }
* }
*
* const app = new App()
* app.register([FooRouter])
* app.listen(3000)
* ```
* ------
* @public
*/
class Application {
constructor() {
const app = express();
mixinApplication(app, this.constructor);
// As the constructor returns an express app, we must keep the class reference
// to retrieve metadata attached to its children.
const metadata = {
class: this.constructor,
registered: false,
};
(0, metadata_map_1.defineMetadata)(METAKEY_APPLICATION, metadata, app);
return app;
}
register(routers = []) {
(0, register_1.register)(this, routers);
return this;
}
}
exports.Application = Application;
/**
* @internal
*/
function mixinApplication(target, source) {
// Build the prototype chain with the top parent as first item, to apply inheritance in the right order.
const protoChain = [];
let protoChainLink = source;
do {
protoChain.unshift(protoChainLink);
protoChainLink = Object.getPrototypeOf(protoChainLink);
} while (protoChainLink !== Function.prototype && protoChainLink !== Object.prototype);
for (const proto of protoChain) {
const keys = Object.getOwnPropertyNames(proto.prototype);
for (const key of keys) {
if (key === 'constructor')
continue;
if (key in target) {
throw new reflet_error_1.RefletExpressError('EXPRESS_PROPERTY_PROTECTED', `Cannot overwrite "${key}" on express application.`);
}
const descriptor = Object.getOwnPropertyDescriptor(proto.prototype, key);
Object.defineProperty(target, key, descriptor);
}
}
}
/**
* @internal
*/
function extractApplicationClass(target) {
return (0, metadata_map_1.getMetadata)(METAKEY_APPLICATION, target);
}
exports.extractApplicationClass = extractApplicationClass;