(subgraph: Subgraph, entryPoints: Node[])
| 122 | * Format a subgraph as an ASCII tree structure |
| 123 | */ |
| 124 | export function formatSubgraphTree(subgraph: Subgraph, entryPoints: Node[]): string { |
| 125 | const lines: string[] = []; |
| 126 | const printed = new Set<string>(); |
| 127 | |
| 128 | // Build adjacency list for outgoing edges |
| 129 | const outgoing = new Map<string, Edge[]>(); |
| 130 | for (const edge of subgraph.edges) { |
| 131 | const existing = outgoing.get(edge.source) ?? []; |
| 132 | existing.push(edge); |
| 133 | outgoing.set(edge.source, existing); |
| 134 | } |
| 135 | |
| 136 | // Print each entry point as a tree root |
| 137 | for (const entry of entryPoints) { |
| 138 | formatNodeTree(entry, subgraph, outgoing, printed, lines, 0, ''); |
| 139 | lines.push(''); // Blank line between trees |
| 140 | } |
| 141 | |
| 142 | // Print any remaining nodes not reached from entry points |
| 143 | const remaining: Node[] = []; |
| 144 | for (const node of subgraph.nodes.values()) { |
| 145 | if (!printed.has(node.id)) { |
| 146 | remaining.push(node); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | if (remaining.length > 0 && remaining.length <= 10) { |
| 151 | lines.push('Other relevant symbols:'); |
| 152 | for (const node of remaining) { |
| 153 | const location = node.startLine ? `:${node.startLine}` : ''; |
| 154 | lines.push(` ${node.kind}: ${node.name} (${node.filePath}${location})`); |
| 155 | } |
| 156 | } else if (remaining.length > 10) { |
| 157 | lines.push(`... and ${remaining.length} more related symbols`); |
| 158 | } |
| 159 | |
| 160 | return lines.join('\n').trim(); |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * Format a single node and its relationships |
nothing calls this directly
no test coverage detected