UNPKG

protoml-parser

Version:

ProtoML is a lightweight, declarative markup language designed for writing and structuring meeting protocols, notes and task lists in a human-readable and machine-parseable format.

138 lines (119 loc) 4.45 kB
const { convertHtmlToText, getVisibleMetaEntries, isProbablyHtml, renderStructuredReference, renderTemplate, stripHtml, } = require("./renderUtils"); function renderSection(title, lines) { if (!lines.length) return []; return [title, "-".repeat(title.length), ...lines, ""]; } function renderMeetingLine(line) { const source = String(line || ""); if (!source.trim()) return ""; return isProbablyHtml(source) ? convertHtmlToText(source) : stripHtml(source); } function renderText(ast, options = {}) { const out = []; const title = stripHtml( renderTemplate(ast.meta?.protocol || "Protocol - {{date}}", { ...(ast.meta || {}), date: ast.meta?.date || "Untitled", }) ); const meetingTitle = stripHtml( renderTemplate(ast.meta?.meeting_title || "Rendered Meeting", ast.meta || {}) ); out.push(title); out.push("=".repeat(title.length)); out.push(""); const metaEntries = getVisibleMetaEntries(ast, options); out.push(...renderSection("Meta", metaEntries.map(([key, value]) => `${key}: ${stripHtml(value)}`))); if (ast.participants && Object.keys(ast.participants).length) { out.push(...renderSection( "Participants", Object.entries(ast.participants).map(([, participant]) => { const alias = participant.alias ? ` (${participant.alias})` : ""; const email = participant.email ? ` - ${participant.email}` : ""; return `${participant.name}${alias}${email}`; }) )); } if (ast.subjects && Object.keys(ast.subjects).length) { out.push(...renderSection( "Subjects", Object.entries(ast.subjects).map(([id, subject]) => `${id}: ${stripHtml(subject)}`) )); } if (ast.tag_stats && Object.keys(ast.tag_stats).length) { out.push(...renderSection( "Tags", Object.entries(ast.tag_stats).map(([id, stat]) => `${id}: ${stripHtml(stat.label)} (total=${stat.total}, open=${stat.open}, done=${stat.done})` ) )); } if (ast.signatures && Object.keys(ast.signatures).length) { out.push(...renderSection( "Signatures", Object.entries(ast.signatures).map(([id, signature]) => { const parts = [signature.name, signature.role, signature.date].filter(Boolean); const notes = signature.note ? ` - ${stripHtml(signature.note)}` : ""; return `${id}: ${parts.join(" | ")}${notes}`; }) )); } if (ast.approvals && Object.keys(ast.approvals).length) { out.push(...renderSection( "Approvals", Object.entries(ast.approvals).map(([id, approval]) => { const parts = [approval.label, approval.status, approval.by, approval.date].filter(Boolean); const notes = approval.notes ? ` - ${stripHtml(approval.notes)}` : ""; return `${id}: ${parts.join(" | ")}${notes}`; }) )); } if (Array.isArray(ast.tasks) && ast.tasks.length) { const lines = []; for (const task of ast.tasks) { const marker = task.done ? "[x]" : "[ ]"; lines.push(`${marker} ${stripHtml(task.text)}`); const meta = []; if (task.assigned_to?.name) meta.push(`assigned=${task.assigned_to.name}`); if (task.subject?.label) meta.push(`subject=${stripHtml(task.subject.label)}`); if (task.tag?.label) meta.push(`tag=${stripHtml(task.tag.label)}`); if (meta.length) lines.push(` ${meta.join(" | ")}`); } out.push(...renderSection("Tasks", lines)); } if (Array.isArray(ast.notes) && ast.notes.length) { out.push(...renderSection("Notes", ast.notes.map((note) => `- ${stripHtml(note)}`))); } if (Array.isArray(ast.references) && ast.references.length) { out.push(...renderSection( "References", ast.references.map((entry) => renderStructuredReference(entry, false)) )); } if (Array.isArray(ast.attachments) && ast.attachments.length) { out.push(...renderSection( "Attachments", ast.attachments.map((entry) => renderStructuredReference(entry, false)) )); } if (Array.isArray(ast.meeting) && ast.meeting.length) { const meetingLines = [`Title: ${meetingTitle}`, ""]; for (const line of ast.meeting) { const rendered = renderMeetingLine(line); meetingLines.push(rendered); if (rendered) { meetingLines.push(""); } } out.push(...renderSection("Meeting", meetingLines)); } return out.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n"; } module.exports = renderText;