@pyreon/document 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/analysis/index.js.html +1 -1
  2. package/lib/confluence-Bd3ua1Ut.js.map +1 -1
  3. package/lib/csv-COrS4qdy.js.map +1 -1
  4. package/lib/discord-BLUnkEh9.js.map +1 -1
  5. package/lib/{dist-BsqdI2nY.js → dist-CYL41kqQ.js} +2 -2
  6. package/lib/dist-CYL41kqQ.js.map +1 -0
  7. package/lib/{docx-BEBOihjl.js → docx-uNAel545.js} +7 -2
  8. package/lib/docx-uNAel545.js.map +1 -0
  9. package/lib/email-D0bbfWq4.js.map +1 -1
  10. package/lib/{exceljs-BoIDUUaw.js → exceljs-BYETsesT.js} +314 -314
  11. package/lib/exceljs-BYETsesT.js.map +1 -0
  12. package/lib/google-chat-CkKCBUWC.js.map +1 -1
  13. package/lib/html-B5biprN2.js.map +1 -1
  14. package/lib/index.js +17 -8
  15. package/lib/index.js.map +1 -1
  16. package/lib/markdown-CdtlFGC0.js.map +1 -1
  17. package/lib/notion-iG2C5bEY.js.map +1 -1
  18. package/lib/{pdf-DIUQUEdj.js → pdf-IuBgTb3T.js} +9 -3
  19. package/lib/pdf-IuBgTb3T.js.map +1 -0
  20. package/lib/{pdfmake-DnmLxK4Q.js → pdfmake-CKMX5URW.js} +2 -4
  21. package/lib/pdfmake-CKMX5URW.js.map +1 -0
  22. package/lib/{pptx-Dd33oL3_.js → pptx-DXiMiYFM.js} +7 -2
  23. package/lib/pptx-DXiMiYFM.js.map +1 -0
  24. package/lib/{pptxgen.es-COcgXsyx.js → pptxgen.es-FsqHs8mD.js} +3 -6
  25. package/lib/pptxgen.es-FsqHs8mD.js.map +1 -0
  26. package/lib/sanitize-O_3j1mNJ.js.map +1 -1
  27. package/lib/slack-BI3EQwYm.js.map +1 -1
  28. package/lib/svg-BKxumy-p.js.map +1 -1
  29. package/lib/teams-Cwz9lce0.js.map +1 -1
  30. package/lib/telegram-gYFqyMXb.js.map +1 -1
  31. package/lib/text-l1XNXBOC.js.map +1 -1
  32. package/lib/types/index.d.ts +43 -39
  33. package/lib/types/index.d.ts.map +1 -1
  34. package/lib/{vfs_fonts-Df1kkZ4Y.js → vfs_fonts-Cap07Jg3.js} +2 -2
  35. package/lib/vfs_fonts-Cap07Jg3.js.map +1 -0
  36. package/lib/whatsapp-CjSGoOKx.js.map +1 -1
  37. package/lib/{xlsx-Bb5TWyXQ.js → xlsx-Cvu4LBNy.js} +8 -2
  38. package/lib/xlsx-Cvu4LBNy.js.map +1 -0
  39. package/package.json +19 -7
  40. package/src/builder.ts +53 -44
  41. package/src/download.ts +32 -36
  42. package/src/env.d.ts +3 -17
  43. package/src/index.ts +6 -8
  44. package/src/nodes.ts +45 -45
  45. package/src/render.ts +45 -118
  46. package/src/renderers/confluence.ts +64 -80
  47. package/src/renderers/csv.ts +11 -18
  48. package/src/renderers/discord.ts +38 -50
  49. package/src/renderers/docx.ts +78 -120
  50. package/src/renderers/email.ts +73 -92
  51. package/src/renderers/google-chat.ts +35 -47
  52. package/src/renderers/html.ts +78 -101
  53. package/src/renderers/markdown.ts +43 -53
  54. package/src/renderers/notion.ts +63 -85
  55. package/src/renderers/pdf.ts +92 -115
  56. package/src/renderers/pptx.ts +60 -66
  57. package/src/renderers/slack.ts +49 -61
  58. package/src/renderers/svg.ts +49 -63
  59. package/src/renderers/teams.ts +68 -80
  60. package/src/renderers/telegram.ts +40 -54
  61. package/src/renderers/text.ts +44 -66
  62. package/src/renderers/whatsapp.ts +34 -48
  63. package/src/renderers/xlsx.ts +47 -61
  64. package/src/sanitize.ts +21 -25
  65. package/src/tests/document.test.ts +1337 -1385
  66. package/src/tests/stress.test.ts +350 -0
  67. package/src/types.ts +66 -65
  68. package/lib/dist-BsqdI2nY.js.map +0 -1
  69. package/lib/docx-BEBOihjl.js.map +0 -1
  70. package/lib/exceljs-BoIDUUaw.js.map +0 -1
  71. package/lib/pdf-DIUQUEdj.js.map +0 -1
  72. package/lib/pdfmake-DnmLxK4Q.js.map +0 -1
  73. package/lib/pptx-Dd33oL3_.js.map +0 -1
  74. package/lib/pptxgen.es-COcgXsyx.js.map +0 -1
  75. package/lib/vfs_fonts-Df1kkZ4Y.js.map +0 -1
  76. package/lib/xlsx-Bb5TWyXQ.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { sanitizeHref, sanitizeXmlColor } from '../sanitize'
1
+ import { sanitizeHref, sanitizeXmlColor } from "../sanitize"
2
2
  import type {
3
3
  DocChild,
4
4
  DocNode,
@@ -7,22 +7,20 @@ import type {
7
7
  PageSize,
8
8
  RenderOptions,
9
9
  TableColumn,
10
- } from '../types'
10
+ } from "../types"
11
11
 
12
12
  /**
13
13
  * DOCX renderer — lazy-loads the 'docx' npm package on first use.
14
14
  */
15
15
 
16
16
  function resolveColumn(col: string | TableColumn): TableColumn {
17
- return typeof col === 'string' ? { header: col } : col
17
+ return typeof col === "string" ? { header: col } : col
18
18
  }
19
19
 
20
20
  function getTextContent(children: DocChild[]): string {
21
21
  return children
22
- .map((c) =>
23
- typeof c === 'string' ? c : getTextContent((c as DocNode).children),
24
- )
25
- .join('')
22
+ .map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
23
+ .join("")
26
24
  }
27
25
 
28
26
  /** Parse a data URL and return the base64 data and media type, or null for external URLs. */
@@ -48,7 +46,7 @@ function getPageSize(
48
46
  }
49
47
  const dims = sizes[size]
50
48
  if (!dims) return undefined
51
- if (orientation === 'landscape') {
49
+ if (orientation === "landscape") {
52
50
  return { width: dims.height, height: dims.width }
53
51
  }
54
52
  return dims
@@ -59,7 +57,7 @@ function getPageMargins(
59
57
  margin?: number | [number, number] | [number, number, number, number],
60
58
  ): object | undefined {
61
59
  if (margin == null) return undefined
62
- if (typeof margin === 'number') {
60
+ if (typeof margin === "number") {
63
61
  const twips = margin * 20
64
62
  return { top: twips, right: twips, bottom: twips, left: twips }
65
63
  }
@@ -80,27 +78,20 @@ function getPageMargins(
80
78
  }
81
79
 
82
80
  /** Map percentage column width to DOCX table column width. */
83
- function getColumnWidth(
84
- width?: number | string,
85
- ): { size: number; type: unknown } | undefined {
81
+ function getColumnWidth(width?: number | string): { size: number; type: unknown } | undefined {
86
82
  if (width == null) return undefined
87
- if (typeof width === 'number') return undefined
83
+ if (typeof width === "number") return undefined
88
84
  const match = width.match(/^(\d+)%$/)
89
85
  if (!match) return undefined
90
- return { size: Number.parseInt(match[1]!, 10) * 100, type: 'pct' as unknown }
86
+ return { size: Number.parseInt(match[1]!, 10) * 100, type: "pct" as unknown }
91
87
  }
92
88
 
93
89
  /** Shared context passed to per-node-type render helpers. */
94
90
  interface DocxCtx {
95
- docx: typeof import('docx')
91
+ docx: typeof import("docx")
96
92
  children: unknown[]
97
93
  alignmentMap: (align?: string) => unknown
98
- processListItems: (
99
- n: DocNode,
100
- listRef: string,
101
- level: number,
102
- ordered: boolean,
103
- ) => void
94
+ processListItems: (n: DocNode, listRef: string, level: number, ordered: boolean) => void
104
95
  nextListId: () => string
105
96
  }
106
97
 
@@ -142,11 +133,9 @@ function renderTextNode(ctx: DocxCtx, n: DocNode): void {
142
133
  ...(p.bold != null ? { bold: p.bold as boolean } : {}),
143
134
  ...(p.italic != null ? { italics: p.italic as boolean } : {}),
144
135
  ...(p.underline ? { underline: {} } : {}),
145
- ...(p.strikethrough != null
146
- ? { strike: p.strikethrough as boolean }
147
- : {}),
136
+ ...(p.strikethrough != null ? { strike: p.strikethrough as boolean } : {}),
148
137
  ...(p.size != null ? { size: (p.size as number) * 2 } : {}),
149
- color: sanitizeXmlColor(p.color as string, '333333'),
138
+ color: sanitizeXmlColor(p.color as string, "333333"),
150
139
  }),
151
140
  ],
152
141
  alignment: alignmentMap(p.align as string) as any,
@@ -166,7 +155,7 @@ function renderLink(ctx: DocxCtx, n: DocNode): void {
166
155
  children: [
167
156
  new docx.TextRun({
168
157
  text: getTextContent(n.children),
169
- color: sanitizeXmlColor(p.color as string, '4f46e5'),
158
+ color: sanitizeXmlColor(p.color as string, "4f46e5"),
170
159
  underline: { type: docx.UnderlineType.SINGLE },
171
160
  }),
172
161
  ],
@@ -189,9 +178,9 @@ function renderImage(ctx: DocxCtx, n: DocNode): void {
189
178
  new docx.Paragraph({
190
179
  children: [
191
180
  new docx.ImageRun({
192
- data: Buffer.from(parsed.data, 'base64'),
181
+ data: Buffer.from(parsed.data, "base64"),
193
182
  transformation: { width: imgWidth, height: imgHeight },
194
- type: parsed.mime === 'image/png' ? 'png' : 'jpg',
183
+ type: parsed.mime === "image/png" ? "png" : "jpg",
195
184
  }),
196
185
  ],
197
186
  alignment: alignmentMap(p.align as string) as any,
@@ -205,7 +194,7 @@ function renderImage(ctx: DocxCtx, n: DocNode): void {
205
194
  text: p.caption as string,
206
195
  italics: true,
207
196
  size: 20,
208
- color: '666666',
197
+ color: "666666",
209
198
  }),
210
199
  ],
211
200
  alignment: alignmentMap(p.align as string) as any,
@@ -214,15 +203,15 @@ function renderImage(ctx: DocxCtx, n: DocNode): void {
214
203
  )
215
204
  }
216
205
  } else {
217
- const alt = (p.alt as string) ?? 'Image'
218
- const caption = p.caption ? ` — ${p.caption}` : ''
206
+ const alt = (p.alt as string) ?? "Image"
207
+ const caption = p.caption ? ` — ${p.caption}` : ""
219
208
  children.push(
220
209
  new docx.Paragraph({
221
210
  children: [
222
211
  new docx.TextRun({
223
212
  text: `[${alt}${caption}]`,
224
213
  italics: true,
225
- color: '999999',
214
+ color: "999999",
226
215
  }),
227
216
  ],
228
217
  }),
@@ -233,16 +222,12 @@ function renderImage(ctx: DocxCtx, n: DocNode): void {
233
222
  function renderDocxTable(ctx: DocxCtx, n: DocNode): void {
234
223
  const { docx, children, alignmentMap } = ctx
235
224
  const p = n.props
236
- const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
237
- resolveColumn,
238
- )
225
+ const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
239
226
  const rows = (p.rows ?? []) as (string | number)[][]
240
- const hs = p.headerStyle as
241
- | { background?: string; color?: string }
242
- | undefined
227
+ const hs = p.headerStyle as { background?: string; color?: string } | undefined
243
228
  const bordered = p.bordered as boolean | undefined
244
229
  const borderStyle = bordered
245
- ? { style: docx.BorderStyle.SINGLE, size: 1, color: 'DDDDDD' }
230
+ ? { style: docx.BorderStyle.SINGLE, size: 1, color: "DDDDDD" }
246
231
  : undefined
247
232
  const cellBorders = borderStyle
248
233
  ? {
@@ -292,14 +277,12 @@ function renderDocxTable(ctx: DocxCtx, n: DocNode): void {
292
277
  new docx.TableCell({
293
278
  children: [
294
279
  new docx.Paragraph({
295
- children: [
296
- new docx.TextRun({ text: String(row[colIdx] ?? '') }),
297
- ],
280
+ children: [new docx.TextRun({ text: String(row[colIdx] ?? "") })],
298
281
  alignment: alignmentMap(col.align) as any,
299
282
  }),
300
283
  ],
301
284
  ...(p.striped && rowIdx % 2 === 1
302
- ? { shading: { fill: 'F9F9F9', type: docx.ShadingType.SOLID } }
285
+ ? { shading: { fill: "F9F9F9", type: docx.ShadingType.SOLID } }
303
286
  : {}),
304
287
  ...(cellBorders != null ? { borders: cellBorders } : {}),
305
288
  width: getColumnWidth(col.width as string | undefined) as any,
@@ -329,7 +312,7 @@ function renderDocxTable(ctx: DocxCtx, n: DocNode): void {
329
312
  width: { size: 100, type: docx.WidthType.PERCENTAGE },
330
313
  }),
331
314
  )
332
- children.push(new docx.Paragraph({ text: '', spacing: { after: 120 } }))
315
+ children.push(new docx.Paragraph({ text: "", spacing: { after: 120 } }))
333
316
  }
334
317
 
335
318
  function renderList(ctx: DocxCtx, n: DocNode): void {
@@ -337,14 +320,14 @@ function renderList(ctx: DocxCtx, n: DocNode): void {
337
320
  const ordered = n.props.ordered as boolean | undefined
338
321
  const listRef = nextListId()
339
322
  processListItems(n, listRef, 0, ordered ?? false)
340
- children.push(new docx.Paragraph({ text: '', spacing: { after: 60 } }))
323
+ children.push(new docx.Paragraph({ text: "", spacing: { after: 60 } }))
341
324
  }
342
325
 
343
326
  function renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {
344
327
  const { docx, children } = ctx
345
328
  const p = n.props
346
329
  const text = getTextContent(n.children)
347
- if (n.type === 'button') {
330
+ if (n.type === "button") {
348
331
  children.push(
349
332
  new docx.Paragraph({
350
333
  children: [
@@ -354,7 +337,7 @@ function renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {
354
337
  new docx.TextRun({
355
338
  text,
356
339
  bold: true,
357
- color: '4F46E5',
340
+ color: "4F46E5",
358
341
  underline: { type: docx.UnderlineType.SINGLE },
359
342
  }),
360
343
  ],
@@ -366,13 +349,13 @@ function renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {
366
349
  } else {
367
350
  children.push(
368
351
  new docx.Paragraph({
369
- children: [new docx.TextRun({ text, italics: true, color: '555555' })],
352
+ children: [new docx.TextRun({ text, italics: true, color: "555555" })],
370
353
  indent: { left: 720 },
371
354
  border: {
372
355
  left: {
373
356
  style: docx.BorderStyle.SINGLE,
374
357
  size: 6,
375
- color: sanitizeXmlColor(p.borderColor as string, 'DDDDDD'),
358
+ color: sanitizeXmlColor(p.borderColor as string, "DDDDDD"),
376
359
  },
377
360
  },
378
361
  spacing: { after: 120 },
@@ -383,7 +366,14 @@ function renderButtonOrQuote(ctx: DocxCtx, n: DocNode): void {
383
366
 
384
367
  export const docxRenderer: DocumentRenderer = {
385
368
  async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {
386
- const docx = await import('docx')
369
+ let docx: typeof import("docx")
370
+ try {
371
+ docx = await import("docx")
372
+ } catch {
373
+ throw new Error(
374
+ '[@pyreon/document] DOCX renderer requires "docx" package. Install it: bun add docx',
375
+ )
376
+ }
387
377
  const children: unknown[] = []
388
378
  let listCounter = 0
389
379
 
@@ -398,43 +388,24 @@ export const docxRenderer: DocumentRenderer = {
398
388
  return map[align]
399
389
  }
400
390
 
401
- function processListItems(
402
- n: DocNode,
403
- listRef: string,
404
- level: number,
405
- ordered: boolean,
406
- ): void {
407
- const items = n.children.filter(
408
- (c): c is DocNode => typeof c !== 'string',
409
- )
391
+ function processListItems(n: DocNode, listRef: string, level: number, ordered: boolean): void {
392
+ const items = n.children.filter((c): c is DocNode => typeof c !== "string")
410
393
  for (const item of items) {
411
394
  const nestedList = item.children.find(
412
- (c): c is DocNode =>
413
- typeof c !== 'string' && (c as DocNode).type === 'list',
395
+ (c): c is DocNode => typeof c !== "string" && (c as DocNode).type === "list",
414
396
  )
415
397
  const textChildren = item.children.filter(
416
- (c) => typeof c === 'string' || (c as DocNode).type !== 'list',
398
+ (c) => typeof c === "string" || (c as DocNode).type !== "list",
417
399
  )
418
400
  children.push(
419
401
  new docx.Paragraph({
420
- children: [
421
- new docx.TextRun({ text: getTextContent(textChildren) }),
422
- ],
423
- ...(ordered
424
- ? { numbering: { reference: listRef, level } }
425
- : { bullet: { level } }),
402
+ children: [new docx.TextRun({ text: getTextContent(textChildren) })],
403
+ ...(ordered ? { numbering: { reference: listRef, level } } : { bullet: { level } }),
426
404
  }),
427
405
  )
428
406
  if (nestedList) {
429
- const nestedOrdered = (nestedList as DocNode).props.ordered as
430
- | boolean
431
- | undefined
432
- processListItems(
433
- nestedList as DocNode,
434
- listRef,
435
- level + 1,
436
- nestedOrdered ?? false,
437
- )
407
+ const nestedOrdered = (nestedList as DocNode).props.ordered as boolean | undefined
408
+ processListItems(nestedList as DocNode, listRef, level + 1, nestedOrdered ?? false)
438
409
  }
439
410
  }
440
411
  }
@@ -449,73 +420,73 @@ export const docxRenderer: DocumentRenderer = {
449
420
 
450
421
  function processNode(n: DocNode): void {
451
422
  switch (n.type) {
452
- case 'document':
453
- case 'page':
454
- case 'section':
455
- case 'row':
456
- case 'column':
423
+ case "document":
424
+ case "page":
425
+ case "section":
426
+ case "row":
427
+ case "column":
457
428
  for (const child of n.children) {
458
- if (typeof child !== 'string') processNode(child)
429
+ if (typeof child !== "string") processNode(child)
459
430
  else children.push(new docx.Paragraph({ text: child }))
460
431
  }
461
432
  break
462
- case 'heading':
433
+ case "heading":
463
434
  renderHeading(ctx, n)
464
435
  break
465
- case 'text':
436
+ case "text":
466
437
  renderTextNode(ctx, n)
467
438
  break
468
- case 'link':
439
+ case "link":
469
440
  renderLink(ctx, n)
470
441
  break
471
- case 'image':
442
+ case "image":
472
443
  renderImage(ctx, n)
473
444
  break
474
- case 'table':
445
+ case "table":
475
446
  renderDocxTable(ctx, n)
476
447
  break
477
- case 'list':
448
+ case "list":
478
449
  renderList(ctx, n)
479
450
  break
480
- case 'code':
451
+ case "code":
481
452
  children.push(
482
453
  new docx.Paragraph({
483
454
  children: [
484
455
  new docx.TextRun({
485
456
  text: getTextContent(n.children),
486
- font: 'Courier New',
457
+ font: "Courier New",
487
458
  size: 20,
488
459
  }),
489
460
  ],
490
- shading: { fill: 'F5F5F5', type: docx.ShadingType.SOLID },
461
+ shading: { fill: "F5F5F5", type: docx.ShadingType.SOLID },
491
462
  spacing: { after: 120 },
492
463
  }),
493
464
  )
494
465
  break
495
- case 'divider':
466
+ case "divider":
496
467
  children.push(
497
468
  new docx.Paragraph({
498
469
  border: {
499
470
  bottom: {
500
471
  style: docx.BorderStyle.SINGLE,
501
472
  size: (n.props.thickness as number | undefined) ?? 1,
502
- color: sanitizeXmlColor(n.props.color as string, 'DDDDDD'),
473
+ color: sanitizeXmlColor(n.props.color as string, "DDDDDD"),
503
474
  },
504
475
  },
505
476
  spacing: { before: 120, after: 120 },
506
477
  }),
507
478
  )
508
479
  break
509
- case 'spacer':
480
+ case "spacer":
510
481
  children.push(
511
482
  new docx.Paragraph({
512
- text: '',
483
+ text: "",
513
484
  spacing: { after: (n.props.height as number) * 20 },
514
485
  }),
515
486
  )
516
487
  break
517
- case 'button':
518
- case 'quote':
488
+ case "button":
489
+ case "quote":
519
490
  renderButtonOrQuote(ctx, n)
520
491
  break
521
492
  }
@@ -542,12 +513,11 @@ export const docxRenderer: DocumentRenderer = {
542
513
 
543
514
  // Extract page properties from first page node
544
515
  const pageNode =
545
- node.type === 'document'
516
+ node.type === "document"
546
517
  ? (node.children.find(
547
- (c): c is DocNode =>
548
- typeof c !== 'string' && (c as DocNode).type === 'page',
518
+ (c): c is DocNode => typeof c !== "string" && (c as DocNode).type === "page",
549
519
  ) as DocNode | undefined)
550
- : node.type === 'page'
520
+ : node.type === "page"
551
521
  ? node
552
522
  : undefined
553
523
 
@@ -557,33 +527,23 @@ export const docxRenderer: DocumentRenderer = {
557
527
  pageProps.orientation as PageOrientation | undefined,
558
528
  )
559
529
  const pageMargins = getPageMargins(
560
- pageProps.margin as
561
- | number
562
- | [number, number]
563
- | [number, number, number, number]
564
- | undefined,
530
+ pageProps.margin as number | [number, number] | [number, number, number, number] | undefined,
565
531
  )
566
532
 
567
- function buildHeaderFooter(
568
- contentNode: DocNode | undefined,
569
- ): unknown[] | undefined {
533
+ function buildHeaderFooter(contentNode: DocNode | undefined): unknown[] | undefined {
570
534
  if (!contentNode) return undefined
571
535
  const text = getTextContent(contentNode.children)
572
536
  if (!text) return undefined
573
537
  return [
574
538
  new docx.Paragraph({
575
- children: [new docx.TextRun({ text, size: 18, color: '999999' })],
539
+ children: [new docx.TextRun({ text, size: 18, color: "999999" })],
576
540
  alignment: docx.AlignmentType.CENTER,
577
541
  }),
578
542
  ]
579
543
  }
580
544
 
581
- const headerContent = buildHeaderFooter(
582
- pageProps.header as DocNode | undefined,
583
- )
584
- const footerContent = buildHeaderFooter(
585
- pageProps.footer as DocNode | undefined,
586
- )
545
+ const headerContent = buildHeaderFooter(pageProps.header as DocNode | undefined)
546
+ const footerContent = buildHeaderFooter(pageProps.footer as DocNode | undefined)
587
547
 
588
548
  const sectionProperties: Record<string, unknown> = {}
589
549
  if (pageDims) {
@@ -593,9 +553,7 @@ export const docxRenderer: DocumentRenderer = {
593
553
  }
594
554
 
595
555
  const doc = new docx.Document({
596
- numbering: (numberingConfigs.length > 0
597
- ? { config: numberingConfigs }
598
- : undefined) as any,
556
+ numbering: (numberingConfigs.length > 0 ? { config: numberingConfigs } : undefined) as any,
599
557
  sections: [
600
558
  {
601
559
  properties: sectionProperties,