From a65bb9609284d273f0aa232dbaf69597c87f5a12 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 15 Jun 2025 13:12:46 +0900 Subject: feat(blog/nuldoc): merge consecutive text nodes --- vhosts/blog/nuldoc-src/djot/to_html.ts | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'vhosts/blog/nuldoc-src/djot/to_html.ts') diff --git a/vhosts/blog/nuldoc-src/djot/to_html.ts b/vhosts/blog/nuldoc-src/djot/to_html.ts index 3a6c1e9f..5ea9b57d 100644 --- a/vhosts/blog/nuldoc-src/djot/to_html.ts +++ b/vhosts/blog/nuldoc-src/djot/to_html.ts @@ -13,6 +13,7 @@ import { } from "../dom.ts"; export default async function toHtml(doc: Document): Promise { + mergeConsecutiveTextNodes(doc); removeUnnecessaryTextNode(doc); transformLinkLikeToAnchorElement(doc); transformSectionIdAttribute(doc); @@ -23,9 +24,47 @@ export default async function toHtml(doc: Document): Promise { traverseFootnotes(doc); removeUnnecessaryParagraphNode(doc); await transformAndHighlightCodeBlockElement(doc); + mergeConsecutiveTextNodes(doc); return doc; } +function mergeConsecutiveTextNodes(doc: Document) { + forEachChildRecursively(doc.root, (n) => { + if (n.kind !== "element") { + return; + } + + const newChildren: Node[] = []; + let currentTextContent = ""; + + for (const child of n.children) { + if (child.kind === "text" && !child.raw) { + currentTextContent += child.content; + } else { + if (currentTextContent !== "") { + newChildren.push({ + kind: "text", + content: currentTextContent, + raw: false, + }); + currentTextContent = ""; + } + newChildren.push(child); + } + } + + if (currentTextContent !== "") { + newChildren.push({ + kind: "text", + content: currentTextContent, + raw: false, + }); + } + + n.children = newChildren; + }); +} + function removeUnnecessaryTextNode(doc: Document) { forEachChildRecursively(doc.root, (n) => { if (n.kind !== "element") { -- cgit v1.2.3-70-g09d2