@prismicio/types-internal
Version:
Prismic types for Custom Types and Prismic Data
153 lines (132 loc) • 4.16 kB
text/typescript
import * as t from "io-ts"
import { withFallback } from "io-ts-types/lib/withFallback"
import type { OnFieldFn } from "../../../_internal/utils"
import { WidgetKey } from "../../../common"
import { Group, NestedGroup, traverseGroup } from "../Group"
import { NestableWidget } from "../nestable/NestableWidget"
import type { SharedSliceRef } from "./SharedSliceRef"
import type { DynamicSlice, StaticSlice } from "./Slice"
import { SlicePrimaryWidget } from "./SlicePrimaryWidget"
const IMAGE_PLACEHOLDER_URL =
"https://images.prismic.io/slice-machine/621a5ec4-0387-4bc5-9860-2dd46cbc07cd_default_ss.png?auto=compress,format"
export const Variation = t.exact(
t.intersection([
t.type({
id: t.string,
name: t.string,
description: t.string,
imageUrl: withFallback(t.string, IMAGE_PLACEHOLDER_URL),
docURL: t.string,
version: t.string,
}),
t.partial({
display: t.string,
primary: t.record(WidgetKey, SlicePrimaryWidget),
items: t.record(WidgetKey, NestableWidget),
}),
]),
)
export type Variation = t.TypeOf<typeof Variation>
// VariationFields is used exclusively for the slices migration, LegacySlice -> SharedSlice
export type VariationFields = {
type: "SharedSlice"
sliceName: string
variationId: string
fields: Pick<Variation, "primary" | "items">
}
export const SharedSliceType = "SharedSlice"
const LegacyPath = t.string
const VariationId = t.string
export const SharedSlice = t.exact(
t.intersection([
t.type({
id: t.string,
type: t.literal(SharedSliceType),
name: t.string,
variations: t.readonlyArray(Variation),
}),
t.partial({
description: t.string,
legacyPaths: t.record(LegacyPath, VariationId),
}),
]),
)
export type SharedSlice = t.TypeOf<typeof SharedSlice>
export function isStaticSharedSlice(slice: StaticSlice): slice is SharedSlice {
return slice.type === "SharedSlice"
}
export function isDynamicSharedSlice(
slice: DynamicSlice,
): slice is SharedSliceRef {
return slice.type === "SharedSlice"
}
export function traverseVariation(args: {
path: ReadonlyArray<string>
variation: Variation
onField: OnFieldFn<NestableWidget | Group | NestedGroup>
}): Variation {
const { path: prevPath, variation, onField } = args
let primary: Record<string, NestableWidget | Group> | undefined
for (const [key, prevField] of Object.entries(variation.primary ?? {})) {
const path = [...prevPath, "primary", key]
let field
switch (prevField.type) {
case "Group":
field = traverseGroup({
path,
group: prevField,
onField: onField as OnFieldFn<NestableWidget | NestedGroup>,
})
break
default:
field = prevField
break
}
const newField = onField({ path, key, field })
if (field !== newField) {
if (!primary) primary = { ...variation.primary }
primary[key] = newField
}
}
let items: Record<string, NestableWidget> | undefined
for (const [key, prevField] of Object.entries(variation.items ?? {})) {
const path = [...prevPath, "items", key]
const newField = (onField as OnFieldFn<NestableWidget>)({
path,
key,
field: prevField,
})
if (prevField !== newField) {
if (!items) items = { ...variation.items }
items[key] = newField
}
}
// returns the traversed model instead of a new one if it didn't change
return primary || items
? { ...variation, ...(primary && { primary }), ...(items && { items }) }
: variation
}
export function traverseSharedSlice(args: {
path: ReadonlyArray<string>
slice: SharedSlice
onField: OnFieldFn<NestableWidget | Group | NestedGroup>
}): SharedSlice {
const { path: prevPath, slice, onField } = args
let variations: Variation[] | undefined
for (let i = 0; i < slice.variations.length; i++) {
const variation = slice.variations[i]
if (!variation) continue
const path = [...prevPath, variation.id]
const newVariation = traverseVariation({
path,
variation,
onField,
})
if (newVariation !== variation) {
if (!variations) variations = [...slice.variations]
variations[i] = newVariation
}
}
// returns the traversed model instead of a new one if it didn't change
return variations ? { ...slice, variations } : slice
}