@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,11 +1,5 @@
1
- import { sanitizeHref, sanitizeImageSrc } from '../sanitize'
2
- import type {
3
- DocChild,
4
- DocNode,
5
- DocumentRenderer,
6
- RenderOptions,
7
- TableColumn,
8
- } from '../types'
1
+ import { sanitizeHref, sanitizeImageSrc } from "../sanitize"
2
+ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
9
3
 
10
4
  /**
11
5
  * Atlassian Document Format (ADF) renderer — for Jira and Confluence.
@@ -14,15 +8,13 @@ import type {
14
8
  */
15
9
 
16
10
  function resolveColumn(col: string | TableColumn): TableColumn {
17
- return typeof col === 'string' ? { header: col } : col
11
+ return typeof col === "string" ? { header: col } : col
18
12
  }
19
13
 
20
14
  function getTextContent(children: DocChild[]): string {
21
15
  return children
22
- .map((c) =>
23
- typeof c === 'string' ? c : getTextContent((c as DocNode).children),
24
- )
25
- .join('')
16
+ .map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
17
+ .join("")
26
18
  }
27
19
 
28
20
  interface AdfNode {
@@ -33,8 +25,8 @@ interface AdfNode {
33
25
  attrs?: Record<string, unknown>
34
26
  }
35
27
 
36
- function textNode(text: string, marks?: AdfNode['marks']): AdfNode {
37
- return { type: 'text', text, ...(marks && marks.length > 0 ? { marks } : {}) }
28
+ function textNode(text: string, marks?: AdfNode["marks"]): AdfNode {
29
+ return { type: "text", text, ...(marks && marks.length > 0 ? { marks } : {}) }
38
30
  }
39
31
 
40
32
  function nodeToAdf(node: DocNode): AdfNode[] {
@@ -42,66 +34,65 @@ function nodeToAdf(node: DocNode): AdfNode[] {
42
34
  const result: AdfNode[] = []
43
35
 
44
36
  switch (node.type) {
45
- case 'document':
46
- case 'page':
47
- case 'section':
48
- case 'row':
49
- case 'column':
37
+ case "document":
38
+ case "page":
39
+ case "section":
40
+ case "row":
41
+ case "column":
50
42
  for (const child of node.children) {
51
- if (typeof child !== 'string') {
43
+ if (typeof child !== "string") {
52
44
  result.push(...nodeToAdf(child))
53
45
  }
54
46
  }
55
47
  break
56
48
 
57
- case 'heading': {
49
+ case "heading": {
58
50
  const level = Math.min(Math.max((p.level as number) ?? 1, 1), 6)
59
51
  const text = getTextContent(node.children)
60
52
  result.push({
61
- type: 'heading',
53
+ type: "heading",
62
54
  attrs: { level },
63
- content: [textNode(text, [{ type: 'strong' }])],
55
+ content: [textNode(text, [{ type: "strong" }])],
64
56
  })
65
57
  break
66
58
  }
67
59
 
68
- case 'text': {
60
+ case "text": {
69
61
  const text = getTextContent(node.children)
70
- const marks: AdfNode['marks'] = []
71
- if (p.bold) marks.push({ type: 'strong' })
72
- if (p.italic) marks.push({ type: 'em' })
73
- if (p.underline) marks.push({ type: 'underline' })
74
- if (p.strikethrough) marks.push({ type: 'strike' })
75
- if (p.color)
76
- marks.push({ type: 'textColor', attrs: { color: p.color as string } })
62
+ const marks: AdfNode["marks"] = []
63
+ if (p.bold) marks.push({ type: "strong" })
64
+ if (p.italic) marks.push({ type: "em" })
65
+ if (p.underline) marks.push({ type: "underline" })
66
+ if (p.strikethrough) marks.push({ type: "strike" })
67
+ if (p.color) marks.push({ type: "textColor", attrs: { color: p.color as string } })
77
68
  result.push({
78
- type: 'paragraph',
69
+ type: "paragraph",
79
70
  content: [textNode(text, marks)],
80
71
  })
81
72
  break
82
73
  }
83
74
 
84
- case 'link': {
75
+ case "link": {
85
76
  const href = sanitizeHref(p.href as string)
86
77
  const text = getTextContent(node.children)
87
78
  result.push({
88
- type: 'paragraph',
89
- content: [textNode(text, [{ type: 'link', attrs: { href } }])],
79
+ type: "paragraph",
80
+ content: [textNode(text, [{ type: "link", attrs: { href } }])],
90
81
  })
91
82
  break
92
83
  }
93
84
 
94
- case 'image': {
85
+ case "image": {
95
86
  const src = sanitizeImageSrc(p.src as string)
96
- if (src.startsWith('http')) {
87
+ if (src.startsWith("http")) {
97
88
  result.push({
98
- type: 'mediaSingle',
99
- attrs: { layout: 'center' },
89
+ type: "mediaSingle",
90
+ attrs: { layout: "center" },
100
91
  content: [
101
92
  {
102
- type: 'media',
93
+ type: "media",
103
94
  attrs: {
104
- type: 'external',
95
+ type: "external",
105
96
  url: src,
106
97
  width: (p.width as number) ?? undefined,
107
98
  height: (p.height as number) ?? undefined,
@@ -113,56 +104,54 @@ function nodeToAdf(node: DocNode): AdfNode[] {
113
104
  break
114
105
  }
115
106
 
116
- case 'table': {
117
- const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
118
- resolveColumn,
119
- )
107
+ case "table": {
108
+ const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
120
109
  const rows = (p.rows ?? []) as (string | number)[][]
121
110
 
122
111
  const headerRow: AdfNode = {
123
- type: 'tableRow',
112
+ type: "tableRow",
124
113
  content: columns.map((col) => ({
125
- type: 'tableHeader',
114
+ type: "tableHeader",
126
115
  content: [
127
116
  {
128
- type: 'paragraph',
129
- content: [textNode(col.header, [{ type: 'strong' }])],
117
+ type: "paragraph",
118
+ content: [textNode(col.header, [{ type: "strong" }])],
130
119
  },
131
120
  ],
132
121
  })),
133
122
  }
134
123
 
135
124
  const dataRows = rows.map((row) => ({
136
- type: 'tableRow' as const,
125
+ type: "tableRow" as const,
137
126
  content: columns.map((_, i) => ({
138
- type: 'tableCell' as const,
127
+ type: "tableCell" as const,
139
128
  content: [
140
129
  {
141
- type: 'paragraph' as const,
142
- content: [textNode(String(row[i] ?? ''))],
130
+ type: "paragraph" as const,
131
+ content: [textNode(String(row[i] ?? ""))],
143
132
  },
144
133
  ],
145
134
  })),
146
135
  }))
147
136
 
148
137
  result.push({
149
- type: 'table',
150
- attrs: { isNumberColumnEnabled: false, layout: 'default' },
138
+ type: "table",
139
+ attrs: { isNumberColumnEnabled: false, layout: "default" },
151
140
  content: [headerRow, ...dataRows],
152
141
  })
153
142
  break
154
143
  }
155
144
 
156
- case 'list': {
145
+ case "list": {
157
146
  const ordered = p.ordered as boolean | undefined
158
- const type = ordered ? 'orderedList' : 'bulletList'
147
+ const type = ordered ? "orderedList" : "bulletList"
159
148
  const items = node.children
160
- .filter((c): c is DocNode => typeof c !== 'string')
149
+ .filter((c): c is DocNode => typeof c !== "string")
161
150
  .map((item) => ({
162
- type: 'listItem' as const,
151
+ type: "listItem" as const,
163
152
  content: [
164
153
  {
165
- type: 'paragraph' as const,
154
+ type: "paragraph" as const,
166
155
  content: [textNode(getTextContent(item.children))],
167
156
  },
168
157
  ],
@@ -171,46 +160,41 @@ function nodeToAdf(node: DocNode): AdfNode[] {
171
160
  break
172
161
  }
173
162
 
174
- case 'code': {
163
+ case "code": {
175
164
  const text = getTextContent(node.children)
176
165
  const lang = (p.language as string) ?? null
177
166
  result.push({
178
- type: 'codeBlock',
167
+ type: "codeBlock",
179
168
  attrs: { language: lang },
180
169
  content: [textNode(text)],
181
170
  })
182
171
  break
183
172
  }
184
173
 
185
- case 'divider':
186
- case 'page-break':
187
- result.push({ type: 'rule' })
174
+ case "divider":
175
+ case "page-break":
176
+ result.push({ type: "rule" })
188
177
  break
189
178
 
190
- case 'spacer':
191
- result.push({ type: 'paragraph', content: [] })
179
+ case "spacer":
180
+ result.push({ type: "paragraph", content: [] })
192
181
  break
193
182
 
194
- case 'button': {
183
+ case "button": {
195
184
  const href = sanitizeHref(p.href as string)
196
185
  const text = getTextContent(node.children)
197
186
  result.push({
198
- type: 'paragraph',
199
- content: [
200
- textNode(text, [
201
- { type: 'link', attrs: { href } },
202
- { type: 'strong' },
203
- ]),
204
- ],
187
+ type: "paragraph",
188
+ content: [textNode(text, [{ type: "link", attrs: { href } }, { type: "strong" }])],
205
189
  })
206
190
  break
207
191
  }
208
192
 
209
- case 'quote': {
193
+ case "quote": {
210
194
  const text = getTextContent(node.children)
211
195
  result.push({
212
- type: 'blockquote',
213
- content: [{ type: 'paragraph', content: [textNode(text)] }],
196
+ type: "blockquote",
197
+ content: [{ type: "paragraph", content: [textNode(text)] }],
214
198
  })
215
199
  break
216
200
  }
@@ -224,7 +208,7 @@ export const confluenceRenderer: DocumentRenderer = {
224
208
  const content = nodeToAdf(node)
225
209
  const adf = {
226
210
  version: 1,
227
- type: 'doc',
211
+ type: "doc",
228
212
  content,
229
213
  }
230
214
  return JSON.stringify(adf, null, 2)
@@ -1,16 +1,11 @@
1
- import type {
2
- DocNode,
3
- DocumentRenderer,
4
- RenderOptions,
5
- TableColumn,
6
- } from '../types'
1
+ import type { DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
7
2
 
8
3
  function resolveColumn(col: string | TableColumn): TableColumn {
9
- return typeof col === 'string' ? { header: col } : col
4
+ return typeof col === "string" ? { header: col } : col
10
5
  }
11
6
 
12
7
  function escapeCsv(value: string): string {
13
- if (value.includes(',') || value.includes('"') || value.includes('\n')) {
8
+ if (value.includes(",") || value.includes('"') || value.includes("\n")) {
14
9
  return `"${value.replace(/"/g, '""')}"`
15
10
  }
16
11
  return value
@@ -18,11 +13,11 @@ function escapeCsv(value: string): string {
18
13
 
19
14
  function findTables(node: DocNode): DocNode[] {
20
15
  const tables: DocNode[] = []
21
- if (node.type === 'table') {
16
+ if (node.type === "table") {
22
17
  tables.push(node)
23
18
  }
24
19
  for (const child of node.children) {
25
- if (typeof child !== 'string') {
20
+ if (typeof child !== "string") {
26
21
  tables.push(...findTables(child))
27
22
  }
28
23
  }
@@ -30,9 +25,7 @@ function findTables(node: DocNode): DocNode[] {
30
25
  }
31
26
 
32
27
  function tableToCsv(node: DocNode): string {
33
- const columns = ((node.props.columns ?? []) as (string | TableColumn)[]).map(
34
- resolveColumn,
35
- )
28
+ const columns = ((node.props.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
36
29
  const rows = (node.props.rows ?? []) as (string | number)[][]
37
30
 
38
31
  const lines: string[] = []
@@ -43,14 +36,14 @@ function tableToCsv(node: DocNode): string {
43
36
  }
44
37
 
45
38
  // Header
46
- lines.push(columns.map((c) => escapeCsv(c.header)).join(','))
39
+ lines.push(columns.map((c) => escapeCsv(c.header)).join(","))
47
40
 
48
41
  // Rows
49
42
  for (const row of rows) {
50
- lines.push(row.map((cell) => escapeCsv(String(cell ?? ''))).join(','))
43
+ lines.push(row.map((cell) => escapeCsv(String(cell ?? ""))).join(","))
51
44
  }
52
45
 
53
- return lines.join('\n')
46
+ return lines.join("\n")
54
47
  }
55
48
 
56
49
  export const csvRenderer: DocumentRenderer = {
@@ -58,10 +51,10 @@ export const csvRenderer: DocumentRenderer = {
58
51
  const tables = findTables(node)
59
52
 
60
53
  if (tables.length === 0) {
61
- return '# No tables found in document\n'
54
+ return "# No tables found in document\n"
62
55
  }
63
56
 
64
57
  // If multiple tables, separate with blank lines
65
- return `${tables.map(tableToCsv).join('\n\n')}\n`
58
+ return `${tables.map(tableToCsv).join("\n\n")}\n`
66
59
  },
67
60
  }
@@ -1,11 +1,5 @@
1
- import { sanitizeHref, sanitizeImageSrc } from '../sanitize'
2
- import type {
3
- DocChild,
4
- DocNode,
5
- DocumentRenderer,
6
- RenderOptions,
7
- TableColumn,
8
- } from '../types'
1
+ import { sanitizeHref, sanitizeImageSrc } from "../sanitize"
2
+ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
9
3
 
10
4
  /**
11
5
  * Discord renderer — outputs embed JSON for Discord webhooks/bots.
@@ -13,15 +7,13 @@ import type {
13
7
  */
14
8
 
15
9
  function resolveColumn(col: string | TableColumn): TableColumn {
16
- return typeof col === 'string' ? { header: col } : col
10
+ return typeof col === "string" ? { header: col } : col
17
11
  }
18
12
 
19
13
  function getTextContent(children: DocChild[]): string {
20
14
  return children
21
- .map((c) =>
22
- typeof c === 'string' ? c : getTextContent((c as DocNode).children),
23
- )
24
- .join('')
15
+ .map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
16
+ .join("")
25
17
  }
26
18
 
27
19
  interface DiscordField {
@@ -32,16 +24,16 @@ interface DiscordField {
32
24
 
33
25
  /** Extract the first h1 title and first HTTP image from the tree. */
34
26
  function extractMeta(node: DocNode): { title?: string; imageUrl?: string } {
35
- if (node.type === 'heading') {
27
+ if (node.type === "heading") {
36
28
  const level = (node.props.level as number) ?? 1
37
29
  if (level === 1) return { title: getTextContent(node.children) }
38
30
  }
39
- if (node.type === 'image') {
31
+ if (node.type === "image") {
40
32
  const src = sanitizeImageSrc(node.props.src as string)
41
- if (src.startsWith('http')) return { imageUrl: src }
33
+ if (src.startsWith("http")) return { imageUrl: src }
42
34
  }
43
35
  for (const child of node.children) {
44
- if (typeof child !== 'string') {
36
+ if (typeof child !== "string") {
45
37
  const result = extractMeta(child)
46
38
  if (result.title || result.imageUrl) return result
47
39
  }
@@ -54,17 +46,17 @@ function nodeToMarkdown(
54
46
  meta: { title?: string },
55
47
  ): { content: string; fields: DiscordField[] } {
56
48
  const p = node.props
57
- let content = ''
49
+ let content = ""
58
50
  const fields: DiscordField[] = []
59
51
 
60
52
  switch (node.type) {
61
- case 'document':
62
- case 'page':
63
- case 'section':
64
- case 'row':
65
- case 'column':
53
+ case "document":
54
+ case "page":
55
+ case "section":
56
+ case "row":
57
+ case "column":
66
58
  for (const child of node.children) {
67
- if (typeof child !== 'string') {
59
+ if (typeof child !== "string") {
68
60
  const result = nodeToMarkdown(child, meta)
69
61
  content += result.content
70
62
  fields.push(...result.fields)
@@ -72,7 +64,7 @@ function nodeToMarkdown(
72
64
  }
73
65
  break
74
66
 
75
- case 'heading': {
67
+ case "heading": {
76
68
  const text = getTextContent(node.children)
77
69
  const level = (p.level as number) ?? 1
78
70
  // Skip the first h1 — it's used as embed title
@@ -83,7 +75,7 @@ function nodeToMarkdown(
83
75
  break
84
76
  }
85
77
 
86
- case 'text': {
78
+ case "text": {
87
79
  let text = getTextContent(node.children)
88
80
  if (p.bold) text = `**${text}**`
89
81
  if (p.italic) text = `*${text}*`
@@ -92,79 +84,75 @@ function nodeToMarkdown(
92
84
  break
93
85
  }
94
86
 
95
- case 'link': {
87
+ case "link": {
96
88
  const href = sanitizeHref(p.href as string)
97
89
  const text = getTextContent(node.children)
98
90
  content += `[${text}](${href})\n\n`
99
91
  break
100
92
  }
101
93
 
102
- case 'image':
94
+ case "image":
103
95
  // Image handled via extractMeta — embedded as embed.image
104
96
  break
105
97
 
106
- case 'table': {
107
- const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
108
- resolveColumn,
109
- )
98
+ case "table": {
99
+ const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
110
100
  const rows = (p.rows ?? []) as (string | number)[][]
111
101
 
112
102
  // Use Discord embed fields for small tables
113
103
  if (columns.length <= 3 && rows.length <= 10) {
114
104
  for (const col of columns) {
115
105
  const colIdx = columns.indexOf(col)
116
- const values = rows.map((row) => String(row[colIdx] ?? '')).join('\n')
106
+ const values = rows.map((row) => String(row[colIdx] ?? "")).join("\n")
117
107
  fields.push({
118
108
  name: col.header,
119
- value: values || '-',
109
+ value: values || "-",
120
110
  inline: true,
121
111
  })
122
112
  }
123
113
  } else {
124
114
  // Fallback to code block for large tables
125
- const header = columns.map((c) => c.header).join(' | ')
126
- const separator = columns.map(() => '---').join(' | ')
127
- const body = rows
128
- .map((row) => row.map((c) => String(c ?? '')).join(' | '))
129
- .join('\n')
115
+ const header = columns.map((c) => c.header).join(" | ")
116
+ const separator = columns.map(() => "---").join(" | ")
117
+ const body = rows.map((row) => row.map((c) => String(c ?? "")).join(" | ")).join("\n")
130
118
  content += `\`\`\`\n${header}\n${separator}\n${body}\n\`\`\`\n\n`
131
119
  }
132
120
  break
133
121
  }
134
122
 
135
- case 'list': {
123
+ case "list": {
136
124
  const ordered = p.ordered as boolean | undefined
137
125
  const items = node.children
138
- .filter((c): c is DocNode => typeof c !== 'string')
126
+ .filter((c): c is DocNode => typeof c !== "string")
139
127
  .map((item, i) => {
140
- const prefix = ordered ? `${i + 1}.` : ''
128
+ const prefix = ordered ? `${i + 1}.` : ""
141
129
  return `${prefix} ${getTextContent(item.children)}`
142
130
  })
143
- .join('\n')
131
+ .join("\n")
144
132
  content += `${items}\n\n`
145
133
  break
146
134
  }
147
135
 
148
- case 'code': {
149
- const lang = (p.language as string) ?? ''
136
+ case "code": {
137
+ const lang = (p.language as string) ?? ""
150
138
  const text = getTextContent(node.children)
151
139
  content += `\`\`\`${lang}\n${text}\n\`\`\`\n\n`
152
140
  break
153
141
  }
154
142
 
155
- case 'divider':
156
- case 'page-break':
157
- content += '───────────\n\n'
143
+ case "divider":
144
+ case "page-break":
145
+ content += "───────────\n\n"
158
146
  break
159
147
 
160
- case 'button': {
148
+ case "button": {
161
149
  const href = sanitizeHref(p.href as string)
162
150
  const text = getTextContent(node.children)
163
151
  content += `[**${text}**](${href})\n\n`
164
152
  break
165
153
  }
166
154
 
167
- case 'quote': {
155
+ case "quote": {
168
156
  const text = getTextContent(node.children)
169
157
  content += `> ${text}\n\n`
170
158
  break