import type { Transform } from './types' export function applyTransforms( input: unknown, transforms: readonly Transform[], onError?: (id: string, error: Error) => void, ): unknown { const disabledIds = new Set() for (const t of transforms) { if (t.enabled && t.disables?.length) { for (const id of t.disables) disabledIds.add(id) } } let acc: unknown = input for (const t of transforms) { if (!t.enabled) continue if (disabledIds.has(t.id)) continue try { acc = t.fn(acc) } catch (e) { const err = e instanceof Error ? e : new Error(String(e)) // eslint-disable-next-line no-console console.warn(`[widgets-v2] Transform "${t.id}" failed:`, err) onError?.(t.id, err) } } return acc } export function upsertTransform( transforms: readonly Transform[], next: Transform, ): readonly Transform[] { const existing = transforms.find((t) => t.id === next.id) if ( existing?.order === next.order && existing?.enabled === next.enabled && existing?.fn === next.fn && existing?.type === next.type && sameStringArray(existing?.disables, next.disables) && sameStringArray(existing?.replaceMergeKeys, next.replaceMergeKeys) ) { return transforms } const filtered = transforms.filter((t) => t.id !== next.id) const idx = filtered.findIndex((t) => t.order > next.order) const out = filtered.slice() out.splice(idx === -1 ? out.length : idx, 0, next) return out } export function removeTransform( transforms: readonly Transform[], id: string, ): readonly Transform[] { if (!transforms.some((t) => t.id === id)) return transforms return transforms.filter((t) => t.id !== id) } function sameStringArray( a?: readonly string[], b?: readonly string[], ): boolean { if (a === b) return true if (!a) return !b?.length if (!b) return !a.length if (a.length !== b.length) return false for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false return true }