@pyreon/document 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/analysis/index.js.html +1 -1
  2. package/lib/confluence-Bd3ua1Ut.js.map +1 -1
  3. package/lib/csv-COrS4qdy.js.map +1 -1
  4. package/lib/discord-BLUnkEh9.js.map +1 -1
  5. package/lib/{dist-BsqdI2nY.js → dist-CYL41kqQ.js} +2 -2
  6. package/lib/dist-CYL41kqQ.js.map +1 -0
  7. package/lib/{docx-BEBOihjl.js → docx-uNAel545.js} +7 -2
  8. package/lib/docx-uNAel545.js.map +1 -0
  9. package/lib/email-D0bbfWq4.js.map +1 -1
  10. package/lib/{exceljs-BoIDUUaw.js → exceljs-BYETsesT.js} +314 -314
  11. package/lib/exceljs-BYETsesT.js.map +1 -0
  12. package/lib/google-chat-CkKCBUWC.js.map +1 -1
  13. package/lib/html-B5biprN2.js.map +1 -1
  14. package/lib/index.js +17 -8
  15. package/lib/index.js.map +1 -1
  16. package/lib/markdown-CdtlFGC0.js.map +1 -1
  17. package/lib/notion-iG2C5bEY.js.map +1 -1
  18. package/lib/{pdf-DIUQUEdj.js → pdf-IuBgTb3T.js} +9 -3
  19. package/lib/pdf-IuBgTb3T.js.map +1 -0
  20. package/lib/{pdfmake-DnmLxK4Q.js → pdfmake-CKMX5URW.js} +2 -4
  21. package/lib/pdfmake-CKMX5URW.js.map +1 -0
  22. package/lib/{pptx-Dd33oL3_.js → pptx-DXiMiYFM.js} +7 -2
  23. package/lib/pptx-DXiMiYFM.js.map +1 -0
  24. package/lib/{pptxgen.es-COcgXsyx.js → pptxgen.es-FsqHs8mD.js} +3 -6
  25. package/lib/pptxgen.es-FsqHs8mD.js.map +1 -0
  26. package/lib/sanitize-O_3j1mNJ.js.map +1 -1
  27. package/lib/slack-BI3EQwYm.js.map +1 -1
  28. package/lib/svg-BKxumy-p.js.map +1 -1
  29. package/lib/teams-Cwz9lce0.js.map +1 -1
  30. package/lib/telegram-gYFqyMXb.js.map +1 -1
  31. package/lib/text-l1XNXBOC.js.map +1 -1
  32. package/lib/types/index.d.ts +43 -39
  33. package/lib/types/index.d.ts.map +1 -1
  34. package/lib/{vfs_fonts-Df1kkZ4Y.js → vfs_fonts-Cap07Jg3.js} +2 -2
  35. package/lib/vfs_fonts-Cap07Jg3.js.map +1 -0
  36. package/lib/whatsapp-CjSGoOKx.js.map +1 -1
  37. package/lib/{xlsx-Bb5TWyXQ.js → xlsx-Cvu4LBNy.js} +8 -2
  38. package/lib/xlsx-Cvu4LBNy.js.map +1 -0
  39. package/package.json +19 -7
  40. package/src/builder.ts +53 -44
  41. package/src/download.ts +32 -36
  42. package/src/env.d.ts +3 -17
  43. package/src/index.ts +6 -8
  44. package/src/nodes.ts +45 -45
  45. package/src/render.ts +45 -118
  46. package/src/renderers/confluence.ts +64 -80
  47. package/src/renderers/csv.ts +11 -18
  48. package/src/renderers/discord.ts +38 -50
  49. package/src/renderers/docx.ts +78 -120
  50. package/src/renderers/email.ts +73 -92
  51. package/src/renderers/google-chat.ts +35 -47
  52. package/src/renderers/html.ts +78 -101
  53. package/src/renderers/markdown.ts +43 -53
  54. package/src/renderers/notion.ts +63 -85
  55. package/src/renderers/pdf.ts +92 -115
  56. package/src/renderers/pptx.ts +60 -66
  57. package/src/renderers/slack.ts +49 -61
  58. package/src/renderers/svg.ts +49 -63
  59. package/src/renderers/teams.ts +68 -80
  60. package/src/renderers/telegram.ts +40 -54
  61. package/src/renderers/text.ts +44 -66
  62. package/src/renderers/whatsapp.ts +34 -48
  63. package/src/renderers/xlsx.ts +47 -61
  64. package/src/sanitize.ts +21 -25
  65. package/src/tests/document.test.ts +1337 -1385
  66. package/src/tests/stress.test.ts +111 -111
  67. package/src/types.ts +66 -65
  68. package/lib/dist-BsqdI2nY.js.map +0 -1
  69. package/lib/docx-BEBOihjl.js.map +0 -1
  70. package/lib/exceljs-BoIDUUaw.js.map +0 -1
  71. package/lib/pdf-DIUQUEdj.js.map +0 -1
  72. package/lib/pdfmake-DnmLxK4Q.js.map +0 -1
  73. package/lib/pptx-Dd33oL3_.js.map +0 -1
  74. package/lib/pptxgen.es-COcgXsyx.js.map +0 -1
  75. package/lib/vfs_fonts-Df1kkZ4Y.js.map +0 -1
  76. package/lib/xlsx-Bb5TWyXQ.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"google-chat-CkKCBUWC.js","names":[],"sources":["../src/renderers/google-chat.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from '../sanitize'\nimport type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * Google Chat renderer — outputs Card V2 JSON for Google Chat API.\n * Cards can be sent via webhooks, Chat API, or Apps Script.\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) =>\n typeof c === 'string' ? c : getTextContent((c as DocNode).children),\n )\n .join('')\n}\n\ninterface CardWidget {\n [key: string]: unknown\n}\n\nfunction nodeToWidgets(node: DocNode): CardWidget[] {\n const p = node.props\n const widgets: CardWidget[] = []\n\n switch (node.type) {\n case 'document':\n case 'page':\n case 'section':\n case 'row':\n case 'column':\n for (const child of node.children) {\n if (typeof child !== 'string') {\n widgets.push(...nodeToWidgets(child))\n }\n }\n break\n\n case 'heading': {\n const text = getTextContent(node.children)\n widgets.push({\n decoratedText: {\n topLabel: '',\n text: `<b>${text}</b>`,\n wrapText: true,\n },\n })\n break\n }\n\n case 'text': {\n let text = getTextContent(node.children)\n if (p.bold) text = `<b>${text}</b>`\n if (p.italic) text = `<i>${text}</i>`\n if (p.strikethrough) text = `<s>${text}</s>`\n widgets.push({\n textParagraph: { text },\n })\n break\n }\n\n case 'link': {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: { text: `<a href=\"${href}\">${text}</a>` },\n })\n break\n }\n\n case 'image': {\n const src = sanitizeImageSrc(p.src as string)\n if (src.startsWith('http')) {\n widgets.push({\n image: {\n imageUrl: src,\n altText: (p.alt as string) ?? 'Image',\n },\n })\n }\n break\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(\n resolveColumn,\n )\n const rows = (p.rows ?? []) as (string | number)[][]\n\n // Google Chat Cards don't have native tables — use grid or formatted text\n const header = columns.map((c) => `<b>${c.header}</b>`).join(' | ')\n const body = rows\n .map((row) => row.map((c) => String(c ?? '')).join(' | '))\n .join('\\n')\n\n widgets.push({\n textParagraph: { text: `${header}\\n${body}` },\n })\n break\n }\n\n case 'list': {\n const ordered = p.ordered as boolean | undefined\n const items = node.children\n .filter((c): c is DocNode => typeof c !== 'string')\n .map((item, i) => {\n const prefix = ordered ? `${i + 1}.` : '•'\n return `${prefix} ${getTextContent(item.children)}`\n })\n .join('\\n')\n widgets.push({\n textParagraph: { text: items },\n })\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: {\n text: `<font color=\"#333333\"><code>${text}</code></font>`,\n },\n })\n break\n }\n\n case 'divider':\n case 'page-break':\n widgets.push({ divider: {} })\n break\n\n case 'spacer':\n // No direct equivalent — skip\n break\n\n case 'button': {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n widgets.push({\n buttonList: {\n buttons: [\n {\n text,\n onClick: { openLink: { url: href } },\n color: {\n red: 0.31,\n green: 0.27,\n blue: 0.89,\n alpha: 1,\n },\n },\n ],\n },\n })\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: { text: `<i>\"${text}\"</i>` },\n })\n break\n }\n }\n\n return widgets\n}\n\nexport const googleChatRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const widgets = nodeToWidgets(node)\n\n // Extract title from first heading or document title\n let title = (node.props.title as string) ?? ''\n if (!title) {\n const firstHeading = node.children.find(\n (c): c is DocNode => typeof c !== 'string' && c.type === 'heading',\n )\n if (firstHeading) title = getTextContent(firstHeading.children)\n }\n\n const card = {\n cardsV2: [\n {\n cardId: 'document',\n card: {\n header: title\n ? { title, subtitle: (node.props.subject as string) ?? undefined }\n : undefined,\n sections: [\n {\n widgets,\n },\n ],\n },\n },\n ],\n }\n\n return JSON.stringify(card, null, 2)\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"google-chat-CkKCBUWC.js","names":[],"sources":["../src/renderers/google-chat.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from \"../sanitize\"\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from \"../types\"\n\n/**\n * Google Chat renderer — outputs Card V2 JSON for Google Chat API.\n * Cards can be sent via webhooks, Chat API, or Apps Script.\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === \"string\" ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) => (typeof c === \"string\" ? c : getTextContent((c as DocNode).children)))\n .join(\"\")\n}\n\ninterface CardWidget {\n [key: string]: unknown\n}\n\nfunction nodeToWidgets(node: DocNode): CardWidget[] {\n const p = node.props\n const widgets: CardWidget[] = []\n\n switch (node.type) {\n case \"document\":\n case \"page\":\n case \"section\":\n case \"row\":\n case \"column\":\n for (const child of node.children) {\n if (typeof child !== \"string\") {\n widgets.push(...nodeToWidgets(child))\n }\n }\n break\n\n case \"heading\": {\n const text = getTextContent(node.children)\n widgets.push({\n decoratedText: {\n topLabel: \"\",\n text: `<b>${text}</b>`,\n wrapText: true,\n },\n })\n break\n }\n\n case \"text\": {\n let text = getTextContent(node.children)\n if (p.bold) text = `<b>${text}</b>`\n if (p.italic) text = `<i>${text}</i>`\n if (p.strikethrough) text = `<s>${text}</s>`\n widgets.push({\n textParagraph: { text },\n })\n break\n }\n\n case \"link\": {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: { text: `<a href=\"${href}\">${text}</a>` },\n })\n break\n }\n\n case \"image\": {\n const src = sanitizeImageSrc(p.src as string)\n if (src.startsWith(\"http\")) {\n widgets.push({\n image: {\n imageUrl: src,\n altText: (p.alt as string) ?? \"Image\",\n },\n })\n }\n break\n }\n\n case \"table\": {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n\n // Google Chat Cards don't have native tables — use grid or formatted text\n const header = columns.map((c) => `<b>${c.header}</b>`).join(\" | \")\n const body = rows.map((row) => row.map((c) => String(c ?? \"\")).join(\" | \")).join(\"\\n\")\n\n widgets.push({\n textParagraph: { text: `${header}\\n${body}` },\n })\n break\n }\n\n case \"list\": {\n const ordered = p.ordered as boolean | undefined\n const items = node.children\n .filter((c): c is DocNode => typeof c !== \"string\")\n .map((item, i) => {\n const prefix = ordered ? `${i + 1}.` : \"•\"\n return `${prefix} ${getTextContent(item.children)}`\n })\n .join(\"\\n\")\n widgets.push({\n textParagraph: { text: items },\n })\n break\n }\n\n case \"code\": {\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: {\n text: `<font color=\"#333333\"><code>${text}</code></font>`,\n },\n })\n break\n }\n\n case \"divider\":\n case \"page-break\":\n widgets.push({ divider: {} })\n break\n\n case \"spacer\":\n // No direct equivalent — skip\n break\n\n case \"button\": {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n widgets.push({\n buttonList: {\n buttons: [\n {\n text,\n onClick: { openLink: { url: href } },\n color: {\n red: 0.31,\n green: 0.27,\n blue: 0.89,\n alpha: 1,\n },\n },\n ],\n },\n })\n break\n }\n\n case \"quote\": {\n const text = getTextContent(node.children)\n widgets.push({\n textParagraph: { text: `<i>\"${text}\"</i>` },\n })\n break\n }\n }\n\n return widgets\n}\n\nexport const googleChatRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const widgets = nodeToWidgets(node)\n\n // Extract title from first heading or document title\n let title = (node.props.title as string) ?? \"\"\n if (!title) {\n const firstHeading = node.children.find(\n (c): c is DocNode => typeof c !== \"string\" && c.type === \"heading\",\n )\n if (firstHeading) title = getTextContent(firstHeading.children)\n }\n\n const card = {\n cardsV2: [\n {\n cardId: \"document\",\n card: {\n header: title\n ? { title, subtitle: (node.props.subject as string) ?? undefined }\n : undefined,\n sections: [\n {\n widgets,\n },\n ],\n },\n },\n ],\n }\n\n return JSON.stringify(card, null, 2)\n },\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"html-B5biprN2.js","names":[],"sources":["../src/renderers/html.ts"],"sourcesContent":["import {\n sanitizeColor,\n sanitizeHref,\n sanitizeImageSrc,\n sanitizeStyle,\n} from '../sanitize'\nimport type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction styleStr(styles: Record<string, string | number | undefined>): string {\n const parts: string[] = []\n for (const [k, v] of Object.entries(styles)) {\n if (v != null && v !== '') {\n const prop = k.replace(/([A-Z])/g, '-$1').toLowerCase()\n parts.push(`${prop}:${typeof v === 'number' ? `${v}px` : v}`)\n }\n }\n return parts.length > 0 ? ` style=\"${parts.join(';')}\"` : ''\n}\n\nfunction padStr(\n pad: number | [number, number] | [number, number, number, number] | undefined,\n): string | undefined {\n if (pad == null) return undefined\n if (typeof pad === 'number') return `${pad}px`\n if (pad.length === 2) return `${pad[0]}px ${pad[1]}px`\n return `${pad[0]}px ${pad[1]}px ${pad[2]}px ${pad[3]}px`\n}\n\nfunction renderChild(child: DocChild): string {\n if (typeof child === 'string') return escapeHtml(child)\n return renderNode(child)\n}\n\nfunction renderChildren(children: DocChild[]): string {\n return children.map(renderChild).join('')\n}\n\nfunction renderNode(node: DocNode): string {\n const p = node.props\n\n switch (node.type) {\n case 'document': {\n const lang = (p.language as string) ?? 'en'\n const title = p.title\n ? `<title>${escapeHtml(p.title as string)}</title>`\n : ''\n return `<!DOCTYPE html><html lang=\"${lang}\"><head><meta charset=\"utf-8\">${title}<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"></head><body>${renderChildren(node.children)}</body></html>`\n }\n\n case 'page': {\n const margin = padStr(p.margin as PageMargin)\n return `<div${styleStr({ maxWidth: '800px', margin: margin ?? '0 auto', padding: margin ?? '40px' })}>${renderChildren(node.children)}</div>`\n }\n\n case 'section': {\n const dir = (p.direction as string) ?? 'column'\n return `<div${styleStr({\n display: dir === 'row' ? 'flex' : 'block',\n flexDirection: dir === 'row' ? 'row' : undefined,\n gap: p.gap as number | undefined,\n padding: padStr(p.padding as PageMargin),\n background: sanitizeColor(p.background as string | undefined),\n borderRadius: p.borderRadius as number | undefined,\n })}>${renderChildren(node.children)}</div>`\n }\n\n case 'row':\n return `<div${styleStr({ display: 'flex', gap: p.gap as number | undefined, alignItems: p.align as string | undefined })}>${renderChildren(node.children)}</div>`\n\n case 'column':\n return `<div${styleStr({ flex: p.width ? undefined : '1', width: p.width as string | undefined, textAlign: p.align as string | undefined })}>${renderChildren(node.children)}</div>`\n\n case 'heading': {\n const level = (p.level as number) ?? 1\n const tag = `h${Math.min(Math.max(level, 1), 6)}`\n return `<${tag}${styleStr({ color: sanitizeColor(p.color as string | undefined), textAlign: p.align as string | undefined })}>${renderChildren(node.children)}</${tag}>`\n }\n\n case 'text': {\n return `<p${styleStr({\n fontSize: p.size as number | undefined,\n color: sanitizeColor(p.color as string | undefined),\n fontWeight: p.bold ? 'bold' : undefined,\n fontStyle: p.italic ? 'italic' : undefined,\n textDecoration: p.underline\n ? 'underline'\n : p.strikethrough\n ? 'line-through'\n : undefined,\n textAlign: p.align as string | undefined,\n lineHeight: p.lineHeight as number | undefined,\n })}>${renderChildren(node.children)}</p>`\n }\n\n case 'link':\n return `<a href=\"${escapeHtml(sanitizeHref(p.href as string))}\"${styleStr({ color: sanitizeColor(p.color as string | undefined) })}>${renderChildren(node.children)}</a>`\n\n case 'image': {\n const alignStyle =\n p.align === 'center'\n ? 'display:block;margin:0 auto'\n : p.align === 'right'\n ? 'display:block;margin-left:auto'\n : ''\n const img = `<img src=\"${escapeHtml(sanitizeImageSrc(p.src as string))}\"${p.width ? ` width=\"${p.width}\"` : ''}${p.height ? ` height=\"${p.height}\"` : ''}${p.alt ? ` alt=\"${escapeHtml(p.alt as string)}\"` : ''}${alignStyle ? ` style=\"${sanitizeStyle(alignStyle)}\"` : ''} />`\n if (p.caption) {\n return `<figure${p.align === 'center' ? ' style=\"text-align:center\"' : ''}>${img}<figcaption>${escapeHtml(p.caption as string)}</figcaption></figure>`\n }\n return img\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(\n resolveColumn,\n )\n const rows = (p.rows ?? []) as (string | number)[][]\n const hs = p.headerStyle as\n | { background?: string; color?: string; bold?: boolean }\n | undefined\n const striped = p.striped as boolean | undefined\n const bordered = p.bordered as boolean | undefined\n const borderStyle = bordered\n ? 'border:1px solid #ddd;border-collapse:collapse;'\n : 'border-collapse:collapse;'\n\n let html = `<table style=\"width:100%;${borderStyle}\">`\n if (p.caption)\n html += `<caption>${escapeHtml(p.caption as string)}</caption>`\n\n html += '<thead><tr>'\n for (const col of columns) {\n const cellBorder = bordered ? 'border:1px solid #ddd;' : ''\n const bgStyle = hs?.background\n ? `background:${sanitizeColor(hs.background)};`\n : ''\n const colorStyle = hs?.color ? `color:${sanitizeColor(hs.color)};` : ''\n const fontStyle = hs?.bold !== false ? 'font-weight:bold;' : ''\n const alignStyle = col.align ? `text-align:${col.align};` : ''\n const widthStyle = col.width\n ? `width:${typeof col.width === 'number' ? `${col.width}px` : col.width};`\n : ''\n html += `<th style=\"${cellBorder}${bgStyle}${colorStyle}${fontStyle}${alignStyle}${widthStyle}padding:8px\">${escapeHtml(col.header)}</th>`\n }\n html += '</tr></thead>'\n\n html += '<tbody>'\n for (let i = 0; i < rows.length; i++) {\n const rowBg =\n striped && i % 2 === 1 ? ' style=\"background:#f9f9f9\"' : ''\n html += `<tr${rowBg}>`\n for (let j = 0; j < columns.length; j++) {\n const cellBorder = bordered ? 'border:1px solid #ddd;' : ''\n const col = columns[j]\n const alignStyle = col?.align ? `text-align:${col.align};` : ''\n html += `<td style=\"${cellBorder}${alignStyle}padding:8px\">${escapeHtml(String(rows[i]?.[j] ?? ''))}</td>`\n }\n html += '</tr>'\n }\n html += '</tbody></table>'\n return html\n }\n\n case 'list': {\n const tag = p.ordered ? 'ol' : 'ul'\n return `<${tag}>${renderChildren(node.children)}</${tag}>`\n }\n\n case 'list-item':\n return `<li>${renderChildren(node.children)}</li>`\n\n case 'code':\n return `<pre style=\"background:#f5f5f5;padding:12px;border-radius:4px;overflow-x:auto\"><code>${escapeHtml(renderChildren(node.children))}</code></pre>`\n\n case 'divider': {\n const color = sanitizeColor((p.color as string) ?? '#ddd')\n const thickness = (p.thickness as number) ?? 1\n return `<hr style=\"border:none;border-top:${thickness}px solid ${color};margin:16px 0\" />`\n }\n\n case 'page-break':\n return '<div style=\"page-break-after:always;break-after:page\"></div>'\n\n case 'spacer':\n return `<div style=\"height:${p.height}px\"></div>`\n\n case 'button': {\n const bg = sanitizeColor((p.background as string) ?? '#4f46e5')\n const color = sanitizeColor((p.color as string) ?? '#fff')\n const radius = (p.borderRadius as number) ?? 4\n const pad = padStr((p.padding ?? [12, 24]) as [number, number])\n const align = (p.align as string) ?? 'left'\n return `<div style=\"text-align:${align}\"><a href=\"${escapeHtml(sanitizeHref(p.href as string))}\" style=\"display:inline-block;background:${bg};color:${color};padding:${pad};border-radius:${radius}px;text-decoration:none;font-weight:bold\">${renderChildren(node.children)}</a></div>`\n }\n\n case 'quote': {\n const borderColor = sanitizeColor((p.borderColor as string) ?? '#ddd')\n return `<blockquote style=\"margin:0;padding:12px 20px;border-left:4px solid ${borderColor};color:#555\">${renderChildren(node.children)}</blockquote>`\n }\n\n default:\n return renderChildren(node.children)\n }\n}\n\ntype PageMargin = number | [number, number] | [number, number, number, number]\n\nexport const htmlRenderer: DocumentRenderer = {\n async render(node: DocNode, options?: RenderOptions): Promise<string> {\n let html = renderNode(node)\n if (options?.direction === 'rtl') {\n html = html.replace('<body>', '<body dir=\"rtl\" style=\"direction:rtl\">')\n }\n return html\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"html-B5biprN2.js","names":[],"sources":["../src/renderers/html.ts"],"sourcesContent":["import { sanitizeColor, sanitizeHref, sanitizeImageSrc, sanitizeStyle } from \"../sanitize\"\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from \"../types\"\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n}\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === \"string\" ? { header: col } : col\n}\n\nfunction styleStr(styles: Record<string, string | number | undefined>): string {\n const parts: string[] = []\n for (const [k, v] of Object.entries(styles)) {\n if (v != null && v !== \"\") {\n const prop = k.replace(/([A-Z])/g, \"-$1\").toLowerCase()\n parts.push(`${prop}:${typeof v === \"number\" ? `${v}px` : v}`)\n }\n }\n return parts.length > 0 ? ` style=\"${parts.join(\";\")}\"` : \"\"\n}\n\nfunction padStr(\n pad: number | [number, number] | [number, number, number, number] | undefined,\n): string | undefined {\n if (pad == null) return undefined\n if (typeof pad === \"number\") return `${pad}px`\n if (pad.length === 2) return `${pad[0]}px ${pad[1]}px`\n return `${pad[0]}px ${pad[1]}px ${pad[2]}px ${pad[3]}px`\n}\n\nfunction renderChild(child: DocChild): string {\n if (typeof child === \"string\") return escapeHtml(child)\n return renderNode(child)\n}\n\nfunction renderChildren(children: DocChild[]): string {\n return children.map(renderChild).join(\"\")\n}\n\nfunction renderNode(node: DocNode): string {\n const p = node.props\n\n switch (node.type) {\n case \"document\": {\n const lang = (p.language as string) ?? \"en\"\n const title = p.title ? `<title>${escapeHtml(p.title as string)}</title>` : \"\"\n return `<!DOCTYPE html><html lang=\"${lang}\"><head><meta charset=\"utf-8\">${title}<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"></head><body>${renderChildren(node.children)}</body></html>`\n }\n\n case \"page\": {\n const margin = padStr(p.margin as PageMargin)\n return `<div${styleStr({ maxWidth: \"800px\", margin: margin ?? \"0 auto\", padding: margin ?? \"40px\" })}>${renderChildren(node.children)}</div>`\n }\n\n case \"section\": {\n const dir = (p.direction as string) ?? \"column\"\n return `<div${styleStr({\n display: dir === \"row\" ? \"flex\" : \"block\",\n flexDirection: dir === \"row\" ? \"row\" : undefined,\n gap: p.gap as number | undefined,\n padding: padStr(p.padding as PageMargin),\n background: sanitizeColor(p.background as string | undefined),\n borderRadius: p.borderRadius as number | undefined,\n })}>${renderChildren(node.children)}</div>`\n }\n\n case \"row\":\n return `<div${styleStr({ display: \"flex\", gap: p.gap as number | undefined, alignItems: p.align as string | undefined })}>${renderChildren(node.children)}</div>`\n\n case \"column\":\n return `<div${styleStr({ flex: p.width ? undefined : \"1\", width: p.width as string | undefined, textAlign: p.align as string | undefined })}>${renderChildren(node.children)}</div>`\n\n case \"heading\": {\n const level = (p.level as number) ?? 1\n const tag = `h${Math.min(Math.max(level, 1), 6)}`\n return `<${tag}${styleStr({ color: sanitizeColor(p.color as string | undefined), textAlign: p.align as string | undefined })}>${renderChildren(node.children)}</${tag}>`\n }\n\n case \"text\": {\n return `<p${styleStr({\n fontSize: p.size as number | undefined,\n color: sanitizeColor(p.color as string | undefined),\n fontWeight: p.bold ? \"bold\" : undefined,\n fontStyle: p.italic ? \"italic\" : undefined,\n textDecoration: p.underline ? \"underline\" : p.strikethrough ? \"line-through\" : undefined,\n textAlign: p.align as string | undefined,\n lineHeight: p.lineHeight as number | undefined,\n })}>${renderChildren(node.children)}</p>`\n }\n\n case \"link\":\n return `<a href=\"${escapeHtml(sanitizeHref(p.href as string))}\"${styleStr({ color: sanitizeColor(p.color as string | undefined) })}>${renderChildren(node.children)}</a>`\n\n case \"image\": {\n const alignStyle =\n p.align === \"center\"\n ? \"display:block;margin:0 auto\"\n : p.align === \"right\"\n ? \"display:block;margin-left:auto\"\n : \"\"\n const img = `<img src=\"${escapeHtml(sanitizeImageSrc(p.src as string))}\"${p.width ? ` width=\"${p.width}\"` : \"\"}${p.height ? ` height=\"${p.height}\"` : \"\"}${p.alt ? ` alt=\"${escapeHtml(p.alt as string)}\"` : \"\"}${alignStyle ? ` style=\"${sanitizeStyle(alignStyle)}\"` : \"\"} />`\n if (p.caption) {\n return `<figure${p.align === \"center\" ? ' style=\"text-align:center\"' : \"\"}>${img}<figcaption>${escapeHtml(p.caption as string)}</figcaption></figure>`\n }\n return img\n }\n\n case \"table\": {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n const hs = p.headerStyle as\n | { background?: string; color?: string; bold?: boolean }\n | undefined\n const striped = p.striped as boolean | undefined\n const bordered = p.bordered as boolean | undefined\n const borderStyle = bordered\n ? \"border:1px solid #ddd;border-collapse:collapse;\"\n : \"border-collapse:collapse;\"\n\n let html = `<table style=\"width:100%;${borderStyle}\">`\n if (p.caption) html += `<caption>${escapeHtml(p.caption as string)}</caption>`\n\n html += \"<thead><tr>\"\n for (const col of columns) {\n const cellBorder = bordered ? \"border:1px solid #ddd;\" : \"\"\n const bgStyle = hs?.background ? `background:${sanitizeColor(hs.background)};` : \"\"\n const colorStyle = hs?.color ? `color:${sanitizeColor(hs.color)};` : \"\"\n const fontStyle = hs?.bold !== false ? \"font-weight:bold;\" : \"\"\n const alignStyle = col.align ? `text-align:${col.align};` : \"\"\n const widthStyle = col.width\n ? `width:${typeof col.width === \"number\" ? `${col.width}px` : col.width};`\n : \"\"\n html += `<th style=\"${cellBorder}${bgStyle}${colorStyle}${fontStyle}${alignStyle}${widthStyle}padding:8px\">${escapeHtml(col.header)}</th>`\n }\n html += \"</tr></thead>\"\n\n html += \"<tbody>\"\n for (let i = 0; i < rows.length; i++) {\n const rowBg = striped && i % 2 === 1 ? ' style=\"background:#f9f9f9\"' : \"\"\n html += `<tr${rowBg}>`\n for (let j = 0; j < columns.length; j++) {\n const cellBorder = bordered ? \"border:1px solid #ddd;\" : \"\"\n const col = columns[j]\n const alignStyle = col?.align ? `text-align:${col.align};` : \"\"\n html += `<td style=\"${cellBorder}${alignStyle}padding:8px\">${escapeHtml(String(rows[i]?.[j] ?? \"\"))}</td>`\n }\n html += \"</tr>\"\n }\n html += \"</tbody></table>\"\n return html\n }\n\n case \"list\": {\n const tag = p.ordered ? \"ol\" : \"ul\"\n return `<${tag}>${renderChildren(node.children)}</${tag}>`\n }\n\n case \"list-item\":\n return `<li>${renderChildren(node.children)}</li>`\n\n case \"code\":\n return `<pre style=\"background:#f5f5f5;padding:12px;border-radius:4px;overflow-x:auto\"><code>${escapeHtml(renderChildren(node.children))}</code></pre>`\n\n case \"divider\": {\n const color = sanitizeColor((p.color as string) ?? \"#ddd\")\n const thickness = (p.thickness as number) ?? 1\n return `<hr style=\"border:none;border-top:${thickness}px solid ${color};margin:16px 0\" />`\n }\n\n case \"page-break\":\n return '<div style=\"page-break-after:always;break-after:page\"></div>'\n\n case \"spacer\":\n return `<div style=\"height:${p.height}px\"></div>`\n\n case \"button\": {\n const bg = sanitizeColor((p.background as string) ?? \"#4f46e5\")\n const color = sanitizeColor((p.color as string) ?? \"#fff\")\n const radius = (p.borderRadius as number) ?? 4\n const pad = padStr((p.padding ?? [12, 24]) as [number, number])\n const align = (p.align as string) ?? \"left\"\n return `<div style=\"text-align:${align}\"><a href=\"${escapeHtml(sanitizeHref(p.href as string))}\" style=\"display:inline-block;background:${bg};color:${color};padding:${pad};border-radius:${radius}px;text-decoration:none;font-weight:bold\">${renderChildren(node.children)}</a></div>`\n }\n\n case \"quote\": {\n const borderColor = sanitizeColor((p.borderColor as string) ?? \"#ddd\")\n return `<blockquote style=\"margin:0;padding:12px 20px;border-left:4px solid ${borderColor};color:#555\">${renderChildren(node.children)}</blockquote>`\n }\n\n default:\n return renderChildren(node.children)\n }\n}\n\ntype PageMargin = number | [number, number] | [number, number, number, number]\n\nexport const htmlRenderer: DocumentRenderer = {\n async render(node: DocNode, options?: RenderOptions): Promise<string> {\n let html = renderNode(node)\n if (options?.direction === \"rtl\") {\n html = html.replace(\"<body>\", '<body dir=\"rtl\" style=\"direction:rtl\">')\n }\n return html\n },\n}\n"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -29,10 +29,10 @@ registerRenderer("email", () => import("./email-D0bbfWq4.js").then((m) => m.emai
29
29
  registerRenderer("md", () => import("./markdown-CdtlFGC0.js").then((m) => m.markdownRenderer));
30
30
  registerRenderer("text", () => import("./text-l1XNXBOC.js").then((m) => m.textRenderer));
31
31
  registerRenderer("csv", () => import("./csv-COrS4qdy.js").then((m) => m.csvRenderer));
32
- registerRenderer("pdf", () => import("./pdf-DIUQUEdj.js").then((m) => m.pdfRenderer));
33
- registerRenderer("docx", () => import("./docx-BEBOihjl.js").then((m) => m.docxRenderer));
34
- registerRenderer("xlsx", () => import("./xlsx-Bb5TWyXQ.js").then((m) => m.xlsxRenderer));
35
- registerRenderer("pptx", () => import("./pptx-Dd33oL3_.js").then((m) => m.pptxRenderer));
32
+ registerRenderer("pdf", () => import("./pdf-IuBgTb3T.js").then((m) => m.pdfRenderer));
33
+ registerRenderer("docx", () => import("./docx-uNAel545.js").then((m) => m.docxRenderer));
34
+ registerRenderer("xlsx", () => import("./xlsx-Cvu4LBNy.js").then((m) => m.xlsxRenderer));
35
+ registerRenderer("pptx", () => import("./pptx-DXiMiYFM.js").then((m) => m.pptxRenderer));
36
36
  registerRenderer("slack", () => import("./slack-BI3EQwYm.js").then((m) => m.slackRenderer));
37
37
  registerRenderer("svg", () => import("./svg-BKxumy-p.js").then((m) => m.svgRenderer));
38
38
  registerRenderer("teams", () => import("./teams-Cwz9lce0.js").then((m) => m.teamsRenderer));
@@ -77,10 +77,10 @@ function _resetRenderers() {
77
77
  registerRenderer("md", () => import("./markdown-CdtlFGC0.js").then((m) => m.markdownRenderer));
78
78
  registerRenderer("text", () => import("./text-l1XNXBOC.js").then((m) => m.textRenderer));
79
79
  registerRenderer("csv", () => import("./csv-COrS4qdy.js").then((m) => m.csvRenderer));
80
- registerRenderer("pdf", () => import("./pdf-DIUQUEdj.js").then((m) => m.pdfRenderer));
81
- registerRenderer("docx", () => import("./docx-BEBOihjl.js").then((m) => m.docxRenderer));
82
- registerRenderer("xlsx", () => import("./xlsx-Bb5TWyXQ.js").then((m) => m.xlsxRenderer));
83
- registerRenderer("pptx", () => import("./pptx-Dd33oL3_.js").then((m) => m.pptxRenderer));
80
+ registerRenderer("pdf", () => import("./pdf-IuBgTb3T.js").then((m) => m.pdfRenderer));
81
+ registerRenderer("docx", () => import("./docx-uNAel545.js").then((m) => m.docxRenderer));
82
+ registerRenderer("xlsx", () => import("./xlsx-Cvu4LBNy.js").then((m) => m.xlsxRenderer));
83
+ registerRenderer("pptx", () => import("./pptx-DXiMiYFM.js").then((m) => m.pptxRenderer));
84
84
  registerRenderer("slack", () => import("./slack-BI3EQwYm.js").then((m) => m.slackRenderer));
85
85
  registerRenderer("svg", () => import("./svg-BKxumy-p.js").then((m) => m.svgRenderer));
86
86
  registerRenderer("teams", () => import("./teams-Cwz9lce0.js").then((m) => m.teamsRenderer));
@@ -515,6 +515,15 @@ function createDocument(props = {}) {
515
515
  sections.push(PageBreak());
516
516
  return builder;
517
517
  },
518
+ add(node) {
519
+ if (Array.isArray(node)) sections.push(...node);
520
+ else sections.push(node);
521
+ return builder;
522
+ },
523
+ section(children) {
524
+ sections.push(Section({ children }));
525
+ return builder;
526
+ },
518
527
  chart(instance, p) {
519
528
  const inst = instance;
520
529
  if (inst?.getDataURL) {
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/render.ts","../src/download.ts","../src/nodes.ts","../src/builder.ts"],"sourcesContent":["import type {\n DocNode,\n DocumentRenderer,\n OutputFormat,\n RenderOptions,\n RenderResult,\n} from './types'\n\n// ─── Renderer Registry ──────────────────────────────────────────────────────\n\nconst renderers = new Map<\n string,\n DocumentRenderer | (() => Promise<DocumentRenderer>)\n>()\n\n/**\n * Register a custom renderer for a format.\n *\n * @example\n * ```ts\n * registerRenderer('thermal', {\n * render(node, options) {\n * // Walk nodes → ESC/POS commands\n * return escPosBuffer\n * },\n * })\n *\n * await render(receipt, 'thermal')\n * ```\n */\nexport function registerRenderer(\n format: string,\n renderer: DocumentRenderer | (() => Promise<DocumentRenderer>),\n): void {\n renderers.set(format, renderer)\n}\n\n/**\n * Remove a registered renderer.\n */\nexport function unregisterRenderer(format: string): void {\n renderers.delete(format)\n}\n\n// ─── Built-in Renderer Loaders ──────────────────────────────────────────────\n\n// Built-in renderers are registered lazily — only loaded when first used.\n\nregisterRenderer('html', () =>\n import('./renderers/html').then((m) => m.htmlRenderer),\n)\n\nregisterRenderer('email', () =>\n import('./renderers/email').then((m) => m.emailRenderer),\n)\n\nregisterRenderer('md', () =>\n import('./renderers/markdown').then((m) => m.markdownRenderer),\n)\n\nregisterRenderer('text', () =>\n import('./renderers/text').then((m) => m.textRenderer),\n)\n\nregisterRenderer('csv', () =>\n import('./renderers/csv').then((m) => m.csvRenderer),\n)\n\nregisterRenderer('pdf', () =>\n import('./renderers/pdf').then((m) => m.pdfRenderer),\n)\n\nregisterRenderer('docx', () =>\n import('./renderers/docx').then((m) => m.docxRenderer),\n)\n\nregisterRenderer('xlsx', () =>\n import('./renderers/xlsx').then((m) => m.xlsxRenderer),\n)\n\nregisterRenderer('pptx', () =>\n import('./renderers/pptx').then((m) => m.pptxRenderer),\n)\n\nregisterRenderer('slack', () =>\n import('./renderers/slack').then((m) => m.slackRenderer),\n)\n\nregisterRenderer('svg', () =>\n import('./renderers/svg').then((m) => m.svgRenderer),\n)\n\nregisterRenderer('teams', () =>\n import('./renderers/teams').then((m) => m.teamsRenderer),\n)\n\nregisterRenderer('discord', () =>\n import('./renderers/discord').then((m) => m.discordRenderer),\n)\n\nregisterRenderer('telegram', () =>\n import('./renderers/telegram').then((m) => m.telegramRenderer),\n)\n\nregisterRenderer('notion', () =>\n import('./renderers/notion').then((m) => m.notionRenderer),\n)\n\nregisterRenderer('confluence', () =>\n import('./renderers/confluence').then((m) => m.confluenceRenderer),\n)\n\nregisterRenderer('whatsapp', () =>\n import('./renderers/whatsapp').then((m) => m.whatsappRenderer),\n)\n\nregisterRenderer('google-chat', () =>\n import('./renderers/google-chat').then((m) => m.googleChatRenderer),\n)\n\n// ─── Render Function ────────────────────────────────────────────────────────\n\nasync function resolveRenderer(format: string): Promise<DocumentRenderer> {\n const entry = renderers.get(format)\n if (!entry) {\n throw new Error(\n `[@pyreon/document] No renderer registered for format '${format}'. Available: ${[...renderers.keys()].join(', ')}`,\n )\n }\n\n if (typeof entry === 'function') {\n const renderer = await entry()\n // Cache the resolved renderer so we don't re-import\n renderers.set(format, renderer)\n return renderer\n }\n\n return entry\n}\n\n/**\n * Render a document node tree to the specified format.\n *\n * @example\n * ```tsx\n * const doc = <Document title=\"Report\"><Page>...</Page></Document>\n *\n * const html = await render(doc, 'html') // → HTML string\n * const pdf = await render(doc, 'pdf') // → PDF Uint8Array\n * const docx = await render(doc, 'docx') // → DOCX Uint8Array\n * const email = await render(doc, 'email') // → email-safe HTML string\n * const md = await render(doc, 'md') // → Markdown string\n * ```\n */\nexport async function render(\n node: DocNode,\n format: OutputFormat | string,\n options?: RenderOptions,\n): Promise<RenderResult> {\n const renderer = await resolveRenderer(format)\n return renderer.render(node, options)\n}\n\n/** @internal For testing — reset renderer registry to defaults. */\nexport function _resetRenderers(): void {\n renderers.clear()\n // Re-register built-in lazy loaders\n registerRenderer('html', () =>\n import('./renderers/html').then((m) => m.htmlRenderer),\n )\n registerRenderer('email', () =>\n import('./renderers/email').then((m) => m.emailRenderer),\n )\n registerRenderer('md', () =>\n import('./renderers/markdown').then((m) => m.markdownRenderer),\n )\n registerRenderer('text', () =>\n import('./renderers/text').then((m) => m.textRenderer),\n )\n registerRenderer('csv', () =>\n import('./renderers/csv').then((m) => m.csvRenderer),\n )\n registerRenderer('pdf', () =>\n import('./renderers/pdf').then((m) => m.pdfRenderer),\n )\n registerRenderer('docx', () =>\n import('./renderers/docx').then((m) => m.docxRenderer),\n )\n registerRenderer('xlsx', () =>\n import('./renderers/xlsx').then((m) => m.xlsxRenderer),\n )\n registerRenderer('pptx', () =>\n import('./renderers/pptx').then((m) => m.pptxRenderer),\n )\n registerRenderer('slack', () =>\n import('./renderers/slack').then((m) => m.slackRenderer),\n )\n registerRenderer('svg', () =>\n import('./renderers/svg').then((m) => m.svgRenderer),\n )\n registerRenderer('teams', () =>\n import('./renderers/teams').then((m) => m.teamsRenderer),\n )\n registerRenderer('discord', () =>\n import('./renderers/discord').then((m) => m.discordRenderer),\n )\n registerRenderer('telegram', () =>\n import('./renderers/telegram').then((m) => m.telegramRenderer),\n )\n registerRenderer('notion', () =>\n import('./renderers/notion').then((m) => m.notionRenderer),\n )\n registerRenderer('confluence', () =>\n import('./renderers/confluence').then((m) => m.confluenceRenderer),\n )\n registerRenderer('whatsapp', () =>\n import('./renderers/whatsapp').then((m) => m.whatsappRenderer),\n )\n registerRenderer('google-chat', () =>\n import('./renderers/google-chat').then((m) => m.googleChatRenderer),\n )\n}\n","import { render } from './render'\nimport type { DocNode, RenderOptions } from './types'\n\nconst FORMAT_MAP: Record<string, string> = {\n html: 'html',\n htm: 'html',\n pdf: 'pdf',\n docx: 'docx',\n doc: 'docx',\n xlsx: 'xlsx',\n xls: 'xlsx',\n pptx: 'pptx',\n ppt: 'pptx',\n md: 'md',\n txt: 'text',\n csv: 'csv',\n svg: 'svg',\n}\n\nconst MIME_TYPES: Record<string, string> = {\n html: 'text/html',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n email: 'text/html',\n md: 'text/markdown',\n text: 'text/plain',\n csv: 'text/csv',\n svg: 'image/svg+xml',\n}\n\n/**\n * Download a document in the browser.\n *\n * @example\n * ```tsx\n * await download(doc, 'report.pdf')\n * await download(doc, 'report.docx')\n * ```\n */\nexport async function download(\n node: DocNode,\n filename: string,\n options?: RenderOptions,\n): Promise<void> {\n const ext = filename.split('.').pop()?.toLowerCase()\n if (!ext) {\n throw new Error(\n '[@pyreon/document] Filename must have an extension (e.g., report.pdf).',\n )\n }\n\n const format = FORMAT_MAP[ext]\n if (!format) {\n throw new Error(\n `[@pyreon/document] Unknown file extension '.${ext}'. Supported: ${Object.keys(FORMAT_MAP).join(', ')}`,\n )\n }\n\n const result = await render(node, format, options)\n\n const blob =\n result instanceof Uint8Array\n ? new Blob([result as BlobPart])\n : new Blob([result], {\n type: MIME_TYPES[format] ?? 'application/octet-stream',\n })\n\n if (typeof document === 'undefined') {\n throw new Error(\n '[@pyreon/document] download() requires a browser environment.',\n )\n }\n\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n","import type {\n ButtonProps,\n CodeProps,\n ColumnProps,\n DividerProps,\n DocChild,\n DocNode,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListItemProps,\n ListProps,\n NodeType,\n PageProps,\n QuoteProps,\n RowProps,\n SectionProps,\n SpacerProps,\n TableProps,\n TextProps,\n} from './types'\n\n// ─── Node Constructor ───────────────────────────────────────────────────────\n\nfunction createNode(type: NodeType, props: object, children: unknown): DocNode {\n return {\n type,\n props: props as Record<string, unknown>,\n children: normalizeChildren(children),\n }\n}\n\nfunction normalizeChildren(children: unknown): DocChild[] {\n if (children == null || children === false) return []\n if (typeof children === 'string') return [children]\n if (typeof children === 'number') return [String(children)]\n if (Array.isArray(children)) return children.flatMap(normalizeChildren)\n if (isDocNode(children)) return [children]\n if (typeof children === 'object') {\n throw new Error(\n '[@pyreon/document] Invalid child: plain objects are not valid document children. Use a document node (Text, Heading, etc.) instead.',\n )\n }\n return [String(children)]\n}\n\n/** Type guard — checks if a value is a DocNode. */\nexport function isDocNode(value: unknown): value is DocNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n 'props' in value &&\n 'children' in value\n )\n}\n\n// ─── Document Primitives ────────────────────────────────────────────────────\n\n/**\n * Root document container. Holds metadata and pages.\n *\n * @example\n * ```tsx\n * <Document title=\"Invoice #1234\" author=\"Acme Corp\">\n * <Page>...</Page>\n * </Document>\n * ```\n */\nexport function Document(props: DocumentProps): DocNode {\n const { children, ...rest } = props\n return createNode('document', rest, children)\n}\nDocument._documentType = 'document' as const\n\n/**\n * Page container. Maps to a PDF page, DOCX section, or email block.\n *\n * @example\n * ```tsx\n * <Page size=\"A4\" margin={40}>\n * <Heading>Title</Heading>\n * </Page>\n * ```\n */\nexport function Page(props: PageProps): DocNode {\n const { children, ...rest } = props\n return createNode('page', rest, children)\n}\nPage._documentType = 'page' as const\n\n/**\n * Layout section — groups content with optional direction, padding, background.\n *\n * @example\n * ```tsx\n * <Section background=\"#f5f5f5\" padding={20} direction=\"row\" gap={12}>\n * <Text>Left</Text>\n * <Text>Right</Text>\n * </Section>\n * ```\n */\nexport function Section(props: SectionProps): DocNode {\n const { children, ...rest } = props\n return createNode('section', rest, children)\n}\nSection._documentType = 'section' as const\n\n/**\n * Horizontal layout container.\n *\n * @example\n * ```tsx\n * <Row gap={20}>\n * <Column width=\"60%\"><Text>Main</Text></Column>\n * <Column width=\"40%\"><Text>Side</Text></Column>\n * </Row>\n * ```\n */\nexport function Row(props: RowProps): DocNode {\n const { children, ...rest } = props\n return createNode('row', rest, children)\n}\nRow._documentType = 'row' as const\n\n/**\n * Column within a Row.\n */\nexport function Column(props: ColumnProps): DocNode {\n const { children, ...rest } = props\n return createNode('column', rest, children)\n}\nColumn._documentType = 'column' as const\n\n/**\n * Heading text (h1–h6).\n *\n * @example\n * ```tsx\n * <Heading level={1}>Invoice #1234</Heading>\n * <Heading level={2} color=\"#666\">Details</Heading>\n * ```\n */\nexport function Heading(props: HeadingProps): DocNode {\n const { children, ...rest } = props\n return createNode('heading', { level: 1, ...rest }, children)\n}\nHeading._documentType = 'heading' as const\n\n/**\n * Text paragraph with optional formatting.\n *\n * @example\n * ```tsx\n * <Text bold size={14} color=\"#333\">Hello World</Text>\n * <Text italic align=\"right\">Subtotal: $100</Text>\n * ```\n */\nexport function Text(props: TextProps): DocNode {\n const { children, ...rest } = props\n return createNode('text', rest, children)\n}\nText._documentType = 'text' as const\n\n/**\n * Hyperlink.\n *\n * @example\n * ```tsx\n * <Link href=\"https://example.com\">Visit site</Link>\n * ```\n */\nexport function Link(props: LinkProps): DocNode {\n const { children, ...rest } = props\n return createNode('link', rest, children)\n}\nLink._documentType = 'link' as const\n\n/**\n * Image with optional sizing and caption.\n *\n * @example\n * ```tsx\n * <Image src=\"/logo.png\" width={120} alt=\"Company Logo\" />\n * <Image src={chartDataUrl} width={500} caption=\"Revenue Chart\" />\n * ```\n */\nexport function Image(props: ImageProps): DocNode {\n return createNode('image', props, [])\n}\nImage._documentType = 'image' as const\n\n/**\n * Data table with columns and rows.\n *\n * @example\n * ```tsx\n * <Table\n * columns={['Name', 'Price', 'Qty']}\n * rows={[['Widget', '$10', '5'], ['Gadget', '$20', '3']]}\n * striped\n * headerStyle={{ background: '#1a1a2e', color: '#fff' }}\n * />\n * ```\n */\nexport function Table(props: TableProps): DocNode {\n return createNode('table', props, [])\n}\nTable._documentType = 'table' as const\n\n/**\n * Ordered or unordered list.\n *\n * @example\n * ```tsx\n * <List ordered>\n * <ListItem>First item</ListItem>\n * <ListItem>Second item</ListItem>\n * </List>\n * ```\n */\nexport function List(props: ListProps): DocNode {\n const { children, ...rest } = props\n return createNode('list', rest, children)\n}\nList._documentType = 'list' as const\n\n/**\n * Single list item within a List.\n */\nexport function ListItem(props: ListItemProps): DocNode {\n const { children } = props\n return createNode('list-item', {}, children)\n}\nListItem._documentType = 'list-item' as const\n\n/**\n * Code block with optional language hint.\n *\n * @example\n * ```tsx\n * <Code language=\"typescript\">const x = 42</Code>\n * ```\n */\nexport function Code(props: CodeProps): DocNode {\n const { children, ...rest } = props\n return createNode('code', rest, children)\n}\nCode._documentType = 'code' as const\n\n/**\n * Horizontal divider line.\n *\n * @example\n * ```tsx\n * <Divider color=\"#ddd\" thickness={2} />\n * ```\n */\nexport function Divider(props: DividerProps = {}): DocNode {\n return createNode('divider', props, [])\n}\nDivider._documentType = 'divider' as const\n\n/**\n * Page break — forces content after this point to the next page (PDF/DOCX)\n * or inserts a visual separator (HTML/email).\n *\n * @example\n * ```tsx\n * <PageBreak />\n * ```\n */\nexport function PageBreak(): DocNode {\n return createNode('page-break', {}, [])\n}\nPageBreak._documentType = 'page-break' as const\n\n/**\n * Vertical spacer.\n *\n * @example\n * ```tsx\n * <Spacer height={20} />\n * ```\n */\nexport function Spacer(props: SpacerProps): DocNode {\n return createNode('spacer', props, [])\n}\nSpacer._documentType = 'spacer' as const\n\n/**\n * CTA button — renders as a bulletproof button in email, styled link in PDF/DOCX.\n *\n * @example\n * ```tsx\n * <Button href=\"https://acme.com/pay\" background=\"#4f46e5\" color=\"#fff\">\n * Pay Now\n * </Button>\n * ```\n */\nexport function Button(props: ButtonProps): DocNode {\n const { children, ...rest } = props\n return createNode('button', rest, children)\n}\nButton._documentType = 'button' as const\n\n/**\n * Block quote.\n *\n * @example\n * ```tsx\n * <Quote borderColor=\"#4f46e5\">This is a quote.</Quote>\n * ```\n */\nexport function Quote(props: QuoteProps): DocNode {\n const { children, ...rest } = props\n return createNode('quote', rest, children)\n}\nQuote._documentType = 'quote' as const\n","import { download } from './download'\nimport {\n Button,\n Code,\n Divider,\n Document,\n Heading,\n Image,\n Link,\n List,\n ListItem,\n Page,\n PageBreak,\n Quote,\n Spacer,\n Table,\n Text,\n} from './nodes'\nimport { render } from './render'\nimport type {\n ButtonProps,\n CodeProps,\n DividerProps,\n DocNode,\n DocumentBuilder,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListProps,\n QuoteProps,\n RenderOptions,\n TableProps,\n TextProps,\n} from './types'\n\n/**\n * Create a document using the builder pattern — no JSX needed.\n *\n * @example\n * ```ts\n * const doc = createDocument({ title: 'Report' })\n * .heading('Sales Report')\n * .text('Q4 performance summary.')\n * .table({ columns: ['Region', 'Revenue'], rows: [['US', '$1M']] })\n *\n * await doc.toPdf()\n * await doc.download('report.pdf')\n * ```\n */\nexport function createDocument(props: DocumentProps = {}): DocumentBuilder {\n const sections: DocNode[] = []\n\n function getNode(): DocNode {\n return Document({ ...props, children: [Page({ children: sections })] })\n }\n\n const builder: DocumentBuilder = {\n heading(text: string, p?: Omit<HeadingProps, 'children'>) {\n sections.push(Heading({ ...p, children: text }))\n return builder\n },\n\n text(text: string, p?: Omit<TextProps, 'children'>) {\n sections.push(Text({ ...p, children: text }))\n return builder\n },\n\n paragraph(text: string, p?: Omit<TextProps, 'children'>) {\n return builder.text(text, p)\n },\n\n image(src: string, p?: Omit<ImageProps, 'src'>) {\n sections.push(Image({ src, ...p }))\n return builder\n },\n\n table(p: TableProps) {\n sections.push(Table(p))\n return builder\n },\n\n list(items: string[], p?: Omit<ListProps, 'children'>) {\n sections.push(\n List({\n ...p,\n children: items.map((item) => ListItem({ children: item })),\n }),\n )\n return builder\n },\n\n code(text: string, p?: Omit<CodeProps, 'children'>) {\n sections.push(Code({ ...p, children: text }))\n return builder\n },\n\n divider(p?: DividerProps) {\n sections.push(Divider(p))\n return builder\n },\n\n spacer(height: number) {\n sections.push(Spacer({ height }))\n return builder\n },\n\n quote(text: string, p?: Omit<QuoteProps, 'children'>) {\n sections.push(Quote({ ...p, children: text }))\n return builder\n },\n\n button(text: string, p: Omit<ButtonProps, 'children'>) {\n sections.push(Button({ ...p, children: text }))\n return builder\n },\n\n link(text: string, p: Omit<LinkProps, 'children'>) {\n sections.push(Link({ ...p, children: text }))\n return builder\n },\n\n pageBreak() {\n sections.push(PageBreak())\n return builder\n },\n\n chart(\n instance: unknown,\n p?: { width?: number; height?: number; caption?: string },\n ) {\n // Try to get data URL from chart instance\n const inst = instance as { getDataURL?: (opts: unknown) => string }\n if (inst?.getDataURL) {\n const dataUrl = inst.getDataURL({ type: 'png', pixelRatio: 2 })\n sections.push(\n Image({\n src: dataUrl,\n ...(p?.width != null ? { width: p.width } : {}),\n ...(p?.height != null ? { height: p.height } : {}),\n ...(p?.caption != null ? { caption: p.caption } : {}),\n }),\n )\n } else {\n sections.push(\n Text({\n children: '[Chart]',\n italic: true,\n color: '#999',\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n flow(\n instance: unknown,\n p?: { width?: number; height?: number; caption?: string },\n ) {\n // Try to get SVG from flow instance\n const inst = instance as { toSVG?: () => string }\n if (inst?.toSVG) {\n const svg = inst.toSVG()\n sections.push(\n Image({\n src: `data:image/svg+xml,${encodeURIComponent(svg)}`,\n ...(p?.width != null ? { width: p.width } : {}),\n ...(p?.height != null ? { height: p.height } : {}),\n ...(p?.caption != null ? { caption: p.caption } : {}),\n }),\n )\n } else {\n sections.push(\n Text({\n children: '[Flow Diagram]',\n italic: true,\n color: '#999',\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n build() {\n return getNode()\n },\n\n async toHtml(options?: RenderOptions) {\n return render(getNode(), 'html', options) as Promise<string>\n },\n\n async toPdf(options?: RenderOptions) {\n return render(getNode(), 'pdf', options) as Promise<Uint8Array>\n },\n\n async toDocx(options?: RenderOptions) {\n return render(getNode(), 'docx', options) as Promise<Uint8Array>\n },\n\n async toEmail(options?: RenderOptions) {\n return render(getNode(), 'email', options) as Promise<string>\n },\n\n async toPptx(options?: RenderOptions) {\n return render(getNode(), 'pptx', options) as Promise<Uint8Array>\n },\n\n async toXlsx(options?: RenderOptions) {\n return render(getNode(), 'xlsx', options) as Promise<Uint8Array>\n },\n\n async toMarkdown(options?: RenderOptions) {\n return render(getNode(), 'md', options) as Promise<string>\n },\n\n async toText(options?: RenderOptions) {\n return render(getNode(), 'text', options) as Promise<string>\n },\n\n async toCsv(options?: RenderOptions) {\n return render(getNode(), 'csv', options) as Promise<string>\n },\n\n async toSlack(options?: RenderOptions) {\n return render(getNode(), 'slack', options) as Promise<string>\n },\n\n async toSvg(options?: RenderOptions) {\n return render(getNode(), 'svg', options) as Promise<string>\n },\n\n async toTeams(options?: RenderOptions) {\n return render(getNode(), 'teams', options) as Promise<string>\n },\n\n async toDiscord(options?: RenderOptions) {\n return render(getNode(), 'discord', options) as Promise<string>\n },\n\n async toTelegram(options?: RenderOptions) {\n return render(getNode(), 'telegram', options) as Promise<string>\n },\n\n async toNotion(options?: RenderOptions) {\n return render(getNode(), 'notion', options) as Promise<string>\n },\n\n async toConfluence(options?: RenderOptions) {\n return render(getNode(), 'confluence', options) as Promise<string>\n },\n\n async toWhatsApp(options?: RenderOptions) {\n return render(getNode(), 'whatsapp', options) as Promise<string>\n },\n\n async toGoogleChat(options?: RenderOptions) {\n return render(getNode(), 'google-chat', options) as Promise<string>\n },\n\n async download(filename: string, options?: RenderOptions) {\n return download(getNode(), filename, options)\n },\n }\n\n return builder\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/render.ts","../src/download.ts","../src/nodes.ts","../src/builder.ts"],"sourcesContent":["import type { DocNode, DocumentRenderer, OutputFormat, RenderOptions, RenderResult } from \"./types\"\n\n// ─── Renderer Registry ──────────────────────────────────────────────────────\n\nconst renderers = new Map<string, DocumentRenderer | (() => Promise<DocumentRenderer>)>()\n\n/**\n * Register a custom renderer for a format.\n *\n * @example\n * ```ts\n * registerRenderer('thermal', {\n * render(node, options) {\n * // Walk nodes → ESC/POS commands\n * return escPosBuffer\n * },\n * })\n *\n * await render(receipt, 'thermal')\n * ```\n */\nexport function registerRenderer(\n format: string,\n renderer: DocumentRenderer | (() => Promise<DocumentRenderer>),\n): void {\n renderers.set(format, renderer)\n}\n\n/**\n * Remove a registered renderer.\n */\nexport function unregisterRenderer(format: string): void {\n renderers.delete(format)\n}\n\n// ─── Built-in Renderer Loaders ──────────────────────────────────────────────\n\n// Built-in renderers are registered lazily — only loaded when first used.\n\nregisterRenderer(\"html\", () => import(\"./renderers/html\").then((m) => m.htmlRenderer))\n\nregisterRenderer(\"email\", () => import(\"./renderers/email\").then((m) => m.emailRenderer))\n\nregisterRenderer(\"md\", () => import(\"./renderers/markdown\").then((m) => m.markdownRenderer))\n\nregisterRenderer(\"text\", () => import(\"./renderers/text\").then((m) => m.textRenderer))\n\nregisterRenderer(\"csv\", () => import(\"./renderers/csv\").then((m) => m.csvRenderer))\n\nregisterRenderer(\"pdf\", () => import(\"./renderers/pdf\").then((m) => m.pdfRenderer))\n\nregisterRenderer(\"docx\", () => import(\"./renderers/docx\").then((m) => m.docxRenderer))\n\nregisterRenderer(\"xlsx\", () => import(\"./renderers/xlsx\").then((m) => m.xlsxRenderer))\n\nregisterRenderer(\"pptx\", () => import(\"./renderers/pptx\").then((m) => m.pptxRenderer))\n\nregisterRenderer(\"slack\", () => import(\"./renderers/slack\").then((m) => m.slackRenderer))\n\nregisterRenderer(\"svg\", () => import(\"./renderers/svg\").then((m) => m.svgRenderer))\n\nregisterRenderer(\"teams\", () => import(\"./renderers/teams\").then((m) => m.teamsRenderer))\n\nregisterRenderer(\"discord\", () => import(\"./renderers/discord\").then((m) => m.discordRenderer))\n\nregisterRenderer(\"telegram\", () => import(\"./renderers/telegram\").then((m) => m.telegramRenderer))\n\nregisterRenderer(\"notion\", () => import(\"./renderers/notion\").then((m) => m.notionRenderer))\n\nregisterRenderer(\"confluence\", () =>\n import(\"./renderers/confluence\").then((m) => m.confluenceRenderer),\n)\n\nregisterRenderer(\"whatsapp\", () => import(\"./renderers/whatsapp\").then((m) => m.whatsappRenderer))\n\nregisterRenderer(\"google-chat\", () =>\n import(\"./renderers/google-chat\").then((m) => m.googleChatRenderer),\n)\n\n// ─── Render Function ────────────────────────────────────────────────────────\n\nasync function resolveRenderer(format: string): Promise<DocumentRenderer> {\n const entry = renderers.get(format)\n if (!entry) {\n throw new Error(\n `[@pyreon/document] No renderer registered for format '${format}'. Available: ${[...renderers.keys()].join(\", \")}`,\n )\n }\n\n if (typeof entry === \"function\") {\n const renderer = await entry()\n // Cache the resolved renderer so we don't re-import\n renderers.set(format, renderer)\n return renderer\n }\n\n return entry\n}\n\n/**\n * Render a document node tree to the specified format.\n *\n * @example\n * ```tsx\n * const doc = <Document title=\"Report\"><Page>...</Page></Document>\n *\n * const html = await render(doc, 'html') // → HTML string\n * const pdf = await render(doc, 'pdf') // → PDF Uint8Array\n * const docx = await render(doc, 'docx') // → DOCX Uint8Array\n * const email = await render(doc, 'email') // → email-safe HTML string\n * const md = await render(doc, 'md') // → Markdown string\n * ```\n */\nexport async function render(\n node: DocNode,\n format: OutputFormat | string,\n options?: RenderOptions,\n): Promise<RenderResult> {\n const renderer = await resolveRenderer(format)\n return renderer.render(node, options)\n}\n\n/** @internal For testing — reset renderer registry to defaults. */\nexport function _resetRenderers(): void {\n renderers.clear()\n // Re-register built-in lazy loaders\n registerRenderer(\"html\", () => import(\"./renderers/html\").then((m) => m.htmlRenderer))\n registerRenderer(\"email\", () => import(\"./renderers/email\").then((m) => m.emailRenderer))\n registerRenderer(\"md\", () => import(\"./renderers/markdown\").then((m) => m.markdownRenderer))\n registerRenderer(\"text\", () => import(\"./renderers/text\").then((m) => m.textRenderer))\n registerRenderer(\"csv\", () => import(\"./renderers/csv\").then((m) => m.csvRenderer))\n registerRenderer(\"pdf\", () => import(\"./renderers/pdf\").then((m) => m.pdfRenderer))\n registerRenderer(\"docx\", () => import(\"./renderers/docx\").then((m) => m.docxRenderer))\n registerRenderer(\"xlsx\", () => import(\"./renderers/xlsx\").then((m) => m.xlsxRenderer))\n registerRenderer(\"pptx\", () => import(\"./renderers/pptx\").then((m) => m.pptxRenderer))\n registerRenderer(\"slack\", () => import(\"./renderers/slack\").then((m) => m.slackRenderer))\n registerRenderer(\"svg\", () => import(\"./renderers/svg\").then((m) => m.svgRenderer))\n registerRenderer(\"teams\", () => import(\"./renderers/teams\").then((m) => m.teamsRenderer))\n registerRenderer(\"discord\", () => import(\"./renderers/discord\").then((m) => m.discordRenderer))\n registerRenderer(\"telegram\", () => import(\"./renderers/telegram\").then((m) => m.telegramRenderer))\n registerRenderer(\"notion\", () => import(\"./renderers/notion\").then((m) => m.notionRenderer))\n registerRenderer(\"confluence\", () =>\n import(\"./renderers/confluence\").then((m) => m.confluenceRenderer),\n )\n registerRenderer(\"whatsapp\", () => import(\"./renderers/whatsapp\").then((m) => m.whatsappRenderer))\n registerRenderer(\"google-chat\", () =>\n import(\"./renderers/google-chat\").then((m) => m.googleChatRenderer),\n )\n}\n","import { render } from \"./render\"\nimport type { DocNode, RenderOptions } from \"./types\"\n\nconst FORMAT_MAP: Record<string, string> = {\n html: \"html\",\n htm: \"html\",\n pdf: \"pdf\",\n docx: \"docx\",\n doc: \"docx\",\n xlsx: \"xlsx\",\n xls: \"xlsx\",\n pptx: \"pptx\",\n ppt: \"pptx\",\n md: \"md\",\n txt: \"text\",\n csv: \"csv\",\n svg: \"svg\",\n}\n\nconst MIME_TYPES: Record<string, string> = {\n html: \"text/html\",\n pdf: \"application/pdf\",\n docx: \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n xlsx: \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n pptx: \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n email: \"text/html\",\n md: \"text/markdown\",\n text: \"text/plain\",\n csv: \"text/csv\",\n svg: \"image/svg+xml\",\n}\n\n/**\n * Download a document in the browser.\n *\n * @example\n * ```tsx\n * await download(doc, 'report.pdf')\n * await download(doc, 'report.docx')\n * ```\n */\nexport async function download(\n node: DocNode,\n filename: string,\n options?: RenderOptions,\n): Promise<void> {\n const ext = filename.split(\".\").pop()?.toLowerCase()\n if (!ext) {\n throw new Error(\"[@pyreon/document] Filename must have an extension (e.g., report.pdf).\")\n }\n\n const format = FORMAT_MAP[ext]\n if (!format) {\n throw new Error(\n `[@pyreon/document] Unknown file extension '.${ext}'. Supported: ${Object.keys(FORMAT_MAP).join(\", \")}`,\n )\n }\n\n const result = await render(node, format, options)\n\n const blob =\n result instanceof Uint8Array\n ? new Blob([result as BlobPart])\n : new Blob([result], {\n type: MIME_TYPES[format] ?? \"application/octet-stream\",\n })\n\n if (typeof document === \"undefined\") {\n throw new Error(\"[@pyreon/document] download() requires a browser environment.\")\n }\n\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n","import type {\n ButtonProps,\n CodeProps,\n ColumnProps,\n DividerProps,\n DocChild,\n DocNode,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListItemProps,\n ListProps,\n NodeType,\n PageProps,\n QuoteProps,\n RowProps,\n SectionProps,\n SpacerProps,\n TableProps,\n TextProps,\n} from \"./types\"\n\n// ─── Node Constructor ───────────────────────────────────────────────────────\n\nfunction createNode(type: NodeType, props: object, children: unknown): DocNode {\n return {\n type,\n props: props as Record<string, unknown>,\n children: normalizeChildren(children),\n }\n}\n\nfunction normalizeChildren(children: unknown): DocChild[] {\n if (children == null || children === false) return []\n if (typeof children === \"string\") return [children]\n if (typeof children === \"number\") return [String(children)]\n if (Array.isArray(children)) return children.flatMap(normalizeChildren)\n if (isDocNode(children)) return [children]\n if (typeof children === \"object\") {\n throw new Error(\n \"[@pyreon/document] Invalid child: plain objects are not valid document children. Use a document node (Text, Heading, etc.) instead.\",\n )\n }\n return [String(children)]\n}\n\n/** Type guard — checks if a value is a DocNode. */\nexport function isDocNode(value: unknown): value is DocNode {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n \"props\" in value &&\n \"children\" in value\n )\n}\n\n// ─── Document Primitives ────────────────────────────────────────────────────\n\n/**\n * Root document container. Holds metadata and pages.\n *\n * @example\n * ```tsx\n * <Document title=\"Invoice #1234\" author=\"Acme Corp\">\n * <Page>...</Page>\n * </Document>\n * ```\n */\nexport function Document(props: DocumentProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"document\", rest, children)\n}\nDocument._documentType = \"document\" as const\n\n/**\n * Page container. Maps to a PDF page, DOCX section, or email block.\n *\n * @example\n * ```tsx\n * <Page size=\"A4\" margin={40}>\n * <Heading>Title</Heading>\n * </Page>\n * ```\n */\nexport function Page(props: PageProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"page\", rest, children)\n}\nPage._documentType = \"page\" as const\n\n/**\n * Layout section — groups content with optional direction, padding, background.\n *\n * @example\n * ```tsx\n * <Section background=\"#f5f5f5\" padding={20} direction=\"row\" gap={12}>\n * <Text>Left</Text>\n * <Text>Right</Text>\n * </Section>\n * ```\n */\nexport function Section(props: SectionProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"section\", rest, children)\n}\nSection._documentType = \"section\" as const\n\n/**\n * Horizontal layout container.\n *\n * @example\n * ```tsx\n * <Row gap={20}>\n * <Column width=\"60%\"><Text>Main</Text></Column>\n * <Column width=\"40%\"><Text>Side</Text></Column>\n * </Row>\n * ```\n */\nexport function Row(props: RowProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"row\", rest, children)\n}\nRow._documentType = \"row\" as const\n\n/**\n * Column within a Row.\n */\nexport function Column(props: ColumnProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"column\", rest, children)\n}\nColumn._documentType = \"column\" as const\n\n/**\n * Heading text (h1–h6).\n *\n * @example\n * ```tsx\n * <Heading level={1}>Invoice #1234</Heading>\n * <Heading level={2} color=\"#666\">Details</Heading>\n * ```\n */\nexport function Heading(props: HeadingProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"heading\", { level: 1, ...rest }, children)\n}\nHeading._documentType = \"heading\" as const\n\n/**\n * Text paragraph with optional formatting.\n *\n * @example\n * ```tsx\n * <Text bold size={14} color=\"#333\">Hello World</Text>\n * <Text italic align=\"right\">Subtotal: $100</Text>\n * ```\n */\nexport function Text(props: TextProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"text\", rest, children)\n}\nText._documentType = \"text\" as const\n\n/**\n * Hyperlink.\n *\n * @example\n * ```tsx\n * <Link href=\"https://example.com\">Visit site</Link>\n * ```\n */\nexport function Link(props: LinkProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"link\", rest, children)\n}\nLink._documentType = \"link\" as const\n\n/**\n * Image with optional sizing and caption.\n *\n * @example\n * ```tsx\n * <Image src=\"/logo.png\" width={120} alt=\"Company Logo\" />\n * <Image src={chartDataUrl} width={500} caption=\"Revenue Chart\" />\n * ```\n */\nexport function Image(props: ImageProps): DocNode {\n return createNode(\"image\", props, [])\n}\nImage._documentType = \"image\" as const\n\n/**\n * Data table with columns and rows.\n *\n * @example\n * ```tsx\n * <Table\n * columns={['Name', 'Price', 'Qty']}\n * rows={[['Widget', '$10', '5'], ['Gadget', '$20', '3']]}\n * striped\n * headerStyle={{ background: '#1a1a2e', color: '#fff' }}\n * />\n * ```\n */\nexport function Table(props: TableProps): DocNode {\n return createNode(\"table\", props, [])\n}\nTable._documentType = \"table\" as const\n\n/**\n * Ordered or unordered list.\n *\n * @example\n * ```tsx\n * <List ordered>\n * <ListItem>First item</ListItem>\n * <ListItem>Second item</ListItem>\n * </List>\n * ```\n */\nexport function List(props: ListProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"list\", rest, children)\n}\nList._documentType = \"list\" as const\n\n/**\n * Single list item within a List.\n */\nexport function ListItem(props: ListItemProps): DocNode {\n const { children } = props\n return createNode(\"list-item\", {}, children)\n}\nListItem._documentType = \"list-item\" as const\n\n/**\n * Code block with optional language hint.\n *\n * @example\n * ```tsx\n * <Code language=\"typescript\">const x = 42</Code>\n * ```\n */\nexport function Code(props: CodeProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"code\", rest, children)\n}\nCode._documentType = \"code\" as const\n\n/**\n * Horizontal divider line.\n *\n * @example\n * ```tsx\n * <Divider color=\"#ddd\" thickness={2} />\n * ```\n */\nexport function Divider(props: DividerProps = {}): DocNode {\n return createNode(\"divider\", props, [])\n}\nDivider._documentType = \"divider\" as const\n\n/**\n * Page break — forces content after this point to the next page (PDF/DOCX)\n * or inserts a visual separator (HTML/email).\n *\n * @example\n * ```tsx\n * <PageBreak />\n * ```\n */\nexport function PageBreak(): DocNode {\n return createNode(\"page-break\", {}, [])\n}\nPageBreak._documentType = \"page-break\" as const\n\n/**\n * Vertical spacer.\n *\n * @example\n * ```tsx\n * <Spacer height={20} />\n * ```\n */\nexport function Spacer(props: SpacerProps): DocNode {\n return createNode(\"spacer\", props, [])\n}\nSpacer._documentType = \"spacer\" as const\n\n/**\n * CTA button — renders as a bulletproof button in email, styled link in PDF/DOCX.\n *\n * @example\n * ```tsx\n * <Button href=\"https://acme.com/pay\" background=\"#4f46e5\" color=\"#fff\">\n * Pay Now\n * </Button>\n * ```\n */\nexport function Button(props: ButtonProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"button\", rest, children)\n}\nButton._documentType = \"button\" as const\n\n/**\n * Block quote.\n *\n * @example\n * ```tsx\n * <Quote borderColor=\"#4f46e5\">This is a quote.</Quote>\n * ```\n */\nexport function Quote(props: QuoteProps): DocNode {\n const { children, ...rest } = props\n return createNode(\"quote\", rest, children)\n}\nQuote._documentType = \"quote\" as const\n","import { download } from \"./download\"\nimport {\n Button,\n Code,\n Divider,\n Document,\n Heading,\n Image,\n Link,\n List,\n ListItem,\n Page,\n PageBreak,\n Quote,\n Section,\n Spacer,\n Table,\n Text,\n} from \"./nodes\"\nimport { render } from \"./render\"\nimport type {\n ButtonProps,\n CodeProps,\n DividerProps,\n DocNode,\n DocumentBuilder,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListProps,\n QuoteProps,\n RenderOptions,\n TableProps,\n TextProps,\n} from \"./types\"\n\n/**\n * Create a document using the builder pattern — no JSX needed.\n *\n * @example\n * ```ts\n * const doc = createDocument({ title: 'Report' })\n * .heading('Sales Report')\n * .text('Q4 performance summary.')\n * .table({ columns: ['Region', 'Revenue'], rows: [['US', '$1M']] })\n *\n * await doc.toPdf()\n * await doc.download('report.pdf')\n * ```\n */\nexport function createDocument(props: DocumentProps = {}): DocumentBuilder {\n const sections: DocNode[] = []\n\n function getNode(): DocNode {\n return Document({ ...props, children: [Page({ children: sections })] })\n }\n\n const builder: DocumentBuilder = {\n heading(text: string, p?: Omit<HeadingProps, \"children\">) {\n sections.push(Heading({ ...p, children: text }))\n return builder\n },\n\n text(text: string, p?: Omit<TextProps, \"children\">) {\n sections.push(Text({ ...p, children: text }))\n return builder\n },\n\n paragraph(text: string, p?: Omit<TextProps, \"children\">) {\n return builder.text(text, p)\n },\n\n image(src: string, p?: Omit<ImageProps, \"src\">) {\n sections.push(Image({ src, ...p }))\n return builder\n },\n\n table(p: TableProps) {\n sections.push(Table(p))\n return builder\n },\n\n list(items: string[], p?: Omit<ListProps, \"children\">) {\n sections.push(\n List({\n ...p,\n children: items.map((item) => ListItem({ children: item })),\n }),\n )\n return builder\n },\n\n code(text: string, p?: Omit<CodeProps, \"children\">) {\n sections.push(Code({ ...p, children: text }))\n return builder\n },\n\n divider(p?: DividerProps) {\n sections.push(Divider(p))\n return builder\n },\n\n spacer(height: number) {\n sections.push(Spacer({ height }))\n return builder\n },\n\n quote(text: string, p?: Omit<QuoteProps, \"children\">) {\n sections.push(Quote({ ...p, children: text }))\n return builder\n },\n\n button(text: string, p: Omit<ButtonProps, \"children\">) {\n sections.push(Button({ ...p, children: text }))\n return builder\n },\n\n link(text: string, p: Omit<LinkProps, \"children\">) {\n sections.push(Link({ ...p, children: text }))\n return builder\n },\n\n pageBreak() {\n sections.push(PageBreak())\n return builder\n },\n\n add(node) {\n if (Array.isArray(node)) {\n sections.push(...node)\n } else {\n sections.push(node)\n }\n return builder\n },\n\n section(children) {\n sections.push(Section({ children }))\n return builder\n },\n\n chart(instance: unknown, p?: { width?: number; height?: number; caption?: string }) {\n // Try to get data URL from chart instance\n const inst = instance as { getDataURL?: (opts: unknown) => string }\n if (inst?.getDataURL) {\n const dataUrl = inst.getDataURL({ type: \"png\", pixelRatio: 2 })\n sections.push(\n Image({\n src: dataUrl,\n ...(p?.width != null ? { width: p.width } : {}),\n ...(p?.height != null ? { height: p.height } : {}),\n ...(p?.caption != null ? { caption: p.caption } : {}),\n }),\n )\n } else {\n sections.push(\n Text({\n children: \"[Chart]\",\n italic: true,\n color: \"#999\",\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n flow(instance: unknown, p?: { width?: number; height?: number; caption?: string }) {\n // Try to get SVG from flow instance\n const inst = instance as { toSVG?: () => string }\n if (inst?.toSVG) {\n const svg = inst.toSVG()\n sections.push(\n Image({\n src: `data:image/svg+xml,${encodeURIComponent(svg)}`,\n ...(p?.width != null ? { width: p.width } : {}),\n ...(p?.height != null ? { height: p.height } : {}),\n ...(p?.caption != null ? { caption: p.caption } : {}),\n }),\n )\n } else {\n sections.push(\n Text({\n children: \"[Flow Diagram]\",\n italic: true,\n color: \"#999\",\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n build() {\n return getNode()\n },\n\n async toHtml(options?: RenderOptions) {\n return render(getNode(), \"html\", options) as Promise<string>\n },\n\n async toPdf(options?: RenderOptions) {\n return render(getNode(), \"pdf\", options) as Promise<Uint8Array>\n },\n\n async toDocx(options?: RenderOptions) {\n return render(getNode(), \"docx\", options) as Promise<Uint8Array>\n },\n\n async toEmail(options?: RenderOptions) {\n return render(getNode(), \"email\", options) as Promise<string>\n },\n\n async toPptx(options?: RenderOptions) {\n return render(getNode(), \"pptx\", options) as Promise<Uint8Array>\n },\n\n async toXlsx(options?: RenderOptions) {\n return render(getNode(), \"xlsx\", options) as Promise<Uint8Array>\n },\n\n async toMarkdown(options?: RenderOptions) {\n return render(getNode(), \"md\", options) as Promise<string>\n },\n\n async toText(options?: RenderOptions) {\n return render(getNode(), \"text\", options) as Promise<string>\n },\n\n async toCsv(options?: RenderOptions) {\n return render(getNode(), \"csv\", options) as Promise<string>\n },\n\n async toSlack(options?: RenderOptions) {\n return render(getNode(), \"slack\", options) as Promise<string>\n },\n\n async toSvg(options?: RenderOptions) {\n return render(getNode(), \"svg\", options) as Promise<string>\n },\n\n async toTeams(options?: RenderOptions) {\n return render(getNode(), \"teams\", options) as Promise<string>\n },\n\n async toDiscord(options?: RenderOptions) {\n return render(getNode(), \"discord\", options) as Promise<string>\n },\n\n async toTelegram(options?: RenderOptions) {\n return render(getNode(), \"telegram\", options) as Promise<string>\n },\n\n async toNotion(options?: RenderOptions) {\n return render(getNode(), \"notion\", options) as Promise<string>\n },\n\n async toConfluence(options?: RenderOptions) {\n return render(getNode(), \"confluence\", options) as Promise<string>\n },\n\n async toWhatsApp(options?: RenderOptions) {\n return render(getNode(), \"whatsapp\", options) as Promise<string>\n },\n\n async toGoogleChat(options?: RenderOptions) {\n return render(getNode(), \"google-chat\", options) as Promise<string>\n },\n\n async download(filename: string, options?: RenderOptions) {\n return download(getNode(), filename, options)\n },\n }\n\n return builder\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-CdtlFGC0.js","names":[],"sources":["../src/renderers/markdown.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from '../sanitize'\nimport type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction renderChild(child: DocChild): string {\n if (typeof child === 'string') return child\n return renderNode(child)\n}\n\nfunction renderChildren(children: DocChild[]): string {\n return children.map(renderChild).join('')\n}\n\nfunction renderInline(children: DocChild[]): string {\n return children.map(renderChild).join('')\n}\n\nfunction renderNode(node: DocNode): string {\n const p = node.props\n\n switch (node.type) {\n case 'document':\n return renderChildren(node.children)\n\n case 'page':\n return renderChildren(node.children)\n\n case 'section':\n return `${renderChildren(node.children)}\\n`\n\n case 'row':\n case 'column':\n return renderChildren(node.children)\n\n case 'heading': {\n const level = (p.level as number) ?? 1\n const prefix = '#'.repeat(Math.min(Math.max(level, 1), 6))\n return `${prefix} ${renderInline(node.children)}\\n\\n`\n }\n\n case 'text': {\n let text = renderInline(node.children)\n if (p.bold) text = `**${text}**`\n if (p.italic) text = `*${text}*`\n if (p.strikethrough) text = `~~${text}~~`\n return `${text}\\n\\n`\n }\n\n case 'link':\n return `[${renderInline(node.children)}](${sanitizeHref(p.href as string)})`\n\n case 'image': {\n const alt = (p.alt as string) ?? ''\n let md = `![${alt}](${sanitizeImageSrc(p.src as string)})`\n if (p.caption) md += `\\n*${p.caption}*`\n return `${md}\\n\\n`\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(\n resolveColumn,\n )\n const rows = (p.rows ?? []) as (string | number)[][]\n\n if (columns.length === 0) return ''\n\n // Header\n const header = `| ${columns.map((c) => c.header).join(' | ')} |`\n\n // Separator with alignment\n const separator = `| ${columns\n .map((c) => {\n const align = c.align ?? 'left'\n if (align === 'center') return ':---:'\n if (align === 'right') return '---:'\n return '---'\n })\n .join(' | ')} |`\n\n // Rows\n const body = rows\n .map(\n (row) => `| ${row.map((cell) => String(cell ?? '')).join(' | ')} |`,\n )\n .join('\\n')\n\n let md = `${header}\\n${separator}\\n${body}\\n\\n`\n if (p.caption) md = `*${p.caption}*\\n\\n${md}`\n return md\n }\n\n case 'list': {\n const ordered = p.ordered as boolean | undefined\n return `${node.children\n .filter((c): c is DocNode => typeof c !== 'string')\n .map((item, i) => {\n const prefix = ordered ? `${i + 1}.` : '-'\n return `${prefix} ${renderInline(item.children)}`\n })\n .join('\\n')}\\n\\n`\n }\n\n case 'list-item':\n return renderInline(node.children)\n\n case 'code': {\n const lang = (p.language as string) ?? ''\n const content = renderInline(node.children)\n return `\\`\\`\\`${lang}\\n${content}\\n\\`\\`\\`\\n\\n`\n }\n\n case 'divider':\n return '---\\n\\n'\n\n case 'page-break':\n return '---\\n\\n'\n\n case 'spacer':\n return '\\n'\n\n case 'button':\n return `[${renderInline(node.children)}](${sanitizeHref(p.href as string)})\\n\\n`\n\n case 'quote':\n return `> ${renderInline(node.children)}\\n\\n`\n\n default:\n return renderChildren(node.children)\n }\n}\n\nexport const markdownRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n return `${renderNode(node).trim()}\\n`\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-CdtlFGC0.js","names":[],"sources":["../src/renderers/markdown.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from \"../sanitize\"\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from \"../types\"\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === \"string\" ? { header: col } : col\n}\n\nfunction renderChild(child: DocChild): string {\n if (typeof child === \"string\") return child\n return renderNode(child)\n}\n\nfunction renderChildren(children: DocChild[]): string {\n return children.map(renderChild).join(\"\")\n}\n\nfunction renderInline(children: DocChild[]): string {\n return children.map(renderChild).join(\"\")\n}\n\nfunction renderNode(node: DocNode): string {\n const p = node.props\n\n switch (node.type) {\n case \"document\":\n return renderChildren(node.children)\n\n case \"page\":\n return renderChildren(node.children)\n\n case \"section\":\n return `${renderChildren(node.children)}\\n`\n\n case \"row\":\n case \"column\":\n return renderChildren(node.children)\n\n case \"heading\": {\n const level = (p.level as number) ?? 1\n const prefix = \"#\".repeat(Math.min(Math.max(level, 1), 6))\n return `${prefix} ${renderInline(node.children)}\\n\\n`\n }\n\n case \"text\": {\n let text = renderInline(node.children)\n if (p.bold) text = `**${text}**`\n if (p.italic) text = `*${text}*`\n if (p.strikethrough) text = `~~${text}~~`\n return `${text}\\n\\n`\n }\n\n case \"link\":\n return `[${renderInline(node.children)}](${sanitizeHref(p.href as string)})`\n\n case \"image\": {\n const alt = (p.alt as string) ?? \"\"\n let md = `![${alt}](${sanitizeImageSrc(p.src as string)})`\n if (p.caption) md += `\\n*${p.caption}*`\n return `${md}\\n\\n`\n }\n\n case \"table\": {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n\n if (columns.length === 0) return \"\"\n\n // Header\n const header = `| ${columns.map((c) => c.header).join(\" | \")} |`\n\n // Separator with alignment\n const separator = `| ${columns\n .map((c) => {\n const align = c.align ?? \"left\"\n if (align === \"center\") return \":---:\"\n if (align === \"right\") return \"---:\"\n return \"---\"\n })\n .join(\" | \")} |`\n\n // Rows\n const body = rows\n .map((row) => `| ${row.map((cell) => String(cell ?? \"\")).join(\" | \")} |`)\n .join(\"\\n\")\n\n let md = `${header}\\n${separator}\\n${body}\\n\\n`\n if (p.caption) md = `*${p.caption}*\\n\\n${md}`\n return md\n }\n\n case \"list\": {\n const ordered = p.ordered as boolean | undefined\n return `${node.children\n .filter((c): c is DocNode => typeof c !== \"string\")\n .map((item, i) => {\n const prefix = ordered ? `${i + 1}.` : \"-\"\n return `${prefix} ${renderInline(item.children)}`\n })\n .join(\"\\n\")}\\n\\n`\n }\n\n case \"list-item\":\n return renderInline(node.children)\n\n case \"code\": {\n const lang = (p.language as string) ?? \"\"\n const content = renderInline(node.children)\n return `\\`\\`\\`${lang}\\n${content}\\n\\`\\`\\`\\n\\n`\n }\n\n case \"divider\":\n return \"---\\n\\n\"\n\n case \"page-break\":\n return \"---\\n\\n\"\n\n case \"spacer\":\n return \"\\n\"\n\n case \"button\":\n return `[${renderInline(node.children)}](${sanitizeHref(p.href as string)})\\n\\n`\n\n case \"quote\":\n return `> ${renderInline(node.children)}\\n\\n`\n\n default:\n return renderChildren(node.children)\n }\n}\n\nexport const markdownRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n return `${renderNode(node).trim()}\\n`\n },\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"notion-iG2C5bEY.js","names":[],"sources":["../src/renderers/notion.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from '../sanitize'\nimport type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * Notion renderer — outputs Notion Block JSON for the Notion API.\n * Blocks can be appended to a page via `notion.blocks.children.append()`.\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) =>\n typeof c === 'string' ? c : getTextContent((c as DocNode).children),\n )\n .join('')\n}\n\ninterface RichText {\n type: 'text'\n text: { content: string; link?: { url: string } }\n annotations?: {\n bold?: boolean\n italic?: boolean\n strikethrough?: boolean\n underline?: boolean\n code?: boolean\n }\n}\n\nfunction textToRichText(\n text: string,\n annotations?: RichText['annotations'],\n): RichText[] {\n return [\n {\n type: 'text',\n text: { content: text },\n ...(annotations ? { annotations } : {}),\n },\n ]\n}\n\ninterface NotionBlock {\n object: 'block'\n type: string\n [key: string]: unknown\n}\n\nfunction nodeToBlocks(node: DocNode): NotionBlock[] {\n const p = node.props\n const blocks: NotionBlock[] = []\n\n switch (node.type) {\n case 'document':\n case 'page':\n case 'section':\n case 'row':\n case 'column':\n for (const child of node.children) {\n if (typeof child !== 'string') {\n blocks.push(...nodeToBlocks(child))\n }\n }\n break\n\n case 'heading': {\n const level = (p.level as number) ?? 1\n const text = getTextContent(node.children)\n const type =\n level <= 1 ? 'heading_1' : level === 2 ? 'heading_2' : 'heading_3'\n blocks.push({\n object: 'block',\n type,\n [type]: { rich_text: textToRichText(text) },\n })\n break\n }\n\n case 'text': {\n const text = getTextContent(node.children)\n const annotations: RichText['annotations'] = {}\n if (p.bold) annotations.bold = true\n if (p.italic) annotations.italic = true\n if (p.strikethrough) annotations.strikethrough = true\n if (p.underline) annotations.underline = true\n blocks.push({\n object: 'block',\n type: 'paragraph',\n paragraph: {\n rich_text: textToRichText(\n text,\n Object.keys(annotations).length > 0 ? annotations : undefined,\n ),\n },\n })\n break\n }\n\n case 'link': {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n blocks.push({\n object: 'block',\n type: 'paragraph',\n paragraph: {\n rich_text: [\n { type: 'text', text: { content: text, link: { url: href } } },\n ],\n },\n })\n break\n }\n\n case 'image': {\n const src = sanitizeImageSrc(p.src as string)\n if (src.startsWith('http')) {\n blocks.push({\n object: 'block',\n type: 'image',\n image: {\n type: 'external',\n external: { url: src },\n ...(p.caption\n ? { caption: textToRichText(p.caption as string) }\n : {}),\n },\n })\n }\n break\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(\n resolveColumn,\n )\n const rows = (p.rows ?? []) as (string | number)[][]\n\n const tableRows: NotionBlock[] = []\n\n // Header row\n tableRows.push({\n object: 'block',\n type: 'table_row',\n table_row: {\n cells: columns.map((col) =>\n textToRichText(col.header, { bold: true }),\n ),\n },\n })\n\n // Data rows\n for (const row of rows) {\n tableRows.push({\n object: 'block',\n type: 'table_row',\n table_row: {\n cells: columns.map((_, i) => textToRichText(String(row[i] ?? ''))),\n },\n })\n }\n\n blocks.push({\n object: 'block',\n type: 'table',\n table: {\n table_width: columns.length,\n has_column_header: true,\n children: tableRows,\n },\n })\n break\n }\n\n case 'list': {\n const ordered = p.ordered as boolean | undefined\n const items = node.children.filter(\n (c): c is DocNode => typeof c !== 'string',\n )\n for (const item of items) {\n const text = getTextContent(item.children)\n const type = ordered ? 'numbered_list_item' : 'bulleted_list_item'\n blocks.push({\n object: 'block',\n type,\n [type]: { rich_text: textToRichText(text) },\n })\n }\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n const lang = (p.language as string) ?? 'plain text'\n blocks.push({\n object: 'block',\n type: 'code',\n code: {\n rich_text: textToRichText(text),\n language: lang,\n },\n })\n break\n }\n\n case 'divider':\n case 'page-break':\n blocks.push({ object: 'block', type: 'divider', divider: {} })\n break\n\n case 'spacer':\n blocks.push({\n object: 'block',\n type: 'paragraph',\n paragraph: { rich_text: [] },\n })\n break\n\n case 'button': {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n blocks.push({\n object: 'block',\n type: 'paragraph',\n paragraph: {\n rich_text: [\n {\n type: 'text',\n text: { content: text, link: { url: href } },\n annotations: { bold: true },\n },\n ],\n },\n })\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n blocks.push({\n object: 'block',\n type: 'quote',\n quote: { rich_text: textToRichText(text) },\n })\n break\n }\n }\n\n return blocks\n}\n\nexport const notionRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const blocks = nodeToBlocks(node)\n return JSON.stringify({ children: blocks }, null, 2)\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"notion-iG2C5bEY.js","names":[],"sources":["../src/renderers/notion.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc } from \"../sanitize\"\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from \"../types\"\n\n/**\n * Notion renderer — outputs Notion Block JSON for the Notion API.\n * Blocks can be appended to a page via `notion.blocks.children.append()`.\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === \"string\" ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) => (typeof c === \"string\" ? c : getTextContent((c as DocNode).children)))\n .join(\"\")\n}\n\ninterface RichText {\n type: \"text\"\n text: { content: string; link?: { url: string } }\n annotations?: {\n bold?: boolean\n italic?: boolean\n strikethrough?: boolean\n underline?: boolean\n code?: boolean\n }\n}\n\nfunction textToRichText(text: string, annotations?: RichText[\"annotations\"]): RichText[] {\n return [\n {\n type: \"text\",\n text: { content: text },\n ...(annotations ? { annotations } : {}),\n },\n ]\n}\n\ninterface NotionBlock {\n object: \"block\"\n type: string\n [key: string]: unknown\n}\n\nfunction nodeToBlocks(node: DocNode): NotionBlock[] {\n const p = node.props\n const blocks: NotionBlock[] = []\n\n switch (node.type) {\n case \"document\":\n case \"page\":\n case \"section\":\n case \"row\":\n case \"column\":\n for (const child of node.children) {\n if (typeof child !== \"string\") {\n blocks.push(...nodeToBlocks(child))\n }\n }\n break\n\n case \"heading\": {\n const level = (p.level as number) ?? 1\n const text = getTextContent(node.children)\n const type = level <= 1 ? \"heading_1\" : level === 2 ? \"heading_2\" : \"heading_3\"\n blocks.push({\n object: \"block\",\n type,\n [type]: { rich_text: textToRichText(text) },\n })\n break\n }\n\n case \"text\": {\n const text = getTextContent(node.children)\n const annotations: RichText[\"annotations\"] = {}\n if (p.bold) annotations.bold = true\n if (p.italic) annotations.italic = true\n if (p.strikethrough) annotations.strikethrough = true\n if (p.underline) annotations.underline = true\n blocks.push({\n object: \"block\",\n type: \"paragraph\",\n paragraph: {\n rich_text: textToRichText(\n text,\n Object.keys(annotations).length > 0 ? annotations : undefined,\n ),\n },\n })\n break\n }\n\n case \"link\": {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n blocks.push({\n object: \"block\",\n type: \"paragraph\",\n paragraph: {\n rich_text: [{ type: \"text\", text: { content: text, link: { url: href } } }],\n },\n })\n break\n }\n\n case \"image\": {\n const src = sanitizeImageSrc(p.src as string)\n if (src.startsWith(\"http\")) {\n blocks.push({\n object: \"block\",\n type: \"image\",\n image: {\n type: \"external\",\n external: { url: src },\n ...(p.caption ? { caption: textToRichText(p.caption as string) } : {}),\n },\n })\n }\n break\n }\n\n case \"table\": {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n\n const tableRows: NotionBlock[] = []\n\n // Header row\n tableRows.push({\n object: \"block\",\n type: \"table_row\",\n table_row: {\n cells: columns.map((col) => textToRichText(col.header, { bold: true })),\n },\n })\n\n // Data rows\n for (const row of rows) {\n tableRows.push({\n object: \"block\",\n type: \"table_row\",\n table_row: {\n cells: columns.map((_, i) => textToRichText(String(row[i] ?? \"\"))),\n },\n })\n }\n\n blocks.push({\n object: \"block\",\n type: \"table\",\n table: {\n table_width: columns.length,\n has_column_header: true,\n children: tableRows,\n },\n })\n break\n }\n\n case \"list\": {\n const ordered = p.ordered as boolean | undefined\n const items = node.children.filter((c): c is DocNode => typeof c !== \"string\")\n for (const item of items) {\n const text = getTextContent(item.children)\n const type = ordered ? \"numbered_list_item\" : \"bulleted_list_item\"\n blocks.push({\n object: \"block\",\n type,\n [type]: { rich_text: textToRichText(text) },\n })\n }\n break\n }\n\n case \"code\": {\n const text = getTextContent(node.children)\n const lang = (p.language as string) ?? \"plain text\"\n blocks.push({\n object: \"block\",\n type: \"code\",\n code: {\n rich_text: textToRichText(text),\n language: lang,\n },\n })\n break\n }\n\n case \"divider\":\n case \"page-break\":\n blocks.push({ object: \"block\", type: \"divider\", divider: {} })\n break\n\n case \"spacer\":\n blocks.push({\n object: \"block\",\n type: \"paragraph\",\n paragraph: { rich_text: [] },\n })\n break\n\n case \"button\": {\n const href = sanitizeHref(p.href as string)\n const text = getTextContent(node.children)\n blocks.push({\n object: \"block\",\n type: \"paragraph\",\n paragraph: {\n rich_text: [\n {\n type: \"text\",\n text: { content: text, link: { url: href } },\n annotations: { bold: true },\n },\n ],\n },\n })\n break\n }\n\n case \"quote\": {\n const text = getTextContent(node.children)\n blocks.push({\n object: \"block\",\n type: \"quote\",\n quote: { rich_text: textToRichText(text) },\n })\n break\n }\n }\n\n return blocks\n}\n\nexport const notionRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const blocks = nodeToBlocks(node)\n return JSON.stringify({ children: blocks }, null, 2)\n },\n}\n"],"mappings":"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"}
@@ -369,8 +369,14 @@ function renderHeaderFooter(node) {
369
369
  };
370
370
  }
371
371
  const pdfRenderer = { async render(node, _options) {
372
- const pdfMakeModule = await import("./pdfmake-DnmLxK4Q.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
373
- const pdfFontsModule = await import("./vfs_fonts-Df1kkZ4Y.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
372
+ let pdfMakeModule;
373
+ let pdfFontsModule;
374
+ try {
375
+ pdfMakeModule = await import("./pdfmake-CKMX5URW.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
376
+ pdfFontsModule = await import("./vfs_fonts-Cap07Jg3.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
377
+ } catch {
378
+ throw new Error("[@pyreon/document] PDF renderer requires \"pdfmake\" package. Install it: bun add pdfmake");
379
+ }
374
380
  let pdfMake = pdfMakeModule.default ?? pdfMakeModule;
375
381
  if (pdfMake.default && typeof pdfMake.default.createPdf === "function") pdfMake = pdfMake.default;
376
382
  const pdfFonts = pdfFontsModule.default ?? pdfFontsModule;
@@ -416,4 +422,4 @@ const pdfRenderer = { async render(node, _options) {
416
422
 
417
423
  //#endregion
418
424
  export { pdfRenderer };
419
- //# sourceMappingURL=pdf-DIUQUEdj.js.map
425
+ //# sourceMappingURL=pdf-IuBgTb3T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-IuBgTb3T.js","names":[],"sources":["../src/renderers/pdf.ts"],"sourcesContent":["import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from \"../types\"\n\n/**\n * PDF renderer — lazy-loads pdfmake on first use.\n * pdfmake handles pagination, tables, text wrapping, and font embedding.\n *\n * @example\n * ```ts\n * import { render, Document, Page, Heading } from '@pyreon/document'\n *\n * const doc = Document({\n * title: 'Report',\n * children: Page({ children: Heading({ children: 'Hello' }) }),\n * })\n * const pdf = await render(doc, 'pdf') // → Uint8Array\n * ```\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === \"string\" ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) => (typeof c === \"string\" ? c : getTextContent((c as DocNode).children)))\n .join(\"\")\n}\n\ntype PdfContent = Record<string, unknown> | string | PdfContent[]\n\n/** pdfmake expects page sizes as `{ width, height }` objects. */\nconst PAGE_SIZES: Record<string, { width: number; height: number }> = {\n A3: { width: 841.89, height: 1190.55 },\n A4: { width: 595.28, height: 841.89 },\n A5: { width: 419.53, height: 595.28 },\n letter: { width: 612, height: 792 },\n legal: { width: 612, height: 1008 },\n tabloid: { width: 792, height: 1224 },\n}\n\n/**\n * Resolve an image `src` for pdfmake.\n *\n * - `data:` URIs are passed through directly (pdfmake supports base64).\n * - `http(s)://` URLs cannot be resolved at render time in the browser.\n * A placeholder text node is returned instead.\n * - Relative / absolute paths (e.g. `/logo.png`) cannot be resolved without\n * a server-side fetch, so they are skipped with a placeholder.\n */\nfunction resolveImageSrc(\n src: string,\n): { image: string } | { text: string; italics: true; color: string } {\n if (src.startsWith(\"data:\")) {\n return { image: src }\n }\n if (src.startsWith(\"http://\") || src.startsWith(\"https://\")) {\n return { text: `[Image: ${src}]`, italics: true, color: \"#999999\" }\n }\n // Local path — cannot resolve in browser\n return { text: `[Image: ${src}]`, italics: true, color: \"#999999\" }\n}\n\nfunction nodeToContent(node: DocNode): PdfContent | PdfContent[] | null {\n const p = node.props\n\n switch (node.type) {\n case \"document\":\n case \"page\":\n return node.children\n .map((c) => (typeof c === \"string\" ? c : nodeToContent(c)))\n .filter((c): c is PdfContent => c != null)\n\n case \"section\": {\n const content = node.children\n .map((c) => (typeof c === \"string\" ? c : nodeToContent(c)))\n .filter((c): c is PdfContent => c != null)\n .flat()\n\n if (p.direction === \"row\") {\n return {\n columns: node.children\n .filter((c): c is DocNode => typeof c !== \"string\")\n .map((child) => ({\n stack: [nodeToContent(child)].flat().filter(Boolean),\n width: child.props.width === \"*\" || !child.props.width ? \"*\" : child.props.width,\n })),\n columnGap: (p.gap as number) ?? 0,\n }\n }\n\n return content\n }\n\n case \"row\": {\n return {\n columns: node.children\n .filter((c): c is DocNode => typeof c !== \"string\")\n .map((child) => ({\n stack: [nodeToContent(child)].flat().filter(Boolean),\n width: child.props.width ?? \"*\",\n })),\n columnGap: (p.gap as number) ?? 0,\n }\n }\n\n case \"column\":\n return node.children\n .map((c) => (typeof c === \"string\" ? c : nodeToContent(c)))\n .filter((c): c is PdfContent => c != null)\n .flat()\n\n case \"heading\": {\n const level = (p.level as number) ?? 1\n const sizes: Record<number, number> = {\n 1: 24,\n 2: 20,\n 3: 18,\n 4: 16,\n 5: 14,\n 6: 12,\n }\n return {\n text: getTextContent(node.children),\n fontSize: sizes[level] ?? 18,\n bold: true,\n color: (p.color as string) ?? \"#000000\",\n alignment: (p.align as string) ?? \"left\",\n margin: [0, level === 1 ? 0 : 8, 0, 8],\n }\n }\n\n case \"text\":\n return {\n text: getTextContent(node.children),\n fontSize: (p.size as number) ?? 12,\n color: (p.color as string) ?? \"#333333\",\n bold: p.bold ?? false,\n italics: p.italic ?? false,\n decoration: p.underline ? \"underline\" : p.strikethrough ? \"lineThrough\" : undefined,\n alignment: (p.align as string) ?? \"left\",\n lineHeight: (p.lineHeight as number) ?? 1.4,\n margin: [0, 0, 0, 8],\n }\n\n case \"link\":\n return {\n text: getTextContent(node.children),\n link: p.href as string,\n color: (p.color as string) ?? \"#4f46e5\",\n decoration: \"underline\",\n }\n\n case \"image\": {\n const src = p.src as string\n const resolved = resolveImageSrc(src)\n\n if (\"image\" in resolved) {\n const result: Record<string, unknown> = {\n image: resolved.image,\n fit: [p.width ?? 500, p.height ?? 400],\n margin: [0, 0, 0, 8],\n }\n if (p.align === \"center\") result.alignment = \"center\"\n if (p.align === \"right\") result.alignment = \"right\"\n return result\n }\n\n // Placeholder for non-resolvable images\n return { ...resolved, margin: [0, 0, 0, 8] }\n }\n\n case \"table\": {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n const hs = p.headerStyle as { background?: string; color?: string } | undefined\n\n const headerRow = columns.map((col) => ({\n text: col.header,\n bold: true,\n fillColor: hs?.background ?? \"#f5f5f5\",\n color: hs?.color ?? \"#000000\",\n alignment: col.align ?? \"left\",\n }))\n\n const dataRows = rows.map((row, rowIdx) =>\n columns.map((col, colIdx) => ({\n text: String(row[colIdx] ?? \"\"),\n alignment: col.align ?? \"left\",\n fillColor: p.striped && rowIdx % 2 === 1 ? \"#f9f9f9\" : undefined,\n })),\n )\n\n const widths = columns.map((col) => {\n if (!col.width) return \"*\"\n if (typeof col.width === \"string\" && col.width.endsWith(\"%\")) {\n return col.width\n }\n return col.width\n })\n\n return {\n table: {\n headerRows: 1,\n widths,\n body: [headerRow, ...dataRows],\n },\n layout: p.bordered ? undefined : \"lightHorizontalLines\",\n unbreakable: p.keepTogether ?? false,\n margin: [0, 0, 0, 12],\n }\n }\n\n case \"list\": {\n const items = node.children\n .filter((c): c is DocNode => typeof c !== \"string\")\n .map((item) => getTextContent(item.children))\n\n return p.ordered ? { ol: items, margin: [0, 0, 0, 8] } : { ul: items, margin: [0, 0, 0, 8] }\n }\n\n case \"list-item\":\n return getTextContent(node.children)\n\n case \"code\":\n return {\n text: getTextContent(node.children),\n font: \"Courier\",\n fontSize: 10,\n background: \"#f5f5f5\",\n margin: [0, 0, 0, 8],\n }\n\n case \"page-break\":\n return { text: \"\", pageBreak: \"after\" }\n\n case \"divider\":\n return {\n canvas: [\n {\n type: \"line\",\n x1: 0,\n y1: 0,\n x2: 515,\n y2: 0,\n lineWidth: (p.thickness as number) ?? 1,\n lineColor: (p.color as string) ?? \"#dddddd\",\n },\n ],\n margin: [0, 8, 0, 8],\n }\n\n case \"spacer\":\n return { text: \"\", margin: [0, (p.height as number) ?? 12, 0, 0] }\n\n case \"button\":\n return {\n text: getTextContent(node.children),\n link: p.href as string,\n bold: true,\n color: (p.color as string) ?? \"#ffffff\",\n background: (p.background as string) ?? \"#4f46e5\",\n margin: [0, 8, 0, 8],\n }\n\n case \"quote\":\n return {\n table: {\n widths: [4, \"*\"],\n body: [\n [\n { text: \"\", fillColor: (p.borderColor as string) ?? \"#dddddd\" },\n {\n text: getTextContent(node.children),\n italics: true,\n color: \"#555555\",\n margin: [8, 4, 0, 4],\n },\n ],\n ],\n },\n layout: \"noBorders\",\n margin: [0, 4, 0, 8],\n }\n\n default:\n return null\n }\n}\n\nfunction resolveMargin(\n margin: number | [number, number] | [number, number, number, number] | undefined,\n): [number, number, number, number] {\n if (margin == null) return [40, 40, 40, 40]\n if (typeof margin === \"number\") return [margin, margin, margin, margin]\n if (margin.length === 2) return [margin[1], margin[0], margin[1], margin[0]]\n return margin\n}\n\n/**\n * Render header/footer DocNodes into pdfmake content for page headers/footers.\n *\n * pdfmake header/footer functions receive `(currentPage, pageCount, pageSize)`\n * and must return a content object. We flatten the DocNode into static content.\n */\nfunction renderHeaderFooter(node: DocNode | undefined): PdfContent | undefined {\n if (!node) return undefined\n const content = nodeToContent(node)\n if (content == null) return undefined\n if (Array.isArray(content)) return { stack: content, margin: [40, 10, 40, 0] }\n if (typeof content === \"object\") return { ...content, margin: [40, 10, 40, 0] }\n return { text: content, margin: [40, 10, 40, 0] }\n}\n\nexport const pdfRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {\n // Lazy-load pdfmake — handle ESM/CJS interop\n let pdfMakeModule: any\n let pdfFontsModule: any\n try {\n pdfMakeModule = await import(\"pdfmake/build/pdfmake\")\n pdfFontsModule = await import(\"pdfmake/build/vfs_fonts\")\n } catch {\n throw new Error(\n '[@pyreon/document] PDF renderer requires \"pdfmake\" package. Install it: bun add pdfmake',\n )\n }\n\n // Resolve the actual exports (handle .default for ESM wrappers).\n // pdfmake's default export is a singleton instance of browser_extensions_pdfmake.\n // ESM interop may wrap it in an extra .default layer.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- pdfmake types are incomplete\n let pdfMake: any = pdfMakeModule.default ?? pdfMakeModule\n if (pdfMake.default && typeof pdfMake.default.createPdf === \"function\") {\n pdfMake = pdfMake.default\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- pdfmake types are incomplete\n const pdfFonts: any = pdfFontsModule.default ?? pdfFontsModule\n\n // Assign virtual filesystem for fonts\n if (pdfMake.vfs == null) {\n pdfMake.vfs = pdfFonts.pdfMake?.vfs ?? pdfFonts.vfs\n }\n\n // Find page config\n const pageNode = node.children.find(\n (c): c is DocNode => typeof c !== \"string\" && c.type === \"page\",\n )\n const pageSize = (pageNode?.props.size as string) ?? \"A4\"\n const pageOrientation = (pageNode?.props.orientation as string) ?? \"portrait\"\n const pageMargin = resolveMargin(\n pageNode?.props.margin as\n | number\n | [number, number]\n | [number, number, number, number]\n | undefined,\n )\n\n const content = [nodeToContent(node)].flat().filter(Boolean) as PdfContent[]\n\n // Build header/footer from PageProps if present\n const headerFn = renderHeaderFooter(pageNode?.props.header as DocNode | undefined)\n const footerFn = renderHeaderFooter(pageNode?.props.footer as DocNode | undefined)\n\n const docDefinition: Record<string, unknown> = {\n pageSize: PAGE_SIZES[pageSize] ?? PAGE_SIZES.A4,\n pageOrientation,\n pageMargins: pageMargin,\n info: {\n title: (node.props.title as string) ?? \"\",\n author: (node.props.author as string) ?? \"\",\n subject: (node.props.subject as string) ?? \"\",\n keywords: (node.props.keywords as string[])?.join(\", \") ?? \"\",\n },\n content,\n defaultStyle: {\n fontSize: 12,\n lineHeight: 1.4,\n },\n // Keep sections together — break before a heading if it would be\n // orphaned at the bottom of a page.\n pageBreakBefore: (\n currentNode: { headlineLevel?: number },\n helpers: { getFollowingNodesOnPage?: () => unknown[] },\n ) => {\n if (currentNode.headlineLevel && helpers.getFollowingNodesOnPage) {\n const following = helpers.getFollowingNodesOnPage()\n if (following.length === 0) return true\n }\n return false\n },\n }\n\n if (headerFn) docDefinition.header = headerFn\n if (footerFn) docDefinition.footer = footerFn\n\n try {\n const pdf = pdfMake.createPdf(docDefinition)\n const buffer = await pdf.getBuffer()\n return new Uint8Array(buffer)\n } catch (err) {\n throw new Error(`[@pyreon/document] PDF generation failed: ${err}`)\n }\n },\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { t as __commonJSMin } from "./chunk-ErZ26oRB.js";
2
2
 
3
- //#region ../../node_modules/.bun/pdfmake@0.3.7/node_modules/pdfmake/build/pdfmake.js
3
+ //#region ../../../node_modules/.bun/pdfmake@0.3.7/node_modules/pdfmake/build/pdfmake.js
4
4
  var require_pdfmake = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
5
  /*! pdfmake v0.3.7, @license MIT, @link http://pdfmake.org */
6
6
  (function webpackUniversalModuleDefinition(root, factory) {
@@ -55446,11 +55446,9 @@ while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] &
55446
55446
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
55447
55447
  return c > 3 && r && Object.defineProperty(target, key, r), r;
55448
55448
  }
55449
- Object.create;
55450
55449
  function __await(v) {
55451
55450
  return this instanceof __await ? (this.v = v, this) : new __await(v);
55452
55451
  }
55453
- Object.create;
55454
55452
  var ownKeys = function(o) {
55455
55453
  ownKeys = Object.getOwnPropertyNames || function(o) {
55456
55454
  var ar = [];
@@ -55508,4 +55506,4 @@ while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] &
55508
55506
  //#endregion
55509
55507
  export default require_pdfmake();
55510
55508
 
55511
- //# sourceMappingURL=pdfmake-DnmLxK4Q.js.map
55509
+ //# sourceMappingURL=pdfmake-CKMX5URW.js.map