whaler
Version:
Define and run multi-container applications with Docker
109 lines (95 loc) • 2.26 kB
JavaScript
;
const compose = require('koa-compose');
const OWNER = Symbol('owner');
const TYPES = Symbol('types');
const MODULES = Symbol('modules');
class Module {
/**
* @api public
*/
constructor(owner) {
this[OWNER] = owner;
this[TYPES] = {};
}
/**
* @api public
*/
add(type, fn) {
if (!this[TYPES].hasOwnProperty(type)) {
this[TYPES][type] = [];
}
this[TYPES][type].push(fn);
return (/* remove */) => {
const index = this[TYPES][type].indexOf(fn);
if (-1 !== index) {
this[TYPES][type].splice(index, 1);
}
};
}
/**
* @api public
*/
get(type) {
if (this[TYPES].hasOwnProperty(type)) {
return this[TYPES][type];
}
return [];
}
}
class Application {
/**
* @api public
*/
constructor() {
this[MODULES] = {};
}
/**
* @api private
*/
getModule(name) {
if (!this[MODULES][name]) {
this[MODULES][name] = new Module(this);
}
return this[MODULES][name];
}
/**
* @api public
*/
before(name, fn) {
return this.getModule(name).add('before', fn);
}
/**
* @api public
*/
after(name, fn) {
return this.getModule(name).add('after', fn);
}
/**
* @api public
*/
on(name, fn) {
const module = this.getModule(name);
if (module.get('on').length) {
throw Error('Module with name `' + name + '` already defined.');
}
return module.add('on', fn);
}
/**
* @api public
*/
emit(name, options, ...args) {
const ctx = { name, options, args, result: null };
const handler = fn => async (ctx, next) => {
await fn(ctx);
await next();
};
const module = this.getModule(name);
const fn = compose([
compose(module.get('before').map(handler)),
compose(module.get('on').map(handler)),
compose(module.get('after').map(handler))
]);
return fn(ctx).then(() => ctx.result);
}
}
module.exports = Application;