UNPKG

han-prev-core

Version:

Core framework for Han - A powerful Node.js framework inspired by NestJS

213 lines 8.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.container = void 0; require("reflect-metadata"); const decorators_1 = require("../decorators"); const utils_1 = require("../utils"); class Container { constructor() { this.instances = new Map(); this.singletons = new Map(); this.processedModules = new Set(); this.metadataCache = new Map(); this.dependencyCache = new Map(); this.asyncProviders = new Map(); this.moduleMiddlewareConfigs = new Map(); this.lifecycleHooks = new Map(); } register(token, factory, singleton = false) { this.instances.set(token, { factory, singleton }); } resolve(token) { const registration = this.instances.get(token); if (!registration) { throw new Error(`No registration found for token: ${token}`); } if (registration.singleton) { if (!this.singletons.has(token)) { this.singletons.set(token, registration.factory()); } return this.singletons.get(token); } return registration.factory(); } registerProvider(provider) { const isSingleton = provider.scope !== "transient"; if (provider.useValue) { this.register(provider.provide, () => provider.useValue, true); } else if (provider.useFactory) { this.register(provider.provide, () => { const dependencies = provider.inject?.map((dep) => this.resolve(dep)) || []; const result = provider.useFactory(...dependencies); if (result instanceof Promise) { if (!this.asyncProviders.has(provider.provide)) { this.asyncProviders.set(provider.provide, result); } } return result; }, isSingleton); } else if (provider.useClass) { this.register(provider.provide, () => { const dependencies = provider.inject?.map((dep) => this.resolve(dep)) || []; return new provider.useClass(...dependencies); }, isSingleton); } } registerController(ControllerClass) { utils_1.Logger.debug(`Auto-registering controller: ${ControllerClass.name}`); this.register(ControllerClass.name, () => { return this.createInstance(ControllerClass); }, true); } createInstance(target) { let paramTypes = this.metadataCache.get(target); if (!paramTypes) { const metadata = Reflect.getMetadata("design:paramtypes", target); paramTypes = metadata || []; this.metadataCache.set(target, paramTypes); } const safeParamTypes = paramTypes || []; if (safeParamTypes.length === 0) { return new target(); } const injectionTokens = (0, decorators_1.getInjectionTokens)(target); const cacheKey = target.name; let dependencies = this.dependencyCache.get(cacheKey); if (!dependencies) { dependencies = this.resolveDependencies(safeParamTypes, target.name, injectionTokens); this.dependencyCache.set(cacheKey, dependencies); } const validDependencies = dependencies.filter((dep) => dep !== undefined); if (validDependencies.length !== safeParamTypes.length) { utils_1.Logger.debug(`${target.name} created with ${validDependencies.length}/${safeParamTypes.length} dependencies resolved`); } return new target(...validDependencies); } resolveDependencies(paramTypes, targetName, injectionTokens = {}) { return paramTypes.map((paramType, index) => { const customToken = injectionTokens[index]; if (customToken) { try { return this.resolve(customToken); } catch (error) { utils_1.Logger.error(`Could not resolve custom injection token '${customToken}' at parameter ${index} in ${targetName}`); throw error; } } if (!paramType || !paramType.name) { return undefined; } try { return this.resolve(paramType.name); } catch (error) { utils_1.Logger.debug(`Dependency resolution failed for ${paramType.name} at parameter ${index} in ${targetName}. Trying alternative resolution...`); for (const [token] of this.instances.entries()) { if (token.includes(paramType.name) || paramType.name.includes(token)) { try { return this.resolve(token); } catch { continue; } } } utils_1.Logger.warn(`Could not resolve dependency ${paramType.name} for ${targetName}`); return undefined; } }); } registerModule(moduleClass) { const isDynamicModule = moduleClass && moduleClass.module; const actualModule = isDynamicModule ? moduleClass.module : moduleClass; if (this.processedModules.has(actualModule)) { return; } this.processedModules.add(actualModule); let moduleMetadata; if (isDynamicModule) { moduleMetadata = moduleClass; } else { moduleMetadata = decorators_1.MetadataStorage.get(actualModule.prototype, decorators_1.METADATA_KEYS.MODULE); } if (!moduleMetadata) { throw new Error(`Module ${actualModule.name} is missing @Module decorator or DynamicModule metadata`); } if (moduleMetadata.imports) { moduleMetadata.imports.forEach((importedModule) => { this.registerModule(importedModule); }); } if (moduleMetadata.providers) { moduleMetadata.providers.forEach((provider) => { if (typeof provider === "function") { this.register(provider.name, () => { return this.createInstance(provider); }, true); } else { this.registerProvider(provider); } }); } if (moduleMetadata.controllers) { moduleMetadata.controllers.forEach((controller) => { this.registerController(controller); }); } } getModuleMetadata(moduleClass) { return decorators_1.MetadataStorage.get(moduleClass.prototype, decorators_1.METADATA_KEYS.MODULE); } async callOnModuleInit() { const initPromises = []; for (const instance of this.singletons.values()) { if (instance && typeof instance.onModuleInit === "function") { const result = instance.onModuleInit(); if (result instanceof Promise) { initPromises.push(result); } } } await Promise.all(initPromises); } async callOnModuleDestroy() { const destroyPromises = []; for (const instance of this.singletons.values()) { if (instance && typeof instance.onModuleDestroy === "function") { const result = instance.onModuleDestroy(); if (result instanceof Promise) { destroyPromises.push(result); } } } await Promise.all(destroyPromises); } async resolveAsyncProviders() { if (this.asyncProviders.size === 0) return; const entries = Array.from(this.asyncProviders.entries()); const results = await Promise.all(entries.map(([_, promise]) => promise)); entries.forEach(([token, _], index) => { this.singletons.set(token, results[index]); }); } configureModuleMiddleware(moduleClass, consumer) { this.moduleMiddlewareConfigs.set(moduleClass, consumer); } getModuleMiddlewareConfigs(moduleClass) { return this.moduleMiddlewareConfigs.get(moduleClass); } getAllMiddlewareConfigs() { return this.moduleMiddlewareConfigs; } } const container = new Container(); exports.container = container; container.register("Logger", () => utils_1.Logger, true); //# sourceMappingURL=container.js.map