src / htmlText.ts
/** Extract readable text from a OneNote one:T inline HTML fragment (ported
* from local-onenote-mcp's HTMLTextExtractor). */
import { Parser } from "htmlparser2";
const NEWLINE_ON_OPEN = new Set(["br", "p", "div", "li", "tr", "h1", "h2", "h3", "h4", "h5", "h6"]);
const NEWLINE_ON_CLOSE = new Set(["p", "div", "li", "tr", "h1", "h2", "h3", "h4", "h5", "h6"]);
export function htmlFragmentToText(fragment: string): string {
const parts: string[] = [];
const newline = () => {
if (parts.length === 0 || !parts[parts.length - 1].endsWith("\n")) parts.push("\n");
};
const parser = new Parser(
{
onopentag: (name) => {
if (NEWLINE_ON_OPEN.has(name.toLowerCase())) newline();
},
onclosetag: (name) => {
if (NEWLINE_ON_CLOSE.has(name.toLowerCase())) newline();
},
ontext: (text) => {
if (text) parts.push(text);
},
},
{ decodeEntities: true },
);
parser.write(fragment || "");
parser.end();
let value = parts.join("");
value = value.replace(/\x00/g, "");
value = value.replace(/[ \t]+\n/g, "\n");
value = value.replace(/\n{3,}/g, "\n\n");
return value.trim();
}