import { Node } from 'prosemirror-model'; import { slugify } from '../ponds'; export interface OutlineEntry { id: string; level: number; text: string; } /** * Heading tree for TOC plugins (data-model.md `page_content_cache`). Ids * are stable across re-derivation: same heading text + position in the * duplicate sequence always yields the same id (deterministic suffixes, * mirroring the pond-slug convention in `../ponds`). */ export function extractOutline(doc: Node): OutlineEntry[] { const entries: OutlineEntry[] = []; const seen = new Map(); doc.descendants((node) => { if (node.type.name !== 'heading') return true; const text = node.textContent.trim(); const base = slugify(text) || 'section'; const count = seen.get(base) ?? 0; seen.set(base, count + 1); const id = count === 0 ? base : `${base}-${count + 1}`; entries.push({ id, level: node.attrs.level as number, text }); return false; }); return entries; }