import { BooleanContentType } from "../content/boolean" import type { DocumentContent } from "../content/document" import { FieldContentType, SelectFieldType } from "../content/field" import type { GroupContent, GroupItemContent } from "../content/group" import { GroupContentType } from "../content/group" import type { SliceContent } from "../content/slice" import { CompositeSliceContentType, SharedSliceContentType } from "../content/slice" import type { SlicesContent } from "../content/slices" import { SlicesContentType } from "../content/slices" import type { WidgetContent } from "../content/widget" import type { StaticCustomTypeModel } from "../model/customType" import type { GroupModel } from "../model/group" import type { NestableModel } from "../model/nestable" import type { StaticSliceModel } from "../model/slice" import type { StaticWidgetModel } from "../model/widget" import * as customTypeModel from "./customTypeModel" export function document(content: DocumentContent, model: StaticCustomTypeModel): DocumentContent { return record(content, customTypeModel.flatten(model)) } export function slice(content: SliceContent, model: StaticSliceModel | undefined): SliceContent { if (!model) { return content } if (model.type === "SharedSlice") { if (content.__TYPE__ !== SharedSliceContentType) { return content } const variation = model.variations.find((variation) => variation.id === content.variation) if (!variation) { return content } return { ...content, primary: record(content.primary, variation?.primary), items: items(content.items, variation?.items), } } if (model.type === "Slice") { if (content.__TYPE__ !== CompositeSliceContentType) { return content } return { ...content, nonRepeat: record(content.nonRepeat, model["non-repeat"]), repeat: items(content.repeat, model.repeat), } } if ( content.__TYPE__ === SharedSliceContentType || content.__TYPE__ === CompositeSliceContentType ) { return content } return widget(content, model) } export function widget( content: TContent, model: StaticWidgetModel | undefined, ): TContent { if (!model) { return content } if ( (model.type === "Slices" || model.type === "Choice") && content?.__TYPE__ === SlicesContentType ) { if (!model.config?.choices) return content const value: SlicesContent["value"] = [] for (const sliceItem of content.value) { value.push({ ...sliceItem, widget: slice(sliceItem.widget, model.config.choices[sliceItem.name]), }) } return { ...content, value } } if (model.type === "Group") { if (content?.__TYPE__ !== GroupContentType) { return { __TYPE__: GroupContentType, value: items([], model.config?.fields), } } return { ...content, value: items(content.value, model.config?.fields) } } if (model.type === "Boolean" && !content) { if (model.config?.default_value === undefined) { return undefined } return { __TYPE__: BooleanContentType, value: model.config.default_value, } } if (model.type === "Select" && !content) { if (!model.config?.default_value) { return undefined } return { __TYPE__: FieldContentType, type: SelectFieldType, value: model.config.default_value, } } return content } export function items( items: GroupContent["value"], fields: Record | undefined, ): GroupContent["value"] { if (!fields) { return items } const itemsWithDefaults: GroupContent["value"] = [] for (const item of items) { const itemValue: GroupItemContent["value"] = [] const missingFields = { ...fields } for (const [key, value] of item.value) { delete missingFields[key] itemValue.push([key, widget(value, fields[key])]) } for (const [key, field] of Object.entries(missingFields)) { const content = widget(undefined, field) if (content) { itemValue.push([key, content]) } } itemsWithDefaults.push({ ...item, value: itemValue }) } return itemsWithDefaults } function record( record: Record, fields: Record | undefined, ): Record { if (!fields) { return record } const missingFields = { ...fields } const recordWithDefaults: Record = {} for (const [key, value] of Object.entries(record)) { delete missingFields[key] recordWithDefaults[key] = widget(value, fields[key]) } for (const [key, field] of Object.entries(missingFields)) { const content = widget(undefined, field) if (content) { recordWithDefaults[key] = content } } return recordWithDefaults }