import type { SharedSliceModel, SharedSliceModelVariation } from "../slice" import { type DiffChange, DiffOperation } from "./changes" import { isNotEmpty, toRecord, zipObjects } from "./utils" import { type VariationDiff, VariationComparator } from "./variation" export type SliceMetadata = Omit export type SliceDiff = DiffChange< SharedSliceModel, Partial< SliceMetadata & { variations?: Partial> } > > function compareSliceMeta( sliceA?: SharedSliceModel, sliceB?: SharedSliceModel, ): Partial { const zippedSlices = zipObjects(sliceA, sliceB) return Object.entries(zippedSlices).reduce((acc, [key, value]) => { if (key === "variations") return acc if (value?.left === value?.right) return acc return { ...acc, [key]: value?.right } }, {}) } export const SliceComparator = { compare(sliceA?: SharedSliceModel, sliceB?: SharedSliceModel): SliceDiff | undefined { if (!sliceA && sliceB) return { op: DiffOperation.Added, value: sliceB, } if (sliceA && !sliceB) return { op: DiffOperation.Removed, } const diffMeta = compareSliceMeta(sliceA, sliceB) const zippedSlices = zipObjects( sliceA && toRecord(sliceA.variations, (v) => v.id), sliceB && toRecord(sliceB.variations, (v) => v.id), ) const diffVariations = Object.entries(zippedSlices).reduce< Partial> >((acc, [variationId, value]) => { if (!value) return acc const vDiff = VariationComparator.compare(value.left, value.right) if (!vDiff) return acc return { ...acc, [variationId]: vDiff, } }, {}) const diffSlice = { ...diffMeta, ...(isNotEmpty(diffVariations) ? { variations: diffVariations } : {}), } if (isNotEmpty(diffSlice)) { return { op: DiffOperation.Updated, value: diffSlice, } } return undefined }, }