Compare commits

...

4 Commits

Author SHA1 Message Date
Alexander Brown
15a4509471 Merge branch 'main' into litegraph/prune-lgraph-misc-hooks 2026-06-24 15:54:57 -07:00
bymyself
d57f5f7bf3 refactor(litegraph): deprecate LGraph.onBeforeChange instead of deleting
Ecosystem re-audit (W2F-1) found bmad4ever/ComfyUI-Bmad-DirtyUndoRedo
assigns app.graph.onBeforeChange via the listener-assignment pattern.
Deleting the field outright silently no-ops those handlers.

Keep the hook as a deprecated shim: the dispatch in beforeChange() is
restored and emits a one-time deprecation warning via warnDeprecated,
nudging migration to LGraphCanvas.onBeforeChange. onGetNodeMenuOptions
stays deleted (zero ecosystem consumers).
2026-06-19 14:44:41 -07:00
Connor Byrne
cd839edc75 fix: mark unused beforeChange info param with underscore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-06-19 14:43:56 -07:00
Connor Byrne
2333a184a3 refactor(litegraph): delete dead LGraph onGetNodeMenuOptions + onBeforeChange
Delete two remaining LGraph instance hook fields confirmed dead by
AUDIT-LG.9:

- LGraph.onGetNodeMenuOptions field + dispatcher in
  LGraphCanvas.ts (context-menu construction).
- LGraph.onBeforeChange field + dispatcher in LGraph.ts:1374.

LGraphCanvas.onBeforeChange is a SEPARATE field and is preserved.

Stacks on #12228. Closes the LGraph-side portion of #12224.
2026-06-19 14:43:56 -07:00
3 changed files with 58 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { NodeId, Subgraph } from '@/lib/litegraph/src/litegraph'
import {
@@ -529,6 +529,52 @@ describe('Subgraph Definition Garbage Collection', () => {
})
})
describe('beforeChange deprecated onBeforeChange shim', () => {
beforeEach(() => {
LiteGraph.onDeprecationWarning = []
LiteGraph.alwaysRepeatWarnings = true
})
afterEach(() => {
LiteGraph.alwaysRepeatWarnings = false
})
it('still invokes a listener assigned to onBeforeChange', () => {
const graph = new LGraph()
const node = new LGraphNode('test')
const onBeforeChange = vi.fn()
graph.onBeforeChange = onBeforeChange
graph.beforeChange(node)
expect(onBeforeChange).toHaveBeenCalledWith(graph, node)
})
it('warns that onBeforeChange is deprecated when used', () => {
const graph = new LGraph()
const deprecationCallback = vi.fn()
LiteGraph.onDeprecationWarning = [deprecationCallback]
graph.onBeforeChange = vi.fn()
graph.beforeChange()
expect(deprecationCallback).toHaveBeenCalledWith(
expect.stringContaining('LGraph.onBeforeChange is deprecated'),
undefined
)
})
it('does not warn when no listener is assigned', () => {
const graph = new LGraph()
const deprecationCallback = vi.fn()
LiteGraph.onDeprecationWarning = [deprecationCallback]
graph.beforeChange()
expect(deprecationCallback).not.toHaveBeenCalled()
})
})
describe('Legacy LGraph Compatibility Layer', () => {
test('can be extended via prototype', ({ expect, minimalGraph }) => {
// @ts-expect-error Should always be an error.

View File

@@ -38,7 +38,6 @@ import type {
DefaultConnectionColors,
Dictionary,
HasBoundingRect,
IContextMenuValue,
INodeInputSlot,
INodeOutputSlot,
LinkNetwork,
@@ -56,6 +55,7 @@ import {
createBounds,
snapPoint
} from './measure'
import { warnDeprecated } from './utils/feedback'
import { SubgraphInput } from './subgraph/SubgraphInput'
import { SubgraphInputNode } from './subgraph/SubgraphInputNode'
import { SubgraphOutput } from './subgraph/SubgraphOutput'
@@ -331,16 +331,16 @@ export class LGraph
onNodeAdded?(node: LGraphNode): void
onNodeRemoved?(node: LGraphNode): void
onTrigger?: LGraphTriggerHandler
/**
* @deprecated Assign a listener to {@link LGraphCanvas.onBeforeChange} instead.
* This graph-level hook will be removed in a future version.
*/
onBeforeChange?(graph: LGraph, info?: LGraphNode): void
onAfterChange?(graph: LGraph, info?: LGraphNode | null): void
onConnectionChange?(node: LGraphNode): void
on_change?(graph: LGraph): void
onSerialize?(data: ISerialisedGraph | SerialisableGraph): void
onConfigure?(data: ISerialisedGraph | SerialisableGraph): void
onGetNodeMenuOptions?(
options: (IContextMenuValue<unknown> | null)[],
node: LGraphNode
): void
// @ts-expect-error - Private property type needs fixing
private _input_nodes?: LGraphNode[]
@@ -1357,7 +1357,12 @@ export class LGraph
// used for undo, called before any change is made to the graph
beforeChange(info?: LGraphNode): void {
this.onBeforeChange?.(this, info)
if (this.onBeforeChange) {
warnDeprecated(
'LGraph.onBeforeChange is deprecated and will be removed in a future version. Assign a listener to LGraphCanvas.onBeforeChange instead.'
)
this.onBeforeChange(this, info)
}
this.canvasAction((c) => c.onBeforeChange?.(this))
}

View File

@@ -8642,8 +8642,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
callback: LGraphCanvas.onMenuNodeRemove
})
node.graph?.onGetNodeMenuOptions?.(options, node)
return options
}