import { z } from "zod/mini" import { DocumentLegacyCodec } from "../content/codec/document" import { defaultCtx } from "../content/codec/legacyContentCtx" import type { DocumentContent } from "../content/document" import type { DocumentLegacy } from "../content/legacy/document" import { DocumentLegacySchema } from "../content/legacy/document" import { isNestableContent } from "../content/nestable" import type { CompositeSliceItemContent, LegacySliceItemContent } from "../content/slices" import type { WidgetContent } from "../content/widget" import type { StaticCustomTypeModel } from "../model/customType" import type { FieldOrSliceType } from "../model/widget" import { FieldOrSliceTypeSchema } from "../model/widget" import * as contentPath from "./contentPath" import * as customTypeModel from "./customTypeModel" import * as sliceContent from "./sliceContent" import { traverseDocumentContent } from "./traverseContent" export function collectWidgets( document: DocumentContent, test: ( content: WidgetContent, args: { path: contentPath.Path key: string apiID: string }, ) => content is TWidgetContent, ): Record { const collected: Record = {} traverseDocumentContent(document, { transformWidget: ({ content, ...args }) => { if (test(content, args)) { collected[contentPath.serialize(args.path)] = content } return content }, }) return collected } export function fromLegacy( legacy: DocumentLegacy, model: StaticCustomTypeModel, ): DocumentContent | undefined { const parsed = DocumentLegacySchema.safeParse(legacy) if (!parsed.success) { return } const types = new Map() const keys = new Map() const widgets: DocumentLegacy = {} for (const [key, value] of Object.entries(parsed.data)) { if (key.endsWith("_TYPE")) { const parsed = FieldOrSliceTypeSchema.safeParse(value) if (parsed.success) { types.set(key.substring(0, key.length - 5), parsed.data) } } else if (key.endsWith("_KEY")) { const parsed = z.uuidv4().safeParse(value) if (parsed.success) { keys.set(key.substring(0, key.length - 4), parsed.data) } } else if (!key.endsWith("_POSITION")) { widgets[key] = value } } const result = DocumentLegacyCodec(defaultCtx("", types, keys)).toContent(widgets) if (!result.success) { return } const needsMigration = Object.values(customTypeModel.collectSharedSlices(model)).some((slice) => Boolean(slice.legacyPaths), ) if (needsMigration) { return traverseDocumentContent(result.data, { model, transformSlice: ({ content, model }) => { if (model?.type === "SharedSlice") { if (content.widget.__TYPE__ === "CompositeSliceContent") { return sliceContent.compositeToShared(content as CompositeSliceItemContent, model) } else if ( content.widget.__TYPE__ === "GroupContentType" || isNestableContent(content.widget) ) { return sliceContent.legacyToShared(content as LegacySliceItemContent, model) } } return content }, }) } return result.data } export function toLegacy(document: DocumentContent): DocumentLegacy { const { content, types, keys } = DocumentLegacyCodec(defaultCtx("")).fromContent(document) return { ...content, ...types, ...keys } }