UNPKG

@prismicio/types-internal

Version:
165 lines (141 loc) 3.83 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 { ContentPath, TraverseWidgetContentFn, } from "../../../_internal/utils" import type { Link, NestableWidget } from "../../../customtypes" import type { LegacyContentCtx, WithTypes } from "../../LegacyContentCtx" import { hasContentType } from "../../utils" import { isLinkContent, LinkContent, LinkContentLegacy, LinkContentType, } from "./LinkContent" const RepeatableContentType = "RepeatableContent" as const export const RepeatableContent = t.strict({ __TYPE__: t.literal(RepeatableContentType), type: t.literal("Link"), value: t.array(LinkContent), }) export type RepeatableContent = t.TypeOf<typeof RepeatableContent> export const isRepeatableContent = (u: unknown): u is RepeatableContent => hasContentType(u) && u.__TYPE__ === RepeatableContentType export const RepeatableLegacy = ( ctx: LegacyContentCtx, fieldType: "Link", ): t.Type<RepeatableContent, WithTypes<Array<unknown>>, unknown> => { return new t.Type<RepeatableContent, WithTypes<Array<unknown>>, unknown>( "RepeatableLegacy", isRepeatableContent, (items) => { const parsed = pipe( t.array(t.unknown).decode(items), either.map((items) => { const parsedItems = items.reduce<Array<LinkContent>>((acc, item) => { let result switch (fieldType) { case "Link": result = LinkContentLegacy(ctx).decode(item) break } if (!result) return acc if (isLeft(result)) return acc return [...acc, result.right] }, []) return { value: parsedItems, type: fieldType, __TYPE__: "RepeatableContent" as const, } }), ) return parsed }, (r: RepeatableContent) => { const res = t.array(LinkContent).encode(r.value) const encodedItems = res.reduce<Array<WithTypes<unknown>>>( (acc, item) => { let encoded switch (item.__TYPE__) { case LinkContentType: encoded = LinkContentLegacy(ctx).encode(item) break } if (!encoded) return acc return [...acc, encoded] }, [], ) return { content: encodedItems.map((encodedItem) => encodedItem.content), types: { [ctx.keyOfType]: `Repeatable.${fieldType}` }, keys: encodedItems.reduce<Record<string, string>>( (acc, item) => ({ ...acc, ...item.keys }), {}, ), } }, ) } export type RepeatableCustomType = Link export function traverseRepeatableContent({ path, key, apiId, model, content, }: { path: ContentPath key: string apiId: string content: RepeatableContent model?: NestableWidget | undefined }) { return ( transform: TraverseWidgetContentFn, ): RepeatableContent | undefined => { const items = content.value.reduce<Array<LinkContent>>( (acc, fieldContent, index) => { const itemPath = path.concat([ { key: index.toString(), type: "Widget" }, ]) // Content inside repeatable can't be repeatable. const newModel = model?.type === "Link" && model.config ? { ...model, config: { ...model.config, repeat: false }, } : model const transformedField = transform({ path: itemPath, key: key, apiId: apiId, model: newModel, content: fieldContent, }) // Can happen if the transform function returns undefined to filter out a field if (!transformedField) return acc // If the transformed field is not a link content, we don't include it if (!isLinkContent(transformedField)) return acc return acc.concat(transformedField) }, [], ) return transform({ path, key, apiId, model, content: { __TYPE__: content.__TYPE__, type: content.type, value: items, }, }) } }