(workflow: Workflow)
| 91 | // in the pre-phase before any user pause. |
| 92 | |
| 93 | function identifyBranches(workflow: Workflow): { |
| 94 | preExecExtNodes: WFNode[] |
| 95 | branches: Map<string, WFNode[]> |
| 96 | waitIds: string[] |
| 97 | parentWait: Map<string, string | null> |
| 98 | ordered: WFNode[] |
| 99 | } { |
| 100 | const ordered = topoSort(workflow.nodes, workflow.edges) |
| 101 | const nodeMap = new Map(workflow.nodes.map((n) => [n.id, n])) |
| 102 | const waitIds = ordered.filter((n) => isBranchStarter(n.type)).map((n) => n.id) |
| 103 | |
| 104 | // A node is owned by its single nearest upstream Wait (dominance). This lets |
| 105 | // Wait → … → Wait chains nest: nodes after the 2nd Wait belong to it, not the 1st. |
| 106 | const branchOwner = new Map<string, string>() |
| 107 | for (const node of workflow.nodes) { |
| 108 | if (isBranchStarter(node.type)) continue |
| 109 | const nearest = nearestUpstreamWaits(node.id, workflow.edges, nodeMap) |
| 110 | if (nearest.size === 1) branchOwner.set(node.id, [...nearest][0]) |
| 111 | } |
| 112 | |
| 113 | // Each Wait's parent = its own nearest upstream Wait (null if top-level). |
| 114 | const parentWait = new Map<string, string | null>() |
| 115 | for (const w of waitIds) { |
| 116 | const nearest = nearestUpstreamWaits(w, workflow.edges, nodeMap) |
| 117 | parentWait.set(w, nearest.size === 1 ? [...nearest][0] : null) |
| 118 | } |
| 119 | |
| 120 | const branches = new Map<string, WFNode[]>() |
| 121 | for (const w of waitIds) branches.set(w, []) |
| 122 | const preExecExtNodes: WFNode[] = [] |
| 123 | for (const node of ordered) { |
| 124 | if (node.type !== 'extensionNode' || !node.data.enabled) continue |
| 125 | const owner = branchOwner.get(node.id) |
| 126 | if (owner) branches.get(owner)!.push(node) |
| 127 | else preExecExtNodes.push(node) |
| 128 | } |
| 129 | |
| 130 | return { preExecExtNodes, branches, waitIds, parentWait, ordered } |
| 131 | } |
| 132 | |
| 133 | // ─── Per-node execution ────────────────────────────────────────────────────── |
| 134 | // Resolves inputs (walking through Wait passthroughs), runs the extension |
no test coverage detected