@pyreon/document 0.0.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/lib/analysis/index.js.html +5406 -0
  3. package/lib/chunk-ErZ26oRB.js +48 -0
  4. package/lib/confluence-Va8e7RxQ.js +192 -0
  5. package/lib/confluence-Va8e7RxQ.js.map +1 -0
  6. package/lib/csv-2c38ub-Y.js +32 -0
  7. package/lib/csv-2c38ub-Y.js.map +1 -0
  8. package/lib/discord-DAoUZqvE.js +134 -0
  9. package/lib/discord-DAoUZqvE.js.map +1 -0
  10. package/lib/dist-BsqdI2nY.js +20179 -0
  11. package/lib/dist-BsqdI2nY.js.map +1 -0
  12. package/lib/docx-CorFwEH9.js +450 -0
  13. package/lib/docx-CorFwEH9.js.map +1 -0
  14. package/lib/email-Bn_Brjdp.js +131 -0
  15. package/lib/email-Bn_Brjdp.js.map +1 -0
  16. package/lib/exceljs-BoIDUUaw.js +34377 -0
  17. package/lib/exceljs-BoIDUUaw.js.map +1 -0
  18. package/lib/google-chat-B6I017I1.js +125 -0
  19. package/lib/google-chat-B6I017I1.js.map +1 -0
  20. package/lib/html-De_iS_f0.js +151 -0
  21. package/lib/html-De_iS_f0.js.map +1 -0
  22. package/lib/index.js +619 -0
  23. package/lib/index.js.map +1 -0
  24. package/lib/markdown-BYC_3C9i.js +75 -0
  25. package/lib/markdown-BYC_3C9i.js.map +1 -0
  26. package/lib/notion-DHaQHO6P.js +187 -0
  27. package/lib/notion-DHaQHO6P.js.map +1 -0
  28. package/lib/pdf-CDPc5Itc.js +419 -0
  29. package/lib/pdf-CDPc5Itc.js.map +1 -0
  30. package/lib/pdfmake-DnmLxK4Q.js +55511 -0
  31. package/lib/pdfmake-DnmLxK4Q.js.map +1 -0
  32. package/lib/pptx-DKQU6bjq.js +252 -0
  33. package/lib/pptx-DKQU6bjq.js.map +1 -0
  34. package/lib/pptxgen.es-COcgXsyx.js +5697 -0
  35. package/lib/pptxgen.es-COcgXsyx.js.map +1 -0
  36. package/lib/slack-CJRJgkag.js +139 -0
  37. package/lib/slack-CJRJgkag.js.map +1 -0
  38. package/lib/svg-BM8biZmL.js +187 -0
  39. package/lib/svg-BM8biZmL.js.map +1 -0
  40. package/lib/teams-S99tonRG.js +176 -0
  41. package/lib/teams-S99tonRG.js.map +1 -0
  42. package/lib/telegram-CbEO_2PN.js +77 -0
  43. package/lib/telegram-CbEO_2PN.js.map +1 -0
  44. package/lib/text-B5U8ucRr.js +75 -0
  45. package/lib/text-B5U8ucRr.js.map +1 -0
  46. package/lib/types/index.d.ts +528 -0
  47. package/lib/types/index.d.ts.map +1 -0
  48. package/lib/vfs_fonts-Df1kkZ4Y.js +19 -0
  49. package/lib/vfs_fonts-Df1kkZ4Y.js.map +1 -0
  50. package/lib/whatsapp-DJ2D1jGG.js +64 -0
  51. package/lib/whatsapp-DJ2D1jGG.js.map +1 -0
  52. package/lib/xlsx-D47x-gZ5.js +199 -0
  53. package/lib/xlsx-D47x-gZ5.js.map +1 -0
  54. package/package.json +62 -0
  55. package/src/builder.ts +266 -0
  56. package/src/download.ts +76 -0
  57. package/src/env.d.ts +17 -0
  58. package/src/index.ts +98 -0
  59. package/src/nodes.ts +315 -0
  60. package/src/render.ts +222 -0
  61. package/src/renderers/confluence.ts +231 -0
  62. package/src/renderers/csv.ts +67 -0
  63. package/src/renderers/discord.ts +192 -0
  64. package/src/renderers/docx.ts +612 -0
  65. package/src/renderers/email.ts +230 -0
  66. package/src/renderers/google-chat.ts +211 -0
  67. package/src/renderers/html.ts +225 -0
  68. package/src/renderers/markdown.ts +144 -0
  69. package/src/renderers/notion.ts +264 -0
  70. package/src/renderers/pdf.ts +427 -0
  71. package/src/renderers/pptx.ts +353 -0
  72. package/src/renderers/slack.ts +192 -0
  73. package/src/renderers/svg.ts +254 -0
  74. package/src/renderers/teams.ts +234 -0
  75. package/src/renderers/telegram.ts +137 -0
  76. package/src/renderers/text.ts +154 -0
  77. package/src/renderers/whatsapp.ts +121 -0
  78. package/src/renderers/xlsx.ts +342 -0
  79. package/src/tests/document.test.ts +2920 -0
  80. package/src/types.ts +291 -0
@@ -0,0 +1,139 @@
1
+ //#region src/renderers/slack.ts
2
+ /**
3
+ * Slack Block Kit renderer — outputs JSON that can be posted via Slack's API.
4
+ * Maps document nodes to Slack blocks (section, header, divider, image, etc.).
5
+ */
6
+ function resolveColumn(col) {
7
+ return typeof col === "string" ? { header: col } : col;
8
+ }
9
+ function getTextContent(children) {
10
+ return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
11
+ }
12
+ function mrkdwn(text) {
13
+ return {
14
+ type: "mrkdwn",
15
+ text
16
+ };
17
+ }
18
+ function plainText(text) {
19
+ return {
20
+ type: "plain_text",
21
+ text
22
+ };
23
+ }
24
+ function nodeToBlocks(node) {
25
+ const p = node.props;
26
+ const blocks = [];
27
+ switch (node.type) {
28
+ case "document":
29
+ case "page":
30
+ case "section":
31
+ case "row":
32
+ case "column":
33
+ for (const child of node.children) if (typeof child !== "string") blocks.push(...nodeToBlocks(child));
34
+ break;
35
+ case "heading":
36
+ blocks.push({
37
+ type: "header",
38
+ text: plainText(getTextContent(node.children))
39
+ });
40
+ break;
41
+ case "text": {
42
+ let text = getTextContent(node.children);
43
+ if (p.bold) text = `*${text}*`;
44
+ if (p.italic) text = `_${text}_`;
45
+ if (p.strikethrough) text = `~${text}~`;
46
+ blocks.push({
47
+ type: "section",
48
+ text: mrkdwn(text)
49
+ });
50
+ break;
51
+ }
52
+ case "link": {
53
+ const href = p.href;
54
+ const text = getTextContent(node.children);
55
+ blocks.push({
56
+ type: "section",
57
+ text: mrkdwn(`<${href}|${text}>`)
58
+ });
59
+ break;
60
+ }
61
+ case "image": {
62
+ const src = p.src;
63
+ if (src.startsWith("http")) blocks.push({
64
+ type: "image",
65
+ image_url: src,
66
+ alt_text: p.alt ?? "Image",
67
+ ...p.caption ? { title: plainText(p.caption) } : {}
68
+ });
69
+ break;
70
+ }
71
+ case "table": {
72
+ const columns = (p.columns ?? []).map(resolveColumn);
73
+ const rows = p.rows ?? [];
74
+ let text = `${columns.map((c) => `*${c.header}*`).join(" | ")}\n${columns.map(() => "---").join(" | ")}\n${rows.map((row) => row.map((cell) => String(cell ?? "")).join(" | ")).join("\n")}`;
75
+ if (p.caption) text = `_${p.caption}_\n${text}`;
76
+ blocks.push({
77
+ type: "section",
78
+ text: mrkdwn(`\`\`\`\n${text}\n\`\`\``)
79
+ });
80
+ break;
81
+ }
82
+ case "list": {
83
+ const ordered = p.ordered;
84
+ const items = node.children.filter((c) => typeof c !== "string").map((item, i) => {
85
+ return `${ordered ? `${i + 1}.` : "•"} ${getTextContent(item.children)}`;
86
+ }).join("\n");
87
+ blocks.push({
88
+ type: "section",
89
+ text: mrkdwn(items)
90
+ });
91
+ break;
92
+ }
93
+ case "code": {
94
+ const text = getTextContent(node.children);
95
+ const lang = p.language ?? "";
96
+ blocks.push({
97
+ type: "section",
98
+ text: mrkdwn(`\`\`\`${lang}\n${text}\n\`\`\``)
99
+ });
100
+ break;
101
+ }
102
+ case "divider":
103
+ case "page-break":
104
+ blocks.push({ type: "divider" });
105
+ break;
106
+ case "spacer": break;
107
+ case "button": {
108
+ const href = p.href;
109
+ const text = getTextContent(node.children);
110
+ blocks.push({
111
+ type: "actions",
112
+ elements: [{
113
+ type: "button",
114
+ text: plainText(text),
115
+ url: href,
116
+ style: "primary"
117
+ }]
118
+ });
119
+ break;
120
+ }
121
+ case "quote": {
122
+ const text = getTextContent(node.children);
123
+ blocks.push({
124
+ type: "section",
125
+ text: mrkdwn(`> ${text}`)
126
+ });
127
+ break;
128
+ }
129
+ }
130
+ return blocks;
131
+ }
132
+ const slackRenderer = { async render(node, _options) {
133
+ const blocks = nodeToBlocks(node);
134
+ return JSON.stringify({ blocks }, null, 2);
135
+ } };
136
+
137
+ //#endregion
138
+ export { slackRenderer };
139
+ //# sourceMappingURL=slack-CJRJgkag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-CJRJgkag.js","names":[],"sources":["../src/renderers/slack.ts"],"sourcesContent":["import type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * Slack Block Kit renderer — outputs JSON that can be posted via Slack's API.\n * Maps document nodes to Slack blocks (section, header, divider, image, etc.).\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 SlackBlock {\n type: string\n [key: string]: unknown\n}\n\nfunction mrkdwn(text: string): { type: 'mrkdwn'; text: string } {\n return { type: 'mrkdwn', text }\n}\n\nfunction plainText(text: string): { type: 'plain_text'; text: string } {\n return { type: 'plain_text', text }\n}\n\nfunction nodeToBlocks(node: DocNode): SlackBlock[] {\n const p = node.props\n const blocks: SlackBlock[] = []\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 blocks.push({\n type: 'header',\n text: plainText(getTextContent(node.children)),\n })\n break\n\n case 'text': {\n let text = getTextContent(node.children)\n if (p.bold) text = `*${text}*`\n if (p.italic) text = `_${text}_`\n if (p.strikethrough) text = `~${text}~`\n blocks.push({\n type: 'section',\n text: mrkdwn(text),\n })\n break\n }\n\n case 'link': {\n const href = p.href as string\n const text = getTextContent(node.children)\n blocks.push({\n type: 'section',\n text: mrkdwn(`<${href}|${text}>`),\n })\n break\n }\n\n case 'image': {\n const src = p.src as string\n // Slack only supports public URLs for images\n if (src.startsWith('http')) {\n blocks.push({\n type: 'image',\n image_url: src,\n alt_text: (p.alt as string) ?? 'Image',\n ...(p.caption ? { title: plainText(p.caption as string) } : {}),\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 // Slack doesn't have native tables — render as formatted text\n const header = columns.map((c) => `*${c.header}*`).join(' | ')\n const separator = columns.map(() => '---').join(' | ')\n const body = rows\n .map((row) => row.map((cell) => String(cell ?? '')).join(' | '))\n .join('\\n')\n\n let text = `${header}\\n${separator}\\n${body}`\n if (p.caption) text = `_${p.caption}_\\n${text}`\n\n blocks.push({\n type: 'section',\n text: mrkdwn(`\\`\\`\\`\\n${text}\\n\\`\\`\\``),\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 blocks.push({\n type: 'section',\n text: mrkdwn(items),\n })\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n const lang = (p.language as string) ?? ''\n blocks.push({\n type: 'section',\n text: mrkdwn(`\\`\\`\\`${lang}\\n${text}\\n\\`\\`\\``),\n })\n break\n }\n\n case 'divider':\n case 'page-break':\n blocks.push({ type: 'divider' })\n break\n\n case 'spacer':\n // No equivalent in Slack — skip\n break\n\n case 'button': {\n const href = p.href as string\n const text = getTextContent(node.children)\n blocks.push({\n type: 'actions',\n elements: [\n {\n type: 'button',\n text: plainText(text),\n url: href,\n style: 'primary',\n },\n ],\n })\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n blocks.push({\n type: 'section',\n text: mrkdwn(`> ${text}`),\n })\n break\n }\n }\n\n return blocks\n}\n\nexport const slackRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const blocks = nodeToBlocks(node)\n return JSON.stringify({ blocks }, null, 2)\n },\n}\n"],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ //#region src/renderers/svg.ts
2
+ /**
3
+ * SVG renderer — generates a standalone SVG document from the node tree.
4
+ * Useful for thumbnails, social cards, and preview images.
5
+ * No external dependencies — pure SVG string generation.
6
+ */
7
+ function resolveColumn(col) {
8
+ return typeof col === "string" ? { header: col } : col;
9
+ }
10
+ function escapeXml(str) {
11
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12
+ }
13
+ function getTextContent(children) {
14
+ return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
15
+ }
16
+ function renderNode(node, ctx) {
17
+ const p = node.props;
18
+ const contentWidth = ctx.width - ctx.padding * 2;
19
+ let svg = "";
20
+ switch (node.type) {
21
+ case "document":
22
+ case "page":
23
+ case "section":
24
+ case "row":
25
+ case "column":
26
+ for (const child of node.children) if (typeof child !== "string") svg += renderNode(child, ctx);
27
+ break;
28
+ case "heading": {
29
+ const level = p.level ?? 1;
30
+ const size = {
31
+ 1: 28,
32
+ 2: 24,
33
+ 3: 20,
34
+ 4: 18,
35
+ 5: 16,
36
+ 6: 14
37
+ }[level] ?? 24;
38
+ const color = p.color ?? "#000000";
39
+ const text = escapeXml(getTextContent(node.children));
40
+ ctx.y += size + 8;
41
+ svg += `<text x="${ctx.padding}" y="${ctx.y}" font-size="${size}" font-weight="bold" fill="${color}" font-family="system-ui, -apple-system, sans-serif">${text}</text>`;
42
+ ctx.y += 12;
43
+ break;
44
+ }
45
+ case "text": {
46
+ const size = p.size ?? 14;
47
+ const color = p.color ?? "#333333";
48
+ const weight = p.bold ? "bold" : "normal";
49
+ const style = p.italic ? "italic" : "normal";
50
+ const text = escapeXml(getTextContent(node.children));
51
+ ctx.y += size + 4;
52
+ svg += `<text x="${ctx.padding}" y="${ctx.y}" font-size="${size}" font-weight="${weight}" font-style="${style}" fill="${color}" font-family="system-ui, -apple-system, sans-serif">${text}</text>`;
53
+ ctx.y += 10;
54
+ break;
55
+ }
56
+ case "link": {
57
+ const href = p.href;
58
+ const text = escapeXml(getTextContent(node.children));
59
+ const color = p.color ?? "#4f46e5";
60
+ ctx.y += 18;
61
+ svg += `<a href="${escapeXml(href)}"><text x="${ctx.padding}" y="${ctx.y}" font-size="14" fill="${color}" text-decoration="underline" font-family="system-ui, -apple-system, sans-serif">${text}</text></a>`;
62
+ ctx.y += 10;
63
+ break;
64
+ }
65
+ case "image": {
66
+ const width = p.width ?? Math.min(contentWidth, 400);
67
+ const height = p.height ?? 200;
68
+ const src = p.src;
69
+ if (src.startsWith("data:") || src.startsWith("http")) svg += `<image x="${ctx.padding}" y="${ctx.y}" width="${width}" height="${height}" href="${escapeXml(src)}" />`;
70
+ else {
71
+ svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${width}" height="${height}" fill="#f0f0f0" stroke="#ddd" rx="4" />`;
72
+ svg += `<text x="${ctx.padding + width / 2}" y="${ctx.y + height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999" font-family="system-ui, sans-serif">${escapeXml(p.alt ?? "Image")}</text>`;
73
+ }
74
+ ctx.y += height + 8;
75
+ if (p.caption) {
76
+ ctx.y += 14;
77
+ svg += `<text x="${ctx.padding}" y="${ctx.y}" font-size="12" fill="#666" font-style="italic" font-family="system-ui, sans-serif">${escapeXml(p.caption)}</text>`;
78
+ ctx.y += 8;
79
+ }
80
+ break;
81
+ }
82
+ case "table": {
83
+ const columns = (p.columns ?? []).map(resolveColumn);
84
+ const rows = p.rows ?? [];
85
+ const hs = p.headerStyle;
86
+ const striped = p.striped;
87
+ const colWidth = contentWidth / columns.length;
88
+ const rowHeight = 28;
89
+ const headerBg = hs?.background ?? "#f5f5f5";
90
+ const headerColor = hs?.color ?? "#000000";
91
+ svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${rowHeight}" fill="${headerBg}" />`;
92
+ for (let i = 0; i < columns.length; i++) {
93
+ const col = columns[i];
94
+ if (!col) continue;
95
+ svg += `<text x="${ctx.padding + i * colWidth + 8}" y="${ctx.y + 18}" font-size="12" font-weight="bold" fill="${headerColor}" font-family="system-ui, sans-serif">${escapeXml(col.header)}</text>`;
96
+ }
97
+ ctx.y += rowHeight;
98
+ for (let r = 0; r < rows.length; r++) {
99
+ if (striped && r % 2 === 1) svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${rowHeight}" fill="#f9f9f9" />`;
100
+ for (let c = 0; c < columns.length; c++) svg += `<text x="${ctx.padding + c * colWidth + 8}" y="${ctx.y + 18}" font-size="12" fill="#333" font-family="system-ui, sans-serif">${escapeXml(String(rows[r]?.[c] ?? ""))}</text>`;
101
+ ctx.y += rowHeight;
102
+ }
103
+ svg += `<line x1="${ctx.padding}" y1="${ctx.y}" x2="${ctx.padding + contentWidth}" y2="${ctx.y}" stroke="#ddd" stroke-width="1" />`;
104
+ ctx.y += 12;
105
+ break;
106
+ }
107
+ case "list": {
108
+ const ordered = p.ordered;
109
+ const items = node.children.filter((c) => typeof c !== "string");
110
+ for (let i = 0; i < items.length; i++) {
111
+ const item = items[i];
112
+ if (!item) continue;
113
+ const prefix = ordered ? `${i + 1}.` : "•";
114
+ const text = escapeXml(getTextContent(item.children));
115
+ ctx.y += 18;
116
+ svg += `<text x="${ctx.padding + 16}" y="${ctx.y}" font-size="13" fill="#333" font-family="system-ui, sans-serif">${prefix} ${text}</text>`;
117
+ }
118
+ ctx.y += 10;
119
+ break;
120
+ }
121
+ case "code": {
122
+ const lines = getTextContent(node.children).split("\n");
123
+ const codeHeight = lines.length * 18 + 16;
124
+ svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${codeHeight}" fill="#f5f5f5" rx="4" />`;
125
+ for (let i = 0; i < lines.length; i++) svg += `<text x="${ctx.padding + 12}" y="${ctx.y + 20 + i * 18}" font-size="12" fill="#333" font-family="monospace">${escapeXml(lines[i] ?? "")}</text>`;
126
+ ctx.y += codeHeight + 8;
127
+ break;
128
+ }
129
+ case "divider": {
130
+ const color = p.color ?? "#ddd";
131
+ const thickness = p.thickness ?? 1;
132
+ ctx.y += 12;
133
+ svg += `<line x1="${ctx.padding}" y1="${ctx.y}" x2="${ctx.padding + contentWidth}" y2="${ctx.y}" stroke="${color}" stroke-width="${thickness}" />`;
134
+ ctx.y += 12;
135
+ break;
136
+ }
137
+ case "page-break":
138
+ ctx.y += 16;
139
+ svg += `<line x1="${ctx.padding}" y1="${ctx.y}" x2="${ctx.padding + contentWidth}" y2="${ctx.y}" stroke="#ccc" stroke-width="2" stroke-dasharray="8,4" />`;
140
+ ctx.y += 16;
141
+ break;
142
+ case "spacer":
143
+ ctx.y += p.height ?? 12;
144
+ break;
145
+ case "button": {
146
+ const bg = p.background ?? "#4f46e5";
147
+ const color = p.color ?? "#ffffff";
148
+ const text = escapeXml(getTextContent(node.children));
149
+ const btnWidth = Math.min(text.length * 10 + 48, contentWidth);
150
+ const btnHeight = 40;
151
+ ctx.y += 8;
152
+ svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${btnWidth}" height="${btnHeight}" fill="${bg}" rx="4" />`;
153
+ svg += `<text x="${ctx.padding + btnWidth / 2}" y="${ctx.y + 25}" text-anchor="middle" font-size="14" font-weight="bold" fill="${color}" font-family="system-ui, sans-serif">${text}</text>`;
154
+ ctx.y += btnHeight + 12;
155
+ break;
156
+ }
157
+ case "quote": {
158
+ const borderColor = p.borderColor ?? "#ddd";
159
+ const text = escapeXml(getTextContent(node.children));
160
+ ctx.y += 4;
161
+ svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="4" height="20" fill="${borderColor}" />`;
162
+ svg += `<text x="${ctx.padding + 16}" y="${ctx.y + 15}" font-size="13" fill="#555" font-style="italic" font-family="system-ui, sans-serif">${text}</text>`;
163
+ ctx.y += 28;
164
+ break;
165
+ }
166
+ }
167
+ return svg;
168
+ }
169
+ const svgRenderer = { async render(node, options) {
170
+ const width = 800;
171
+ const padding = 40;
172
+ const ctx = {
173
+ y: padding,
174
+ width,
175
+ padding
176
+ };
177
+ const content = renderNode(node, ctx);
178
+ const height = ctx.y + padding;
179
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"${options?.direction === "rtl" ? " direction=\"rtl\"" : ""}>
180
+ <rect width="${width}" height="${height}" fill="#ffffff" />
181
+ ${content}
182
+ </svg>`;
183
+ } };
184
+
185
+ //#endregion
186
+ export { svgRenderer };
187
+ //# sourceMappingURL=svg-BM8biZmL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg-BM8biZmL.js","names":[],"sources":["../src/renderers/svg.ts"],"sourcesContent":["import type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * SVG renderer — generates a standalone SVG document from the node tree.\n * Useful for thumbnails, social cards, and preview images.\n * No external dependencies — pure SVG string generation.\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction escapeXml(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 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 RenderContext {\n y: number\n width: number\n padding: number\n}\n\nfunction renderNode(node: DocNode, ctx: RenderContext): string {\n const p = node.props\n const contentWidth = ctx.width - ctx.padding * 2\n let svg = ''\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 svg += renderNode(child, ctx)\n }\n }\n break\n\n case 'heading': {\n const level = (p.level as number) ?? 1\n const sizes: Record<number, number> = {\n 1: 28,\n 2: 24,\n 3: 20,\n 4: 18,\n 5: 16,\n 6: 14,\n }\n const size = sizes[level] ?? 24\n const color = (p.color as string) ?? '#000000'\n const text = escapeXml(getTextContent(node.children))\n ctx.y += size + 8\n svg += `<text x=\"${ctx.padding}\" y=\"${ctx.y}\" font-size=\"${size}\" font-weight=\"bold\" fill=\"${color}\" font-family=\"system-ui, -apple-system, sans-serif\">${text}</text>`\n ctx.y += 12\n break\n }\n\n case 'text': {\n const size = (p.size as number) ?? 14\n const color = (p.color as string) ?? '#333333'\n const weight = p.bold ? 'bold' : 'normal'\n const style = p.italic ? 'italic' : 'normal'\n const text = escapeXml(getTextContent(node.children))\n ctx.y += size + 4\n svg += `<text x=\"${ctx.padding}\" y=\"${ctx.y}\" font-size=\"${size}\" font-weight=\"${weight}\" font-style=\"${style}\" fill=\"${color}\" font-family=\"system-ui, -apple-system, sans-serif\">${text}</text>`\n ctx.y += 10\n break\n }\n\n case 'link': {\n const href = p.href as string\n const text = escapeXml(getTextContent(node.children))\n const color = (p.color as string) ?? '#4f46e5'\n ctx.y += 18\n svg += `<a href=\"${escapeXml(href)}\"><text x=\"${ctx.padding}\" y=\"${ctx.y}\" font-size=\"14\" fill=\"${color}\" text-decoration=\"underline\" font-family=\"system-ui, -apple-system, sans-serif\">${text}</text></a>`\n ctx.y += 10\n break\n }\n\n case 'image': {\n const width = (p.width as number) ?? Math.min(contentWidth, 400)\n const height = (p.height as number) ?? 200\n const src = p.src as string\n\n if (src.startsWith('data:') || src.startsWith('http')) {\n svg += `<image x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${width}\" height=\"${height}\" href=\"${escapeXml(src)}\" />`\n } else {\n // Placeholder rectangle for local paths\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${width}\" height=\"${height}\" fill=\"#f0f0f0\" stroke=\"#ddd\" rx=\"4\" />`\n svg += `<text x=\"${ctx.padding + width / 2}\" y=\"${ctx.y + height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" font-size=\"12\" fill=\"#999\" font-family=\"system-ui, sans-serif\">${escapeXml((p.alt as string) ?? 'Image')}</text>`\n }\n ctx.y += height + 8\n\n if (p.caption) {\n ctx.y += 14\n svg += `<text x=\"${ctx.padding}\" y=\"${ctx.y}\" font-size=\"12\" fill=\"#666\" font-style=\"italic\" font-family=\"system-ui, sans-serif\">${escapeXml(p.caption as string)}</text>`\n ctx.y += 8\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 const hs = p.headerStyle as\n | { background?: string; color?: string }\n | undefined\n const striped = p.striped as boolean | undefined\n\n const colWidth = contentWidth / columns.length\n const rowHeight = 28\n const headerBg = hs?.background ?? '#f5f5f5'\n const headerColor = hs?.color ?? '#000000'\n\n // Header\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${contentWidth}\" height=\"${rowHeight}\" fill=\"${headerBg}\" />`\n for (let i = 0; i < columns.length; i++) {\n const col = columns[i]\n if (!col) continue\n svg += `<text x=\"${ctx.padding + i * colWidth + 8}\" y=\"${ctx.y + 18}\" font-size=\"12\" font-weight=\"bold\" fill=\"${headerColor}\" font-family=\"system-ui, sans-serif\">${escapeXml(col.header)}</text>`\n }\n ctx.y += rowHeight\n\n // Rows\n for (let r = 0; r < rows.length; r++) {\n if (striped && r % 2 === 1) {\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${contentWidth}\" height=\"${rowHeight}\" fill=\"#f9f9f9\" />`\n }\n for (let c = 0; c < columns.length; c++) {\n svg += `<text x=\"${ctx.padding + c * colWidth + 8}\" y=\"${ctx.y + 18}\" font-size=\"12\" fill=\"#333\" font-family=\"system-ui, sans-serif\">${escapeXml(String(rows[r]?.[c] ?? ''))}</text>`\n }\n ctx.y += rowHeight\n }\n\n // Bottom border\n svg += `<line x1=\"${ctx.padding}\" y1=\"${ctx.y}\" x2=\"${ctx.padding + contentWidth}\" y2=\"${ctx.y}\" stroke=\"#ddd\" stroke-width=\"1\" />`\n ctx.y += 12\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 (let i = 0; i < items.length; i++) {\n const item = items[i]\n if (!item) continue\n const prefix = ordered ? `${i + 1}.` : '•'\n const text = escapeXml(getTextContent(item.children))\n ctx.y += 18\n svg += `<text x=\"${ctx.padding + 16}\" y=\"${ctx.y}\" font-size=\"13\" fill=\"#333\" font-family=\"system-ui, sans-serif\">${prefix} ${text}</text>`\n }\n ctx.y += 10\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n const lines = text.split('\\n')\n const codeHeight = lines.length * 18 + 16\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${contentWidth}\" height=\"${codeHeight}\" fill=\"#f5f5f5\" rx=\"4\" />`\n for (let i = 0; i < lines.length; i++) {\n svg += `<text x=\"${ctx.padding + 12}\" y=\"${ctx.y + 20 + i * 18}\" font-size=\"12\" fill=\"#333\" font-family=\"monospace\">${escapeXml(lines[i] ?? '')}</text>`\n }\n ctx.y += codeHeight + 8\n break\n }\n\n case 'divider': {\n const color = (p.color as string) ?? '#ddd'\n const thickness = (p.thickness as number) ?? 1\n ctx.y += 12\n svg += `<line x1=\"${ctx.padding}\" y1=\"${ctx.y}\" x2=\"${ctx.padding + contentWidth}\" y2=\"${ctx.y}\" stroke=\"${color}\" stroke-width=\"${thickness}\" />`\n ctx.y += 12\n break\n }\n\n case 'page-break':\n ctx.y += 16\n svg += `<line x1=\"${ctx.padding}\" y1=\"${ctx.y}\" x2=\"${ctx.padding + contentWidth}\" y2=\"${ctx.y}\" stroke=\"#ccc\" stroke-width=\"2\" stroke-dasharray=\"8,4\" />`\n ctx.y += 16\n break\n\n case 'spacer':\n ctx.y += (p.height as number) ?? 12\n break\n\n case 'button': {\n const bg = (p.background as string) ?? '#4f46e5'\n const color = (p.color as string) ?? '#ffffff'\n const text = escapeXml(getTextContent(node.children))\n const btnWidth = Math.min(text.length * 10 + 48, contentWidth)\n const btnHeight = 40\n ctx.y += 8\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"${btnWidth}\" height=\"${btnHeight}\" fill=\"${bg}\" rx=\"4\" />`\n svg += `<text x=\"${ctx.padding + btnWidth / 2}\" y=\"${ctx.y + 25}\" text-anchor=\"middle\" font-size=\"14\" font-weight=\"bold\" fill=\"${color}\" font-family=\"system-ui, sans-serif\">${text}</text>`\n ctx.y += btnHeight + 12\n break\n }\n\n case 'quote': {\n const borderColor = (p.borderColor as string) ?? '#ddd'\n const text = escapeXml(getTextContent(node.children))\n ctx.y += 4\n svg += `<rect x=\"${ctx.padding}\" y=\"${ctx.y}\" width=\"4\" height=\"20\" fill=\"${borderColor}\" />`\n svg += `<text x=\"${ctx.padding + 16}\" y=\"${ctx.y + 15}\" font-size=\"13\" fill=\"#555\" font-style=\"italic\" font-family=\"system-ui, sans-serif\">${text}</text>`\n ctx.y += 28\n break\n }\n }\n\n return svg\n}\n\nexport const svgRenderer: DocumentRenderer = {\n async render(node: DocNode, options?: RenderOptions): Promise<string> {\n const width = 800\n const padding = 40\n const ctx: RenderContext = { y: padding, width, padding }\n\n const content = renderNode(node, ctx)\n const height = ctx.y + padding\n\n const dir = options?.direction === 'rtl' ? ' direction=\"rtl\"' : ''\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\"${dir}>\n<rect width=\"${width}\" height=\"${height}\" fill=\"#ffffff\" />\n${content}\n</svg>`\n },\n}\n"],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ //#region src/renderers/teams.ts
2
+ /**
3
+ * Microsoft Teams renderer — outputs Adaptive Cards JSON.
4
+ * Can be posted via Teams Webhooks, Bot Framework, or Power Automate.
5
+ */
6
+ function resolveColumn(col) {
7
+ return typeof col === "string" ? { header: col } : col;
8
+ }
9
+ function getTextContent(children) {
10
+ return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
11
+ }
12
+ function nodeToElements(node) {
13
+ const p = node.props;
14
+ const elements = [];
15
+ switch (node.type) {
16
+ case "document":
17
+ case "page":
18
+ case "section":
19
+ case "row":
20
+ case "column":
21
+ for (const child of node.children) if (typeof child !== "string") elements.push(...nodeToElements(child));
22
+ break;
23
+ case "heading": {
24
+ const level = p.level ?? 1;
25
+ elements.push({
26
+ type: "TextBlock",
27
+ text: getTextContent(node.children),
28
+ size: {
29
+ 1: "extraLarge",
30
+ 2: "large",
31
+ 3: "medium",
32
+ 4: "default",
33
+ 5: "small",
34
+ 6: "small"
35
+ }[level] ?? "large",
36
+ weight: "bolder",
37
+ wrap: true
38
+ });
39
+ break;
40
+ }
41
+ case "text": {
42
+ let text = getTextContent(node.children);
43
+ if (p.bold) text = `**${text}**`;
44
+ if (p.italic) text = `_${text}_`;
45
+ if (p.strikethrough) text = `~~${text}~~`;
46
+ elements.push({
47
+ type: "TextBlock",
48
+ text,
49
+ wrap: true,
50
+ ...p.color ? { color: "default" } : {},
51
+ ...p.size ? { size: p.size >= 18 ? "large" : "default" } : {}
52
+ });
53
+ break;
54
+ }
55
+ case "link": {
56
+ const href = p.href;
57
+ const text = getTextContent(node.children);
58
+ elements.push({
59
+ type: "TextBlock",
60
+ text: `[${text}](${href})`,
61
+ wrap: true
62
+ });
63
+ break;
64
+ }
65
+ case "image": {
66
+ const src = p.src;
67
+ if (src.startsWith("http")) elements.push({
68
+ type: "Image",
69
+ url: src,
70
+ altText: p.alt ?? "Image",
71
+ size: "large"
72
+ });
73
+ break;
74
+ }
75
+ case "table": {
76
+ const columns = (p.columns ?? []).map(resolveColumn);
77
+ const rows = p.rows ?? [];
78
+ const tableColumns = columns.map((col) => ({
79
+ type: "Column",
80
+ width: "stretch",
81
+ items: [{
82
+ type: "TextBlock",
83
+ text: `**${col.header}**`,
84
+ weight: "bolder",
85
+ wrap: true
86
+ }, ...rows.map((row, i) => ({
87
+ type: "TextBlock",
88
+ text: String(row[columns.indexOf(col)] ?? ""),
89
+ wrap: true,
90
+ separator: i === 0
91
+ }))]
92
+ }));
93
+ elements.push({
94
+ type: "ColumnSet",
95
+ columns: tableColumns
96
+ });
97
+ break;
98
+ }
99
+ case "list": {
100
+ const ordered = p.ordered;
101
+ const items = node.children.filter((c) => typeof c !== "string").map((item, i) => {
102
+ return `${ordered ? `${i + 1}.` : "•"} ${getTextContent(item.children)}`;
103
+ }).join("\n");
104
+ elements.push({
105
+ type: "TextBlock",
106
+ text: items,
107
+ wrap: true
108
+ });
109
+ break;
110
+ }
111
+ case "code": {
112
+ const text = getTextContent(node.children);
113
+ elements.push({
114
+ type: "TextBlock",
115
+ text: `\`\`\`\n${text}\n\`\`\``,
116
+ fontType: "monospace",
117
+ wrap: true
118
+ });
119
+ break;
120
+ }
121
+ case "divider":
122
+ case "page-break":
123
+ elements.push({
124
+ type: "TextBlock",
125
+ text: " ",
126
+ separator: true
127
+ });
128
+ break;
129
+ case "spacer":
130
+ elements.push({
131
+ type: "TextBlock",
132
+ text: " ",
133
+ spacing: "large"
134
+ });
135
+ break;
136
+ case "button":
137
+ elements.push({
138
+ type: "ActionSet",
139
+ actions: [{
140
+ type: "Action.OpenUrl",
141
+ title: getTextContent(node.children),
142
+ url: p.href,
143
+ style: "positive"
144
+ }]
145
+ });
146
+ break;
147
+ case "quote": {
148
+ const text = getTextContent(node.children);
149
+ elements.push({
150
+ type: "Container",
151
+ style: "emphasis",
152
+ items: [{
153
+ type: "TextBlock",
154
+ text: `_${text}_`,
155
+ wrap: true,
156
+ isSubtle: true
157
+ }]
158
+ });
159
+ break;
160
+ }
161
+ }
162
+ return elements;
163
+ }
164
+ const teamsRenderer = { async render(node, _options) {
165
+ const card = {
166
+ type: "AdaptiveCard",
167
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
168
+ version: "1.5",
169
+ body: nodeToElements(node)
170
+ };
171
+ return JSON.stringify(card, null, 2);
172
+ } };
173
+
174
+ //#endregion
175
+ export { teamsRenderer };
176
+ //# sourceMappingURL=teams-S99tonRG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams-S99tonRG.js","names":[],"sources":["../src/renderers/teams.ts"],"sourcesContent":["import type {\n DocChild,\n DocNode,\n DocumentRenderer,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * Microsoft Teams renderer — outputs Adaptive Cards JSON.\n * Can be posted via Teams Webhooks, Bot Framework, or Power Automate.\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 AdaptiveElement {\n type: string\n [key: string]: unknown\n}\n\nfunction nodeToElements(node: DocNode): AdaptiveElement[] {\n const p = node.props\n const elements: AdaptiveElement[] = []\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 elements.push(...nodeToElements(child))\n }\n }\n break\n\n case 'heading': {\n const level = (p.level as number) ?? 1\n const sizeMap: Record<number, string> = {\n 1: 'extraLarge',\n 2: 'large',\n 3: 'medium',\n 4: 'default',\n 5: 'small',\n 6: 'small',\n }\n elements.push({\n type: 'TextBlock',\n text: getTextContent(node.children),\n size: sizeMap[level] ?? 'large',\n weight: 'bolder',\n wrap: true,\n })\n break\n }\n\n case 'text': {\n let text = getTextContent(node.children)\n if (p.bold) text = `**${text}**`\n if (p.italic) text = `_${text}_`\n if (p.strikethrough) text = `~~${text}~~`\n elements.push({\n type: 'TextBlock',\n text,\n wrap: true,\n ...(p.color ? { color: 'default' } : {}),\n ...(p.size\n ? { size: (p.size as number) >= 18 ? 'large' : 'default' }\n : {}),\n })\n break\n }\n\n case 'link': {\n const href = p.href as string\n const text = getTextContent(node.children)\n elements.push({\n type: 'TextBlock',\n text: `[${text}](${href})`,\n wrap: true,\n })\n break\n }\n\n case 'image': {\n const src = p.src as string\n if (src.startsWith('http')) {\n elements.push({\n type: 'Image',\n url: src,\n altText: (p.alt as string) ?? 'Image',\n size: 'large',\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 // Adaptive Cards have native Table support (schema 1.5+)\n const tableColumns = columns.map((col) => ({\n type: 'Column',\n width: 'stretch',\n items: [\n {\n type: 'TextBlock',\n text: `**${col.header}**`,\n weight: 'bolder',\n wrap: true,\n },\n ...rows.map((row, i) => ({\n type: 'TextBlock',\n text: String(row[columns.indexOf(col)] ?? ''),\n wrap: true,\n separator: i === 0,\n })),\n ],\n }))\n\n elements.push({\n type: 'ColumnSet',\n columns: tableColumns,\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 elements.push({\n type: 'TextBlock',\n text: items,\n wrap: true,\n })\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n elements.push({\n type: 'TextBlock',\n text: `\\`\\`\\`\\n${text}\\n\\`\\`\\``,\n fontType: 'monospace',\n wrap: true,\n })\n break\n }\n\n case 'divider':\n case 'page-break':\n elements.push({\n type: 'TextBlock',\n text: ' ',\n separator: true,\n })\n break\n\n case 'spacer':\n elements.push({\n type: 'TextBlock',\n text: ' ',\n spacing: 'large',\n })\n break\n\n case 'button': {\n elements.push({\n type: 'ActionSet',\n actions: [\n {\n type: 'Action.OpenUrl',\n title: getTextContent(node.children),\n url: p.href as string,\n style: 'positive',\n },\n ],\n })\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n elements.push({\n type: 'Container',\n style: 'emphasis',\n items: [\n {\n type: 'TextBlock',\n text: `_${text}_`,\n wrap: true,\n isSubtle: true,\n },\n ],\n })\n break\n }\n }\n\n return elements\n}\n\nexport const teamsRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<string> {\n const body = nodeToElements(node)\n const card = {\n type: 'AdaptiveCard',\n $schema: 'http://adaptivecards.io/schemas/adaptive-card.json',\n version: '1.5',\n body,\n }\n return JSON.stringify(card, null, 2)\n },\n}\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ //#region src/renderers/telegram.ts
2
+ /**
3
+ * Telegram renderer — outputs HTML using Telegram's supported subset.
4
+ * Telegram Bot API supports: <b>, <i>, <u>, <s>, <a>, <code>, <pre>, <blockquote>.
5
+ * No tables, no images inline — images sent separately via sendPhoto.
6
+ */
7
+ function resolveColumn(col) {
8
+ return typeof col === "string" ? { header: col } : col;
9
+ }
10
+ function esc(str) {
11
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12
+ }
13
+ function getTextContent(children) {
14
+ return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
15
+ }
16
+ function renderNode(node) {
17
+ const p = node.props;
18
+ switch (node.type) {
19
+ case "document":
20
+ case "page":
21
+ case "section":
22
+ case "row":
23
+ case "column": return node.children.map((c) => typeof c === "string" ? esc(c) : renderNode(c)).join("");
24
+ case "heading": return `<b>${esc(getTextContent(node.children))}</b>\n\n`;
25
+ case "text": {
26
+ let text = esc(getTextContent(node.children));
27
+ if (p.bold) text = `<b>${text}</b>`;
28
+ if (p.italic) text = `<i>${text}</i>`;
29
+ if (p.underline) text = `<u>${text}</u>`;
30
+ if (p.strikethrough) text = `<s>${text}</s>`;
31
+ return `${text}\n\n`;
32
+ }
33
+ case "link": {
34
+ const href = p.href;
35
+ const text = esc(getTextContent(node.children));
36
+ return `<a href="${esc(href)}">${text}</a>\n\n`;
37
+ }
38
+ case "image": return "";
39
+ case "table": {
40
+ const columns = (p.columns ?? []).map(resolveColumn);
41
+ const rows = p.rows ?? [];
42
+ const header = columns.map((c) => c.header).join(" | ");
43
+ const separator = columns.map(() => "---").join("-+-");
44
+ const body = rows.map((row) => row.map((c) => String(c ?? "")).join(" | ")).join("\n");
45
+ return `<pre>${esc(header)}\n${esc(separator)}\n${esc(body)}</pre>\n\n`;
46
+ }
47
+ case "list": {
48
+ const ordered = p.ordered;
49
+ return `${node.children.filter((c) => typeof c !== "string").map((item, i) => {
50
+ return `${ordered ? `${i + 1}.` : "•"} ${esc(getTextContent(item.children))}`;
51
+ }).join("\n")}\n\n`;
52
+ }
53
+ case "code": {
54
+ const lang = p.language ?? "";
55
+ const text = esc(getTextContent(node.children));
56
+ if (lang) return `<pre><code class="language-${esc(lang)}">${text}</code></pre>\n\n`;
57
+ return `<pre>${text}</pre>\n\n`;
58
+ }
59
+ case "divider":
60
+ case "page-break": return "───────────\n\n";
61
+ case "spacer": return "\n";
62
+ case "button": {
63
+ const href = p.href;
64
+ const text = esc(getTextContent(node.children));
65
+ return `<a href="${esc(href)}">${text}</a>\n\n`;
66
+ }
67
+ case "quote": return `<blockquote>${esc(getTextContent(node.children))}</blockquote>\n\n`;
68
+ default: return "";
69
+ }
70
+ }
71
+ const telegramRenderer = { async render(node, _options) {
72
+ return renderNode(node).trim();
73
+ } };
74
+
75
+ //#endregion
76
+ export { telegramRenderer };
77
+ //# sourceMappingURL=telegram-CbEO_2PN.js.map