import type { NodeChange, PluginData, PluginRelaunchData } from '#core/kiwi/binary/codec' import type { PluginDataEntry, PluginRelaunchDataEntry } from '#core/scene-graph' import { guidToString } from './guid' export const OPEN_PENCIL_PLUGIN_ID = 'open-pencil' export const TEXT_DIRECTION_PLUGIN_KEY = 'textDirection' export const LAYOUT_DIRECTION_PLUGIN_KEY = 'layoutDirection' export const NODE_TYPE_PLUGIN_KEY = 'nodeType' export const BOUND_VARIABLES_PLUGIN_KEY = 'boundVariables' export function upsertPluginData( node: { pluginData: PluginDataEntry[] }, key: string, value: string ): void { const pluginData = node.pluginData.filter( (entry) => !(entry.pluginId === OPEN_PENCIL_PLUGIN_ID && entry.key === key) ) pluginData.push({ pluginId: OPEN_PENCIL_PLUGIN_ID, key, value }) node.pluginData = pluginData } function parseBoundVariablesPluginValue(value: string | null): Record { if (!value) return {} try { const parsed = JSON.parse(value) as unknown if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {} return Object.fromEntries( Object.entries(parsed).filter( (entry): entry is [string, string] => typeof entry[0] === 'string' && typeof entry[1] === 'string' ) ) } catch { return {} } } export function extractBoundVariables(nc: NodeChange): Record { const bindings = parseBoundVariablesPluginValue( getOpenPencilPluginValue(nc, BOUND_VARIABLES_PLUGIN_KEY) ) nc.fillPaints?.forEach((paint, i) => { if (paint.colorVariableBinding) { bindings[`fills/${i}/color`] = guidToString(paint.colorVariableBinding.variableID) } }) nc.strokePaints?.forEach((paint, i) => { if (paint.colorVariableBinding) { bindings[`strokes/${i}/color`] = guidToString(paint.colorVariableBinding.variableID) } }) return bindings } export function extractPluginData(nc: NodeChange): PluginDataEntry[] { return (nc.pluginData ?? []).map((entry) => ({ pluginId: entry.pluginID, key: entry.key, value: entry.value })) } export function getOpenPencilPluginValue(nc: NodeChange, key: string): string | null { return ( nc.pluginData?.find((entry) => entry.pluginID === OPEN_PENCIL_PLUGIN_ID && entry.key === key) ?.value ?? null ) } export function extractPluginRelaunchData(nc: NodeChange): PluginRelaunchDataEntry[] { return (nc.pluginRelaunchData ?? []).map((entry) => ({ pluginId: entry.pluginID, command: entry.command, message: entry.message, isDeleted: entry.isDeleted })) } export function mergePluginData(pluginData: PluginDataEntry[]): PluginData[] { return pluginData.map((entry) => ({ pluginID: entry.pluginId, key: entry.key, value: entry.value })) } export function serializePluginRelaunchData( entries: PluginRelaunchDataEntry[] ): PluginRelaunchData[] { return entries.map((entry) => ({ pluginID: entry.pluginId, command: entry.command, message: entry.message, isDeleted: entry.isDeleted })) }