UNPKG

@prismicio/types-internal

Version:
185 lines (169 loc) 5.08 kB
import { either } from "fp-ts" import { isLeft } from "fp-ts/lib/Either" import { pipe } from "fp-ts/lib/function" import * as t from "io-ts" import type { StaticSlice } from "../../../customtypes" import { nullable } from "../../../validators/function" import { getFieldCtx, LegacyContentCtx, WithTypes, } from "../../LegacyContentCtx" import type { TraverseSliceContentFn } from "../../utils" import { isGroupContent } from "../GroupContent" import { isNestableContent } from "../nestable" import { repeatableContentWithDefaultNestableContentValues } from "../withDefaultValues" import { compositeSliceContentWithDefaultValues, sharedSliceContentWithDefaultValues, SliceContent, SliceLegacy, } from "./Slice" import { CompositeSliceContent, isCompositeSliceContent, migrateCompositeSlice, } from "./Slice/CompositeSliceContent" import { isSharedSliceContent, SharedSliceContent, } from "./Slice/SharedSliceContent" import { isSimpleSliceContent, migrateSimpleSlice, SimpleSliceContent, } from "./Slice/SimpleSliceContent" export const SliceItemContent = t.type({ key: t.string, name: t.string, maybeLabel: t.union([t.string, t.undefined]), widget: SliceContent, }) export type SliceItemContent = t.TypeOf<typeof SliceItemContent> export type SharedSliceItemContent = Omit<SliceItemContent, "widget"> & { widget: SharedSliceContent } export function isSharedSliceItemContent( item: SliceItemContent, ): item is SharedSliceItemContent { return isSharedSliceContent(item.widget) } export type CompositeSliceItemContent = Omit<SliceItemContent, "widget"> & { widget: CompositeSliceContent } export function isCompositeSliceItemContent( item: SliceItemContent, ): item is CompositeSliceItemContent { return isCompositeSliceContent(item.widget) } export type SimpleSliceItemContent = Omit<SliceItemContent, "widget"> & { widget: SimpleSliceContent } export function isSimpleSliceItemContent( item: SliceItemContent, ): item is SimpleSliceItemContent { return isGroupContent(item.widget) || isNestableContent(item.widget) } export function sliceItemContentWithDefaultValues( customType: StaticSlice, content: SliceContent, ): SliceContent { if (customType.type === "SharedSlice" && isSharedSliceContent(content)) { return sharedSliceContentWithDefaultValues(customType, content) } if (customType.type === "Slice" && isCompositeSliceContent(content)) { return compositeSliceContentWithDefaultValues(customType, content) } if ( customType.type === "Group" && isGroupContent(content) && customType.config?.fields ) { const updateGroupFieldValue = repeatableContentWithDefaultNestableContentValues( customType.config.fields, content.value, ) return { ...content, value: updateGroupFieldValue, } } // Note - SimpleSliceContent can also be a NestableContent, but in that case we have no default value to fill, because the content is already there. // There is no key specified in custom type that does not have a value provided like in other cases. return content } const itemLegacyReader = t.exact( t.intersection([ t.type({ key: t.string, value: t.unknown, }), t.partial({ label: nullable(t.string), }), ]), ) export type SliceItemLegacy = t.TypeOf<typeof itemLegacyReader> export const SlicesItemLegacy = (ctx: LegacyContentCtx) => { return new t.Type<SliceItemContent, WithTypes<SliceItemLegacy>, unknown>( "SlicesItemLegacy", (u): u is SliceItemContent => ( isSharedSliceContent((u as SliceItemContent).widget), isCompositeSliceContent((u as SliceItemContent).widget), isSimpleSliceContent((u as SliceItemContent).widget) ), (sliceItem, context) => { return pipe( itemLegacyReader.decode(sliceItem), either.chain((parsedSlice) => { const stopIdx = parsedSlice.key.indexOf("$") const sliceName = parsedSlice.key.substring( 0, stopIdx > 0 ? stopIdx : undefined, ) const itemCtx = getFieldCtx({ fieldKey: sliceName, contentKey: parsedSlice.key, ctx, }) const item = SliceLegacy(itemCtx).decode(parsedSlice.value) if (!item || isLeft(item)) return t.failure(sliceItem, context) return t.success({ key: parsedSlice.key, name: sliceName, maybeLabel: parsedSlice.label ?? undefined, widget: item.right, }) }), ) }, (sItem: SliceItemContent) => { const itemCtx = getFieldCtx({ fieldKey: sItem.name, contentKey: sItem.key, ctx, }) const result = SliceLegacy(itemCtx).encode(sItem.widget) return { content: { key: sItem.key, label: sItem.maybeLabel, value: result?.content || {}, }, types: result?.types || {}, keys: result?.keys || {}, } }, ) } export const migrateSliceItem: TraverseSliceContentFn = ({ model, content, }) => { if (isCompositeSliceItemContent(content) && model?.type === "SharedSlice") return migrateCompositeSlice(model, content) if (isSimpleSliceItemContent(content) && model?.type === "SharedSlice") return migrateSimpleSlice(model, content) return content }