import { IInstantiationService } from '#/_base/di/instantiation'; import type { InstantiationService } from '#/_base/di/instantiationService'; import { ScopeActivation, registerScopedService } from '#/_base/di/scope'; import { LifecycleScope } from '#/app/scopes'; import { IDebugGraphService, type DebugGraph, type DebugGraphEdge, type DebugGraphNode, } from './debugGraph'; import { walkScopeContainers } from './scopeTree'; export class DebugGraphService implements IDebugGraphService { declare readonly _serviceBrand: undefined; private readonly root: InstantiationService; constructor(@IInstantiationService instantiation: IInstantiationService) { this.root = instantiation as InstantiationService; } graph(): DebugGraph { const infos = walkScopeContainers(this.root); const pathByContainer = new Map( infos.map((info) => [info.container, info.path]), ); const nodes = new Map(); for (const info of infos) { const states = new Map( info.container.cascade.unitsSnapshot().map((unit) => [unit.token, unit]), ); for (const registration of info.container.servicesSnapshot()) { const id = nodeId(info.path, registration.token); nodes.set(id, { id, token: registration.token, scopePath: info.path, uid: registration.uid, state: states.get(registration.token)?.state, }); } } const pathOf = (scope: object): string => pathByContainer.get(scope as InstantiationService) ?? `#${this.root.cascadeTree.seqOf(scope)}`; const edges: DebugGraphEdge[] = []; const endpointNode = (path: string, token: string): string => { const id = nodeId(path, token); if (!nodes.has(id)) { nodes.set(id, { id, token, scopePath: path }); } return id; }; for (const edge of this.root.dependencyGraph.edges()) { edges.push({ from: endpointNode(pathOf(edge.consumer.scope), edge.consumer.token.toString()), to: endpointNode(pathOf(edge.dependency.scope), edge.dependency.token.toString()), kind: edge.kind, }); } return { nodes: [...nodes.values()], edges }; } } function nodeId(scopePath: string, token: string): string { return `${scopePath}::${token}`; } registerScopedService( LifecycleScope.App, IDebugGraphService, DebugGraphService, ScopeActivation.OnDemand, 'debug', );