@notjustcoders/ioc-arise
Version:
Arise type-safe IoC containers from your code. Zero overhead, zero coupling.
70 lines • 3.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CircularDependencyDetector = void 0;
const topological_sorter_1 = require("./topological-sorter");
class CircularDependencyDetector {
/**
* Detects circular dependencies in a list of classes
* @param classes - Array of analyzed classes
* @returns Array of cycles, where each cycle is an array of class names involved
*/
static detect(classes) {
// Build a map from interface/class name to actual class name
const nameToClassName = new Map();
classes.forEach((cls) => {
nameToClassName.set(cls.name, cls.name); // Class name maps to itself
if (cls.interfaceName) {
nameToClassName.set(cls.interfaceName, cls.name); // Interface name maps to implementing class
}
});
const dependencyGraph = new Map();
// Build dependency graph using actual class names
classes.forEach((cls) => {
const resolvedDeps = cls.dependencies
.map((dep) => nameToClassName.get(dep.name))
.filter((name) => name !== undefined);
dependencyGraph.set(cls.name, resolvedDeps);
});
// Use TopologicalSorter to detect cycles
const result = topological_sorter_1.TopologicalSorter.sort(dependencyGraph);
return result.cycles;
}
/**
* Detects circular dependencies between modules
* @param moduleGroupedClasses - Map of module name to classes in that module
* @returns Array of cycles, where each cycle is an array of module names involved
*/
static detectModuleCycles(moduleGroupedClasses) {
const moduleDependencyGraph = new Map();
// Build module dependency graph
for (const [moduleName, classes] of moduleGroupedClasses.entries()) {
const moduleDeps = new Set();
// For each class in this module, find which modules its dependencies belong to
for (const cls of classes) {
for (const dep of cls.dependencies) {
// Find which module this dependency belongs to
for (const [depModuleName, depModuleClasses] of moduleGroupedClasses.entries()) {
if (depModuleName === moduleName)
continue; // Skip self-dependencies
// Check if the dependency is in this other module (by interface name or class name)
const isInModule = depModuleClasses.some(depCls => depCls.interfaceName === dep.name || depCls.name === dep.name);
if (isInModule) {
moduleDeps.add(depModuleName);
}
}
}
}
moduleDependencyGraph.set(moduleName, moduleDeps);
}
// Convert Set to Array for TopologicalSorter
const graphForSorter = new Map();
for (const [module, deps] of moduleDependencyGraph.entries()) {
graphForSorter.set(module, Array.from(deps));
}
// Use TopologicalSorter to detect cycles
const result = topological_sorter_1.TopologicalSorter.sort(graphForSorter);
return result.cycles;
}
}
exports.CircularDependencyDetector = CircularDependencyDetector;
//# sourceMappingURL=circular-dependency-detector.js.map