Skip to content

Commit 0098081

Browse files
authored
refactor: extract entity ID allocation into idAllocation module (#15001)
Split 1/6 of #14480 (see that PR for the full map). Collapses the copy-pasted `lastLinkId`/`lastNodeId`/`lastGroupId`/`lastRerouteId` increment-and-sync idioms across `LGraph`, `LGraphNode`, subgraph slots, and `subgraphDeduplication` into `mint*`/`observe*` helpers in `src/lib/litegraph/src/idAllocation.ts`. No behavior change. Notes for review: - Module lives in `src/lib/litegraph/src/` (litegraph-only behavior), not `src/types/` as in #14480. - `snapshotIdState`/`restoreIdState` from #14480 are omitted — no callers until the layout rollback PR; they land there. - `LGraphState` is re-exported from `LGraph.ts` so existing importers are unaffected.
1 parent 867ac42 commit 0098081

8 files changed

Lines changed: 172 additions & 80 deletions

File tree

src/lib/litegraph/src/LGraph.ts

Lines changed: 24 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ import {
1818
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
1919
import { toLinkId } from '@/types/linkId'
2020
import { toRerouteId } from '@/types/rerouteId'
21+
import {
22+
createLGraphState,
23+
mintGroupId,
24+
mintNodeId,
25+
mintRerouteId,
26+
observeGroupId,
27+
observeNodeId,
28+
observeRerouteId
29+
} from './idAllocation'
30+
import type { LGraphState } from './idAllocation'
2131
import { useLinkStore } from '@/stores/linkStore'
2232
import { useNodeDataStore } from '@/stores/nodeDataStore'
2333
import { useRerouteStore } from '@/stores/rerouteStore'
@@ -44,7 +54,6 @@ import type { DragAndScaleState } from './DragAndScale'
4454
import { LGraphCanvas } from './LGraphCanvas'
4555
import { Rectangle } from './infrastructure/Rectangle'
4656
import { LGraphGroup } from './LGraphGroup'
47-
import { toGroupId } from '@/types/groupId'
4857
import {
4958
LGraphNode,
5059
registerNodeState,
@@ -144,22 +153,11 @@ function isLGraphTriggerAction(action: string): action is LGraphTriggerAction {
144153
return validTriggerActions.has(action as LGraphTriggerAction)
145154
}
146155

147-
function nextNodeId(state: LGraphState): NodeId {
148-
return toNodeId(++state.lastNodeId)
149-
}
150-
151156
function numericNodeId(id: NodeId): number | null {
152157
const numericId = Number(id)
153158
return Number.isInteger(numericId) ? numericId : null
154159
}
155160

156-
function syncLastNodeId(state: LGraphState, id: NodeId): void {
157-
const numericId = numericNodeId(id)
158-
if (numericId !== null && state.lastNodeId < numericId) {
159-
state.lastNodeId = numericId
160-
}
161-
}
162-
163161
export type RendererType = 'LG' | 'Vue' | 'Vue-corrected'
164162

165163
/**
@@ -168,13 +166,7 @@ export type RendererType = 'LG' | 'Vue' | 'Vue-corrected'
168166
*/
169167
export type SubgraphId = UUID
170168

171-
export interface LGraphState {
172-
/** Counter, not an id — brand at the point a group is constructed. */
173-
lastGroupId: number
174-
lastNodeId: number
175-
lastLinkId: LinkId
176-
lastRerouteId: RerouteId
177-
}
169+
export type { LGraphState } from './idAllocation'
178170

179171
type ParamsArray<T, K extends MethodNames<T>> = Parameters<
180172
Extract<T[K], (...args: never[]) => unknown>
@@ -349,12 +341,7 @@ export class LGraph
349341
list_of_graphcanvas: LGraphCanvas[] | null
350342
status: number = LGraph.STATUS_STOPPED
351343

352-
private _state: LGraphState = {
353-
lastGroupId: 0,
354-
lastNodeId: 0,
355-
lastLinkId: toLinkId(0),
356-
lastRerouteId: toRerouteId(0)
357-
}
344+
private _state: LGraphState = createLGraphState()
358345

359346
get state(): LGraphState {
360347
return this._state
@@ -516,12 +503,7 @@ export class LGraph
516503
this.id = zeroUuid
517504
this.revision = 0
518505

519-
this.state = {
520-
lastGroupId: 0,
521-
lastNodeId: 0,
522-
lastLinkId: toLinkId(0),
523-
lastRerouteId: toRerouteId(0)
524-
}
506+
this.state = createLGraphState()
525507

526508
// used to detect changes
527509
this._version = -1
@@ -1078,9 +1060,8 @@ export class LGraph
10781060
// groups
10791061
if (node instanceof LGraphGroup) {
10801062
// Assign group ID
1081-
if (node.id == null || node.id === -1)
1082-
node.id = toGroupId(++state.lastGroupId)
1083-
if (node.id > state.lastGroupId) state.lastGroupId = node.id
1063+
if (node.id == null || node.id === -1) node.id = mintGroupId(state)
1064+
observeGroupId(state, node.id)
10841065

10851066
this._groups.push(node)
10861067
this.setDirtyCanvas(true)
@@ -1097,7 +1078,7 @@ export class LGraph
10971078
console.warn(
10981079
'LiteGraph: there is already a node with this ID, changing it'
10991080
)
1100-
node.id = nextNodeId(state)
1081+
node.id = mintNodeId(state)
11011082
}
11021083

11031084
if (this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES) {
@@ -1106,9 +1087,9 @@ export class LGraph
11061087

11071088
// give him an id
11081089
if (node.id == null || node.id === UNASSIGNED_NODE_ID) {
1109-
node.id = nextNodeId(state)
1090+
node.id = mintNodeId(state)
11101091
} else {
1111-
syncLastNodeId(state, node.id)
1092+
observeNodeId(state, node.id)
11121093
}
11131094

11141095
// Set ghost flag before registration so the node state carries it
@@ -1627,12 +1608,8 @@ export class LGraph
16271608
floating
16281609
}: OptionalProps<SerialisableReroute, 'id'>): Reroute {
16291610
const rerouteId =
1630-
id === undefined
1631-
? toRerouteId(Number(this.state.lastRerouteId) + 1)
1632-
: toRerouteId(id)
1633-
if (rerouteId > this.state.lastRerouteId) {
1634-
this.state.lastRerouteId = rerouteId
1635-
}
1611+
id === undefined ? mintRerouteId(this.state) : toRerouteId(id)
1612+
observeRerouteId(this.state, rerouteId)
16361613

16371614
const existingReroute = this.reroutes.get(rerouteId)
16381615
const reroute = existingReroute ?? new Reroute(rerouteId, this, pos)
@@ -1655,8 +1632,7 @@ export class LGraph
16551632
if (!(before instanceof LLink) && !(before instanceof Reroute)) {
16561633
return
16571634
}
1658-
const rerouteId = toRerouteId(Number(this.state.lastRerouteId) + 1)
1659-
this.state.lastRerouteId = rerouteId
1635+
const rerouteId = mintRerouteId(this.state)
16601636
const chainLinks =
16611637
before instanceof Reroute
16621638
? [
@@ -2116,7 +2092,7 @@ export class LGraph
21162092
}
21172093
}
21182094

2119-
const newNodeId = nextNodeId(this.state)
2095+
const newNodeId = mintNodeId(this.state)
21202096
nodeIdMap.set(toNodeId(n_info.id), newNodeId)
21212097
node.id = newNodeId
21222098
n_info.id = newNodeId
@@ -2219,7 +2195,7 @@ export class LGraph
22192195
// Shared definitions may survive, so unpacked groups need fresh layout
22202196
// ids, like the reroutes below.
22212197
for (const groupInfo of groups) {
2222-
groupInfo.id = ++this.rootGraph.state.lastGroupId
2198+
groupInfo.id = mintGroupId(this.rootGraph.state)
22232199
const group = new LGraphGroup(groupInfo.title, groupInfo.id)
22242200
this.add(group, true)
22252201
group.configure(groupInfo)
@@ -2291,8 +2267,7 @@ export class LGraph
22912267
const rerouteIdMap = new Map<RerouteId, RerouteId>()
22922268
const oldReroutes = subgraphNode.subgraph.reroutes
22932269
for (const reroute of oldReroutes.values()) {
2294-
const migratedId = toRerouteId(Number(this.state.lastRerouteId) + 1)
2295-
this.state.lastRerouteId = migratedId
2270+
const migratedId = mintRerouteId(this.state)
22962271
const migratedReroute = new Reroute(migratedId, this, [
22972272
reroute.pos[0] + offsetX,
22982273
reroute.pos[1] + offsetY

src/lib/litegraph/src/LGraphNode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMuta
99
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
1010
import { LayoutSource } from '@/renderer/core/layout/types'
1111
import { toLinkId } from '@/types/linkId'
12+
import { mintLinkId } from './idAllocation'
1213
import { useNodeDataStore } from '@/stores/nodeDataStore'
1314
import { useWidgetValueStore } from '@/stores/widgetValueStore'
1415
import { UNASSIGNED_NODE_ID, toNodeId, serializeNodeId } from '@/types/nodeId'
@@ -3124,8 +3125,7 @@ export class LGraphNode
31243125
const maybeCommonType =
31253126
input.type && output.type && commonType(input.type, output.type)
31263127

3127-
const linkId = toLinkId(Number(graph.state.lastLinkId) + 1)
3128-
graph.state.lastLinkId = linkId
3128+
const linkId = mintLinkId(graph.state)
31293129

31303130
const link = new LLink(
31313131
linkId,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import {
4+
createLGraphState,
5+
mintGroupId,
6+
mintLinkId,
7+
mintNodeId,
8+
mintRerouteId,
9+
observeGroupId,
10+
observeLinkId,
11+
observeNodeId,
12+
observeRerouteId
13+
} from '@/lib/litegraph/src/idAllocation'
14+
import { toGroupId } from '@/types/groupId'
15+
import { toLinkId } from '@/types/linkId'
16+
import { toNodeId } from '@/types/nodeId'
17+
import { toRerouteId } from '@/types/rerouteId'
18+
19+
describe('idAllocation', () => {
20+
it('mints increasing ids for each entity kind', () => {
21+
const state = createLGraphState()
22+
23+
expect([mintNodeId(state), mintNodeId(state)]).toEqual(['1', '2'])
24+
expect([mintGroupId(state), mintGroupId(state)]).toEqual([1, 2])
25+
expect([mintLinkId(state), mintLinkId(state)]).toEqual([1, 2])
26+
expect([mintRerouteId(state), mintRerouteId(state)]).toEqual([1, 2])
27+
})
28+
29+
it('observes higher ids and ignores lower ids', () => {
30+
const state = createLGraphState()
31+
32+
observeNodeId(state, toNodeId(4))
33+
observeNodeId(state, toNodeId(2))
34+
observeGroupId(state, toGroupId(5))
35+
observeGroupId(state, toGroupId(3))
36+
observeLinkId(state, toLinkId(6))
37+
observeLinkId(state, toLinkId(4))
38+
observeRerouteId(state, toRerouteId(7))
39+
observeRerouteId(state, toRerouteId(5))
40+
41+
expect(state).toEqual({
42+
lastGroupId: 5,
43+
lastNodeId: 4,
44+
lastLinkId: 6,
45+
lastRerouteId: 7
46+
})
47+
})
48+
49+
it('observes numeric-string node ids', () => {
50+
const state = createLGraphState()
51+
52+
observeNodeId(state, toNodeId('12'))
53+
observeNodeId(state, toNodeId('named'))
54+
55+
expect(state.lastNodeId).toBe(12)
56+
})
57+
})
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { toGroupId } from '@/types/groupId'
2+
import type { GroupId } from '@/types/groupId'
3+
import { toLinkId } from '@/types/linkId'
4+
import type { LinkId } from '@/types/linkId'
5+
import { toNodeId } from '@/types/nodeId'
6+
import type { NodeId } from '@/types/nodeId'
7+
import { toRerouteId } from '@/types/rerouteId'
8+
import type { RerouteId } from '@/types/rerouteId'
9+
10+
export interface LGraphState {
11+
/** Counter, not an id — brand at the point a group is constructed. */
12+
lastGroupId: number
13+
lastNodeId: number
14+
lastLinkId: LinkId
15+
lastRerouteId: RerouteId
16+
}
17+
18+
export function createLGraphState(): LGraphState {
19+
return {
20+
lastGroupId: 0,
21+
lastNodeId: 0,
22+
lastLinkId: toLinkId(0),
23+
lastRerouteId: toRerouteId(0)
24+
}
25+
}
26+
27+
export function mintNodeId(state: LGraphState): NodeId {
28+
return toNodeId(++state.lastNodeId)
29+
}
30+
31+
export function mintGroupId(state: LGraphState): GroupId {
32+
return toGroupId(++state.lastGroupId)
33+
}
34+
35+
export function mintLinkId(state: LGraphState): LinkId {
36+
state.lastLinkId = toLinkId(Number(state.lastLinkId) + 1)
37+
return state.lastLinkId
38+
}
39+
40+
export function mintRerouteId(state: LGraphState): RerouteId {
41+
state.lastRerouteId = toRerouteId(Number(state.lastRerouteId) + 1)
42+
return state.lastRerouteId
43+
}
44+
45+
export function observeNodeId(state: LGraphState, id: NodeId): void {
46+
const numericId = Number(id)
47+
if (Number.isInteger(numericId) && numericId > state.lastNodeId) {
48+
state.lastNodeId = numericId
49+
}
50+
}
51+
52+
export function observeGroupId(state: LGraphState, id: GroupId): void {
53+
if (id > state.lastGroupId) state.lastGroupId = id
54+
}
55+
56+
export function observeLinkId(state: LGraphState, id: LinkId): void {
57+
if (id > state.lastLinkId) state.lastLinkId = id
58+
}
59+
60+
export function observeRerouteId(state: LGraphState, id: RerouteId): void {
61+
if (id > state.lastRerouteId) state.lastRerouteId = id
62+
}

src/lib/litegraph/src/subgraph/SubgraphInput.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { inputLink } from '@/lib/litegraph/src/node/slotLinks'
22
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
33
import { LLink } from '@/lib/litegraph/src/LLink'
4-
import { toLinkId } from '@/types/linkId'
4+
import { mintLinkId } from '../idAllocation'
55
import { anchorRerouteChain } from '@/lib/litegraph/src/Reroute'
66
import type { RerouteId } from '@/lib/litegraph/src/Reroute'
77
import { CustomEventTarget } from '@/lib/litegraph/src/infrastructure/CustomEventTarget'
@@ -102,8 +102,7 @@ export class SubgraphInput extends SubgraphSlot {
102102
this.events.dispatch('input-connected', { input: slot })
103103
}
104104

105-
const linkId = toLinkId(Number(subgraph.state.lastLinkId) + 1)
106-
subgraph.state.lastLinkId = linkId
105+
const linkId = mintLinkId(subgraph.state)
107106

108107
const link = new LLink(
109108
linkId,

src/lib/litegraph/src/subgraph/SubgraphInputNode.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { CanvasPointer } from '@/lib/litegraph/src/CanvasPointer'
22
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
33
import type { NodeId } from '@/types/nodeId'
44
import { LLink, slotFloatingLinks } from '@/lib/litegraph/src/LLink'
5-
import { toLinkId } from '@/types/linkId'
5+
import { mintLinkId } from '../idAllocation'
66
import type { RerouteId } from '@/lib/litegraph/src/Reroute'
77
import type { LinkConnector } from '@/lib/litegraph/src/canvas/LinkConnector'
88
import { SUBGRAPH_INPUT_ID } from '@/lib/litegraph/src/constants'
@@ -108,8 +108,7 @@ export class SubgraphInputNode
108108
if (outputIndex === -1 || inputIndex === -1)
109109
throw new Error('Invalid slot indices.')
110110

111-
const linkId = toLinkId(Number(subgraph.state.lastLinkId) + 1)
112-
subgraph.state.lastLinkId = linkId
111+
const linkId = mintLinkId(subgraph.state)
113112

114113
return new LLink(
115114
linkId,

src/lib/litegraph/src/subgraph/SubgraphOutput.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
22
import { LLink } from '@/lib/litegraph/src/LLink'
3-
import { toLinkId } from '@/types/linkId'
3+
import { mintLinkId } from '../idAllocation'
44
import { anchorRerouteChain } from '@/lib/litegraph/src/Reroute'
55
import type { RerouteId } from '@/lib/litegraph/src/Reroute'
66
import type {
@@ -60,8 +60,7 @@ export class SubgraphOutput extends SubgraphSlot {
6060
existingLink.disconnect(subgraph, 'input')
6161
}
6262

63-
const linkId = toLinkId(Number(subgraph.state.lastLinkId) + 1)
64-
subgraph.state.lastLinkId = linkId
63+
const linkId = mintLinkId(subgraph.state)
6564

6665
const link = new LLink(
6766
linkId,

0 commit comments

Comments
 (0)