[Schema] ComfyNodeDefV2 schema (#2847)

This commit is contained in:
Chenlei Hu
2025-03-04 09:15:16 -05:00
committed by GitHub
parent 252e07ad17
commit f593f3caa4
10 changed files with 457 additions and 263 deletions

View File

@@ -0,0 +1,121 @@
import {
ComfyNodeDef as ComfyNodeDefV2,
InputSpec as InputSpecV2,
OutputSpec as OutputSpecV2
} from '@/schemas/nodeDef/nodeDefSchemaV2'
import {
ComfyNodeDef as ComfyNodeDefV1,
InputSpec as InputSpecV1,
getComboSpecComboOptions,
isComboInputSpec,
isComboInputSpecV1
} from '@/schemas/nodeDefSchema'
/**
* Transforms a V1 node definition to V2 format
* @param nodeDefV1 The V1 node definition to transform
* @returns The transformed V2 node definition
*/
export function transformNodeDefV1ToV2(
nodeDefV1: ComfyNodeDefV1
): ComfyNodeDefV2 {
// Transform inputs
const inputs: Record<string, InputSpecV2> = {}
// Process required inputs
if (nodeDefV1.input?.required) {
Object.entries(nodeDefV1.input.required).forEach(([name, inputSpecV1]) => {
inputs[name] = transformInputSpec(inputSpecV1, name, false)
})
}
// Process optional inputs
if (nodeDefV1.input?.optional) {
Object.entries(nodeDefV1.input.optional).forEach(([name, inputSpecV1]) => {
inputs[name] = transformInputSpec(inputSpecV1, name, true)
})
}
// Transform outputs
const outputs: OutputSpecV2[] = []
if (nodeDefV1.output) {
nodeDefV1.output.forEach((outputType, index) => {
const outputSpec: OutputSpecV2 = {
index,
name: nodeDefV1.output_name?.[index] || `output_${index}`,
type: Array.isArray(outputType) ? 'COMBO' : outputType,
is_list: nodeDefV1.output_is_list?.[index] || false,
tooltip: nodeDefV1.output_tooltips?.[index]
}
// Add options for combo outputs
if (Array.isArray(outputType)) {
outputSpec.options = outputType
}
outputs.push(outputSpec)
})
}
// Create the V2 node definition
return {
inputs,
outputs,
hidden: nodeDefV1.input?.hidden,
name: nodeDefV1.name,
display_name: nodeDefV1.display_name,
description: nodeDefV1.description,
category: nodeDefV1.category,
output_node: nodeDefV1.output_node,
python_module: nodeDefV1.python_module,
deprecated: nodeDefV1.deprecated,
experimental: nodeDefV1.experimental
}
}
/**
* Transforms a V1 input specification to V2 format
* @param inputSpecV1 The V1 input specification to transform
* @param name The name of the input
* @param isOptional Whether the input is optional
* @returns The transformed V2 input specification
*/
function transformInputSpec(
inputSpecV1: InputSpecV1,
name: string,
isOptional: boolean
): InputSpecV2 {
// Extract options from the input spec
const options = inputSpecV1[1] || {}
// Base properties for all input types
const baseProps = {
name,
isOptional,
...options
}
// Handle different input types
if (isComboInputSpec(inputSpecV1)) {
return {
type: 'COMBO',
...baseProps,
options: isComboInputSpecV1(inputSpecV1)
? inputSpecV1[0]
: getComboSpecComboOptions(inputSpecV1)
}
} else if (typeof inputSpecV1[0] === 'string') {
// Handle standard types (INT, FLOAT, BOOLEAN, STRING) and custom types
return {
type: inputSpecV1[0],
...baseProps
}
}
// Fallback for any unhandled cases
return {
type: 'UNKNOWN',
...baseProps
}
}

View File

@@ -0,0 +1,93 @@
import { z } from 'zod'
import {
zBaseInputOptions,
zBooleanInputOptions,
zComboInputOptions,
zFloatInputOptions,
zIntInputOptions,
zStringInputOptions
} from '@/schemas/nodeDefSchema'
const zIntInputSpec = zIntInputOptions.extend({
type: z.literal('INT'),
name: z.string(),
isOptional: z.boolean().optional()
})
const zFloatInputSpec = zFloatInputOptions.extend({
type: z.literal('FLOAT'),
name: z.string(),
isOptional: z.boolean().optional()
})
const zBooleanInputSpec = zBooleanInputOptions.extend({
type: z.literal('BOOLEAN'),
name: z.string(),
isOptional: z.boolean().optional()
})
const zStringInputSpec = zStringInputOptions.extend({
type: z.literal('STRING'),
name: z.string(),
isOptional: z.boolean().optional()
})
const zComboInputSpec = zComboInputOptions.extend({
type: z.literal('COMBO'),
name: z.string(),
isOptional: z.boolean().optional()
})
const zCustomInputSpec = zBaseInputOptions.extend({
type: z.string(),
name: z.string(),
isOptional: z.boolean().optional()
})
const zInputSpec = z.union([
zIntInputSpec,
zFloatInputSpec,
zBooleanInputSpec,
zStringInputSpec,
zComboInputSpec,
zCustomInputSpec
])
// Output specs
const zOutputSpec = z.object({
index: z.number(),
name: z.string(),
type: z.string(),
is_list: z.boolean(),
options: z.array(z.any()).optional(),
tooltip: z.string().optional()
})
// Main node definition schema
const zNodeDef = z.object({
inputs: z.record(zInputSpec),
outputs: z.array(zOutputSpec),
hidden: z.record(z.any()).optional(),
name: z.string(),
display_name: z.string(),
description: z.string(),
category: z.string(),
output_node: z.boolean(),
python_module: z.string(),
deprecated: z.boolean().optional(),
experimental: z.boolean().optional()
})
// Export types
export type IntInputSpec = z.infer<typeof zIntInputSpec>
export type FloatInputSpec = z.infer<typeof zFloatInputSpec>
export type BooleanInputSpec = z.infer<typeof zBooleanInputSpec>
export type StringInputSpec = z.infer<typeof zStringInputSpec>
export type ComboInputSpec = z.infer<typeof zComboInputSpec>
export type CustomInputSpec = z.infer<typeof zCustomInputSpec>
export type InputSpec = z.infer<typeof zInputSpec>
export type OutputSpec = z.infer<typeof zOutputSpec>
export type ComfyNodeDef = z.infer<typeof zNodeDef>