mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 10:42:44 +00:00
fix: enhance recomputeInsideNodes to support nested group processing with visited set
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect } from 'vitest'
|
import { describe, expect } from 'vitest'
|
||||||
|
|
||||||
import { LGraphGroup } from '@/lib/litegraph/src/litegraph'
|
import { LGraph, LGraphGroup } from '@/lib/litegraph/src/litegraph'
|
||||||
|
|
||||||
import { test } from './__fixtures__/testExtensions'
|
import { test } from './__fixtures__/testExtensions'
|
||||||
|
|
||||||
@@ -9,4 +9,72 @@ describe('LGraphGroup', () => {
|
|||||||
const link = new LGraphGroup('title', 929)
|
const link = new LGraphGroup('title', 929)
|
||||||
expect(link.serialize()).toMatchSnapshot('Basic')
|
expect(link.serialize()).toMatchSnapshot('Basic')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('recomputeInsideNodes', () => {
|
||||||
|
test('uses visited set to avoid redundant computation', () => {
|
||||||
|
const graph = new LGraph()
|
||||||
|
|
||||||
|
// Create 4 nested groups: outer -> mid1 -> mid2 -> inner
|
||||||
|
const outer = new LGraphGroup('outer')
|
||||||
|
outer.pos = [0, 0]
|
||||||
|
outer.size = [400, 400]
|
||||||
|
graph.add(outer)
|
||||||
|
|
||||||
|
const mid1 = new LGraphGroup('mid1')
|
||||||
|
mid1.pos = [10, 10]
|
||||||
|
mid1.size = [300, 300]
|
||||||
|
graph.add(mid1)
|
||||||
|
|
||||||
|
const mid2 = new LGraphGroup('mid2')
|
||||||
|
mid2.pos = [20, 20]
|
||||||
|
mid2.size = [200, 200]
|
||||||
|
graph.add(mid2)
|
||||||
|
|
||||||
|
const inner = new LGraphGroup('inner')
|
||||||
|
inner.pos = [30, 30]
|
||||||
|
inner.size = [100, 100]
|
||||||
|
graph.add(inner)
|
||||||
|
|
||||||
|
// Track the visited set to verify each group is only fully processed once
|
||||||
|
const visited = new Set<number>()
|
||||||
|
outer.recomputeInsideNodes(100, visited)
|
||||||
|
|
||||||
|
// All nested groups should be in the visited set
|
||||||
|
expect(visited.has(outer.id)).toBe(true)
|
||||||
|
expect(visited.has(mid1.id)).toBe(true)
|
||||||
|
expect(visited.has(mid2.id)).toBe(true)
|
||||||
|
expect(visited.has(inner.id)).toBe(true)
|
||||||
|
expect(visited.size).toBe(4)
|
||||||
|
|
||||||
|
// Verify children relationships are correct
|
||||||
|
expect(outer.children.has(mid1)).toBe(true)
|
||||||
|
expect(outer.children.has(mid2)).toBe(true)
|
||||||
|
expect(outer.children.has(inner)).toBe(true)
|
||||||
|
expect(mid1.children.has(mid2)).toBe(true)
|
||||||
|
expect(mid1.children.has(inner)).toBe(true)
|
||||||
|
expect(mid2.children.has(inner)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('respects maxDepth limit', () => {
|
||||||
|
const graph = new LGraph()
|
||||||
|
|
||||||
|
const outer = new LGraphGroup('outer')
|
||||||
|
outer.pos = [0, 0]
|
||||||
|
outer.size = [300, 300]
|
||||||
|
graph.add(outer)
|
||||||
|
|
||||||
|
const inner = new LGraphGroup('inner')
|
||||||
|
inner.pos = [10, 10]
|
||||||
|
inner.size = [100, 100]
|
||||||
|
graph.add(inner)
|
||||||
|
|
||||||
|
// With maxDepth=1, inner group is added as child but not processed
|
||||||
|
outer.recomputeInsideNodes(1)
|
||||||
|
|
||||||
|
// outer should have inner as a child
|
||||||
|
expect(outer.children.has(inner)).toBe(true)
|
||||||
|
// inner should not have computed its own children (it was never processed)
|
||||||
|
expect(inner.children.size).toBe(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -245,10 +245,16 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
|
|||||||
* Recomputes which items (nodes, reroutes, nested groups) are inside this group.
|
* Recomputes which items (nodes, reroutes, nested groups) are inside this group.
|
||||||
* Recursively processes nested groups to ensure their children are also computed.
|
* Recursively processes nested groups to ensure their children are also computed.
|
||||||
* @param maxDepth Maximum recursion depth for nested groups. Use 1 to skip nested group computation.
|
* @param maxDepth Maximum recursion depth for nested groups. Use 1 to skip nested group computation.
|
||||||
|
* @param visited Set of already visited group IDs to prevent redundant computation.
|
||||||
*/
|
*/
|
||||||
recomputeInsideNodes(maxDepth: number = 100): void {
|
recomputeInsideNodes(
|
||||||
|
maxDepth: number = 100,
|
||||||
|
visited: Set<number> = new Set()
|
||||||
|
): void {
|
||||||
if (!this.graph) throw new NullGraphError()
|
if (!this.graph) throw new NullGraphError()
|
||||||
if (maxDepth <= 0) return
|
if (maxDepth <= 0 || visited.has(this.id)) return
|
||||||
|
|
||||||
|
visited.add(this.id)
|
||||||
|
|
||||||
const { nodes, reroutes, groups } = this.graph
|
const { nodes, reroutes, groups } = this.graph
|
||||||
const children = this._children
|
const children = this._children
|
||||||
@@ -277,7 +283,7 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const group of containedGroups)
|
for (const group of containedGroups)
|
||||||
group.recomputeInsideNodes(maxDepth - 1)
|
group.recomputeInsideNodes(maxDepth - 1, visited)
|
||||||
|
|
||||||
groups.sort((a, b) => {
|
groups.sort((a, b) => {
|
||||||
if (a === this) {
|
if (a === this) {
|
||||||
|
|||||||
Reference in New Issue
Block a user