@prismicio/types-internal
Version:
Prismic types for Custom Types and Prismic Data
168 lines (145 loc) • 4.16 kB
text/typescript
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
},
}