dipend
Version:
This library implements a dependency injection (DI) system in JavaScript/TypeScript, making it easier to manage dependencies in modular applications.
98 lines (96 loc) • 3.95 kB
JavaScript
/*
* 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.
*/
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DependencyStore = void 0;
const exceptions_1 = require("../exceptions");
class DependencyStore {
dependencies = new Map();
sortedDependenciesIdsCacheInvalidated = false;
sortedDependenciesIds = [];
addDependency(registry) {
this.sortedDependenciesIdsCacheInvalidated = true;
this.dependencies.set(registry.dependencyId, registry);
}
getDependency(dependencyId) {
const registry = this.dependencies.get(dependencyId);
if (registry === undefined) {
throw new exceptions_1.MissingDependencyException([dependencyId]);
}
return registry;
}
reset() {
this.dependencies.clear();
}
initializeGraphAndDegrees() {
const graph = new Map();
const inputDegree = new Map();
this.dependencies.forEach((dependencyRegistry, dependencyId) => {
inputDegree.set(dependencyId, inputDegree.get(dependencyId) ?? 0);
dependencyRegistry.implementationDetails.classConstructorDependenciesIds.forEach((classConstructorDependencyId) => {
inputDegree.set(classConstructorDependencyId, (inputDegree.get(classConstructorDependencyId) ?? 0) + 1);
if (!graph.has(dependencyId)) {
graph.set(dependencyId, []);
}
graph.get(dependencyId).push(classConstructorDependencyId);
});
});
return { graph, inputDegree };
}
performTopologicalSort(graph, inputDegree) {
const queue = [];
inputDegree.forEach((degree, dependencyId) => {
if (degree === 0) {
queue.push(dependencyId);
}
});
const sortedList = [];
while (queue.length > 0) {
const currentItem = queue.shift();
sortedList.push(currentItem);
if (!graph.has(currentItem)) {
continue;
}
graph.get(currentItem).forEach((dependent) => {
inputDegree.set(dependent, inputDegree.get(dependent) - 1);
if (inputDegree.get(dependent) === 0) {
queue.push(dependent);
}
});
}
return sortedList;
}
detectAndThrowCyclicDependencies(graph, inputDegree) {
const unresolved = Array.from(inputDegree.keys()).filter((dependencyId) => inputDegree.get(dependencyId) > 0 && graph.get(dependencyId));
if (unresolved.length > 0) {
throw new exceptions_1.CyclicDependenciesException(unresolved);
}
}
getSortedDependenciesIds() {
if (this.sortedDependenciesIdsCacheInvalidated) {
const { graph, inputDegree } = this.initializeGraphAndDegrees();
const sortedList = this.performTopologicalSort(graph, inputDegree);
if (sortedList.length !== this.dependencies.size) {
this.detectAndThrowCyclicDependencies(graph, inputDegree);
}
this.sortedDependenciesIds = sortedList.reverse();
this.sortedDependenciesIdsCacheInvalidated = false;
return this.sortedDependenciesIds;
}
return this.sortedDependenciesIds;
}
}
exports.DependencyStore = DependencyStore;