function escapeHtml (str) { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } function isNumberedHeading (line) { return line.length <= 80 && /^\d+\.\s+[A-Z]/.test(line) && !/[.!?,;]$/.test(line) } function isAllCapsHeading (line) { return line.length >= 3 && !/[.!?,;]$/.test(line) && line === line.toUpperCase() && /[A-Z]/.test(line) } export function pdfTextToHtml (pageText) { if (!pageText) return '' const lines = pageText.split(/\r?\n/) let output = '' let inList = false for (const line of lines) { const stripped = line.trim() if (!stripped) { if (inList) { output += ''; inList = false } continue } if (isNumberedHeading(stripped)) { if (inList) { output += ''; inList = false } output += `
${escapeHtml(stripped)}
` } } } if (inList) output += '' return output }