/** * Shallow-merges two ECharts option objects: * - Top-level keys from both are combined. * - Arrays are merged by index (element-wise shallow merge, primitive override). * - Plain objects are shallow-merged. * - Primitives are overridden by the override value. * * Designed for the two-stage memoization pattern: first build a base option * object from data + theme + formatters, then call `mergeOptions(base, override)` * inside a second `useMemo` keyed on `[base, override]`. */ export function mergeOptions>( base: T, override?: Partial, ): T { if (!override) return base const out: Record = { ...base } for (const key of Object.keys(override) as (keyof T)[]) { const a = base[key] const b = override[key] if (b === undefined) continue out[key as string] = mergeValue(a, b) } return out as T } function mergeValue(a: unknown, b: unknown): unknown { if (Array.isArray(a) && Array.isArray(b)) { const len = Math.max(a.length, b.length) const result = new Array(len) for (let i = 0; i < len; i++) { const av: unknown = a[i] const bv: unknown = b[i] if (bv === undefined) result[i] = av else if (av === undefined) result[i] = bv else result[i] = mergeValue(av, bv) } return result } if (isPlainObject(a) && isPlainObject(b)) { return { ...a, ...b } } return b } function isPlainObject(v: unknown): v is Record { if (v === null || typeof v !== 'object') return false const proto = Object.getPrototypeOf(v) as unknown return proto === Object.prototype || proto === null }