| 483 | } |
| 484 | |
| 485 | async function toWireFlow( |
| 486 | cg: CodeGraph, |
| 487 | projectRoot: string, |
| 488 | cache: Map<string, FileCache>, |
| 489 | raw: readonly RawHop[], |
| 490 | extra: { boundary?: WireFlowBoundary | null; partial?: boolean } = {} |
| 491 | ): Promise<WireFlow> { |
| 492 | const hops: WireFlowHop[] = []; |
| 493 | for (let i = 0; i < raw.length; i++) { |
| 494 | const step = raw[i] as RawHop; |
| 495 | const previous = raw[i - 1]; |
| 496 | const next = raw[i + 1]; |
| 497 | // Forward: the edge into the NEXT hop was recorded at the line inside THIS |
| 498 | // body that makes the call. Backwards (a trail read from a callee up to its |
| 499 | // caller): this card IS the caller, and its own incoming edge carries the |
| 500 | // line where it calls the card before it. |
| 501 | let callRef: WireFlowCallRef | null = null; |
| 502 | if (next !== undefined && !next.upward && next.edge?.line) { |
| 503 | callRef = { |
| 504 | line: next.edge.line, |
| 505 | col: typeof next.edge.column === 'number' ? next.edge.column : null, |
| 506 | name: next.node.name, |
| 507 | targetId: next.node.id, |
| 508 | backwards: false, |
| 509 | }; |
| 510 | } else if (step.upward && previous !== undefined && step.edge?.line) { |
| 511 | callRef = { |
| 512 | line: step.edge.line, |
| 513 | col: typeof step.edge.column === 'number' ? step.edge.column : null, |
| 514 | name: previous.node.name, |
| 515 | targetId: previous.node.id, |
| 516 | backwards: true, |
| 517 | }; |
| 518 | } |
| 519 | // The connector's condition: the call site is in the caller's file — the |
| 520 | // previous card going down, this card itself when the reader stepped up. |
| 521 | const wireEdge = step.edge === null ? null : toFlowEdge(step.edge, step.upward); |
| 522 | if (wireEdge && step.edge?.line) { |
| 523 | const siteNode = step.upward ? step.node : previous?.node; |
| 524 | const when = siteNode ? await whenAt(cg, projectRoot, cache, siteNode, step.edge) : ''; |
| 525 | if (when) { |
| 526 | wireEdge.when = when; |
| 527 | wireEdge.label = `${wireEdge.label} · when ${when}`; |
| 528 | } |
| 529 | } |
| 530 | hops.push({ |
| 531 | node: toNodeRef(step.node), |
| 532 | edge: wireEdge, |
| 533 | callRef, |
| 534 | source: await windowFor( |
| 535 | cg, |
| 536 | projectRoot, |
| 537 | cache, |
| 538 | step.node, |
| 539 | step.anchor ?? callRef?.line ?? step.node.startLine |
| 540 | ), |
| 541 | }); |
| 542 | } |