mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-11 05:52:33 +08:00
mores tests + refactor
This commit is contained in:
parent
9d17f78476
commit
efea06dda5
@ -2,6 +2,8 @@
|
|||||||
const config = {
|
const config = {
|
||||||
testEnvironment: "jsdom",
|
testEnvironment: "jsdom",
|
||||||
setupFiles: ["./globalSetup.js"],
|
setupFiles: ["./globalSetup.js"],
|
||||||
|
clearMocks: true,
|
||||||
|
resetModules: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|||||||
@ -1,9 +1,49 @@
|
|||||||
/// <reference path="../node_modules/@types/jest/index.d.ts" />
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
/// <reference path="../node_modules/@types/jest/index.d.ts" />
|
||||||
|
|
||||||
const { start } = require("../utils");
|
const { start, makeNodeDef, checkBeforeAndAfterReload, assertNotNullOrUndefined } = require("../utils");
|
||||||
const lg = require("../utils/litegraph");
|
const lg = require("../utils/litegraph");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef { import("../utils/ezgraph") } Ez
|
||||||
|
* @typedef { ReturnType<Ez["Ez"]["graph"]>["ez"] } EzNodeFactory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { EzNodeFactory } ez
|
||||||
|
* @param { InstanceType<Ez["EzGraph"]> } graph
|
||||||
|
* @param { InstanceType<Ez["EzInput"]> } input
|
||||||
|
* @param { string } widgetType
|
||||||
|
* @param { boolean } hasControlWidget
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function connectPrimitiveAndReload(ez, graph, input, widgetType, hasControlWidget) {
|
||||||
|
// Connect to primitive and ensure its still connected after
|
||||||
|
let primitive = ez.PrimitiveNode();
|
||||||
|
primitive.outputs[0].connectTo(input);
|
||||||
|
|
||||||
|
await checkBeforeAndAfterReload(graph, async () => {
|
||||||
|
primitive = graph.find(primitive);
|
||||||
|
let { connections } = primitive.outputs[0];
|
||||||
|
expect(connections).toHaveLength(1);
|
||||||
|
expect(connections[0].targetNode.id).toBe(input.node.node.id);
|
||||||
|
|
||||||
|
// Ensure widget is correct type
|
||||||
|
const valueWidget = primitive.widgets.value;
|
||||||
|
expect(valueWidget.widget.type).toBe(widgetType);
|
||||||
|
|
||||||
|
// Check if control_after_generate should be added
|
||||||
|
if (hasControlWidget) {
|
||||||
|
const controlWidget = primitive.widgets.control_after_generate;
|
||||||
|
expect(controlWidget.widget.type).toBe("combo");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we dont have other widgets
|
||||||
|
expect(primitive.node.widgets).toHaveLength(1 + +!!hasControlWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
return primitive;
|
||||||
|
}
|
||||||
|
|
||||||
describe("widget inputs", () => {
|
describe("widget inputs", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -12,7 +52,6 @@ describe("widget inputs", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
lg.teardown(global);
|
lg.teardown(global);
|
||||||
jest.resetModules();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -28,58 +67,27 @@ describe("widget inputs", () => {
|
|||||||
{ name: "combo", type: ["a", "b", "c"], control: true },
|
{ name: "combo", type: ["a", "b", "c"], control: true },
|
||||||
].forEach((c) => {
|
].forEach((c) => {
|
||||||
test(`widget conversion + primitive works on ${c.name}`, async () => {
|
test(`widget conversion + primitive works on ${c.name}`, async () => {
|
||||||
/**
|
const { ez, graph } = await start({
|
||||||
* Test node with widgets of each type
|
|
||||||
* @type { import("../../web/types/comfy").ComfyObjectInfo } ComfyObjectInfo
|
|
||||||
*/
|
|
||||||
const WidgetTestNode = {
|
|
||||||
category: "test",
|
|
||||||
name: "WidgetTestNode",
|
|
||||||
output_name: [],
|
|
||||||
input: {
|
|
||||||
required: {
|
|
||||||
[c.name]: [c.type, c.opt ?? {}],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const { ez } = await start({
|
|
||||||
mockNodeDefs: {
|
mockNodeDefs: {
|
||||||
WidgetTestNode,
|
["TestNode"]: makeNodeDef("TestNode", { [c.name]: [c.type, c.opt ?? {}] }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create test node and convert to input
|
// Create test node and convert to input
|
||||||
const n = ez.WidgetTestNode();
|
const n = ez.TestNode();
|
||||||
const w = n.widgets[c.name];
|
const w = n.widgets[c.name];
|
||||||
w.convertToInput();
|
w.convertToInput();
|
||||||
expect(w.isConvertedToInput).toBeTruthy();
|
expect(w.isConvertedToInput).toBeTruthy();
|
||||||
const input = w.getConvertedInput();
|
const input = w.getConvertedInput();
|
||||||
expect(input).toBeTruthy();
|
expect(input).toBeTruthy();
|
||||||
|
|
||||||
// Connect to primitive
|
// @ts-ignore : input is valid here
|
||||||
const p1 = ez.PrimitiveNode();
|
await connectPrimitiveAndReload(ez, graph, input, c.widget ?? c.name, c.control);
|
||||||
// @ts-ignore : input is valid
|
|
||||||
p1.outputs[0].connectTo(input);
|
|
||||||
expect(p1.outputs[0].connectTo).toHaveLength(1);
|
|
||||||
|
|
||||||
// Ensure widget is correct type
|
|
||||||
const valueWidget = p1.widgets.value;
|
|
||||||
expect(valueWidget.widget.type).toBe(c.widget ?? c.name);
|
|
||||||
|
|
||||||
// Check if control_after_generate should be added
|
|
||||||
if (c.control) {
|
|
||||||
const controlWidget = p1.widgets.control_after_generate;
|
|
||||||
expect(controlWidget.widget.type).toBe("combo");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we dont have other widgets
|
|
||||||
expect(p1.node.widgets).toHaveLength(1 + +!!c.control);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("converted widget works after reload", async () => {
|
test("converted widget works after reload", async () => {
|
||||||
const { graph, ez } = await start();
|
const { ez, graph } = await start();
|
||||||
let n = ez.CheckpointLoaderSimple();
|
let n = ez.CheckpointLoaderSimple();
|
||||||
|
|
||||||
const inputCount = n.inputs.length;
|
const inputCount = n.inputs.length;
|
||||||
@ -100,31 +108,14 @@ describe("widget inputs", () => {
|
|||||||
n.widgets.ckpt_name.convertToInput();
|
n.widgets.ckpt_name.convertToInput();
|
||||||
expect(n.inputs.length).toEqual(inputCount + 1);
|
expect(n.inputs.length).toEqual(inputCount + 1);
|
||||||
|
|
||||||
let primitive = ez.PrimitiveNode();
|
const primitive = await connectPrimitiveAndReload(ez, graph, n.inputs.ckpt_name, "combo", true);
|
||||||
primitive.outputs[0].connectTo(n.inputs.ckpt_name);
|
|
||||||
|
|
||||||
await graph.reload();
|
|
||||||
|
|
||||||
// Find the reloaded nodes in the graph
|
|
||||||
n = graph.find(n);
|
|
||||||
primitive = graph.find(primitive);
|
|
||||||
|
|
||||||
// Ensure widget is converted
|
|
||||||
expect(n.widgets.ckpt_name.isConvertedToInput).toBeTruthy();
|
|
||||||
expect(n.inputs.ckpt_name).toBeTruthy();
|
|
||||||
expect(n.inputs.length).toEqual(inputCount + 1);
|
|
||||||
|
|
||||||
// Ensure primitive is connected
|
|
||||||
let { connections } = primitive.outputs[0];
|
|
||||||
expect(connections).toHaveLength(1);
|
|
||||||
expect(connections[0].targetNode.id).toBe(n.node.id);
|
|
||||||
|
|
||||||
// Disconnect & reconnect
|
// Disconnect & reconnect
|
||||||
connections[0].disconnect();
|
primitive.outputs[0].connections[0].disconnect();
|
||||||
({ connections } = primitive.outputs[0]);
|
let { connections } = primitive.outputs[0];
|
||||||
expect(connections).toHaveLength(0);
|
expect(connections).toHaveLength(0);
|
||||||
primitive.outputs[0].connectTo(n.inputs.ckpt_name);
|
|
||||||
|
|
||||||
|
primitive.outputs[0].connectTo(n.inputs.ckpt_name);
|
||||||
({ connections } = primitive.outputs[0]);
|
({ connections } = primitive.outputs[0]);
|
||||||
expect(connections).toHaveLength(1);
|
expect(connections).toHaveLength(1);
|
||||||
expect(connections[0].targetNode.id).toBe(n.node.id);
|
expect(connections[0].targetNode.id).toBe(n.node.id);
|
||||||
@ -169,7 +160,7 @@ describe("widget inputs", () => {
|
|||||||
test("shows missing node error on custom node with converted input", async () => {
|
test("shows missing node error on custom node with converted input", async () => {
|
||||||
const { graph } = await start();
|
const { graph } = await start();
|
||||||
|
|
||||||
const dialogShow = jest.spyOn(graph.app.ui.dialog, "show")
|
const dialogShow = jest.spyOn(graph.app.ui.dialog, "show");
|
||||||
|
|
||||||
await graph.app.loadGraphData({
|
await graph.app.loadGraphData({
|
||||||
last_node_id: 3,
|
last_node_id: 3,
|
||||||
@ -212,4 +203,75 @@ describe("widget inputs", () => {
|
|||||||
expect(dialogShow.mock.calls[0][0]).toContain("the following node types were not found");
|
expect(dialogShow.mock.calls[0][0]).toContain("the following node types were not found");
|
||||||
expect(dialogShow.mock.calls[0][0]).toContain("TestNode");
|
expect(dialogShow.mock.calls[0][0]).toContain("TestNode");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("defaultInput widgets can be converted back to inputs", async () => {
|
||||||
|
const { graph, ez } = await start({
|
||||||
|
mockNodeDefs: {
|
||||||
|
["TestNode"]: makeNodeDef("TestNode", { example: ["INT", { defaultInput: true }] }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create test node and ensure it starts as an input
|
||||||
|
let n = ez.TestNode();
|
||||||
|
let w = n.widgets.example;
|
||||||
|
expect(w.isConvertedToInput).toBeTruthy();
|
||||||
|
let input = w.getConvertedInput();
|
||||||
|
expect(input).toBeTruthy();
|
||||||
|
|
||||||
|
// Ensure it can be converted to
|
||||||
|
w.convertToWidget();
|
||||||
|
expect(w.isConvertedToInput).toBeFalsy();
|
||||||
|
expect(n.inputs.length).toEqual(0);
|
||||||
|
// and from
|
||||||
|
w.convertToInput();
|
||||||
|
expect(w.isConvertedToInput).toBeTruthy();
|
||||||
|
input = w.getConvertedInput();
|
||||||
|
|
||||||
|
// Reload and ensure it still only has 1 converted widget
|
||||||
|
if (!assertNotNullOrUndefined(input)) return;
|
||||||
|
|
||||||
|
await connectPrimitiveAndReload(ez, graph, input, "number", true);
|
||||||
|
n = graph.find(n);
|
||||||
|
expect(n.widgets).toHaveLength(1);
|
||||||
|
w = n.widgets.example;
|
||||||
|
expect(w.isConvertedToInput).toBeTruthy();
|
||||||
|
|
||||||
|
// Convert back to widget and ensure it is still a widget after reload
|
||||||
|
w.convertToWidget();
|
||||||
|
await graph.reload();
|
||||||
|
n = graph.find(n);
|
||||||
|
expect(n.widgets).toHaveLength(1);
|
||||||
|
expect(n.widgets[0].isConvertedToInput).toBeFalsy();
|
||||||
|
expect(n.inputs.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("forceInput widgets can not be converted back to inputs", async () => {
|
||||||
|
const { graph, ez } = await start({
|
||||||
|
mockNodeDefs: {
|
||||||
|
["TestNode"]: makeNodeDef("TestNode", { example: ["INT", { forceInput: true }] }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create test node and ensure it starts as an input
|
||||||
|
let n = ez.TestNode();
|
||||||
|
let w = n.widgets.example;
|
||||||
|
expect(w.isConvertedToInput).toBeTruthy();
|
||||||
|
const input = w.getConvertedInput();
|
||||||
|
expect(input).toBeTruthy();
|
||||||
|
|
||||||
|
// Convert to widget should error
|
||||||
|
expect(() => w.convertToWidget()).toThrow();
|
||||||
|
|
||||||
|
// Reload and ensure it still only has 1 converted widget
|
||||||
|
if (assertNotNullOrUndefined(input)) {
|
||||||
|
await connectPrimitiveAndReload(ez, graph, input, "number", true);
|
||||||
|
n = graph.find(n);
|
||||||
|
expect(n.widgets).toHaveLength(1);
|
||||||
|
expect(n.widgets.example.isConvertedToInput).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("primitive combo cannot connect to non matching list", () => {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@ -12,7 +12,7 @@
|
|||||||
* @typedef { (...args: EzOutput[] | [...EzOutput[], Record<string, unknown>]) => EzNode } EzNodeFactory
|
* @typedef { (...args: EzOutput[] | [...EzOutput[], Record<string, unknown>]) => EzNode } EzNodeFactory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class EzConnection {
|
export class EzConnection {
|
||||||
/** @type { app } */
|
/** @type { app } */
|
||||||
app;
|
app;
|
||||||
/** @type { InstanceType<LG["LLink"]> } */
|
/** @type { InstanceType<LG["LLink"]> } */
|
||||||
@ -48,7 +48,7 @@ class EzConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzSlot {
|
export class EzSlot {
|
||||||
/** @type { EzNode } */
|
/** @type { EzNode } */
|
||||||
node;
|
node;
|
||||||
/** @type { number } */
|
/** @type { number } */
|
||||||
@ -64,7 +64,7 @@ class EzSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzInput extends EzSlot {
|
export class EzInput extends EzSlot {
|
||||||
/** @type { INodeInputSlot } */
|
/** @type { INodeInputSlot } */
|
||||||
input;
|
input;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class EzInput extends EzSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzOutput extends EzSlot {
|
export class EzOutput extends EzSlot {
|
||||||
/** @type { INodeOutputSlot } */
|
/** @type { INodeOutputSlot } */
|
||||||
output;
|
output;
|
||||||
|
|
||||||
@ -98,8 +98,9 @@ class EzOutput extends EzSlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get connections() {
|
get connections() {
|
||||||
return (this.node.node.outputs?.[this.index]?.links ?? [])
|
return (this.node.node.outputs?.[this.index]?.links ?? []).map(
|
||||||
.map(l => new EzConnection(this.node.app, this.node.app.graph.links[l]));
|
(l) => new EzConnection(this.node.app, this.node.app.graph.links[l])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,18 +124,22 @@ class EzOutput extends EzSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzNodeMenuItem {
|
export class EzNodeMenuItem {
|
||||||
/** @type { EzNode } */
|
/** @type { EzNode } */
|
||||||
node;
|
node;
|
||||||
|
/** @type { number } */
|
||||||
|
index;
|
||||||
/** @type { ContextMenuItem } */
|
/** @type { ContextMenuItem } */
|
||||||
item;
|
item;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param { EzNode } node
|
* @param { EzNode } node
|
||||||
|
* @param { number } index
|
||||||
* @param { ContextMenuItem } item
|
* @param { ContextMenuItem } item
|
||||||
*/
|
*/
|
||||||
constructor(node, item) {
|
constructor(node, index, item) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
|
this.index = index;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,18 +152,22 @@ class EzNodeMenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzWidget {
|
export class EzWidget {
|
||||||
/** @type { EzNode } */
|
/** @type { EzNode } */
|
||||||
node;
|
node;
|
||||||
|
/** @type { number } */
|
||||||
|
index;
|
||||||
/** @type { IWidget } */
|
/** @type { IWidget } */
|
||||||
widget;
|
widget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param { EzNode } node
|
* @param { EzNode } node
|
||||||
|
* @param { number } index
|
||||||
* @param { IWidget } widget
|
* @param { IWidget } widget
|
||||||
*/
|
*/
|
||||||
constructor(node, widget) {
|
constructor(node, index, widget) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
|
this.index = index;
|
||||||
this.widget = widget;
|
this.widget = widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,10 +185,9 @@ class EzWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getConvertedInput() {
|
getConvertedInput() {
|
||||||
if (!this.isConvertedToInput)
|
if (!this.isConvertedToInput) throw new Error(`Widget ${this.widget.name} is not converted to input.`);
|
||||||
throw new Error(`Widget ${this.widget.name} is not converted to input.`);
|
|
||||||
|
|
||||||
return this.node.inputs.find(inp => inp.input["widget"]?.name === this.widget.name);
|
return this.node.inputs.find((inp) => inp.input["widget"]?.name === this.widget.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
convertToWidget() {
|
convertToWidget() {
|
||||||
@ -195,7 +203,7 @@ class EzWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzNode {
|
export class EzNode {
|
||||||
/** @type { app } */
|
/** @type { app } */
|
||||||
app;
|
app;
|
||||||
/** @type { LGNode } */
|
/** @type { LGNode } */
|
||||||
@ -215,55 +223,68 @@ class EzNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get inputs() {
|
get inputs() {
|
||||||
return this.#getSlotItems("inputs");
|
return this.#makeLookupArray("inputs", "name", EzInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
get outputs() {
|
get outputs() {
|
||||||
return this.#getSlotItems("outputs");
|
return this.#makeLookupArray("outputs", "name", EzOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns { Record<string, EzWidget> } */
|
|
||||||
get widgets() {
|
get widgets() {
|
||||||
return (this.node.widgets ?? []).reduce((p, w, i) => {
|
return this.#makeLookupArray("widgets", "name", EzWidget);
|
||||||
p[w.name ?? i] = new EzWidget(this, w);
|
|
||||||
return p;
|
|
||||||
}, {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get menu() {
|
get menu() {
|
||||||
const items = this.app.canvas.getNodeMenuOptions(this.node);
|
return this.#makeLookupArray(() => this.app.canvas.getNodeMenuOptions(this.node), "content", EzNodeMenuItem);
|
||||||
return items.reduce((p, w) => {
|
|
||||||
if(w?.content) {
|
|
||||||
p[w.content] = new EzNodeMenuItem(this, w);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}, {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select() {
|
select() {
|
||||||
this.app.canvas.selectNode(this.node);
|
this.app.canvas.selectNode(this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @template { "inputs" | "outputs" } T
|
||||||
|
// * @param { T } type
|
||||||
|
// * @returns { Record<string, type extends "inputs" ? EzInput : EzOutput> & (type extends "inputs" ? EzInput [] : EzOutput[]) }
|
||||||
|
// */
|
||||||
|
// #getSlotItems(type) {
|
||||||
|
// // @ts-ignore : these items are correct
|
||||||
|
// return (this.node[type] ?? []).reduce((p, s, i) => {
|
||||||
|
// if (s.name in p) {
|
||||||
|
// throw new Error(`Unable to store input ${s.name} on array as name conflicts.`);
|
||||||
|
// }
|
||||||
|
// // @ts-ignore
|
||||||
|
// p.push((p[s.name] = new (type === "inputs" ? EzInput : EzOutput)(this, i, s)));
|
||||||
|
// return p;
|
||||||
|
// }, Object.assign([], { $: this }));
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template { "inputs" | "outputs" } T
|
* @template { { new(node: EzNode, index: number, obj: any): any } } T
|
||||||
* @param { T } type
|
* @param { "inputs" | "outputs" | "widgets" | (() => Array<unknown>) } nodeProperty
|
||||||
* @returns { Record<string, type extends "inputs" ? EzInput : EzOutput> & (type extends "inputs" ? EzInput [] : EzOutput[]) }
|
* @param { string } nameProperty
|
||||||
*/
|
* @param { T } ctor
|
||||||
#getSlotItems(type) {
|
* @returns { Record<string, InstanceType<T>> & Array<InstanceType<T>> }
|
||||||
// @ts-ignore : these items are correct
|
*/
|
||||||
return (this.node[type] ?? []).reduce((p, s, i) => {
|
#makeLookupArray(nodeProperty, nameProperty, ctor) {
|
||||||
if(s.name in p) {
|
const items = typeof nodeProperty === "function" ? nodeProperty() : this.node[nodeProperty];
|
||||||
throw new Error(`Unable to store input ${s.name} on array as name conflicts.`);
|
// @ts-ignore
|
||||||
}
|
return (items ?? []).reduce((p, s, i) => {
|
||||||
;
|
if (!s) return p;
|
||||||
|
|
||||||
|
const name = s[nameProperty];
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
p.push(p[s.name] = new (type === "inputs" ? EzInput : EzOutput)(this, i, s));
|
if (!name || name in p) {
|
||||||
|
throw new Error(`Unable to store ${nodeProperty} ${name} on array as name conflicts.`);
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
p.push((p[name] = new ctor(this, i, s)));
|
||||||
return p;
|
return p;
|
||||||
}, Object.assign([], {$: this}))
|
}, Object.assign([], { $: this }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EzGraph {
|
export class EzGraph {
|
||||||
/** @type { app } */
|
/** @type { app } */
|
||||||
app;
|
app;
|
||||||
|
|
||||||
@ -373,8 +394,7 @@ export const Ez = {
|
|||||||
const inputs = ezNode.inputs;
|
const inputs = ezNode.inputs;
|
||||||
|
|
||||||
let slot = 0;
|
let slot = 0;
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (const arg of args) {
|
||||||
const arg = args[i];
|
|
||||||
if (arg instanceof EzOutput) {
|
if (arg instanceof EzOutput) {
|
||||||
arg.connectTo(inputs[slot++]);
|
arg.connectTo(inputs[slot++]);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -12,3 +12,45 @@ export async function start(config = undefined) {
|
|||||||
await app.setup();
|
await app.setup();
|
||||||
return Ez.graph(app, global["LiteGraph"], global["LGraphCanvas"]);
|
return Ez.graph(app, global["LiteGraph"], global["LGraphCanvas"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { ReturnType<Ez["graph"]>["graph"] } graph
|
||||||
|
* @param { (hasReloaded: boolean) => (Promise<void> | void) } cb
|
||||||
|
*/
|
||||||
|
export async function checkBeforeAndAfterReload(graph, cb) {
|
||||||
|
await cb(false);
|
||||||
|
await graph.reload();
|
||||||
|
await cb(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { string } name
|
||||||
|
* @param { Record<string, string | [string | string[], any]> } input
|
||||||
|
* @returns { import("../../web/types/comfy").ComfyObjectInfo }
|
||||||
|
*/
|
||||||
|
export function makeNodeDef(name, input) {
|
||||||
|
const nodeDef = {
|
||||||
|
name,
|
||||||
|
category: "test",
|
||||||
|
output_name: [],
|
||||||
|
input: {
|
||||||
|
required: {}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
for(const k in input) {
|
||||||
|
nodeDef.input.required[k] = typeof input[k] === "string" ? [input[k], {}] : [...input[k]];
|
||||||
|
}
|
||||||
|
return nodeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
/**
|
||||||
|
* @template { any } T
|
||||||
|
* @param { T } x
|
||||||
|
* @returns { x is Exclude<T, null | undefined> }
|
||||||
|
*/
|
||||||
|
export function assertNotNullOrUndefined(x) {
|
||||||
|
expect(x).not.toEqual(null);
|
||||||
|
expect(x).not.toEqual(undefined);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user