UNPKG

@hapiness/core

Version:

Project to have a HapiJS (https://hapijs.com/) based framework to create easier NodeJS back-end with some awesome features

244 lines 8.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const rxjs_1 = require("rxjs"); const logger_1 = require("./logger"); const metadata_1 = require("./metadata"); const decorators_1 = require("./decorators"); const di_1 = require("./di"); const enums_1 = require("./enums"); class ModuleManager { /** * Resolve into a tree of CoreModule * * @param {any} module * @returns Observable */ static resolve(module) { this.logger.debug(`Resolving module '${module.name}'`); return this.resolution(module); } static instantiate(module, providers) { this.logger.debug(`Instantiation of module '${module.name}'`); return this.instantiation(module, providers); } /** * Get all the tree modules * * @param {CoreModule} module * @returns CoreModule */ static getModules(module) { const lookup = (_module) => { return [] .concat(_module) .concat([] .concat(_module.modules) .filter(_ => !!_) .map(m => lookup(m)) .reduce((a, c) => a.concat(c), [])); }; return lookup(module); } /** * Helper to convert provider * to a CoreProvide type * * @param {any} provider * @returns CoreProvide */ static toCoreProvider(provider) { return (!!provider.provide ? provider : { provide: provider, useClass: provider }); } /** * =========================================================================== * * MODULE RESOLUTION * * =========================================================================== */ /** * Process module to CoreModule type * from metadata and the children * * @param {any} module * @param {CoreModule} parent? * @returns Observable */ static resolution(module, parent) { return rxjs_1.Observable .of(module) .map(_ => this.toCoreModuleWithProviders(_)) .flatMap(cmwp => this .extractMetadata(cmwp.module) .map(_ => ({ metadata: _, moduleWithProviders: cmwp }))) .flatMap(mcmwp => this .metadataToCoreModule(mcmwp.metadata, mcmwp.moduleWithProviders, parent) .map(_ => this.coreModuleParentConfigProviders(_)) .map(_ => Object.assign({ module: _ }, mcmwp))) .flatMap(data => rxjs_1.Observable .from(data.metadata.imports || []) .flatMap(_ => this.resolution(_, data.module)) .toArray() .do(_ => this.logger.debug(`'${data.module.name}' got ${_.length} children`)) .map(_ => Object.assign({ modules: _ }, data.module))); } /** * FIX for exported providers * that need internal config * * @todo find a better solution * @param {CoreModule} module * @returns CoreModule */ static coreModuleParentConfigProviders(module) { module.providers = [] .concat(module.providers) .concat((module.parent && module.parent.providers) ? module.parent.providers.filter(_ => (_.provide instanceof decorators_1.InjectionToken)) : []) .filter(_ => !!_); return module; } /** * Convert metadata to CoreModule type * * @param {HapinessModule} metadata * @param {CoreModuleWithProviders} moduleWithProviders * @param {CoreModule} parent? * @returns Observable */ static metadataToCoreModule(metadata, moduleWithProviders, parent) { return rxjs_1.Observable .of({ parent, token: moduleWithProviders.module, name: moduleWithProviders.module.name, version: metadata.version, exports: metadata.exports || [], declarations: metadata.declarations || [], providers: (metadata.providers || []) .concat(moduleWithProviders.providers) .map(_ => this.toCoreProvider(_)), level: !!parent ? parent.level === enums_1.ModuleLevel.ROOT ? enums_1.ModuleLevel.PRIMARY : enums_1.ModuleLevel.SECONDARY : enums_1.ModuleLevel.ROOT }) .do(_ => this.logger.debug(`Build CoreModule for '${_.name}'`)); } /** * Get HapinessModule metadata type * if does not exist, throw an error * * @param {Type<any>} module * @returns Observable */ static extractMetadata(module) { return rxjs_1.Observable .of(metadata_1.extractMetadataByDecorator(module, this.decoratorName)) .flatMap(_ => !!_ ? rxjs_1.Observable.of(_) : rxjs_1.Observable.throw(new Error(`Module '${module ? module.name : null}' resolution failed: No metadata`))); } /** * Make sure to convert module into * a CoreModuleWithProviders type * * @param {CoreModuleWithProviders|Type<any>} module * @returns CoreModuleWithProviders */ static toCoreModuleWithProviders(module) { return ((module && module['module']) ? module : { module, providers: [] }); } /** * =========================================================================== * * MODULE INSTANTIATION * * =========================================================================== */ /** * Create the module's DI * and instantiate the module * * @param {CoreModule} module * @param {CoreProvide[]} providers? * @param {CoreModule} parent? * @returns Observable */ static instantiation(module, providers, parent) { return rxjs_1.Observable .of(module) .flatMap(_ => rxjs_1.Observable .from(_.modules) .flatMap(child => this.instantiation(child, providers, parent)) .toArray() .map(children => Object.assign({}, _, { modules: children }))) .flatMap(_ => di_1.DependencyInjection .createAndResolve(this.collectProviders(_, providers)) .map(di => Object.assign({ di }, _))) .flatMap(_ => di_1.DependencyInjection .instantiateComponent(_.token, _.di) .map(instance => Object.assign({ instance }, _))) .flatMap(_ => this.instantiateLibs(_)); } /** * Instantiate and return array of libs * * @param {CoreModule} module * @returns Type */ static instantiateLibs(module) { return rxjs_1.Observable .from(module.declarations) .filter(_ => !!_ && !!metadata_1.extractMetadataByDecorator(_, 'Lib')) .flatMap(_ => di_1.DependencyInjection.instantiateComponent(_, module.di)) .toArray() .map(_ => module); } /** * Collect all providers to * inject into the DI * * @param {HapinessModule} module */ static collectProviders(module, providers) { this.logger.debug(`Collect providers for '${module.name}'`); return [] .concat(module.providers) .concat(providers) .filter(_ => !!_) .concat(this.extractExportedProviders(module)); } /** * Extract exported children providers * * @param {CoreModule} module * @returns CoreProvide[] */ static extractExportedProviders(module) { this.logger.debug(`Extract exported children providers for '${module.name}'`); return [] .concat(module.modules) .filter(_ => (!!_.exports && _.exports.length > 0)) .map(_ => [] .concat(_.exports) .concat(_.providers .filter(__ => (__.provide instanceof decorators_1.InjectionToken)))) .reduce((a, c) => a.concat(c), []) .filter(_ => !!_) .map(_ => this.toCoreProvider(_)); } } ModuleManager.decoratorName = 'HapinessModule'; ModuleManager.logger = new logger_1.InternalLogger('module'); exports.ModuleManager = ModuleManager; //# sourceMappingURL=module.js.map