( childRef: string, parentRef: string, type: 'fulfilled' | 'skipped', readyQueue: ReadyItem[], pending: Set<string>, nodeStates: Map<string, NodeState>, successEdges: Map<string, WorkflowEdge[]>, onNodeSkipped?: (ref: string) => Promise<void>, )
| 283 | } |
| 284 | |
| 285 | async function processChild( |
| 286 | childRef: string, |
| 287 | parentRef: string, |
| 288 | type: 'fulfilled' | 'skipped', |
| 289 | readyQueue: ReadyItem[], |
| 290 | pending: Set<string>, |
| 291 | nodeStates: Map<string, NodeState>, |
| 292 | successEdges: Map<string, WorkflowEdge[]>, |
| 293 | onNodeSkipped?: (ref: string) => Promise<void>, |
| 294 | ) { |
| 295 | if (!pending.has(childRef)) return; |
| 296 | |
| 297 | const state = nodeStates.get(childRef); |
| 298 | if (!state || state.failureTriggered || state.skipped) return; |
| 299 | |
| 300 | if (state.successParents.has(parentRef)) { |
| 301 | state.successParents.delete(parentRef); |
| 302 | |
| 303 | if (type === 'skipped') { |
| 304 | state.skippedParents.add(parentRef); |
| 305 | } |
| 306 | } else { |
| 307 | // Already processed this parent |
| 308 | return; |
| 309 | } |
| 310 | |
| 311 | if (state.strategy === 'all') { |
| 312 | if (state.successParents.size === 0) { |
| 313 | if (state.skippedParents.size > 0) { |
| 314 | // If 'all' strategy and at least one parent skipped, we skip. |
| 315 | await handleSkip(childRef, readyQueue, pending, nodeStates, successEdges, onNodeSkipped); |
| 316 | } else if (!state.triggeredBySuccess) { |
| 317 | state.triggeredBySuccess = true; |
| 318 | readyQueue.push({ ref: childRef, context: { joinStrategy: state.strategy } }); |
| 319 | } |
| 320 | } |
| 321 | } else { |
| 322 | // ANY / FIRST |
| 323 | if (type === 'fulfilled' && !state.triggeredBySuccess) { |
| 324 | state.triggeredBySuccess = true; |
| 325 | readyQueue.push({ |
| 326 | ref: childRef, |
| 327 | context: { joinStrategy: state.strategy, triggeredBy: parentRef }, |
| 328 | }); |
| 329 | } else if (state.successParents.size === 0) { |
| 330 | // All parents finished. |
| 331 | // If we haven't been triggered yet, it means everything skipped. |
| 332 | if (!state.triggeredBySuccess) { |
| 333 | await handleSkip(childRef, readyQueue, pending, nodeStates, successEdges, onNodeSkipped); |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | async function handleSkip( |
| 340 | ref: string, |
no test coverage detected