UNPKG

dipend

Version:

This library implements a dependency injection (DI) system in JavaScript/TypeScript, making it easier to manage dependencies in modular applications.

264 lines (262 loc) 11.3 kB
/* * Copyright 2025 Saulo V. Alvarenga. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DependencyContainer = void 0; const add_dependency_1 = require("./commands/add-dependency"); const resolve_dependency_1 = require("./commands/resolve-dependency"); const check_for_cyclic_dependencies_1 = require("./commands/check-for-cyclic-dependencies"); const resolve_singletons_1 = require("./commands/resolve-singletons"); const dependency_1 = require("./dependency"); const dependency_2 = require("./dependency"); const token_1 = require("./token"); const enums_1 = require("./enums"); const exceptions_1 = require("./exceptions"); const exceptions_2 = require("./exceptions"); /** * Class representing a Dependency Container for managing dependencies. */ class DependencyContainer { dependencyTokenStore = new token_1.TokenStore(); dependencyStore = new dependency_2.DependencyStore(); dependencyResolver = new dependency_1.DependencyResolver(this.dependencyStore); dependencyTokenType = new token_1.TokenTypeResolver(); dependencyTokenName = new token_1.TokenNameResolver(); exceptionHandler = new exceptions_1.ExceptionHandler(this.dependencyTokenStore, this.dependencyTokenType, this.dependencyTokenName); addDependencyCommandHandler = new add_dependency_1.AddDependencyCommandHandler(this.dependencyTokenStore, this.dependencyStore); checkForCyclicDependenciesCommandHandler = new check_for_cyclic_dependencies_1.CheckForCyclicDependenciesCommandHandler(this.dependencyStore); resolveDependencyCommandHandler = new resolve_dependency_1.ResolveDependencyCommandHandler(this.dependencyTokenStore, this.dependencyResolver); resolveSingletonsCommandHandler = new resolve_singletons_1.ResolveSingletonsCommandHandler(this.dependencyStore, this.dependencyResolver); isContainerBuilt = false; isBuildSingletonsRequired = false; dependencyContainerToken = DependencyContainer; /** * Constructor to initialize the DependencyContainer with optional configurations. * @param {Object} [config] - Configuration options for the container. */ constructor(config) { this.loadConfigs(config); } loadConfigs(config) { if (!config?.disableDefaultResolveLifecycleStrategies) { this.dependencyResolver.setDefaultResolveLifecycleStrategies(); } if (!config?.disableDefaultTokenTypeCheckers) { this.dependencyTokenType.setDefaultTokenTypeCheckers(); } if (!config?.disableDefaultTokenNameStrategies) { this.dependencyTokenName.setDefaultTokenNameStrategies(); } if (config?.buildSingletonsRequired !== undefined) { this.isBuildSingletonsRequired = config?.buildSingletonsRequired; } if (config?.customDependencyContainerToken !== undefined) { this.dependencyContainerToken = config.customDependencyContainerToken; } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: this.dependencyContainerToken, instance: this, }); } exceptionHandlerWrapper(callback) { try { return callback(); } catch (err) { if (err instanceof exceptions_2.BaseDependencyContainerException) { throw this.exceptionHandler.handle(err); } throw err; } } /** * Builds all singleton dependencies. * @returns {DependencyContainer} The current instance of the container. */ buildSingletons() { this.exceptionHandlerWrapper(() => this.resolveSingletonsCommandHandler.handle()); this.isContainerBuilt = true; return this; } checkForCyclicDependencies() { this.exceptionHandlerWrapper(() => this.checkForCyclicDependenciesCommandHandler.handle()); return this; } addDependency(config) { const dependencyToken = config.dependencyToken || config.classConstructor; if (dependencyToken === undefined) { throw new Error("Invalid configuration, missing dependency token."); } const addDependencyCommandInput = new add_dependency_1.AddDependencyCommandInput(dependencyToken, config.qualifierToken, config.lifecycle, config.classConstructor, config.builder, config.instance); this.exceptionHandlerWrapper(() => this.addDependencyCommandHandler.handle(addDependencyCommandInput)); } retrieveDependency(config) { if (config?.dependencyToken === undefined) { throw new Error("Missing dependency token."); } if (this.isContainerBuilt === false && this.isBuildSingletonsRequired === true) { throw new Error("Dependency container not initialized. Please call the 'build()' method before attempting to retrieve dependencies."); } const resolveDependencyCommandInput = new resolve_dependency_1.ResolveDependencyCommandInput(config.dependencyToken, config.qualifierToken); const output = this.exceptionHandlerWrapper(() => this.resolveDependencyCommandHandler.handle(resolveDependencyCommandInput)); return output.dependencyInstance; } addSingletonBuilder(config) { if (config.builder === undefined) { throw new Error("Invalid configuration, missing builder function."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, builder: config.builder, }); } addMappedSingletonBuilder(config) { if (config.qualifierToken === undefined) { throw new Error("Invalid configuration, missing qualifier token."); } if (config.builder === undefined) { throw new Error("Invalid configuration, missing builder function."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, builder: config.builder, }); } addSingletonInstance(config) { if (config.instance === undefined) { throw new Error("Invalid configuration, missing instance."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, instance: config.instance, }); } addMappedSingletonInstance(config) { if (config.qualifierToken === undefined) { throw new Error("Invalid configuration, missing qualifier token."); } if (config.instance === undefined) { throw new Error("Invalid configuration, missing instance."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, instance: config.instance, }); } addSingleton(config) { if (config?.classConstructor === undefined) { throw new Error("Invalid configuration, missing class constructor."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, classConstructor: config.classConstructor, }); } addMappedSingleton(config) { if (config.qualifierToken === undefined) { throw new Error("Invalid configuration, missing qualifier token."); } if (config.classConstructor === undefined) { throw new Error("Invalid configuration, missing class constructor."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.SINGLETON, dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, classConstructor: config.classConstructor, }); } addTransientBuilder(config) { if (config.builder === undefined) { throw new Error("Invalid configuration, missing builder function."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.TRANSIENT, dependencyToken: config.dependencyToken, builder: config.builder, }); } addMappedTransientBuilder(config) { if (config.qualifierToken === undefined) { throw new Error("Invalid configuration, missing qualifier token."); } if (config.builder === undefined) { throw new Error("Invalid configuration, missing builder function."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.TRANSIENT, dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, builder: config.builder, }); } addTransient(config) { if (config?.classConstructor === undefined) { throw new Error("Invalid configuration, missing class constructor."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.TRANSIENT, dependencyToken: config.dependencyToken, classConstructor: config.classConstructor, }); } addMappedTransient(config) { if (config.qualifierToken === undefined) { throw new Error("Invalid configuration, missing qualifier token."); } if (config.classConstructor === undefined) { throw new Error("Invalid configuration, missing class constructor."); } this.addDependency({ lifecycle: enums_1.LifecycleEnum.TRANSIENT, dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, classConstructor: config.classConstructor, }); } getDependency(config) { return this.retrieveDependency({ dependencyToken: config?.dependencyToken, }); } getMappedDependency(config) { if (config.dependencyToken === undefined || config.qualifierToken === undefined) { throw new Error("Missing dependency or qualifier token."); } return this.retrieveDependency({ dependencyToken: config.dependencyToken, qualifierToken: config.qualifierToken, }); } /** * Resets the dependency container to its initial state. * Remove all dependencies. */ reset() { this.dependencyTokenStore.reset(); this.dependencyStore.reset(); this.isContainerBuilt = false; } } exports.DependencyContainer = DependencyContainer;