mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
[Schema] ComfyNodeDefV2 schema (#2847)
This commit is contained in:
121
src/schemas/nodeDef/migration.ts
Normal file
121
src/schemas/nodeDef/migration.ts
Normal 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
|
||||
}
|
||||
}
|
||||
93
src/schemas/nodeDef/nodeDefSchemaV2.ts
Normal file
93
src/schemas/nodeDef/nodeDefSchemaV2.ts
Normal 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>
|
||||
Reference in New Issue
Block a user