import Module from './Module.ts' import Instantiable from '../../../../di/src/type/Instantiable.ts' import AppClass from '../../lifecycle/AppClass.ts' import {Collection} from '../../collection/Collection.ts' import {Service} from '../../../../di/src/decorator/Service.ts' import {Request} from '../Request.ts' import {Logging} from '../../service/logging/Logging.ts' export interface ModuleRegistrationFluency { before: (other?: Instantiable) => Kernel, after: (other?: Instantiable) => Kernel, first: () => Kernel, last: () => Kernel, core: () => Kernel, } export class KernelModuleNotFoundError extends Error { constructor(mod_name: string) { super(`The kernel module ${mod_name} is not registered with the kernel.`) } } @Service() export default class Kernel extends AppClass { protected preflight: Collection = new Collection() protected inflight?: Module protected postflight: Collection = new Collection() public async handle(request: Request): Promise { for ( const module of this.preflight.toArray() ) { request = await module.apply(request) } if ( this.inflight ) { request = await this.inflight.apply(request) } for ( const module of this.postflight.toArray() ) { request = await module.apply(request) } return request } public register(module: Instantiable): ModuleRegistrationFluency { this.make(Logging).verbose(`Registering HTTP kernel module: ${module.name}`) return { before: (other?: Instantiable): Kernel => { if ( !other ) { this.preflight = this.preflight.push(this.make(module)) return this } let found_index = this.preflight.find((mod: Module) => mod instanceof other) if ( typeof found_index !== 'undefined' ) { this.preflight = this.preflight.put(found_index, this.make(module)) } else { found_index = this.postflight.find((mod: Module) => mod instanceof other) } if ( typeof found_index !== 'undefined' ) { this.postflight = this.postflight.put(found_index, this.make(module)) } else { throw new KernelModuleNotFoundError(other.name) } return this }, after: (other?: Instantiable): Kernel => { if ( !other ) { this.postflight = this.postflight.push(this.make(module)) return this } let found_index = this.preflight.find((mod: Module) => mod instanceof other) if ( typeof found_index !== 'undefined' ) { this.preflight = this.preflight.put(found_index + 1, this.make(module)) } else { found_index = this.postflight.find((mod: Module) => mod instanceof other) } if ( typeof found_index !== 'undefined' ) { this.postflight = this.postflight.put(found_index + 1, this.make(module)) } else { console.log(this.preflight, this.postflight) throw new KernelModuleNotFoundError(other.name) } return this }, first: (): Kernel => { this.preflight = this.preflight.put(0, this.make(module)) return this }, last: (): Kernel => { this.postflight = this.postflight.push(this.make(module)) return this }, core: (): Kernel => { this.inflight = this.make(module) return this }, } } }