Make Id types mutually incompatible

This commit is contained in:
Austin Mroz
2025-09-23 09:34:40 -05:00
parent f086377307
commit f1cb8edcaa
9 changed files with 38 additions and 26 deletions

View File

@@ -574,7 +574,7 @@ export class LGraph
const S: LGraphNode[] = []
const M: Dictionary<LGraphNode> = {}
// to avoid repeating links
const visited_links: Record<NodeId, boolean> = {}
const visited_links: Record<LinkId, boolean> = {}
const remaining_links: Record<NodeId, number> = {}
// search for the nodes without inputs (starting nodes)
@@ -1341,9 +1341,9 @@ export class LGraph
createReroute(pos: Point, before: LinkSegment): Reroute {
const layoutMutations = useLayoutMutations()
const rerouteId = ++this.state.lastRerouteId
const linkIds = before instanceof Reroute ? before.linkIds : [before.id]
const linkIds = before instanceof Reroute ? before.linkIds : []
const floatingLinkIds =
before instanceof Reroute ? before.floatingLinkIds : [before.id]
before instanceof Reroute ? before.floatingLinkIds : []
const reroute = new Reroute(
rerouteId,
this,

View File

@@ -6168,14 +6168,19 @@ export class LGraphCanvas
case 'Delete': {
// segment can be a Reroute object, in which case segment.id is the reroute id
const linkId =
if (!(segment instanceof Reroute) && !(segment instanceof LLink))
// FIXME: Need better way of determining if segment is a Link or Reroute
throw new Error('Unimplemented link type')
const linkIds =
segment instanceof Reroute
? segment.linkIds.values().next().value
: segment.id
if (linkId !== undefined) {
graph.removeLink(linkId)
// Clean up layout store
layoutStore.deleteLinkLayout(linkId)
? segment.linkIds
: [segment.id satisfies LinkId]
for (const linkId of linkIds) {
if (linkId !== undefined) {
graph.removeLink(linkId)
// Clean up layout store
layoutStore.deleteLinkLayout(linkId)
}
}
break
}

View File

@@ -90,7 +90,9 @@ import { type WidgetTypeMap, toConcreteWidget } from './widgets/widgetMap'
// #region Types
export type NodeId = number | string
export type NodeId =
| (number & { type?: 'NodeId' })
| (string & { type?: 'NodeId' })
export type NodeProperty = string | number | boolean | object

View File

@@ -24,7 +24,7 @@ import type {
const layoutMutations = useLayoutMutations()
export type LinkId = number
export type LinkId = number & { type?: 'LinkId' }
export type SerialisedLLinkArray = [
id: LinkId,

View File

@@ -20,7 +20,7 @@ import type { Serialisable, SerialisableReroute } from './types/serialisation'
const layoutMutations = useLayoutMutations()
export type RerouteId = number
export type RerouteId = number & { type?: 'RerouteId' }
/** The input or output slot that an incomplete reroute link is connected to. */
export interface FloatingRerouteSlot {

View File

@@ -592,7 +592,7 @@ export const useWorkflowStore = defineStore('workflow', () => {
): NodeLocatorId | null => {
// Handle simple node IDs (root graph - no colons)
if (!nodeExecutionId.includes(':')) {
return nodeExecutionId
return nodeExecutionId as NodeLocatorId
}
const parts = parseNodeExecutionId(nodeExecutionId)

View File

@@ -15,7 +15,7 @@ import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSche
* Unlike execution IDs which change based on the instance path,
* NodeLocatorId remains the same for all instances of a particular node.
*/
export type NodeLocatorId = string
export type NodeLocatorId = string & { type?: 'LocatorId' }
/**
* An execution identifier representing a node's position in nested subgraphs.
@@ -24,7 +24,7 @@ export type NodeLocatorId = string
* Format: Colon-separated path of node IDs
* Example: "123:456:789" (node 789 in subgraph 456 in subgraph 123)
*/
export type NodeExecutionId = string
export type NodeExecutionId = string & { type?: 'ExecutionId' }
/**
* Type guard to check if a value is a NodeLocatorId

View File

@@ -1,3 +1,4 @@
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
import type {
LGraph,
LGraphNode,
@@ -9,7 +10,7 @@ import { parseNodeLocatorId } from '@/types/nodeIdentification'
import { isSubgraphIoNode } from './typeGuardUtil'
interface NodeWithId {
id: string | number
id: NodeId
subgraphId?: string | null
}
@@ -19,7 +20,7 @@ interface NodeWithId {
* @param nodeData - Node data containing id and optional subgraphId
* @returns The locator ID string
*/
export function getLocatorIdFromNodeData(nodeData: NodeWithId): string {
export function getLocatorIdFromNodeData(nodeData: NodeWithId): NodeLocatorId {
return nodeData.subgraphId
? `${nodeData.subgraphId}:${String(nodeData.id)}`
: String(nodeData.id)
@@ -31,7 +32,9 @@ export function getLocatorIdFromNodeData(nodeData: NodeWithId): string {
* @param executionId - The execution ID (e.g., "123:456:789" or "789")
* @returns Array of node IDs in the path, or null if invalid
*/
export function parseExecutionId(executionId: string): string[] | null {
export function parseExecutionId(
executionId: NodeExecutionId
): string[] | null {
if (!executionId || typeof executionId !== 'string') return null
return executionId.split(':').filter((part) => part.length > 0)
}
@@ -55,7 +58,9 @@ export function getLocalNodeIdFromExecutionId(
* @param executionId - The execution ID (e.g., "123:456:789" or "789")
* @returns Array of subgraph node IDs (excluding the final node ID), or empty array
*/
export function getSubgraphPathFromExecutionId(executionId: string): string[] {
export function getSubgraphPathFromExecutionId(
executionId: NodeExecutionId
): string[] {
const parts = parseExecutionId(executionId)
return parts ? parts.slice(0, -1) : []
}
@@ -196,7 +201,7 @@ export function collectAllNodes(
*/
export function findNodeInHierarchy(
graph: LGraph | Subgraph,
nodeId: string | number
nodeId: NodeId
): LGraphNode | null {
// Check current graph
const node = graph.getNodeById(nodeId)
@@ -284,7 +289,7 @@ export function findSubgraphPathById(
*/
export function getNodeByExecutionId(
rootGraph: LGraph,
executionId: string
executionId: NodeExecutionId
): LGraphNode | null {
if (!rootGraph) return null
@@ -316,7 +321,7 @@ export function getNodeByExecutionId(
*/
export function getNodeByLocatorId(
rootGraph: LGraph,
locatorId: NodeLocatorId | string
locatorId: NodeLocatorId
): LGraphNode | null {
if (!rootGraph) return null

View File

@@ -25,7 +25,7 @@
* SOFTWARE.
*/
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
import type { SerialisedLLinkArray } from '@/lib/litegraph/src/LLink'
import type { LinkId, SerialisedLLinkArray } from '@/lib/litegraph/src/LLink'
import type { LGraph, LGraphNode, LLink } from '@/lib/litegraph/src/litegraph'
import type {
ISerialisedGraph,
@@ -105,7 +105,7 @@ export function fixBadLinks(
const data: {
patchedNodes: Array<ISerialisedNode | LGraphNode>
deletedLinks: number[]
deletedLinks: LinkId[]
} = {
patchedNodes: [],
deletedLinks: []
@@ -419,7 +419,7 @@ export function fixBadLinks(
for (let i = data.deletedLinks.length - 1; i >= 0; i--) {
logger.log(`Deleting link #${data.deletedLinks[i]}.`)
if ((graph as LGraph).getNodeById) {
delete graph.links[data.deletedLinks[i]!]
delete (graph as LGraph).links[data.deletedLinks[i]!]
} else {
graph = graph as ISerialisedGraph
// Sometimes we got objects for links if passed after ComfyUI's loadGraphData modifies the