UNPKG

@prismicio/types-internal

Version:
290 lines (260 loc) 7.03 kB
import { either } from "fp-ts" import { pipe } from "fp-ts/lib/function" import * as t from "io-ts" import { ContentPath, SliceModel, TraverseSliceContentFn, TraverseWidgetContentFn, } from "../../../_internal/utils" import { type StaticSlices, CompositeSlice, Group, isCompositeSlice, isLegacySlice, isStaticSharedSlice, NestableWidget, SharedSlice, VariationFields, } from "../../../customtypes" import type { FieldOrSliceType, LegacyContentCtx, WithTypes, } from "../../LegacyContentCtx" import { hasContentType } from "../../utils" import { traverseCompositeSliceContent } from "./Slice/CompositeSliceContent" import { traverseSharedSliceContent } from "./Slice/SharedSliceContent" import { traverseSimpleSliceContent } from "./Slice/SimpleSliceContent" import { isCompositeSliceItemContent, isSharedSliceItemContent, isSimpleSliceItemContent, SliceItemContent, sliceItemContentWithDefaultValues, SlicesItemLegacy, } from "./SliceItem" export const SlicesContentType = "SliceContentType" export const isSlicesContent = (u: unknown): u is SlicesContent => hasContentType(u) && u.__TYPE__ === SlicesContentType type SlicesLegacy = Array<unknown> export const SlicesLegacy = (ctx: LegacyContentCtx) => { const codec = t.array(SlicesItemLegacy(ctx)) return new t.Type<SlicesContent, WithTypes<SlicesLegacy>, unknown>( "SlicesLegacy", isSlicesContent, (items) => { return pipe( codec.decode(items), either.map((parsedSlices) => { return { __TYPE__: SlicesContentType, value: parsedSlices, } }), ) }, (s: SlicesContent) => { const result = codec.encode(s.value) return { content: result.map((s) => s.content), types: result.reduce<Record<string, FieldOrSliceType>>( (acc, s) => ({ ...acc, ...s.types }), { [ctx.keyOfType]: "Slices" }, ), keys: result.reduce<Record<string, string>>( (acc, s) => ({ ...acc, ...s.keys }), {}, ), } }, ) } export const SlicesContent = t.type({ __TYPE__: t.literal(SlicesContentType), value: t.array(SliceItemContent), }) export type SlicesContent = t.TypeOf<typeof SlicesContent> export function slicesContentWithDefaultValues( codec: StaticSlices, content: SlicesContent, ): SlicesContent { const choices = codec?.config?.choices if (choices === undefined) return content const updateSlicesValue = content.value.map((slice) => { const sliceConfig = choices[slice.name] if (sliceConfig) { const updatedSliceWidget = sliceItemContentWithDefaultValues( sliceConfig, slice.widget, ) return { ...slice, widget: updatedSliceWidget, } } return slice }) return { ...content, value: updateSlicesValue, } } function findSliceModel( slicesPath: ContentPath, model: StaticSlices, content: SliceItemContent, ): SliceModel | undefined { const defaultModel = model?.config?.choices?.[content.name] // regular case for shared slices const sharedSliceModel = (): VariationFields | undefined => { if (isSharedSliceItemContent(content)) { if (defaultModel && isStaticSharedSlice(defaultModel)) { const variationDef = defaultModel.variations.find( (v) => v.id === content.widget.variation, ) return variationDef ? { type: "SharedSlice", sliceName: defaultModel.id, variationId: variationDef.id, fields: { primary: variationDef.primary || {}, items: variationDef.items || {}, }, } : undefined } } return } const migratedSliceModel = (): VariationFields | undefined => { const legacyContentPath = ContentPath.append( ContentPath.serialize(slicesPath), content.name, ) const migratedSliceModel = Object.values(model?.config?.choices || {}).find( (sliceModel): sliceModel is SharedSlice => { if (isStaticSharedSlice(sliceModel)) { return !!sliceModel.legacyPaths?.[legacyContentPath] } return false }, ) if (!migratedSliceModel) return const migratedVariation = migratedSliceModel?.variations.find( (v) => v.id === migratedSliceModel.legacyPaths?.[legacyContentPath], ) if (!migratedVariation) return return { type: "SharedSlice", sliceName: migratedSliceModel.id, variationId: migratedVariation.id, fields: { primary: migratedVariation.primary || {}, items: migratedVariation.items || {}, }, } } const legacySliceModel = (): | NestableWidget | CompositeSlice | Group | undefined => { if (!defaultModel) return if (isCompositeSlice(defaultModel)) { return { type: "Slice", "non-repeat": defaultModel["non-repeat"] || {}, repeat: defaultModel.repeat || {}, } } if (isLegacySlice(defaultModel)) { return defaultModel } return } return sharedSliceModel() || migratedSliceModel() || legacySliceModel() } export function traverseSlices({ path, key, model, content, }: { path: ContentPath key: string content: SlicesContent model?: StaticSlices | undefined }) { return ({ transformWidget = ({ content }) => content, transformSlice = ({ content }) => content, }: { transformWidget?: TraverseWidgetContentFn transformSlice?: TraverseSliceContentFn }): SlicesContent | undefined => { const value = content.value.reduce<SlicesContent["value"]>( (acc, sliceContent) => { const sliceModel = model && findSliceModel(path, model, sliceContent) const convertedSlice: SliceItemContent | undefined = (() => { if (isSharedSliceItemContent(sliceContent)) return traverseSharedSliceContent({ path: path.concat({ key: sliceContent.key, type: "SharedSlice", }), sliceKey: sliceContent.key, sliceName: sliceContent.name, model: sliceModel?.type === "SharedSlice" ? sliceModel : undefined, content: sliceContent, })(transformWidget, transformSlice) if (isCompositeSliceItemContent(sliceContent)) return traverseCompositeSliceContent({ path: path.concat({ key: sliceContent.key, type: "Slice", }), sliceKey: sliceContent.key, sliceName: sliceContent.name, model: sliceModel?.type === "Slice" || sliceModel?.type === "SharedSlice" ? sliceModel : undefined, content: sliceContent, })(transformWidget, transformSlice) if (isSimpleSliceItemContent(sliceContent)) return traverseSimpleSliceContent({ path: path.concat({ key: sliceContent.key, type: "LegacySlice", }), sliceKey: sliceContent.key, sliceName: sliceContent.name, model: sliceModel && sliceModel?.type !== "Slice" ? sliceModel : undefined, content: sliceContent, })(transformWidget, transformSlice) return })() return convertedSlice ? acc.concat(convertedSlice) : acc }, [], ) return transformWidget({ path, key, apiId: key, model, content: { __TYPE__: content.__TYPE__, value, }, }) } }