From a7bf3f38b7780c6770f0816e7b29f659cafab5fe Mon Sep 17 00:00:00 2001 From: Alexander Brown <448862+DrJKL@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:15:33 -0800 Subject: [PATCH] refactor: extract litegraph types to dedicated types directory - Create src/lib/litegraph/types/ with pure type definitions - Extract geometry, slot, id, and utility types - Create type-only barrel for importing without runtime deps - Update interfaces.ts to import from types/ and re-export - Move utility.ts from src/types to types/ (consolidate) - Enables type-only imports to reduce circular dependencies Amp-Thread-ID: https://ampcode.com/threads/T-019bfe73-6a29-7638-8160-8de515af8707 Co-authored-by: Amp --- src/lib/litegraph/src/LGraphCanvas.ts | 2 +- .../src/infrastructure/CustomEventTarget.ts | 2 +- src/lib/litegraph/src/interfaces.ts | 236 +++++------------- src/lib/litegraph/src/types/utility.ts | 13 - src/lib/litegraph/types/geometry.ts | 40 +++ src/lib/litegraph/types/ids.ts | 25 ++ src/lib/litegraph/types/index.ts | 54 ++++ src/lib/litegraph/types/slots.ts | 113 +++++++++ src/lib/litegraph/types/utility.ts | 60 +++++ 9 files changed, 361 insertions(+), 184 deletions(-) delete mode 100644 src/lib/litegraph/src/types/utility.ts create mode 100644 src/lib/litegraph/types/geometry.ts create mode 100644 src/lib/litegraph/types/ids.ts create mode 100644 src/lib/litegraph/types/index.ts create mode 100644 src/lib/litegraph/types/slots.ts create mode 100644 src/lib/litegraph/types/utility.ts diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 37c0950a2..b6e06fc71 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -99,7 +99,7 @@ import type { ISerialisedNode, SubgraphIO } from './types/serialisation' -import type { NeverNever, PickNevers } from './types/utility' +import type { NeverNever, PickNevers } from '../types/utility' import type { IBaseWidget, TWidgetValue } from './types/widgets' import { alignNodes, distributeNodes, getBoundaryNodes } from './utils/arrange' import { findFirstNode, getAllNestedItems } from './utils/collections' diff --git a/src/lib/litegraph/src/infrastructure/CustomEventTarget.ts b/src/lib/litegraph/src/infrastructure/CustomEventTarget.ts index 2c7f93f33..662a2b305 100644 --- a/src/lib/litegraph/src/infrastructure/CustomEventTarget.ts +++ b/src/lib/litegraph/src/infrastructure/CustomEventTarget.ts @@ -1,4 +1,4 @@ -import type { NeverNever, PickNevers } from '@/lib/litegraph/src/types/utility' +import type { NeverNever, PickNevers } from '@/lib/litegraph/types/utility' type EventListeners = { readonly [K in keyof T]: diff --git a/src/lib/litegraph/src/interfaces.ts b/src/lib/litegraph/src/interfaces.ts index 9df7339af..eb20de2a9 100644 --- a/src/lib/litegraph/src/interfaces.ts +++ b/src/lib/litegraph/src/interfaces.ts @@ -3,65 +3,72 @@ import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' import type { TWidgetValue } from '@/lib/litegraph/src/types/widgets' import type { ContextMenu } from './ContextMenu' -import type { LGraphNode, NodeId } from './LGraphNode' -import type { LLink, LinkId } from './LLink' -import type { Reroute, RerouteId } from './Reroute' +import type { LGraphNode } from './LGraphNode' +import type { LLink } from './LLink' +import type { Reroute } from './Reroute' import type { SubgraphInput } from './subgraph/SubgraphInput' import type { SubgraphInputNode } from './subgraph/SubgraphInputNode' import type { SubgraphOutputNode } from './subgraph/SubgraphOutputNode' -import type { LinkDirection, RenderShape } from './types/globalEnums' +import type { LinkDirection } from './types/globalEnums' import type { IBaseWidget } from './types/widgets' -export type Dictionary = { [key: string]: T } +// Re-export pure types from the types directory for backwards compatibility +export type { + CanvasColour, + CompassCorners, + Direction, + Point, + ReadOnlyRect, + ReadOnlyTypedArray, + Rect, + Size +} from '../types/geometry' -/** Allows all properties to be null. The same as `Partial`, but adds null instead of undefined. */ -export type NullableProperties = { - [P in keyof T]: T[P] | null +export type { LinkId, NodeId, RerouteId } from '../types/ids' + +export type { + HasBoundingRect, + INodeFlags, + INodeSlotBase, + ISlotType, + IWidgetLocator +} from '../types/slots' + +export type { + Dictionary, + MethodNames, + NullableProperties, + OptionalProps, + RequiredProps, + SharedIntersection, + WhenNullish +} from '../types/utility' + +// Import types we need locally +import type { CanvasColour, Point, Size } from '../types/geometry' +import type { LinkId, NodeId, RerouteId } from '../types/ids' +import type { + HasBoundingRect, + INodeInputSlotBase, + INodeOutputSlotBase, + INodeSlotBase, + ISlotType, + IWidgetLocator +} from '../types/slots' + +export interface NewNodePosition { + node: LGraphNode + newPos: { + x: number + y: number + } } -/** - * If {@link T} is `null` or `undefined`, evaluates to {@link Result}. Otherwise, evaluates to {@link T}. - * Useful for functions that return e.g. `undefined` when a param is nullish. - */ -export type WhenNullish = - | (T & {}) - | (T extends null ? Result : T extends undefined ? Result : T & {}) - -/** A type with each of the {@link Properties} made optional. */ -export type OptionalProps = Omit< - T, - Properties -> & { [K in Properties]?: T[K] } - -/** A type with each of the {@link Properties} marked as required. */ -export type RequiredProps = Omit< - T, - Properties -> & { [K in Properties]-?: T[K] } - -/** Bitwise AND intersection of two types; returns a new, non-union type that includes only properties that exist on both types. */ -export type SharedIntersection = { - [P in keyof T1 as P extends keyof T2 ? P : never]: T1[P] -} & { - [P in keyof T2 as P extends keyof T1 ? P : never]: T2[P] -} - -export type CanvasColour = string | CanvasGradient | CanvasPattern - -/** - * Any object that has a {@link boundingRect}. - */ -export interface HasBoundingRect { - /** - * A rectangle that represents the outer edges of the item. - * - * Used for various calculations, such as overlap, selective rendering, and click checks. - * For most items, this is cached position & size as `x, y, width, height`. - * Some items (such as nodes and slots) may extend above and/or to the left of their {@link pos}. - * @readonly - * @see {@link move} - */ - readonly boundingRect: ReadOnlyRect +export interface IBoundaryNodes { + top: LGraphNode + right: LGraphNode + bottom: LGraphNode + left: LGraphNode } /** An object containing a set of child objects */ @@ -226,130 +233,22 @@ export interface IFoundSlot extends IInputOrOutput { link_pos: Point } -/** A point represented as `[x, y]` co-ordinates */ -export type Point = [x: number, y: number] - -/** A size represented as `[width, height]` */ -export type Size = [width: number, height: number] - -/** A rectangle starting at top-left coordinates `[x, y, width, height]` */ -export type Rect = - | [x: number, y: number, width: number, height: number] - | Float64Array - -/** A rectangle starting at top-left coordinates `[x, y, width, height]` that will not be modified */ -export type ReadOnlyRect = - | readonly [x: number, y: number, width: number, height: number] - | ReadOnlyTypedArray - -export type ReadOnlyTypedArray = Omit< - Readonly, - 'fill' | 'copyWithin' | 'reverse' | 'set' | 'sort' | 'subarray' -> - -/** Union of property names that are of type Match */ -type KeysOfType = Exclude< - { [P in keyof T]: T[P] extends Match ? P : never }[keyof T], - undefined -> - -/** The names of all (optional) methods and functions in T */ -export type MethodNames = KeysOfType< - T, - ((...args: unknown[]) => unknown) | undefined -> -export interface NewNodePosition { - node: LGraphNode - newPos: { - x: number - y: number - } -} -export interface IBoundaryNodes { - top: LGraphNode - right: LGraphNode - bottom: LGraphNode - left: LGraphNode -} - -export type Direction = 'top' | 'bottom' | 'left' | 'right' - -/** Resize handle positions (compass points) */ -export type CompassCorners = 'NE' | 'SE' | 'SW' | 'NW' - /** - * A string that represents a specific data / slot type, e.g. `STRING`. - * - * Can be comma-delimited to specify multiple allowed types, e.g. `STRING,INT`. + * Full slot interface with runtime-dependent properties. + * Extends the base slot from types/slots.ts with LLink reference. */ -export type ISlotType = number | string - -export interface INodeSlot extends HasBoundingRect { - /** - * The name of the slot in English. - * Will be included in the serialized data. - */ - name: string - /** - * The localized name of the slot to display in the UI. - * Takes higher priority than {@link name} if set. - * Will be included in the serialized data. - */ - localized_name?: string - /** - * The name of the slot to display in the UI, modified by the user. - * Takes higher priority than {@link display_name} if set. - * Will be included in the serialized data. - */ - label?: string - - type: ISlotType - dir?: LinkDirection - removable?: boolean - shape?: RenderShape - color_off?: CanvasColour - color_on?: CanvasColour - locked?: boolean - nameLocked?: boolean - pos?: Point - /** @remarks Automatically calculated; not included in serialisation. */ - boundingRect: ReadOnlyRect +export interface INodeSlot extends INodeSlotBase { /** * A list of floating link IDs that are connected to this slot. * This is calculated at runtime; it is **not** serialized. */ _floatingLinks?: Set - /** - * Whether the slot has errors. It is **not** serialized. - */ - hasErrors?: boolean -} - -export interface INodeFlags { - skip_repeated_outputs?: boolean - allow_interaction?: boolean - pinned?: boolean - collapsed?: boolean - /** Configuration setting for {@link LGraphNode.connectInputToOutput} */ - keepAllLinksOnBypass?: boolean } /** - * A widget that is linked to a slot. - * - * This is set by the ComfyUI_frontend logic. See - * https://github.com/Comfy-Org/ComfyUI_frontend/blob/b80e0e1a3c74040f328c4e344326c969c97f67e0/src/extensions/core/widgetInputs.ts#L659 + * Full input slot interface with runtime-dependent properties. */ -export interface IWidgetLocator { - name: string - type?: string -} - -export interface INodeInputSlot extends INodeSlot { - link: LinkId | null - widget?: IWidgetLocator - alwaysVisible?: boolean - +export interface INodeInputSlot extends INodeInputSlotBase, INodeSlot { /** * Internal use only; API is not finalised and may change at any time. */ @@ -360,11 +259,10 @@ export interface IWidgetInputSlot extends INodeInputSlot { widget: IWidgetLocator } -export interface INodeOutputSlot extends INodeSlot { - links: LinkId[] | null - _data?: unknown - slot_index?: number -} +/** + * Full output slot interface with runtime-dependent properties. + */ +export interface INodeOutputSlot extends INodeOutputSlotBase, INodeSlot {} /** Links */ export interface ConnectingLink extends IInputOrOutput { diff --git a/src/lib/litegraph/src/types/utility.ts b/src/lib/litegraph/src/types/utility.ts deleted file mode 100644 index 6aaad4415..000000000 --- a/src/lib/litegraph/src/types/utility.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * General-purpose, TypeScript utility types. - */ - -/** {@link Pick} only properties that evaluate to `never`. */ -export type PickNevers = { - [K in keyof T as T[K] extends never ? K : never]: T[K] -} - -/** {@link Omit} all properties that evaluate to `never`. */ -export type NeverNever = { - [K in keyof T as T[K] extends never ? never : K]: T[K] -} diff --git a/src/lib/litegraph/types/geometry.ts b/src/lib/litegraph/types/geometry.ts new file mode 100644 index 000000000..222aac196 --- /dev/null +++ b/src/lib/litegraph/types/geometry.ts @@ -0,0 +1,40 @@ +/** + * Pure geometry types for litegraph. + * These have no dependencies on runtime code. + */ + +/** A point represented as `[x, y]` co-ordinates */ +export type Point = [x: number, y: number] + +/** A size represented as `[width, height]` */ +export type Size = [width: number, height: number] + +/** A rectangle starting at top-left coordinates `[x, y, width, height]` */ +export type Rect = + | [x: number, y: number, width: number, height: number] + | Float64Array + +/** A rectangle starting at top-left coordinates `[x, y, width, height]` that will not be modified */ +export type ReadOnlyRect = + | readonly [x: number, y: number, width: number, height: number] + | ReadOnlyTypedArray + +export type ReadOnlyTypedArray = Omit< + Readonly, + 'fill' | 'copyWithin' | 'reverse' | 'set' | 'sort' | 'subarray' +> + +/** A 2D vector */ +export type Vector2 = [x: number, y: number] + +/** A 4D vector */ +export type Vector4 = [x: number, y: number, z: number, w: number] + +/** Direction as cardinal points */ +export type Direction = 'top' | 'bottom' | 'left' | 'right' + +/** Resize handle positions (compass points) */ +export type CompassCorners = 'NE' | 'SE' | 'SW' | 'NW' + +/** A color value for canvas rendering */ +export type CanvasColour = string | CanvasGradient | CanvasPattern diff --git a/src/lib/litegraph/types/ids.ts b/src/lib/litegraph/types/ids.ts new file mode 100644 index 000000000..0aebbb4f4 --- /dev/null +++ b/src/lib/litegraph/types/ids.ts @@ -0,0 +1,25 @@ +/** + * ID types for litegraph entities. + * These are branded types that can be used without importing runtime modules. + */ + +/** + * Node ID type. + * @remarks Re-exported from LGraphNode for backwards compatibility, + * but defined here to avoid circular imports. + */ +export type NodeId = number | string + +/** + * Link ID type. + * @remarks Re-exported from LLink for backwards compatibility, + * but defined here to avoid circular imports. + */ +export type LinkId = number + +/** + * Reroute ID type. + * @remarks Re-exported from Reroute for backwards compatibility, + * but defined here to avoid circular imports. + */ +export type RerouteId = number diff --git a/src/lib/litegraph/types/index.ts b/src/lib/litegraph/types/index.ts new file mode 100644 index 000000000..3539d2f7d --- /dev/null +++ b/src/lib/litegraph/types/index.ts @@ -0,0 +1,54 @@ +/** + * Type-only barrel export for litegraph types. + * + * This module exports pure type definitions that can be imported + * without pulling in any runtime code, helping to avoid circular + * dependency issues. + * + * @example + * ```typescript + * import type { Point, NodeId, INodeSlot } from '@/lib/litegraph/types' + * ``` + */ + +// Geometry types +export type { + CanvasColour, + CompassCorners, + Direction, + Point, + ReadOnlyRect, + ReadOnlyTypedArray, + Rect, + Size, + Vector2, + Vector4 +} from './geometry' + +// ID types +export type { LinkId, NodeId, RerouteId } from './ids' + +// Slot types +export type { + HasBoundingRect, + INodeFlags, + INodeInputSlotBase, + INodeOutputSlotBase, + INodeSlotBase, + ISlotType, + IWidgetInputSlotBase, + IWidgetLocator +} from './slots' + +// Utility types +export type { + Dictionary, + MethodNames, + NeverNever, + NullableProperties, + OptionalProps, + PickNevers, + RequiredProps, + SharedIntersection, + WhenNullish +} from './utility' diff --git a/src/lib/litegraph/types/slots.ts b/src/lib/litegraph/types/slots.ts new file mode 100644 index 000000000..82652f1f0 --- /dev/null +++ b/src/lib/litegraph/types/slots.ts @@ -0,0 +1,113 @@ +/** + * Slot-related types for litegraph. + * These have minimal dependencies and can be imported without pulling in runtime code. + */ + +import type { LinkDirection, RenderShape } from '../src/types/globalEnums' +import type { CanvasColour, Point, ReadOnlyRect } from './geometry' +import type { LinkId } from './ids' + +/** + * A string that represents a specific data / slot type, e.g. `STRING`. + * + * Can be comma-delimited to specify multiple allowed types, e.g. `STRING,INT`. + */ +export type ISlotType = number | string + +/** + * Any object that has a {@link boundingRect}. + */ +export interface HasBoundingRect { + /** + * A rectangle that represents the outer edges of the item. + * + * Used for various calculations, such as overlap, selective rendering, and click checks. + * For most items, this is cached position & size as `x, y, width, height`. + * Some items (such as nodes and slots) may extend above and/or to the left of their {@link pos}. + * @readonly + * @see {@link move} + */ + readonly boundingRect: ReadOnlyRect +} + +/** + * Base slot interface without runtime-dependent properties. + * The full INodeSlot in interfaces.ts extends this with runtime properties. + */ +export interface INodeSlotBase extends HasBoundingRect { + /** + * The name of the slot in English. + * Will be included in the serialized data. + */ + name: string + /** + * The localized name of the slot to display in the UI. + * Takes higher priority than {@link name} if set. + * Will be included in the serialized data. + */ + localized_name?: string + /** + * The name of the slot to display in the UI, modified by the user. + * Takes higher priority than {@link display_name} if set. + * Will be included in the serialized data. + */ + label?: string + + type: ISlotType + dir?: LinkDirection + removable?: boolean + shape?: RenderShape + color_off?: CanvasColour + color_on?: CanvasColour + locked?: boolean + nameLocked?: boolean + pos?: Point + /** @remarks Automatically calculated; not included in serialisation. */ + boundingRect: ReadOnlyRect + /** + * Whether the slot has errors. It is **not** serialized. + */ + hasErrors?: boolean +} + +/** + * A widget that is linked to a slot. + * + * This is set by the ComfyUI_frontend logic. See + * https://github.com/Comfy-Org/ComfyUI_frontend/blob/b80e0e1a3c74040f328c4e344326c969c97f67e0/src/extensions/core/widgetInputs.ts#L659 + */ +export interface IWidgetLocator { + name: string + type?: string +} + +/** + * Base input slot interface without runtime-dependent properties. + */ +export interface INodeInputSlotBase extends INodeSlotBase { + link: LinkId | null + widget?: IWidgetLocator + alwaysVisible?: boolean +} + +export interface IWidgetInputSlotBase extends INodeInputSlotBase { + widget: IWidgetLocator +} + +/** + * Base output slot interface without runtime-dependent properties. + */ +export interface INodeOutputSlotBase extends INodeSlotBase { + links: LinkId[] | null + _data?: unknown + slot_index?: number +} + +export interface INodeFlags { + skip_repeated_outputs?: boolean + allow_interaction?: boolean + pinned?: boolean + collapsed?: boolean + /** Configuration setting for {@link LGraphNode.connectInputToOutput} */ + keepAllLinksOnBypass?: boolean +} diff --git a/src/lib/litegraph/types/utility.ts b/src/lib/litegraph/types/utility.ts new file mode 100644 index 000000000..2db511e07 --- /dev/null +++ b/src/lib/litegraph/types/utility.ts @@ -0,0 +1,60 @@ +/** + * General-purpose TypeScript utility types for litegraph. + * These have no dependencies on runtime code. + */ + +export type Dictionary = { [key: string]: T } + +/** Allows all properties to be null. The same as `Partial`, but adds null instead of undefined. */ +export type NullableProperties = { + [P in keyof T]: T[P] | null +} + +/** + * If {@link T} is `null` or `undefined`, evaluates to {@link Result}. Otherwise, evaluates to {@link T}. + * Useful for functions that return e.g. `undefined` when a param is nullish. + */ +export type WhenNullish = + | (T & {}) + | (T extends null ? Result : T extends undefined ? Result : T & {}) + +/** A type with each of the {@link Properties} made optional. */ +export type OptionalProps = Omit< + T, + Properties +> & { [K in Properties]?: T[K] } + +/** A type with each of the {@link Properties} marked as required. */ +export type RequiredProps = Omit< + T, + Properties +> & { [K in Properties]-?: T[K] } + +/** Bitwise AND intersection of two types; returns a new, non-union type that includes only properties that exist on both types. */ +export type SharedIntersection = { + [P in keyof T1 as P extends keyof T2 ? P : never]: T1[P] +} & { + [P in keyof T2 as P extends keyof T1 ? P : never]: T2[P] +} + +/** Union of property names that are of type Match */ +type KeysOfType = Exclude< + { [P in keyof T]: T[P] extends Match ? P : never }[keyof T], + undefined +> + +/** The names of all (optional) methods and functions in T */ +export type MethodNames = KeysOfType< + T, + ((...args: unknown[]) => unknown) | undefined +> + +/** {@link Pick} only properties that evaluate to `never`. */ +export type PickNevers = { + [K in keyof T as T[K] extends never ? K : never]: T[K] +} + +/** {@link Omit} all properties that evaluate to `never`. */ +export type NeverNever = { + [K in keyof T as T[K] extends never ? never : K]: T[K] +}