@abraca/convert 2.23.0 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"abracadabra-convert.cjs","names":["Y","Y","Y","Y"],"sources":["../src/markdown-to-yjs.ts","../src/yjs-to-markdown.ts","../src/html-to-yjs.ts","../src/code.ts","../src/diff.ts","../src/spec/nodes.ts","../src/spec/marks.ts","../src/spec/universal-meta.ts","../src/file-blocks/manifest.ts","../src/file-blocks/paths.ts"],"sourcesContent":["import * as Y from 'yjs'\nimport type { DocPageMeta } from './types.ts'\n\n// ── Filename → readable label ────────────────────────────────────────────────\n\n/**\n * Converts a filename (without extension) to a human-readable label.\n *\n * - `this-is-a-doc` → `\"This is a doc\"` (kebab/snake: sentence case)\n * - `ThisIsADoc` → `\"This Is A Doc\"` (PascalCase: preserves word caps)\n * - `thisIsADoc` → `\"This Is A Doc\"` (camelCase: preserves word caps)\n */\nexport function filenameToLabel(raw: string): string {\n const base = raw.replace(/\\.[^.]+$/, '') // strip extension if present\n const spaced = base.replace(/([a-z])([A-Z])/g, '$1 $2')\n const clean = spaced.replace(/[-_.]+/g, ' ').replace(/\\s+/g, ' ').trim()\n return clean.charAt(0).toUpperCase() + clean.slice(1)\n}\n\n// ── YAML frontmatter parser ──────────────────────────────────────────────────\n\nexport interface FrontmatterResult {\n title?: string\n type?: string\n meta: Partial<DocPageMeta>\n body: string\n}\n\nfunction coerceScalar(raw: string): string | number | boolean {\n const trimmed = raw.trim()\n if (trimmed === 'true') return true\n if (trimmed === 'false') return false\n const num = Number(trimmed)\n if (!Number.isNaN(num) && trimmed !== '') return num\n // Strip surrounding quotes\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n || (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\nfunction parseInlineArray(raw: string): string[] {\n // e.g. \"[a, b, c]\"\n return raw.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean)\n}\n\nfunction stripQuotes(s: string): string {\n if (s.length >= 2\n && ((s.startsWith('\"') && s.endsWith('\"'))\n || (s.startsWith('\\'') && s.endsWith('\\'')))) {\n return s.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\')\n }\n return s\n}\n\nexport function parseFrontmatter(markdown: string): FrontmatterResult {\n const noResult: FrontmatterResult = { meta: {}, body: markdown }\n\n const match = markdown.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/)\n if (!match) return noResult\n\n const yamlBlock = match[1]!\n const body = markdown.slice(match[0].length)\n\n // Parse YAML into a raw map\n const raw: Record<string, string | string[]> = {}\n const lines = yamlBlock.split('\\n')\n let i = 0\n while (i < lines.length) {\n const line = lines[i]!\n // Block sequence: \"key:\\n - a\\n - b\"\n const blockSeqKey = line.match(/^(\\w[\\w-]*):\\s*$/)\n if (blockSeqKey && i + 1 < lines.length && /^\\s+-\\s/.test(lines[i + 1]!)) {\n const key = blockSeqKey[1]!\n const items: string[] = []\n i++\n while (i < lines.length && /^\\s+-\\s/.test(lines[i]!)) {\n items.push(lines[i]!.replace(/^\\s+-\\s/, '').trim())\n i++\n }\n raw[key] = items\n continue\n }\n // Scalar or inline array\n const kvMatch = line.match(/^(\\w[\\w-]*):\\s*(.*)$/)\n if (kvMatch) {\n const key = kvMatch[1]!\n const val = kvMatch[2]!.trim()\n if (val.startsWith('[') && val.endsWith(']')) {\n raw[key] = parseInlineArray(val).map(stripQuotes)\n } else {\n // Strip surrounding quotes up-front so downstream readers\n // don't have to. The original quote state is irrelevant — we\n // re-emit with our canonical quoting rules.\n raw[key] = stripQuotes(val)\n }\n }\n i++\n }\n\n // Map raw YAML keys → PageMeta\n const meta: Partial<DocPageMeta> = {}\n\n const getStr = (keys: string[]): string | undefined => {\n for (const k of keys) {\n const v = raw[k]\n if (typeof v === 'string' && v) return v\n }\n }\n const getArr = (keys: string[]): string[] | undefined => {\n for (const k of keys) {\n const v = raw[k]\n if (Array.isArray(v)) return v\n if (typeof v === 'string' && v) return [v]\n }\n }\n\n if (raw['tags']) meta.tags = Array.isArray(raw['tags']) ? raw['tags'] : [raw['tags'] as string]\n const color = getStr(['color'])\n if (color) meta.color = color\n const icon = getStr(['icon'])\n if (icon) meta.icon = icon\n const status = getStr(['status'])\n if (status) meta.status = status\n\n const priorityRaw = getStr(['priority'])\n if (priorityRaw !== undefined) {\n const map: Record<string, number> = { low: 1, medium: 2, high: 3, urgent: 4 }\n meta.priority = map[priorityRaw.toLowerCase()] ?? (Number(priorityRaw) || 0)\n }\n\n const checkedRaw: unknown = raw['checked'] ?? raw['done']\n if (checkedRaw !== undefined) meta.checked = checkedRaw === 'true' || checkedRaw === true\n\n // Canonical keys are checked first, aliases follow — so files that\n // already use the canonical name (dateStart, dateEnd, subtitle) keep\n // round-tripping byte-stably while legacy aliases still parse.\n const dateStart = getStr(['dateStart', 'date', 'created'])\n if (dateStart) meta.dateStart = dateStart\n const dateEnd = getStr(['dateEnd', 'due'])\n if (dateEnd) meta.dateEnd = dateEnd\n\n const subtitle = getStr(['subtitle', 'description'])\n if (subtitle) meta.subtitle = subtitle\n const url = getStr(['url'])\n if (url) meta.url = url\n\n // Code page type meta.\n const language = getStr(['language'])\n if (language) meta.language = language\n const fileExtension = getStr(['fileExtension'])\n if (fileExtension) meta.fileExtension = fileExtension\n const codeTheme = getStr(['codeTheme'])\n if (codeTheme) meta.codeTheme = codeTheme\n\n const ratingRaw = getStr(['rating'])\n if (ratingRaw !== undefined) {\n const n = Number(ratingRaw)\n if (!Number.isNaN(n)) meta.rating = Math.min(5, Math.max(0, n))\n }\n\n const rawTitle = typeof raw['title'] === 'string' ? raw['title'] : undefined\n const title = rawTitle !== undefined ? stripQuotes(rawTitle) : undefined\n const type = getStr(['type'])\n\n return { title, type, meta, body }\n}\n\n// ── Inline token parsing ─────────────────────────────────────────────────────\n\ninterface InlineToken {\n text: string\n attrs?: Record<string, unknown>\n}\n\n// Re-tokenize the inner text of a wrapping mark (bold/italic/strike) so nested\n// atoms (wikilinks, mentions, code, math) and nested marks survive instead of\n// being captured as a single literal leaf. The wrapping mark's attrs are merged\n// onto every produced child token; object-valued attrs (docLink/mention/badge)\n// are preserved alongside the boolean mark. Terminates because `inner` is\n// strictly shorter than the matched delimiter run.\nfunction pushNested(\n out: InlineToken[],\n inner: string,\n wrap: Record<string, unknown>,\n): void {\n const children = parseInline(inner)\n if (children.length === 0) {\n out.push({ text: inner, attrs: { ...wrap } })\n return\n }\n for (const child of children) {\n out.push({ text: child.text, attrs: { ...(child.attrs ?? {}), ...wrap } })\n }\n}\n\nfunction parseInline(text: string): InlineToken[] {\n // Strip MDC attribute annotations on inline code: `string`{lang=\"ts-type\"}\n const stripped = text.replace(/\\{lang=\"[^\"]*\"\\}/g, '')\n // Strip remaining unknown inline MDC components (but NOT badge/icon/kbd — handled below)\n .replace(/:(?!badge|icon|kbd)(\\w[\\w-]*)\\[([^\\]]*)\\](\\{[^}]*\\})?/g, '$2')\n .replace(/:(?!badge|icon|kbd)(\\w[\\w-]*)(\\{[^}]*\\})/g, '')\n\n const tokens: InlineToken[] = []\n // Order matters: math (`$\\u2026$`) before italic (so `$x$` doesn't match\n // `$ \\u2026 $` as italic-with-dollars); inline MDC first; mentions before\n // plain `[\\u2026]` links; wikilinks before plain brackets; strikethrough;\n // bold before italic.\n const re = /\\$([^$\\n]+?)\\$|@\\[([^\\]]+?)\\]\\(user:([^)]+?)\\)|:badge\\[([^\\]]*)\\](\\{[^}]*\\})?|:icon\\{([^}]*)\\}|:kbd\\{([^}]*)\\}|\\[\\[([0-9a-fA-F-]{36})(?:\\|([^\\]]+?))?\\]\\]|~~(.+?)~~|\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|_(.+?)_|`(.+?)`|\\[(.+?)\\]\\((.+?)\\)/g\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n while ((match = re.exec(stripped)) !== null) {\n if (match.index > lastIndex) {\n tokens.push({ text: stripped.slice(lastIndex, match.index) })\n }\n if (match[1] !== undefined) {\n // $expression$ \\u2014 inline math atom\n tokens.push({ text: match[1], attrs: { mathInline: { expression: match[1] } } })\n } else if (match[2] !== undefined && match[3] !== undefined) {\n // @[label](user:uuid) \\u2014 mention atom\n tokens.push({ text: match[2], attrs: { mention: { userId: match[3], label: match[2] } } })\n } else if (match[4] !== undefined) {\n // :badge[text]{props}\n const badgeProps = parseMdcProps(match[5])\n tokens.push({ text: match[4] || 'Badge', attrs: { badge: { label: match[4] || 'Badge', color: badgeProps['color'] || 'neutral', variant: badgeProps['variant'] || 'subtle' } } })\n } else if (match[6] !== undefined) {\n // :icon{name=\"...\"}\n const iconProps = parseMdcProps(`{${match[6]}}`)\n tokens.push({ text: '\\u200B', attrs: { proseIcon: { name: iconProps['name'] || 'i-lucide-star' } } })\n } else if (match[7] !== undefined) {\n // :kbd{value=\"...\"}\n const kbdProps = parseMdcProps(`{${match[7]}}`)\n tokens.push({ text: kbdProps['value'] || '', attrs: { kbd: { value: kbdProps['value'] || '' } } })\n } else if (match[8] !== undefined) {\n // [[uuid]] or [[uuid|label]] \\u2014 inline doc link atom. The docId\n // is the canonical anchor; the label is display-only. The\n // serialiser may regenerate the label from a live doc registry\n // (see SPEC.md \\u00A76); when no resolver is supplied, the parser's\n // stored display text is reused on emit.\n const docId = match[8]\n const label = match[9] ?? docId\n tokens.push({ text: label, attrs: { docLink: { docId } } })\n } else if (match[10] !== undefined) {\n pushNested(tokens, match[10], { strike: true })\n } else if (match[11] !== undefined) {\n pushNested(tokens, match[11], { bold: true })\n } else if (match[12] !== undefined) {\n pushNested(tokens, match[12], { italic: true })\n } else if (match[13] !== undefined) {\n pushNested(tokens, match[13], { italic: true })\n } else if (match[14] !== undefined) {\n tokens.push({ text: match[14], attrs: { code: true } })\n } else if (match[15] !== undefined && match[16] !== undefined) {\n tokens.push({ text: match[15], attrs: { link: { href: match[16] } } })\n }\n lastIndex = match.index + match[0].length\n }\n\n if (lastIndex < stripped.length) {\n tokens.push({ text: stripped.slice(lastIndex) })\n }\n return tokens.filter(t => t.text.length > 0)\n}\n\n// ── Block-level parser ───────────────────────────────────────────────────────\n\ninterface TaskItem {\n text: string\n checked: boolean\n}\n\ninterface ListItemBlock {\n text: string\n innerBlocks?: Block[]\n checked?: boolean\n}\n\ntype Block\n = | { type: 'heading', level: number, text: string }\n | { type: 'paragraph', text: string }\n | { type: 'bulletList', items: ListItemBlock[] }\n | { type: 'orderedList', items: ListItemBlock[] }\n | { type: 'taskList', items: ListItemBlock[] }\n | { type: 'codeBlock', lang: string, code: string }\n | { type: 'blockquote', lines: string[] }\n | { type: 'table', headerRow: string[], dataRows: string[][] }\n | { type: 'hr' }\n | { type: 'callout', calloutType: string, innerBlocks: Block[] }\n | { type: 'collapsible', label: string, open: boolean, innerBlocks: Block[] }\n | { type: 'steps', innerBlocks: Block[] }\n | { type: 'card', title: string, icon: string, to: string, innerBlocks: Block[] }\n | { type: 'cardGroup', cards: Block[] }\n | { type: 'codeCollapse', codeBlocks: Block[] }\n | { type: 'codeGroup', codeBlocks: Block[] }\n | { type: 'codePreview', innerBlocks: Block[], codeBlocks: Block[] }\n | { type: 'codeTree', files: string }\n | { type: 'accordion', items: { label: string, icon: string, innerBlocks: Block[] }[] }\n | { type: 'tabs', items: { label: string, icon: string, innerBlocks: Block[] }[] }\n | { type: 'field', name: string, fieldType: string, required: boolean, innerBlocks: Block[] }\n | { type: 'fieldGroup', fields: Block[] }\n | { type: 'image', src: string, alt: string, width?: string, height?: string }\n | { type: 'docEmbed', docId: string, label: string, props: Record<string, string> }\n | { type: 'mathBlock', expression: string }\n | { type: 'fileBlock', src: string, mime: string, uploadId: string, filename: string }\n\nfunction parseTableRow(line: string): string[] {\n const parts = line.split('|')\n // Remove the first and last (empty from leading/trailing |) and trim each\n return parts.slice(1, parts.length - 1).map(c => c.trim())\n}\n\nfunction isTableSeparator(line: string): boolean {\n return /^\\|[\\s|:-]+\\|$/.test(line.trim())\n}\n\n/** Extract fenced code blocks from MDC #code slot lines. */\nfunction extractFencedCode(lines: string[]): Block[] {\n const result: Block[] = []\n let i = 0\n while (i < lines.length) {\n const line = lines[i]!\n // Match opening fence (```, ````, etc.)\n const fenceMatch = line.match(/^(`{3,})(\\w*)/)\n if (fenceMatch) {\n const fence = fenceMatch[1]!\n const lang = fenceMatch[2] ?? ''\n const codeLines: string[] = []\n i++\n while (i < lines.length && !lines[i]!.startsWith(fence)) {\n codeLines.push(lines[i]!)\n i++\n }\n i++ // skip closing fence\n result.push({ type: 'codeBlock', lang, code: codeLines.join('\\n') })\n continue\n }\n i++\n }\n return result\n}\n\n/** Extract key=\"value\" pairs from MDC prop syntax `{key=\"value\" other=\"x\"}` */\nfunction parseMdcProps(propsStr: string | undefined): Record<string, string> {\n if (!propsStr) return {}\n const result: Record<string, string> = {}\n // Drop the wrapping `{ … }` if present.\n let s = propsStr.trim()\n if (s.startsWith('{') && s.endsWith('}')) s = s.slice(1, -1)\n\n // Three accepted shapes per SPEC.md §5:\n // key=\"value\" (quoted)\n // key=value (bare, no whitespace)\n // key (boolean shorthand → \"true\")\n const re = /(\\w[\\w-]*)(?:=(?:\"([^\"]*)\"|([^\\s\"}]+)))?/g\n let m: RegExpExecArray | null\n while ((m = re.exec(s)) !== null) {\n const key = m[1]!\n if (m[2] !== undefined) result[key] = m[2]\n else if (m[3] !== undefined) result[key] = m[3]\n else result[key] = 'true'\n }\n return result\n}\n\n/** Parse named child MDC blocks from inner lines (e.g. #item for accordion, #tab for tabs) */\nfunction parseMdcChildren(innerLines: string[], slotPrefix: string): { label: string, icon: string, innerBlocks: Block[] }[] {\n const items: { label: string, icon: string, lines: string[] }[] = []\n let current: { label: string, icon: string, lines: string[] } | null = null\n const slotRe = new RegExp(`^#${slotPrefix}(\\\\{[^}]*\\\\})?\\\\s*$`)\n\n for (const line of innerLines) {\n const slotMatch = line.match(slotRe)\n if (slotMatch) {\n if (current) items.push(current)\n const props = parseMdcProps(slotMatch[1])\n current = { label: props['label'] || props['title'] || `Item ${items.length + 1}`, icon: props['icon'] || '', lines: [] }\n continue\n }\n if (current) {\n current.lines.push(line)\n } else {\n // Content before first slot — treat as first unnamed item\n if (!items.length && !current) {\n current = { label: `Item 1`, icon: '', lines: [line] }\n }\n }\n }\n if (current) items.push(current)\n\n return items.map(item => ({\n label: item.label,\n icon: item.icon,\n innerBlocks: parseBlocks(item.lines.join('\\n'))\n }))\n}\n\nconst TASK_RE = /^[-*+]\\s+\\[([ xX])\\]\\s+(.*)/\n\n/**\n * Consume a list (bullet / ordered / task) starting at `start`. Indented\n * continuation lines and nested lists are captured into each item's\n * `innerBlocks` so the parse → serialise → parse cycle preserves tree\n * structure instead of flattening nested lists onto a single line.\n *\n * `indent` is the column of the item marker for the current list. A\n * nested list starts ≥2 columns deeper. Lines with less indent than\n * `indent` belong to the outer block and stop consumption.\n */\nfunction consumeList(\n lines: string[],\n start: number,\n indent: number,\n kind: 'bullet' | 'ordered' | 'task',\n): { items: ListItemBlock[], next: number } {\n const items: ListItemBlock[] = []\n let i = start\n while (i < lines.length) {\n const line = lines[i]!\n if (line.trim() === '') {\n // Blank line — peek ahead: if the next non-blank line still\n // belongs to this list, treat the blank as an inter-item\n // separator. Otherwise terminate.\n let j = i + 1\n while (j < lines.length && lines[j]!.trim() === '') j++\n if (j >= lines.length) break\n const lookahead = lines[j]!\n if (leadingSpaces(lookahead) < indent) break\n if (!matchMarker(lookahead.slice(indent), kind)) break\n i = j\n continue\n }\n const leading = leadingSpaces(line)\n if (leading < indent) break\n if (leading > indent) break // belongs to a nested list opened by the previous item\n const deindented = line.slice(indent)\n const m = matchMarker(deindented, kind)\n if (!m) break\n\n const item: ListItemBlock = { text: m.text }\n if (kind === 'task') item.checked = m.checked\n i++\n\n // Consume continuation: lines indented deeper than `indent`.\n const contLines: string[] = []\n while (i < lines.length) {\n const next = lines[i]!\n if (next.trim() === '') {\n // Blank inside a continuation block — could be part of the\n // continuation if the next non-blank is still indented. Peek.\n let k = i + 1\n while (k < lines.length && lines[k]!.trim() === '') k++\n if (k >= lines.length) break\n const peekIndent = leadingSpaces(lines[k]!)\n if (peekIndent <= indent) break\n // Carry forward the blank line as a paragraph separator.\n contLines.push('')\n i++\n continue\n }\n const nextIndent = leadingSpaces(next)\n if (nextIndent <= indent) break\n // De-indent by exactly 2 to match the canonical wire form.\n const deindentBy = Math.min(nextIndent, indent + 2)\n contLines.push(next.slice(deindentBy))\n i++\n }\n if (contLines.length > 0) {\n item.innerBlocks = parseBlocks(contLines.join('\\n'))\n }\n items.push(item)\n }\n return { items, next: i }\n}\n\nfunction leadingSpaces(s: string): number {\n let n = 0\n while (n < s.length && s[n] === ' ') n++\n return n\n}\n\nfunction matchMarker(\n s: string,\n kind: 'bullet' | 'ordered' | 'task',\n): { text: string, checked: boolean } | null {\n if (kind === 'task') {\n const m = s.match(TASK_RE)\n if (!m) return null\n return { text: m[2]!, checked: m[1]!.toLowerCase() === 'x' }\n }\n if (kind === 'bullet') {\n if (TASK_RE.test(s)) return null\n const m = s.match(/^[-*+]\\s+(.*)$/)\n if (!m) return null\n return { text: m[1]!, checked: false }\n }\n // ordered\n const m = s.match(/^\\d+\\.\\s+(.*)$/)\n if (!m) return null\n return { text: m[1]!, checked: false }\n}\n\nfunction parseBlocks(markdown: string): Block[] {\n // Strip top-level MDX import/export lines (only before the first content block).\n // We must NOT strip `export default ...` etc. inside fenced code blocks.\n const rawLines = markdown.split('\\n')\n let firstContentLine = 0\n while (firstContentLine < rawLines.length) {\n const l = rawLines[firstContentLine]!\n if (l.trim() === '' || /^import\\s/.test(l) || /^export\\s/.test(l)) {\n firstContentLine++\n } else {\n break\n }\n }\n const stripped = rawLines.slice(firstContentLine).join('\\n')\n\n const blocks: Block[] = []\n const lines = stripped.split('\\n')\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]!\n\n // Fenced code block (supports variable-length fences: ```, ````, etc.)\n const fenceBlockMatch = line.match(/^(`{3,})(.*)$/)\n if (fenceBlockMatch) {\n const fence = fenceBlockMatch[1]!\n const lang = fenceBlockMatch[2]!.trim()\n .replace(/\\{[^}]*\\}$/, '') // strip highlight annotations like {4-5}\n .replace(/\\s*\\[.*\\]$/, '') // strip filename hints like [nuxt.config.ts]\n .trim()\n const codeLines: string[] = []\n i++\n while (i < lines.length && !lines[i]!.startsWith(fence)) {\n codeLines.push(lines[i]!)\n i++\n }\n i++ // skip closing fence\n const code = codeLines.join('\\n')\n if (lang === 'math') {\n // ```math … ``` — block math atom (SPEC.md §6).\n blocks.push({ type: 'mathBlock', expression: code })\n }\n else {\n blocks.push({ type: 'codeBlock', lang, code })\n }\n continue\n }\n\n // Heading\n const headingMatch = line.match(/^(#{1,6})\\s+(.*)/)\n if (headingMatch) {\n blocks.push({ type: 'heading', level: headingMatch[1]!.length, text: headingMatch[2]!.trim() })\n i++\n continue\n }\n\n // Horizontal rule\n if (/^[-*_]{3,}\\s*$/.test(line)) {\n blocks.push({ type: 'hr' })\n i++\n continue\n }\n\n // Doc embed: ![[uuid|label]]{collapsed tall seamless} — block-level,\n // must be on its own line. UUID is required (the bracket syntax\n // without one is reserved for inline doc-link).\n const embedMatch = line.match(/^!\\[\\[([0-9a-fA-F-]{36})(?:\\|([^\\]]+))?\\]\\](\\{[^}]*\\})?\\s*$/)\n if (embedMatch) {\n const docId = embedMatch[1]!\n const label = embedMatch[2] ?? ''\n const props = parseMdcProps(embedMatch[3])\n blocks.push({ type: 'docEmbed', docId, label, props })\n i++\n continue\n }\n\n // Image: ![alt](src){attrs} — must be on its own line\n const imgMatch = line.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)(\\{[^}]*\\})?\\s*$/)\n if (imgMatch) {\n const alt = imgMatch[1] ?? ''\n const src = imgMatch[2] ?? ''\n const attrs = parseMdcProps(imgMatch[3])\n blocks.push({ type: 'image', src, alt, width: attrs['width'], height: attrs['height'] })\n i++\n continue\n }\n\n // Blockquote. Match any line that opens with `>` (CommonMark allows the\n // space after the marker to be omitted, e.g. `>50 comments`). The paragraph\n // collector below treats EVERY `>`-leading line as a block start, so this\n // branch must claim all of them — otherwise a `>x` line matches no branch\n // and the loop spins without advancing `i` (silent infinite hang).\n if (line.startsWith('>')) {\n const bqLines: string[] = []\n while (i < lines.length && lines[i]!.startsWith('>')) {\n bqLines.push(lines[i]!.replace(/^>\\s?/, ''))\n i++\n }\n blocks.push({ type: 'blockquote', lines: bqLines })\n continue\n }\n\n // Table — detect by leading pipe\n if (/^\\s*\\|/.test(line)) {\n const tableLines: string[] = []\n while (i < lines.length && /^\\s*\\|/.test(lines[i]!)) {\n tableLines.push(lines[i]!)\n i++\n }\n // Need at least: header row, separator row\n if (tableLines.length >= 2 && isTableSeparator(tableLines[1]!)) {\n const headerRow = parseTableRow(tableLines[0]!)\n const dataRows = tableLines.slice(2)\n .filter(l => !isTableSeparator(l))\n .map(parseTableRow)\n blocks.push({ type: 'table', headerRow, dataRows })\n } else {\n // Couldn't parse as table — emit as paragraphs\n for (const l of tableLines) blocks.push({ type: 'paragraph', text: l })\n }\n continue\n }\n\n // MDC atom block (single-colon, no body): `:name{props}` on its\n // own line. Currently recognised: `:file{…}` (fileBlock per\n // SPEC.md §7). Other atom blocks (`:video{…}`, `:embed{…}`, etc.)\n // are reserved for later workstreams.\n const atomMatch = line.match(/^:(\\w[\\w-]*)(\\{[^}]*\\})?\\s*$/)\n if (atomMatch && atomMatch[1] === 'file') {\n const props = parseMdcProps(atomMatch[2])\n const uploadId = props['upload-id'] ?? props['uploadId'] ?? ''\n const filename = props['filename'] ?? ''\n const mime = props['mime'] ?? ''\n const src = props['src'] ?? (uploadId && filename\n ? `.abracadabra/files/${uploadId}-${filename}`\n : '')\n blocks.push({ type: 'fileBlock', src, mime, uploadId, filename })\n i++\n continue\n }\n\n // MDC component block (::component-name ... ::)\n // Allow optional leading whitespace so indented nested blocks are recognised\n const MDC_OPEN = /^\\s*(:{2,})(\\w[\\w-]*)(\\{[^}]*\\})?\\s*$/\n if (MDC_OPEN.test(line)) {\n const colons = line.match(/^\\s*(:+)/)?.[1]?.length ?? 2\n const componentName = line.match(/^\\s*:{2,}(\\w[\\w-]*)/)?.[1] ?? ''\n const innerLines: string[] = []\n i++\n // Collect inner lines, but skip over fenced code blocks so that\n // `::` inside ```...``` or ````...```` doesn't close the MDC block\n while (i < lines.length) {\n const l = lines[i]!\n // Closing tag: same colon count, possibly indented\n if (new RegExp(`^\\\\s*:{${colons}}\\\\s*$`).test(l)) { i++; break }\n // If we hit a fenced code block, consume it entirely\n const innerFence = l.match(/^(\\s*`{3,})/)\n if (innerFence) {\n const fenceStr = innerFence[1]!.trimStart()\n innerLines.push(l)\n i++\n while (i < lines.length && !lines[i]!.trimStart().startsWith(fenceStr)) {\n innerLines.push(lines[i]!)\n i++\n }\n if (i < lines.length) { innerLines.push(lines[i]!); i++ } // push closing fence\n continue\n }\n innerLines.push(l)\n i++\n }\n\n // Strip common leading indentation from inner lines\n const nonBlank = innerLines.filter(l => l.trim().length > 0)\n if (nonBlank.length) {\n const minIndent = Math.min(...nonBlank.map(l => l.match(/^(\\s*)/)?.[1]?.length ?? 0))\n if (minIndent > 0) {\n for (let j = 0; j < innerLines.length; j++) {\n innerLines[j] = innerLines[j]!.slice(Math.min(minIndent, innerLines[j]!.length))\n }\n }\n }\n\n // Strip inline frontmatter props (---...---)\n let contentStart = 0\n if (innerLines[0]?.trim() === '---') {\n const fmEnd = innerLines.findIndex((l, idx) => idx > 0 && l.trim() === '---')\n if (fmEnd !== -1) contentStart = fmEnd + 1\n }\n const contentLines = innerLines.slice(contentStart)\n\n // Split into named slots: collect default slot and #code slot separately\n const defaultSlotLines: string[] = []\n const codeSlotLines: string[] = []\n let currentSlot: 'default' | 'code' | 'other' = 'default'\n for (const l of contentLines) {\n if (/^#code\\s*$/.test(l)) { currentSlot = 'code'; continue }\n if (/^#\\w+/.test(l) && !/^#{2,}\\s/.test(l)) { currentSlot = 'other'; continue }\n if (currentSlot === 'default') defaultSlotLines.push(l)\n else if (currentSlot === 'code') codeSlotLines.push(l)\n }\n const innerBlocks = parseBlocks(defaultSlotLines.join('\\n'))\n\n // Extract fenced code from #code slot and add as code blocks\n const codeBlocks = extractFencedCode(codeSlotLines)\n\n const CALLOUT_NAMES = new Set(['tip', 'note', 'info', 'warning', 'caution', 'danger', 'callout', 'alert'])\n if (CALLOUT_NAMES.has(componentName.toLowerCase())) {\n blocks.push({ type: 'callout', calloutType: componentName.toLowerCase(), innerBlocks })\n } else {\n const mdcProps = parseMdcProps(line.match(MDC_OPEN)?.[3])\n const lc = componentName.toLowerCase()\n\n if (lc === 'collapsible') {\n blocks.push({ type: 'collapsible', label: mdcProps['label'] || 'Details', open: mdcProps['open'] === 'true', innerBlocks })\n } else if (lc === 'steps') {\n blocks.push({ type: 'steps', innerBlocks })\n } else if (lc === 'card') {\n blocks.push({ type: 'card', title: mdcProps['title'] || '', icon: mdcProps['icon'] || '', to: mdcProps['to'] || '', innerBlocks })\n } else if (lc === 'card-group') {\n // Each nested ::card inside card-group is already parsed as inner blocks\n const cards = innerBlocks.filter(b => b.type === 'card')\n if (cards.length) {\n blocks.push({ type: 'cardGroup', cards })\n } else {\n blocks.push(...innerBlocks)\n }\n } else if (lc === 'code-collapse') {\n blocks.push({ type: 'codeCollapse', codeBlocks: codeBlocks.length ? codeBlocks : innerBlocks.filter(b => b.type === 'codeBlock') })\n } else if (lc === 'code-group') {\n const allCode = [...innerBlocks.filter(b => b.type === 'codeBlock'), ...codeBlocks]\n blocks.push({ type: 'codeGroup', codeBlocks: allCode })\n } else if (lc === 'code-preview') {\n blocks.push({ type: 'codePreview', innerBlocks, codeBlocks })\n } else if (lc === 'code-tree') {\n blocks.push({ type: 'codeTree', files: mdcProps['files'] || '[]' })\n } else if (lc === 'accordion') {\n const items = parseMdcChildren(contentLines, 'item')\n if (items.length) {\n blocks.push({ type: 'accordion', items })\n } else {\n blocks.push({ type: 'accordion', items: [{ label: 'Item 1', icon: '', innerBlocks }] })\n }\n } else if (lc === 'tabs') {\n const items = parseMdcChildren(contentLines, 'tab')\n if (items.length) {\n blocks.push({ type: 'tabs', items })\n } else {\n blocks.push({ type: 'tabs', items: [{ label: 'Tab 1', icon: '', innerBlocks }] })\n }\n } else if (lc === 'field') {\n blocks.push({ type: 'field', name: mdcProps['name'] || '', fieldType: mdcProps['type'] || 'string', required: mdcProps['required'] === 'true', innerBlocks })\n } else if (lc === 'field-group') {\n const fields = innerBlocks.filter(b => b.type === 'field')\n if (fields.length) {\n blocks.push({ type: 'fieldGroup', fields })\n } else {\n blocks.push(...innerBlocks)\n }\n } else {\n // Unknown component — inline the content\n blocks.push(...innerBlocks)\n blocks.push(...codeBlocks)\n }\n }\n continue\n }\n\n // Task list (must check before bullet list — `- [x]` starts the same way)\n if (TASK_RE.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'task')\n i = next\n blocks.push({ type: 'taskList', items })\n continue\n }\n\n // Bullet list\n if (/^[-*+]\\s+/.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'bullet')\n if (items.length > 0) {\n i = next\n blocks.push({ type: 'bulletList', items })\n continue\n }\n }\n\n // Ordered list\n if (/^\\d+\\.\\s+/.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'ordered')\n if (items.length > 0) {\n i = next\n blocks.push({ type: 'orderedList', items })\n continue\n }\n }\n\n // Blank line\n if (line.trim() === '') {\n i++\n continue\n }\n\n // Paragraph — consecutive non-special lines\n const paraLines: string[] = []\n while (\n i < lines.length\n && lines[i]!.trim() !== ''\n && !/^(#{1,6}\\s|[-*+]\\s|\\d+\\.\\s|>|`{3,}|\\s*\\||[-*_]{3,}\\s*$|\\s*:{2,}\\w)/.test(lines[i]!)\n ) {\n paraLines.push(lines[i]!)\n i++\n }\n if (paraLines.length) {\n blocks.push({ type: 'paragraph', text: paraLines.join(' ') })\n } else {\n // No branch claimed this line and the paragraph collector rejected it too\n // (its guard excludes block-marker leads like `>`). Without forcing\n // progress here `i` never advances and parseBlocks hangs forever. Emit the\n // stray line as a paragraph so it survives the round-trip, and step past it.\n blocks.push({ type: 'paragraph', text: line })\n i++\n }\n }\n\n return blocks\n}\n\n// ── Y.js content population ──────────────────────────────────────────────────\n//\n// IMPORTANT — attach-before-fill ordering:\n//\n// Y.XmlText.insert() is only deterministically ordered when the text node is\n// already attached to a Y.Doc (so it can use the doc's logical clock).\n// Inserting text into a standalone Y.XmlText gives every operation clock-0,\n// which causes the YATA algorithm to produce reversed or scrambled text.\n//\n// Rule: attach container to doc → attach Y.XmlText to container → insert text.\n\n/**\n * Insert formatted inline tokens into an already-attached Y.XmlElement.\n * Creates one Y.XmlText per token (attach first, fill second).\n */\nfunction fillTextInto(el: Y.XmlElement, tokens: InlineToken[]): void {\n const filtered = tokens.filter(t => t.text.length > 0)\n if (!filtered.length) return\n\n // Build the child skeleton. A docLink is an inline ATOM NODE, not a text\n // mark: it must be a Y.XmlElement so the y-prosemirror binding materializes\n // it as a `docLink` node (its label is resolved live from the doc tree by\n // the renderer, never stored). Every other token is a Y.XmlText run.\n // Attach all children in one batch first (attach-before-fill), then fill.\n const children: (Y.XmlText | Y.XmlElement)[] = filtered.map((tok) => {\n const dl = tok.attrs?.docLink as { docId?: string } | undefined\n return dl?.docId ? new Y.XmlElement('docLink') : new Y.XmlText()\n })\n el.insert(0, children)\n\n // Fill only after attachment — el is already attached to the doc.\n filtered.forEach((tok, i) => {\n const node = children[i]!\n if (node instanceof Y.XmlElement) {\n const dl = tok.attrs!.docLink as { docId: string }\n node.setAttribute('docId', dl.docId)\n return\n }\n if (tok.attrs) {\n node.insert(0, tok.text, tok.attrs as Record<string, boolean | object>)\n } else {\n node.insert(0, tok.text)\n }\n })\n}\n\nfunction blockElName(b: Block): string {\n switch (b.type) {\n case 'heading': return 'heading'\n case 'paragraph': return 'paragraph'\n case 'bulletList': return 'bulletList'\n case 'orderedList': return 'orderedList'\n case 'taskList': return 'taskList'\n case 'codeBlock': return 'codeBlock'\n case 'blockquote': return 'blockquote'\n case 'table': return 'table'\n case 'hr': return 'horizontalRule'\n case 'callout': return 'callout'\n case 'collapsible': return 'collapsible'\n case 'steps': return 'steps'\n case 'card': return 'card'\n case 'cardGroup': return 'cardGroup'\n case 'codeCollapse': return 'codeCollapse'\n case 'codeGroup': return 'codeGroup'\n case 'codePreview': return 'codePreview'\n case 'codeTree': return 'codeTree'\n case 'accordion': return 'accordion'\n case 'tabs': return 'tabs'\n case 'field': return 'field'\n case 'fieldGroup': return 'fieldGroup'\n case 'image': return 'image'\n case 'docEmbed': return 'docEmbed'\n case 'mathBlock': return 'mathBlock'\n case 'fileBlock': return 'fileBlock'\n }\n}\n\nfunction populateListItemChildren(\n itemEl: Y.XmlElement,\n item: ListItemBlock,\n _itemKind: 'listItem' | 'taskItem',\n): void {\n // Always start with a paragraph carrying the item's inline text.\n const paraEl = new Y.XmlElement('paragraph')\n itemEl.insert(itemEl.length, [paraEl])\n fillTextInto(paraEl, parseInline(item.text))\n\n // Nested blocks (sub-lists, paragraphs, code, etc.) follow.\n if (!item.innerBlocks?.length) return\n const innerEls = item.innerBlocks.map(b => new Y.XmlElement(blockElName(b)))\n itemEl.insert(itemEl.length, innerEls)\n item.innerBlocks.forEach((b, i) => fillBlock(innerEls[i]!, b))\n}\n\nfunction fillBlock(el: Y.XmlElement, block: Block): void {\n switch (block.type) {\n case 'heading': {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('level', block.level as any)\n fillTextInto(el, parseInline(block.text))\n break\n }\n case 'paragraph': {\n fillTextInto(el, parseInline(block.text))\n break\n }\n case 'bulletList':\n case 'orderedList': {\n const listItemEls = block.items.map(() => new Y.XmlElement('listItem'))\n el.insert(0, listItemEls)\n block.items.forEach((item, i) => {\n populateListItemChildren(listItemEls[i]!, item, 'listItem')\n })\n break\n }\n case 'taskList': {\n const taskItemEls = block.items.map(() => new Y.XmlElement('taskItem'))\n el.insert(0, taskItemEls)\n block.items.forEach((item, i) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n taskItemEls[i]!.setAttribute('checked', !!item.checked as any)\n populateListItemChildren(taskItemEls[i]!, item, 'taskItem')\n })\n break\n }\n case 'codeBlock': {\n if (block.lang) el.setAttribute('language', block.lang)\n const xt = new Y.XmlText()\n el.insert(0, [xt]) // attach xt to el (already attached)\n xt.insert(0, block.code)\n break\n }\n case 'blockquote': {\n const paraEls = block.lines.map(() => new Y.XmlElement('paragraph'))\n el.insert(0, paraEls)\n block.lines.forEach((line, i) => fillTextInto(paraEls[i]!, parseInline(line)))\n break\n }\n case 'table': {\n const headerRowEl = new Y.XmlElement('tableRow')\n const dataRowEls = block.dataRows.map(() => new Y.XmlElement('tableRow'))\n el.insert(0, [headerRowEl, ...dataRowEls])\n\n // Header cells\n const headerCellEls = block.headerRow.map(() => new Y.XmlElement('tableHeader'))\n headerRowEl.insert(0, headerCellEls)\n block.headerRow.forEach((cellText, i) => {\n const paraEl = new Y.XmlElement('paragraph')\n headerCellEls[i]!.insert(0, [paraEl])\n fillTextInto(paraEl, parseInline(cellText))\n })\n\n // Data rows\n block.dataRows.forEach((row, ri) => {\n const cellEls = row.map(() => new Y.XmlElement('tableCell'))\n dataRowEls[ri]!.insert(0, cellEls)\n row.forEach((cellText, ci) => {\n const paraEl = new Y.XmlElement('paragraph')\n cellEls[ci]!.insert(0, [paraEl])\n fillTextInto(paraEl, parseInline(cellText))\n })\n })\n break\n }\n case 'hr': break // horizontalRule has no content\n case 'callout': {\n el.setAttribute('type', block.calloutType)\n if (!block.innerBlocks.length) {\n const paraEl = new Y.XmlElement('paragraph')\n el.insert(0, [paraEl])\n break\n }\n const innerEls = block.innerBlocks.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n block.innerBlocks.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'collapsible': {\n el.setAttribute('label', block.label)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('open', block.open as any)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'steps': {\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'card': {\n if (block.title) el.setAttribute('title', block.title)\n if (block.icon) el.setAttribute('icon', block.icon)\n if (block.to) el.setAttribute('to', block.to)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'cardGroup': {\n const cardEls = block.cards.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, cardEls)\n block.cards.forEach((b, i) => fillBlock(cardEls[i]!, b))\n break\n }\n case 'codeCollapse': {\n const codes = block.codeBlocks.length ? block.codeBlocks : [{ type: 'codeBlock' as const, lang: '', code: '' }]\n // Only insert the first code block (content model is singular codeBlock)\n const codeEl = new Y.XmlElement('codeBlock')\n el.insert(0, [codeEl])\n fillBlock(codeEl, codes[0]!)\n break\n }\n case 'codeGroup': {\n const codes = block.codeBlocks.length ? block.codeBlocks : [{ type: 'codeBlock' as const, lang: '', code: '' }]\n const codeEls = codes.map(() => new Y.XmlElement('codeBlock'))\n el.insert(0, codeEls)\n codes.forEach((b, i) => fillBlock(codeEls[i]!, b))\n break\n }\n case 'codePreview': {\n const all = [...block.innerBlocks, ...block.codeBlocks]\n const inner = all.length ? all : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'codeTree': {\n el.setAttribute('files', block.files)\n break\n }\n case 'accordion': {\n const itemEls = block.items.map(() => new Y.XmlElement('accordionItem'))\n el.insert(0, itemEls)\n block.items.forEach((item, i) => {\n itemEls[i]!.setAttribute('label', item.label)\n if (item.icon) itemEls[i]!.setAttribute('icon', item.icon)\n const inner = item.innerBlocks.length ? item.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const childEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n itemEls[i]!.insert(0, childEls)\n inner.forEach((b, ci) => fillBlock(childEls[ci]!, b))\n })\n break\n }\n case 'tabs': {\n const itemEls = block.items.map(() => new Y.XmlElement('tabsItem'))\n el.insert(0, itemEls)\n block.items.forEach((item, i) => {\n itemEls[i]!.setAttribute('label', item.label)\n if (item.icon) itemEls[i]!.setAttribute('icon', item.icon)\n const inner = item.innerBlocks.length ? item.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const childEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n itemEls[i]!.insert(0, childEls)\n inner.forEach((b, ci) => fillBlock(childEls[ci]!, b))\n })\n break\n }\n case 'field': {\n if (block.name) el.setAttribute('name', block.name)\n el.setAttribute('type', block.fieldType)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('required', block.required as any)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'fieldGroup': {\n const fieldEls = block.fields.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, fieldEls)\n block.fields.forEach((b, i) => fillBlock(fieldEls[i]!, b))\n break\n }\n case 'image': {\n el.setAttribute('src', block.src)\n if (block.alt) el.setAttribute('alt', block.alt)\n if (block.width) el.setAttribute('width', block.width)\n if (block.height) el.setAttribute('height', block.height)\n break\n }\n case 'docEmbed': {\n el.setAttribute('docId', block.docId)\n for (const flag of ['collapsed', 'tall', 'seamless']) {\n if (block.props[flag] === 'true' || block.props[flag] === '1') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute(flag, true as any)\n }\n }\n break\n }\n case 'mathBlock': {\n el.setAttribute('expression', block.expression)\n break\n }\n case 'fileBlock': {\n if (block.src) el.setAttribute('src', block.src)\n if (block.mime) el.setAttribute('mime', block.mime)\n if (block.uploadId) el.setAttribute('uploadId', block.uploadId)\n if (block.filename) el.setAttribute('filename', block.filename)\n break\n }\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Parses markdown text and writes the result into a Y.XmlFragment that\n * TipTap's Collaboration extension can read.\n *\n * Requires `fragment.doc` to be set (i.e. the fragment must already be\n * obtained from a live Y.Doc via `ydoc.getXmlFragment('default')`).\n *\n * @param fragment The target `Y.Doc.getXmlFragment('default')`\n * @param markdown Raw markdown string\n * @param fallbackTitle Used as the title when the markdown has no H1\n */\nexport function populateYDocFromMarkdown(\n fragment: Y.XmlFragment,\n markdown: string,\n fallbackTitle = 'Untitled'\n): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[markdownToYjs] fragment has no doc — skipping population')\n return\n }\n\n // Strip YAML frontmatter from the head of the input so its `---`\n // fences don't get reinterpreted as horizontal rules.\n const fm = parseFrontmatter(markdown)\n const blocks = parseBlocks(fm.body)\n\n let title = fallbackTitle\n // The title can live in three places: frontmatter, the first body H1,\n // or a filename-derived fallback. We track which so the serialiser\n // can round-trip into the same form. Body H1 wins over frontmatter\n // when both are present (frontmatter's title is typically a stale\n // copy of the body H1).\n let titleSource: 'h1' | 'frontmatter' | undefined\n if (fm.title !== undefined) {\n title = fm.title\n titleSource = 'frontmatter'\n }\n let contentBlocks = blocks\n const h1 = blocks.findIndex(b => b.type === 'heading' && b.level === 1)\n if (h1 !== -1) {\n title = (blocks[h1] as { type: 'heading', level: number, text: string }).text\n contentBlocks = blocks.filter((_, i) => i !== h1)\n titleSource = 'h1'\n }\n // For empty markdown we used to seed an empty paragraph so the\n // editor had something to focus. That bytes-pads the round-trip\n // back to \"\\n\\n\" — keep contentBlocks empty so the serialiser can\n // emit a clean empty file.\n\n ydoc.transact(() => {\n // ── Step 1: create empty skeleton elements ────────────────────────────\n const headerEl = new Y.XmlElement('documentHeader')\n const metaEl = new Y.XmlElement('documentMeta')\n const bodyEls: Y.XmlElement[] = contentBlocks.map((b) => {\n switch (b.type) {\n case 'heading': return new Y.XmlElement('heading')\n case 'paragraph': return new Y.XmlElement('paragraph')\n case 'bulletList': return new Y.XmlElement('bulletList')\n case 'orderedList': return new Y.XmlElement('orderedList')\n case 'taskList': return new Y.XmlElement('taskList')\n case 'codeBlock': return new Y.XmlElement('codeBlock')\n case 'blockquote': return new Y.XmlElement('blockquote')\n case 'table': return new Y.XmlElement('table')\n case 'hr': return new Y.XmlElement('horizontalRule')\n case 'callout': return new Y.XmlElement('callout')\n case 'collapsible': return new Y.XmlElement('collapsible')\n case 'steps': return new Y.XmlElement('steps')\n case 'card': return new Y.XmlElement('card')\n case 'cardGroup': return new Y.XmlElement('cardGroup')\n case 'codeCollapse': return new Y.XmlElement('codeCollapse')\n case 'codeGroup': return new Y.XmlElement('codeGroup')\n case 'codePreview': return new Y.XmlElement('codePreview')\n case 'codeTree': return new Y.XmlElement('codeTree')\n case 'accordion': return new Y.XmlElement('accordion')\n case 'tabs': return new Y.XmlElement('tabs')\n case 'field': return new Y.XmlElement('field')\n case 'fieldGroup': return new Y.XmlElement('fieldGroup')\n case 'image': return new Y.XmlElement('image')\n case 'docEmbed': return new Y.XmlElement('docEmbed')\n case 'mathBlock': return new Y.XmlElement('mathBlock')\n case 'fileBlock': return new Y.XmlElement('fileBlock')\n }\n })\n\n // ── Step 2: attach ALL skeleton elements to fragment in one shot ──────\n // After this line everything is connected to ydoc and subsequent ops\n // use the real doc clock — no more clock-0 scrambling.\n fragment.insert(0, [headerEl, metaEl, ...bodyEls])\n\n // ── Step 3: fill header title + record where it came from ─────────────\n if (titleSource) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n headerEl.setAttribute('titleSource', titleSource as any)\n }\n const headerXt = new Y.XmlText()\n headerEl.insert(0, [headerXt])\n headerXt.insert(0, title)\n\n // ── Step 4: stash parsed frontmatter meta on documentMeta ─────────────\n // Each universal-meta key becomes an attribute on documentMeta so\n // the serialiser can faithfully emit it back to frontmatter. Type\n // (page-type) is also stashed here under the well-known \"type\" key.\n for (const k of Object.keys(fm.meta)) {\n const v = (fm.meta as Record<string, unknown>)[k]\n if (v === undefined || v === null) continue\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metaEl.setAttribute(k, v as any)\n }\n if (fm.type) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metaEl.setAttribute('type', fm.type as any)\n }\n\n // ── Step 5: fill body blocks ──────────────────────────────────────────\n contentBlocks.forEach((block, i) => fillBlock(bodyEls[i]!, block))\n })\n}\n","import * as Y from 'yjs'\nimport type { DocPageMeta } from './types.ts'\n\n// ── Cross-yjs-copy node typing ───────────────────────────────────────────────\n//\n// The serializers must decide \"is this a Y.XmlText vs Y.XmlElement\"\n// without `instanceof`. A host that wires @abraca/dabra (file: dep) or\n// bundles us through Vite/esbuild dep-prebundling ends up with a SECOND\n// physical copy of yjs; nodes built by that copy are NOT `instanceof`\n// *our* Y.XmlText/Y.XmlElement, so every check silently fails and text\n// and inline atoms (docLink/mention) serialize to NOTHING. Duck-typed\n// predicates work regardless of which yjs constructed the node — the\n// same lesson as getTreeData's `instanceof Y.Map` fix. (`nodeName` is a\n// plain own-property; `toDelta` only exists on Y.XmlText.)\n// An element is anything carrying a string `nodeName` (paragraph,\n// heading, bulletList, AND inline atoms like docLink/mention — atoms\n// have no children but still have a nodeName). Mirrors the original\n// `instanceof Y.XmlElement` intent with NO extra constraint: requiring\n// `.toArray` wrongly excluded childless atom nodes → docLinks dropped.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction isXElem(n: any): n is Y.XmlElement {\n return !!n && typeof n.nodeName === 'string'\n}\n// Y.XmlText: no nodeName, has toDelta. (Y.XmlFragment has neither →\n// classified as neither, which is correct — it's only ever the root.)\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction isXText(n: any): n is Y.XmlText {\n return !!n && typeof n.nodeName !== 'string' && typeof n.toDelta === 'function'\n}\n\n// No fragment normalization is needed any more — the serializers are\n// duck-typed, so a foreign-yjs fragment serializes directly. Kept as an\n// identity so the public entry points don't need to change.\nfunction localizeFragment(fragment: Y.XmlFragment): Y.XmlFragment {\n return fragment\n}\n\n// ── Inline serialization ────────────────────────────────────────────────────\n\nfunction serializeDelta(delta: any[]): string {\n let result = ''\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n let text = op.insert as string\n const attrs = op.attributes ?? {}\n\n if (attrs.code) {\n result += `\\`${text}\\``\n continue\n }\n\n // Badge mark\n if (attrs.badge) {\n const b = attrs.badge as { label?: string, color?: string, variant?: string }\n const props: string[] = []\n if (b.color && b.color !== 'neutral') props.push(`color=\"${b.color}\"`)\n if (b.variant && b.variant !== 'subtle') props.push(`variant=\"${b.variant}\"`)\n result += `:badge[${b.label || text}]${props.length ? `{${props.join(' ')}}` : ''}`\n continue\n }\n\n // Prose icon mark\n if (attrs.proseIcon) {\n const icon = (attrs.proseIcon as { name?: string }).name || 'i-lucide-star'\n result += `:icon{name=\"${icon}\"}`\n continue\n }\n\n // Kbd mark\n if (attrs.kbd) {\n const value = (attrs.kbd as { value?: string }).value || text\n result += `:kbd{value=\"${value}\"}`\n continue\n }\n\n // docLink — inline doc reference. The label is the displayed text;\n // the docId is the canonical anchor. Per SPEC.md §6 the label may\n // be regenerated from a live registry, but the converter is pure —\n // we use the stored text. Consumers that need fresh labels should\n // rewrite them in the Y tree before serialising.\n if (attrs.docLink) {\n const docId = (attrs.docLink as { docId?: string }).docId\n if (docId) {\n result += text === docId ? `[[${docId}]]` : `[[${docId}|${text}]]`\n continue\n }\n }\n\n // mention — `@[label](user:uuid)`\n if (attrs.mention) {\n const { userId, label } = attrs.mention as { userId?: string, label?: string }\n if (userId) {\n result += `@[${label || text}](user:${userId})`\n continue\n }\n }\n\n // Inline math — `$expression$`\n if (attrs.mathInline) {\n const expr = (attrs.mathInline as { expression?: string }).expression ?? text\n result += `$${expr}$`\n continue\n }\n\n if (attrs.bold) text = `**${text}**`\n if (attrs.italic) text = `*${text}*`\n if (attrs.strike) text = `~~${text}~~`\n if (attrs.link) {\n const href = (attrs.link as { href?: string }).href ?? ''\n text = `[${text}](${href})`\n }\n\n result += text\n }\n return result\n}\n\nfunction serializeInline(el: Y.XmlElement | Y.XmlFragment): string {\n const parts: string[] = []\n for (const child of el.toArray()) {\n if (isXText(child)) {\n parts.push(serializeDelta(child.toDelta()))\n } else if (isXElem(child)) {\n if (child.nodeName === 'docLink') {\n // Inline doc-link atom node — bare wire form; label is tree-derived.\n const docId = child.getAttribute('docId') ?? ''\n parts.push(`[[${docId}]]`)\n } else {\n // Nested inline element — just get text\n parts.push(serializeInline(child))\n }\n }\n }\n return parts.join('')\n}\n\n// ── Block serialization ─────────────────────────────────────────────────────\n\nfunction serializeBlock(el: Y.XmlElement | Y.XmlText, indent = ''): string {\n if (isXText(el)) {\n return serializeDelta(el.toDelta())\n }\n\n const name = el.nodeName\n switch (name) {\n case 'documentHeader':\n case 'documentMeta':\n return '' // handled via frontmatter\n\n case 'heading': {\n const level = Number(el.getAttribute('level') ?? 2)\n const hashes = '#'.repeat(level)\n return `${hashes} ${serializeInline(el)}`\n }\n\n case 'paragraph':\n return serializeInline(el)\n\n case 'bulletList':\n return serializeListItems(el, 'bullet', indent)\n\n case 'orderedList':\n return serializeListItems(el, 'ordered', indent)\n\n case 'taskList':\n return serializeTaskList(el, indent)\n\n case 'codeBlock': {\n const lang = el.getAttribute('language') ?? ''\n const code = getCodeBlockText(el)\n // Empty body — single-newline form preserves the `\\`\\`\\`lang\\n\\`\\`\\``\n // wire form (no padding blank line).\n if (code === '') return `\\`\\`\\`${lang}\\n\\`\\`\\``\n return `\\`\\`\\`${lang}\\n${code}\\n\\`\\`\\``\n }\n\n case 'blockquote': {\n const lines: string[] = []\n for (const child of el.toArray()) {\n if (isXElem(child)) {\n const text = serializeBlock(child)\n for (const line of text.split('\\n')) {\n lines.push(`> ${line}`)\n }\n }\n }\n return lines.join('\\n')\n }\n\n case 'table':\n return serializeTable(el)\n\n case 'horizontalRule':\n return '---'\n\n case 'image': {\n const src = el.getAttribute('src') ?? ''\n const alt = el.getAttribute('alt') ?? ''\n const width = el.getAttribute('width')\n const height = el.getAttribute('height')\n const attrs: string[] = []\n // MDC convention is `{width=400 height=300}` — bare values, no\n // quotes — matching what the parser at the time accepts.\n if (width) attrs.push(`width=${width}`)\n if (height) attrs.push(`height=${height}`)\n return `![${alt}](${src})${attrs.length ? `{${attrs.join(' ')}}` : ''}`\n }\n\n case 'docEmbed': {\n const docId = el.getAttribute('docId') ?? ''\n const collapsed: unknown = el.getAttribute('collapsed')\n const tall: unknown = el.getAttribute('tall')\n const seamless: unknown = el.getAttribute('seamless')\n const flags: string[] = []\n if (collapsed === true || collapsed === 'true') flags.push('collapsed')\n if (tall === true || tall === 'true') flags.push('tall')\n if (seamless === true || seamless === 'true') flags.push('seamless')\n return `![[${docId}]]${flags.length ? `{${flags.join(' ')}}` : ''}`\n }\n\n case 'mathBlock': {\n const expr = el.getAttribute('expression') ?? ''\n return `\\`\\`\\`math\\n${expr}\\n\\`\\`\\``\n }\n\n case 'fileBlock': {\n // SPEC.md §7 wire form: `:file{src=… mime=… upload-id=… filename=…}`.\n // The sidecar binary lives under `.abracadabra/files/`; this tag\n // is purely a reference into that store + the manifest.\n const uploadId = el.getAttribute('uploadId') ?? ''\n const filename = el.getAttribute('filename') ?? ''\n const mime = el.getAttribute('mime') ?? ''\n const src = el.getAttribute('src') ?? (uploadId && filename\n ? `.abracadabra/files/${uploadId}-${filename}`\n : '')\n const props: string[] = []\n if (src) props.push(`src=\"${src}\"`)\n if (mime) props.push(`mime=\"${mime}\"`)\n if (uploadId) props.push(`upload-id=\"${uploadId}\"`)\n if (filename) props.push(`filename=\"${filename}\"`)\n return `:file{${props.join(' ')}}`\n }\n\n // MDC components\n case 'callout': {\n const type = el.getAttribute('type') ?? 'note'\n return `::${type}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'collapsible': {\n const label = el.getAttribute('label') ?? 'Details'\n const open: unknown = el.getAttribute('open')\n const props: string[] = [`label=\"${label}\"`]\n if (open === true || open === 'true') props.push('open=\"true\"')\n return `::collapsible{${props.join(' ')}}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'steps':\n return `::steps\\n${serializeChildren(el)}\\n::`\n\n case 'card': {\n const props: string[] = []\n const title = el.getAttribute('title')\n const icon = el.getAttribute('icon')\n const to = el.getAttribute('to')\n if (title) props.push(`title=\"${title}\"`)\n if (icon) props.push(`icon=\"${icon}\"`)\n if (to) props.push(`to=\"${to}\"`)\n return `::card${props.length ? `{${props.join(' ')}}` : ''}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'cardGroup': {\n const cards = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::card-group\\n${cards}\\n::`\n }\n\n case 'codeCollapse': {\n const code = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'codeBlock')\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::code-collapse\\n${code}\\n::`\n }\n\n case 'codeGroup': {\n const code = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'codeBlock')\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::code-group\\n${code}\\n::`\n }\n\n case 'codePreview': {\n const children = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n const nonCode = children.filter(c => c.nodeName !== 'codeBlock').map(c => serializeBlock(c)).join('\\n\\n')\n const code = children.filter(c => c.nodeName === 'codeBlock').map(c => serializeBlock(c)).join('\\n\\n')\n const parts = [nonCode]\n if (code) parts.push(`#code\\n${code}`)\n return `::code-preview\\n${parts.filter(Boolean).join('\\n\\n')}\\n::`\n }\n\n case 'codeTree': {\n const files = el.getAttribute('files') ?? '[]'\n return `::code-tree{files=\"${files}\"}\\n::`\n }\n\n case 'accordion':\n return serializeSlottedContainer(el, 'accordion', 'accordionItem', 'item')\n\n case 'tabs':\n return serializeSlottedContainer(el, 'tabs', 'tabsItem', 'tab')\n\n case 'field': {\n const fieldName = el.getAttribute('name') ?? ''\n const fieldType = el.getAttribute('type') ?? 'string'\n const required: unknown = el.getAttribute('required')\n const props = [`name=\"${fieldName}\"`, `type=\"${fieldType}\"`]\n if (required === true || required === 'true') props.push('required=\"true\"')\n return `::field{${props.join(' ')}}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'fieldGroup': {\n const fields = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::field-group\\n${fields}\\n::`\n }\n\n default:\n // Unknown node type — try to serialize children\n return serializeChildren(el)\n }\n}\n\nfunction serializeChildren(el: Y.XmlElement | Y.XmlFragment): string {\n const blocks: string[] = []\n for (const child of el.toArray()) {\n if (isXElem(child)) {\n const text = serializeBlock(child)\n if (text) blocks.push(text)\n } else if (isXText(child)) {\n const text = serializeDelta(child.toDelta())\n if (text) blocks.push(text)\n }\n }\n return blocks.join('\\n\\n')\n}\n\nfunction serializeListItems(el: Y.XmlElement, type: 'bullet' | 'ordered', indent: string): string {\n const lines: string[] = []\n let counter = 1\n for (const child of el.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'listItem') continue\n const prefix = type === 'bullet' ? '- ' : `${counter++}. `\n // A listItem may contain paragraphs and nested lists\n const subParts: string[] = []\n for (const sub of child.toArray()) {\n if (!(isXElem(sub))) continue\n if (sub.nodeName === 'bulletList') {\n subParts.push(serializeListItems(sub, 'bullet', indent + ' '))\n } else if (sub.nodeName === 'orderedList') {\n subParts.push(serializeListItems(sub, 'ordered', indent + ' '))\n } else {\n subParts.push(serializeInline(sub))\n }\n }\n if (subParts.length <= 1) {\n lines.push(`${indent}${prefix}${subParts[0] ?? ''}`)\n } else {\n lines.push(`${indent}${prefix}${subParts[0] ?? ''}`)\n for (let i = 1; i < subParts.length; i++) {\n // Nested lists are already indented; plain text gets continuation indent\n lines.push(subParts[i]!)\n }\n }\n }\n return lines.join('\\n')\n}\n\nfunction serializeTaskList(el: Y.XmlElement, indent: string): string {\n const lines: string[] = []\n for (const child of el.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'taskItem') continue\n const checked: unknown = child.getAttribute('checked')\n const marker = (checked === true || checked === 'true') ? '[x]' : '[ ]'\n\n let header = ''\n const nestedParts: string[] = []\n for (const sub of child.toArray()) {\n if (!(isXElem(sub))) continue\n if (sub.nodeName === 'paragraph' && header === '') {\n header = serializeInline(sub)\n }\n else if (sub.nodeName === 'bulletList') {\n nestedParts.push(serializeListItems(sub, 'bullet', indent + ' '))\n }\n else if (sub.nodeName === 'orderedList') {\n nestedParts.push(serializeListItems(sub, 'ordered', indent + ' '))\n }\n else if (sub.nodeName === 'taskList') {\n nestedParts.push(serializeTaskList(sub, indent + ' '))\n }\n else {\n // Other block — render under the item with a 2-space hanging indent\n nestedParts.push((indent + ' ') + serializeBlock(sub, indent + ' '))\n }\n }\n lines.push(`${indent}- ${marker} ${header}`)\n for (const part of nestedParts) lines.push(part)\n }\n return lines.join('\\n')\n}\n\nfunction getCodeBlockText(el: Y.XmlElement): string {\n for (const child of el.toArray()) {\n if (isXText(child)) {\n return child.toString()\n }\n }\n return ''\n}\n\nfunction serializeTable(el: Y.XmlElement): string {\n const rows = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n if (!rows.length) return ''\n\n const serializedRows: string[][] = []\n for (const row of rows) {\n const cells = row.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map((cell) => {\n // Cell contains paragraphs — join their text\n return cell.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeInline(c))\n .join(' ')\n })\n serializedRows.push(cells)\n }\n\n if (!serializedRows.length) return ''\n\n const colCount = Math.max(...serializedRows.map(r => r.length))\n const headerRow = serializedRows[0]!\n const separator = Array(colCount).fill('---')\n const dataRows = serializedRows.slice(1)\n\n const formatRow = (cells: string[]) => {\n const padded = Array(colCount).fill('').map((_, i) => cells[i] ?? '')\n return `| ${padded.join(' | ')} |`\n }\n\n const lines = [formatRow(headerRow), formatRow(separator), ...dataRows.map(formatRow)]\n return lines.join('\\n')\n}\n\nfunction serializeSlottedContainer(\n el: Y.XmlElement,\n containerName: string,\n childName: string,\n slotPrefix: string\n): string {\n const items = el.toArray().filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === childName)\n const slots = items.map((item) => {\n const label = item.getAttribute('label') ?? ''\n const icon = item.getAttribute('icon') ?? ''\n const props: string[] = []\n if (label) props.push(`label=\"${label}\"`)\n if (icon) props.push(`icon=\"${icon}\"`)\n const content = serializeChildren(item)\n return `#${slotPrefix}{${props.join(' ')}}\\n${content}`\n })\n return `::${containerName}\\n${slots.join('\\n\\n')}\\n::`\n}\n\n// ── Frontmatter generation ──────────────────────────────────────────────────\n\nfunction generateFrontmatter(label: string | undefined, meta?: DocPageMeta, type?: string): string {\n const lines: string[] = []\n\n if (label !== undefined) lines.push(`title: \"${escapeYaml(label)}\"`)\n\n if (type && type !== 'doc') {\n lines.push(`type: ${type}`)\n }\n\n if (!meta) return `---\\n${lines.join('\\n')}\\n---`\n\n if (meta.tags?.length) {\n lines.push(`tags: [${meta.tags.join(', ')}]`)\n }\n if (meta.color) lines.push(`color: ${yamlScalar(meta.color)}`)\n if (meta.icon) lines.push(`icon: ${yamlScalar(meta.icon)}`)\n if (meta.status) lines.push(`status: ${yamlScalar(meta.status)}`)\n\n if (meta.priority !== undefined && meta.priority !== 0) {\n const map: Record<number, string> = { 1: 'low', 2: 'medium', 3: 'high', 4: 'urgent' }\n lines.push(`priority: ${map[meta.priority] ?? meta.priority}`)\n }\n\n if (meta.checked !== undefined) lines.push(`checked: ${meta.checked}`)\n // Code page type: syntax-highlight language + on-disk extension. These\n // round-trip the `.md` envelope so the companion code file can be re-derived.\n if (meta.language) lines.push(`language: ${yamlScalar(meta.language)}`)\n if (meta.fileExtension) lines.push(`fileExtension: ${yamlScalar(meta.fileExtension)}`)\n if (meta.codeTheme) lines.push(`codeTheme: ${yamlScalar(meta.codeTheme)}`)\n if (meta.dateStart) lines.push(`dateStart: \"${escapeYaml(meta.dateStart)}\"`)\n if (meta.dateEnd) lines.push(`dateEnd: \"${escapeYaml(meta.dateEnd)}\"`)\n if (meta.subtitle) lines.push(`subtitle: \"${escapeYaml(meta.subtitle)}\"`)\n if (meta.url) lines.push(`url: ${meta.url}`)\n if (meta.rating !== undefined && meta.rating !== 0) lines.push(`rating: ${meta.rating}`)\n\n return `---\\n${lines.join('\\n')}\\n---`\n}\n\n/**\n * Render a YAML scalar — bare when safe, double-quoted when the value\n * needs escaping. YAML treats `#`, `:`, leading whitespace, and a few\n * other characters as syntactically significant, so anything starting\n * with one of those gets quoted to stay round-trip safe.\n */\nfunction yamlScalar(s: string): string {\n if (s === '') return '\"\"'\n if (/^[#&*!|>%@`]/.test(s)) return `\"${escapeYaml(s)}\"`\n if (/[:\"]/.test(s)) return `\"${escapeYaml(s)}\"`\n if (/^\\s|\\s$/.test(s)) return `\"${escapeYaml(s)}\"`\n return s\n}\n\nfunction escapeYaml(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n// ── HTML serialization ──────────────────────────────────────────────────────\n\nfunction serializeBlockToHtml(el: Y.XmlElement | Y.XmlText): string {\n if (isXText(el)) {\n return serializeDeltaToHtml(el.toDelta())\n }\n\n const name = el.nodeName\n switch (name) {\n case 'documentHeader':\n case 'documentMeta':\n return ''\n\n case 'heading': {\n const level = Number(el.getAttribute('level') ?? 2)\n return `<h${level}>${serializeInlineHtml(el)}</h${level}>`\n }\n\n case 'paragraph':\n return `<p>${serializeInlineHtml(el)}</p>`\n\n case 'bulletList':\n return `<ul>${serializeListHtml(el)}</ul>`\n\n case 'orderedList':\n return `<ol>${serializeListHtml(el)}</ol>`\n\n case 'taskList':\n return `<ul>${serializeTaskListHtml(el)}</ul>`\n\n case 'codeBlock': {\n // Restrict the language to a safe identifier charset — it is interpolated\n // into a class attribute below; an unsanitised value is a stored-XSS sink.\n const lang = (el.getAttribute('language') ?? '').replace(/[^\\w.-]/g, '')\n const code = escapeHtml(getCodeBlockText(el))\n return lang\n ? `<pre><code class=\"language-${lang}\">${code}</code></pre>`\n : `<pre><code>${code}</code></pre>`\n }\n\n case 'blockquote': {\n const inner = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlockToHtml(c))\n .join('\\n')\n return `<blockquote>\\n${inner}\\n</blockquote>`\n }\n\n case 'table':\n return serializeTableHtml(el)\n\n case 'horizontalRule':\n return '<hr>'\n\n case 'image': {\n const src = el.getAttribute('src') ?? ''\n const alt = el.getAttribute('alt') ?? ''\n return `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(alt)}\">`\n }\n\n case 'fileBlock': {\n const uploadId = el.getAttribute('uploadId') ?? ''\n const filename = el.getAttribute('filename') ?? 'file'\n if (uploadId) return `<!--fileblock:${uploadId}:${filename}-->`\n return `<!-- file: ${filename} -->`\n }\n\n default: {\n // Generic wrapper for MDC blocks etc.\n const inner = el.toArray()\n .filter((c): c is Y.XmlElement | Y.XmlText => isXElem(c) || isXText(c))\n .map(c => isXElem(c) ? serializeBlockToHtml(c) : serializeDeltaToHtml(c.toDelta()))\n .join('\\n')\n return `<div data-type=\"${name}\">\\n${inner}\\n</div>`\n }\n }\n}\n\nfunction serializeInlineHtml(el: Y.XmlElement | Y.XmlFragment): string {\n const parts: string[] = []\n for (const child of el.toArray()) {\n if (isXText(child)) {\n parts.push(serializeDeltaToHtml(child.toDelta()))\n } else if (isXElem(child)) {\n parts.push(serializeInlineHtml(child))\n }\n }\n return parts.join('')\n}\n\nfunction serializeDeltaToHtml(delta: any[]): string {\n let result = ''\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n let text = escapeHtml(op.insert as string)\n const attrs = op.attributes ?? {}\n if (attrs.code) text = `<code>${text}</code>`\n if (attrs.bold) text = `<strong>${text}</strong>`\n if (attrs.italic) text = `<em>${text}</em>`\n if (attrs.strike) text = `<s>${text}</s>`\n if (attrs.link) {\n const href = escapeHtml((attrs.link as { href?: string }).href ?? '')\n text = `<a href=\"${href}\">${text}</a>`\n }\n result += text\n }\n return result\n}\n\nfunction serializeListHtml(el: Y.XmlElement): string {\n return el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'listItem')\n .map(li => `<li>${li.toArray().filter((c): c is Y.XmlElement => isXElem(c)).map(c => serializeBlockToHtml(c)).join('')}</li>`)\n .join('\\n')\n}\n\nfunction serializeTaskListHtml(el: Y.XmlElement): string {\n return el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'taskItem')\n .map((ti) => {\n const rawChecked: unknown = ti.getAttribute('checked')\n const checked = rawChecked === true || rawChecked === 'true'\n const text = ti.toArray().filter((c): c is Y.XmlElement => isXElem(c)).map(c => serializeInlineHtml(c)).join('')\n return `<li><input type=\"checkbox\"${checked ? ' checked' : ''} disabled> ${text}</li>`\n })\n .join('\\n')\n}\n\nfunction serializeTableHtml(el: Y.XmlElement): string {\n const rows = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n if (!rows.length) return ''\n\n const htmlRows = rows.map((row, ri) => {\n const tag = ri === 0 ? 'th' : 'td'\n const cells = row.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map((cell) => {\n const inner = cell.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeInlineHtml(c))\n .join('')\n return `<${tag}>${inner}</${tag}>`\n })\n .join('')\n return `<tr>${cells}</tr>`\n })\n\n return `<table>\\n${htmlRows.join('\\n')}\\n</table>`\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function yjsToMarkdown(\n fragment: Y.XmlFragment,\n label: string,\n meta?: DocPageMeta,\n type?: string\n): string {\n fragment = localizeFragment(fragment)\n // The title can come from three places. We honour where the parser\n // captured it so the wire form round-trips byte-stably:\n // - 'h1' → emit `# title` as the first body block\n // - 'frontmatter' → emit `title:` in frontmatter\n // - undefined → no real title; skip the frontmatter block\n // when no other meta is set\n const { text: headerText, source: titleSource } = readDocumentHeader(fragment)\n const effectiveTitle = headerText || label\n\n // If the caller didn't pass meta / type, read them from documentMeta —\n // that's where the parser stashes frontmatter fields so they survive\n // round-trip without needing to be piped through the consumer.\n const docMeta = readDocumentMeta(fragment)\n const effectiveMeta = meta ?? docMeta.meta\n const effectiveType = type ?? docMeta.type\n\n const metaIsEmpty = isMetaEmpty(effectiveMeta)\n const typeIsDefault = !effectiveType || effectiveType === 'doc'\n\n const bodyBlocks = collectBodyBlocks(fragment)\n\n // Body assembly — when the parser captured the title from a body H1\n // we restore it at the top of the body before serialising.\n let body: string\n if (titleSource === 'h1' && effectiveTitle) {\n const tail = serializeBlocksClean(bodyBlocks)\n body = tail === '' ? `# ${effectiveTitle}` : `# ${effectiveTitle}\\n\\n${tail}`\n }\n else {\n body = serializeBlocksClean(bodyBlocks)\n }\n\n const wantFrontmatterTitle = titleSource === 'frontmatter'\n const wantFrontmatterMeta = !metaIsEmpty || !typeIsDefault\n if (!wantFrontmatterTitle && !wantFrontmatterMeta) {\n return body === '' ? '' : `${body}\\n`\n }\n const fmTitle = wantFrontmatterTitle ? effectiveTitle : undefined\n const frontmatter = generateFrontmatter(fmTitle, effectiveMeta, effectiveType)\n if (body === '') return `${frontmatter}\\n`\n return `${frontmatter}\\n\\n${body}\\n`\n}\n\nfunction readDocumentMeta(fragment: Y.XmlFragment): { meta: DocPageMeta, type?: string } {\n const meta: DocPageMeta = {}\n let type: string | undefined\n for (const child of fragment.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'documentMeta') continue\n const attrs = child.getAttributes() as Record<string, unknown>\n for (const k of Object.keys(attrs)) {\n const v = attrs[k]\n if (v === undefined || v === null) continue\n if (k === 'type' && typeof v === 'string') {\n type = v\n continue\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (meta as Record<string, unknown>)[k] = v\n }\n break\n }\n return { meta, type }\n}\n\ninterface HeaderInfo { text: string, source?: 'h1' | 'frontmatter' }\n\nfunction readDocumentHeader(fragment: Y.XmlFragment): HeaderInfo {\n for (const child of fragment.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'documentHeader') continue\n const text = child.toArray().find(c => isXText(c)) as Y.XmlText | undefined\n const src: unknown = child.getAttribute('titleSource')\n const source = src === 'h1' || src === 'frontmatter' ? src : undefined\n return { text: text ? text.toString() : '', source }\n }\n return { text: '' }\n}\n\nfunction collectBodyBlocks(fragment: Y.XmlFragment): Y.XmlElement[] {\n const out: Y.XmlElement[] = []\n for (const child of fragment.toArray()) {\n if (!(isXElem(child))) continue\n if (child.nodeName === 'documentHeader' || child.nodeName === 'documentMeta') continue\n out.push(child)\n }\n return out\n}\n\nfunction serializeBlocksClean(blocks: Y.XmlElement[]): string {\n const parts: string[] = []\n for (const block of blocks) {\n // Empty trailing paragraphs are the parser's placeholder for an\n // \"empty doc\"; skip them so empty input round-trips to \"\".\n if (block.nodeName === 'paragraph' && block.length === 0) {\n parts.push('')\n continue\n }\n parts.push(serializeBlock(block))\n }\n while (parts.length && parts[parts.length - 1] === '') parts.pop()\n return parts.join('\\n\\n')\n}\n\nfunction isMetaEmpty(meta: DocPageMeta | undefined): boolean {\n if (!meta) return true\n for (const key of Object.keys(meta)) {\n const v = (meta as Record<string, unknown>)[key]\n if (v === undefined || v === null) continue\n if (typeof v === 'string' && v === '') continue\n if (Array.isArray(v) && v.length === 0) continue\n return false\n }\n return true\n}\n\n/**\n * Walk the Y.XmlFragment and concatenate all text content with no\n * markup or frontmatter. Block boundaries become newlines. Useful for\n * accessibility tooling, search indexing, and snippet previews.\n */\nexport function yjsToPlainText(fragment: Y.XmlFragment): string {\n fragment = localizeFragment(fragment)\n const out: string[] = []\n const visit = (node: Y.XmlElement | Y.XmlText): void => {\n if (isXText(node)) {\n out.push(node.toString())\n return\n }\n if (node.nodeName === 'documentMeta') return\n if (node.nodeName === 'image') {\n const alt = node.getAttribute('alt') ?? ''\n if (alt) out.push(alt)\n return\n }\n for (const child of node.toArray()) {\n if (isXText(child) || isXElem(child)) visit(child)\n }\n // Insert a single newline after block-level elements so paragraphs\n // and headings produce a readable plain-text form.\n if (node.nodeName !== 'paragraph' && node.length === 0) return\n out.push('\\n')\n }\n for (const child of fragment.toArray()) {\n if (isXText(child) || isXElem(child)) visit(child)\n }\n return out.join('').replace(/\\n+$/, '').replace(/\\n{3,}/g, '\\n\\n')\n}\n\nexport function yjsToHtml(\n fragment: Y.XmlFragment,\n label: string\n): string {\n fragment = localizeFragment(fragment)\n const title = escapeHtml(label)\n const bodyParts: string[] = []\n for (const child of fragment.toArray()) {\n if (isXElem(child)) {\n const html = serializeBlockToHtml(child)\n if (html) bodyParts.push(html)\n }\n }\n return `<!DOCTYPE html>\n<html>\n<head><meta charset=\"utf-8\"><title>${title}</title></head>\n<body>\n<h1>${title}</h1>\n${bodyParts.join('\\n')}\n</body>\n</html>\n`\n}\n","import * as Y from 'yjs'\n\n// ── HTML → Y.js converter ───────────────────────────────────────────────────\n//\n// Uses DOMParser (browser builtin) to parse HTML, then walks the DOM tree\n// and writes TipTap-compatible Y.XmlElement nodes into the fragment.\n//\n// Follows the same attach-before-fill pattern as markdownToYjs.ts:\n// always attach nodes to the doc before inserting text into them.\n\ninterface ActiveMarks {\n bold?: true\n italic?: true\n code?: true\n strike?: true\n link?: { href: string }\n}\n\nfunction getTextContent(node: Node): string {\n return node.textContent ?? ''\n}\n\nfunction langFromClass(el: Element): string {\n for (const cls of Array.from(el.classList)) {\n if (cls.startsWith('language-')) return cls.slice(9)\n }\n return ''\n}\n\n/**\n * Collect inline marks from a DOM element's ancestry.\n * Returns merged marks object accumulated from the provided stack.\n */\nfunction mergeMarks(stack: ActiveMarks[]): ActiveMarks {\n const merged: ActiveMarks = {}\n for (const m of stack) {\n if (m.bold) merged.bold = true\n if (m.italic) merged.italic = true\n if (m.code) merged.code = true\n if (m.strike) merged.strike = true\n if (m.link) merged.link = m.link\n }\n return merged\n}\n\ninterface TextRun {\n text: string\n marks: ActiveMarks\n}\n\n/** Walk an inline subtree and collect { text, marks } runs. */\nfunction collectInlineRuns(node: Node, markStack: ActiveMarks[]): TextRun[] {\n const runs: TextRun[] = []\n\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? ''\n if (text) runs.push({ text, marks: mergeMarks(markStack) })\n return runs\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return runs\n\n const el = node as Element\n const tag = el.tagName.toLowerCase()\n\n const newMarks: ActiveMarks = {}\n if (tag === 'strong' || tag === 'b') newMarks.bold = true\n if (tag === 'em' || tag === 'i') newMarks.italic = true\n if (tag === 'code') newMarks.code = true\n if (tag === 's' || tag === 'del' || tag === 'strike') newMarks.strike = true\n if (tag === 'a') {\n const href = el.getAttribute('href')\n if (href) newMarks.link = { href }\n }\n\n const nextStack = Object.keys(newMarks).length ? [...markStack, newMarks] : markStack\n\n for (const child of Array.from(el.childNodes)) {\n runs.push(...collectInlineRuns(child, nextStack))\n }\n return runs\n}\n\n/** Fill an already-attached Y.XmlElement with inline text runs. */\nfunction fillInlineRuns(paraEl: Y.XmlElement, runs: TextRun[]): void {\n if (!runs.length) return\n const xtNodes = runs.map(() => new Y.XmlText())\n paraEl.insert(0, xtNodes)\n runs.forEach((run, i) => {\n const attrs: Record<string, boolean | object> = {}\n if (run.marks.bold) attrs['bold'] = true\n if (run.marks.italic) attrs['italic'] = true\n if (run.marks.code) attrs['code'] = true\n if (run.marks.strike) attrs['strike'] = true\n if (run.marks.link) attrs['link'] = run.marks.link\n if (Object.keys(attrs).length) {\n xtNodes[i]!.insert(0, run.text, attrs)\n } else {\n xtNodes[i]!.insert(0, run.text)\n }\n })\n}\n\n/** Convert a single block-level DOM element to Y.XmlElement(s) and append to `container`. */\nfunction convertBlockElement(el: Element, container: Y.XmlElement | Y.XmlFragment): void {\n const tag = el.tagName.toLowerCase()\n\n // fileBlock: DOMSerializer renders <div data-type=\"file-block\" uploadid=\"...\" ...>\n // HTML lowercases attribute names; read in lowercase, store in camelCase for Y.js\n if (tag === 'div' && el.getAttribute('data-type') === 'file-block') {\n const fileBlockEl = new Y.XmlElement('fileBlock')\n container.insert(container.length, [fileBlockEl])\n const uploadId = el.getAttribute('uploadid') ?? ''\n const docId = el.getAttribute('docid') ?? ''\n const filename = el.getAttribute('filename') ?? ''\n const mimeType = el.getAttribute('mimetype') ?? ''\n if (uploadId) fileBlockEl.setAttribute('uploadId', uploadId)\n if (docId) fileBlockEl.setAttribute('docId', docId)\n if (filename) fileBlockEl.setAttribute('filename', filename)\n if (mimeType) fileBlockEl.setAttribute('mimeType', mimeType)\n return\n }\n\n // Headings\n const headingMatch = tag.match(/^h([1-6])$/)\n if (headingMatch) {\n const level = parseInt(headingMatch[1]!)\n const headingEl = new Y.XmlElement('heading')\n container.insert(container.length, [headingEl])\n headingEl.setAttribute('level', level as unknown as string)\n fillInlineRuns(headingEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'p') {\n const paraEl = new Y.XmlElement('paragraph')\n container.insert(container.length, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'hr') {\n const hrEl = new Y.XmlElement('horizontalRule')\n container.insert(container.length, [hrEl])\n return\n }\n\n if (tag === 'pre') {\n const codeEl = el.querySelector('code')\n const codeBlock = new Y.XmlElement('codeBlock')\n container.insert(container.length, [codeBlock])\n const lang = codeEl ? langFromClass(codeEl) : ''\n if (lang) codeBlock.setAttribute('language', lang)\n const xt = new Y.XmlText()\n codeBlock.insert(0, [xt])\n xt.insert(0, (codeEl ?? el).textContent ?? '')\n return\n }\n\n if (tag === 'blockquote') {\n const bqEl = new Y.XmlElement('blockquote')\n container.insert(container.length, [bqEl])\n // Wrap text in a paragraph\n const paraEl = new Y.XmlElement('paragraph')\n bqEl.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'ul' || tag === 'ol') {\n // Check if any li contains a checkbox → taskList\n const items = Array.from(el.querySelectorAll(':scope > li'))\n const hasCheckbox = items.some(li => li.querySelector('input[type=\"checkbox\"]'))\n\n if (hasCheckbox) {\n const taskListEl = new Y.XmlElement('taskList')\n container.insert(container.length, [taskListEl])\n const taskItemEls = items.map(() => new Y.XmlElement('taskItem'))\n taskListEl.insert(0, taskItemEls)\n items.forEach((li, i) => {\n const checkbox = li.querySelector('input[type=\"checkbox\"]') as HTMLInputElement | null\n const checked = checkbox?.checked ?? false\n taskItemEls[i]!.setAttribute('checked', checked as unknown as string)\n const paraEl = new Y.XmlElement('paragraph')\n taskItemEls[i]!.insert(0, [paraEl])\n // Remove checkbox from text extraction\n const clone = li.cloneNode(true) as Element\n clone.querySelector('input')?.remove()\n fillInlineRuns(paraEl, collectInlineRuns(clone, []))\n })\n } else {\n const listType = tag === 'ul' ? 'bulletList' : 'orderedList'\n const listEl = new Y.XmlElement(listType)\n container.insert(container.length, [listEl])\n const listItemEls = items.map(() => new Y.XmlElement('listItem'))\n listEl.insert(0, listItemEls)\n items.forEach((li, i) => {\n const paraEl = new Y.XmlElement('paragraph')\n listItemEls[i]!.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(li, []))\n })\n }\n return\n }\n\n if (tag === 'table') {\n const tableEl = new Y.XmlElement('table')\n container.insert(container.length, [tableEl])\n\n const rows = Array.from(el.querySelectorAll('tr'))\n const rowEls = rows.map(() => new Y.XmlElement('tableRow'))\n tableEl.insert(0, rowEls)\n\n rows.forEach((row, ri) => {\n const cells = Array.from(row.querySelectorAll('th, td'))\n const isHeader = cells.some(c => c.tagName.toLowerCase() === 'th')\n const cellType = isHeader ? 'tableHeader' : 'tableCell'\n const cellEls = cells.map(() => new Y.XmlElement(cellType))\n rowEls[ri]!.insert(0, cellEls)\n cells.forEach((cell, ci) => {\n const paraEl = new Y.XmlElement('paragraph')\n cellEls[ci]!.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(cell, []))\n })\n })\n return\n }\n\n // Fallback: treat as paragraph (div, section, article, etc.)\n const text = getTextContent(el).trim()\n if (text) {\n const paraEl = new Y.XmlElement('paragraph')\n container.insert(container.length, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Parses an HTML string and writes the result into a Y.XmlFragment that\n * TipTap's Collaboration extension can read.\n *\n * @param fragment The target `Y.Doc.getXmlFragment('default')`\n * @param html Raw HTML string\n * @param fallbackTitle Used when no <title> or <h1> is found\n */\nexport function populateYDocFromHtml(\n fragment: Y.XmlFragment,\n html: string,\n fallbackTitle = 'Untitled'\n): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[htmlToYjs] fragment has no doc — skipping population')\n return\n }\n\n const doc = new DOMParser().parseFromString(html, 'text/html')\n\n // Determine title\n let title = doc.title?.trim() || fallbackTitle\n const firstH1 = doc.body.querySelector('h1')\n if (firstH1) title = firstH1.textContent?.trim() || title\n\n ydoc.transact(() => {\n const headerEl = new Y.XmlElement('documentHeader')\n const metaEl = new Y.XmlElement('documentMeta')\n fragment.insert(0, [headerEl, metaEl])\n\n const headerXt = new Y.XmlText()\n headerEl.insert(0, [headerXt])\n headerXt.insert(0, title)\n\n // Walk body block children\n const blockTags = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'pre', 'blockquote', 'table', 'hr',\n 'div', 'section', 'article', 'header', 'footer', 'main', 'aside'\n ])\n\n let hasContent = false\n for (const child of Array.from(doc.body.children)) {\n const tag = child.tagName.toLowerCase()\n if (!blockTags.has(tag)) continue\n // Skip first h1 (already used as title)\n if (tag === 'h1' && child === firstH1) continue\n convertBlockElement(child, fragment)\n hasContent = true\n }\n\n // Ensure at least one paragraph exists\n if (!hasContent) {\n const paraEl = new Y.XmlElement('paragraph')\n fragment.insert(fragment.length, [paraEl])\n }\n })\n}\n\n/**\n * Appends blocks from an HTML string to an existing Y.XmlFragment.\n * Does NOT insert documentHeader/documentMeta — for appending to an existing doc.\n */\nexport function appendHtmlToFragment(fragment: Y.XmlFragment, html: string): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[htmlToYjs] appendHtmlToFragment: fragment has no doc — skipping')\n return\n }\n const doc = new DOMParser().parseFromString(html, 'text/html')\n const blockTags = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'pre', 'blockquote', 'table', 'hr',\n 'div', 'section', 'article', 'header', 'footer', 'main', 'aside'\n ])\n ydoc.transact(() => {\n for (const child of Array.from(doc.body.children)) {\n if (blockTags.has(child.tagName.toLowerCase()))\n convertBlockElement(child, fragment)\n }\n })\n}\n","// Code page-type helpers for @abraca/convert.\n//\n// A `code` document stores its content in a plain `Y.Text` under the\n// `code` key (edited via CodeMirror + y-codemirror.next), separate from\n// the TipTap prose fragment that carries the `documentHeader`/\n// `documentMeta` envelope. fs-sync writes that text out to a real code\n// file (e.g. `main.rs`) alongside the `.md` envelope.\n//\n// This module owns the single source of truth for:\n// - the `code` Y.Text key name,\n// - reading/replacing that text,\n// - the file-extension ↔ CodeMirror-language mapping used by both\n// fs-sync directions and the renderer.\n//\n// `yjs` stays a type-only peer import — these helpers only call methods\n// on the Y.Doc handed in by the caller, never construct Y types.\n\nimport type * as Y from 'yjs'\n\n/** Y.Text key holding a code document's content. */\nexport const CODE_TEXT_KEY = 'code'\n\n/** Read a code document's raw text. Empty string when absent. */\nexport function readCodeText(doc: Y.Doc): string {\n return doc.getText(CODE_TEXT_KEY).toString()\n}\n\n/**\n * Replace a code document's full text in a single transaction. `origin`\n * is forwarded to `transact` so callers (e.g. fs-sync) can tag the write\n * and skip their own observers.\n */\nexport function writeCodeText(doc: Y.Doc, content: string, origin?: unknown): void {\n const ytext = doc.getText(CODE_TEXT_KEY)\n doc.transact(() => {\n if (ytext.length > 0) ytext.delete(0, ytext.length)\n if (content.length > 0) ytext.insert(0, content)\n }, origin)\n}\n\n// ── Extension ↔ language ─────────────────────────────────────────────────────\n//\n// Keys are lowercase extensions without the leading dot; values are the\n// canonical CodeMirror language id the renderer resolves against\n// `@codemirror/language-data`. The first extension listed for a language\n// in EXT_BY_LANGUAGE is the one fs-sync uses when writing the file.\n\nconst LANGUAGE_BY_EXT: Readonly<Record<string, string>> = {\n // JS/TS family\n js: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n jsx: 'jsx',\n ts: 'typescript',\n mts: 'typescript',\n cts: 'typescript',\n tsx: 'tsx',\n // Web\n html: 'html',\n htm: 'html',\n css: 'css',\n scss: 'scss',\n less: 'less',\n vue: 'vue',\n svelte: 'svelte',\n // Data / config\n json: 'json',\n jsonc: 'json',\n json5: 'json',\n yaml: 'yaml',\n yml: 'yaml',\n toml: 'toml',\n xml: 'xml',\n ini: 'properties',\n env: 'properties',\n // Systems\n rs: 'rust',\n go: 'go',\n c: 'c',\n h: 'c',\n cpp: 'cpp',\n cc: 'cpp',\n cxx: 'cpp',\n hpp: 'cpp',\n cs: 'csharp',\n java: 'java',\n kt: 'kotlin',\n kts: 'kotlin',\n swift: 'swift',\n m: 'objective-c',\n mm: 'objective-c',\n // Scripting\n py: 'python',\n pyi: 'python',\n rb: 'ruby',\n php: 'php',\n pl: 'perl',\n lua: 'lua',\n r: 'r',\n // Shell\n sh: 'shell',\n bash: 'shell',\n zsh: 'shell',\n fish: 'shell',\n // Query / misc\n sql: 'sql',\n graphql: 'graphql',\n gql: 'graphql',\n dockerfile: 'dockerfile',\n // Markup that is genuinely \"code\" in a vault context\n md: 'markdown',\n markdown: 'markdown',\n}\n\n/** Preferred on-disk extension per language (reverse of LANGUAGE_BY_EXT). */\nconst EXT_BY_LANGUAGE: Readonly<Record<string, string>> = {\n javascript: 'js',\n jsx: 'jsx',\n typescript: 'ts',\n tsx: 'tsx',\n html: 'html',\n css: 'css',\n scss: 'scss',\n less: 'less',\n vue: 'vue',\n svelte: 'svelte',\n json: 'json',\n yaml: 'yaml',\n toml: 'toml',\n xml: 'xml',\n properties: 'ini',\n rust: 'rs',\n go: 'go',\n c: 'c',\n cpp: 'cpp',\n csharp: 'cs',\n java: 'java',\n kotlin: 'kt',\n swift: 'swift',\n 'objective-c': 'm',\n python: 'py',\n ruby: 'rb',\n php: 'php',\n perl: 'pl',\n lua: 'lua',\n r: 'r',\n shell: 'sh',\n sql: 'sql',\n graphql: 'graphql',\n dockerfile: 'dockerfile',\n markdown: 'md',\n plain: 'txt',\n}\n\n/** Normalize an extension: strip leading dot(s), lowercase. */\nexport function normalizeExtension(ext: string): string {\n return ext.replace(/^\\.+/, '').toLowerCase()\n}\n\n/**\n * Whether a file extension should import as a `code` page type. Note\n * `md`/`markdown` are intentionally NOT code extensions here — fs-sync\n * treats `.md` as the prose/envelope format, so it's excluded from the\n * code-import gate even though it has a language mapping for in-editor use.\n */\nexport function isCodeExtension(ext: string): boolean {\n const e = normalizeExtension(ext)\n if (e === 'md' || e === 'markdown') return false\n return e in LANGUAGE_BY_EXT\n}\n\n/** CodeMirror language id for an extension, or undefined when unknown. */\nexport function extToLanguage(ext: string): string | undefined {\n return LANGUAGE_BY_EXT[normalizeExtension(ext)]\n}\n\n/** Preferred on-disk extension (no dot) for a language, or undefined. */\nexport function languageToExtension(language: string): string | undefined {\n return EXT_BY_LANGUAGE[language.toLowerCase()]\n}\n\n/**\n * Derive `{ language, fileExtension }` from a filename for code import.\n * Returns undefined when the extension is not a recognized code extension\n * (so callers fall back to the prose/doc path).\n */\nexport function inferCodeMetaFromFilename(\n filename: string,\n): { language: string, fileExtension: string } | undefined {\n const dot = filename.lastIndexOf('.')\n if (dot < 0) return undefined\n const ext = normalizeExtension(filename.slice(dot + 1))\n if (!isCodeExtension(ext)) return undefined\n const language = LANGUAGE_BY_EXT[ext]\n if (!language) return undefined\n return { language, fileExtension: ext }\n}\n\n/**\n * Choose the on-disk extension for a code doc on export. Prefers an\n * explicit `fileExtension`, then the language's primary extension, then\n * `txt`.\n */\nexport function codeFileExtension(meta?: { fileExtension?: string, language?: string }): string {\n if (meta?.fileExtension) return normalizeExtension(meta.fileExtension)\n if (meta?.language) return languageToExtension(meta.language) ?? 'txt'\n return 'txt'\n}\n","// Structural Y.XmlFragment ↔ JSON converter, used by the test harness\n// to make round-trip assertions and to author golden fixtures by hand.\n//\n// The JSON shape is canonical:\n//\n// YjsJsonNode =\n// | { kind: 'element'; tag: string; attrs?: Record<string, JsonAttr>; children: YjsJsonNode[] }\n// | { kind: 'text'; runs: Array<{ insert: string; attributes?: Record<string, JsonAttr> }> }\n//\n// Attributes are stored verbatim — strings, numbers, booleans, null,\n// nested JSON (for things like codeTree's `files`). The format is\n// committed alongside fixtures as `.y.json` so reviews of intent\n// changes are diffable.\n//\n// `yfragmentToJson(frag)` is deterministic: the same Y.XmlFragment\n// always produces byte-identical JSON when stringified with sorted\n// keys.\n\nimport * as Y from 'yjs'\n\nexport type JsonAttr =\n | string\n | number\n | boolean\n | null\n | JsonAttr[]\n | { [key: string]: JsonAttr }\n\nexport interface YjsTextRun {\n insert: string\n attributes?: Record<string, JsonAttr>\n}\n\nexport interface YjsJsonText {\n kind: 'text'\n runs: YjsTextRun[]\n}\n\nexport interface YjsJsonElement {\n kind: 'element'\n tag: string\n attrs?: Record<string, JsonAttr>\n children: YjsJsonNode[]\n}\n\nexport type YjsJsonNode = YjsJsonElement | YjsJsonText\n\n// ── Yjs → JSON ──────────────────────────────────────────────────────────────\n\nfunction attrsToJson(el: Y.XmlElement): Record<string, JsonAttr> | undefined {\n const out: Record<string, JsonAttr> = {}\n let count = 0\n for (const key of Object.keys(el.getAttributes())) {\n const raw: unknown = el.getAttribute(key)\n out[key] = normaliseAttr(raw)\n count++\n }\n if (count === 0) return undefined\n return sortKeys(out)\n}\n\nfunction normaliseAttr(v: unknown): JsonAttr {\n if (v == null) return null\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') return v\n if (Array.isArray(v)) return v.map(normaliseAttr)\n if (typeof v === 'object') {\n const out: Record<string, JsonAttr> = {}\n for (const k of Object.keys(v as object).sort()) {\n out[k] = normaliseAttr((v as Record<string, unknown>)[k])\n }\n return out\n }\n // Functions / symbols / undefined — coerce to null so the JSON\n // remains valid and diffs surface the loss.\n return null\n}\n\nfunction sortKeys(obj: Record<string, JsonAttr>): Record<string, JsonAttr> {\n const out: Record<string, JsonAttr> = {}\n for (const k of Object.keys(obj).sort()) out[k] = obj[k]!\n return out\n}\n\nfunction textToJson(text: Y.XmlText): YjsJsonText {\n const delta = text.toDelta() as Array<{ insert: unknown, attributes?: Record<string, unknown> }>\n const runs: YjsTextRun[] = []\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n const run: YjsTextRun = { insert: op.insert }\n if (op.attributes && Object.keys(op.attributes).length > 0) {\n const normalised: Record<string, JsonAttr> = {}\n for (const k of Object.keys(op.attributes).sort()) {\n normalised[k] = normaliseAttr(op.attributes[k])\n }\n run.attributes = normalised\n }\n runs.push(run)\n }\n return { kind: 'text', runs }\n}\n\nfunction elementToJson(el: Y.XmlElement): YjsJsonElement {\n const attrs = attrsToJson(el)\n const children: YjsJsonNode[] = []\n for (const child of el.toArray()) {\n if (child instanceof Y.XmlElement) children.push(elementToJson(child))\n else if (child instanceof Y.XmlText) children.push(textToJson(child))\n }\n const out: YjsJsonElement = { kind: 'element', tag: el.nodeName, children }\n if (attrs) out.attrs = attrs\n return out\n}\n\nexport function yfragmentToJson(frag: Y.XmlFragment): YjsJsonElement {\n const children: YjsJsonNode[] = []\n for (const child of frag.toArray()) {\n if (child instanceof Y.XmlElement) children.push(elementToJson(child))\n else if (child instanceof Y.XmlText) children.push(textToJson(child))\n }\n return { kind: 'element', tag: '#fragment', children }\n}\n\n// ── JSON → Yjs ──────────────────────────────────────────────────────────────\n\n// Yjs rule: every Y.XmlElement must be attached to its parent BEFORE\n// its attributes are set or its children inserted. Otherwise the runtime\n// logs \"Invalid access: Add Yjs type to a document before reading data.\"\n// and silently no-ops the mutation.\n//\n// So we do this in two passes per node: (1) create empty skeleton +\n// attach to parent; (2) populate attrs + recurse on children, which\n// each follow the same pattern. cou-sh's populateYDocFromMarkdown uses\n// the same pattern.\n\nfunction populateElement(el: Y.XmlElement, node: YjsJsonElement): void {\n if (node.attrs) {\n for (const k of Object.keys(node.attrs)) {\n // Y.XmlElement.setAttribute only types `string`, but accepts\n // arbitrary values in practice (numbers, booleans, JSON objects).\n const v = node.attrs[k]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute(k, v as any)\n }\n }\n for (const child of node.children) {\n if (child.kind === 'element') {\n const sub = new Y.XmlElement(child.tag)\n el.insert(el.length, [sub])\n populateElement(sub, child)\n }\n else {\n const text = new Y.XmlText()\n el.insert(el.length, [text])\n populateText(text, child)\n }\n }\n}\n\nfunction populateText(text: Y.XmlText, node: YjsJsonText): void {\n let offset = 0\n for (const run of node.runs) {\n if (run.attributes) {\n text.insert(offset, run.insert, run.attributes as unknown as object)\n }\n else {\n text.insert(offset, run.insert)\n }\n offset += run.insert.length\n }\n}\n\n/**\n * Build a Y.XmlFragment from a previously captured golden JSON. The\n * returned fragment is bound to a fresh Y.Doc so consumers can hand\n * it to serialisers immediately. All Yjs mutations happen inside a\n * single transaction.\n */\nexport function jsonToYFragment(root: YjsJsonElement, doc?: Y.Doc, key = 'body'): Y.XmlFragment {\n if (root.tag !== '#fragment') {\n throw new Error(`jsonToYFragment expected tag=\"#fragment\", got \"${root.tag}\"`)\n }\n const ydoc = doc ?? new Y.Doc()\n const frag = ydoc.getXmlFragment(key)\n ydoc.transact(() => {\n for (const child of root.children) {\n if (child.kind === 'element') {\n const sub = new Y.XmlElement(child.tag)\n frag.insert(frag.length, [sub])\n populateElement(sub, child)\n }\n else {\n const text = new Y.XmlText()\n frag.insert(frag.length, [text])\n populateText(text, child)\n }\n }\n })\n return frag\n}\n\n// ── Diff (deep equality with a path) ────────────────────────────────────────\n\nexport interface YjsDiff {\n equal: boolean\n /** Dotted path to the first divergence (empty when equal). */\n path: string\n /** Short human-readable explanation. */\n reason: string\n}\n\nexport function diffYjs(a: Y.XmlFragment, b: Y.XmlFragment): YjsDiff {\n return diffNode(yfragmentToJson(a), yfragmentToJson(b), '')\n}\n\nexport function diffJson(a: YjsJsonNode, b: YjsJsonNode): YjsDiff {\n return diffNode(a, b, '')\n}\n\nfunction diffNode(a: YjsJsonNode, b: YjsJsonNode, path: string): YjsDiff {\n if (a.kind !== b.kind) {\n return { equal: false, path, reason: `kind mismatch: ${a.kind} vs ${b.kind}` }\n }\n if (a.kind === 'text' && b.kind === 'text') {\n const ar = a.runs\n const br = b.runs\n if (ar.length !== br.length) {\n return { equal: false, path, reason: `text run count: ${ar.length} vs ${br.length}` }\n }\n for (let i = 0; i < ar.length; i++) {\n const sub = `${path}/runs[${i}]`\n const ai = ar[i]!\n const bi = br[i]!\n if (ai.insert !== bi.insert) {\n return { equal: false, path: sub, reason: `insert: ${JSON.stringify(ai.insert)} vs ${JSON.stringify(bi.insert)}` }\n }\n const attrDiff = diffAttrs(ai.attributes, bi.attributes, sub)\n if (!attrDiff.equal) return attrDiff\n }\n return { equal: true, path: '', reason: '' }\n }\n if (a.kind === 'element' && b.kind === 'element') {\n if (a.tag !== b.tag) return { equal: false, path, reason: `tag: ${a.tag} vs ${b.tag}` }\n const attrDiff = diffAttrs(a.attrs, b.attrs, path)\n if (!attrDiff.equal) return attrDiff\n if (a.children.length !== b.children.length) {\n return { equal: false, path, reason: `child count: ${a.children.length} vs ${b.children.length}` }\n }\n for (let i = 0; i < a.children.length; i++) {\n const sub = path === '' ? `[${i}]` : `${path}[${i}]`\n const childDiff = diffNode(a.children[i]!, b.children[i]!, sub)\n if (!childDiff.equal) return childDiff\n }\n return { equal: true, path: '', reason: '' }\n }\n return { equal: false, path, reason: 'unreachable kind combination' }\n}\n\nfunction diffAttrs(\n a: Record<string, JsonAttr> | undefined,\n b: Record<string, JsonAttr> | undefined,\n path: string,\n): YjsDiff {\n const ak = a ? Object.keys(a).sort() : []\n const bk = b ? Object.keys(b).sort() : []\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) {\n return { equal: false, path: `${path}.attrs`, reason: `attr keys: [${ak.join(',')}] vs [${bk.join(',')}]` }\n }\n for (const k of ak) {\n const av = a![k]\n const bv = b![k]\n if (!attrEqual(av, bv)) {\n return {\n equal: false,\n path: `${path}.attrs.${k}`,\n reason: `attr value: ${JSON.stringify(av)} vs ${JSON.stringify(bv)}`,\n }\n }\n }\n return { equal: true, path: '', reason: '' }\n}\n\nfunction attrEqual(a: JsonAttr, b: JsonAttr): boolean {\n if (a === b) return true\n if (a === null || b === null) return false\n if (typeof a !== typeof b) return false\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n return a.every((v, i) => attrEqual(v, b[i]!))\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a).sort()\n const bk = Object.keys(b).sort()\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) return false\n return ak.every(k => attrEqual((a as Record<string, JsonAttr>)[k]!, (b as Record<string, JsonAttr>)[k]!))\n }\n return false\n}\n\n/** Stringify a YjsJsonNode with sorted keys for byte-stable golden files. */\nexport function stringifyJsonNode(node: YjsJsonNode): string {\n return JSON.stringify(node, null, 2) + '\\n'\n}\n","// NodeSpec registry — every TipTap node supported by the converter,\n// paired with its canonical Markdown / MDC wire form.\n//\n// This is **data**, not behaviour. The parser and serialiser\n// (markdown-to-yjs.ts, yjs-to-markdown.ts) consult this table to\n// decide what to do; when the spec and the runtime disagree the\n// registry wins (per SPEC.md).\n//\n// Wire kinds:\n// - vanilla Standard Markdown (paragraph, heading, list, …).\n// - fence Fenced code block with a language tag.\n// - mdc-container `:name{props}\\n…children…\\n::` block with children.\n// - mdc-slotted `:name\\n :name-item{…}\\n…\\n ::\\n…\\n::` slotted container.\n// - mdc-atom-block `:name{props}` single-line block atom.\n// - mdc-atom-inl `:name[label]{props}` or `:name{props}` inline atom.\n// - special Has bespoke parsing/serialising (doc-link, doc-embed,\n// file-block, image, mention, math).\n\nimport type { DocPageMeta } from '../types.ts'\n\nexport type NodeWireKind =\n | 'vanilla'\n | 'fence'\n | 'mdc-container'\n | 'mdc-slotted'\n | 'mdc-atom-block'\n | 'mdc-atom-inl'\n | 'special'\n\nexport interface NodeAttrSpec {\n /** Attribute name on the Y.XmlElement and on the MDC prop. */\n key: string\n /** Wire type — controls how the attr is parsed/serialised in props. */\n type: 'string' | 'number' | 'integer' | 'boolean' | 'json'\n /** Optional default value omitted from serialised output when equal. */\n default?: unknown\n /** Allowed values for enum-like string attrs. */\n values?: readonly string[]\n /** Whether the attr is allowed to be omitted entirely. */\n optional?: boolean\n}\n\nexport interface NodeSpec {\n /** Y.XmlElement nodeName. */\n name: string\n /** Block vs inline. */\n group: 'block' | 'inline'\n /** Wire form on Markdown. */\n wire: NodeWireKind\n /**\n * For slotted containers: name of the child element used as a slot\n * (e.g. `accordion-item` under `accordion`).\n */\n slotChild?: string\n /** Declared attributes. */\n attrs?: readonly NodeAttrSpec[]\n /**\n * For `mdc-container` and `mdc-slotted`: what MDC tag name to emit.\n * Defaults to `name` (kebab-cased — `accordionItem` → `accordion-item`).\n */\n mdcTag?: string\n /**\n * Whether the node is content-bearing (paragraph, listItem, etc.)\n * or a child wrapper (tableRow, tableHeader).\n */\n contentBearing?: boolean\n doc?: string\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nconst BOOL_FALSE_DEFAULT: NodeAttrSpec = {\n key: '',\n type: 'boolean',\n default: false,\n optional: true,\n}\n\nconst bool = (key: string): NodeAttrSpec => ({ ...BOOL_FALSE_DEFAULT, key })\nconst str = (key: string, def?: string): NodeAttrSpec => ({\n key,\n type: 'string',\n default: def,\n optional: true,\n})\nconst num = (key: string): NodeAttrSpec => ({ key, type: 'number', optional: true })\nconst int = (key: string): NodeAttrSpec => ({ key, type: 'integer', optional: true })\n\n// ── Vanilla block nodes ─────────────────────────────────────────────────────\n\nconst VANILLA_BLOCKS: readonly NodeSpec[] = [\n { name: 'documentHeader', group: 'block', wire: 'special', doc: 'Holds the title; hoisted to frontmatter on serialise.' },\n { name: 'documentMeta', group: 'block', wire: 'special', doc: 'Holds page-level meta; serialised into frontmatter.' },\n { name: 'paragraph', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'heading', group: 'block', wire: 'vanilla', attrs: [int('level')], contentBearing: true },\n { name: 'blockquote', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'codeBlock', group: 'block', wire: 'fence', attrs: [str('language', '')] },\n { name: 'bulletList', group: 'block', wire: 'vanilla' },\n { name: 'orderedList', group: 'block', wire: 'vanilla' },\n { name: 'listItem', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'taskList', group: 'block', wire: 'vanilla' },\n { name: 'taskItem', group: 'block', wire: 'vanilla', attrs: [bool('checked')], contentBearing: true },\n { name: 'table', group: 'block', wire: 'vanilla' },\n { name: 'tableRow', group: 'block', wire: 'vanilla' },\n { name: 'tableHeader', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'tableCell', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'horizontalRule', group: 'block', wire: 'vanilla' },\n {\n name: 'image',\n group: 'block',\n wire: 'special',\n attrs: [str('src'), str('alt', ''), int('width'), int('height')],\n },\n { name: 'hardBreak', group: 'inline', wire: 'vanilla' },\n]\n\n// ── MDC custom containers ───────────────────────────────────────────────────\n\nconst MDC_CONTAINERS: readonly NodeSpec[] = [\n {\n name: 'callout',\n group: 'block',\n wire: 'mdc-container',\n attrs: [\n { key: 'type', type: 'string', default: 'note', optional: true,\n values: ['note', 'tip', 'warning', 'danger', 'info', 'caution', 'alert', 'success', 'error'] },\n str('title'),\n str('icon'),\n ],\n },\n {\n name: 'collapsible',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('label', 'Details'), bool('open')],\n },\n {\n name: 'accordion',\n group: 'block',\n wire: 'mdc-slotted',\n slotChild: 'accordionItem',\n },\n {\n name: 'accordionItem',\n group: 'block',\n wire: 'mdc-container',\n mdcTag: 'accordion-item',\n attrs: [str('label', 'Item'), str('icon')],\n },\n {\n name: 'tabs',\n group: 'block',\n wire: 'mdc-slotted',\n slotChild: 'tabsItem',\n },\n {\n name: 'tabsItem',\n group: 'block',\n wire: 'mdc-container',\n mdcTag: 'tabs-item',\n attrs: [str('label'), str('icon')],\n },\n { name: 'steps', group: 'block', wire: 'mdc-container' },\n {\n name: 'card',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('title'), str('icon'), str('to')],\n },\n {\n name: 'cardGroup',\n group: 'block',\n wire: 'mdc-slotted',\n mdcTag: 'card-group',\n slotChild: 'card',\n },\n {\n name: 'field',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('name'), str('type', 'string'), bool('required')],\n },\n {\n name: 'fieldGroup',\n group: 'block',\n wire: 'mdc-slotted',\n mdcTag: 'field-group',\n slotChild: 'field',\n },\n { name: 'codeGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'code-group', slotChild: 'codeBlock' },\n { name: 'codeCollapse', group: 'block', wire: 'mdc-container', mdcTag: 'code-collapse' },\n { name: 'codePreview', group: 'block', wire: 'mdc-container', mdcTag: 'code-preview' },\n {\n name: 'codeTree',\n group: 'block',\n wire: 'mdc-atom-block',\n mdcTag: 'code-tree',\n attrs: [{ key: 'files', type: 'json' }],\n },\n {\n name: 'figure',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('src'), str('alt', ''), str('caption')],\n },\n {\n name: 'video',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('src'), str('poster'), bool('autoplay'), bool('loop'), bool('controls')],\n },\n {\n name: 'embed',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('src'), str('title')],\n },\n {\n name: 'svgEmbed',\n group: 'block',\n wire: 'fence',\n attrs: [str('title')],\n mdcTag: 'svg',\n doc: 'Serialised as a ```svg fenced block; the SVG markup is the body.',\n },\n {\n name: 'divider',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('label'), str('icon')],\n },\n { name: 'quote', group: 'block', wire: 'mdc-container', attrs: [str('cite')] },\n { name: 'progress', group: 'block', wire: 'mdc-atom-block', attrs: [num('value'), num('max'), str('label')] },\n { name: 'spoiler', group: 'block', wire: 'mdc-container', attrs: [str('label')] },\n { name: 'colorSwatch', group: 'block', wire: 'mdc-atom-block', mdcTag: 'color-swatch', attrs: [str('color'), str('label')] },\n { name: 'stat', group: 'block', wire: 'mdc-container', attrs: [str('label'), str('value'), str('icon')] },\n { name: 'statGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'stat-group', slotChild: 'stat' },\n { name: 'button', group: 'block', wire: 'mdc-atom-block', attrs: [str('label'), str('to'), str('icon'), str('variant')] },\n { name: 'buttonGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'button-group', slotChild: 'button' },\n { name: 'timeline', group: 'block', wire: 'mdc-slotted', slotChild: 'timelineItem' },\n { name: 'timelineItem', group: 'block', wire: 'mdc-container', mdcTag: 'timeline-item', attrs: [str('label'), str('icon'), str('date')] },\n { name: 'diff', group: 'block', wire: 'mdc-atom-block', attrs: [str('language', ''), { key: 'value', type: 'string' }] },\n]\n\n// ── Inline atoms / special nodes ────────────────────────────────────────────\n\nconst INLINE_AND_SPECIAL: readonly NodeSpec[] = [\n {\n name: 'docLink',\n group: 'inline',\n wire: 'special',\n attrs: [str('docId')],\n doc: 'Wire form `[[uuid|label]]`; label regenerated on export.',\n },\n {\n name: 'docEmbed',\n group: 'block',\n wire: 'special',\n attrs: [str('docId'), bool('collapsed'), bool('tall'), bool('seamless')],\n doc: 'Wire form `![[uuid|label]]{collapsed tall seamless}`.',\n },\n {\n name: 'mention',\n group: 'inline',\n wire: 'special',\n attrs: [str('userId')],\n doc: 'Wire form `@[label](user:uuid)`; label regenerated on export.',\n },\n {\n name: 'mathInline',\n group: 'inline',\n wire: 'special',\n attrs: [{ key: 'expression', type: 'string' }],\n doc: 'Wire form `$expression$`.',\n },\n {\n name: 'mathBlock',\n group: 'block',\n wire: 'fence',\n attrs: [{ key: 'expression', type: 'string' }],\n mdcTag: 'math',\n doc: 'Wire form ``` ```math\\\\nexpression\\\\n``` ```.',\n },\n {\n name: 'fileBlock',\n group: 'block',\n wire: 'mdc-atom-block',\n mdcTag: 'file',\n attrs: [str('src'), str('mime'), str('uploadId'), str('filename')],\n doc: 'Wire form `:file{src=… mime=… upload-id=… filename=…}`; binary in sidecar.',\n },\n {\n name: 'badge',\n group: 'inline',\n wire: 'mdc-atom-inl',\n attrs: [str('label'), str('color'), str('variant', 'subtle')],\n doc: 'Wire form `:badge[Label]{color=… variant=…}`.',\n },\n {\n name: 'proseIcon',\n group: 'inline',\n wire: 'mdc-atom-inl',\n mdcTag: 'icon',\n attrs: [str('name')],\n doc: 'Wire form `:icon{name=…}`.',\n },\n {\n name: 'kbd',\n group: 'inline',\n wire: 'mdc-atom-inl',\n attrs: [str('value')],\n doc: 'Wire form `:kbd{value=…}`.',\n },\n]\n\nexport const NODE_SPECS: readonly NodeSpec[] = [\n ...VANILLA_BLOCKS,\n ...MDC_CONTAINERS,\n ...INLINE_AND_SPECIAL,\n]\n\nexport const NODE_SPEC_BY_NAME: ReadonlyMap<string, NodeSpec> = new Map(\n NODE_SPECS.map(spec => [spec.name, spec]),\n)\n\n/** Derive the MDC tag for a node — `mdcTag` override or kebab-case of `name`. */\nexport function mdcTagOf(spec: NodeSpec): string {\n if (spec.mdcTag) return spec.mdcTag\n return spec.name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n}\n\n/** Type-only re-export so consumers can build typed meta without a second import. */\nexport type { DocPageMeta }\n","// MarkSpec registry — every inline mark supported by the converter,\n// paired with its canonical Markdown wire form.\n//\n// Marks are pure inline annotations on text runs; they have no\n// children. The parser sets these as `op.attributes` on Yjs delta\n// inserts; the serialiser wraps text runs with the matching wire\n// delimiters.\n//\n// See SPEC.md §3-4 for the rendered table and the disambiguation\n// rules between bold (`**…**`) and underline (`__…__`).\n\nexport type MarkWireKind =\n | 'delimited' // `**text**`, `*text*`, `~~text~~`, `` `text` ``\n | 'link' // `[text](href)`\n | 'mdc-span' // `:span[text]{prop=value}` for color/font/textStyle\n\nexport interface MarkAttrSpec {\n key: string\n type: 'string' | 'number' | 'boolean'\n optional?: boolean\n}\n\nexport interface MarkSpec {\n name: string\n wire: MarkWireKind\n /** For `delimited`: the markdown delimiter (e.g. `**`, `*`, `~~`, `` ` ``, `__`, `==`). */\n delim?: string\n attrs?: readonly MarkAttrSpec[]\n doc?: string\n}\n\nexport const MARK_SPECS: readonly MarkSpec[] = [\n // Vanilla MD marks\n { name: 'bold', wire: 'delimited', delim: '**' },\n { name: 'italic', wire: 'delimited', delim: '*' },\n { name: 'strike', wire: 'delimited', delim: '~~' },\n { name: 'code', wire: 'delimited', delim: '`' },\n {\n name: 'link',\n wire: 'link',\n attrs: [\n { key: 'href', type: 'string' },\n { key: 'title', type: 'string', optional: true },\n ],\n },\n\n // Extended marks (lossless via MDC syntax)\n {\n name: 'underline',\n wire: 'delimited',\n delim: '__',\n doc: 'Disambiguated from bold by delimiter character. Two underscores = underline; two asterisks = bold.',\n },\n {\n name: 'highlight',\n wire: 'delimited',\n delim: '==',\n doc: 'Pandoc-style.',\n },\n {\n name: 'subscript',\n wire: 'delimited',\n delim: '~',\n doc: 'Single tilde; double tilde is strike.',\n },\n {\n name: 'superscript',\n wire: 'delimited',\n delim: '^',\n },\n {\n name: 'textStyle',\n wire: 'mdc-span',\n attrs: [\n { key: 'color', type: 'string', optional: true },\n { key: 'backgroundColor', type: 'string', optional: true },\n { key: 'fontSize', type: 'string', optional: true },\n { key: 'fontFamily', type: 'string', optional: true },\n ],\n doc: 'Wire form `:span[text]{color=\"…\" font-size=\"…\"}`. Any of the attrs may be set.',\n },\n]\n\nexport const MARK_SPEC_BY_NAME: ReadonlyMap<string, MarkSpec> = new Map(\n MARK_SPECS.map(spec => [spec.name, spec]),\n)\n\nexport const MARK_SPEC_BY_DELIM: ReadonlyMap<string, MarkSpec> = new Map(\n MARK_SPECS\n .filter((spec): spec is MarkSpec & { delim: string } => spec.wire === 'delimited' && !!spec.delim)\n .map(spec => [spec.delim, spec]),\n)\n","// Universal-meta registry.\n//\n// Mirrors `@abraca/schema/src/types/universal.ts` — the canonical\n// source. We don't import @abraca/schema here to keep this package\n// dependency-free, but the keys MUST stay in sync. A future codegen\n// step in @abraca/schema can verify this file is up to date.\n//\n// Order is significant — it's the canonical key order in serialised\n// YAML frontmatter (see SPEC.md §2). Adding new keys appends to the\n// end so existing fixtures don't churn.\n\nexport type MetaValueType =\n | 'string'\n | 'number'\n | 'integer'\n | 'boolean'\n | 'string[]'\n | 'string-enum'\n | 'iso-date'\n | 'iso-datetime'\n | 'hh-mm'\n | 'members'\n | 'json'\n\nexport interface UniversalMetaKey {\n key: string\n type: MetaValueType\n /** Allowed values for `string-enum`. */\n values?: readonly string[]\n /** Inclusive minimum for `number` / `integer`. */\n min?: number\n /** Inclusive maximum for `number` / `integer`. */\n max?: number\n /**\n * Alternate YAML key names recognised on parse — for backwards\n * compatibility with hand-written frontmatter (e.g. `date` → `dateStart`).\n * Serialise always uses the canonical `key`.\n */\n parseAliases?: readonly string[]\n /** Human-readable hint, surfaced in documentation. */\n doc?: string\n}\n\nexport const UNIVERSAL_META_KEYS: readonly UniversalMetaKey[] = [\n // Identity / display\n { key: 'title', type: 'string', doc: 'Display title; the first H1 is hoisted into this field on import.' },\n { key: 'type', type: 'string', doc: 'Page type (doc, kanban, table, …). Omitted on serialise when \"doc\".' },\n { key: 'color', type: 'string', doc: 'Hex or CSS color name.' },\n { key: 'icon', type: 'string', doc: 'Lucide icon name in kebab-case.' },\n\n // Datetime\n { key: 'datetimeStart', type: 'iso-datetime' },\n { key: 'datetimeEnd', type: 'iso-datetime' },\n { key: 'allDay', type: 'boolean' },\n { key: 'dateTaken', type: 'iso-datetime' },\n { key: 'dateStart', type: 'iso-date', parseAliases: ['date', 'created'] },\n { key: 'dateEnd', type: 'iso-date', parseAliases: ['due'] },\n { key: 'timeStart', type: 'hh-mm' },\n { key: 'timeEnd', type: 'hh-mm' },\n\n // Generic\n { key: 'tags', type: 'string[]' },\n { key: 'checked', type: 'boolean', parseAliases: ['done'] },\n {\n key: 'priority',\n type: 'integer',\n min: 0,\n max: 4,\n doc: 'Numeric or named (low/medium/high/urgent → 1/2/3/4).',\n },\n { key: 'status', type: 'string' },\n { key: 'rating', type: 'number', min: 0, max: 5 },\n { key: 'url', type: 'string' },\n { key: 'email', type: 'string' },\n { key: 'phone', type: 'string' },\n { key: 'number', type: 'number' },\n { key: 'unit', type: 'string' },\n { key: 'subtitle', type: 'string', parseAliases: ['description'] },\n { key: 'note', type: 'string' },\n { key: 'taskProgress', type: 'integer', min: 0, max: 100 },\n { key: 'members', type: 'members' },\n\n // Cover\n { key: 'coverUploadId', type: 'string' },\n { key: 'coverDocId', type: 'string' },\n { key: 'coverMimeType', type: 'string' },\n\n // Geo / map\n { key: 'geoType', type: 'string-enum', values: ['marker', 'line', 'measure'] },\n { key: 'geoLat', type: 'number' },\n { key: 'geoLng', type: 'number' },\n { key: 'geoDescription', type: 'string' },\n\n // Dashboard / mindmap / graph layout\n { key: 'deskX', type: 'number' },\n { key: 'deskY', type: 'number' },\n { key: 'deskZ', type: 'number' },\n { key: 'deskMode', type: 'string-enum', values: ['icon', 'widget-sm', 'widget-lg'] },\n { key: 'mmX', type: 'number' },\n { key: 'mmY', type: 'number' },\n { key: 'graphX', type: 'number' },\n { key: 'graphY', type: 'number' },\n { key: 'graphPinned', type: 'boolean' },\n\n // Spatial\n { key: 'spX', type: 'number' },\n { key: 'spY', type: 'number' },\n { key: 'spZ', type: 'number' },\n { key: 'spRX', type: 'number' },\n { key: 'spRY', type: 'number' },\n { key: 'spRZ', type: 'number' },\n { key: 'spSX', type: 'number' },\n { key: 'spSY', type: 'number' },\n { key: 'spSZ', type: 'number' },\n {\n key: 'spShape',\n type: 'string-enum',\n values: ['box', 'sphere', 'cylinder', 'cone', 'plane', 'torus', 'glb'],\n },\n { key: 'spOpacity', type: 'integer', min: 0, max: 100 },\n { key: 'spModelUploadId', type: 'string' },\n { key: 'spModelDocId', type: 'string' },\n\n // Slides\n { key: 'slidesTransition', type: 'string-enum', values: ['none', 'fade', 'slide'] },\n { key: 'slidesTheme', type: 'string-enum', values: ['dark', 'light'] },\n\n // Migration version (last so unknown keys ahead of it surface clearly)\n { key: '__schemaVersion', type: 'integer', min: 0 },\n] as const\n\nexport const UNIVERSAL_META_KEY_NAMES: ReadonlySet<string> = new Set(\n UNIVERSAL_META_KEYS.map(k => k.key),\n)\n\n/**\n * Build a map of every recognised input key (canonical + aliases) to\n * its canonical key. Used by the frontmatter parser.\n */\nexport function buildAliasMap(): ReadonlyMap<string, string> {\n const map = new Map<string, string>()\n for (const entry of UNIVERSAL_META_KEYS) {\n map.set(entry.key, entry.key)\n for (const alias of entry.parseAliases ?? []) map.set(alias, entry.key)\n }\n return map\n}\n","// ── Manifest: docId <-> filesystem path mapping ─────────────────────────────\n//\n// The manifest tracks which doc on the server maps to which file on\n// disk, plus per-doc upload (binary attachment) records and content\n// hashes for change detection.\n//\n// Filesystem I/O is INJECTABLE so Node hosts (memfs for tests, fs/promises\n// for Electron, @tauri-apps/plugin-fs for Tauri) can all use this code\n// without the package taking a hard dep on any one. If no adapter has\n// been wired and we're inside Tauri, we lazily fall back to the Tauri\n// plugin. Pure-test setups should always call `setFsAdapter()` first.\n\nexport interface FsAdapter {\n readTextFile: (path: string) => Promise<string>\n writeTextFile: (path: string, contents: string) => Promise<void>\n mkdir: (path: string, options?: { recursive?: boolean }) => Promise<void>\n readBinaryFile?: (path: string) => Promise<Uint8Array>\n writeBinaryFile?: (path: string, contents: Uint8Array) => Promise<void>\n exists?: (path: string) => Promise<boolean>\n remove?: (path: string) => Promise<void>\n}\n\nlet _adapter: FsAdapter | null = null\n\n/** Install a filesystem adapter. Call this once at boot. */\nexport function setFsAdapter(adapter: FsAdapter): void {\n _adapter = adapter\n}\n\n/** Read back the active adapter — useful for tests and for layered code. */\nexport function getFsAdapter(): FsAdapter | null {\n return _adapter\n}\n\nasync function loadFsApi(): Promise<FsAdapter> {\n if (_adapter) return _adapter\n throw new Error(\n '@abraca/convert: no FsAdapter installed. '\n + 'Call setFsAdapter({readTextFile, writeTextFile, mkdir, …}) at boot. '\n + 'Tauri hosts can pass `@tauri-apps/plugin-fs` directly; Node hosts can pass '\n + 'a wrapper over `fs/promises`; tests can use the in-memory adapter from '\n + 'tests/file-blocks.test.ts as a template.',\n )\n}\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface UploadManifestEntry {\n uploadId: string\n filename: string\n relativePath: string // e.g. \"_files/abc123/photo.jpg\"\n contentHash: string\n}\n\nexport interface ManifestEntry {\n docId: string\n relativePath: string // e.g. \"projects/my-project/_index.md\"\n contentHash: string // hash of last-written/read markdown\n lastWrittenAt: number\n lastReadAt: number\n // Code page type: the companion code file written alongside the `.md`\n // envelope (e.g. \"src/main.rs\"), and the hash of its last-synced text.\n // Present only for `code` docs.\n codePath?: string\n codeHash?: string\n uploads: UploadManifestEntry[]\n}\n\nexport interface FsSyncManifest {\n version: 2\n spaceId: string\n lastSyncAt: number\n entries: Record<string, ManifestEntry> // keyed by docId\n}\n\n// ── CRUD ─────────────────────────────────────────────────────────────────────\n\nconst MANIFEST_DIR = '.abracadabra'\nconst MANIFEST_FILE = 'manifest.json'\n\nfunction manifestPath(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/${MANIFEST_FILE}`\n}\n\nexport function manifestDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}`\n}\n\nexport function trashDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/trash`\n}\n\nexport function orphansDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/orphans`\n}\n\nexport function conflictsDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/conflicts`\n}\n\nexport function createEmptyManifest(spaceId: string): FsSyncManifest {\n return {\n version: 2,\n spaceId,\n lastSyncAt: 0,\n entries: {}\n }\n}\n\nexport async function loadManifest(syncDir: string, spaceId: string): Promise<FsSyncManifest> {\n const fs = await loadFsApi()\n try {\n const raw = await fs.readTextFile(manifestPath(syncDir))\n const parsed = JSON.parse(raw) as FsSyncManifest\n if (parsed.version === 2) return parsed\n }\n catch {\n // missing or corrupt — return fresh\n }\n return createEmptyManifest(spaceId)\n}\n\nexport async function saveManifest(syncDir: string, manifest: FsSyncManifest): Promise<void> {\n const fs = await loadFsApi()\n const dir = `${syncDir}/${MANIFEST_DIR}`\n try {\n await fs.mkdir(dir, { recursive: true })\n }\n catch {\n // already exists\n }\n manifest.lastSyncAt = Date.now()\n await fs.writeTextFile(manifestPath(syncDir), JSON.stringify(manifest, null, 2))\n}\n\n// ── Lookups ──────────────────────────────────────────────────────────────────\n\nexport function lookupByDocId(manifest: FsSyncManifest, docId: string): ManifestEntry | undefined {\n return manifest.entries[docId]\n}\n\nexport function lookupByPath(manifest: FsSyncManifest, relativePath: string): ManifestEntry | undefined {\n for (const entry of Object.values(manifest.entries)) {\n if (entry.relativePath === relativePath) return entry\n }\n return undefined\n}\n\nexport function lookupByHash(manifest: FsSyncManifest, contentHash: string): ManifestEntry | undefined {\n for (const entry of Object.values(manifest.entries)) {\n if (entry.contentHash === contentHash) return entry\n }\n return undefined\n}\n\nexport function setEntry(manifest: FsSyncManifest, entry: ManifestEntry): void {\n manifest.entries[entry.docId] = entry\n}\n\nexport function removeEntry(manifest: FsSyncManifest, docId: string): ManifestEntry | undefined {\n const entry = manifest.entries[docId]\n if (entry) delete manifest.entries[docId]\n return entry\n}\n\n// ── Build reverse lookup (path -> docId) ─────────────────────────────────────\n\nexport function buildReverseLookup(manifest: FsSyncManifest): Map<string, string> {\n const map = new Map<string, string>()\n for (const [docId, entry] of Object.entries(manifest.entries)) {\n map.set(entry.relativePath, docId)\n }\n return map\n}\n","// ── Collision-safe path building for FS sync ─────────────────────────────────\n\nimport * as Y from 'yjs'\n\nimport type { FsSyncManifest } from './manifest.ts'\n\nexport interface FsTreeEntry {\n label: string\n parentId: string | null\n order: number\n type?: string\n meta?: any\n}\n\n/**\n * Convert a document label to a filesystem-safe filename (without extension).\n * e.g. \"My Project!\" -> \"my-project\"\n */\nexport function labelToFilename(label: string): string {\n // Nullish-safe: real trees (kanban cards, server-compacted entries)\n // contain entries with no `label`; buildRelativePath() calls this for\n // a doc AND every ancestor, so one missing label must not throw and\n // abort fs-sync for the whole tree. Empty → 'untitled' (below).\n return (\n String(label ?? '')\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '') || 'untitled'\n )\n}\n\n/**\n * Convert a filename back to a label (best-effort).\n * e.g. \"my-project\" -> \"my project\", \"my-project~a3f2\" -> \"my project\"\n */\nexport function fsFilenameToLabel(filename: string): string {\n // Strip collision suffix\n const cleaned = filename.replace(/~[a-z0-9]{4}$/, '')\n return cleaned.replace(/-/g, ' ')\n}\n\n/**\n * Check if a doc has children in the tree (needs _index.md convention).\n */\nexport function hasChildren(docId: string, treeData: Record<string, FsTreeEntry>): boolean {\n for (const entry of Object.values(treeData)) {\n if (entry.parentId === docId) return true\n }\n return false\n}\n\n/**\n * Resolve filename collisions by appending ~XXXX (first 4 chars of docId).\n * Returns the filename (without extension) that should be used.\n */\nfunction resolveCollision(\n desiredFilename: string,\n docId: string,\n parentPath: string,\n manifest: FsSyncManifest,\n isIndex: boolean\n): string {\n const ext = '.md'\n const desiredRelative = isIndex\n ? `${parentPath}${parentPath ? '/' : ''}${desiredFilename}/_index${ext}`\n : `${parentPath}${parentPath ? '/' : ''}${desiredFilename}${ext}`\n\n // Check if any other doc already claims this path\n for (const [entryDocId, entry] of Object.entries(manifest.entries)) {\n if (entryDocId === docId) continue\n if (entry.relativePath === desiredRelative) {\n // Collision — append disambiguator\n return `${desiredFilename}~${docId.substring(0, 4)}`\n }\n }\n\n return desiredFilename\n}\n\n/**\n * Build the relative path for a document (from syncDir root).\n * Handles:\n * - Ancestor chain walking\n * - _index.md for docs with children\n * - Collision resolution via ~XXXX suffix\n */\nexport function buildRelativePath(\n docId: string,\n treeData: Record<string, FsTreeEntry>,\n manifest: FsSyncManifest\n): string {\n const entry = treeData[docId]\n if (!entry) return `${docId}.md` // fallback for unknown docs\n\n // Walk up the ancestor chain to build path segments\n const segments: string[] = []\n let current: FsTreeEntry | undefined = entry\n let currentId = docId\n\n const visited = new Set<string>()\n while (current) {\n if (visited.has(currentId)) break // circular reference guard\n visited.add(currentId)\n\n segments.unshift(labelToFilename(current.label))\n if (!current.parentId) break\n currentId = current.parentId\n current = treeData[currentId]\n }\n\n // The last segment is the doc itself; everything before is parent dirs\n const filename = segments.pop()!\n const parentPath = segments.join('/')\n\n // Check if this doc needs _index.md (has children)\n const isIndex = hasChildren(docId, treeData)\n\n // Resolve collisions\n const resolvedFilename = resolveCollision(filename, docId, parentPath, manifest, isIndex)\n\n if (isIndex) {\n return `${parentPath}${parentPath ? '/' : ''}${resolvedFilename}/_index.md`\n }\n return `${parentPath}${parentPath ? '/' : ''}${resolvedFilename}.md`\n}\n\n/**\n * Companion code-file path for a `code` doc, derived from its `.md`\n * envelope path by swapping the extension. e.g.\n * `src/main.md` + `rs` -> `src/main.rs`. A code doc never has children,\n * so the `_index.md` form is not expected here, but is handled defensively.\n */\nexport function codeCompanionPath(mdRelativePath: string, fileExtension: string): string {\n const ext = fileExtension.replace(/^\\.+/, '').toLowerCase() || 'txt'\n if (mdRelativePath.endsWith('/_index.md')) {\n return `${mdRelativePath.slice(0, -'/_index.md'.length)}/_index.${ext}`\n }\n if (mdRelativePath.endsWith('.md')) {\n return `${mdRelativePath.slice(0, -'.md'.length)}.${ext}`\n }\n return `${mdRelativePath}.${ext}`\n}\n\n/**\n * Get the directory portion of a relative path for a doc.\n * For _index.md docs: returns the directory containing _index.md\n * For leaf docs: returns the parent directory\n */\nexport function getDocDir(relativePath: string): string {\n if (relativePath.endsWith('/_index.md')) {\n // e.g. \"projects/my-project/_index.md\" -> \"projects/my-project\"\n return relativePath.replace('/_index.md', '')\n }\n // e.g. \"projects/my-project/task.md\" -> \"projects/my-project\"\n const lastSlash = relativePath.lastIndexOf('/')\n return lastSlash >= 0 ? relativePath.substring(0, lastSlash) : ''\n}\n\n/**\n * Determine the parent docId from a filesystem relative path by walking the\n * path segments and matching against the tree.\n */\nexport function resolveParentFromPath(\n relativePath: string,\n treeData: Record<string, FsTreeEntry>\n): string | null {\n // Strip filename to get directory parts\n const parts = relativePath.split('/')\n parts.pop() // remove filename\n\n // For _index.md, also remove the doc's own directory name\n if (relativePath.endsWith('/_index.md') && parts.length > 0) {\n parts.pop()\n }\n\n if (parts.length === 0) return null // root-level doc\n\n let parentId: string | null = null\n for (const segment of parts) {\n const found = Object.entries(treeData).find(\n ([, e]) => labelToFilename(e.label) === segment && e.parentId === parentId\n )\n if (found) {\n parentId = found[0]\n } else {\n // Can't resolve further — return last known parent\n break\n }\n }\n return parentId\n}\n\n/**\n * Simple string hash (same as current useFsSync).\n */\nexport function simpleHash(str: string): string {\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0\n }\n return hash.toString(36)\n}\n\n/**\n * Get all tree data as a flat record.\n */\nexport function getTreeData(treeMap: any): Record<string, FsTreeEntry> {\n const data: Record<string, FsTreeEntry> = {}\n treeMap.forEach((val: any, key: string) => {\n // A tree entry may be stored as a nested Y.Map — both from the\n // per-key ⑦ write path (every SDK + cou-sh) and from server-side\n // Yrs compaction. Read it as a plain object (mirror of the\n // provider's `toPlain`); a raw Y.Map would expose\n // label/parentId/order as `undefined` and silently corrupt the\n // FS-sync tree (mass mis-parent / mis-label / spurious delete).\n //\n // Detect Y.Map by DUCK-TYPING, not `instanceof`: a host that wires\n // @abraca/dabra (which bundles its own physical `yjs`) alongside\n // this package would fail an instanceof across the two yjs copies\n // and hand back the raw Y.Map → every doc \"untitled\". toJSON()\n // works regardless of which yjs constructed the map.\n const isYMap = val instanceof Y.Map\n || (!!val && typeof val === 'object'\n && typeof (val as any).toJSON === 'function'\n && typeof (val as any).get === 'function')\n const plain = isYMap ? (val as any).toJSON() : val\n if (plain && typeof plain === 'object') {\n data[key] = plain as FsTreeEntry\n }\n })\n return data\n}\n\n/**\n * Find the next order value for a given parent (max sibling order + 1).\n */\nexport function nextOrder(treeData: Record<string, FsTreeEntry>, parentId: string | null): number {\n let max = -1\n for (const entry of Object.values(treeData)) {\n if (entry.parentId === parentId && entry.order > max) {\n max = entry.order\n }\n }\n return max + 1\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"abracadabra-convert.cjs","names":["Y","Y","Y","Y"],"sources":["../src/spec/universal-meta.ts","../src/markdown-to-yjs.ts","../src/yjs-to-markdown.ts","../src/html-to-yjs.ts","../src/code.ts","../src/diff.ts","../src/spec/nodes.ts","../src/spec/marks.ts","../src/file-blocks/manifest.ts","../src/file-blocks/paths.ts"],"sourcesContent":["// Universal-meta registry.\n//\n// Mirrors `@abraca/schema/src/types/universal.ts` — the canonical\n// source. We don't import @abraca/schema here to keep this package\n// dependency-free, but the keys MUST stay in sync. A future codegen\n// step in @abraca/schema can verify this file is up to date.\n//\n// Order is significant — it's the canonical key order in serialised\n// YAML frontmatter (see SPEC.md §2). Adding new keys appends to the\n// end so existing fixtures don't churn.\n\nexport type MetaValueType =\n | 'string'\n | 'number'\n | 'integer'\n | 'boolean'\n | 'string[]'\n | 'string-enum'\n | 'iso-date'\n | 'iso-datetime'\n | 'hh-mm'\n | 'members'\n | 'json'\n\nexport interface UniversalMetaKey {\n key: string\n type: MetaValueType\n /** Allowed values for `string-enum`. */\n values?: readonly string[]\n /** Inclusive minimum for `number` / `integer`. */\n min?: number\n /** Inclusive maximum for `number` / `integer`. */\n max?: number\n /**\n * Alternate YAML key names recognised on parse — for backwards\n * compatibility with hand-written frontmatter (e.g. `date` → `dateStart`).\n * Serialise always uses the canonical `key`.\n */\n parseAliases?: readonly string[]\n /** Human-readable hint, surfaced in documentation. */\n doc?: string\n}\n\nexport const UNIVERSAL_META_KEYS: readonly UniversalMetaKey[] = [\n // Identity / display\n { key: 'title', type: 'string', doc: 'Display title; the first H1 is hoisted into this field on import.' },\n { key: 'type', type: 'string', doc: 'Page type (doc, kanban, table, …). Omitted on serialise when \"doc\".' },\n { key: 'color', type: 'string', doc: 'Hex or CSS color name.' },\n { key: 'icon', type: 'string', doc: 'Lucide icon name in kebab-case.' },\n\n // Datetime\n { key: 'datetimeStart', type: 'iso-datetime' },\n { key: 'datetimeEnd', type: 'iso-datetime' },\n { key: 'allDay', type: 'boolean' },\n { key: 'dateTaken', type: 'iso-datetime' },\n { key: 'dateStart', type: 'iso-date', parseAliases: ['date', 'created'] },\n { key: 'dateEnd', type: 'iso-date', parseAliases: ['due'] },\n { key: 'timeStart', type: 'hh-mm' },\n { key: 'timeEnd', type: 'hh-mm' },\n\n // Generic\n { key: 'tags', type: 'string[]' },\n { key: 'checked', type: 'boolean', parseAliases: ['done'] },\n {\n key: 'priority',\n type: 'integer',\n min: 0,\n max: 4,\n doc: 'Numeric or named (low/medium/high/urgent → 1/2/3/4).',\n },\n { key: 'status', type: 'string' },\n { key: 'rating', type: 'number', min: 0, max: 5 },\n { key: 'url', type: 'string' },\n { key: 'email', type: 'string' },\n { key: 'phone', type: 'string' },\n { key: 'number', type: 'number' },\n { key: 'unit', type: 'string' },\n { key: 'subtitle', type: 'string', parseAliases: ['description'] },\n { key: 'note', type: 'string' },\n { key: 'taskProgress', type: 'integer', min: 0, max: 100 },\n { key: 'members', type: 'members' },\n\n // Cover\n { key: 'coverUploadId', type: 'string' },\n { key: 'coverDocId', type: 'string' },\n { key: 'coverMimeType', type: 'string' },\n\n // Geo / map\n { key: 'geoType', type: 'string-enum', values: ['marker', 'line', 'measure'] },\n { key: 'geoLat', type: 'number' },\n { key: 'geoLng', type: 'number' },\n { key: 'geoDescription', type: 'string' },\n\n // Dashboard / mindmap / graph layout\n { key: 'deskX', type: 'number' },\n { key: 'deskY', type: 'number' },\n { key: 'deskZ', type: 'number' },\n { key: 'deskMode', type: 'string-enum', values: ['icon', 'widget-sm', 'widget-lg'] },\n { key: 'mmX', type: 'number' },\n { key: 'mmY', type: 'number' },\n { key: 'graphX', type: 'number' },\n { key: 'graphY', type: 'number' },\n { key: 'graphPinned', type: 'boolean' },\n\n // Spatial\n { key: 'spX', type: 'number' },\n { key: 'spY', type: 'number' },\n { key: 'spZ', type: 'number' },\n { key: 'spRX', type: 'number' },\n { key: 'spRY', type: 'number' },\n { key: 'spRZ', type: 'number' },\n { key: 'spSX', type: 'number' },\n { key: 'spSY', type: 'number' },\n { key: 'spSZ', type: 'number' },\n {\n key: 'spShape',\n type: 'string-enum',\n values: ['box', 'sphere', 'cylinder', 'cone', 'plane', 'torus', 'glb'],\n },\n { key: 'spOpacity', type: 'integer', min: 0, max: 100 },\n { key: 'spModelUploadId', type: 'string' },\n { key: 'spModelDocId', type: 'string' },\n\n // Slides\n { key: 'slidesTransition', type: 'string-enum', values: ['none', 'fade', 'slide'] },\n { key: 'slidesTheme', type: 'string-enum', values: ['dark', 'light'] },\n\n // Migration version (last so unknown keys ahead of it surface clearly)\n { key: '__schemaVersion', type: 'integer', min: 0 },\n] as const\n\nexport const UNIVERSAL_META_KEY_NAMES: ReadonlySet<string> = new Set(\n UNIVERSAL_META_KEYS.map(k => k.key),\n)\n\n/**\n * Build a map of every recognised input key (canonical + aliases) to\n * its canonical key. Used by the frontmatter parser.\n */\nexport function buildAliasMap(): ReadonlyMap<string, string> {\n const map = new Map<string, string>()\n for (const entry of UNIVERSAL_META_KEYS) {\n map.set(entry.key, entry.key)\n for (const alias of entry.parseAliases ?? []) map.set(alias, entry.key)\n }\n return map\n}\n","import * as Y from 'yjs'\nimport type { DocPageMeta } from './types.ts'\nimport {\n buildAliasMap,\n UNIVERSAL_META_KEYS,\n type UniversalMetaKey,\n type MetaValueType,\n} from './spec/universal-meta.ts'\n\n// ── Filename → readable label ────────────────────────────────────────────────\n\n/**\n * Converts a filename (without extension) to a human-readable label.\n *\n * - `this-is-a-doc` → `\"This is a doc\"` (kebab/snake: sentence case)\n * - `ThisIsADoc` → `\"This Is A Doc\"` (PascalCase: preserves word caps)\n * - `thisIsADoc` → `\"This Is A Doc\"` (camelCase: preserves word caps)\n */\nexport function filenameToLabel(raw: string): string {\n const base = raw.replace(/\\.[^.]+$/, '') // strip extension if present\n const spaced = base.replace(/([a-z])([A-Z])/g, '$1 $2')\n const clean = spaced.replace(/[-_.]+/g, ' ').replace(/\\s+/g, ' ').trim()\n return clean.charAt(0).toUpperCase() + clean.slice(1)\n}\n\n// ── YAML frontmatter parser ──────────────────────────────────────────────────\n\nexport interface FrontmatterResult {\n title?: string\n type?: string\n meta: Partial<DocPageMeta>\n body: string\n}\n\nfunction coerceScalar(raw: string): string | number | boolean {\n const trimmed = raw.trim()\n if (trimmed === 'true') return true\n if (trimmed === 'false') return false\n const num = Number(trimmed)\n if (!Number.isNaN(num) && trimmed !== '') return num\n // Strip surrounding quotes\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n || (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\nfunction parseInlineArray(raw: string): string[] {\n // e.g. \"[a, b, c]\"\n return raw.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean)\n}\n\nfunction stripQuotes(s: string): string {\n if (s.length >= 2\n && ((s.startsWith('\"') && s.endsWith('\"'))\n || (s.startsWith('\\'') && s.endsWith('\\'')))) {\n return s.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\')\n }\n return s\n}\n\nexport function parseFrontmatter(markdown: string): FrontmatterResult {\n const noResult: FrontmatterResult = { meta: {}, body: markdown }\n\n const match = markdown.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/)\n if (!match) return noResult\n\n const yamlBlock = match[1]!\n const body = markdown.slice(match[0].length)\n\n // Parse YAML into a raw map\n const raw: Record<string, string | string[]> = {}\n const lines = yamlBlock.split('\\n')\n let i = 0\n while (i < lines.length) {\n const line = lines[i]!\n // Block sequence: \"key:\\n - a\\n - b\"\n const blockSeqKey = line.match(/^(\\w[\\w-]*):\\s*$/)\n if (blockSeqKey && i + 1 < lines.length && /^\\s+-\\s/.test(lines[i + 1]!)) {\n const key = blockSeqKey[1]!\n const items: string[] = []\n i++\n while (i < lines.length && /^\\s+-\\s/.test(lines[i]!)) {\n items.push(lines[i]!.replace(/^\\s+-\\s/, '').trim())\n i++\n }\n raw[key] = items\n continue\n }\n // Scalar or inline array\n const kvMatch = line.match(/^(\\w[\\w-]*):\\s*(.*)$/)\n if (kvMatch) {\n const key = kvMatch[1]!\n const val = kvMatch[2]!.trim()\n if (val.startsWith('[') && val.endsWith(']')) {\n raw[key] = parseInlineArray(val).map(stripQuotes)\n } else {\n // Strip surrounding quotes up-front so downstream readers\n // don't have to. The original quote state is irrelevant — we\n // re-emit with our canonical quoting rules.\n raw[key] = stripQuotes(val)\n }\n }\n i++\n }\n\n // Map raw YAML keys → PageMeta\n const meta: Partial<DocPageMeta> = {}\n\n const getStr = (keys: string[]): string | undefined => {\n for (const k of keys) {\n const v = raw[k]\n if (typeof v === 'string' && v) return v\n }\n }\n const getArr = (keys: string[]): string[] | undefined => {\n for (const k of keys) {\n const v = raw[k]\n if (Array.isArray(v)) return v\n if (typeof v === 'string' && v) return [v]\n }\n }\n\n if (raw['tags']) meta.tags = Array.isArray(raw['tags']) ? raw['tags'] : [raw['tags'] as string]\n const color = getStr(['color'])\n if (color) meta.color = color\n const icon = getStr(['icon'])\n if (icon) meta.icon = icon\n const status = getStr(['status'])\n if (status) meta.status = status\n\n const priorityRaw = getStr(['priority'])\n if (priorityRaw !== undefined) {\n const map: Record<string, number> = { low: 1, medium: 2, high: 3, urgent: 4 }\n meta.priority = map[priorityRaw.toLowerCase()] ?? (Number(priorityRaw) || 0)\n }\n\n const checkedRaw: unknown = raw['checked'] ?? raw['done']\n if (checkedRaw !== undefined) meta.checked = checkedRaw === 'true' || checkedRaw === true\n\n // Canonical keys are checked first, aliases follow — so files that\n // already use the canonical name (dateStart, dateEnd, subtitle) keep\n // round-tripping byte-stably while legacy aliases still parse.\n const dateStart = getStr(['dateStart', 'date', 'created'])\n if (dateStart) meta.dateStart = dateStart\n const dateEnd = getStr(['dateEnd', 'due'])\n if (dateEnd) meta.dateEnd = dateEnd\n\n const subtitle = getStr(['subtitle', 'description'])\n if (subtitle) meta.subtitle = subtitle\n const url = getStr(['url'])\n if (url) meta.url = url\n\n // Code page type meta.\n const language = getStr(['language'])\n if (language) meta.language = language\n const fileExtension = getStr(['fileExtension'])\n if (fileExtension) meta.fileExtension = fileExtension\n const codeTheme = getStr(['codeTheme'])\n if (codeTheme) meta.codeTheme = codeTheme\n\n const ratingRaw = getStr(['rating'])\n if (ratingRaw !== undefined) {\n const n = Number(ratingRaw)\n if (!Number.isNaN(n)) meta.rating = Math.min(5, Math.max(0, n))\n }\n\n // ── Generic spec-driven pass ──\n // Everything the hand-rolled section above didn't consume: map through\n // the universal-meta alias map and coerce by the spec's value type, so\n // graph/map/spatial/dashboard layout, covers, datetimes etc. survive\n // import instead of being silently dropped. Unknown custom keys are\n // preserved with best-effort coercion; internal `_`-keys are ignored.\n for (const [rawKey, rawVal] of Object.entries(raw)) {\n if (CONSUMED_FM_KEYS.has(rawKey)) continue\n if (rawKey.startsWith('_')) continue\n const canonical = FM_ALIAS_MAP.get(rawKey)\n if (canonical) {\n if (canonical === 'title' || canonical === 'type') continue\n if ((meta as Record<string, unknown>)[canonical] !== undefined) continue\n const spec = FM_SPEC_BY_KEY.get(canonical)\n const coerced = coerceMetaValue(rawVal, spec?.type)\n if (coerced !== undefined) (meta as Record<string, unknown>)[canonical] = coerced\n } else {\n const coerced = coerceMetaValue(rawVal, undefined)\n if (coerced !== undefined) (meta as Record<string, unknown>)[rawKey] = coerced\n }\n }\n\n const rawTitle = typeof raw['title'] === 'string' ? raw['title'] : undefined\n const title = rawTitle !== undefined ? stripQuotes(rawTitle) : undefined\n const type = getStr(['type'])\n\n return { title, type, meta, body }\n}\n\n/** Raw YAML keys the hand-rolled section of parseFrontmatter consumes. */\nconst CONSUMED_FM_KEYS: ReadonlySet<string> = new Set([\n 'title', 'type', 'tags', 'color', 'icon', 'status', 'priority',\n 'checked', 'done', 'dateStart', 'date', 'created', 'dateEnd', 'due',\n 'subtitle', 'description', 'url', 'language', 'fileExtension',\n 'codeTheme', 'rating',\n])\n\nconst FM_ALIAS_MAP: ReadonlyMap<string, string> = buildAliasMap()\nconst FM_SPEC_BY_KEY: ReadonlyMap<string, UniversalMetaKey> = new Map(\n UNIVERSAL_META_KEYS.map(k => [k.key, k]),\n)\n\n/**\n * Coerce a raw YAML scalar/array to the spec's value type. With no spec\n * (custom key) the coercion is best-effort: booleans and numbers are\n * recognised by shape, everything else stays a string. Returns undefined\n * when the value can't be represented (caller skips the key).\n */\nfunction coerceMetaValue(\n rawVal: string | string[],\n specType: MetaValueType | undefined,\n): unknown {\n if (Array.isArray(rawVal)) return rawVal\n const v = rawVal\n if (v === '') return undefined\n switch (specType) {\n case 'number':\n case 'integer': {\n const n = Number(v)\n return Number.isFinite(n) ? n : undefined\n }\n case 'boolean':\n return v === 'true'\n case 'string[]':\n return [v]\n case 'members':\n case 'json': {\n try {\n return JSON.parse(v)\n } catch {\n return undefined\n }\n }\n case 'string':\n case 'string-enum':\n case 'iso-date':\n case 'iso-datetime':\n case 'hh-mm':\n return v\n case undefined: {\n // Custom key — recognise booleans/numbers/JSON payloads by shape\n // (quotes were already stripped when the raw map was built).\n if (v === 'true') return true\n if (v === 'false') return false\n if (/^-?\\d+(\\.\\d+)?$/.test(v)) return Number(v)\n if (v.startsWith('{')) {\n try {\n return JSON.parse(v)\n } catch { /* fall through to string */ }\n }\n return v\n }\n }\n}\n\n// ── Inline token parsing ─────────────────────────────────────────────────────\n\ninterface InlineToken {\n text: string\n attrs?: Record<string, unknown>\n}\n\n// Re-tokenize the inner text of a wrapping mark (bold/italic/strike) so nested\n// atoms (wikilinks, mentions, code, math) and nested marks survive instead of\n// being captured as a single literal leaf. The wrapping mark's attrs are merged\n// onto every produced child token; object-valued attrs (docLink/mention/badge)\n// are preserved alongside the boolean mark. Terminates because `inner` is\n// strictly shorter than the matched delimiter run.\nfunction pushNested(\n out: InlineToken[],\n inner: string,\n wrap: Record<string, unknown>,\n): void {\n const children = parseInline(inner)\n if (children.length === 0) {\n out.push({ text: inner, attrs: { ...wrap } })\n return\n }\n for (const child of children) {\n out.push({ text: child.text, attrs: { ...(child.attrs ?? {}), ...wrap } })\n }\n}\n\nfunction parseInline(text: string): InlineToken[] {\n // Strip MDC attribute annotations on inline code: `string`{lang=\"ts-type\"}\n const stripped = text.replace(/\\{lang=\"[^\"]*\"\\}/g, '')\n // Strip remaining unknown inline MDC components (but NOT badge/icon/kbd — handled below)\n .replace(/:(?!badge|icon|kbd)(\\w[\\w-]*)\\[([^\\]]*)\\](\\{[^}]*\\})?/g, '$2')\n .replace(/:(?!badge|icon|kbd)(\\w[\\w-]*)(\\{[^}]*\\})/g, '')\n\n const tokens: InlineToken[] = []\n // Order matters: math (`$\\u2026$`) before italic (so `$x$` doesn't match\n // `$ \\u2026 $` as italic-with-dollars); inline MDC first; mentions before\n // plain `[\\u2026]` links; wikilinks before plain brackets; strikethrough;\n // bold before italic.\n const re = /\\$([^$\\n]+?)\\$|@\\[([^\\]]+?)\\]\\(user:([^)]+?)\\)|:badge\\[([^\\]]*)\\](\\{[^}]*\\})?|:icon\\{([^}]*)\\}|:kbd\\{([^}]*)\\}|\\[\\[([0-9a-fA-F-]{36})(?:\\|([^\\]]+?))?\\]\\]|~~(.+?)~~|\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|_(.+?)_|`(.+?)`|\\[(.+?)\\]\\((.+?)\\)/g\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n while ((match = re.exec(stripped)) !== null) {\n if (match.index > lastIndex) {\n tokens.push({ text: stripped.slice(lastIndex, match.index) })\n }\n if (match[1] !== undefined) {\n // $expression$ \\u2014 inline math atom\n tokens.push({ text: match[1], attrs: { mathInline: { expression: match[1] } } })\n } else if (match[2] !== undefined && match[3] !== undefined) {\n // @[label](user:uuid) \\u2014 mention atom\n tokens.push({ text: match[2], attrs: { mention: { userId: match[3], label: match[2] } } })\n } else if (match[4] !== undefined) {\n // :badge[text]{props}\n const badgeProps = parseMdcProps(match[5])\n tokens.push({ text: match[4] || 'Badge', attrs: { badge: { label: match[4] || 'Badge', color: badgeProps['color'] || 'neutral', variant: badgeProps['variant'] || 'subtle' } } })\n } else if (match[6] !== undefined) {\n // :icon{name=\"...\"}\n const iconProps = parseMdcProps(`{${match[6]}}`)\n tokens.push({ text: '\\u200B', attrs: { proseIcon: { name: iconProps['name'] || 'i-lucide-star' } } })\n } else if (match[7] !== undefined) {\n // :kbd{value=\"...\"}\n const kbdProps = parseMdcProps(`{${match[7]}}`)\n tokens.push({ text: kbdProps['value'] || '', attrs: { kbd: { value: kbdProps['value'] || '' } } })\n } else if (match[8] !== undefined) {\n // [[uuid]] or [[uuid|label]] \\u2014 inline doc link atom. The docId\n // is the canonical anchor; the label is display-only. The\n // serialiser may regenerate the label from a live doc registry\n // (see SPEC.md \\u00A76); when no resolver is supplied, the parser's\n // stored display text is reused on emit.\n const docId = match[8]\n const label = match[9] ?? docId\n tokens.push({ text: label, attrs: { docLink: { docId } } })\n } else if (match[10] !== undefined) {\n pushNested(tokens, match[10], { strike: true })\n } else if (match[11] !== undefined) {\n pushNested(tokens, match[11], { bold: true })\n } else if (match[12] !== undefined) {\n pushNested(tokens, match[12], { italic: true })\n } else if (match[13] !== undefined) {\n pushNested(tokens, match[13], { italic: true })\n } else if (match[14] !== undefined) {\n tokens.push({ text: match[14], attrs: { code: true } })\n } else if (match[15] !== undefined && match[16] !== undefined) {\n tokens.push({ text: match[15], attrs: { link: { href: match[16] } } })\n }\n lastIndex = match.index + match[0].length\n }\n\n if (lastIndex < stripped.length) {\n tokens.push({ text: stripped.slice(lastIndex) })\n }\n return tokens.filter(t => t.text.length > 0)\n}\n\n// ── Block-level parser ───────────────────────────────────────────────────────\n\ninterface TaskItem {\n text: string\n checked: boolean\n}\n\ninterface ListItemBlock {\n text: string\n innerBlocks?: Block[]\n checked?: boolean\n}\n\ntype Block\n = | { type: 'heading', level: number, text: string }\n | { type: 'paragraph', text: string }\n | { type: 'bulletList', items: ListItemBlock[] }\n | { type: 'orderedList', items: ListItemBlock[] }\n | { type: 'taskList', items: ListItemBlock[] }\n | { type: 'codeBlock', lang: string, code: string }\n | { type: 'blockquote', lines: string[] }\n | { type: 'table', headerRow: string[], dataRows: string[][] }\n | { type: 'hr' }\n | { type: 'callout', calloutType: string, innerBlocks: Block[] }\n | { type: 'collapsible', label: string, open: boolean, innerBlocks: Block[] }\n | { type: 'steps', innerBlocks: Block[] }\n | { type: 'card', title: string, icon: string, to: string, innerBlocks: Block[] }\n | { type: 'cardGroup', cards: Block[] }\n | { type: 'codeCollapse', codeBlocks: Block[] }\n | { type: 'codeGroup', codeBlocks: Block[] }\n | { type: 'codePreview', innerBlocks: Block[], codeBlocks: Block[] }\n | { type: 'codeTree', files: string }\n | { type: 'accordion', items: { label: string, icon: string, innerBlocks: Block[] }[] }\n | { type: 'tabs', items: { label: string, icon: string, innerBlocks: Block[] }[] }\n | { type: 'field', name: string, fieldType: string, required: boolean, innerBlocks: Block[] }\n | { type: 'fieldGroup', fields: Block[] }\n | { type: 'image', src: string, alt: string, width?: string, height?: string }\n | { type: 'docEmbed', docId: string, label: string, props: Record<string, string> }\n | { type: 'mathBlock', expression: string }\n | { type: 'fileBlock', src: string, mime: string, uploadId: string, filename: string }\n\nfunction parseTableRow(line: string): string[] {\n const parts = line.split('|')\n // Remove the first and last (empty from leading/trailing |) and trim each\n return parts.slice(1, parts.length - 1).map(c => c.trim())\n}\n\nfunction isTableSeparator(line: string): boolean {\n return /^\\|[\\s|:-]+\\|$/.test(line.trim())\n}\n\n/** Extract fenced code blocks from MDC #code slot lines. */\nfunction extractFencedCode(lines: string[]): Block[] {\n const result: Block[] = []\n let i = 0\n while (i < lines.length) {\n const line = lines[i]!\n // Match opening fence (```, ````, etc.)\n const fenceMatch = line.match(/^(`{3,})(\\w*)/)\n if (fenceMatch) {\n const fence = fenceMatch[1]!\n const lang = fenceMatch[2] ?? ''\n const codeLines: string[] = []\n i++\n while (i < lines.length && !lines[i]!.startsWith(fence)) {\n codeLines.push(lines[i]!)\n i++\n }\n i++ // skip closing fence\n result.push({ type: 'codeBlock', lang, code: codeLines.join('\\n') })\n continue\n }\n i++\n }\n return result\n}\n\n/** Extract key=\"value\" pairs from MDC prop syntax `{key=\"value\" other=\"x\"}` */\nfunction parseMdcProps(propsStr: string | undefined): Record<string, string> {\n if (!propsStr) return {}\n const result: Record<string, string> = {}\n // Drop the wrapping `{ … }` if present.\n let s = propsStr.trim()\n if (s.startsWith('{') && s.endsWith('}')) s = s.slice(1, -1)\n\n // Three accepted shapes per SPEC.md §5:\n // key=\"value\" (quoted)\n // key=value (bare, no whitespace)\n // key (boolean shorthand → \"true\")\n const re = /(\\w[\\w-]*)(?:=(?:\"([^\"]*)\"|([^\\s\"}]+)))?/g\n let m: RegExpExecArray | null\n while ((m = re.exec(s)) !== null) {\n const key = m[1]!\n if (m[2] !== undefined) result[key] = m[2]\n else if (m[3] !== undefined) result[key] = m[3]\n else result[key] = 'true'\n }\n return result\n}\n\n/** Parse named child MDC blocks from inner lines (e.g. #item for accordion, #tab for tabs) */\nfunction parseMdcChildren(innerLines: string[], slotPrefix: string): { label: string, icon: string, innerBlocks: Block[] }[] {\n const items: { label: string, icon: string, lines: string[] }[] = []\n let current: { label: string, icon: string, lines: string[] } | null = null\n const slotRe = new RegExp(`^#${slotPrefix}(\\\\{[^}]*\\\\})?\\\\s*$`)\n\n for (const line of innerLines) {\n const slotMatch = line.match(slotRe)\n if (slotMatch) {\n if (current) items.push(current)\n const props = parseMdcProps(slotMatch[1])\n current = { label: props['label'] || props['title'] || `Item ${items.length + 1}`, icon: props['icon'] || '', lines: [] }\n continue\n }\n if (current) {\n current.lines.push(line)\n } else {\n // Content before first slot — treat as first unnamed item\n if (!items.length && !current) {\n current = { label: `Item 1`, icon: '', lines: [line] }\n }\n }\n }\n if (current) items.push(current)\n\n return items.map(item => ({\n label: item.label,\n icon: item.icon,\n innerBlocks: parseBlocks(item.lines.join('\\n'))\n }))\n}\n\nconst TASK_RE = /^[-*+]\\s+\\[([ xX])\\]\\s+(.*)/\n\n/**\n * Consume a list (bullet / ordered / task) starting at `start`. Indented\n * continuation lines and nested lists are captured into each item's\n * `innerBlocks` so the parse → serialise → parse cycle preserves tree\n * structure instead of flattening nested lists onto a single line.\n *\n * `indent` is the column of the item marker for the current list. A\n * nested list starts ≥2 columns deeper. Lines with less indent than\n * `indent` belong to the outer block and stop consumption.\n */\nfunction consumeList(\n lines: string[],\n start: number,\n indent: number,\n kind: 'bullet' | 'ordered' | 'task',\n): { items: ListItemBlock[], next: number } {\n const items: ListItemBlock[] = []\n let i = start\n while (i < lines.length) {\n const line = lines[i]!\n if (line.trim() === '') {\n // Blank line — peek ahead: if the next non-blank line still\n // belongs to this list, treat the blank as an inter-item\n // separator. Otherwise terminate.\n let j = i + 1\n while (j < lines.length && lines[j]!.trim() === '') j++\n if (j >= lines.length) break\n const lookahead = lines[j]!\n if (leadingSpaces(lookahead) < indent) break\n if (!matchMarker(lookahead.slice(indent), kind)) break\n i = j\n continue\n }\n const leading = leadingSpaces(line)\n if (leading < indent) break\n if (leading > indent) break // belongs to a nested list opened by the previous item\n const deindented = line.slice(indent)\n const m = matchMarker(deindented, kind)\n if (!m) break\n\n const item: ListItemBlock = { text: m.text }\n if (kind === 'task') item.checked = m.checked\n i++\n\n // Consume continuation: lines indented deeper than `indent`.\n const contLines: string[] = []\n let contMinIndent = Infinity\n while (i < lines.length) {\n const next = lines[i]!\n if (next.trim() === '') {\n // Blank inside a continuation block — could be part of the\n // continuation if the next non-blank is still indented. Peek.\n let k = i + 1\n while (k < lines.length && lines[k]!.trim() === '') k++\n if (k >= lines.length) break\n const peekIndent = leadingSpaces(lines[k]!)\n if (peekIndent <= indent) break\n // Carry forward the blank line as a paragraph separator.\n contLines.push('')\n i++\n continue\n }\n const nextIndent = leadingSpaces(next)\n if (nextIndent <= indent) break\n if (nextIndent < contMinIndent) contMinIndent = nextIndent\n contLines.push(next)\n i++\n }\n if (contLines.length > 0) {\n // De-indent the whole continuation block by its common minimum\n // indent (not a fixed `indent + 2`): CommonMark nests 3 columns\n // under `1. ` markers, so clamping at 2 left a 1-space residue\n // that parseBlocks read as paragraph text — merging nested list\n // items onto a single line. Stripping the common indent keeps\n // relative structure for deeper levels and lands the first nested\n // marker at column 0, where parseBlocks recognises it. Canonical\n // wire-form input (exactly `indent + 2`) strips identically.\n const deindentBy = contMinIndent === Infinity ? 0 : contMinIndent\n item.innerBlocks = parseBlocks(\n contLines.map(l => l.slice(deindentBy)).join('\\n')\n )\n }\n items.push(item)\n }\n return { items, next: i }\n}\n\nfunction leadingSpaces(s: string): number {\n let n = 0\n while (n < s.length && s[n] === ' ') n++\n return n\n}\n\nfunction matchMarker(\n s: string,\n kind: 'bullet' | 'ordered' | 'task',\n): { text: string, checked: boolean } | null {\n if (kind === 'task') {\n const m = s.match(TASK_RE)\n if (!m) return null\n return { text: m[2]!, checked: m[1]!.toLowerCase() === 'x' }\n }\n if (kind === 'bullet') {\n if (TASK_RE.test(s)) return null\n const m = s.match(/^[-*+]\\s+(.*)$/)\n if (!m) return null\n return { text: m[1]!, checked: false }\n }\n // ordered\n const m = s.match(/^\\d+\\.\\s+(.*)$/)\n if (!m) return null\n return { text: m[1]!, checked: false }\n}\n\nfunction parseBlocks(markdown: string): Block[] {\n // Strip top-level MDX import/export lines (only before the first content block).\n // We must NOT strip `export default ...` etc. inside fenced code blocks.\n const rawLines = markdown.split('\\n')\n let firstContentLine = 0\n while (firstContentLine < rawLines.length) {\n const l = rawLines[firstContentLine]!\n if (l.trim() === '' || /^import\\s/.test(l) || /^export\\s/.test(l)) {\n firstContentLine++\n } else {\n break\n }\n }\n const stripped = rawLines.slice(firstContentLine).join('\\n')\n\n const blocks: Block[] = []\n const lines = stripped.split('\\n')\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]!\n\n // Fenced code block (supports variable-length fences: ```, ````, etc.)\n const fenceBlockMatch = line.match(/^(`{3,})(.*)$/)\n if (fenceBlockMatch) {\n const fence = fenceBlockMatch[1]!\n const lang = fenceBlockMatch[2]!.trim()\n .replace(/\\{[^}]*\\}$/, '') // strip highlight annotations like {4-5}\n .replace(/\\s*\\[.*\\]$/, '') // strip filename hints like [nuxt.config.ts]\n .trim()\n const codeLines: string[] = []\n i++\n while (i < lines.length && !lines[i]!.startsWith(fence)) {\n codeLines.push(lines[i]!)\n i++\n }\n i++ // skip closing fence\n const code = codeLines.join('\\n')\n if (lang === 'math') {\n // ```math … ``` — block math atom (SPEC.md §6).\n blocks.push({ type: 'mathBlock', expression: code })\n }\n else {\n blocks.push({ type: 'codeBlock', lang, code })\n }\n continue\n }\n\n // Heading\n const headingMatch = line.match(/^(#{1,6})\\s+(.*)/)\n if (headingMatch) {\n blocks.push({ type: 'heading', level: headingMatch[1]!.length, text: headingMatch[2]!.trim() })\n i++\n continue\n }\n\n // Horizontal rule\n if (/^[-*_]{3,}\\s*$/.test(line)) {\n blocks.push({ type: 'hr' })\n i++\n continue\n }\n\n // Doc embed: ![[uuid|label]]{collapsed tall seamless} — block-level,\n // must be on its own line. UUID is required (the bracket syntax\n // without one is reserved for inline doc-link).\n const embedMatch = line.match(/^!\\[\\[([0-9a-fA-F-]{36})(?:\\|([^\\]]+))?\\]\\](\\{[^}]*\\})?\\s*$/)\n if (embedMatch) {\n const docId = embedMatch[1]!\n const label = embedMatch[2] ?? ''\n const props = parseMdcProps(embedMatch[3])\n blocks.push({ type: 'docEmbed', docId, label, props })\n i++\n continue\n }\n\n // Image: ![alt](src){attrs} — must be on its own line\n const imgMatch = line.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)(\\{[^}]*\\})?\\s*$/)\n if (imgMatch) {\n const alt = imgMatch[1] ?? ''\n const src = imgMatch[2] ?? ''\n const attrs = parseMdcProps(imgMatch[3])\n blocks.push({ type: 'image', src, alt, width: attrs['width'], height: attrs['height'] })\n i++\n continue\n }\n\n // Blockquote. Match any line that opens with `>` (CommonMark allows the\n // space after the marker to be omitted, e.g. `>50 comments`). The paragraph\n // collector below treats EVERY `>`-leading line as a block start, so this\n // branch must claim all of them — otherwise a `>x` line matches no branch\n // and the loop spins without advancing `i` (silent infinite hang).\n if (line.startsWith('>')) {\n const bqLines: string[] = []\n while (i < lines.length && lines[i]!.startsWith('>')) {\n bqLines.push(lines[i]!.replace(/^>\\s?/, ''))\n i++\n }\n blocks.push({ type: 'blockquote', lines: bqLines })\n continue\n }\n\n // Table — detect by leading pipe\n if (/^\\s*\\|/.test(line)) {\n const tableLines: string[] = []\n while (i < lines.length && /^\\s*\\|/.test(lines[i]!)) {\n tableLines.push(lines[i]!)\n i++\n }\n // Need at least: header row, separator row\n if (tableLines.length >= 2 && isTableSeparator(tableLines[1]!)) {\n const headerRow = parseTableRow(tableLines[0]!)\n const dataRows = tableLines.slice(2)\n .filter(l => !isTableSeparator(l))\n .map(parseTableRow)\n blocks.push({ type: 'table', headerRow, dataRows })\n } else {\n // Couldn't parse as table — emit as paragraphs\n for (const l of tableLines) blocks.push({ type: 'paragraph', text: l })\n }\n continue\n }\n\n // MDC atom block (single-colon, no body): `:name{props}` on its\n // own line. Currently recognised: `:file{…}` (fileBlock per\n // SPEC.md §7). Other atom blocks (`:video{…}`, `:embed{…}`, etc.)\n // are reserved for later workstreams.\n const atomMatch = line.match(/^:(\\w[\\w-]*)(\\{[^}]*\\})?\\s*$/)\n if (atomMatch && atomMatch[1] === 'file') {\n const props = parseMdcProps(atomMatch[2])\n const uploadId = props['upload-id'] ?? props['uploadId'] ?? ''\n const filename = props['filename'] ?? ''\n const mime = props['mime'] ?? ''\n const src = props['src'] ?? (uploadId && filename\n ? `.abracadabra/files/${uploadId}-${filename}`\n : '')\n blocks.push({ type: 'fileBlock', src, mime, uploadId, filename })\n i++\n continue\n }\n\n // MDC component block (::component-name ... ::)\n // Allow optional leading whitespace so indented nested blocks are recognised\n const MDC_OPEN = /^\\s*(:{2,})(\\w[\\w-]*)(\\{[^}]*\\})?\\s*$/\n if (MDC_OPEN.test(line)) {\n const colons = line.match(/^\\s*(:+)/)?.[1]?.length ?? 2\n const componentName = line.match(/^\\s*:{2,}(\\w[\\w-]*)/)?.[1] ?? ''\n const innerLines: string[] = []\n i++\n // Collect inner lines, but skip over fenced code blocks so that\n // `::` inside ```...``` or ````...```` doesn't close the MDC block\n while (i < lines.length) {\n const l = lines[i]!\n // Closing tag: same colon count, possibly indented\n if (new RegExp(`^\\\\s*:{${colons}}\\\\s*$`).test(l)) { i++; break }\n // If we hit a fenced code block, consume it entirely\n const innerFence = l.match(/^(\\s*`{3,})/)\n if (innerFence) {\n const fenceStr = innerFence[1]!.trimStart()\n innerLines.push(l)\n i++\n while (i < lines.length && !lines[i]!.trimStart().startsWith(fenceStr)) {\n innerLines.push(lines[i]!)\n i++\n }\n if (i < lines.length) { innerLines.push(lines[i]!); i++ } // push closing fence\n continue\n }\n innerLines.push(l)\n i++\n }\n\n // Strip common leading indentation from inner lines\n const nonBlank = innerLines.filter(l => l.trim().length > 0)\n if (nonBlank.length) {\n const minIndent = Math.min(...nonBlank.map(l => l.match(/^(\\s*)/)?.[1]?.length ?? 0))\n if (minIndent > 0) {\n for (let j = 0; j < innerLines.length; j++) {\n innerLines[j] = innerLines[j]!.slice(Math.min(minIndent, innerLines[j]!.length))\n }\n }\n }\n\n // Strip inline frontmatter props (---...---)\n let contentStart = 0\n if (innerLines[0]?.trim() === '---') {\n const fmEnd = innerLines.findIndex((l, idx) => idx > 0 && l.trim() === '---')\n if (fmEnd !== -1) contentStart = fmEnd + 1\n }\n const contentLines = innerLines.slice(contentStart)\n\n // Split into named slots: collect default slot and #code slot separately\n const defaultSlotLines: string[] = []\n const codeSlotLines: string[] = []\n let currentSlot: 'default' | 'code' | 'other' = 'default'\n for (const l of contentLines) {\n if (/^#code\\s*$/.test(l)) { currentSlot = 'code'; continue }\n if (/^#\\w+/.test(l) && !/^#{2,}\\s/.test(l)) { currentSlot = 'other'; continue }\n if (currentSlot === 'default') defaultSlotLines.push(l)\n else if (currentSlot === 'code') codeSlotLines.push(l)\n }\n const innerBlocks = parseBlocks(defaultSlotLines.join('\\n'))\n\n // Extract fenced code from #code slot and add as code blocks\n const codeBlocks = extractFencedCode(codeSlotLines)\n\n const CALLOUT_NAMES = new Set(['tip', 'note', 'info', 'warning', 'caution', 'danger', 'callout', 'alert'])\n if (CALLOUT_NAMES.has(componentName.toLowerCase())) {\n blocks.push({ type: 'callout', calloutType: componentName.toLowerCase(), innerBlocks })\n } else {\n const mdcProps = parseMdcProps(line.match(MDC_OPEN)?.[3])\n const lc = componentName.toLowerCase()\n\n if (lc === 'collapsible') {\n blocks.push({ type: 'collapsible', label: mdcProps['label'] || 'Details', open: mdcProps['open'] === 'true', innerBlocks })\n } else if (lc === 'steps') {\n blocks.push({ type: 'steps', innerBlocks })\n } else if (lc === 'card') {\n blocks.push({ type: 'card', title: mdcProps['title'] || '', icon: mdcProps['icon'] || '', to: mdcProps['to'] || '', innerBlocks })\n } else if (lc === 'card-group') {\n // Each nested ::card inside card-group is already parsed as inner blocks\n const cards = innerBlocks.filter(b => b.type === 'card')\n if (cards.length) {\n blocks.push({ type: 'cardGroup', cards })\n } else {\n blocks.push(...innerBlocks)\n }\n } else if (lc === 'code-collapse') {\n blocks.push({ type: 'codeCollapse', codeBlocks: codeBlocks.length ? codeBlocks : innerBlocks.filter(b => b.type === 'codeBlock') })\n } else if (lc === 'code-group') {\n const allCode = [...innerBlocks.filter(b => b.type === 'codeBlock'), ...codeBlocks]\n blocks.push({ type: 'codeGroup', codeBlocks: allCode })\n } else if (lc === 'code-preview') {\n blocks.push({ type: 'codePreview', innerBlocks, codeBlocks })\n } else if (lc === 'code-tree') {\n blocks.push({ type: 'codeTree', files: mdcProps['files'] || '[]' })\n } else if (lc === 'accordion') {\n const items = parseMdcChildren(contentLines, 'item')\n if (items.length) {\n blocks.push({ type: 'accordion', items })\n } else {\n blocks.push({ type: 'accordion', items: [{ label: 'Item 1', icon: '', innerBlocks }] })\n }\n } else if (lc === 'tabs') {\n const items = parseMdcChildren(contentLines, 'tab')\n if (items.length) {\n blocks.push({ type: 'tabs', items })\n } else {\n blocks.push({ type: 'tabs', items: [{ label: 'Tab 1', icon: '', innerBlocks }] })\n }\n } else if (lc === 'field') {\n blocks.push({ type: 'field', name: mdcProps['name'] || '', fieldType: mdcProps['type'] || 'string', required: mdcProps['required'] === 'true', innerBlocks })\n } else if (lc === 'field-group') {\n const fields = innerBlocks.filter(b => b.type === 'field')\n if (fields.length) {\n blocks.push({ type: 'fieldGroup', fields })\n } else {\n blocks.push(...innerBlocks)\n }\n } else {\n // Unknown component — inline the content\n blocks.push(...innerBlocks)\n blocks.push(...codeBlocks)\n }\n }\n continue\n }\n\n // Task list (must check before bullet list — `- [x]` starts the same way)\n if (TASK_RE.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'task')\n i = next\n blocks.push({ type: 'taskList', items })\n continue\n }\n\n // Bullet list\n if (/^[-*+]\\s+/.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'bullet')\n if (items.length > 0) {\n i = next\n blocks.push({ type: 'bulletList', items })\n continue\n }\n }\n\n // Ordered list\n if (/^\\d+\\.\\s+/.test(line)) {\n const { items, next } = consumeList(lines, i, 0, 'ordered')\n if (items.length > 0) {\n i = next\n blocks.push({ type: 'orderedList', items })\n continue\n }\n }\n\n // Blank line\n if (line.trim() === '') {\n i++\n continue\n }\n\n // Paragraph — consecutive non-special lines\n const paraLines: string[] = []\n while (\n i < lines.length\n && lines[i]!.trim() !== ''\n && !/^(#{1,6}\\s|[-*+]\\s|\\d+\\.\\s|>|`{3,}|\\s*\\||[-*_]{3,}\\s*$|\\s*:{2,}\\w)/.test(lines[i]!)\n ) {\n paraLines.push(lines[i]!)\n i++\n }\n if (paraLines.length) {\n blocks.push({ type: 'paragraph', text: paraLines.join(' ') })\n } else {\n // No branch claimed this line and the paragraph collector rejected it too\n // (its guard excludes block-marker leads like `>`). Without forcing\n // progress here `i` never advances and parseBlocks hangs forever. Emit the\n // stray line as a paragraph so it survives the round-trip, and step past it.\n blocks.push({ type: 'paragraph', text: line })\n i++\n }\n }\n\n return blocks\n}\n\n// ── Y.js content population ──────────────────────────────────────────────────\n//\n// IMPORTANT — attach-before-fill ordering:\n//\n// Y.XmlText.insert() is only deterministically ordered when the text node is\n// already attached to a Y.Doc (so it can use the doc's logical clock).\n// Inserting text into a standalone Y.XmlText gives every operation clock-0,\n// which causes the YATA algorithm to produce reversed or scrambled text.\n//\n// Rule: attach container to doc → attach Y.XmlText to container → insert text.\n\n/**\n * Insert formatted inline tokens into an already-attached Y.XmlElement.\n * Creates one Y.XmlText per token (attach first, fill second).\n */\nfunction fillTextInto(el: Y.XmlElement, tokens: InlineToken[]): void {\n const filtered = tokens.filter(t => t.text.length > 0)\n if (!filtered.length) return\n\n // Build the child skeleton. A docLink is an inline ATOM NODE, not a text\n // mark: it must be a Y.XmlElement so the y-prosemirror binding materializes\n // it as a `docLink` node (its label is resolved live from the doc tree by\n // the renderer, never stored). Every other token is a Y.XmlText run.\n // Attach all children in one batch first (attach-before-fill), then fill.\n const children: (Y.XmlText | Y.XmlElement)[] = filtered.map((tok) => {\n const dl = tok.attrs?.docLink as { docId?: string } | undefined\n return dl?.docId ? new Y.XmlElement('docLink') : new Y.XmlText()\n })\n el.insert(0, children)\n\n // Fill only after attachment — el is already attached to the doc.\n filtered.forEach((tok, i) => {\n const node = children[i]!\n if (node instanceof Y.XmlElement) {\n const dl = tok.attrs!.docLink as { docId: string }\n node.setAttribute('docId', dl.docId)\n return\n }\n if (tok.attrs) {\n node.insert(0, tok.text, tok.attrs as Record<string, boolean | object>)\n } else {\n node.insert(0, tok.text)\n }\n })\n}\n\nfunction blockElName(b: Block): string {\n switch (b.type) {\n case 'heading': return 'heading'\n case 'paragraph': return 'paragraph'\n case 'bulletList': return 'bulletList'\n case 'orderedList': return 'orderedList'\n case 'taskList': return 'taskList'\n case 'codeBlock': return 'codeBlock'\n case 'blockquote': return 'blockquote'\n case 'table': return 'table'\n case 'hr': return 'horizontalRule'\n case 'callout': return 'callout'\n case 'collapsible': return 'collapsible'\n case 'steps': return 'steps'\n case 'card': return 'card'\n case 'cardGroup': return 'cardGroup'\n case 'codeCollapse': return 'codeCollapse'\n case 'codeGroup': return 'codeGroup'\n case 'codePreview': return 'codePreview'\n case 'codeTree': return 'codeTree'\n case 'accordion': return 'accordion'\n case 'tabs': return 'tabs'\n case 'field': return 'field'\n case 'fieldGroup': return 'fieldGroup'\n case 'image': return 'image'\n case 'docEmbed': return 'docEmbed'\n case 'mathBlock': return 'mathBlock'\n case 'fileBlock': return 'fileBlock'\n }\n}\n\nfunction populateListItemChildren(\n itemEl: Y.XmlElement,\n item: ListItemBlock,\n _itemKind: 'listItem' | 'taskItem',\n): void {\n // Always start with a paragraph carrying the item's inline text.\n const paraEl = new Y.XmlElement('paragraph')\n itemEl.insert(itemEl.length, [paraEl])\n fillTextInto(paraEl, parseInline(item.text))\n\n // Nested blocks (sub-lists, paragraphs, code, etc.) follow.\n if (!item.innerBlocks?.length) return\n const innerEls = item.innerBlocks.map(b => new Y.XmlElement(blockElName(b)))\n itemEl.insert(itemEl.length, innerEls)\n item.innerBlocks.forEach((b, i) => fillBlock(innerEls[i]!, b))\n}\n\nfunction fillBlock(el: Y.XmlElement, block: Block): void {\n switch (block.type) {\n case 'heading': {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('level', block.level as any)\n fillTextInto(el, parseInline(block.text))\n break\n }\n case 'paragraph': {\n fillTextInto(el, parseInline(block.text))\n break\n }\n case 'bulletList':\n case 'orderedList': {\n const listItemEls = block.items.map(() => new Y.XmlElement('listItem'))\n el.insert(0, listItemEls)\n block.items.forEach((item, i) => {\n populateListItemChildren(listItemEls[i]!, item, 'listItem')\n })\n break\n }\n case 'taskList': {\n const taskItemEls = block.items.map(() => new Y.XmlElement('taskItem'))\n el.insert(0, taskItemEls)\n block.items.forEach((item, i) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n taskItemEls[i]!.setAttribute('checked', !!item.checked as any)\n populateListItemChildren(taskItemEls[i]!, item, 'taskItem')\n })\n break\n }\n case 'codeBlock': {\n if (block.lang) el.setAttribute('language', block.lang)\n const xt = new Y.XmlText()\n el.insert(0, [xt]) // attach xt to el (already attached)\n xt.insert(0, block.code)\n break\n }\n case 'blockquote': {\n const paraEls = block.lines.map(() => new Y.XmlElement('paragraph'))\n el.insert(0, paraEls)\n block.lines.forEach((line, i) => fillTextInto(paraEls[i]!, parseInline(line)))\n break\n }\n case 'table': {\n const headerRowEl = new Y.XmlElement('tableRow')\n const dataRowEls = block.dataRows.map(() => new Y.XmlElement('tableRow'))\n el.insert(0, [headerRowEl, ...dataRowEls])\n\n // Header cells\n const headerCellEls = block.headerRow.map(() => new Y.XmlElement('tableHeader'))\n headerRowEl.insert(0, headerCellEls)\n block.headerRow.forEach((cellText, i) => {\n const paraEl = new Y.XmlElement('paragraph')\n headerCellEls[i]!.insert(0, [paraEl])\n fillTextInto(paraEl, parseInline(cellText))\n })\n\n // Data rows\n block.dataRows.forEach((row, ri) => {\n const cellEls = row.map(() => new Y.XmlElement('tableCell'))\n dataRowEls[ri]!.insert(0, cellEls)\n row.forEach((cellText, ci) => {\n const paraEl = new Y.XmlElement('paragraph')\n cellEls[ci]!.insert(0, [paraEl])\n fillTextInto(paraEl, parseInline(cellText))\n })\n })\n break\n }\n case 'hr': break // horizontalRule has no content\n case 'callout': {\n el.setAttribute('type', block.calloutType)\n if (!block.innerBlocks.length) {\n const paraEl = new Y.XmlElement('paragraph')\n el.insert(0, [paraEl])\n break\n }\n const innerEls = block.innerBlocks.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n block.innerBlocks.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'collapsible': {\n el.setAttribute('label', block.label)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('open', block.open as any)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'steps': {\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'card': {\n if (block.title) el.setAttribute('title', block.title)\n if (block.icon) el.setAttribute('icon', block.icon)\n if (block.to) el.setAttribute('to', block.to)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'cardGroup': {\n const cardEls = block.cards.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, cardEls)\n block.cards.forEach((b, i) => fillBlock(cardEls[i]!, b))\n break\n }\n case 'codeCollapse': {\n const codes = block.codeBlocks.length ? block.codeBlocks : [{ type: 'codeBlock' as const, lang: '', code: '' }]\n // Only insert the first code block (content model is singular codeBlock)\n const codeEl = new Y.XmlElement('codeBlock')\n el.insert(0, [codeEl])\n fillBlock(codeEl, codes[0]!)\n break\n }\n case 'codeGroup': {\n const codes = block.codeBlocks.length ? block.codeBlocks : [{ type: 'codeBlock' as const, lang: '', code: '' }]\n const codeEls = codes.map(() => new Y.XmlElement('codeBlock'))\n el.insert(0, codeEls)\n codes.forEach((b, i) => fillBlock(codeEls[i]!, b))\n break\n }\n case 'codePreview': {\n const all = [...block.innerBlocks, ...block.codeBlocks]\n const inner = all.length ? all : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'codeTree': {\n el.setAttribute('files', block.files)\n break\n }\n case 'accordion': {\n const itemEls = block.items.map(() => new Y.XmlElement('accordionItem'))\n el.insert(0, itemEls)\n block.items.forEach((item, i) => {\n itemEls[i]!.setAttribute('label', item.label)\n if (item.icon) itemEls[i]!.setAttribute('icon', item.icon)\n const inner = item.innerBlocks.length ? item.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const childEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n itemEls[i]!.insert(0, childEls)\n inner.forEach((b, ci) => fillBlock(childEls[ci]!, b))\n })\n break\n }\n case 'tabs': {\n const itemEls = block.items.map(() => new Y.XmlElement('tabsItem'))\n el.insert(0, itemEls)\n block.items.forEach((item, i) => {\n itemEls[i]!.setAttribute('label', item.label)\n if (item.icon) itemEls[i]!.setAttribute('icon', item.icon)\n const inner = item.innerBlocks.length ? item.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const childEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n itemEls[i]!.insert(0, childEls)\n inner.forEach((b, ci) => fillBlock(childEls[ci]!, b))\n })\n break\n }\n case 'field': {\n if (block.name) el.setAttribute('name', block.name)\n el.setAttribute('type', block.fieldType)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute('required', block.required as any)\n const inner = block.innerBlocks.length ? block.innerBlocks : [{ type: 'paragraph' as const, text: '' }]\n const innerEls = inner.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, innerEls)\n inner.forEach((b, i) => fillBlock(innerEls[i]!, b))\n break\n }\n case 'fieldGroup': {\n const fieldEls = block.fields.map(b => new Y.XmlElement(blockElName(b)))\n el.insert(0, fieldEls)\n block.fields.forEach((b, i) => fillBlock(fieldEls[i]!, b))\n break\n }\n case 'image': {\n el.setAttribute('src', block.src)\n if (block.alt) el.setAttribute('alt', block.alt)\n if (block.width) el.setAttribute('width', block.width)\n if (block.height) el.setAttribute('height', block.height)\n break\n }\n case 'docEmbed': {\n el.setAttribute('docId', block.docId)\n for (const flag of ['collapsed', 'tall', 'seamless']) {\n if (block.props[flag] === 'true' || block.props[flag] === '1') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute(flag, true as any)\n }\n }\n break\n }\n case 'mathBlock': {\n el.setAttribute('expression', block.expression)\n break\n }\n case 'fileBlock': {\n if (block.src) el.setAttribute('src', block.src)\n if (block.mime) el.setAttribute('mime', block.mime)\n if (block.uploadId) el.setAttribute('uploadId', block.uploadId)\n if (block.filename) el.setAttribute('filename', block.filename)\n break\n }\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Parses markdown text and writes the result into a Y.XmlFragment that\n * TipTap's Collaboration extension can read.\n *\n * Requires `fragment.doc` to be set (i.e. the fragment must already be\n * obtained from a live Y.Doc via `ydoc.getXmlFragment('default')`).\n *\n * @param fragment The target `Y.Doc.getXmlFragment('default')`\n * @param markdown Raw markdown string\n * @param fallbackTitle Used as the title when the markdown has no H1\n */\nexport function populateYDocFromMarkdown(\n fragment: Y.XmlFragment,\n markdown: string,\n fallbackTitle = 'Untitled'\n): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[markdownToYjs] fragment has no doc — skipping population')\n return\n }\n\n // Strip YAML frontmatter from the head of the input so its `---`\n // fences don't get reinterpreted as horizontal rules.\n const fm = parseFrontmatter(markdown)\n const blocks = parseBlocks(fm.body)\n\n let title = fallbackTitle\n // The title can live in three places: frontmatter, the first body H1,\n // or a filename-derived fallback. We track which so the serialiser\n // can round-trip into the same form. Body H1 wins over frontmatter\n // when both are present (frontmatter's title is typically a stale\n // copy of the body H1).\n let titleSource: 'h1' | 'frontmatter' | undefined\n if (fm.title !== undefined) {\n title = fm.title\n titleSource = 'frontmatter'\n }\n let contentBlocks = blocks\n const h1 = blocks.findIndex(b => b.type === 'heading' && b.level === 1)\n if (h1 !== -1) {\n title = (blocks[h1] as { type: 'heading', level: number, text: string }).text\n contentBlocks = blocks.filter((_, i) => i !== h1)\n titleSource = 'h1'\n }\n // For empty markdown we used to seed an empty paragraph so the\n // editor had something to focus. That bytes-pads the round-trip\n // back to \"\\n\\n\" — keep contentBlocks empty so the serialiser can\n // emit a clean empty file.\n\n ydoc.transact(() => {\n // ── Step 1: create empty skeleton elements ────────────────────────────\n const headerEl = new Y.XmlElement('documentHeader')\n const metaEl = new Y.XmlElement('documentMeta')\n const bodyEls: Y.XmlElement[] = contentBlocks.map((b) => {\n switch (b.type) {\n case 'heading': return new Y.XmlElement('heading')\n case 'paragraph': return new Y.XmlElement('paragraph')\n case 'bulletList': return new Y.XmlElement('bulletList')\n case 'orderedList': return new Y.XmlElement('orderedList')\n case 'taskList': return new Y.XmlElement('taskList')\n case 'codeBlock': return new Y.XmlElement('codeBlock')\n case 'blockquote': return new Y.XmlElement('blockquote')\n case 'table': return new Y.XmlElement('table')\n case 'hr': return new Y.XmlElement('horizontalRule')\n case 'callout': return new Y.XmlElement('callout')\n case 'collapsible': return new Y.XmlElement('collapsible')\n case 'steps': return new Y.XmlElement('steps')\n case 'card': return new Y.XmlElement('card')\n case 'cardGroup': return new Y.XmlElement('cardGroup')\n case 'codeCollapse': return new Y.XmlElement('codeCollapse')\n case 'codeGroup': return new Y.XmlElement('codeGroup')\n case 'codePreview': return new Y.XmlElement('codePreview')\n case 'codeTree': return new Y.XmlElement('codeTree')\n case 'accordion': return new Y.XmlElement('accordion')\n case 'tabs': return new Y.XmlElement('tabs')\n case 'field': return new Y.XmlElement('field')\n case 'fieldGroup': return new Y.XmlElement('fieldGroup')\n case 'image': return new Y.XmlElement('image')\n case 'docEmbed': return new Y.XmlElement('docEmbed')\n case 'mathBlock': return new Y.XmlElement('mathBlock')\n case 'fileBlock': return new Y.XmlElement('fileBlock')\n }\n })\n\n // ── Step 2: attach ALL skeleton elements to fragment in one shot ──────\n // After this line everything is connected to ydoc and subsequent ops\n // use the real doc clock — no more clock-0 scrambling.\n fragment.insert(0, [headerEl, metaEl, ...bodyEls])\n\n // ── Step 3: fill header title + record where it came from ─────────────\n if (titleSource) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n headerEl.setAttribute('titleSource', titleSource as any)\n }\n const headerXt = new Y.XmlText()\n headerEl.insert(0, [headerXt])\n headerXt.insert(0, title)\n\n // ── Step 4: stash parsed frontmatter meta on documentMeta ─────────────\n // Each universal-meta key becomes an attribute on documentMeta so\n // the serialiser can faithfully emit it back to frontmatter. Type\n // (page-type) is also stashed here under the well-known \"type\" key.\n for (const k of Object.keys(fm.meta)) {\n const v = (fm.meta as Record<string, unknown>)[k]\n if (v === undefined || v === null) continue\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metaEl.setAttribute(k, v as any)\n }\n if (fm.type) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metaEl.setAttribute('type', fm.type as any)\n }\n\n // ── Step 5: fill body blocks ──────────────────────────────────────────\n contentBlocks.forEach((block, i) => fillBlock(bodyEls[i]!, block))\n })\n}\n","import * as Y from 'yjs'\nimport type { DocPageMeta } from './types.ts'\nimport {\n UNIVERSAL_META_KEYS,\n UNIVERSAL_META_KEY_NAMES,\n type MetaValueType,\n} from './spec/universal-meta.ts'\n\n// ── Cross-yjs-copy node typing ───────────────────────────────────────────────\n//\n// The serializers must decide \"is this a Y.XmlText vs Y.XmlElement\"\n// without `instanceof`. A host that wires @abraca/dabra (file: dep) or\n// bundles us through Vite/esbuild dep-prebundling ends up with a SECOND\n// physical copy of yjs; nodes built by that copy are NOT `instanceof`\n// *our* Y.XmlText/Y.XmlElement, so every check silently fails and text\n// and inline atoms (docLink/mention) serialize to NOTHING. Duck-typed\n// predicates work regardless of which yjs constructed the node — the\n// same lesson as getTreeData's `instanceof Y.Map` fix. (`nodeName` is a\n// plain own-property; `toDelta` only exists on Y.XmlText.)\n// An element is anything carrying a string `nodeName` (paragraph,\n// heading, bulletList, AND inline atoms like docLink/mention — atoms\n// have no children but still have a nodeName). Mirrors the original\n// `instanceof Y.XmlElement` intent with NO extra constraint: requiring\n// `.toArray` wrongly excluded childless atom nodes → docLinks dropped.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction isXElem(n: any): n is Y.XmlElement {\n return !!n && typeof n.nodeName === 'string'\n}\n// Y.XmlText: no nodeName, has toDelta. (Y.XmlFragment has neither →\n// classified as neither, which is correct — it's only ever the root.)\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction isXText(n: any): n is Y.XmlText {\n return !!n && typeof n.nodeName !== 'string' && typeof n.toDelta === 'function'\n}\n\n// No fragment normalization is needed any more — the serializers are\n// duck-typed, so a foreign-yjs fragment serializes directly. Kept as an\n// identity so the public entry points don't need to change.\nfunction localizeFragment(fragment: Y.XmlFragment): Y.XmlFragment {\n return fragment\n}\n\n// ── Inline serialization ────────────────────────────────────────────────────\n\nfunction serializeDelta(delta: any[]): string {\n let result = ''\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n let text = op.insert as string\n const attrs = op.attributes ?? {}\n\n if (attrs.code) {\n result += `\\`${text}\\``\n continue\n }\n\n // Badge mark\n if (attrs.badge) {\n const b = attrs.badge as { label?: string, color?: string, variant?: string }\n const props: string[] = []\n if (b.color && b.color !== 'neutral') props.push(`color=\"${b.color}\"`)\n if (b.variant && b.variant !== 'subtle') props.push(`variant=\"${b.variant}\"`)\n result += `:badge[${b.label || text}]${props.length ? `{${props.join(' ')}}` : ''}`\n continue\n }\n\n // Prose icon mark\n if (attrs.proseIcon) {\n const icon = (attrs.proseIcon as { name?: string }).name || 'i-lucide-star'\n result += `:icon{name=\"${icon}\"}`\n continue\n }\n\n // Kbd mark\n if (attrs.kbd) {\n const value = (attrs.kbd as { value?: string }).value || text\n result += `:kbd{value=\"${value}\"}`\n continue\n }\n\n // docLink — inline doc reference. The label is the displayed text;\n // the docId is the canonical anchor. Per SPEC.md §6 the label may\n // be regenerated from a live registry, but the converter is pure —\n // we use the stored text. Consumers that need fresh labels should\n // rewrite them in the Y tree before serialising.\n if (attrs.docLink) {\n const docId = (attrs.docLink as { docId?: string }).docId\n if (docId) {\n result += text === docId ? `[[${docId}]]` : `[[${docId}|${text}]]`\n continue\n }\n }\n\n // mention — `@[label](user:uuid)`\n if (attrs.mention) {\n const { userId, label } = attrs.mention as { userId?: string, label?: string }\n if (userId) {\n result += `@[${label || text}](user:${userId})`\n continue\n }\n }\n\n // Inline math — `$expression$`\n if (attrs.mathInline) {\n const expr = (attrs.mathInline as { expression?: string }).expression ?? text\n result += `$${expr}$`\n continue\n }\n\n if (attrs.bold) text = `**${text}**`\n if (attrs.italic) text = `*${text}*`\n if (attrs.strike) text = `~~${text}~~`\n if (attrs.link) {\n const href = (attrs.link as { href?: string }).href ?? ''\n text = `[${text}](${href})`\n }\n\n result += text\n }\n return result\n}\n\nfunction serializeInline(el: Y.XmlElement | Y.XmlFragment): string {\n const parts: string[] = []\n for (const child of el.toArray()) {\n if (isXText(child)) {\n parts.push(serializeDelta(child.toDelta()))\n } else if (isXElem(child)) {\n if (child.nodeName === 'docLink') {\n // Inline doc-link atom node — bare wire form; label is tree-derived.\n const docId = child.getAttribute('docId') ?? ''\n parts.push(`[[${docId}]]`)\n } else {\n // Nested inline element — just get text\n parts.push(serializeInline(child))\n }\n }\n }\n return parts.join('')\n}\n\n// ── Block serialization ─────────────────────────────────────────────────────\n\nfunction serializeBlock(el: Y.XmlElement | Y.XmlText, indent = ''): string {\n if (isXText(el)) {\n return serializeDelta(el.toDelta())\n }\n\n const name = el.nodeName\n switch (name) {\n case 'documentHeader':\n case 'documentMeta':\n return '' // handled via frontmatter\n\n case 'heading': {\n const level = Number(el.getAttribute('level') ?? 2)\n const hashes = '#'.repeat(level)\n return `${hashes} ${serializeInline(el)}`\n }\n\n case 'paragraph':\n return serializeInline(el)\n\n case 'bulletList':\n return serializeListItems(el, 'bullet', indent)\n\n case 'orderedList':\n return serializeListItems(el, 'ordered', indent)\n\n case 'taskList':\n return serializeTaskList(el, indent)\n\n case 'codeBlock': {\n const lang = el.getAttribute('language') ?? ''\n const code = getCodeBlockText(el)\n // Empty body — single-newline form preserves the `\\`\\`\\`lang\\n\\`\\`\\``\n // wire form (no padding blank line).\n if (code === '') return `\\`\\`\\`${lang}\\n\\`\\`\\``\n return `\\`\\`\\`${lang}\\n${code}\\n\\`\\`\\``\n }\n\n case 'blockquote': {\n const lines: string[] = []\n for (const child of el.toArray()) {\n if (isXElem(child)) {\n const text = serializeBlock(child)\n for (const line of text.split('\\n')) {\n lines.push(`> ${line}`)\n }\n }\n }\n return lines.join('\\n')\n }\n\n case 'table':\n return serializeTable(el)\n\n case 'horizontalRule':\n return '---'\n\n case 'image': {\n const src = el.getAttribute('src') ?? ''\n const alt = el.getAttribute('alt') ?? ''\n const width = el.getAttribute('width')\n const height = el.getAttribute('height')\n const attrs: string[] = []\n // MDC convention is `{width=400 height=300}` — bare values, no\n // quotes — matching what the parser at the time accepts.\n if (width) attrs.push(`width=${width}`)\n if (height) attrs.push(`height=${height}`)\n return `![${alt}](${src})${attrs.length ? `{${attrs.join(' ')}}` : ''}`\n }\n\n case 'docEmbed': {\n const docId = el.getAttribute('docId') ?? ''\n const collapsed: unknown = el.getAttribute('collapsed')\n const tall: unknown = el.getAttribute('tall')\n const seamless: unknown = el.getAttribute('seamless')\n const flags: string[] = []\n if (collapsed === true || collapsed === 'true') flags.push('collapsed')\n if (tall === true || tall === 'true') flags.push('tall')\n if (seamless === true || seamless === 'true') flags.push('seamless')\n return `![[${docId}]]${flags.length ? `{${flags.join(' ')}}` : ''}`\n }\n\n case 'mathBlock': {\n const expr = el.getAttribute('expression') ?? ''\n return `\\`\\`\\`math\\n${expr}\\n\\`\\`\\``\n }\n\n case 'fileBlock': {\n // SPEC.md §7 wire form: `:file{src=… mime=… upload-id=… filename=…}`.\n // The sidecar binary lives under `.abracadabra/files/`; this tag\n // is purely a reference into that store + the manifest.\n const uploadId = el.getAttribute('uploadId') ?? ''\n const filename = el.getAttribute('filename') ?? ''\n const mime = el.getAttribute('mime') ?? ''\n const src = el.getAttribute('src') ?? (uploadId && filename\n ? `.abracadabra/files/${uploadId}-${filename}`\n : '')\n const props: string[] = []\n if (src) props.push(`src=\"${src}\"`)\n if (mime) props.push(`mime=\"${mime}\"`)\n if (uploadId) props.push(`upload-id=\"${uploadId}\"`)\n if (filename) props.push(`filename=\"${filename}\"`)\n return `:file{${props.join(' ')}}`\n }\n\n // MDC components\n case 'callout': {\n const type = el.getAttribute('type') ?? 'note'\n return `::${type}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'collapsible': {\n const label = el.getAttribute('label') ?? 'Details'\n const open: unknown = el.getAttribute('open')\n const props: string[] = [`label=\"${label}\"`]\n if (open === true || open === 'true') props.push('open=\"true\"')\n return `::collapsible{${props.join(' ')}}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'steps':\n return `::steps\\n${serializeChildren(el)}\\n::`\n\n case 'card': {\n const props: string[] = []\n const title = el.getAttribute('title')\n const icon = el.getAttribute('icon')\n const to = el.getAttribute('to')\n if (title) props.push(`title=\"${title}\"`)\n if (icon) props.push(`icon=\"${icon}\"`)\n if (to) props.push(`to=\"${to}\"`)\n return `::card${props.length ? `{${props.join(' ')}}` : ''}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'cardGroup': {\n const cards = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::card-group\\n${cards}\\n::`\n }\n\n case 'codeCollapse': {\n const code = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'codeBlock')\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::code-collapse\\n${code}\\n::`\n }\n\n case 'codeGroup': {\n const code = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'codeBlock')\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::code-group\\n${code}\\n::`\n }\n\n case 'codePreview': {\n const children = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n const nonCode = children.filter(c => c.nodeName !== 'codeBlock').map(c => serializeBlock(c)).join('\\n\\n')\n const code = children.filter(c => c.nodeName === 'codeBlock').map(c => serializeBlock(c)).join('\\n\\n')\n const parts = [nonCode]\n if (code) parts.push(`#code\\n${code}`)\n return `::code-preview\\n${parts.filter(Boolean).join('\\n\\n')}\\n::`\n }\n\n case 'codeTree': {\n const files = el.getAttribute('files') ?? '[]'\n return `::code-tree{files=\"${files}\"}\\n::`\n }\n\n case 'accordion':\n return serializeSlottedContainer(el, 'accordion', 'accordionItem', 'item')\n\n case 'tabs':\n return serializeSlottedContainer(el, 'tabs', 'tabsItem', 'tab')\n\n case 'field': {\n const fieldName = el.getAttribute('name') ?? ''\n const fieldType = el.getAttribute('type') ?? 'string'\n const required: unknown = el.getAttribute('required')\n const props = [`name=\"${fieldName}\"`, `type=\"${fieldType}\"`]\n if (required === true || required === 'true') props.push('required=\"true\"')\n return `::field{${props.join(' ')}}\\n${serializeChildren(el)}\\n::`\n }\n\n case 'fieldGroup': {\n const fields = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlock(c))\n .join('\\n\\n')\n return `::field-group\\n${fields}\\n::`\n }\n\n default:\n // Unknown node type — try to serialize children\n return serializeChildren(el)\n }\n}\n\nfunction serializeChildren(el: Y.XmlElement | Y.XmlFragment): string {\n const blocks: string[] = []\n for (const child of el.toArray()) {\n if (isXElem(child)) {\n const text = serializeBlock(child)\n if (text) blocks.push(text)\n } else if (isXText(child)) {\n const text = serializeDelta(child.toDelta())\n if (text) blocks.push(text)\n }\n }\n return blocks.join('\\n\\n')\n}\n\nfunction serializeListItems(el: Y.XmlElement, type: 'bullet' | 'ordered', indent: string): string {\n const lines: string[] = []\n let counter = 1\n for (const child of el.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'listItem') continue\n const prefix = type === 'bullet' ? '- ' : `${counter++}. `\n // A listItem may contain paragraphs and nested lists\n const subParts: Array<{ text: string, isList: boolean }> = []\n for (const sub of child.toArray()) {\n if (!(isXElem(sub))) continue\n if (sub.nodeName === 'bulletList') {\n subParts.push({ text: serializeListItems(sub, 'bullet', indent + ' '), isList: true })\n } else if (sub.nodeName === 'orderedList') {\n subParts.push({ text: serializeListItems(sub, 'ordered', indent + ' '), isList: true })\n } else {\n subParts.push({ text: serializeInline(sub), isList: false })\n }\n }\n lines.push(`${indent}${prefix}${subParts[0]?.text ?? ''}`)\n for (let i = 1; i < subParts.length; i++) {\n const part = subParts[i]!\n // Nested lists are already indented; plain-text continuation gets\n // the item's content indent so it stays inside the listItem on\n // re-parse instead of escaping as a sibling paragraph.\n lines.push(part.isList ? part.text : `${indent} ${part.text}`)\n }\n }\n return lines.join('\\n')\n}\n\nfunction serializeTaskList(el: Y.XmlElement, indent: string): string {\n const lines: string[] = []\n for (const child of el.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'taskItem') continue\n const checked: unknown = child.getAttribute('checked')\n const marker = (checked === true || checked === 'true') ? '[x]' : '[ ]'\n\n let header = ''\n const nestedParts: string[] = []\n for (const sub of child.toArray()) {\n if (!(isXElem(sub))) continue\n if (sub.nodeName === 'paragraph' && header === '') {\n header = serializeInline(sub)\n }\n else if (sub.nodeName === 'bulletList') {\n nestedParts.push(serializeListItems(sub, 'bullet', indent + ' '))\n }\n else if (sub.nodeName === 'orderedList') {\n nestedParts.push(serializeListItems(sub, 'ordered', indent + ' '))\n }\n else if (sub.nodeName === 'taskList') {\n nestedParts.push(serializeTaskList(sub, indent + ' '))\n }\n else {\n // Other block — render under the item with a 2-space hanging indent\n nestedParts.push((indent + ' ') + serializeBlock(sub, indent + ' '))\n }\n }\n lines.push(`${indent}- ${marker} ${header}`)\n for (const part of nestedParts) lines.push(part)\n }\n return lines.join('\\n')\n}\n\nfunction getCodeBlockText(el: Y.XmlElement): string {\n for (const child of el.toArray()) {\n if (isXText(child)) {\n return child.toString()\n }\n }\n return ''\n}\n\nfunction serializeTable(el: Y.XmlElement): string {\n const rows = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n if (!rows.length) return ''\n\n const serializedRows: string[][] = []\n for (const row of rows) {\n const cells = row.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map((cell) => {\n // Cell contains paragraphs — join their text\n return cell.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeInline(c))\n .join(' ')\n })\n serializedRows.push(cells)\n }\n\n if (!serializedRows.length) return ''\n\n const colCount = Math.max(...serializedRows.map(r => r.length))\n const headerRow = serializedRows[0]!\n const separator = Array(colCount).fill('---')\n const dataRows = serializedRows.slice(1)\n\n const formatRow = (cells: string[]) => {\n const padded = Array(colCount).fill('').map((_, i) => cells[i] ?? '')\n return `| ${padded.join(' | ')} |`\n }\n\n const lines = [formatRow(headerRow), formatRow(separator), ...dataRows.map(formatRow)]\n return lines.join('\\n')\n}\n\nfunction serializeSlottedContainer(\n el: Y.XmlElement,\n containerName: string,\n childName: string,\n slotPrefix: string\n): string {\n const items = el.toArray().filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === childName)\n const slots = items.map((item) => {\n const label = item.getAttribute('label') ?? ''\n const icon = item.getAttribute('icon') ?? ''\n const props: string[] = []\n if (label) props.push(`label=\"${label}\"`)\n if (icon) props.push(`icon=\"${icon}\"`)\n const content = serializeChildren(item)\n return `#${slotPrefix}{${props.join(' ')}}\\n${content}`\n })\n return `::${containerName}\\n${slots.join('\\n\\n')}\\n::`\n}\n\n// ── Frontmatter generation ──────────────────────────────────────────────────\n\n/**\n * Keys the hand-rolled canonical section below emits itself. The generic\n * spec-driven pass must skip these so each key is serialised exactly once,\n * in the canonical order existing fixtures depend on.\n */\nconst CANONICAL_FM_KEYS: ReadonlySet<string> = new Set([\n 'title', 'type', 'tags', 'color', 'icon', 'status', 'priority', 'checked',\n 'language', 'fileExtension', 'codeTheme', 'dateStart', 'dateEnd',\n 'subtitle', 'url', 'rating',\n])\n\n/** Render one meta value as a YAML line, or null when it can't be emitted. */\nfunction yamlLine(key: string, v: unknown, specType?: MetaValueType): string | null {\n if (v === undefined || v === null) return null\n if (Array.isArray(v)) {\n if (v.length === 0) return null\n return `${key}: [${v.map(x => String(x)).join(', ')}]`\n }\n if (typeof v === 'number') return Number.isFinite(v) ? `${key}: ${v}` : null\n if (typeof v === 'boolean') return `${key}: ${v}`\n if (typeof v === 'string') return v === '' ? null : `${key}: ${yamlScalar(v)}`\n if (specType === 'members' || specType === 'json' || typeof v === 'object') {\n // Structured value — emit as single-quoted JSON (parse side JSON.parses\n // it back). Skip when the payload itself contains a single quote rather\n // than emit un-round-trippable YAML.\n try {\n const json = JSON.stringify(v)\n return json.includes('\\'') ? null : `${key}: '${json}'`\n } catch {\n return null\n }\n }\n return null\n}\n\n/**\n * Generate the YAML frontmatter block. Returns '' when there is nothing to\n * emit, so callers can skip the block entirely — an empty `---\\n\\n---` shell\n * is never produced (docs whose meta holds only internal `_`-keys used to\n * export as exactly that junk).\n *\n * Emission order: the long-standing hand-rolled canonical keys first (byte\n * stability for existing files), then every remaining universal-meta key in\n * registry order, then custom keys alphabetically. Internal keys (leading\n * `_`, e.g. `_metaInitialized`) are never serialised.\n */\nfunction generateFrontmatter(label: string | undefined, meta?: DocPageMeta, type?: string): string {\n const lines: string[] = []\n\n if (label !== undefined) lines.push(`title: \"${escapeYaml(label)}\"`)\n\n if (type && type !== 'doc') {\n lines.push(`type: ${type}`)\n }\n\n if (meta) {\n if (meta.tags?.length) {\n lines.push(`tags: [${meta.tags.join(', ')}]`)\n }\n if (meta.color) lines.push(`color: ${yamlScalar(meta.color)}`)\n if (meta.icon) lines.push(`icon: ${yamlScalar(meta.icon)}`)\n if (meta.status) lines.push(`status: ${yamlScalar(meta.status)}`)\n\n if (meta.priority !== undefined && meta.priority !== 0) {\n const map: Record<number, string> = { 1: 'low', 2: 'medium', 3: 'high', 4: 'urgent' }\n lines.push(`priority: ${map[meta.priority] ?? meta.priority}`)\n }\n\n if (meta.checked !== undefined) lines.push(`checked: ${meta.checked}`)\n // Code page type: syntax-highlight language + on-disk extension. These\n // round-trip the `.md` envelope so the companion code file can be re-derived.\n if (meta.language) lines.push(`language: ${yamlScalar(meta.language)}`)\n if (meta.fileExtension) lines.push(`fileExtension: ${yamlScalar(meta.fileExtension)}`)\n if (meta.codeTheme) lines.push(`codeTheme: ${yamlScalar(meta.codeTheme)}`)\n if (meta.dateStart) lines.push(`dateStart: \"${escapeYaml(meta.dateStart)}\"`)\n if (meta.dateEnd) lines.push(`dateEnd: \"${escapeYaml(meta.dateEnd)}\"`)\n if (meta.subtitle) lines.push(`subtitle: \"${escapeYaml(meta.subtitle)}\"`)\n if (meta.url) lines.push(`url: ${meta.url}`)\n if (meta.rating !== undefined && meta.rating !== 0) lines.push(`rating: ${meta.rating}`)\n\n // Spec-driven pass: every other universal key, in registry order, so\n // graph/map/spatial/dashboard layout, covers, datetimes etc. survive\n // export instead of being silently dropped.\n const m = meta as Record<string, unknown>\n for (const spec of UNIVERSAL_META_KEYS) {\n if (CANONICAL_FM_KEYS.has(spec.key)) continue\n const line = yamlLine(spec.key, m[spec.key], spec.type)\n if (line) lines.push(line)\n }\n\n // Custom (non-spec) keys, alphabetically; internal `_`-keys skipped.\n const customKeys = Object.keys(m)\n .filter(k => !k.startsWith('_')\n && !CANONICAL_FM_KEYS.has(k)\n && !UNIVERSAL_META_KEY_NAMES.has(k))\n .sort()\n for (const k of customKeys) {\n const line = yamlLine(k, m[k])\n if (line) lines.push(line)\n }\n }\n\n if (lines.length === 0) return ''\n return `---\\n${lines.join('\\n')}\\n---`\n}\n\n/**\n * Render a YAML scalar — bare when safe, double-quoted when the value\n * needs escaping. YAML treats `#`, `:`, leading whitespace, and a few\n * other characters as syntactically significant, so anything starting\n * with one of those gets quoted to stay round-trip safe.\n */\nfunction yamlScalar(s: string): string {\n if (s === '') return '\"\"'\n if (/^[#&*!|>%@`]/.test(s)) return `\"${escapeYaml(s)}\"`\n if (/[:\"]/.test(s)) return `\"${escapeYaml(s)}\"`\n if (/^\\s|\\s$/.test(s)) return `\"${escapeYaml(s)}\"`\n return s\n}\n\nfunction escapeYaml(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n// ── HTML serialization ──────────────────────────────────────────────────────\n\nfunction serializeBlockToHtml(el: Y.XmlElement | Y.XmlText): string {\n if (isXText(el)) {\n return serializeDeltaToHtml(el.toDelta())\n }\n\n const name = el.nodeName\n switch (name) {\n case 'documentHeader':\n case 'documentMeta':\n return ''\n\n case 'heading': {\n const level = Number(el.getAttribute('level') ?? 2)\n return `<h${level}>${serializeInlineHtml(el)}</h${level}>`\n }\n\n case 'paragraph':\n return `<p>${serializeInlineHtml(el)}</p>`\n\n case 'bulletList':\n return `<ul>${serializeListHtml(el)}</ul>`\n\n case 'orderedList':\n return `<ol>${serializeListHtml(el)}</ol>`\n\n case 'taskList':\n return `<ul>${serializeTaskListHtml(el)}</ul>`\n\n case 'codeBlock': {\n // Restrict the language to a safe identifier charset — it is interpolated\n // into a class attribute below; an unsanitised value is a stored-XSS sink.\n const lang = (el.getAttribute('language') ?? '').replace(/[^\\w.-]/g, '')\n const code = escapeHtml(getCodeBlockText(el))\n return lang\n ? `<pre><code class=\"language-${lang}\">${code}</code></pre>`\n : `<pre><code>${code}</code></pre>`\n }\n\n case 'blockquote': {\n const inner = el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeBlockToHtml(c))\n .join('\\n')\n return `<blockquote>\\n${inner}\\n</blockquote>`\n }\n\n case 'table':\n return serializeTableHtml(el)\n\n case 'horizontalRule':\n return '<hr>'\n\n case 'image': {\n const src = el.getAttribute('src') ?? ''\n const alt = el.getAttribute('alt') ?? ''\n return `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(alt)}\">`\n }\n\n case 'fileBlock': {\n const uploadId = el.getAttribute('uploadId') ?? ''\n const filename = el.getAttribute('filename') ?? 'file'\n if (uploadId) return `<!--fileblock:${uploadId}:${filename}-->`\n return `<!-- file: ${filename} -->`\n }\n\n default: {\n // Generic wrapper for MDC blocks etc.\n const inner = el.toArray()\n .filter((c): c is Y.XmlElement | Y.XmlText => isXElem(c) || isXText(c))\n .map(c => isXElem(c) ? serializeBlockToHtml(c) : serializeDeltaToHtml(c.toDelta()))\n .join('\\n')\n return `<div data-type=\"${name}\">\\n${inner}\\n</div>`\n }\n }\n}\n\nfunction serializeInlineHtml(el: Y.XmlElement | Y.XmlFragment): string {\n const parts: string[] = []\n for (const child of el.toArray()) {\n if (isXText(child)) {\n parts.push(serializeDeltaToHtml(child.toDelta()))\n } else if (isXElem(child)) {\n parts.push(serializeInlineHtml(child))\n }\n }\n return parts.join('')\n}\n\nfunction serializeDeltaToHtml(delta: any[]): string {\n let result = ''\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n let text = escapeHtml(op.insert as string)\n const attrs = op.attributes ?? {}\n if (attrs.code) text = `<code>${text}</code>`\n if (attrs.bold) text = `<strong>${text}</strong>`\n if (attrs.italic) text = `<em>${text}</em>`\n if (attrs.strike) text = `<s>${text}</s>`\n if (attrs.link) {\n const href = escapeHtml((attrs.link as { href?: string }).href ?? '')\n text = `<a href=\"${href}\">${text}</a>`\n }\n result += text\n }\n return result\n}\n\nfunction serializeListHtml(el: Y.XmlElement): string {\n return el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'listItem')\n .map(li => `<li>${li.toArray().filter((c): c is Y.XmlElement => isXElem(c)).map(c => serializeBlockToHtml(c)).join('')}</li>`)\n .join('\\n')\n}\n\nfunction serializeTaskListHtml(el: Y.XmlElement): string {\n return el.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c) && c.nodeName === 'taskItem')\n .map((ti) => {\n const rawChecked: unknown = ti.getAttribute('checked')\n const checked = rawChecked === true || rawChecked === 'true'\n const text = ti.toArray().filter((c): c is Y.XmlElement => isXElem(c)).map(c => serializeInlineHtml(c)).join('')\n return `<li><input type=\"checkbox\"${checked ? ' checked' : ''} disabled> ${text}</li>`\n })\n .join('\\n')\n}\n\nfunction serializeTableHtml(el: Y.XmlElement): string {\n const rows = el.toArray().filter((c): c is Y.XmlElement => isXElem(c))\n if (!rows.length) return ''\n\n const htmlRows = rows.map((row, ri) => {\n const tag = ri === 0 ? 'th' : 'td'\n const cells = row.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map((cell) => {\n const inner = cell.toArray()\n .filter((c): c is Y.XmlElement => isXElem(c))\n .map(c => serializeInlineHtml(c))\n .join('')\n return `<${tag}>${inner}</${tag}>`\n })\n .join('')\n return `<tr>${cells}</tr>`\n })\n\n return `<table>\\n${htmlRows.join('\\n')}\\n</table>`\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function yjsToMarkdown(\n fragment: Y.XmlFragment,\n label: string,\n meta?: DocPageMeta,\n type?: string\n): string {\n fragment = localizeFragment(fragment)\n // The title can come from three places. We honour where the parser\n // captured it so the wire form round-trips byte-stably:\n // - 'h1' → emit `# title` as the first body block\n // - 'frontmatter' → emit `title:` in frontmatter\n // - undefined → no real title; skip the frontmatter block\n // when no other meta is set\n const { text: headerText, source: titleSource } = readDocumentHeader(fragment)\n const effectiveTitle = headerText || label\n\n // If the caller didn't pass meta / type, read them from documentMeta —\n // that's where the parser stashes frontmatter fields so they survive\n // round-trip without needing to be piped through the consumer.\n const docMeta = readDocumentMeta(fragment)\n const effectiveMeta = meta ?? docMeta.meta\n const effectiveType = type ?? docMeta.type\n\n const bodyBlocks = collectBodyBlocks(fragment)\n\n // Body assembly — when the parser captured the title from a body H1\n // we restore it at the top of the body before serialising.\n let body: string\n if (titleSource === 'h1' && effectiveTitle) {\n const tail = serializeBlocksClean(bodyBlocks)\n body = tail === '' ? `# ${effectiveTitle}` : `# ${effectiveTitle}\\n\\n${tail}`\n }\n else {\n body = serializeBlocksClean(bodyBlocks)\n }\n\n const fmTitle = titleSource === 'frontmatter' ? effectiveTitle : undefined\n // The generator returns '' when there is nothing to emit — never an\n // empty `---\\n\\n---` shell (e.g. meta holding only internal `_`-keys).\n const frontmatter = generateFrontmatter(fmTitle, effectiveMeta, effectiveType)\n if (frontmatter === '') {\n return body === '' ? '' : `${body}\\n`\n }\n if (body === '') return `${frontmatter}\\n`\n return `${frontmatter}\\n\\n${body}\\n`\n}\n\nfunction readDocumentMeta(fragment: Y.XmlFragment): { meta: DocPageMeta, type?: string } {\n const meta: DocPageMeta = {}\n let type: string | undefined\n for (const child of fragment.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'documentMeta') continue\n const attrs = child.getAttributes() as Record<string, unknown>\n for (const k of Object.keys(attrs)) {\n const v = attrs[k]\n if (v === undefined || v === null) continue\n if (k === 'type' && typeof v === 'string') {\n type = v\n continue\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (meta as Record<string, unknown>)[k] = v\n }\n break\n }\n return { meta, type }\n}\n\ninterface HeaderInfo { text: string, source?: 'h1' | 'frontmatter' }\n\nfunction readDocumentHeader(fragment: Y.XmlFragment): HeaderInfo {\n for (const child of fragment.toArray()) {\n if (!(isXElem(child)) || child.nodeName !== 'documentHeader') continue\n const text = child.toArray().find(c => isXText(c)) as Y.XmlText | undefined\n const src: unknown = child.getAttribute('titleSource')\n const source = src === 'h1' || src === 'frontmatter' ? src : undefined\n return { text: text ? text.toString() : '', source }\n }\n return { text: '' }\n}\n\nfunction collectBodyBlocks(fragment: Y.XmlFragment): Y.XmlElement[] {\n const out: Y.XmlElement[] = []\n for (const child of fragment.toArray()) {\n if (!(isXElem(child))) continue\n if (child.nodeName === 'documentHeader' || child.nodeName === 'documentMeta') continue\n out.push(child)\n }\n return out\n}\n\nfunction serializeBlocksClean(blocks: Y.XmlElement[]): string {\n const parts: string[] = []\n for (const block of blocks) {\n // Empty trailing paragraphs are the parser's placeholder for an\n // \"empty doc\"; skip them so empty input round-trips to \"\".\n if (block.nodeName === 'paragraph' && block.length === 0) {\n parts.push('')\n continue\n }\n parts.push(serializeBlock(block))\n }\n while (parts.length && parts[parts.length - 1] === '') parts.pop()\n return parts.join('\\n\\n')\n}\n\n/**\n * Make a serialised doc self-describing for an Obsidian-style vault or a\n * markdown export: the doc's label is always present as a leading `# Title`,\n * even when the body is empty (containers, kanban columns) — that's how the\n * app shows it, and it makes the label round-trip losslessly (the parser\n * maps a leading H1 → the doc title) with zero sidecar dependency.\n *\n * Pure post-process of yjsToMarkdown's output; the serializer's own\n * byte-stability invariants are untouched. Originally lived in cou-sh's\n * fs-sync (useFsSyncTo) — lifted here so fs-sync and doc export share one\n * implementation.\n */\nexport function ensureLeadingTitle(md: string, label: unknown): string {\n const title = typeof label === 'string' ? label.trim() : ''\n\n // Peel an optional leading frontmatter block off the body.\n let fm = ''\n let body = md\n const fmMatch = /^---\\n([\\s\\S]*?)\\n---\\n?/.exec(md)\n if (fmMatch) {\n body = md.slice(fmMatch[0].length)\n // Collapse an empty frontmatter (only whitespace between fences).\n fm = (fmMatch[1] ?? '').trim() === '' ? '' : `---\\n${fmMatch[1]}\\n---`\n }\n body = body.replace(/^\\n+/, '')\n\n if (!title) {\n const out = fm ? (body ? `${fm}\\n\\n${body}` : `${fm}\\n`) : body\n return out && !out.endsWith('\\n') ? `${out}\\n` : out\n }\n\n // A leading ATX H1 is already the title (the serializer emitted\n // headerText||label via titleSource:'h1') — leave it, never double it.\n const hasH1 = /^#[ \\t]+\\S/.test(body)\n let out = hasH1\n ? body\n : (body ? `# ${title}\\n\\n${body}` : `# ${title}\\n`)\n if (fm) out = `${fm}\\n\\n${out}`\n if (!out.endsWith('\\n')) out += '\\n'\n return out\n}\n\n/**\n * Walk the Y.XmlFragment and concatenate all text content with no\n * markup or frontmatter. Block boundaries become newlines. Useful for\n * accessibility tooling, search indexing, and snippet previews.\n */\nexport function yjsToPlainText(fragment: Y.XmlFragment): string {\n fragment = localizeFragment(fragment)\n const out: string[] = []\n const visit = (node: Y.XmlElement | Y.XmlText): void => {\n if (isXText(node)) {\n out.push(node.toString())\n return\n }\n if (node.nodeName === 'documentMeta') return\n if (node.nodeName === 'image') {\n const alt = node.getAttribute('alt') ?? ''\n if (alt) out.push(alt)\n return\n }\n for (const child of node.toArray()) {\n if (isXText(child) || isXElem(child)) visit(child)\n }\n // Insert a single newline after block-level elements so paragraphs\n // and headings produce a readable plain-text form.\n if (node.nodeName !== 'paragraph' && node.length === 0) return\n out.push('\\n')\n }\n for (const child of fragment.toArray()) {\n if (isXText(child) || isXElem(child)) visit(child)\n }\n return out.join('').replace(/\\n+$/, '').replace(/\\n{3,}/g, '\\n\\n')\n}\n\nexport function yjsToHtml(\n fragment: Y.XmlFragment,\n label: string\n): string {\n fragment = localizeFragment(fragment)\n const title = escapeHtml(label)\n const bodyParts: string[] = []\n for (const child of fragment.toArray()) {\n if (isXElem(child)) {\n const html = serializeBlockToHtml(child)\n if (html) bodyParts.push(html)\n }\n }\n return `<!DOCTYPE html>\n<html>\n<head><meta charset=\"utf-8\"><title>${title}</title></head>\n<body>\n<h1>${title}</h1>\n${bodyParts.join('\\n')}\n</body>\n</html>\n`\n}\n","import * as Y from 'yjs'\n\n// ── HTML → Y.js converter ───────────────────────────────────────────────────\n//\n// Uses DOMParser (browser builtin) to parse HTML, then walks the DOM tree\n// and writes TipTap-compatible Y.XmlElement nodes into the fragment.\n//\n// Follows the same attach-before-fill pattern as markdownToYjs.ts:\n// always attach nodes to the doc before inserting text into them.\n\ninterface ActiveMarks {\n bold?: true\n italic?: true\n code?: true\n strike?: true\n link?: { href: string }\n}\n\nfunction getTextContent(node: Node): string {\n return node.textContent ?? ''\n}\n\nfunction langFromClass(el: Element): string {\n for (const cls of Array.from(el.classList)) {\n if (cls.startsWith('language-')) return cls.slice(9)\n }\n return ''\n}\n\n/**\n * Collect inline marks from a DOM element's ancestry.\n * Returns merged marks object accumulated from the provided stack.\n */\nfunction mergeMarks(stack: ActiveMarks[]): ActiveMarks {\n const merged: ActiveMarks = {}\n for (const m of stack) {\n if (m.bold) merged.bold = true\n if (m.italic) merged.italic = true\n if (m.code) merged.code = true\n if (m.strike) merged.strike = true\n if (m.link) merged.link = m.link\n }\n return merged\n}\n\ninterface TextRun {\n text: string\n marks: ActiveMarks\n}\n\n/** Walk an inline subtree and collect { text, marks } runs. */\nfunction collectInlineRuns(node: Node, markStack: ActiveMarks[]): TextRun[] {\n const runs: TextRun[] = []\n\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent ?? ''\n if (text) runs.push({ text, marks: mergeMarks(markStack) })\n return runs\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return runs\n\n const el = node as Element\n const tag = el.tagName.toLowerCase()\n\n const newMarks: ActiveMarks = {}\n if (tag === 'strong' || tag === 'b') newMarks.bold = true\n if (tag === 'em' || tag === 'i') newMarks.italic = true\n if (tag === 'code') newMarks.code = true\n if (tag === 's' || tag === 'del' || tag === 'strike') newMarks.strike = true\n if (tag === 'a') {\n const href = el.getAttribute('href')\n if (href) newMarks.link = { href }\n }\n\n const nextStack = Object.keys(newMarks).length ? [...markStack, newMarks] : markStack\n\n for (const child of Array.from(el.childNodes)) {\n runs.push(...collectInlineRuns(child, nextStack))\n }\n return runs\n}\n\n/** Fill an already-attached Y.XmlElement with inline text runs. */\nfunction fillInlineRuns(paraEl: Y.XmlElement, runs: TextRun[]): void {\n if (!runs.length) return\n const xtNodes = runs.map(() => new Y.XmlText())\n paraEl.insert(0, xtNodes)\n runs.forEach((run, i) => {\n const attrs: Record<string, boolean | object> = {}\n if (run.marks.bold) attrs['bold'] = true\n if (run.marks.italic) attrs['italic'] = true\n if (run.marks.code) attrs['code'] = true\n if (run.marks.strike) attrs['strike'] = true\n if (run.marks.link) attrs['link'] = run.marks.link\n if (Object.keys(attrs).length) {\n xtNodes[i]!.insert(0, run.text, attrs)\n } else {\n xtNodes[i]!.insert(0, run.text)\n }\n })\n}\n\n/** Convert a single block-level DOM element to Y.XmlElement(s) and append to `container`. */\nfunction convertBlockElement(el: Element, container: Y.XmlElement | Y.XmlFragment): void {\n const tag = el.tagName.toLowerCase()\n\n // fileBlock: DOMSerializer renders <div data-type=\"file-block\" uploadid=\"...\" ...>\n // HTML lowercases attribute names; read in lowercase, store in camelCase for Y.js\n if (tag === 'div' && el.getAttribute('data-type') === 'file-block') {\n const fileBlockEl = new Y.XmlElement('fileBlock')\n container.insert(container.length, [fileBlockEl])\n const uploadId = el.getAttribute('uploadid') ?? ''\n const docId = el.getAttribute('docid') ?? ''\n const filename = el.getAttribute('filename') ?? ''\n const mimeType = el.getAttribute('mimetype') ?? ''\n if (uploadId) fileBlockEl.setAttribute('uploadId', uploadId)\n if (docId) fileBlockEl.setAttribute('docId', docId)\n if (filename) fileBlockEl.setAttribute('filename', filename)\n if (mimeType) fileBlockEl.setAttribute('mimeType', mimeType)\n return\n }\n\n // Headings\n const headingMatch = tag.match(/^h([1-6])$/)\n if (headingMatch) {\n const level = parseInt(headingMatch[1]!)\n const headingEl = new Y.XmlElement('heading')\n container.insert(container.length, [headingEl])\n headingEl.setAttribute('level', level as unknown as string)\n fillInlineRuns(headingEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'p') {\n const paraEl = new Y.XmlElement('paragraph')\n container.insert(container.length, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'hr') {\n const hrEl = new Y.XmlElement('horizontalRule')\n container.insert(container.length, [hrEl])\n return\n }\n\n if (tag === 'pre') {\n const codeEl = el.querySelector('code')\n const codeBlock = new Y.XmlElement('codeBlock')\n container.insert(container.length, [codeBlock])\n const lang = codeEl ? langFromClass(codeEl) : ''\n if (lang) codeBlock.setAttribute('language', lang)\n const xt = new Y.XmlText()\n codeBlock.insert(0, [xt])\n xt.insert(0, (codeEl ?? el).textContent ?? '')\n return\n }\n\n if (tag === 'blockquote') {\n const bqEl = new Y.XmlElement('blockquote')\n container.insert(container.length, [bqEl])\n // Wrap text in a paragraph\n const paraEl = new Y.XmlElement('paragraph')\n bqEl.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n return\n }\n\n if (tag === 'ul' || tag === 'ol') {\n // Check if any li contains a checkbox → taskList\n const items = Array.from(el.querySelectorAll(':scope > li'))\n const hasCheckbox = items.some(li => li.querySelector('input[type=\"checkbox\"]'))\n\n if (hasCheckbox) {\n const taskListEl = new Y.XmlElement('taskList')\n container.insert(container.length, [taskListEl])\n const taskItemEls = items.map(() => new Y.XmlElement('taskItem'))\n taskListEl.insert(0, taskItemEls)\n items.forEach((li, i) => {\n const checkbox = li.querySelector('input[type=\"checkbox\"]') as HTMLInputElement | null\n const checked = checkbox?.checked ?? false\n taskItemEls[i]!.setAttribute('checked', checked as unknown as string)\n const paraEl = new Y.XmlElement('paragraph')\n taskItemEls[i]!.insert(0, [paraEl])\n // Remove checkbox from text extraction\n const clone = li.cloneNode(true) as Element\n clone.querySelector('input')?.remove()\n fillInlineRuns(paraEl, collectInlineRuns(clone, []))\n })\n } else {\n const listType = tag === 'ul' ? 'bulletList' : 'orderedList'\n const listEl = new Y.XmlElement(listType)\n container.insert(container.length, [listEl])\n const listItemEls = items.map(() => new Y.XmlElement('listItem'))\n listEl.insert(0, listItemEls)\n items.forEach((li, i) => {\n const paraEl = new Y.XmlElement('paragraph')\n listItemEls[i]!.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(li, []))\n })\n }\n return\n }\n\n if (tag === 'table') {\n const tableEl = new Y.XmlElement('table')\n container.insert(container.length, [tableEl])\n\n const rows = Array.from(el.querySelectorAll('tr'))\n const rowEls = rows.map(() => new Y.XmlElement('tableRow'))\n tableEl.insert(0, rowEls)\n\n rows.forEach((row, ri) => {\n const cells = Array.from(row.querySelectorAll('th, td'))\n const isHeader = cells.some(c => c.tagName.toLowerCase() === 'th')\n const cellType = isHeader ? 'tableHeader' : 'tableCell'\n const cellEls = cells.map(() => new Y.XmlElement(cellType))\n rowEls[ri]!.insert(0, cellEls)\n cells.forEach((cell, ci) => {\n const paraEl = new Y.XmlElement('paragraph')\n cellEls[ci]!.insert(0, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(cell, []))\n })\n })\n return\n }\n\n // Fallback: treat as paragraph (div, section, article, etc.)\n const text = getTextContent(el).trim()\n if (text) {\n const paraEl = new Y.XmlElement('paragraph')\n container.insert(container.length, [paraEl])\n fillInlineRuns(paraEl, collectInlineRuns(el, []))\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Parses an HTML string and writes the result into a Y.XmlFragment that\n * TipTap's Collaboration extension can read.\n *\n * @param fragment The target `Y.Doc.getXmlFragment('default')`\n * @param html Raw HTML string\n * @param fallbackTitle Used when no <title> or <h1> is found\n */\nexport function populateYDocFromHtml(\n fragment: Y.XmlFragment,\n html: string,\n fallbackTitle = 'Untitled'\n): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[htmlToYjs] fragment has no doc — skipping population')\n return\n }\n\n const doc = new DOMParser().parseFromString(html, 'text/html')\n\n // Determine title\n let title = doc.title?.trim() || fallbackTitle\n const firstH1 = doc.body.querySelector('h1')\n if (firstH1) title = firstH1.textContent?.trim() || title\n\n ydoc.transact(() => {\n const headerEl = new Y.XmlElement('documentHeader')\n const metaEl = new Y.XmlElement('documentMeta')\n fragment.insert(0, [headerEl, metaEl])\n\n const headerXt = new Y.XmlText()\n headerEl.insert(0, [headerXt])\n headerXt.insert(0, title)\n\n // Walk body block children\n const blockTags = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'pre', 'blockquote', 'table', 'hr',\n 'div', 'section', 'article', 'header', 'footer', 'main', 'aside'\n ])\n\n let hasContent = false\n for (const child of Array.from(doc.body.children)) {\n const tag = child.tagName.toLowerCase()\n if (!blockTags.has(tag)) continue\n // Skip first h1 (already used as title)\n if (tag === 'h1' && child === firstH1) continue\n convertBlockElement(child, fragment)\n hasContent = true\n }\n\n // Ensure at least one paragraph exists\n if (!hasContent) {\n const paraEl = new Y.XmlElement('paragraph')\n fragment.insert(fragment.length, [paraEl])\n }\n })\n}\n\n/**\n * Appends blocks from an HTML string to an existing Y.XmlFragment.\n * Does NOT insert documentHeader/documentMeta — for appending to an existing doc.\n */\nexport function appendHtmlToFragment(fragment: Y.XmlFragment, html: string): void {\n const ydoc = fragment.doc\n if (!ydoc) {\n console.warn('[htmlToYjs] appendHtmlToFragment: fragment has no doc — skipping')\n return\n }\n const doc = new DOMParser().parseFromString(html, 'text/html')\n const blockTags = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'pre', 'blockquote', 'table', 'hr',\n 'div', 'section', 'article', 'header', 'footer', 'main', 'aside'\n ])\n ydoc.transact(() => {\n for (const child of Array.from(doc.body.children)) {\n if (blockTags.has(child.tagName.toLowerCase()))\n convertBlockElement(child, fragment)\n }\n })\n}\n","// Code page-type helpers for @abraca/convert.\n//\n// A `code` document stores its content in a plain `Y.Text` under the\n// `code` key (edited via CodeMirror + y-codemirror.next), separate from\n// the TipTap prose fragment that carries the `documentHeader`/\n// `documentMeta` envelope. fs-sync writes that text out to a real code\n// file (e.g. `main.rs`) alongside the `.md` envelope.\n//\n// This module owns the single source of truth for:\n// - the `code` Y.Text key name,\n// - reading/replacing that text,\n// - the file-extension ↔ CodeMirror-language mapping used by both\n// fs-sync directions and the renderer.\n//\n// `yjs` stays a type-only peer import — these helpers only call methods\n// on the Y.Doc handed in by the caller, never construct Y types.\n\nimport type * as Y from 'yjs'\n\n/** Y.Text key holding a code document's content. */\nexport const CODE_TEXT_KEY = 'code'\n\n/** Read a code document's raw text. Empty string when absent. */\nexport function readCodeText(doc: Y.Doc): string {\n return doc.getText(CODE_TEXT_KEY).toString()\n}\n\n/**\n * Replace a code document's full text in a single transaction. `origin`\n * is forwarded to `transact` so callers (e.g. fs-sync) can tag the write\n * and skip their own observers.\n */\nexport function writeCodeText(doc: Y.Doc, content: string, origin?: unknown): void {\n const ytext = doc.getText(CODE_TEXT_KEY)\n doc.transact(() => {\n if (ytext.length > 0) ytext.delete(0, ytext.length)\n if (content.length > 0) ytext.insert(0, content)\n }, origin)\n}\n\n// ── Extension ↔ language ─────────────────────────────────────────────────────\n//\n// Keys are lowercase extensions without the leading dot; values are the\n// canonical CodeMirror language id the renderer resolves against\n// `@codemirror/language-data`. The first extension listed for a language\n// in EXT_BY_LANGUAGE is the one fs-sync uses when writing the file.\n\nconst LANGUAGE_BY_EXT: Readonly<Record<string, string>> = {\n // JS/TS family\n js: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n jsx: 'jsx',\n ts: 'typescript',\n mts: 'typescript',\n cts: 'typescript',\n tsx: 'tsx',\n // Web\n html: 'html',\n htm: 'html',\n css: 'css',\n scss: 'scss',\n less: 'less',\n vue: 'vue',\n svelte: 'svelte',\n // Data / config\n json: 'json',\n jsonc: 'json',\n json5: 'json',\n yaml: 'yaml',\n yml: 'yaml',\n toml: 'toml',\n xml: 'xml',\n ini: 'properties',\n env: 'properties',\n // Systems\n rs: 'rust',\n go: 'go',\n c: 'c',\n h: 'c',\n cpp: 'cpp',\n cc: 'cpp',\n cxx: 'cpp',\n hpp: 'cpp',\n cs: 'csharp',\n java: 'java',\n kt: 'kotlin',\n kts: 'kotlin',\n swift: 'swift',\n m: 'objective-c',\n mm: 'objective-c',\n // Scripting\n py: 'python',\n pyi: 'python',\n rb: 'ruby',\n php: 'php',\n pl: 'perl',\n lua: 'lua',\n r: 'r',\n // Shell\n sh: 'shell',\n bash: 'shell',\n zsh: 'shell',\n fish: 'shell',\n // Query / misc\n sql: 'sql',\n graphql: 'graphql',\n gql: 'graphql',\n dockerfile: 'dockerfile',\n // Markup that is genuinely \"code\" in a vault context\n md: 'markdown',\n markdown: 'markdown',\n}\n\n/** Preferred on-disk extension per language (reverse of LANGUAGE_BY_EXT). */\nconst EXT_BY_LANGUAGE: Readonly<Record<string, string>> = {\n javascript: 'js',\n jsx: 'jsx',\n typescript: 'ts',\n tsx: 'tsx',\n html: 'html',\n css: 'css',\n scss: 'scss',\n less: 'less',\n vue: 'vue',\n svelte: 'svelte',\n json: 'json',\n yaml: 'yaml',\n toml: 'toml',\n xml: 'xml',\n properties: 'ini',\n rust: 'rs',\n go: 'go',\n c: 'c',\n cpp: 'cpp',\n csharp: 'cs',\n java: 'java',\n kotlin: 'kt',\n swift: 'swift',\n 'objective-c': 'm',\n python: 'py',\n ruby: 'rb',\n php: 'php',\n perl: 'pl',\n lua: 'lua',\n r: 'r',\n shell: 'sh',\n sql: 'sql',\n graphql: 'graphql',\n dockerfile: 'dockerfile',\n markdown: 'md',\n plain: 'txt',\n}\n\n/** Normalize an extension: strip leading dot(s), lowercase. */\nexport function normalizeExtension(ext: string): string {\n return ext.replace(/^\\.+/, '').toLowerCase()\n}\n\n/**\n * Whether a file extension should import as a `code` page type. Note\n * `md`/`markdown` are intentionally NOT code extensions here — fs-sync\n * treats `.md` as the prose/envelope format, so it's excluded from the\n * code-import gate even though it has a language mapping for in-editor use.\n */\nexport function isCodeExtension(ext: string): boolean {\n const e = normalizeExtension(ext)\n if (e === 'md' || e === 'markdown') return false\n return e in LANGUAGE_BY_EXT\n}\n\n/** CodeMirror language id for an extension, or undefined when unknown. */\nexport function extToLanguage(ext: string): string | undefined {\n return LANGUAGE_BY_EXT[normalizeExtension(ext)]\n}\n\n/** Preferred on-disk extension (no dot) for a language, or undefined. */\nexport function languageToExtension(language: string): string | undefined {\n return EXT_BY_LANGUAGE[language.toLowerCase()]\n}\n\n/**\n * Derive `{ language, fileExtension }` from a filename for code import.\n * Returns undefined when the extension is not a recognized code extension\n * (so callers fall back to the prose/doc path).\n */\nexport function inferCodeMetaFromFilename(\n filename: string,\n): { language: string, fileExtension: string } | undefined {\n const dot = filename.lastIndexOf('.')\n if (dot < 0) return undefined\n const ext = normalizeExtension(filename.slice(dot + 1))\n if (!isCodeExtension(ext)) return undefined\n const language = LANGUAGE_BY_EXT[ext]\n if (!language) return undefined\n return { language, fileExtension: ext }\n}\n\n/**\n * Choose the on-disk extension for a code doc on export. Prefers an\n * explicit `fileExtension`, then the language's primary extension, then\n * `txt`.\n */\nexport function codeFileExtension(meta?: { fileExtension?: string, language?: string }): string {\n if (meta?.fileExtension) return normalizeExtension(meta.fileExtension)\n if (meta?.language) return languageToExtension(meta.language) ?? 'txt'\n return 'txt'\n}\n","// Structural Y.XmlFragment ↔ JSON converter, used by the test harness\n// to make round-trip assertions and to author golden fixtures by hand.\n//\n// The JSON shape is canonical:\n//\n// YjsJsonNode =\n// | { kind: 'element'; tag: string; attrs?: Record<string, JsonAttr>; children: YjsJsonNode[] }\n// | { kind: 'text'; runs: Array<{ insert: string; attributes?: Record<string, JsonAttr> }> }\n//\n// Attributes are stored verbatim — strings, numbers, booleans, null,\n// nested JSON (for things like codeTree's `files`). The format is\n// committed alongside fixtures as `.y.json` so reviews of intent\n// changes are diffable.\n//\n// `yfragmentToJson(frag)` is deterministic: the same Y.XmlFragment\n// always produces byte-identical JSON when stringified with sorted\n// keys.\n\nimport * as Y from 'yjs'\n\nexport type JsonAttr =\n | string\n | number\n | boolean\n | null\n | JsonAttr[]\n | { [key: string]: JsonAttr }\n\nexport interface YjsTextRun {\n insert: string\n attributes?: Record<string, JsonAttr>\n}\n\nexport interface YjsJsonText {\n kind: 'text'\n runs: YjsTextRun[]\n}\n\nexport interface YjsJsonElement {\n kind: 'element'\n tag: string\n attrs?: Record<string, JsonAttr>\n children: YjsJsonNode[]\n}\n\nexport type YjsJsonNode = YjsJsonElement | YjsJsonText\n\n// ── Yjs → JSON ──────────────────────────────────────────────────────────────\n\nfunction attrsToJson(el: Y.XmlElement): Record<string, JsonAttr> | undefined {\n const out: Record<string, JsonAttr> = {}\n let count = 0\n for (const key of Object.keys(el.getAttributes())) {\n const raw: unknown = el.getAttribute(key)\n out[key] = normaliseAttr(raw)\n count++\n }\n if (count === 0) return undefined\n return sortKeys(out)\n}\n\nfunction normaliseAttr(v: unknown): JsonAttr {\n if (v == null) return null\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') return v\n if (Array.isArray(v)) return v.map(normaliseAttr)\n if (typeof v === 'object') {\n const out: Record<string, JsonAttr> = {}\n for (const k of Object.keys(v as object).sort()) {\n out[k] = normaliseAttr((v as Record<string, unknown>)[k])\n }\n return out\n }\n // Functions / symbols / undefined — coerce to null so the JSON\n // remains valid and diffs surface the loss.\n return null\n}\n\nfunction sortKeys(obj: Record<string, JsonAttr>): Record<string, JsonAttr> {\n const out: Record<string, JsonAttr> = {}\n for (const k of Object.keys(obj).sort()) out[k] = obj[k]!\n return out\n}\n\nfunction textToJson(text: Y.XmlText): YjsJsonText {\n const delta = text.toDelta() as Array<{ insert: unknown, attributes?: Record<string, unknown> }>\n const runs: YjsTextRun[] = []\n for (const op of delta) {\n if (typeof op.insert !== 'string') continue\n const run: YjsTextRun = { insert: op.insert }\n if (op.attributes && Object.keys(op.attributes).length > 0) {\n const normalised: Record<string, JsonAttr> = {}\n for (const k of Object.keys(op.attributes).sort()) {\n normalised[k] = normaliseAttr(op.attributes[k])\n }\n run.attributes = normalised\n }\n runs.push(run)\n }\n return { kind: 'text', runs }\n}\n\nfunction elementToJson(el: Y.XmlElement): YjsJsonElement {\n const attrs = attrsToJson(el)\n const children: YjsJsonNode[] = []\n for (const child of el.toArray()) {\n if (child instanceof Y.XmlElement) children.push(elementToJson(child))\n else if (child instanceof Y.XmlText) children.push(textToJson(child))\n }\n const out: YjsJsonElement = { kind: 'element', tag: el.nodeName, children }\n if (attrs) out.attrs = attrs\n return out\n}\n\nexport function yfragmentToJson(frag: Y.XmlFragment): YjsJsonElement {\n const children: YjsJsonNode[] = []\n for (const child of frag.toArray()) {\n if (child instanceof Y.XmlElement) children.push(elementToJson(child))\n else if (child instanceof Y.XmlText) children.push(textToJson(child))\n }\n return { kind: 'element', tag: '#fragment', children }\n}\n\n// ── JSON → Yjs ──────────────────────────────────────────────────────────────\n\n// Yjs rule: every Y.XmlElement must be attached to its parent BEFORE\n// its attributes are set or its children inserted. Otherwise the runtime\n// logs \"Invalid access: Add Yjs type to a document before reading data.\"\n// and silently no-ops the mutation.\n//\n// So we do this in two passes per node: (1) create empty skeleton +\n// attach to parent; (2) populate attrs + recurse on children, which\n// each follow the same pattern. cou-sh's populateYDocFromMarkdown uses\n// the same pattern.\n\nfunction populateElement(el: Y.XmlElement, node: YjsJsonElement): void {\n if (node.attrs) {\n for (const k of Object.keys(node.attrs)) {\n // Y.XmlElement.setAttribute only types `string`, but accepts\n // arbitrary values in practice (numbers, booleans, JSON objects).\n const v = node.attrs[k]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n el.setAttribute(k, v as any)\n }\n }\n for (const child of node.children) {\n if (child.kind === 'element') {\n const sub = new Y.XmlElement(child.tag)\n el.insert(el.length, [sub])\n populateElement(sub, child)\n }\n else {\n const text = new Y.XmlText()\n el.insert(el.length, [text])\n populateText(text, child)\n }\n }\n}\n\nfunction populateText(text: Y.XmlText, node: YjsJsonText): void {\n let offset = 0\n for (const run of node.runs) {\n if (run.attributes) {\n text.insert(offset, run.insert, run.attributes as unknown as object)\n }\n else {\n text.insert(offset, run.insert)\n }\n offset += run.insert.length\n }\n}\n\n/**\n * Build a Y.XmlFragment from a previously captured golden JSON. The\n * returned fragment is bound to a fresh Y.Doc so consumers can hand\n * it to serialisers immediately. All Yjs mutations happen inside a\n * single transaction.\n */\nexport function jsonToYFragment(root: YjsJsonElement, doc?: Y.Doc, key = 'body'): Y.XmlFragment {\n if (root.tag !== '#fragment') {\n throw new Error(`jsonToYFragment expected tag=\"#fragment\", got \"${root.tag}\"`)\n }\n const ydoc = doc ?? new Y.Doc()\n const frag = ydoc.getXmlFragment(key)\n ydoc.transact(() => {\n for (const child of root.children) {\n if (child.kind === 'element') {\n const sub = new Y.XmlElement(child.tag)\n frag.insert(frag.length, [sub])\n populateElement(sub, child)\n }\n else {\n const text = new Y.XmlText()\n frag.insert(frag.length, [text])\n populateText(text, child)\n }\n }\n })\n return frag\n}\n\n// ── Diff (deep equality with a path) ────────────────────────────────────────\n\nexport interface YjsDiff {\n equal: boolean\n /** Dotted path to the first divergence (empty when equal). */\n path: string\n /** Short human-readable explanation. */\n reason: string\n}\n\nexport function diffYjs(a: Y.XmlFragment, b: Y.XmlFragment): YjsDiff {\n return diffNode(yfragmentToJson(a), yfragmentToJson(b), '')\n}\n\nexport function diffJson(a: YjsJsonNode, b: YjsJsonNode): YjsDiff {\n return diffNode(a, b, '')\n}\n\nfunction diffNode(a: YjsJsonNode, b: YjsJsonNode, path: string): YjsDiff {\n if (a.kind !== b.kind) {\n return { equal: false, path, reason: `kind mismatch: ${a.kind} vs ${b.kind}` }\n }\n if (a.kind === 'text' && b.kind === 'text') {\n const ar = a.runs\n const br = b.runs\n if (ar.length !== br.length) {\n return { equal: false, path, reason: `text run count: ${ar.length} vs ${br.length}` }\n }\n for (let i = 0; i < ar.length; i++) {\n const sub = `${path}/runs[${i}]`\n const ai = ar[i]!\n const bi = br[i]!\n if (ai.insert !== bi.insert) {\n return { equal: false, path: sub, reason: `insert: ${JSON.stringify(ai.insert)} vs ${JSON.stringify(bi.insert)}` }\n }\n const attrDiff = diffAttrs(ai.attributes, bi.attributes, sub)\n if (!attrDiff.equal) return attrDiff\n }\n return { equal: true, path: '', reason: '' }\n }\n if (a.kind === 'element' && b.kind === 'element') {\n if (a.tag !== b.tag) return { equal: false, path, reason: `tag: ${a.tag} vs ${b.tag}` }\n const attrDiff = diffAttrs(a.attrs, b.attrs, path)\n if (!attrDiff.equal) return attrDiff\n if (a.children.length !== b.children.length) {\n return { equal: false, path, reason: `child count: ${a.children.length} vs ${b.children.length}` }\n }\n for (let i = 0; i < a.children.length; i++) {\n const sub = path === '' ? `[${i}]` : `${path}[${i}]`\n const childDiff = diffNode(a.children[i]!, b.children[i]!, sub)\n if (!childDiff.equal) return childDiff\n }\n return { equal: true, path: '', reason: '' }\n }\n return { equal: false, path, reason: 'unreachable kind combination' }\n}\n\nfunction diffAttrs(\n a: Record<string, JsonAttr> | undefined,\n b: Record<string, JsonAttr> | undefined,\n path: string,\n): YjsDiff {\n const ak = a ? Object.keys(a).sort() : []\n const bk = b ? Object.keys(b).sort() : []\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) {\n return { equal: false, path: `${path}.attrs`, reason: `attr keys: [${ak.join(',')}] vs [${bk.join(',')}]` }\n }\n for (const k of ak) {\n const av = a![k]\n const bv = b![k]\n if (!attrEqual(av, bv)) {\n return {\n equal: false,\n path: `${path}.attrs.${k}`,\n reason: `attr value: ${JSON.stringify(av)} vs ${JSON.stringify(bv)}`,\n }\n }\n }\n return { equal: true, path: '', reason: '' }\n}\n\nfunction attrEqual(a: JsonAttr, b: JsonAttr): boolean {\n if (a === b) return true\n if (a === null || b === null) return false\n if (typeof a !== typeof b) return false\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n return a.every((v, i) => attrEqual(v, b[i]!))\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a).sort()\n const bk = Object.keys(b).sort()\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) return false\n return ak.every(k => attrEqual((a as Record<string, JsonAttr>)[k]!, (b as Record<string, JsonAttr>)[k]!))\n }\n return false\n}\n\n/** Stringify a YjsJsonNode with sorted keys for byte-stable golden files. */\nexport function stringifyJsonNode(node: YjsJsonNode): string {\n return JSON.stringify(node, null, 2) + '\\n'\n}\n","// NodeSpec registry — every TipTap node supported by the converter,\n// paired with its canonical Markdown / MDC wire form.\n//\n// This is **data**, not behaviour. The parser and serialiser\n// (markdown-to-yjs.ts, yjs-to-markdown.ts) consult this table to\n// decide what to do; when the spec and the runtime disagree the\n// registry wins (per SPEC.md).\n//\n// Wire kinds:\n// - vanilla Standard Markdown (paragraph, heading, list, …).\n// - fence Fenced code block with a language tag.\n// - mdc-container `:name{props}\\n…children…\\n::` block with children.\n// - mdc-slotted `:name\\n :name-item{…}\\n…\\n ::\\n…\\n::` slotted container.\n// - mdc-atom-block `:name{props}` single-line block atom.\n// - mdc-atom-inl `:name[label]{props}` or `:name{props}` inline atom.\n// - special Has bespoke parsing/serialising (doc-link, doc-embed,\n// file-block, image, mention, math).\n\nimport type { DocPageMeta } from '../types.ts'\n\nexport type NodeWireKind =\n | 'vanilla'\n | 'fence'\n | 'mdc-container'\n | 'mdc-slotted'\n | 'mdc-atom-block'\n | 'mdc-atom-inl'\n | 'special'\n\nexport interface NodeAttrSpec {\n /** Attribute name on the Y.XmlElement and on the MDC prop. */\n key: string\n /** Wire type — controls how the attr is parsed/serialised in props. */\n type: 'string' | 'number' | 'integer' | 'boolean' | 'json'\n /** Optional default value omitted from serialised output when equal. */\n default?: unknown\n /** Allowed values for enum-like string attrs. */\n values?: readonly string[]\n /** Whether the attr is allowed to be omitted entirely. */\n optional?: boolean\n}\n\nexport interface NodeSpec {\n /** Y.XmlElement nodeName. */\n name: string\n /** Block vs inline. */\n group: 'block' | 'inline'\n /** Wire form on Markdown. */\n wire: NodeWireKind\n /**\n * For slotted containers: name of the child element used as a slot\n * (e.g. `accordion-item` under `accordion`).\n */\n slotChild?: string\n /** Declared attributes. */\n attrs?: readonly NodeAttrSpec[]\n /**\n * For `mdc-container` and `mdc-slotted`: what MDC tag name to emit.\n * Defaults to `name` (kebab-cased — `accordionItem` → `accordion-item`).\n */\n mdcTag?: string\n /**\n * Whether the node is content-bearing (paragraph, listItem, etc.)\n * or a child wrapper (tableRow, tableHeader).\n */\n contentBearing?: boolean\n doc?: string\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nconst BOOL_FALSE_DEFAULT: NodeAttrSpec = {\n key: '',\n type: 'boolean',\n default: false,\n optional: true,\n}\n\nconst bool = (key: string): NodeAttrSpec => ({ ...BOOL_FALSE_DEFAULT, key })\nconst str = (key: string, def?: string): NodeAttrSpec => ({\n key,\n type: 'string',\n default: def,\n optional: true,\n})\nconst num = (key: string): NodeAttrSpec => ({ key, type: 'number', optional: true })\nconst int = (key: string): NodeAttrSpec => ({ key, type: 'integer', optional: true })\n\n// ── Vanilla block nodes ─────────────────────────────────────────────────────\n\nconst VANILLA_BLOCKS: readonly NodeSpec[] = [\n { name: 'documentHeader', group: 'block', wire: 'special', doc: 'Holds the title; hoisted to frontmatter on serialise.' },\n { name: 'documentMeta', group: 'block', wire: 'special', doc: 'Holds page-level meta; serialised into frontmatter.' },\n { name: 'paragraph', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'heading', group: 'block', wire: 'vanilla', attrs: [int('level')], contentBearing: true },\n { name: 'blockquote', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'codeBlock', group: 'block', wire: 'fence', attrs: [str('language', '')] },\n { name: 'bulletList', group: 'block', wire: 'vanilla' },\n { name: 'orderedList', group: 'block', wire: 'vanilla' },\n { name: 'listItem', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'taskList', group: 'block', wire: 'vanilla' },\n { name: 'taskItem', group: 'block', wire: 'vanilla', attrs: [bool('checked')], contentBearing: true },\n { name: 'table', group: 'block', wire: 'vanilla' },\n { name: 'tableRow', group: 'block', wire: 'vanilla' },\n { name: 'tableHeader', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'tableCell', group: 'block', wire: 'vanilla', contentBearing: true },\n { name: 'horizontalRule', group: 'block', wire: 'vanilla' },\n {\n name: 'image',\n group: 'block',\n wire: 'special',\n attrs: [str('src'), str('alt', ''), int('width'), int('height')],\n },\n { name: 'hardBreak', group: 'inline', wire: 'vanilla' },\n]\n\n// ── MDC custom containers ───────────────────────────────────────────────────\n\nconst MDC_CONTAINERS: readonly NodeSpec[] = [\n {\n name: 'callout',\n group: 'block',\n wire: 'mdc-container',\n attrs: [\n { key: 'type', type: 'string', default: 'note', optional: true,\n values: ['note', 'tip', 'warning', 'danger', 'info', 'caution', 'alert', 'success', 'error'] },\n str('title'),\n str('icon'),\n ],\n },\n {\n name: 'collapsible',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('label', 'Details'), bool('open')],\n },\n {\n name: 'accordion',\n group: 'block',\n wire: 'mdc-slotted',\n slotChild: 'accordionItem',\n },\n {\n name: 'accordionItem',\n group: 'block',\n wire: 'mdc-container',\n mdcTag: 'accordion-item',\n attrs: [str('label', 'Item'), str('icon')],\n },\n {\n name: 'tabs',\n group: 'block',\n wire: 'mdc-slotted',\n slotChild: 'tabsItem',\n },\n {\n name: 'tabsItem',\n group: 'block',\n wire: 'mdc-container',\n mdcTag: 'tabs-item',\n attrs: [str('label'), str('icon')],\n },\n { name: 'steps', group: 'block', wire: 'mdc-container' },\n {\n name: 'card',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('title'), str('icon'), str('to')],\n },\n {\n name: 'cardGroup',\n group: 'block',\n wire: 'mdc-slotted',\n mdcTag: 'card-group',\n slotChild: 'card',\n },\n {\n name: 'field',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('name'), str('type', 'string'), bool('required')],\n },\n {\n name: 'fieldGroup',\n group: 'block',\n wire: 'mdc-slotted',\n mdcTag: 'field-group',\n slotChild: 'field',\n },\n { name: 'codeGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'code-group', slotChild: 'codeBlock' },\n { name: 'codeCollapse', group: 'block', wire: 'mdc-container', mdcTag: 'code-collapse' },\n { name: 'codePreview', group: 'block', wire: 'mdc-container', mdcTag: 'code-preview' },\n {\n name: 'codeTree',\n group: 'block',\n wire: 'mdc-atom-block',\n mdcTag: 'code-tree',\n attrs: [{ key: 'files', type: 'json' }],\n },\n {\n name: 'figure',\n group: 'block',\n wire: 'mdc-container',\n attrs: [str('src'), str('alt', ''), str('caption')],\n },\n {\n name: 'video',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('src'), str('poster'), bool('autoplay'), bool('loop'), bool('controls')],\n },\n {\n name: 'embed',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('src'), str('title')],\n },\n {\n name: 'svgEmbed',\n group: 'block',\n wire: 'fence',\n attrs: [str('title')],\n mdcTag: 'svg',\n doc: 'Serialised as a ```svg fenced block; the SVG markup is the body.',\n },\n {\n name: 'divider',\n group: 'block',\n wire: 'mdc-atom-block',\n attrs: [str('label'), str('icon')],\n },\n { name: 'quote', group: 'block', wire: 'mdc-container', attrs: [str('cite')] },\n { name: 'progress', group: 'block', wire: 'mdc-atom-block', attrs: [num('value'), num('max'), str('label')] },\n { name: 'spoiler', group: 'block', wire: 'mdc-container', attrs: [str('label')] },\n { name: 'colorSwatch', group: 'block', wire: 'mdc-atom-block', mdcTag: 'color-swatch', attrs: [str('color'), str('label')] },\n { name: 'stat', group: 'block', wire: 'mdc-container', attrs: [str('label'), str('value'), str('icon')] },\n { name: 'statGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'stat-group', slotChild: 'stat' },\n { name: 'button', group: 'block', wire: 'mdc-atom-block', attrs: [str('label'), str('to'), str('icon'), str('variant')] },\n { name: 'buttonGroup', group: 'block', wire: 'mdc-slotted', mdcTag: 'button-group', slotChild: 'button' },\n { name: 'timeline', group: 'block', wire: 'mdc-slotted', slotChild: 'timelineItem' },\n { name: 'timelineItem', group: 'block', wire: 'mdc-container', mdcTag: 'timeline-item', attrs: [str('label'), str('icon'), str('date')] },\n { name: 'diff', group: 'block', wire: 'mdc-atom-block', attrs: [str('language', ''), { key: 'value', type: 'string' }] },\n]\n\n// ── Inline atoms / special nodes ────────────────────────────────────────────\n\nconst INLINE_AND_SPECIAL: readonly NodeSpec[] = [\n {\n name: 'docLink',\n group: 'inline',\n wire: 'special',\n attrs: [str('docId')],\n doc: 'Wire form `[[uuid|label]]`; label regenerated on export.',\n },\n {\n name: 'docEmbed',\n group: 'block',\n wire: 'special',\n attrs: [str('docId'), bool('collapsed'), bool('tall'), bool('seamless')],\n doc: 'Wire form `![[uuid|label]]{collapsed tall seamless}`.',\n },\n {\n name: 'mention',\n group: 'inline',\n wire: 'special',\n attrs: [str('userId')],\n doc: 'Wire form `@[label](user:uuid)`; label regenerated on export.',\n },\n {\n name: 'mathInline',\n group: 'inline',\n wire: 'special',\n attrs: [{ key: 'expression', type: 'string' }],\n doc: 'Wire form `$expression$`.',\n },\n {\n name: 'mathBlock',\n group: 'block',\n wire: 'fence',\n attrs: [{ key: 'expression', type: 'string' }],\n mdcTag: 'math',\n doc: 'Wire form ``` ```math\\\\nexpression\\\\n``` ```.',\n },\n {\n name: 'fileBlock',\n group: 'block',\n wire: 'mdc-atom-block',\n mdcTag: 'file',\n attrs: [str('src'), str('mime'), str('uploadId'), str('filename')],\n doc: 'Wire form `:file{src=… mime=… upload-id=… filename=…}`; binary in sidecar.',\n },\n {\n name: 'badge',\n group: 'inline',\n wire: 'mdc-atom-inl',\n attrs: [str('label'), str('color'), str('variant', 'subtle')],\n doc: 'Wire form `:badge[Label]{color=… variant=…}`.',\n },\n {\n name: 'proseIcon',\n group: 'inline',\n wire: 'mdc-atom-inl',\n mdcTag: 'icon',\n attrs: [str('name')],\n doc: 'Wire form `:icon{name=…}`.',\n },\n {\n name: 'kbd',\n group: 'inline',\n wire: 'mdc-atom-inl',\n attrs: [str('value')],\n doc: 'Wire form `:kbd{value=…}`.',\n },\n]\n\nexport const NODE_SPECS: readonly NodeSpec[] = [\n ...VANILLA_BLOCKS,\n ...MDC_CONTAINERS,\n ...INLINE_AND_SPECIAL,\n]\n\nexport const NODE_SPEC_BY_NAME: ReadonlyMap<string, NodeSpec> = new Map(\n NODE_SPECS.map(spec => [spec.name, spec]),\n)\n\n/** Derive the MDC tag for a node — `mdcTag` override or kebab-case of `name`. */\nexport function mdcTagOf(spec: NodeSpec): string {\n if (spec.mdcTag) return spec.mdcTag\n return spec.name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n}\n\n/** Type-only re-export so consumers can build typed meta without a second import. */\nexport type { DocPageMeta }\n","// MarkSpec registry — every inline mark supported by the converter,\n// paired with its canonical Markdown wire form.\n//\n// Marks are pure inline annotations on text runs; they have no\n// children. The parser sets these as `op.attributes` on Yjs delta\n// inserts; the serialiser wraps text runs with the matching wire\n// delimiters.\n//\n// See SPEC.md §3-4 for the rendered table and the disambiguation\n// rules between bold (`**…**`) and underline (`__…__`).\n\nexport type MarkWireKind =\n | 'delimited' // `**text**`, `*text*`, `~~text~~`, `` `text` ``\n | 'link' // `[text](href)`\n | 'mdc-span' // `:span[text]{prop=value}` for color/font/textStyle\n\nexport interface MarkAttrSpec {\n key: string\n type: 'string' | 'number' | 'boolean'\n optional?: boolean\n}\n\nexport interface MarkSpec {\n name: string\n wire: MarkWireKind\n /** For `delimited`: the markdown delimiter (e.g. `**`, `*`, `~~`, `` ` ``, `__`, `==`). */\n delim?: string\n attrs?: readonly MarkAttrSpec[]\n doc?: string\n}\n\nexport const MARK_SPECS: readonly MarkSpec[] = [\n // Vanilla MD marks\n { name: 'bold', wire: 'delimited', delim: '**' },\n { name: 'italic', wire: 'delimited', delim: '*' },\n { name: 'strike', wire: 'delimited', delim: '~~' },\n { name: 'code', wire: 'delimited', delim: '`' },\n {\n name: 'link',\n wire: 'link',\n attrs: [\n { key: 'href', type: 'string' },\n { key: 'title', type: 'string', optional: true },\n ],\n },\n\n // Extended marks (lossless via MDC syntax)\n {\n name: 'underline',\n wire: 'delimited',\n delim: '__',\n doc: 'Disambiguated from bold by delimiter character. Two underscores = underline; two asterisks = bold.',\n },\n {\n name: 'highlight',\n wire: 'delimited',\n delim: '==',\n doc: 'Pandoc-style.',\n },\n {\n name: 'subscript',\n wire: 'delimited',\n delim: '~',\n doc: 'Single tilde; double tilde is strike.',\n },\n {\n name: 'superscript',\n wire: 'delimited',\n delim: '^',\n },\n {\n name: 'textStyle',\n wire: 'mdc-span',\n attrs: [\n { key: 'color', type: 'string', optional: true },\n { key: 'backgroundColor', type: 'string', optional: true },\n { key: 'fontSize', type: 'string', optional: true },\n { key: 'fontFamily', type: 'string', optional: true },\n ],\n doc: 'Wire form `:span[text]{color=\"…\" font-size=\"…\"}`. Any of the attrs may be set.',\n },\n]\n\nexport const MARK_SPEC_BY_NAME: ReadonlyMap<string, MarkSpec> = new Map(\n MARK_SPECS.map(spec => [spec.name, spec]),\n)\n\nexport const MARK_SPEC_BY_DELIM: ReadonlyMap<string, MarkSpec> = new Map(\n MARK_SPECS\n .filter((spec): spec is MarkSpec & { delim: string } => spec.wire === 'delimited' && !!spec.delim)\n .map(spec => [spec.delim, spec]),\n)\n","// ── Manifest: docId <-> filesystem path mapping ─────────────────────────────\n//\n// The manifest tracks which doc on the server maps to which file on\n// disk, plus per-doc upload (binary attachment) records and content\n// hashes for change detection.\n//\n// Filesystem I/O is INJECTABLE so Node hosts (memfs for tests, fs/promises\n// for Electron, @tauri-apps/plugin-fs for Tauri) can all use this code\n// without the package taking a hard dep on any one. If no adapter has\n// been wired and we're inside Tauri, we lazily fall back to the Tauri\n// plugin. Pure-test setups should always call `setFsAdapter()` first.\n\nexport interface FsAdapter {\n readTextFile: (path: string) => Promise<string>\n writeTextFile: (path: string, contents: string) => Promise<void>\n mkdir: (path: string, options?: { recursive?: boolean }) => Promise<void>\n readBinaryFile?: (path: string) => Promise<Uint8Array>\n writeBinaryFile?: (path: string, contents: Uint8Array) => Promise<void>\n exists?: (path: string) => Promise<boolean>\n remove?: (path: string) => Promise<void>\n}\n\nlet _adapter: FsAdapter | null = null\n\n/** Install a filesystem adapter. Call this once at boot. */\nexport function setFsAdapter(adapter: FsAdapter): void {\n _adapter = adapter\n}\n\n/** Read back the active adapter — useful for tests and for layered code. */\nexport function getFsAdapter(): FsAdapter | null {\n return _adapter\n}\n\nasync function loadFsApi(): Promise<FsAdapter> {\n if (_adapter) return _adapter\n throw new Error(\n '@abraca/convert: no FsAdapter installed. '\n + 'Call setFsAdapter({readTextFile, writeTextFile, mkdir, …}) at boot. '\n + 'Tauri hosts can pass `@tauri-apps/plugin-fs` directly; Node hosts can pass '\n + 'a wrapper over `fs/promises`; tests can use the in-memory adapter from '\n + 'tests/file-blocks.test.ts as a template.',\n )\n}\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface UploadManifestEntry {\n uploadId: string\n filename: string\n relativePath: string // e.g. \"_files/abc123/photo.jpg\"\n contentHash: string\n}\n\nexport interface ManifestEntry {\n docId: string\n relativePath: string // e.g. \"projects/my-project/_index.md\"\n contentHash: string // hash of last-written/read markdown\n lastWrittenAt: number\n lastReadAt: number\n // Code page type: the companion code file written alongside the `.md`\n // envelope (e.g. \"src/main.rs\"), and the hash of its last-synced text.\n // Present only for `code` docs.\n codePath?: string\n codeHash?: string\n uploads: UploadManifestEntry[]\n}\n\nexport interface FsSyncManifest {\n version: 2\n spaceId: string\n lastSyncAt: number\n entries: Record<string, ManifestEntry> // keyed by docId\n}\n\n// ── CRUD ─────────────────────────────────────────────────────────────────────\n\nconst MANIFEST_DIR = '.abracadabra'\nconst MANIFEST_FILE = 'manifest.json'\n\nfunction manifestPath(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/${MANIFEST_FILE}`\n}\n\nexport function manifestDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}`\n}\n\nexport function trashDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/trash`\n}\n\nexport function orphansDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/orphans`\n}\n\nexport function conflictsDir(syncDir: string): string {\n return `${syncDir}/${MANIFEST_DIR}/conflicts`\n}\n\nexport function createEmptyManifest(spaceId: string): FsSyncManifest {\n return {\n version: 2,\n spaceId,\n lastSyncAt: 0,\n entries: {}\n }\n}\n\nexport async function loadManifest(syncDir: string, spaceId: string): Promise<FsSyncManifest> {\n const fs = await loadFsApi()\n try {\n const raw = await fs.readTextFile(manifestPath(syncDir))\n const parsed = JSON.parse(raw) as FsSyncManifest\n if (parsed.version === 2) return parsed\n }\n catch {\n // missing or corrupt — return fresh\n }\n return createEmptyManifest(spaceId)\n}\n\nexport async function saveManifest(syncDir: string, manifest: FsSyncManifest): Promise<void> {\n const fs = await loadFsApi()\n const dir = `${syncDir}/${MANIFEST_DIR}`\n try {\n await fs.mkdir(dir, { recursive: true })\n }\n catch {\n // already exists\n }\n manifest.lastSyncAt = Date.now()\n await fs.writeTextFile(manifestPath(syncDir), JSON.stringify(manifest, null, 2))\n}\n\n// ── Lookups ──────────────────────────────────────────────────────────────────\n\nexport function lookupByDocId(manifest: FsSyncManifest, docId: string): ManifestEntry | undefined {\n return manifest.entries[docId]\n}\n\nexport function lookupByPath(manifest: FsSyncManifest, relativePath: string): ManifestEntry | undefined {\n for (const entry of Object.values(manifest.entries)) {\n if (entry.relativePath === relativePath) return entry\n }\n return undefined\n}\n\nexport function lookupByHash(manifest: FsSyncManifest, contentHash: string): ManifestEntry | undefined {\n for (const entry of Object.values(manifest.entries)) {\n if (entry.contentHash === contentHash) return entry\n }\n return undefined\n}\n\nexport function setEntry(manifest: FsSyncManifest, entry: ManifestEntry): void {\n manifest.entries[entry.docId] = entry\n}\n\nexport function removeEntry(manifest: FsSyncManifest, docId: string): ManifestEntry | undefined {\n const entry = manifest.entries[docId]\n if (entry) delete manifest.entries[docId]\n return entry\n}\n\n// ── Build reverse lookup (path -> docId) ─────────────────────────────────────\n\nexport function buildReverseLookup(manifest: FsSyncManifest): Map<string, string> {\n const map = new Map<string, string>()\n for (const [docId, entry] of Object.entries(manifest.entries)) {\n map.set(entry.relativePath, docId)\n }\n return map\n}\n","// ── Collision-safe path building for FS sync ─────────────────────────────────\n\nimport * as Y from 'yjs'\n\nimport type { FsSyncManifest } from './manifest.ts'\n\nexport interface FsTreeEntry {\n label: string\n parentId: string | null\n order: number\n type?: string\n meta?: any\n}\n\n/**\n * Convert a document label to a filesystem-safe filename (without extension).\n * e.g. \"My Project!\" -> \"my-project\"\n */\nexport function labelToFilename(label: string): string {\n // Nullish-safe: real trees (kanban cards, server-compacted entries)\n // contain entries with no `label`; buildRelativePath() calls this for\n // a doc AND every ancestor, so one missing label must not throw and\n // abort fs-sync for the whole tree. Empty → 'untitled' (below).\n return (\n String(label ?? '')\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '') || 'untitled'\n )\n}\n\n/**\n * Convert a filename back to a label (best-effort).\n * e.g. \"my-project\" -> \"my project\", \"my-project~a3f2\" -> \"my project\"\n */\nexport function fsFilenameToLabel(filename: string): string {\n // Strip collision suffix\n const cleaned = filename.replace(/~[a-z0-9]{4}$/, '')\n return cleaned.replace(/-/g, ' ')\n}\n\n/**\n * Check if a doc has children in the tree (needs _index.md convention).\n */\nexport function hasChildren(docId: string, treeData: Record<string, FsTreeEntry>): boolean {\n for (const entry of Object.values(treeData)) {\n if (entry.parentId === docId) return true\n }\n return false\n}\n\n/**\n * Resolve filename collisions by appending ~XXXX (first 4 chars of docId).\n * Returns the filename (without extension) that should be used.\n */\nfunction resolveCollision(\n desiredFilename: string,\n docId: string,\n parentPath: string,\n manifest: FsSyncManifest,\n isIndex: boolean\n): string {\n const ext = '.md'\n const desiredRelative = isIndex\n ? `${parentPath}${parentPath ? '/' : ''}${desiredFilename}/_index${ext}`\n : `${parentPath}${parentPath ? '/' : ''}${desiredFilename}${ext}`\n\n // Check if any other doc already claims this path\n for (const [entryDocId, entry] of Object.entries(manifest.entries)) {\n if (entryDocId === docId) continue\n if (entry.relativePath === desiredRelative) {\n // Collision — append disambiguator\n return `${desiredFilename}~${docId.substring(0, 4)}`\n }\n }\n\n return desiredFilename\n}\n\n/**\n * Build the relative path for a document (from syncDir root).\n * Handles:\n * - Ancestor chain walking\n * - _index.md for docs with children\n * - Collision resolution via ~XXXX suffix\n */\nexport function buildRelativePath(\n docId: string,\n treeData: Record<string, FsTreeEntry>,\n manifest: FsSyncManifest\n): string {\n const entry = treeData[docId]\n if (!entry) return `${docId}.md` // fallback for unknown docs\n\n // Walk up the ancestor chain to build path segments\n const segments: string[] = []\n let current: FsTreeEntry | undefined = entry\n let currentId = docId\n\n const visited = new Set<string>()\n while (current) {\n if (visited.has(currentId)) break // circular reference guard\n visited.add(currentId)\n\n segments.unshift(labelToFilename(current.label))\n if (!current.parentId) break\n currentId = current.parentId\n current = treeData[currentId]\n }\n\n // The last segment is the doc itself; everything before is parent dirs\n const filename = segments.pop()!\n const parentPath = segments.join('/')\n\n // Check if this doc needs _index.md (has children)\n const isIndex = hasChildren(docId, treeData)\n\n // Resolve collisions\n const resolvedFilename = resolveCollision(filename, docId, parentPath, manifest, isIndex)\n\n if (isIndex) {\n return `${parentPath}${parentPath ? '/' : ''}${resolvedFilename}/_index.md`\n }\n return `${parentPath}${parentPath ? '/' : ''}${resolvedFilename}.md`\n}\n\n/**\n * Companion code-file path for a `code` doc, derived from its `.md`\n * envelope path by swapping the extension. e.g.\n * `src/main.md` + `rs` -> `src/main.rs`. A code doc never has children,\n * so the `_index.md` form is not expected here, but is handled defensively.\n */\nexport function codeCompanionPath(mdRelativePath: string, fileExtension: string): string {\n const ext = fileExtension.replace(/^\\.+/, '').toLowerCase() || 'txt'\n if (mdRelativePath.endsWith('/_index.md')) {\n return `${mdRelativePath.slice(0, -'/_index.md'.length)}/_index.${ext}`\n }\n if (mdRelativePath.endsWith('.md')) {\n return `${mdRelativePath.slice(0, -'.md'.length)}.${ext}`\n }\n return `${mdRelativePath}.${ext}`\n}\n\n/**\n * Get the directory portion of a relative path for a doc.\n * For _index.md docs: returns the directory containing _index.md\n * For leaf docs: returns the parent directory\n */\nexport function getDocDir(relativePath: string): string {\n if (relativePath.endsWith('/_index.md')) {\n // e.g. \"projects/my-project/_index.md\" -> \"projects/my-project\"\n return relativePath.replace('/_index.md', '')\n }\n // e.g. \"projects/my-project/task.md\" -> \"projects/my-project\"\n const lastSlash = relativePath.lastIndexOf('/')\n return lastSlash >= 0 ? relativePath.substring(0, lastSlash) : ''\n}\n\n/**\n * Determine the parent docId from a filesystem relative path by walking the\n * path segments and matching against the tree.\n */\nexport function resolveParentFromPath(\n relativePath: string,\n treeData: Record<string, FsTreeEntry>\n): string | null {\n // Strip filename to get directory parts\n const parts = relativePath.split('/')\n parts.pop() // remove filename\n\n // For _index.md, also remove the doc's own directory name\n if (relativePath.endsWith('/_index.md') && parts.length > 0) {\n parts.pop()\n }\n\n if (parts.length === 0) return null // root-level doc\n\n let parentId: string | null = null\n for (const segment of parts) {\n const found = Object.entries(treeData).find(\n ([, e]) => labelToFilename(e.label) === segment && e.parentId === parentId\n )\n if (found) {\n parentId = found[0]\n } else {\n // Can't resolve further — return last known parent\n break\n }\n }\n return parentId\n}\n\n/**\n * Simple string hash (same as current useFsSync).\n */\nexport function simpleHash(str: string): string {\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0\n }\n return hash.toString(36)\n}\n\n/**\n * Get all tree data as a flat record.\n */\nexport function getTreeData(treeMap: any): Record<string, FsTreeEntry> {\n const data: Record<string, FsTreeEntry> = {}\n treeMap.forEach((val: any, key: string) => {\n // A tree entry may be stored as a nested Y.Map — both from the\n // per-key ⑦ write path (every SDK + cou-sh) and from server-side\n // Yrs compaction. Read it as a plain object (mirror of the\n // provider's `toPlain`); a raw Y.Map would expose\n // label/parentId/order as `undefined` and silently corrupt the\n // FS-sync tree (mass mis-parent / mis-label / spurious delete).\n //\n // Detect Y.Map by DUCK-TYPING, not `instanceof`: a host that wires\n // @abraca/dabra (which bundles its own physical `yjs`) alongside\n // this package would fail an instanceof across the two yjs copies\n // and hand back the raw Y.Map → every doc \"untitled\". toJSON()\n // works regardless of which yjs constructed the map.\n const isYMap = val instanceof Y.Map\n || (!!val && typeof val === 'object'\n && typeof (val as any).toJSON === 'function'\n && typeof (val as any).get === 'function')\n const plain = isYMap ? (val as any).toJSON() : val\n if (plain && typeof plain === 'object') {\n data[key] = plain as FsTreeEntry\n }\n })\n return data\n}\n\n/**\n * Find the next order value for a given parent (max sibling order + 1).\n */\nexport function nextOrder(treeData: Record<string, FsTreeEntry>, parentId: string | null): number {\n let max = -1\n for (const entry of Object.values(treeData)) {\n if (entry.parentId === parentId && entry.order > max) {\n max = entry.order\n }\n }\n return max + 1\n}\n"],"mappings":"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"}