import type { Paragraph, PhrasingContent, Root, RootContent } from "mdast"; // Display-only: preserve every inline node and character. Never rewrite source // files, SQL, links, existing lists or short authored paragraphs. export function readableParagraphs() { return (tree: Root) => { tree.children = tree.children.flatMap(node => { if (node.type !== "paragraph") return [node]; const length = node.children.reduce((total, child) => total + ("value" in child ? String(child.value).length : 0), 0); if (length < 360) return [node]; const paragraphs: Paragraph[] = []; let children: PhrasingContent[] = []; let size = 0; for (const child of node.children) { if (child.type !== "text") { children.push(child); if ("value" in child) size += String(child.value).length; continue; } // Boundaries must be outside inline code/emphasis/links. Decimal points // and identifiers cannot match because they have no following space. let start = 0; for (const match of child.value.matchAll(/;\s+|[.!?]\s+(?=[A-ZÀ-Ý])/g)) { const end = match.index! + match[0].length; if (size + end - start < 180) continue; children.push({ type: "text", value: child.value.slice(start, end) }); paragraphs.push({ type: "paragraph", children }); children = []; size = 0; start = end; } if (start < child.value.length) { children.push({ type: "text", value: child.value.slice(start) }); size += child.value.length - start; } } if (children.length) paragraphs.push({ type: "paragraph", children }); return paragraphs; }); }; }