import type { RichTextLegacy, RichTextLegacyBlock, RichTextLegacySpan } from "../legacy/richText" import { RichTextLegacyBlockSchema, RichTextLegacySchema, RichTextNodeType, } from "../legacy/richText" import type { RichTextContent, RichTextContentBlock, RichTextContentSpan } from "../richText" import { RichTextContentSchema, RichTextContentType } from "../richText" import { embedContentToLegacy, embedLegacyToContent } from "./embed" import { imageLegacyToContent } from "./image" import type { LegacyCodec, LegacyContentCtx } from "./legacyContentCtx" import { linkLegacyToValue, linkValueToLegacy } from "./link" // Also used by content/codec/table export function blockLegacyToValue(block: RichTextLegacyBlock): RichTextContentBlock { if (block.type === RichTextNodeType.embed) { return { ...block, data: embedLegacyToContent(block.data), } } if (block.type === RichTextNodeType.image) { return { ...block, data: { ...imageLegacyToContent(block.data), ...(block.data.linkTo ? { linkTo: linkLegacyToValue(block.data.linkTo) } : {}), }, } } const spans: RichTextContentSpan[] = [] for (const span of block.content.spans ?? []) { if (span.type === RichTextNodeType.hyperlink) { // Legacy documents can have hyperlink spans with null data. We // drop them since a hyperlink without link data is meaningless. if (span.data) { spans.push({ ...span, data: linkLegacyToValue(span.data) }) } } else { spans.push(span) } } return { ...block, content: { ...block.content, spans } } } // Also used by content/codec/table export function blockValueToLegacy(block: RichTextContentBlock): RichTextLegacyBlock { if (block.type === RichTextNodeType.embed) { return { ...block, data: embedContentToLegacy(block.data), } } if (block.type === RichTextNodeType.image) { return { ...block, data: { ...block.data, ...(block.data.linkTo ? { linkTo: linkValueToLegacy(block.data.linkTo) } : {}), }, } } if ("content" in block) { const spans: RichTextLegacySpan[] = [] for (const span of block.content.spans ?? []) { if (span.type === RichTextNodeType.hyperlink) { // Legacy documents can have hyperlink spans with null data. We // drop them since a hyperlink without link data is meaningless. if (span.data) { spans.push({ ...span, data: linkValueToLegacy(span.data) }) } } else { spans.push(span) } } return { ...block, content: { ...block.content, spans } } } return RichTextLegacyBlockSchema.parse(block) } export const RichTextLegacyCodec = ( ctx: LegacyContentCtx, ): LegacyCodec => ({ name: "RichTextLegacy", is(input): input is RichTextContent { return RichTextContentSchema.safeParse(input).success }, toContent(input) { const parsed = RichTextLegacySchema.safeParse(input) if (!parsed.success) { return parsed } return { success: true, data: { value: parsed.data.map((block) => blockLegacyToValue(block)), __TYPE__: RichTextContentType, }, } }, fromContent(input) { return { content: input.value.map((block) => blockValueToLegacy(block)), types: { [ctx.keyOfType]: "StructuredText" }, keys: {}, } }, })