(graph: INodeDirectedGraph, endNodeId: string)
| 228 | * @param {string} endNodeId |
| 229 | */ |
| 230 | export const getStartingNodes = (graph: INodeDirectedGraph, endNodeId: string) => { |
| 231 | const depthQueue: IDepthQueue = { |
| 232 | [endNodeId]: 0 |
| 233 | } |
| 234 | |
| 235 | // Assuming that this is a directed acyclic graph, there will be no infinite loop problem. |
| 236 | const walkGraph = (nodeId: string) => { |
| 237 | const depth = depthQueue[nodeId] |
| 238 | graph[nodeId].flatMap((id) => { |
| 239 | depthQueue[id] = Math.max(depthQueue[id] ?? 0, depth + 1) |
| 240 | walkGraph(id) |
| 241 | }) |
| 242 | } |
| 243 | |
| 244 | walkGraph(endNodeId) |
| 245 | |
| 246 | const maxDepth = Math.max(...Object.values(depthQueue)) |
| 247 | const depthQueueReversed: IDepthQueue = {} |
| 248 | for (const nodeId in depthQueue) { |
| 249 | if (Object.prototype.hasOwnProperty.call(depthQueue, nodeId)) { |
| 250 | depthQueueReversed[nodeId] = Math.abs(depthQueue[nodeId] - maxDepth) |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | const startingNodeIds = Object.entries(depthQueueReversed) |
| 255 | .filter(([_, depth]) => depth === 0) |
| 256 | .map(([id, _]) => id) |
| 257 | |
| 258 | return { startingNodeIds, depthQueue: depthQueueReversed } |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | * Get all connected nodes from startnode |
no test coverage detected