const { push } = Array.prototype; export type Middleware = ( context: C, next: () => Promise ) => Promise | any; export class Stack { length = 0; use(...middlewares: Middleware[]) { push.apply(this, middlewares); return this; } execute(context?: C, depth = 0) { const middleware: Middleware | undefined = this[depth]; if (middleware instanceof Function) return middleware( context, this.execute.bind(this, context, ++depth) ); } mount(condition: (context: C) => boolean, stack: Stack) { return this.use((context, next) => condition(context) ? stack.execute(context) : next() ); } }