interface LexicalTextNode { type: string; text?: unknown; children?: unknown[]; } interface LexicalBlock { type: string; children?: unknown[]; } export type SerializedLexicalState = { root: { type: "root"; children: { type: "paragraph"; children: { type: "text"; text: string; version: number }[]; direction: null; format: ""; indent: number; version: number; }[]; direction: "ltr" | "rtl" | null; format: "left" | "start" | "center" | "right" | "end" | "justify" | ""; indent: number; version: number; }; }; function collectText(node: unknown): string { if (typeof node !== "object" || node === null) return ""; const n = node as LexicalTextNode; if (n.type === "linebreak") return "\n"; if (typeof n.text === "string") return n.text; if (!Array.isArray(n.children)) return ""; return n.children.map(collectText).join(""); } function collectBlockText(node: unknown): string { if (typeof node !== "object" || node === null) return ""; const n = node as LexicalBlock; if (!Array.isArray(n.children)) return ""; return n.children.map(collectText).join(""); } export function lexicalToText(details: unknown): string { if (typeof details !== "object" || details === null) return ""; const root = (details as SerializedLexicalState).root; if (!root || !Array.isArray(root.children)) return ""; return root.children .map(collectBlockText) .filter((line, i, all) => line.trim() !== "" || (i > 0 && i < all.length - 1)) .join("\n"); } export function textToLexical(text: string): SerializedLexicalState { const lines = text.split("\n"); return { root: { type: "root", children: (lines.length > 0 ? lines : [""]).map((line) => ({ type: "paragraph", children: line === "" ? [] : [ { type: "text", text: line, version: 1, }, ], direction: null, format: "", indent: 0, version: 1, })), direction: "ltr", format: "", indent: 0, version: 1, }, }; }