From c8ffacf1720a3be1b209f87efe87b658be8e717f Mon Sep 17 00:00:00 2001 From: filtered <176114999+webfiltered@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:12:46 +1100 Subject: [PATCH] [TS] Use strict mode in LGraph (#579) * [TS] Undefined is not a valid object key * Deprecate unused code Adds ts-expect-error to TS strict issues on unmaintained public interfaces. * [TS] Fix nullability: asSerialisable return type * nit - Remove outdated comment * [TS] Strict mode: LGraph - Adds minor coercion changes; would need extremely specific hacks performed to result in runtime change * [TMP] Work around typescript-strict-plugin Must be reverted once plugin removed. See #578 --- src/LGraph.ts | 31 ++++++++++++++++++++++++------- src/LGraphCanvas.ts | 2 +- src/interfaces.ts | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/LGraph.ts b/src/LGraph.ts index 00c0deb7c..deb3eaaea 100644 --- a/src/LGraph.ts +++ b/src/LGraph.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import type { Dictionary, IContextMenuValue, @@ -25,6 +24,7 @@ import { type LinkId, LLink } from "./LLink" import { MapProxyHandler } from "./MapProxyHandler" import { isSortaInsideOctagon } from "./measure" import { getAllNestedItems } from "./utils/collections" +import { stringOrEmpty } from "./strings" interface IGraphInput { name: string @@ -122,6 +122,9 @@ export class LGraph implements LinkNetwork, Serialisable { inputs: Dictionary = {} outputs: Dictionary = {} + /** @deprecated Deserialising a workflow sets this unused property. */ + version?: number + /** @returns Whether the graph has no items */ get empty(): boolean { return this._nodes.length + this._groups.length + this.reroutes.size === 0 @@ -341,6 +344,7 @@ export class LGraph implements LinkNetwork, Serialisable { } /** + * @deprecated Will be removed in 0.9 * Starts running this graph every interval milliseconds. * @param interval amount of milliseconds between executions, if 0 then it renders to the monitor refresh rate */ @@ -386,6 +390,7 @@ export class LGraph implements LinkNetwork, Serialisable { } /** + * @deprecated Will be removed in 0.9 * Stops the execution loop of the graph */ stop(): void { @@ -622,6 +627,7 @@ export class LGraph implements LinkNetwork, Serialisable { } /** + * @deprecated Will be removed in 0.9 * Returns all the nodes that could affect this one (ancestors) by crawling all the inputs recursively. * It doesn't include the node itself * @returns an array with all the LGraphNodes that affect this node, in order of execution @@ -649,6 +655,7 @@ export class LGraph implements LinkNetwork, Serialisable { } ancestors.sort(function (a, b) { + // @ts-ignore deprecated return a.order - b.order }) return ancestors @@ -719,6 +726,7 @@ export class LGraph implements LinkNetwork, Serialisable { } /** + * @deprecated Will be removed in 0.9 * Sends an event to all the nodes, useful to trigger stuff * @param eventname the name of the event (function to be called) * @param params parameters in array format @@ -734,12 +742,16 @@ export class LGraph implements LinkNetwork, Serialisable { if (!nodes) return for (const node of nodes) { + // @ts-ignore deprecated if (!node[eventname] || node.mode != mode) continue if (params === undefined) { + // @ts-ignore deprecated node[eventname]() } else if (params && params.constructor === Array) { + // @ts-ignore deprecated node[eventname].apply(node, params) } else { + // @ts-ignore deprecated node[eventname](params) } } @@ -1079,6 +1091,7 @@ export class LGraph implements LinkNetwork, Serialisable { } /** + * @deprecated Will be removed in 0.9 * Checks that the node type matches the node type registered, * used when replacing a nodetype by a newer version during execution * this replaces the ones using the old version with the new version @@ -1086,11 +1099,14 @@ export class LGraph implements LinkNetwork, Serialisable { checkNodeTypes() { const { _nodes } = this for (const [i, node] of _nodes.entries()) { + // @ts-ignore deprecated const ctor = LiteGraph.registered_node_types[node.type] if (node.constructor == ctor) continue console.log("node being replaced by newer version: " + node.type) + // @ts-ignore deprecated const newnode = LiteGraph.createNode(node.type) + if (!newnode) continue _nodes[i] = newnode newnode.configure(node.serialize()) newnode.graph = this @@ -1479,7 +1495,7 @@ export class LGraph implements LinkNetwork, Serialisable { * Mutating the properties of the return object may result in changes to your graph. * It is intended for use with {@link structuredClone} or {@link JSON.stringify}. */ - asSerialisable(options?: { sortNodes: boolean }): SerialisableGraph { + asSerialisable(options?: { sortNodes: boolean }): Required { const { config, state, extra } = this const nodeList = !LiteGraph.use_uuids && options?.sortNodes @@ -1493,7 +1509,7 @@ export class LGraph implements LinkNetwork, Serialisable { const links = [...this._links.values()].map(x => x.asSerialisable()) const reroutes = [...this.reroutes.values()].map(x => x.asSerialisable()) - const data: SerialisableGraph = { + const data: Required = { version: LGraph.serialisedSchemaVersion, config, state, @@ -1595,6 +1611,7 @@ export class LGraph implements LinkNetwork, Serialisable { i === "reroutes" ) continue + // @ts-ignore #574 Legacy property assignment this[i] = data[i] } @@ -1605,12 +1622,12 @@ export class LGraph implements LinkNetwork, Serialisable { if (nodesData) { for (const n_info of nodesData) { // stored info - let node = LiteGraph.createNode(n_info.type, n_info.title) + let node = LiteGraph.createNode(String(n_info.type), n_info.title) if (!node) { if (LiteGraph.debug) console.log("Node not found or has errors: " + n_info.type) // in case of error we create a replacement node to avoid losing info - node = new LGraphNode(undefined) + node = new LGraphNode("") node.last_serialization = n_info node.has_errors = true error = true @@ -1653,12 +1670,12 @@ export class LGraph implements LinkNetwork, Serialisable { load(url: string | Blob | URL | File, callback: () => void) { const that = this - // LEGACY: This was changed from constructor === File/Blob // from file if (url instanceof Blob || url instanceof File) { const reader = new FileReader() reader.addEventListener("load", function (event) { - const data = JSON.parse(event.target.result.toString()) + const result = stringOrEmpty(event.target?.result) + const data = JSON.parse(result) that.configure(data) callback?.() }) diff --git a/src/LGraphCanvas.ts b/src/LGraphCanvas.ts index 3a2d4f51c..abd584b8c 100644 --- a/src/LGraphCanvas.ts +++ b/src/LGraphCanvas.ts @@ -465,7 +465,7 @@ export class LGraphCanvas implements ConnectionColorContext { node_in_panel?: LGraphNode last_mouse: ReadOnlyPoint = [0, 0] last_mouseclick: number = 0 - graph!: LGraph + graph!: LGraph | null canvas: HTMLCanvasElement bgcanvas: HTMLCanvasElement ctx?: CanvasRenderingContext2D diff --git a/src/interfaces.ts b/src/interfaces.ts index c979948c6..2af796647 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -184,7 +184,7 @@ type ReadOnlyTypedArray = Omit /** Union of property names that are of type Match */ -export type KeysOfType = { [P in keyof T]: T[P] extends Match ? P : never }[keyof T] +export type KeysOfType = Exclude<{ [P in keyof T]: T[P] extends Match ? P : never }[keyof T], undefined> /** A new type that contains only the properties of T that are of type Match */ export type PickByType = { [P in keyof T]: Extract }