diff --git a/src/extensions/dispatch.ts b/src/extensions/dispatch.ts index a527d3886..efd2166ee 100644 --- a/src/extensions/dispatch.ts +++ b/src/extensions/dispatch.ts @@ -2,9 +2,17 @@ import { isCloud } from '@/platform/distribution/types' import type { ComfyExtensionConfigs, ComfyExtensionEntrance, - ComfyExtensionLoadContext + ComfyExtensionLoadContext, + StaticComfyCommand, + StaticComfyKeybinding, + StaticComfyMenuCommandGroup, + StaticComfySettingParams } from './types' -import { formatExtensions, normalizationActivationEvents } from './utils' +import { + defineProcessQueue, + formatExtensions, + normalizationActivationEvents +} from './utils' const extLoadContext: ComfyExtensionLoadContext = { get isCloud() { @@ -29,6 +37,18 @@ export async function dispatchComfyExtensions(options: { activationEvents.forEach((event) => onceExtImportEvent(event, async () => void (await extension.entry())) ) + + let contributes = extension.config?.contributes + if (contributes && !Array.isArray(contributes)) contributes = [contributes] + if (contributes && contributes.length) { + for (const contribute of contributes) { + const { settings, commands, keybindings, menuCommands } = contribute + if (settings) pushExtensionSettings(settings) + if (commands) pushExtensionCommands(commands) + if (keybindings) pushExtensionKeybindings(keybindings) + if (menuCommands) pushExtensionMenuCommands(menuCommands) + } + } } } @@ -54,3 +74,23 @@ function onceExtImportEvent(event: string, callback: EventCallback) { eventMap.set(event, new Set([callback])) } } + +const { process: _processExtensionSettings, push: pushExtensionSettings } = + defineProcessQueue() +export const processExtensionSettings = _processExtensionSettings + +const { process: _processExtensionCommands, push: pushExtensionCommands } = + defineProcessQueue() +export const processExtensionCommands = _processExtensionCommands + +const { + process: _processExtensionMenuCommands, + push: pushExtensionMenuCommands +} = defineProcessQueue() +export const processExtensionMenuCommands = _processExtensionMenuCommands + +const { + process: _processExtensionKeybindings, + push: pushExtensionKeybindings +} = defineProcessQueue() +export const processExtensionKeybindings = _processExtensionKeybindings diff --git a/src/extensions/types.ts b/src/extensions/types.ts index fa788933c..bb5ffde4c 100644 --- a/src/extensions/types.ts +++ b/src/extensions/types.ts @@ -4,19 +4,21 @@ import type { ComfyExtension } from '@/types' type ExcludeFunctions = T extends Function ? never : T type StaticOnly = { // eslint-disable-next-line prettier/prettier - [K in keyof T as ExcludeFunctions extends never ? never : K]: ExcludeFunctions + [K in keyof T as ExcludeFunctions extends never + ? never + : K]: ExcludeFunctions } -type StaticComfyCommand = StaticOnly< +export type StaticComfyCommand = StaticOnly< NonNullable[number] > -type StaticComfySettingParams = StaticOnly< +export type StaticComfySettingParams = StaticOnly< NonNullable[number] > -type StaticComfyKeybinding = StaticOnly< +export type StaticComfyKeybinding = StaticOnly< NonNullable[number] > -type StaticComfyMenuCommandGroup = StaticOnly< +export type StaticComfyMenuCommandGroup = StaticOnly< NonNullable[number] > @@ -30,6 +32,7 @@ type ComfyExtensionContributes = { name: string widgets?: string[] commands?: StaticComfyCommand[] + menuCommands?: StaticComfyMenuCommandGroup[] settings?: StaticComfySettingParams[] keybindings?: StaticComfyKeybinding[] } @@ -40,7 +43,6 @@ export interface ComfyExtensionConfig { activationEvents: ComfyExtensionActivationEvent[] contributes?: ComfyExtensionContributes | ComfyExtensionContributes[] - menuCommands?: StaticComfyMenuCommandGroup[] comfyCloud?: | boolean diff --git a/src/extensions/utils.ts b/src/extensions/utils.ts index 8b28f930e..d6539a9ae 100644 --- a/src/extensions/utils.ts +++ b/src/extensions/utils.ts @@ -107,3 +107,42 @@ function checkAboutCloud( // Default Extension -> Load Extension return true } + +/** + * Defines a queue processing function for handling elements in a queue. + * When elements are present in the queue, all existing elements are automatically retrieved + * and passed to the callback function for processing. + * Use the process method to register a callback function, and use the push method to add elements to the queue. + * @returns Returns an object containing process and push methods + */ +export function defineProcessQueue(): { + process: (worker: (items: T[]) => void) => void + push: (items: T[]) => void +} { + let worker: ((items: T[]) => void) | undefined = undefined + const items: T[] = [] + function push(newItems: T[]) { + items.push(...newItems) + consume() + } + function process(newWorker: (items: T[]) => void) { + if (worker) { + throw new Error('queue worker already registered') + } + worker = newWorker + consume() + } + + function consume() { + if (worker !== undefined && items.length > 0) { + const itemsToProcess = items.slice() + items.length = 0 + worker(itemsToProcess) + } + } + + return { + process, + push + } +}