@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,450 @@
1
+ //#region src/renderers/docx.ts
2
+ /**
3
+ * DOCX renderer — lazy-loads the 'docx' npm package on first use.
4
+ */
5
+ function resolveColumn(col) {
6
+ return typeof col === "string" ? { header: col } : col;
7
+ }
8
+ function getTextContent(children) {
9
+ return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
10
+ }
11
+ /** Parse a data URL and return the base64 data and media type, or null for external URLs. */
12
+ function parseDataUrl(src) {
13
+ const match = src.match(/^data:(image\/[^;]+);base64,(.+)$/);
14
+ if (!match) return null;
15
+ return {
16
+ mime: match[1],
17
+ data: match[2]
18
+ };
19
+ }
20
+ /** Convert page size name to DOCX page dimensions in twips (1 inch = 1440 twips). */
21
+ function getPageSize(size, orientation) {
22
+ if (!size) return void 0;
23
+ const dims = {
24
+ A4: {
25
+ width: 11906,
26
+ height: 16838
27
+ },
28
+ A3: {
29
+ width: 16838,
30
+ height: 23811
31
+ },
32
+ A5: {
33
+ width: 8391,
34
+ height: 11906
35
+ },
36
+ letter: {
37
+ width: 12240,
38
+ height: 15840
39
+ },
40
+ legal: {
41
+ width: 12240,
42
+ height: 20160
43
+ },
44
+ tabloid: {
45
+ width: 15840,
46
+ height: 24480
47
+ }
48
+ }[size];
49
+ if (!dims) return void 0;
50
+ if (orientation === "landscape") return {
51
+ width: dims.height,
52
+ height: dims.width
53
+ };
54
+ return dims;
55
+ }
56
+ /** Convert margin prop to DOCX section margin (in twips, 1pt ~= 20 twips). */
57
+ function getPageMargins(margin) {
58
+ if (margin == null) return void 0;
59
+ if (typeof margin === "number") {
60
+ const twips = margin * 20;
61
+ return {
62
+ top: twips,
63
+ right: twips,
64
+ bottom: twips,
65
+ left: twips
66
+ };
67
+ }
68
+ if (margin.length === 2) return {
69
+ top: margin[0] * 20,
70
+ right: margin[1] * 20,
71
+ bottom: margin[0] * 20,
72
+ left: margin[1] * 20
73
+ };
74
+ return {
75
+ top: margin[0] * 20,
76
+ right: margin[1] * 20,
77
+ bottom: margin[2] * 20,
78
+ left: margin[3] * 20
79
+ };
80
+ }
81
+ /** Map percentage column width to DOCX table column width. */
82
+ function getColumnWidth(width) {
83
+ if (width == null) return void 0;
84
+ if (typeof width === "number") return void 0;
85
+ const match = width.match(/^(\d+)%$/);
86
+ if (!match) return void 0;
87
+ return {
88
+ size: Number.parseInt(match[1], 10) * 100,
89
+ type: "pct"
90
+ };
91
+ }
92
+ function renderHeading(ctx, n) {
93
+ const { docx, children, alignmentMap } = ctx;
94
+ const p = n.props;
95
+ const level = p.level ?? 1;
96
+ const headingMap = {
97
+ 1: docx.HeadingLevel.HEADING_1,
98
+ 2: docx.HeadingLevel.HEADING_2,
99
+ 3: docx.HeadingLevel.HEADING_3,
100
+ 4: docx.HeadingLevel.HEADING_4,
101
+ 5: docx.HeadingLevel.HEADING_5,
102
+ 6: docx.HeadingLevel.HEADING_6
103
+ };
104
+ children.push(new docx.Paragraph({
105
+ heading: headingMap[level] ?? docx.HeadingLevel.HEADING_1,
106
+ children: [new docx.TextRun({
107
+ text: getTextContent(n.children),
108
+ bold: true,
109
+ color: p.color?.replace("#", "") ?? "000000"
110
+ })],
111
+ alignment: alignmentMap(p.align)
112
+ }));
113
+ }
114
+ function renderTextNode(ctx, n) {
115
+ const { docx, children, alignmentMap } = ctx;
116
+ const p = n.props;
117
+ children.push(new docx.Paragraph({
118
+ children: [new docx.TextRun({
119
+ text: getTextContent(n.children),
120
+ bold: p.bold,
121
+ italics: p.italic,
122
+ underline: p.underline ? {} : void 0,
123
+ strike: p.strikethrough,
124
+ size: p.size ? p.size * 2 : void 0,
125
+ color: p.color?.replace("#", "") ?? "333333"
126
+ })],
127
+ alignment: alignmentMap(p.align),
128
+ spacing: { after: 120 }
129
+ }));
130
+ }
131
+ function renderLink(ctx, n) {
132
+ const { docx, children } = ctx;
133
+ const p = n.props;
134
+ children.push(new docx.Paragraph({ children: [new docx.ExternalHyperlink({
135
+ link: p.href,
136
+ children: [new docx.TextRun({
137
+ text: getTextContent(n.children),
138
+ color: p.color?.replace("#", "") ?? "4f46e5",
139
+ underline: { type: docx.UnderlineType.SINGLE }
140
+ })]
141
+ })] }));
142
+ }
143
+ function renderImage(ctx, n) {
144
+ const { docx, children, alignmentMap } = ctx;
145
+ const p = n.props;
146
+ const src = p.src;
147
+ const parsed = parseDataUrl(src);
148
+ if (parsed) {
149
+ const imgWidth = p.width ?? 300;
150
+ const imgHeight = p.height ?? 200;
151
+ children.push(new docx.Paragraph({
152
+ children: [new docx.ImageRun({
153
+ data: Buffer.from(parsed.data, "base64"),
154
+ transformation: {
155
+ width: imgWidth,
156
+ height: imgHeight
157
+ },
158
+ type: parsed.mime === "image/png" ? "png" : "jpg"
159
+ })],
160
+ alignment: alignmentMap(p.align)
161
+ }));
162
+ if (p.caption) children.push(new docx.Paragraph({
163
+ children: [new docx.TextRun({
164
+ text: p.caption,
165
+ italics: true,
166
+ size: 20,
167
+ color: "666666"
168
+ })],
169
+ alignment: alignmentMap(p.align),
170
+ spacing: { after: 120 }
171
+ }));
172
+ } else {
173
+ const alt = p.alt ?? "Image";
174
+ const caption = p.caption ? ` — ${p.caption}` : "";
175
+ children.push(new docx.Paragraph({ children: [new docx.TextRun({
176
+ text: `[${alt}${caption}]`,
177
+ italics: true,
178
+ color: "999999"
179
+ })] }));
180
+ }
181
+ }
182
+ function renderDocxTable(ctx, n) {
183
+ const { docx, children, alignmentMap } = ctx;
184
+ const p = n.props;
185
+ const columns = (p.columns ?? []).map(resolveColumn);
186
+ const rows = p.rows ?? [];
187
+ const hs = p.headerStyle;
188
+ const borderStyle = p.bordered ? {
189
+ style: docx.BorderStyle.SINGLE,
190
+ size: 1,
191
+ color: "DDDDDD"
192
+ } : void 0;
193
+ const cellBorders = borderStyle ? {
194
+ top: borderStyle,
195
+ bottom: borderStyle,
196
+ left: borderStyle,
197
+ right: borderStyle
198
+ } : void 0;
199
+ const headerRow = new docx.TableRow({
200
+ tableHeader: true,
201
+ children: columns.map((col) => new docx.TableCell({
202
+ children: [new docx.Paragraph({
203
+ children: [new docx.TextRun({
204
+ text: col.header,
205
+ bold: true,
206
+ color: hs?.color?.replace("#", "") ?? "000000"
207
+ })],
208
+ alignment: alignmentMap(col.align)
209
+ })],
210
+ shading: hs?.background ? {
211
+ fill: hs.background.replace("#", ""),
212
+ type: docx.ShadingType.SOLID
213
+ } : void 0,
214
+ borders: cellBorders,
215
+ width: getColumnWidth(col.width)
216
+ }))
217
+ });
218
+ const dataRows = rows.map((row, rowIdx) => new docx.TableRow({ children: columns.map((col, colIdx) => new docx.TableCell({
219
+ children: [new docx.Paragraph({
220
+ children: [new docx.TextRun({ text: String(row[colIdx] ?? "") })],
221
+ alignment: alignmentMap(col.align)
222
+ })],
223
+ shading: p.striped && rowIdx % 2 === 1 ? {
224
+ fill: "F9F9F9",
225
+ type: docx.ShadingType.SOLID
226
+ } : void 0,
227
+ borders: cellBorders,
228
+ width: getColumnWidth(col.width)
229
+ })) }));
230
+ if (p.caption) children.push(new docx.Paragraph({
231
+ children: [new docx.TextRun({
232
+ text: p.caption,
233
+ italics: true,
234
+ size: 20
235
+ })],
236
+ spacing: { after: 60 }
237
+ }));
238
+ children.push(new docx.Table({
239
+ rows: [headerRow, ...dataRows],
240
+ width: {
241
+ size: 100,
242
+ type: docx.WidthType.PERCENTAGE
243
+ }
244
+ }));
245
+ children.push(new docx.Paragraph({
246
+ text: "",
247
+ spacing: { after: 120 }
248
+ }));
249
+ }
250
+ function renderList(ctx, n) {
251
+ const { docx, children, processListItems, nextListId } = ctx;
252
+ const ordered = n.props.ordered;
253
+ processListItems(n, nextListId(), 0, ordered ?? false);
254
+ children.push(new docx.Paragraph({
255
+ text: "",
256
+ spacing: { after: 60 }
257
+ }));
258
+ }
259
+ function renderButtonOrQuote(ctx, n) {
260
+ const { docx, children } = ctx;
261
+ const p = n.props;
262
+ const text = getTextContent(n.children);
263
+ if (n.type === "button") children.push(new docx.Paragraph({
264
+ children: [new docx.ExternalHyperlink({
265
+ link: p.href,
266
+ children: [new docx.TextRun({
267
+ text,
268
+ bold: true,
269
+ color: "4F46E5",
270
+ underline: { type: docx.UnderlineType.SINGLE }
271
+ })]
272
+ })],
273
+ spacing: { after: 120 }
274
+ }));
275
+ else children.push(new docx.Paragraph({
276
+ children: [new docx.TextRun({
277
+ text,
278
+ italics: true,
279
+ color: "555555"
280
+ })],
281
+ indent: { left: 720 },
282
+ border: { left: {
283
+ style: docx.BorderStyle.SINGLE,
284
+ size: 6,
285
+ color: p.borderColor?.replace("#", "") ?? "DDDDDD"
286
+ } },
287
+ spacing: { after: 120 }
288
+ }));
289
+ }
290
+ const docxRenderer = { async render(node, _options) {
291
+ const docx = await import("./dist-BsqdI2nY.js");
292
+ const children = [];
293
+ let listCounter = 0;
294
+ function alignmentMap(align) {
295
+ if (!align) return void 0;
296
+ return {
297
+ left: docx.AlignmentType.LEFT,
298
+ center: docx.AlignmentType.CENTER,
299
+ right: docx.AlignmentType.RIGHT,
300
+ justify: docx.AlignmentType.JUSTIFIED
301
+ }[align];
302
+ }
303
+ function processListItems(n, listRef, level, ordered) {
304
+ const items = n.children.filter((c) => typeof c !== "string");
305
+ for (const item of items) {
306
+ const nestedList = item.children.find((c) => typeof c !== "string" && c.type === "list");
307
+ const textChildren = item.children.filter((c) => typeof c === "string" || c.type !== "list");
308
+ children.push(new docx.Paragraph({
309
+ children: [new docx.TextRun({ text: getTextContent(textChildren) })],
310
+ numbering: ordered ? {
311
+ reference: listRef,
312
+ level
313
+ } : void 0,
314
+ bullet: ordered ? void 0 : { level }
315
+ }));
316
+ if (nestedList) {
317
+ const nestedOrdered = nestedList.props.ordered;
318
+ processListItems(nestedList, listRef, level + 1, nestedOrdered ?? false);
319
+ }
320
+ }
321
+ }
322
+ const ctx = {
323
+ docx,
324
+ children,
325
+ alignmentMap,
326
+ processListItems,
327
+ nextListId: () => `list-${listCounter++}`
328
+ };
329
+ function processNode(n) {
330
+ switch (n.type) {
331
+ case "document":
332
+ case "page":
333
+ case "section":
334
+ case "row":
335
+ case "column":
336
+ for (const child of n.children) if (typeof child !== "string") processNode(child);
337
+ else children.push(new docx.Paragraph({ text: child }));
338
+ break;
339
+ case "heading":
340
+ renderHeading(ctx, n);
341
+ break;
342
+ case "text":
343
+ renderTextNode(ctx, n);
344
+ break;
345
+ case "link":
346
+ renderLink(ctx, n);
347
+ break;
348
+ case "image":
349
+ renderImage(ctx, n);
350
+ break;
351
+ case "table":
352
+ renderDocxTable(ctx, n);
353
+ break;
354
+ case "list":
355
+ renderList(ctx, n);
356
+ break;
357
+ case "code":
358
+ children.push(new docx.Paragraph({
359
+ children: [new docx.TextRun({
360
+ text: getTextContent(n.children),
361
+ font: "Courier New",
362
+ size: 20
363
+ })],
364
+ shading: {
365
+ fill: "F5F5F5",
366
+ type: docx.ShadingType.SOLID
367
+ },
368
+ spacing: { after: 120 }
369
+ }));
370
+ break;
371
+ case "divider":
372
+ children.push(new docx.Paragraph({
373
+ border: { bottom: {
374
+ style: docx.BorderStyle.SINGLE,
375
+ size: n.props.thickness ?? 1,
376
+ color: n.props.color?.replace("#", "") ?? "DDDDDD"
377
+ } },
378
+ spacing: {
379
+ before: 120,
380
+ after: 120
381
+ }
382
+ }));
383
+ break;
384
+ case "spacer":
385
+ children.push(new docx.Paragraph({
386
+ text: "",
387
+ spacing: { after: n.props.height * 20 }
388
+ }));
389
+ break;
390
+ case "button":
391
+ case "quote":
392
+ renderButtonOrQuote(ctx, n);
393
+ break;
394
+ }
395
+ }
396
+ processNode(node);
397
+ const numberingConfigs = [];
398
+ for (let i = 0; i < listCounter; i++) numberingConfigs.push({
399
+ reference: `list-${i}`,
400
+ levels: Array.from({ length: 9 }, (_, level) => ({
401
+ level,
402
+ format: docx.LevelFormat.DECIMAL,
403
+ text: `%${level + 1}.`,
404
+ alignment: docx.AlignmentType.LEFT,
405
+ style: { paragraph: { indent: {
406
+ left: 720 * (level + 1),
407
+ hanging: 360
408
+ } } }
409
+ }))
410
+ });
411
+ const pageProps = (node.type === "document" ? node.children.find((c) => typeof c !== "string" && c.type === "page") : node.type === "page" ? node : void 0)?.props ?? {};
412
+ const pageDims = getPageSize(pageProps.size, pageProps.orientation);
413
+ const pageMargins = getPageMargins(pageProps.margin);
414
+ function buildHeaderFooter(contentNode) {
415
+ if (!contentNode) return void 0;
416
+ const text = getTextContent(contentNode.children);
417
+ if (!text) return void 0;
418
+ return [new docx.Paragraph({
419
+ children: [new docx.TextRun({
420
+ text,
421
+ size: 18,
422
+ color: "999999"
423
+ })],
424
+ alignment: docx.AlignmentType.CENTER
425
+ })];
426
+ }
427
+ const headerContent = buildHeaderFooter(pageProps.header);
428
+ const footerContent = buildHeaderFooter(pageProps.footer);
429
+ const sectionProperties = {};
430
+ if (pageDims) sectionProperties.page = {
431
+ size: pageDims,
432
+ margin: pageMargins
433
+ };
434
+ else if (pageMargins) sectionProperties.page = { margin: pageMargins };
435
+ const doc = new docx.Document({
436
+ numbering: numberingConfigs.length > 0 ? { config: numberingConfigs } : void 0,
437
+ sections: [{
438
+ properties: sectionProperties,
439
+ headers: headerContent ? { default: new docx.Header({ children: headerContent }) } : void 0,
440
+ footers: footerContent ? { default: new docx.Footer({ children: footerContent }) } : void 0,
441
+ children
442
+ }]
443
+ });
444
+ const buffer = await docx.Packer.toBuffer(doc);
445
+ return new Uint8Array(buffer);
446
+ } };
447
+
448
+ //#endregion
449
+ export { docxRenderer };
450
+ //# sourceMappingURL=docx-CorFwEH9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docx-CorFwEH9.js","names":[],"sources":["../src/renderers/docx.ts"],"sourcesContent":["import type {\n DocChild,\n DocNode,\n DocumentRenderer,\n PageOrientation,\n PageSize,\n RenderOptions,\n TableColumn,\n} from '../types'\n\n/**\n * DOCX renderer — lazy-loads the 'docx' npm package on first use.\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\n/** Parse a data URL and return the base64 data and media type, or null for external URLs. */\nfunction parseDataUrl(src: string): { data: string; mime: string } | null {\n const match = src.match(/^data:(image\\/[^;]+);base64,(.+)$/)\n if (!match) return null\n return { mime: match[1]!, data: match[2]! }\n}\n\n/** Convert page size name to DOCX page dimensions in twips (1 inch = 1440 twips). */\nfunction getPageSize(\n size?: PageSize,\n orientation?: PageOrientation,\n): { width: number; height: number } | undefined {\n if (!size) return undefined\n const sizes: Record<string, { width: number; height: number }> = {\n A4: { width: 11906, height: 16838 },\n A3: { width: 16838, height: 23811 },\n A5: { width: 8391, height: 11906 },\n letter: { width: 12240, height: 15840 },\n legal: { width: 12240, height: 20160 },\n tabloid: { width: 15840, height: 24480 },\n }\n const dims = sizes[size]\n if (!dims) return undefined\n if (orientation === 'landscape') {\n return { width: dims.height, height: dims.width }\n }\n return dims\n}\n\n/** Convert margin prop to DOCX section margin (in twips, 1pt ~= 20 twips). */\nfunction getPageMargins(\n margin?: number | [number, number] | [number, number, number, number],\n): object | undefined {\n if (margin == null) return undefined\n if (typeof margin === 'number') {\n const twips = margin * 20\n return { top: twips, right: twips, bottom: twips, left: twips }\n }\n if (margin.length === 2) {\n return {\n top: margin[0] * 20,\n right: margin[1] * 20,\n bottom: margin[0] * 20,\n left: margin[1] * 20,\n }\n }\n return {\n top: margin[0] * 20,\n right: margin[1] * 20,\n bottom: margin[2] * 20,\n left: margin[3] * 20,\n }\n}\n\n/** Map percentage column width to DOCX table column width. */\nfunction getColumnWidth(\n width?: number | string,\n): { size: number; type: unknown } | undefined {\n if (width == null) return undefined\n if (typeof width === 'number') return undefined\n const match = width.match(/^(\\d+)%$/)\n if (!match) return undefined\n return { size: Number.parseInt(match[1]!, 10) * 100, type: 'pct' as unknown }\n}\n\n/** Shared context passed to per-node-type render helpers. */\ninterface DocxCtx {\n docx: typeof import('docx')\n children: unknown[]\n alignmentMap: (align?: string) => unknown\n processListItems: (\n n: DocNode,\n listRef: string,\n level: number,\n ordered: boolean,\n ) => void\n nextListId: () => string\n}\n\nfunction renderHeading(ctx: DocxCtx, n: DocNode): void {\n const { docx, children, alignmentMap } = ctx\n const p = n.props\n const level = (p.level as number) ?? 1\n const headingMap: Record<number, unknown> = {\n 1: docx.HeadingLevel.HEADING_1,\n 2: docx.HeadingLevel.HEADING_2,\n 3: docx.HeadingLevel.HEADING_3,\n 4: docx.HeadingLevel.HEADING_4,\n 5: docx.HeadingLevel.HEADING_5,\n 6: docx.HeadingLevel.HEADING_6,\n }\n children.push(\n new docx.Paragraph({\n heading: (headingMap[level] ?? docx.HeadingLevel.HEADING_1) as any,\n children: [\n new docx.TextRun({\n text: getTextContent(n.children),\n bold: true,\n color: (p.color as string)?.replace('#', '') ?? '000000',\n }),\n ],\n alignment: alignmentMap(p.align as string) as any,\n }),\n )\n}\n\nfunction renderTextNode(ctx: DocxCtx, n: DocNode): void {\n const { docx, children, alignmentMap } = ctx\n const p = n.props\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: getTextContent(n.children),\n bold: p.bold as boolean | undefined,\n italics: p.italic as boolean | undefined,\n underline: p.underline ? {} : undefined,\n strike: p.strikethrough as boolean | undefined,\n size: p.size ? (p.size as number) * 2 : undefined,\n color: (p.color as string)?.replace('#', '') ?? '333333',\n }),\n ],\n alignment: alignmentMap(p.align as string) as any,\n spacing: { after: 120 },\n }),\n )\n}\n\nfunction renderLink(ctx: DocxCtx, n: DocNode): void {\n const { docx, children } = ctx\n const p = n.props\n children.push(\n new docx.Paragraph({\n children: [\n new docx.ExternalHyperlink({\n link: p.href as string,\n children: [\n new docx.TextRun({\n text: getTextContent(n.children),\n color: (p.color as string)?.replace('#', '') ?? '4f46e5',\n underline: { type: docx.UnderlineType.SINGLE },\n }),\n ],\n }),\n ],\n }),\n )\n}\n\nfunction renderImage(ctx: DocxCtx, n: DocNode): void {\n const { docx, children, alignmentMap } = ctx\n const p = n.props\n const src = p.src as string\n const parsed = parseDataUrl(src)\n\n if (parsed) {\n const imgWidth = (p.width as number) ?? 300\n const imgHeight = (p.height as number) ?? 200\n children.push(\n new docx.Paragraph({\n children: [\n new docx.ImageRun({\n data: Buffer.from(parsed.data, 'base64'),\n transformation: { width: imgWidth, height: imgHeight },\n type: parsed.mime === 'image/png' ? 'png' : 'jpg',\n }),\n ],\n alignment: alignmentMap(p.align as string) as any,\n }),\n )\n if (p.caption) {\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: p.caption as string,\n italics: true,\n size: 20,\n color: '666666',\n }),\n ],\n alignment: alignmentMap(p.align as string) as any,\n spacing: { after: 120 },\n }),\n )\n }\n } else {\n const alt = (p.alt as string) ?? 'Image'\n const caption = p.caption ? ` — ${p.caption}` : ''\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: `[${alt}${caption}]`,\n italics: true,\n color: '999999',\n }),\n ],\n }),\n )\n }\n}\n\nfunction renderDocxTable(ctx: DocxCtx, n: DocNode): void {\n const { docx, children, alignmentMap } = ctx\n const p = n.props\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 bordered = p.bordered as boolean | undefined\n const borderStyle = bordered\n ? { style: docx.BorderStyle.SINGLE, size: 1, color: 'DDDDDD' }\n : undefined\n const cellBorders = borderStyle\n ? {\n top: borderStyle,\n bottom: borderStyle,\n left: borderStyle,\n right: borderStyle,\n }\n : undefined\n\n const headerRow = new docx.TableRow({\n tableHeader: true,\n children: columns.map(\n (col) =>\n new docx.TableCell({\n children: [\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: col.header,\n bold: true,\n color: hs?.color?.replace('#', '') ?? '000000',\n }),\n ],\n alignment: alignmentMap(col.align) as any,\n }),\n ],\n shading: hs?.background\n ? {\n fill: hs.background.replace('#', ''),\n type: docx.ShadingType.SOLID,\n }\n : undefined,\n borders: cellBorders,\n width: getColumnWidth(col.width as string | undefined) as any,\n }),\n ),\n })\n\n const dataRows = rows.map(\n (row, rowIdx) =>\n new docx.TableRow({\n children: columns.map(\n (col, colIdx) =>\n new docx.TableCell({\n children: [\n new docx.Paragraph({\n children: [\n new docx.TextRun({ text: String(row[colIdx] ?? '') }),\n ],\n alignment: alignmentMap(col.align) as any,\n }),\n ],\n shading:\n p.striped && rowIdx % 2 === 1\n ? { fill: 'F9F9F9', type: docx.ShadingType.SOLID }\n : undefined,\n borders: cellBorders,\n width: getColumnWidth(col.width as string | undefined) as any,\n }),\n ),\n }),\n )\n\n if (p.caption) {\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: p.caption as string,\n italics: true,\n size: 20,\n }),\n ],\n spacing: { after: 60 },\n }),\n )\n }\n\n children.push(\n new docx.Table({\n rows: [headerRow, ...dataRows],\n width: { size: 100, type: docx.WidthType.PERCENTAGE },\n }),\n )\n children.push(new docx.Paragraph({ text: '', spacing: { after: 120 } }))\n}\n\nfunction renderList(ctx: DocxCtx, n: DocNode): void {\n const { docx, children, processListItems, nextListId } = ctx\n const ordered = n.props.ordered as boolean | undefined\n const listRef = nextListId()\n processListItems(n, listRef, 0, ordered ?? false)\n children.push(new docx.Paragraph({ text: '', spacing: { after: 60 } }))\n}\n\nfunction renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {\n const { docx, children } = ctx\n const p = n.props\n const text = getTextContent(n.children)\n if (n.type === 'button') {\n children.push(\n new docx.Paragraph({\n children: [\n new docx.ExternalHyperlink({\n link: p.href as string,\n children: [\n new docx.TextRun({\n text,\n bold: true,\n color: '4F46E5',\n underline: { type: docx.UnderlineType.SINGLE },\n }),\n ],\n }),\n ],\n spacing: { after: 120 },\n }),\n )\n } else {\n children.push(\n new docx.Paragraph({\n children: [new docx.TextRun({ text, italics: true, color: '555555' })],\n indent: { left: 720 },\n border: {\n left: {\n style: docx.BorderStyle.SINGLE,\n size: 6,\n color: (p.borderColor as string)?.replace('#', '') ?? 'DDDDDD',\n },\n },\n spacing: { after: 120 },\n }),\n )\n }\n}\n\nexport const docxRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {\n const docx = await import('docx')\n const children: unknown[] = []\n let listCounter = 0\n\n function alignmentMap(align?: string): unknown {\n if (!align) return undefined\n const map: Record<string, unknown> = {\n left: docx.AlignmentType.LEFT,\n center: docx.AlignmentType.CENTER,\n right: docx.AlignmentType.RIGHT,\n justify: docx.AlignmentType.JUSTIFIED,\n }\n return map[align]\n }\n\n function processListItems(\n n: DocNode,\n listRef: string,\n level: number,\n ordered: boolean,\n ): void {\n const items = n.children.filter(\n (c): c is DocNode => typeof c !== 'string',\n )\n for (const item of items) {\n const nestedList = item.children.find(\n (c): c is DocNode =>\n typeof c !== 'string' && (c as DocNode).type === 'list',\n )\n const textChildren = item.children.filter(\n (c) => typeof c === 'string' || (c as DocNode).type !== 'list',\n )\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({ text: getTextContent(textChildren) }),\n ],\n numbering: ordered ? { reference: listRef, level } : undefined,\n bullet: ordered ? undefined : { level },\n }),\n )\n if (nestedList) {\n const nestedOrdered = (nestedList as DocNode).props.ordered as\n | boolean\n | undefined\n processListItems(\n nestedList as DocNode,\n listRef,\n level + 1,\n nestedOrdered ?? false,\n )\n }\n }\n }\n\n const ctx: DocxCtx = {\n docx,\n children,\n alignmentMap,\n processListItems,\n nextListId: () => `list-${listCounter++}`,\n }\n\n function processNode(n: DocNode): void {\n switch (n.type) {\n case 'document':\n case 'page':\n case 'section':\n case 'row':\n case 'column':\n for (const child of n.children) {\n if (typeof child !== 'string') processNode(child)\n else children.push(new docx.Paragraph({ text: child }))\n }\n break\n case 'heading':\n renderHeading(ctx, n)\n break\n case 'text':\n renderTextNode(ctx, n)\n break\n case 'link':\n renderLink(ctx, n)\n break\n case 'image':\n renderImage(ctx, n)\n break\n case 'table':\n renderDocxTable(ctx, n)\n break\n case 'list':\n renderList(ctx, n)\n break\n case 'code':\n children.push(\n new docx.Paragraph({\n children: [\n new docx.TextRun({\n text: getTextContent(n.children),\n font: 'Courier New',\n size: 20,\n }),\n ],\n shading: { fill: 'F5F5F5', type: docx.ShadingType.SOLID },\n spacing: { after: 120 },\n }),\n )\n break\n case 'divider':\n children.push(\n new docx.Paragraph({\n border: {\n bottom: {\n style: docx.BorderStyle.SINGLE,\n size: (n.props.thickness as number | undefined) ?? 1,\n color:\n (n.props.color as string)?.replace('#', '') ?? 'DDDDDD',\n },\n },\n spacing: { before: 120, after: 120 },\n }),\n )\n break\n case 'spacer':\n children.push(\n new docx.Paragraph({\n text: '',\n spacing: { after: (n.props.height as number) * 20 },\n }),\n )\n break\n case 'button':\n case 'quote':\n renderButtonOrQuote(ctx, n)\n break\n }\n }\n\n processNode(node)\n\n // Build numbering configs for all lists\n const numberingConfigs: unknown[] = []\n for (let i = 0; i < listCounter; i++) {\n numberingConfigs.push({\n reference: `list-${i}`,\n levels: Array.from({ length: 9 }, (_, level) => ({\n level,\n format: docx.LevelFormat.DECIMAL,\n text: `%${level + 1}.`,\n alignment: docx.AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 720 * (level + 1), hanging: 360 } },\n },\n })),\n })\n }\n\n // Extract page properties from first page node\n const pageNode =\n node.type === 'document'\n ? (node.children.find(\n (c): c is DocNode =>\n typeof c !== 'string' && (c as DocNode).type === 'page',\n ) as DocNode | undefined)\n : node.type === 'page'\n ? node\n : undefined\n\n const pageProps = pageNode?.props ?? {}\n const pageDims = getPageSize(\n pageProps.size as PageSize | undefined,\n pageProps.orientation as PageOrientation | undefined,\n )\n const pageMargins = getPageMargins(\n pageProps.margin as\n | number\n | [number, number]\n | [number, number, number, number]\n | undefined,\n )\n\n function buildHeaderFooter(\n contentNode: DocNode | undefined,\n ): unknown[] | undefined {\n if (!contentNode) return undefined\n const text = getTextContent(contentNode.children)\n if (!text) return undefined\n return [\n new docx.Paragraph({\n children: [new docx.TextRun({ text, size: 18, color: '999999' })],\n alignment: docx.AlignmentType.CENTER,\n }),\n ]\n }\n\n const headerContent = buildHeaderFooter(\n pageProps.header as DocNode | undefined,\n )\n const footerContent = buildHeaderFooter(\n pageProps.footer as DocNode | undefined,\n )\n\n const sectionProperties: Record<string, unknown> = {}\n if (pageDims) {\n sectionProperties.page = { size: pageDims, margin: pageMargins }\n } else if (pageMargins) {\n sectionProperties.page = { margin: pageMargins }\n }\n\n const doc = new docx.Document({\n numbering: (numberingConfigs.length > 0\n ? { config: numberingConfigs }\n : undefined) as any,\n sections: [\n {\n properties: sectionProperties,\n headers: headerContent\n ? { default: new docx.Header({ children: headerContent as any }) }\n : undefined,\n footers: footerContent\n ? { default: new docx.Footer({ children: footerContent as any }) }\n : undefined,\n children: children as any,\n },\n ],\n })\n\n const buffer = await docx.Packer.toBuffer(doc)\n return new Uint8Array(buffer)\n },\n}\n"],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ //#region src/renderers/email.ts
2
+ /**
3
+ * Email renderer — generates table-based HTML with inline styles
4
+ * that works across Gmail, Outlook, Apple Mail, and other email clients.
5
+ *
6
+ * Key constraints:
7
+ * - No CSS classes (Gmail strips <style> tags)
8
+ * - Table-based layout (no flexbox/grid)
9
+ * - All styles inline
10
+ * - VML buttons for Outlook
11
+ * - Max width 600px for compatibility
12
+ */
13
+ function esc(str) {
14
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
15
+ }
16
+ function resolveColumn(col) {
17
+ return typeof col === "string" ? { header: col } : col;
18
+ }
19
+ function renderChild(child) {
20
+ if (typeof child === "string") return esc(child);
21
+ return renderNode(child);
22
+ }
23
+ function renderChildren(children) {
24
+ return children.map(renderChild).join("");
25
+ }
26
+ function wrapInTable(content, style = "") {
27
+ return `<table width="100%" cellpadding="0" cellspacing="0" border="0"${style ? ` style="${style}"` : ""}><tr><td>${content}</td></tr></table>`;
28
+ }
29
+ function renderNode(node) {
30
+ const p = node.props;
31
+ switch (node.type) {
32
+ case "document": return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">${p.title ? `<title>${esc(p.title)}</title>` : ""}<!--[if mso]><noscript><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript><![endif]--></head><body style="margin:0;padding:0;background-color:#f4f4f4;font-family:Arial,Helvetica,sans-serif">${p.subject ? `<div style="display:none;max-height:0;overflow:hidden">${esc(p.subject)}</div>` : ""}<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#f4f4f4"><tr><td align="center" style="padding:20px 0"><table width="600" cellpadding="0" cellspacing="0" border="0" style="background-color:#ffffff;max-width:600px;width:100%"><tr><td>${renderChildren(node.children)}</td></tr></table></td></tr></table></body></html>`;
33
+ case "page": return renderChildren(node.children);
34
+ case "section": {
35
+ const bg = p.background ? `background-color:${p.background};` : "";
36
+ const pad = p.padding ? `padding:${typeof p.padding === "number" ? `${p.padding}px` : Array.isArray(p.padding) ? p.padding.map((v) => `${v}px`).join(" ") : "0"}` : "padding:0";
37
+ const radius = p.borderRadius ? `border-radius:${p.borderRadius}px;` : "";
38
+ if (p.direction === "row") {
39
+ const children = node.children.filter((c) => typeof c !== "string");
40
+ const colWidth = Math.floor(100 / Math.max(children.length, 1));
41
+ return `<table width="100%" cellpadding="0" cellspacing="0" border="0" style="${bg}${radius}${pad}"><tr>${children.map((child) => `<td width="${colWidth}%" valign="top" style="padding:${p.gap ? `0 ${p.gap / 2}px` : "0"}">${renderNode(child)}</td>`).join("")}</tr></table>`;
42
+ }
43
+ return wrapInTable(renderChildren(node.children), `${bg}${radius}${pad}`);
44
+ }
45
+ case "row": {
46
+ const children = node.children.filter((c) => typeof c !== "string");
47
+ const gap = p.gap ?? 0;
48
+ return `<table width="100%" cellpadding="0" cellspacing="0" border="0"><tr>${children.map((child) => `<td valign="top" style="padding:0 ${gap / 2}px">${renderNode(child)}</td>`).join("")}</tr></table>`;
49
+ }
50
+ case "column": return renderChildren(node.children);
51
+ case "heading": {
52
+ const level = p.level ?? 1;
53
+ return `<h${level} style="margin:0 0 12px 0;font-size:${{
54
+ 1: 28,
55
+ 2: 24,
56
+ 3: 20,
57
+ 4: 18,
58
+ 5: 16,
59
+ 6: 14
60
+ }[level] ?? 24}px;color:${p.color ?? "#000000"};text-align:${p.align ?? "left"};font-weight:bold;line-height:1.3">${renderChildren(node.children)}</h${level}>`;
61
+ }
62
+ case "text": return `<p style="margin:0 0 12px 0;font-size:${p.size ?? 14}px;color:${p.color ?? "#333333"};font-weight:${p.bold ? "bold" : "normal"};font-style:${p.italic ? "italic" : "normal"};text-decoration:${p.underline ? "underline" : p.strikethrough ? "line-through" : "none"};text-align:${p.align ?? "left"};line-height:${p.lineHeight ?? 1.5}">${renderChildren(node.children)}</p>`;
63
+ case "link": return `<a href="${esc(p.href)}" style="color:${p.color ?? "#4f46e5"};text-decoration:underline" target="_blank">${renderChildren(node.children)}</a>`;
64
+ case "image": {
65
+ const align = p.align ?? "left";
66
+ const img = `<img src="${esc(p.src)}"${p.width ? ` width="${p.width}"` : ""}${p.height ? ` height="${p.height}"` : ""} alt="${esc(p.alt ?? "")}" style="display:block;outline:none;border:none;text-decoration:none${p.width ? `;max-width:${p.width}px` : ""}" />`;
67
+ if (p.caption) return `<table cellpadding="0" cellspacing="0" border="0"${align === "center" ? " align=\"center\"" : ""}><tr><td>${img}</td></tr><tr><td style="font-size:12px;color:#666;padding-top:4px;text-align:center">${esc(p.caption)}</td></tr></table>`;
68
+ if (align === "center") return `<div style="text-align:center">${img}</div>`;
69
+ if (align === "right") return `<div style="text-align:right">${img}</div>`;
70
+ return img;
71
+ }
72
+ case "table": {
73
+ const columns = (p.columns ?? []).map(resolveColumn);
74
+ const rows = p.rows ?? [];
75
+ const hs = p.headerStyle;
76
+ const striped = p.striped;
77
+ let html = "<table width=\"100%\" cellpadding=\"8\" cellspacing=\"0\" border=\"0\" style=\"border-collapse:collapse\">";
78
+ if (p.caption) html += `<caption style="font-size:12px;color:#666;padding:8px;text-align:left">${esc(p.caption)}</caption>`;
79
+ html += "<tr>";
80
+ for (const col of columns) {
81
+ const bg = hs?.background ? `background-color:${hs.background};` : "background-color:#f5f5f5;";
82
+ const color = hs?.color ? `color:${hs.color};` : "";
83
+ const align = col.align ? `text-align:${col.align};` : "";
84
+ const width = col.width ? `width:${typeof col.width === "number" ? `${col.width}px` : col.width};` : "";
85
+ html += `<th style="${bg}${color}font-weight:bold;${align}${width}padding:8px;border-bottom:2px solid #ddd">${esc(col.header)}</th>`;
86
+ }
87
+ html += "</tr>";
88
+ for (let i = 0; i < rows.length; i++) {
89
+ const bg = striped && i % 2 === 1 ? "background-color:#f9f9f9;" : "";
90
+ html += "<tr>";
91
+ for (let j = 0; j < columns.length; j++) {
92
+ const col = columns[j];
93
+ const align = col?.align ? `text-align:${col.align};` : "";
94
+ html += `<td style="${bg}${align}padding:8px;border-bottom:1px solid #eee">${esc(String(rows[i]?.[j] ?? ""))}</td>`;
95
+ }
96
+ html += "</tr>";
97
+ }
98
+ html += "</table>";
99
+ return html;
100
+ }
101
+ case "list": {
102
+ const tag = p.ordered ? "ol" : "ul";
103
+ return `<${tag} style="margin:0 0 12px 0;padding-left:24px">${renderChildren(node.children)}</${tag}>`;
104
+ }
105
+ case "list-item": return `<li style="margin:0 0 4px 0;font-size:14px;color:#333">${renderChildren(node.children)}</li>`;
106
+ case "code": return `<pre style="background-color:#f5f5f5;padding:12px;border-radius:4px;font-family:Courier New,monospace;font-size:13px;color:#333;overflow-x:auto;margin:0 0 12px 0"><code>${esc(renderChildren(node.children))}</code></pre>`;
107
+ case "divider": {
108
+ const color = p.color ?? "#dddddd";
109
+ return `<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0"><tr><td style="border-top:${p.thickness ?? 1}px solid ${color};font-size:0;line-height:0">&nbsp;</td></tr></table>`;
110
+ }
111
+ case "page-break": return `<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin:24px 0"><tr><td style="border-top:2px solid #dddddd;font-size:0;line-height:0">&nbsp;</td></tr></table>`;
112
+ case "spacer": return `<div style="height:${p.height}px;line-height:${p.height}px;font-size:0">&nbsp;</div>`;
113
+ case "button": {
114
+ const bg = p.background ?? "#4f46e5";
115
+ const color = p.color ?? "#ffffff";
116
+ const radius = p.borderRadius ?? 4;
117
+ const href = esc(p.href);
118
+ const text = renderChildren(node.children);
119
+ return `<div style="text-align:${p.align ?? "left"};margin:12px 0"><!--[if mso]><v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${href}" style="height:44px;v-text-anchor:middle;width:200px" arcsize="10%" strokecolor="${bg}" fillcolor="${bg}"><w:anchorlock/><center style="color:${color};font-family:Arial,sans-serif;font-size:14px;font-weight:bold">${text}</center></v:roundrect><![endif]--><!--[if !mso]><!--><a href="${href}" style="display:inline-block;background-color:${bg};color:${color};padding:12px 24px;border-radius:${radius}px;text-decoration:none;font-weight:bold;font-size:14px;font-family:Arial,sans-serif" target="_blank">${text}</a><!--<![endif]--></div>`;
120
+ }
121
+ case "quote": return `<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin:12px 0"><tr><td style="border-left:4px solid ${p.borderColor ?? "#dddddd"};padding:12px 20px;color:#555555;font-style:italic">${renderChildren(node.children)}</td></tr></table>`;
122
+ default: return renderChildren(node.children);
123
+ }
124
+ }
125
+ const emailRenderer = { async render(node, _options) {
126
+ return renderNode(node);
127
+ } };
128
+
129
+ //#endregion
130
+ export { emailRenderer };
131
+ //# sourceMappingURL=email-Bn_Brjdp.js.map