File size: 3,107 Bytes
7312c42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
 * ComfyUI graph utility functions for tracing and navigating node connections.
 */

export interface NodeInfo {
  nodeId: number
  nodeName: string
  nodeType: string
  outputSlotIndex: number
  isList: boolean
}

/**
 * Get output slot information from a node.
 */
export function getOutputSlotInfo(
  nodeId: number,
  slotIndex: number,
  graph: any,
): { isList: boolean; linkId: number | null } | null {
  const node: any = graph.getNodeById(nodeId)
  if (!node) return null

  const outputSlot: any = node.outputs?.[slotIndex]
  if (!outputSlot) return null

  return {
    isList: outputSlot.shape == 6,
    linkId: outputSlot.link ?? null,
  }
}

/**
 * Get link information by link ID.
 */
export function getLinkInfo(linkId: number, graph: any): {
  originId: number
  originSlot: number
  targetId: number
  targetSlot: number
} | null {
  const link: any = graph.links[linkId]
  if (!link) return null

  return {
    originId: link.origin_id,
    originSlot: link.origin_slot,
    targetId: link.target_id,
    targetSlot: link.target_slot,
  }
}

/**
 * Recursively trace back through links to find the original source node.
 * Returns the root node ID, or null if not found.
 */
export function traceToRootSource(
  nodeId: number,
  slotIndex: number,
  graph: any,
  visited: Set<string> = new Set(),
): number | null {
  let currentNodeId: number | null = nodeId
  let currentSlotIdx: number | null = slotIndex

  while (currentNodeId !== null && currentSlotIdx !== null) {
    const key = `${currentNodeId}:${currentSlotIdx}`
    if (visited.has(key)) {
      console.debug(`[trace] Cycle detected at node ${currentNodeId}, slot ${currentSlotIdx}`)
      break
    }
    visited.add(key)

    const node: any = graph.getNodeById(currentNodeId)
    if (!node) break

    const outputSlot: any = node.outputs?.[currentSlotIdx]
    if (!outputSlot) break

    console.debug(
      `[trace] Node #${currentNodeId} "${node.name || node.type || 'unknown'}" slot ${currentSlotIdx} isList=${outputSlot.shape == 6}`,
    )

    const linkId: number | null = outputSlot.link
    if (linkId === null || linkId === undefined) {
      console.debug(`[trace] Root source found: #${currentNodeId}`)
      return currentNodeId
    }

    const link: any = graph.links[linkId]
    if (!link) break

    currentNodeId = link.origin_id
    currentSlotIdx = link.origin_slot
  }

  console.debug('[trace] Root source: none')
  return null
}

/**
 * Trace from a link ID to find the root source node.
 * The link points from a source output to a target input.
 */
export function traceToRootSourceViaLink(linkId: number, graph: any): number | null {
  if (linkId === null || linkId === undefined) {
    console.debug('[traceViaLink] No link ID')
    return null
  }
  const link: any = graph.links[linkId]
  if (!link) {
    console.debug('[traceViaLink] Link not found:', linkId)
    return null
  }

  console.debug('[traceViaLink] Found link, tracing from:', {
    originId: link.origin_id,
    originSlot: link.origin_slot,
  })

  return traceToRootSource(link.origin_id, link.origin_slot, graph)
}