* Recursive DFS helper
(
node: Node,
depth: number,
opts: Required<TraversalOptions>,
nodes: Map<string, Node>,
edges: Edge[],
visited: Set<string>
)
| 180 | * Recursive DFS helper |
| 181 | */ |
| 182 | private dfsRecursive( |
| 183 | node: Node, |
| 184 | depth: number, |
| 185 | opts: Required<TraversalOptions>, |
| 186 | nodes: Map<string, Node>, |
| 187 | edges: Edge[], |
| 188 | visited: Set<string> |
| 189 | ): void { |
| 190 | if (visited.has(node.id) || nodes.size >= opts.limit || depth >= opts.maxDepth) { |
| 191 | return; |
| 192 | } |
| 193 | |
| 194 | visited.add(node.id); |
| 195 | |
| 196 | // Get adjacent edges |
| 197 | const adjacentEdges = this.getAdjacentEdges(node.id, opts.direction, opts.edgeKinds); |
| 198 | |
| 199 | // Batch-fetch unvisited neighbors (was N+1 per DFS step). |
| 200 | const wantIds = adjacentEdges |
| 201 | .map((e) => (e.source === node.id ? e.target : e.source)) |
| 202 | .filter((id) => !visited.has(id)); |
| 203 | const neighborNodes = wantIds.length > 0 ? this.queries.getNodesByIds(wantIds) : new Map(); |
| 204 | |
| 205 | for (const edge of adjacentEdges) { |
| 206 | // Cap per-add, not just at the top of each frame: the top-of-function |
| 207 | // guard only stops the next recursion, so without this every sibling of |
| 208 | // the first over-budget child still got inserted, overshooting |
| 209 | // `opts.limit` by a node's full fan-out (#1088). |
| 210 | if (nodes.size >= opts.limit) break; |
| 211 | |
| 212 | const nextNodeId = edge.source === node.id ? edge.target : edge.source; |
| 213 | if (visited.has(nextNodeId)) continue; |
| 214 | |
| 215 | const nextNode = neighborNodes.get(nextNodeId); |
| 216 | if (!nextNode) continue; |
| 217 | |
| 218 | // Apply node kind filter |
| 219 | if (opts.nodeKinds && opts.nodeKinds.length > 0 && !opts.nodeKinds.includes(nextNode.kind)) { |
| 220 | continue; |
| 221 | } |
| 222 | |
| 223 | // Add node and edge to result |
| 224 | nodes.set(nextNode.id, nextNode); |
| 225 | edges.push(edge); |
| 226 | |
| 227 | // Recurse |
| 228 | this.dfsRecursive(nextNode, depth + 1, opts, nodes, edges, visited); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Get adjacent edges based on direction |
no test coverage detected