@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,612 @@
1
+ import type {
2
+ DocChild,
3
+ DocNode,
4
+ DocumentRenderer,
5
+ PageOrientation,
6
+ PageSize,
7
+ RenderOptions,
8
+ TableColumn,
9
+ } from '../types'
10
+
11
+ /**
12
+ * DOCX renderer — lazy-loads the 'docx' npm package on first use.
13
+ */
14
+
15
+ function resolveColumn(col: string | TableColumn): TableColumn {
16
+ return typeof col === 'string' ? { header: col } : col
17
+ }
18
+
19
+ function getTextContent(children: DocChild[]): string {
20
+ return children
21
+ .map((c) =>
22
+ typeof c === 'string' ? c : getTextContent((c as DocNode).children),
23
+ )
24
+ .join('')
25
+ }
26
+
27
+ /** Parse a data URL and return the base64 data and media type, or null for external URLs. */
28
+ function parseDataUrl(src: string): { data: string; mime: string } | null {
29
+ const match = src.match(/^data:(image\/[^;]+);base64,(.+)$/)
30
+ if (!match) return null
31
+ return { mime: match[1]!, data: match[2]! }
32
+ }
33
+
34
+ /** Convert page size name to DOCX page dimensions in twips (1 inch = 1440 twips). */
35
+ function getPageSize(
36
+ size?: PageSize,
37
+ orientation?: PageOrientation,
38
+ ): { width: number; height: number } | undefined {
39
+ if (!size) return undefined
40
+ const sizes: Record<string, { width: number; height: number }> = {
41
+ A4: { width: 11906, height: 16838 },
42
+ A3: { width: 16838, height: 23811 },
43
+ A5: { width: 8391, height: 11906 },
44
+ letter: { width: 12240, height: 15840 },
45
+ legal: { width: 12240, height: 20160 },
46
+ tabloid: { width: 15840, height: 24480 },
47
+ }
48
+ const dims = sizes[size]
49
+ if (!dims) return undefined
50
+ if (orientation === 'landscape') {
51
+ return { width: dims.height, height: dims.width }
52
+ }
53
+ return dims
54
+ }
55
+
56
+ /** Convert margin prop to DOCX section margin (in twips, 1pt ~= 20 twips). */
57
+ function getPageMargins(
58
+ margin?: number | [number, number] | [number, number, number, number],
59
+ ): object | undefined {
60
+ if (margin == null) return undefined
61
+ if (typeof margin === 'number') {
62
+ const twips = margin * 20
63
+ return { top: twips, right: twips, bottom: twips, left: twips }
64
+ }
65
+ if (margin.length === 2) {
66
+ return {
67
+ top: margin[0] * 20,
68
+ right: margin[1] * 20,
69
+ bottom: margin[0] * 20,
70
+ left: margin[1] * 20,
71
+ }
72
+ }
73
+ return {
74
+ top: margin[0] * 20,
75
+ right: margin[1] * 20,
76
+ bottom: margin[2] * 20,
77
+ left: margin[3] * 20,
78
+ }
79
+ }
80
+
81
+ /** Map percentage column width to DOCX table column width. */
82
+ function getColumnWidth(
83
+ width?: number | string,
84
+ ): { size: number; type: unknown } | undefined {
85
+ if (width == null) return undefined
86
+ if (typeof width === 'number') return undefined
87
+ const match = width.match(/^(\d+)%$/)
88
+ if (!match) return undefined
89
+ return { size: Number.parseInt(match[1]!, 10) * 100, type: 'pct' as unknown }
90
+ }
91
+
92
+ /** Shared context passed to per-node-type render helpers. */
93
+ interface DocxCtx {
94
+ docx: typeof import('docx')
95
+ children: unknown[]
96
+ alignmentMap: (align?: string) => unknown
97
+ processListItems: (
98
+ n: DocNode,
99
+ listRef: string,
100
+ level: number,
101
+ ordered: boolean,
102
+ ) => void
103
+ nextListId: () => string
104
+ }
105
+
106
+ function renderHeading(ctx: DocxCtx, n: DocNode): void {
107
+ const { docx, children, alignmentMap } = ctx
108
+ const p = n.props
109
+ const level = (p.level as number) ?? 1
110
+ const headingMap: Record<number, unknown> = {
111
+ 1: docx.HeadingLevel.HEADING_1,
112
+ 2: docx.HeadingLevel.HEADING_2,
113
+ 3: docx.HeadingLevel.HEADING_3,
114
+ 4: docx.HeadingLevel.HEADING_4,
115
+ 5: docx.HeadingLevel.HEADING_5,
116
+ 6: docx.HeadingLevel.HEADING_6,
117
+ }
118
+ children.push(
119
+ new docx.Paragraph({
120
+ heading: (headingMap[level] ?? docx.HeadingLevel.HEADING_1) as any,
121
+ children: [
122
+ new docx.TextRun({
123
+ text: getTextContent(n.children),
124
+ bold: true,
125
+ color: (p.color as string)?.replace('#', '') ?? '000000',
126
+ }),
127
+ ],
128
+ alignment: alignmentMap(p.align as string) as any,
129
+ }),
130
+ )
131
+ }
132
+
133
+ function renderTextNode(ctx: DocxCtx, n: DocNode): void {
134
+ const { docx, children, alignmentMap } = ctx
135
+ const p = n.props
136
+ children.push(
137
+ new docx.Paragraph({
138
+ children: [
139
+ new docx.TextRun({
140
+ text: getTextContent(n.children),
141
+ bold: p.bold as boolean | undefined,
142
+ italics: p.italic as boolean | undefined,
143
+ underline: p.underline ? {} : undefined,
144
+ strike: p.strikethrough as boolean | undefined,
145
+ size: p.size ? (p.size as number) * 2 : undefined,
146
+ color: (p.color as string)?.replace('#', '') ?? '333333',
147
+ }),
148
+ ],
149
+ alignment: alignmentMap(p.align as string) as any,
150
+ spacing: { after: 120 },
151
+ }),
152
+ )
153
+ }
154
+
155
+ function renderLink(ctx: DocxCtx, n: DocNode): void {
156
+ const { docx, children } = ctx
157
+ const p = n.props
158
+ children.push(
159
+ new docx.Paragraph({
160
+ children: [
161
+ new docx.ExternalHyperlink({
162
+ link: p.href as string,
163
+ children: [
164
+ new docx.TextRun({
165
+ text: getTextContent(n.children),
166
+ color: (p.color as string)?.replace('#', '') ?? '4f46e5',
167
+ underline: { type: docx.UnderlineType.SINGLE },
168
+ }),
169
+ ],
170
+ }),
171
+ ],
172
+ }),
173
+ )
174
+ }
175
+
176
+ function renderImage(ctx: DocxCtx, n: DocNode): void {
177
+ const { docx, children, alignmentMap } = ctx
178
+ const p = n.props
179
+ const src = p.src as string
180
+ const parsed = parseDataUrl(src)
181
+
182
+ if (parsed) {
183
+ const imgWidth = (p.width as number) ?? 300
184
+ const imgHeight = (p.height as number) ?? 200
185
+ children.push(
186
+ new docx.Paragraph({
187
+ children: [
188
+ new docx.ImageRun({
189
+ data: Buffer.from(parsed.data, 'base64'),
190
+ transformation: { width: imgWidth, height: imgHeight },
191
+ type: parsed.mime === 'image/png' ? 'png' : 'jpg',
192
+ }),
193
+ ],
194
+ alignment: alignmentMap(p.align as string) as any,
195
+ }),
196
+ )
197
+ if (p.caption) {
198
+ children.push(
199
+ new docx.Paragraph({
200
+ children: [
201
+ new docx.TextRun({
202
+ text: p.caption as string,
203
+ italics: true,
204
+ size: 20,
205
+ color: '666666',
206
+ }),
207
+ ],
208
+ alignment: alignmentMap(p.align as string) as any,
209
+ spacing: { after: 120 },
210
+ }),
211
+ )
212
+ }
213
+ } else {
214
+ const alt = (p.alt as string) ?? 'Image'
215
+ const caption = p.caption ? ` — ${p.caption}` : ''
216
+ children.push(
217
+ new docx.Paragraph({
218
+ children: [
219
+ new docx.TextRun({
220
+ text: `[${alt}${caption}]`,
221
+ italics: true,
222
+ color: '999999',
223
+ }),
224
+ ],
225
+ }),
226
+ )
227
+ }
228
+ }
229
+
230
+ function renderDocxTable(ctx: DocxCtx, n: DocNode): void {
231
+ const { docx, children, alignmentMap } = ctx
232
+ const p = n.props
233
+ const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
234
+ resolveColumn,
235
+ )
236
+ const rows = (p.rows ?? []) as (string | number)[][]
237
+ const hs = p.headerStyle as
238
+ | { background?: string; color?: string }
239
+ | undefined
240
+ const bordered = p.bordered as boolean | undefined
241
+ const borderStyle = bordered
242
+ ? { style: docx.BorderStyle.SINGLE, size: 1, color: 'DDDDDD' }
243
+ : undefined
244
+ const cellBorders = borderStyle
245
+ ? {
246
+ top: borderStyle,
247
+ bottom: borderStyle,
248
+ left: borderStyle,
249
+ right: borderStyle,
250
+ }
251
+ : undefined
252
+
253
+ const headerRow = new docx.TableRow({
254
+ tableHeader: true,
255
+ children: columns.map(
256
+ (col) =>
257
+ new docx.TableCell({
258
+ children: [
259
+ new docx.Paragraph({
260
+ children: [
261
+ new docx.TextRun({
262
+ text: col.header,
263
+ bold: true,
264
+ color: hs?.color?.replace('#', '') ?? '000000',
265
+ }),
266
+ ],
267
+ alignment: alignmentMap(col.align) as any,
268
+ }),
269
+ ],
270
+ shading: hs?.background
271
+ ? {
272
+ fill: hs.background.replace('#', ''),
273
+ type: docx.ShadingType.SOLID,
274
+ }
275
+ : undefined,
276
+ borders: cellBorders,
277
+ width: getColumnWidth(col.width as string | undefined) as any,
278
+ }),
279
+ ),
280
+ })
281
+
282
+ const dataRows = rows.map(
283
+ (row, rowIdx) =>
284
+ new docx.TableRow({
285
+ children: columns.map(
286
+ (col, colIdx) =>
287
+ new docx.TableCell({
288
+ children: [
289
+ new docx.Paragraph({
290
+ children: [
291
+ new docx.TextRun({ text: String(row[colIdx] ?? '') }),
292
+ ],
293
+ alignment: alignmentMap(col.align) as any,
294
+ }),
295
+ ],
296
+ shading:
297
+ p.striped && rowIdx % 2 === 1
298
+ ? { fill: 'F9F9F9', type: docx.ShadingType.SOLID }
299
+ : undefined,
300
+ borders: cellBorders,
301
+ width: getColumnWidth(col.width as string | undefined) as any,
302
+ }),
303
+ ),
304
+ }),
305
+ )
306
+
307
+ if (p.caption) {
308
+ children.push(
309
+ new docx.Paragraph({
310
+ children: [
311
+ new docx.TextRun({
312
+ text: p.caption as string,
313
+ italics: true,
314
+ size: 20,
315
+ }),
316
+ ],
317
+ spacing: { after: 60 },
318
+ }),
319
+ )
320
+ }
321
+
322
+ children.push(
323
+ new docx.Table({
324
+ rows: [headerRow, ...dataRows],
325
+ width: { size: 100, type: docx.WidthType.PERCENTAGE },
326
+ }),
327
+ )
328
+ children.push(new docx.Paragraph({ text: '', spacing: { after: 120 } }))
329
+ }
330
+
331
+ function renderList(ctx: DocxCtx, n: DocNode): void {
332
+ const { docx, children, processListItems, nextListId } = ctx
333
+ const ordered = n.props.ordered as boolean | undefined
334
+ const listRef = nextListId()
335
+ processListItems(n, listRef, 0, ordered ?? false)
336
+ children.push(new docx.Paragraph({ text: '', spacing: { after: 60 } }))
337
+ }
338
+
339
+ function renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {
340
+ const { docx, children } = ctx
341
+ const p = n.props
342
+ const text = getTextContent(n.children)
343
+ if (n.type === 'button') {
344
+ children.push(
345
+ new docx.Paragraph({
346
+ children: [
347
+ new docx.ExternalHyperlink({
348
+ link: p.href as string,
349
+ children: [
350
+ new docx.TextRun({
351
+ text,
352
+ bold: true,
353
+ color: '4F46E5',
354
+ underline: { type: docx.UnderlineType.SINGLE },
355
+ }),
356
+ ],
357
+ }),
358
+ ],
359
+ spacing: { after: 120 },
360
+ }),
361
+ )
362
+ } else {
363
+ children.push(
364
+ new docx.Paragraph({
365
+ children: [new docx.TextRun({ text, italics: true, color: '555555' })],
366
+ indent: { left: 720 },
367
+ border: {
368
+ left: {
369
+ style: docx.BorderStyle.SINGLE,
370
+ size: 6,
371
+ color: (p.borderColor as string)?.replace('#', '') ?? 'DDDDDD',
372
+ },
373
+ },
374
+ spacing: { after: 120 },
375
+ }),
376
+ )
377
+ }
378
+ }
379
+
380
+ export const docxRenderer: DocumentRenderer = {
381
+ async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {
382
+ const docx = await import('docx')
383
+ const children: unknown[] = []
384
+ let listCounter = 0
385
+
386
+ function alignmentMap(align?: string): unknown {
387
+ if (!align) return undefined
388
+ const map: Record<string, unknown> = {
389
+ left: docx.AlignmentType.LEFT,
390
+ center: docx.AlignmentType.CENTER,
391
+ right: docx.AlignmentType.RIGHT,
392
+ justify: docx.AlignmentType.JUSTIFIED,
393
+ }
394
+ return map[align]
395
+ }
396
+
397
+ function processListItems(
398
+ n: DocNode,
399
+ listRef: string,
400
+ level: number,
401
+ ordered: boolean,
402
+ ): void {
403
+ const items = n.children.filter(
404
+ (c): c is DocNode => typeof c !== 'string',
405
+ )
406
+ for (const item of items) {
407
+ const nestedList = item.children.find(
408
+ (c): c is DocNode =>
409
+ typeof c !== 'string' && (c as DocNode).type === 'list',
410
+ )
411
+ const textChildren = item.children.filter(
412
+ (c) => typeof c === 'string' || (c as DocNode).type !== 'list',
413
+ )
414
+ children.push(
415
+ new docx.Paragraph({
416
+ children: [
417
+ new docx.TextRun({ text: getTextContent(textChildren) }),
418
+ ],
419
+ numbering: ordered ? { reference: listRef, level } : undefined,
420
+ bullet: ordered ? undefined : { level },
421
+ }),
422
+ )
423
+ if (nestedList) {
424
+ const nestedOrdered = (nestedList as DocNode).props.ordered as
425
+ | boolean
426
+ | undefined
427
+ processListItems(
428
+ nestedList as DocNode,
429
+ listRef,
430
+ level + 1,
431
+ nestedOrdered ?? false,
432
+ )
433
+ }
434
+ }
435
+ }
436
+
437
+ const ctx: DocxCtx = {
438
+ docx,
439
+ children,
440
+ alignmentMap,
441
+ processListItems,
442
+ nextListId: () => `list-${listCounter++}`,
443
+ }
444
+
445
+ function processNode(n: DocNode): void {
446
+ switch (n.type) {
447
+ case 'document':
448
+ case 'page':
449
+ case 'section':
450
+ case 'row':
451
+ case 'column':
452
+ for (const child of n.children) {
453
+ if (typeof child !== 'string') processNode(child)
454
+ else children.push(new docx.Paragraph({ text: child }))
455
+ }
456
+ break
457
+ case 'heading':
458
+ renderHeading(ctx, n)
459
+ break
460
+ case 'text':
461
+ renderTextNode(ctx, n)
462
+ break
463
+ case 'link':
464
+ renderLink(ctx, n)
465
+ break
466
+ case 'image':
467
+ renderImage(ctx, n)
468
+ break
469
+ case 'table':
470
+ renderDocxTable(ctx, n)
471
+ break
472
+ case 'list':
473
+ renderList(ctx, n)
474
+ break
475
+ case 'code':
476
+ children.push(
477
+ new docx.Paragraph({
478
+ children: [
479
+ new docx.TextRun({
480
+ text: getTextContent(n.children),
481
+ font: 'Courier New',
482
+ size: 20,
483
+ }),
484
+ ],
485
+ shading: { fill: 'F5F5F5', type: docx.ShadingType.SOLID },
486
+ spacing: { after: 120 },
487
+ }),
488
+ )
489
+ break
490
+ case 'divider':
491
+ children.push(
492
+ new docx.Paragraph({
493
+ border: {
494
+ bottom: {
495
+ style: docx.BorderStyle.SINGLE,
496
+ size: (n.props.thickness as number | undefined) ?? 1,
497
+ color:
498
+ (n.props.color as string)?.replace('#', '') ?? 'DDDDDD',
499
+ },
500
+ },
501
+ spacing: { before: 120, after: 120 },
502
+ }),
503
+ )
504
+ break
505
+ case 'spacer':
506
+ children.push(
507
+ new docx.Paragraph({
508
+ text: '',
509
+ spacing: { after: (n.props.height as number) * 20 },
510
+ }),
511
+ )
512
+ break
513
+ case 'button':
514
+ case 'quote':
515
+ renderButtonOrQuote(ctx, n)
516
+ break
517
+ }
518
+ }
519
+
520
+ processNode(node)
521
+
522
+ // Build numbering configs for all lists
523
+ const numberingConfigs: unknown[] = []
524
+ for (let i = 0; i < listCounter; i++) {
525
+ numberingConfigs.push({
526
+ reference: `list-${i}`,
527
+ levels: Array.from({ length: 9 }, (_, level) => ({
528
+ level,
529
+ format: docx.LevelFormat.DECIMAL,
530
+ text: `%${level + 1}.`,
531
+ alignment: docx.AlignmentType.LEFT,
532
+ style: {
533
+ paragraph: { indent: { left: 720 * (level + 1), hanging: 360 } },
534
+ },
535
+ })),
536
+ })
537
+ }
538
+
539
+ // Extract page properties from first page node
540
+ const pageNode =
541
+ node.type === 'document'
542
+ ? (node.children.find(
543
+ (c): c is DocNode =>
544
+ typeof c !== 'string' && (c as DocNode).type === 'page',
545
+ ) as DocNode | undefined)
546
+ : node.type === 'page'
547
+ ? node
548
+ : undefined
549
+
550
+ const pageProps = pageNode?.props ?? {}
551
+ const pageDims = getPageSize(
552
+ pageProps.size as PageSize | undefined,
553
+ pageProps.orientation as PageOrientation | undefined,
554
+ )
555
+ const pageMargins = getPageMargins(
556
+ pageProps.margin as
557
+ | number
558
+ | [number, number]
559
+ | [number, number, number, number]
560
+ | undefined,
561
+ )
562
+
563
+ function buildHeaderFooter(
564
+ contentNode: DocNode | undefined,
565
+ ): unknown[] | undefined {
566
+ if (!contentNode) return undefined
567
+ const text = getTextContent(contentNode.children)
568
+ if (!text) return undefined
569
+ return [
570
+ new docx.Paragraph({
571
+ children: [new docx.TextRun({ text, size: 18, color: '999999' })],
572
+ alignment: docx.AlignmentType.CENTER,
573
+ }),
574
+ ]
575
+ }
576
+
577
+ const headerContent = buildHeaderFooter(
578
+ pageProps.header as DocNode | undefined,
579
+ )
580
+ const footerContent = buildHeaderFooter(
581
+ pageProps.footer as DocNode | undefined,
582
+ )
583
+
584
+ const sectionProperties: Record<string, unknown> = {}
585
+ if (pageDims) {
586
+ sectionProperties.page = { size: pageDims, margin: pageMargins }
587
+ } else if (pageMargins) {
588
+ sectionProperties.page = { margin: pageMargins }
589
+ }
590
+
591
+ const doc = new docx.Document({
592
+ numbering: (numberingConfigs.length > 0
593
+ ? { config: numberingConfigs }
594
+ : undefined) as any,
595
+ sections: [
596
+ {
597
+ properties: sectionProperties,
598
+ headers: headerContent
599
+ ? { default: new docx.Header({ children: headerContent as any }) }
600
+ : undefined,
601
+ footers: footerContent
602
+ ? { default: new docx.Footer({ children: footerContent as any }) }
603
+ : undefined,
604
+ children: children as any,
605
+ },
606
+ ],
607
+ })
608
+
609
+ const buffer = await docx.Packer.toBuffer(doc)
610
+ return new Uint8Array(buffer)
611
+ },
612
+ }