UNPKG

@prismicio/types-internal

Version:
168 lines (145 loc) 4.16 kB
import { Objects } from "../../utils" import { Group, GroupFieldType } from "../widgets/Group" import type { NestableWidget } from "../widgets/nestable" import type { SlicePrimaryWidget } from "../widgets/slices" import type { Variation } from "../widgets/slices" import { type DiffChange, DiffOperation } from "./Changes" import type { GroupWidgetWithFieldsDiff, NestableWidgetDiff, SlicePrimaryWidgetDiff, } from "./Widgets" export type VariationMetadata = Omit<Variation, "primary" | "items"> export type VariationDiff = DiffChange< Variation, Partial<VariationMetadata> & { primary?: Record<string, SlicePrimaryWidgetDiff> items?: Record<string, NestableWidgetDiff> } > function compareVariationMeta( variationA?: Variation, variationB?: Variation, ): Partial<VariationMetadata> { const zippedVariations = Objects.zipObjects(variationA, variationB) return Object.entries(zippedVariations).reduce((acc, [key, value]) => { if (key === `primary` || key === "items") return acc if (value?.left === value?.right) return acc return { ...acc, [key]: value?.right } }, {}) } function compareWidgets<TWidget extends NestableWidget | Group>( widgetsA?: { [key: string]: TWidget }, widgetsB?: { [key: string]: TWidget }, ): | Record< string, SlicePrimaryWidget extends TWidget ? SlicePrimaryWidgetDiff : NestableWidgetDiff > | undefined { const zippedWidgets = Objects.zipObjects(widgetsA, widgetsB) const diffWidgets = Object.entries(zippedWidgets).reduce( (acc, [widgetKey, widgetValue]) => { if ( JSON.stringify(widgetValue?.left) === JSON.stringify(widgetValue?.right) ) return acc const changes = (() => { if (!widgetValue?.left && !widgetValue?.right) return if (widgetValue?.left && !widgetValue.right) { return { op: DiffOperation.Removed, } } if (!widgetValue?.left && widgetValue?.right) { if (widgetValue.right?.type === GroupFieldType) { const group: GroupWidgetWithFieldsDiff = { ...widgetValue.right, config: { ...widgetValue.right.config, fields: {}, }, } // On added groups, this basically marks all fields in the group as added group.config.fields = compareWidgets(undefined, widgetValue.right.config?.fields) || {} return { op: DiffOperation.Added, value: group, } } return { op: DiffOperation.Added, value: widgetValue.right, } } if (widgetValue.right?.type === GroupFieldType) { const group: GroupWidgetWithFieldsDiff = { ...widgetValue.right, config: { ...widgetValue.right.config, fields: {}, }, } // On updated groups, this also compares the fields inside the group group.config.fields = compareWidgets( widgetValue.left?.type === GroupFieldType ? widgetValue.left?.config?.fields : undefined, widgetValue.right.config?.fields, ) || {} return { op: DiffOperation.Updated, value: group, } } return { op: DiffOperation.Updated, value: widgetValue.right, } })() if (!changes) return acc return { ...acc, [widgetKey]: changes, } }, {}, ) return Objects.isNotEmpty(diffWidgets) ? diffWidgets : undefined } export const VariationComparator = { compare( variationA?: Variation, variationB?: Variation, ): VariationDiff | undefined { if (variationA && !variationB) return { op: DiffOperation.Removed, } if (!variationA && variationB) { return { op: DiffOperation.Added, value: variationB, } } const diffMeta = compareVariationMeta(variationA, variationB) const diffPrimary = compareWidgets(variationA?.primary, variationB?.primary) const diffItems = compareWidgets(variationA?.items, variationB?.items) const diffVariation = { ...diffMeta, ...(diffPrimary ? { primary: diffPrimary } : {}), ...(diffItems ? { items: diffItems } : {}), } if (Objects.isNotEmpty(diffVariation)) { return { op: DiffOperation.Updated, value: diffVariation, } } return undefined }, }