Skip to content

Commit

Permalink
perf(core): use topology tree for calculating distance
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Feb 10, 2025
1 parent bf7768b commit c743c74
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 26 deletions.
60 changes: 60 additions & 0 deletions packages/core/injector/topology-tree/topology-tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Module } from '../module';
import { TreeNode } from './tree-node';

export class TopologyTree {
private root: TreeNode<Module>;
private links: Map<
Module,
{
node: TreeNode<Module>;
depth: number;
}
> = new Map();

static from(root: Module) {
const tree = new TopologyTree();
tree.root = new TreeNode<Module>({
value: root,
parent: null,
});

tree.traverseAndCloneTree(tree.root);
return tree;
}

public walk(callback: (value: Module, depth: number) => void) {
function walkNode(node: TreeNode<Module>, depth = 1) {
callback(node.value, depth);
node.children.forEach(child => walkNode(child, depth + 1));
}
walkNode(this.root);
}

private traverseAndCloneTree(node: TreeNode<Module>, depth = 1) {
node.value.imports.forEach(child => {
if (!child) {
return;
}
if (this.links.has(child)) {
const existingSubtree = this.links.get(child)!;
if (existingSubtree.depth < depth) {
existingSubtree.node.relink(node);
existingSubtree.depth = depth;
}
return;
}

const childNode = new TreeNode<Module>({
value: child,
parent: node,
});
node.addChild(childNode);
this.links.set(child, {
node: childNode,
depth,
});

this.traverseAndCloneTree(childNode, depth + 1);
});
}
}
23 changes: 23 additions & 0 deletions packages/core/injector/topology-tree/tree-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export class TreeNode<T> {
public readonly value: T;
public readonly children = new Set<TreeNode<T>>();
private parent: TreeNode<T> | null;

constructor({ value, parent }: { value: T; parent: TreeNode<T> | null }) {
this.value = value;
this.parent = parent;
}

addChild(child: TreeNode<T>) {
this.children.add(child);
}

removeChild(child: TreeNode<T>) {
this.children.delete(child);
}

relink(parent: TreeNode<T>) {
this.parent = parent;
this.parent.addChild(this);
}
}
35 changes: 9 additions & 26 deletions packages/core/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { NestContainer } from './injector/container';
import { InstanceWrapper } from './injector/instance-wrapper';
import { InternalCoreModuleFactory } from './injector/internal-core-module/internal-core-module-factory';
import { Module } from './injector/module';
import { TopologyTree } from './injector/topology-tree/topology-tree';
import { GraphInspector } from './inspector/graph-inspector';
import { UuidFactory } from './inspector/uuid-factory';
import { ModuleDefinition } from './interfaces/module-definition.interface';
Expand Down Expand Up @@ -395,37 +396,19 @@ export class DependenciesScanner {

public calculateModulesDistance() {
const modulesGenerator = this.container.getModules().values();

// Skip "InternalCoreModule" from calculating distance
modulesGenerator.next();

const calculateDistance = (
moduleRef: Module,
distance = 1,
modulesStack: Module[] = [],
) => {
const localModulesStack = [...modulesStack];
if (!moduleRef || localModulesStack.includes(moduleRef)) {
const rootModule = modulesGenerator.next().value!;

// Convert modules to an acyclic connected graph
const tree = TopologyTree.from(rootModule);
tree.walk((moduleRef, depth) => {
if (moduleRef.isGlobal) {
return;
}
localModulesStack.push(moduleRef);

const moduleImports = moduleRef.imports;
moduleImports.forEach(importedModuleRef => {
if (importedModuleRef) {
if (
distance > importedModuleRef.distance &&
!importedModuleRef.isGlobal
) {
importedModuleRef.distance = distance;
}
calculateDistance(importedModuleRef, distance + 1, localModulesStack);
}
});
};

const rootModule = modulesGenerator.next().value;
calculateDistance(rootModule!);
moduleRef.distance = depth;
});
}

public async insertImport(related: any, token: string, context: string) {
Expand Down

0 comments on commit c743c74

Please sign in to comment.