@pyreon/document 0.10.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.
- package/lib/analysis/index.js.html +1 -1
- package/lib/confluence-Bd3ua1Ut.js.map +1 -1
- package/lib/csv-COrS4qdy.js.map +1 -1
- package/lib/discord-BLUnkEh9.js.map +1 -1
- package/lib/{dist-BsqdI2nY.js → dist-CYL41kqQ.js} +2 -2
- package/lib/dist-CYL41kqQ.js.map +1 -0
- package/lib/{docx-BEBOihjl.js → docx-uNAel545.js} +7 -2
- package/lib/docx-uNAel545.js.map +1 -0
- package/lib/email-D0bbfWq4.js.map +1 -1
- package/lib/{exceljs-BoIDUUaw.js → exceljs-BYETsesT.js} +314 -314
- package/lib/exceljs-BYETsesT.js.map +1 -0
- package/lib/google-chat-CkKCBUWC.js.map +1 -1
- package/lib/html-B5biprN2.js.map +1 -1
- package/lib/index.js +17 -8
- package/lib/index.js.map +1 -1
- package/lib/markdown-CdtlFGC0.js.map +1 -1
- package/lib/notion-iG2C5bEY.js.map +1 -1
- package/lib/{pdf-DIUQUEdj.js → pdf-IuBgTb3T.js} +9 -3
- package/lib/pdf-IuBgTb3T.js.map +1 -0
- package/lib/{pdfmake-DnmLxK4Q.js → pdfmake-CKMX5URW.js} +2 -4
- package/lib/pdfmake-CKMX5URW.js.map +1 -0
- package/lib/{pptx-Dd33oL3_.js → pptx-DXiMiYFM.js} +7 -2
- package/lib/pptx-DXiMiYFM.js.map +1 -0
- package/lib/{pptxgen.es-COcgXsyx.js → pptxgen.es-FsqHs8mD.js} +3 -6
- package/lib/pptxgen.es-FsqHs8mD.js.map +1 -0
- package/lib/sanitize-O_3j1mNJ.js.map +1 -1
- package/lib/slack-BI3EQwYm.js.map +1 -1
- package/lib/svg-BKxumy-p.js.map +1 -1
- package/lib/teams-Cwz9lce0.js.map +1 -1
- package/lib/telegram-gYFqyMXb.js.map +1 -1
- package/lib/text-l1XNXBOC.js.map +1 -1
- package/lib/types/index.d.ts +43 -39
- package/lib/types/index.d.ts.map +1 -1
- package/lib/{vfs_fonts-Df1kkZ4Y.js → vfs_fonts-Cap07Jg3.js} +2 -2
- package/lib/vfs_fonts-Cap07Jg3.js.map +1 -0
- package/lib/whatsapp-CjSGoOKx.js.map +1 -1
- package/lib/{xlsx-Bb5TWyXQ.js → xlsx-Cvu4LBNy.js} +8 -2
- package/lib/xlsx-Cvu4LBNy.js.map +1 -0
- package/package.json +19 -7
- package/src/builder.ts +53 -44
- package/src/download.ts +32 -36
- package/src/env.d.ts +3 -17
- package/src/index.ts +6 -8
- package/src/nodes.ts +45 -45
- package/src/render.ts +45 -118
- package/src/renderers/confluence.ts +64 -80
- package/src/renderers/csv.ts +11 -18
- package/src/renderers/discord.ts +38 -50
- package/src/renderers/docx.ts +78 -120
- package/src/renderers/email.ts +73 -92
- package/src/renderers/google-chat.ts +35 -47
- package/src/renderers/html.ts +78 -101
- package/src/renderers/markdown.ts +43 -53
- package/src/renderers/notion.ts +63 -85
- package/src/renderers/pdf.ts +92 -115
- package/src/renderers/pptx.ts +60 -66
- package/src/renderers/slack.ts +49 -61
- package/src/renderers/svg.ts +49 -63
- package/src/renderers/teams.ts +68 -80
- package/src/renderers/telegram.ts +40 -54
- package/src/renderers/text.ts +44 -66
- package/src/renderers/whatsapp.ts +34 -48
- package/src/renderers/xlsx.ts +47 -61
- package/src/sanitize.ts +21 -25
- package/src/tests/document.test.ts +1337 -1385
- package/src/tests/stress.test.ts +111 -111
- package/src/types.ts +66 -65
- package/lib/dist-BsqdI2nY.js.map +0 -1
- package/lib/docx-BEBOihjl.js.map +0 -1
- package/lib/exceljs-BoIDUUaw.js.map +0 -1
- package/lib/pdf-DIUQUEdj.js.map +0 -1
- package/lib/pdfmake-DnmLxK4Q.js.map +0 -1
- package/lib/pptx-Dd33oL3_.js.map +0 -1
- package/lib/pptxgen.es-COcgXsyx.js.map +0 -1
- package/lib/vfs_fonts-Df1kkZ4Y.js.map +0 -1
- package/lib/xlsx-Bb5TWyXQ.js.map +0 -1
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { sanitizeHref } from
|
|
2
|
-
import type {
|
|
3
|
-
DocChild,
|
|
4
|
-
DocNode,
|
|
5
|
-
DocumentRenderer,
|
|
6
|
-
RenderOptions,
|
|
7
|
-
TableColumn,
|
|
8
|
-
} from '../types'
|
|
1
|
+
import { sanitizeHref } from "../sanitize"
|
|
2
|
+
import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
|
|
9
3
|
|
|
10
4
|
/**
|
|
11
5
|
* Telegram renderer — outputs HTML using Telegram's supported subset.
|
|
@@ -14,44 +8,40 @@ import type {
|
|
|
14
8
|
*/
|
|
15
9
|
|
|
16
10
|
function resolveColumn(col: string | TableColumn): TableColumn {
|
|
17
|
-
return typeof col ===
|
|
11
|
+
return typeof col === "string" ? { header: col } : col
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
function esc(str: string): string {
|
|
21
15
|
return str
|
|
22
|
-
.replace(/&/g,
|
|
23
|
-
.replace(/</g,
|
|
24
|
-
.replace(/>/g,
|
|
25
|
-
.replace(/"/g,
|
|
16
|
+
.replace(/&/g, "&")
|
|
17
|
+
.replace(/</g, "<")
|
|
18
|
+
.replace(/>/g, ">")
|
|
19
|
+
.replace(/"/g, """)
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
function getTextContent(children: DocChild[]): string {
|
|
29
23
|
return children
|
|
30
|
-
.map((c) =>
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
.join('')
|
|
24
|
+
.map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
|
|
25
|
+
.join("")
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
function renderNode(node: DocNode): string {
|
|
37
29
|
const p = node.props
|
|
38
30
|
|
|
39
31
|
switch (node.type) {
|
|
40
|
-
case
|
|
41
|
-
case
|
|
42
|
-
case
|
|
43
|
-
case
|
|
44
|
-
case
|
|
45
|
-
return node.children
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
case 'heading': {
|
|
32
|
+
case "document":
|
|
33
|
+
case "page":
|
|
34
|
+
case "section":
|
|
35
|
+
case "row":
|
|
36
|
+
case "column":
|
|
37
|
+
return node.children.map((c) => (typeof c === "string" ? esc(c) : renderNode(c))).join("")
|
|
38
|
+
|
|
39
|
+
case "heading": {
|
|
50
40
|
const text = esc(getTextContent(node.children))
|
|
51
41
|
return `<b>${text}</b>\n\n`
|
|
52
42
|
}
|
|
53
43
|
|
|
54
|
-
case
|
|
44
|
+
case "text": {
|
|
55
45
|
let text = esc(getTextContent(node.children))
|
|
56
46
|
if (p.bold) text = `<b>${text}</b>`
|
|
57
47
|
if (p.italic) text = `<i>${text}</i>`
|
|
@@ -60,47 +50,43 @@ function renderNode(node: DocNode): string {
|
|
|
60
50
|
return `${text}\n\n`
|
|
61
51
|
}
|
|
62
52
|
|
|
63
|
-
case
|
|
53
|
+
case "link": {
|
|
64
54
|
const href = sanitizeHref(p.href as string)
|
|
65
55
|
const text = esc(getTextContent(node.children))
|
|
66
56
|
return `<a href="${esc(href)}">${text}</a>\n\n`
|
|
67
57
|
}
|
|
68
58
|
|
|
69
|
-
case
|
|
59
|
+
case "image":
|
|
70
60
|
// Telegram doesn't support inline images in HTML
|
|
71
61
|
// Images need to be sent separately via sendPhoto
|
|
72
|
-
return
|
|
62
|
+
return ""
|
|
73
63
|
|
|
74
|
-
case
|
|
75
|
-
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
|
|
76
|
-
resolveColumn,
|
|
77
|
-
)
|
|
64
|
+
case "table": {
|
|
65
|
+
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
|
|
78
66
|
const rows = (p.rows ?? []) as (string | number)[][]
|
|
79
67
|
|
|
80
68
|
// Render as preformatted text since Telegram has no table support
|
|
81
|
-
const header = columns.map((c) => c.header).join(
|
|
82
|
-
const separator = columns.map(() =>
|
|
83
|
-
const body = rows
|
|
84
|
-
.map((row) => row.map((c) => String(c ?? '')).join(' | '))
|
|
85
|
-
.join('\n')
|
|
69
|
+
const header = columns.map((c) => c.header).join(" | ")
|
|
70
|
+
const separator = columns.map(() => "---").join("-+-")
|
|
71
|
+
const body = rows.map((row) => row.map((c) => String(c ?? "")).join(" | ")).join("\n")
|
|
86
72
|
|
|
87
73
|
return `<pre>${esc(header)}\n${esc(separator)}\n${esc(body)}</pre>\n\n`
|
|
88
74
|
}
|
|
89
75
|
|
|
90
|
-
case
|
|
76
|
+
case "list": {
|
|
91
77
|
const ordered = p.ordered as boolean | undefined
|
|
92
78
|
const items = node.children
|
|
93
|
-
.filter((c): c is DocNode => typeof c !==
|
|
79
|
+
.filter((c): c is DocNode => typeof c !== "string")
|
|
94
80
|
.map((item, i) => {
|
|
95
|
-
const prefix = ordered ? `${i + 1}.` :
|
|
81
|
+
const prefix = ordered ? `${i + 1}.` : "•"
|
|
96
82
|
return `${prefix} ${esc(getTextContent(item.children))}`
|
|
97
83
|
})
|
|
98
|
-
.join(
|
|
84
|
+
.join("\n")
|
|
99
85
|
return `${items}\n\n`
|
|
100
86
|
}
|
|
101
87
|
|
|
102
|
-
case
|
|
103
|
-
const lang = (p.language as string) ??
|
|
88
|
+
case "code": {
|
|
89
|
+
const lang = (p.language as string) ?? ""
|
|
104
90
|
const text = esc(getTextContent(node.children))
|
|
105
91
|
if (lang) {
|
|
106
92
|
return `<pre><code class="language-${esc(lang)}">${text}</code></pre>\n\n`
|
|
@@ -108,26 +94,26 @@ function renderNode(node: DocNode): string {
|
|
|
108
94
|
return `<pre>${text}</pre>\n\n`
|
|
109
95
|
}
|
|
110
96
|
|
|
111
|
-
case
|
|
112
|
-
case
|
|
113
|
-
return
|
|
97
|
+
case "divider":
|
|
98
|
+
case "page-break":
|
|
99
|
+
return "───────────\n\n"
|
|
114
100
|
|
|
115
|
-
case
|
|
116
|
-
return
|
|
101
|
+
case "spacer":
|
|
102
|
+
return "\n"
|
|
117
103
|
|
|
118
|
-
case
|
|
104
|
+
case "button": {
|
|
119
105
|
const href = sanitizeHref(p.href as string)
|
|
120
106
|
const text = esc(getTextContent(node.children))
|
|
121
107
|
return `<a href="${esc(href)}">${text}</a>\n\n`
|
|
122
108
|
}
|
|
123
109
|
|
|
124
|
-
case
|
|
110
|
+
case "quote": {
|
|
125
111
|
const text = esc(getTextContent(node.children))
|
|
126
112
|
return `<blockquote>${text}</blockquote>\n\n`
|
|
127
113
|
}
|
|
128
114
|
|
|
129
115
|
default:
|
|
130
|
-
return
|
|
116
|
+
return ""
|
|
131
117
|
}
|
|
132
118
|
}
|
|
133
119
|
|
package/src/renderers/text.ts
CHANGED
|
@@ -1,145 +1,123 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DocChild,
|
|
3
|
-
DocNode,
|
|
4
|
-
DocumentRenderer,
|
|
5
|
-
RenderOptions,
|
|
6
|
-
TableColumn,
|
|
7
|
-
} from '../types'
|
|
1
|
+
import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
|
|
8
2
|
|
|
9
3
|
function resolveColumn(col: string | TableColumn): TableColumn {
|
|
10
|
-
return typeof col ===
|
|
4
|
+
return typeof col === "string" ? { header: col } : col
|
|
11
5
|
}
|
|
12
6
|
|
|
13
7
|
function renderChild(child: DocChild): string {
|
|
14
|
-
if (typeof child ===
|
|
8
|
+
if (typeof child === "string") return child
|
|
15
9
|
return renderNode(child)
|
|
16
10
|
}
|
|
17
11
|
|
|
18
12
|
function renderChildren(children: DocChild[]): string {
|
|
19
|
-
return children.map(renderChild).join(
|
|
13
|
+
return children.map(renderChild).join("")
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
function pad(
|
|
23
|
-
str: string,
|
|
24
|
-
width: number,
|
|
25
|
-
align: 'left' | 'center' | 'right' = 'left',
|
|
26
|
-
): string {
|
|
16
|
+
function pad(str: string, width: number, align: "left" | "center" | "right" = "left"): string {
|
|
27
17
|
if (str.length >= width) return str.slice(0, width)
|
|
28
18
|
const diff = width - str.length
|
|
29
|
-
if (align ===
|
|
19
|
+
if (align === "center") {
|
|
30
20
|
const left = Math.floor(diff / 2)
|
|
31
|
-
return
|
|
21
|
+
return " ".repeat(left) + str + " ".repeat(diff - left)
|
|
32
22
|
}
|
|
33
|
-
if (align ===
|
|
34
|
-
return str +
|
|
23
|
+
if (align === "right") return " ".repeat(diff) + str
|
|
24
|
+
return str + " ".repeat(diff)
|
|
35
25
|
}
|
|
36
26
|
|
|
37
27
|
function renderNode(node: DocNode): string {
|
|
38
28
|
const p = node.props
|
|
39
29
|
|
|
40
30
|
switch (node.type) {
|
|
41
|
-
case
|
|
31
|
+
case "document":
|
|
42
32
|
return renderChildren(node.children)
|
|
43
33
|
|
|
44
|
-
case
|
|
34
|
+
case "page":
|
|
45
35
|
return renderChildren(node.children)
|
|
46
36
|
|
|
47
|
-
case
|
|
48
|
-
case
|
|
49
|
-
case
|
|
37
|
+
case "section":
|
|
38
|
+
case "row":
|
|
39
|
+
case "column":
|
|
50
40
|
return renderChildren(node.children)
|
|
51
41
|
|
|
52
|
-
case
|
|
42
|
+
case "heading": {
|
|
53
43
|
const text = renderChildren(node.children)
|
|
54
44
|
const level = (p.level as number) ?? 1
|
|
55
|
-
if (level === 1)
|
|
56
|
-
|
|
57
|
-
if (level === 2) return `${text}\n${'-'.repeat(text.length)}\n\n`
|
|
45
|
+
if (level === 1) return `${text.toUpperCase()}\n${"=".repeat(text.length)}\n\n`
|
|
46
|
+
if (level === 2) return `${text}\n${"-".repeat(text.length)}\n\n`
|
|
58
47
|
return `${text}\n\n`
|
|
59
48
|
}
|
|
60
49
|
|
|
61
|
-
case
|
|
50
|
+
case "text":
|
|
62
51
|
return `${renderChildren(node.children)}\n\n`
|
|
63
52
|
|
|
64
|
-
case
|
|
53
|
+
case "link":
|
|
65
54
|
return `${renderChildren(node.children)} (${p.href})`
|
|
66
55
|
|
|
67
|
-
case
|
|
68
|
-
const alt = (p.alt as string) ??
|
|
69
|
-
const caption = p.caption ? ` — ${p.caption}` :
|
|
56
|
+
case "image": {
|
|
57
|
+
const alt = (p.alt as string) ?? "Image"
|
|
58
|
+
const caption = p.caption ? ` — ${p.caption}` : ""
|
|
70
59
|
return `[${alt}${caption}]\n\n`
|
|
71
60
|
}
|
|
72
61
|
|
|
73
|
-
case
|
|
74
|
-
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
|
|
75
|
-
resolveColumn,
|
|
76
|
-
)
|
|
62
|
+
case "table": {
|
|
63
|
+
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
|
|
77
64
|
const rows = (p.rows ?? []) as (string | number)[][]
|
|
78
65
|
|
|
79
|
-
if (columns.length === 0) return
|
|
66
|
+
if (columns.length === 0) return ""
|
|
80
67
|
|
|
81
68
|
// Calculate column widths
|
|
82
69
|
const widths = columns.map((col, i) => {
|
|
83
70
|
const headerLen = col.header.length
|
|
84
|
-
const maxDataLen = rows.reduce(
|
|
85
|
-
(max, row) => Math.max(max, String(row[i] ?? '').length),
|
|
86
|
-
0,
|
|
87
|
-
)
|
|
71
|
+
const maxDataLen = rows.reduce((max, row) => Math.max(max, String(row[i] ?? "").length), 0)
|
|
88
72
|
return Math.max(headerLen, maxDataLen, 3)
|
|
89
73
|
})
|
|
90
74
|
|
|
91
75
|
// Header
|
|
92
|
-
const header = columns
|
|
93
|
-
|
|
94
|
-
.join(' | ')
|
|
95
|
-
const separator = widths.map((w) => '-'.repeat(w ?? 3)).join('-+-')
|
|
76
|
+
const header = columns.map((col, i) => pad(col.header, widths[i] ?? 3, col.align)).join(" | ")
|
|
77
|
+
const separator = widths.map((w) => "-".repeat(w ?? 3)).join("-+-")
|
|
96
78
|
|
|
97
79
|
// Rows
|
|
98
80
|
const body = rows
|
|
99
81
|
.map((row) =>
|
|
100
|
-
columns
|
|
101
|
-
.map((col, i) =>
|
|
102
|
-
pad(String(row[i] ?? ''), widths[i] ?? 3, col.align),
|
|
103
|
-
)
|
|
104
|
-
.join(' | '),
|
|
82
|
+
columns.map((col, i) => pad(String(row[i] ?? ""), widths[i] ?? 3, col.align)).join(" | "),
|
|
105
83
|
)
|
|
106
|
-
.join(
|
|
84
|
+
.join("\n")
|
|
107
85
|
|
|
108
86
|
let result = `${header}\n${separator}\n${body}\n\n`
|
|
109
87
|
if (p.caption) result = `${p.caption}\n\n${result}`
|
|
110
88
|
return result
|
|
111
89
|
}
|
|
112
90
|
|
|
113
|
-
case
|
|
91
|
+
case "list": {
|
|
114
92
|
const ordered = p.ordered as boolean | undefined
|
|
115
93
|
return `${node.children
|
|
116
|
-
.filter((c): c is DocNode => typeof c !==
|
|
94
|
+
.filter((c): c is DocNode => typeof c !== "string")
|
|
117
95
|
.map((item, i) => {
|
|
118
|
-
const prefix = ordered ? `${i + 1}.` :
|
|
96
|
+
const prefix = ordered ? `${i + 1}.` : "*"
|
|
119
97
|
return ` ${prefix} ${renderChildren(item.children)}`
|
|
120
98
|
})
|
|
121
|
-
.join(
|
|
99
|
+
.join("\n")}\n\n`
|
|
122
100
|
}
|
|
123
101
|
|
|
124
|
-
case
|
|
102
|
+
case "list-item":
|
|
125
103
|
return renderChildren(node.children)
|
|
126
104
|
|
|
127
|
-
case
|
|
105
|
+
case "code":
|
|
128
106
|
return `${renderChildren(node.children)}\n\n`
|
|
129
107
|
|
|
130
|
-
case
|
|
131
|
-
return `${
|
|
108
|
+
case "divider":
|
|
109
|
+
return `${"─".repeat(40)}\n\n`
|
|
132
110
|
|
|
133
|
-
case
|
|
134
|
-
return `\n${
|
|
111
|
+
case "page-break":
|
|
112
|
+
return `\n${"═".repeat(40)}\n\n`
|
|
135
113
|
|
|
136
|
-
case
|
|
137
|
-
return
|
|
114
|
+
case "spacer":
|
|
115
|
+
return "\n"
|
|
138
116
|
|
|
139
|
-
case
|
|
117
|
+
case "button":
|
|
140
118
|
return `[${renderChildren(node.children)}] → ${p.href}\n\n`
|
|
141
119
|
|
|
142
|
-
case
|
|
120
|
+
case "quote":
|
|
143
121
|
return ` "${renderChildren(node.children)}"\n\n`
|
|
144
122
|
|
|
145
123
|
default:
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { sanitizeHref } from
|
|
2
|
-
import type {
|
|
3
|
-
DocChild,
|
|
4
|
-
DocNode,
|
|
5
|
-
DocumentRenderer,
|
|
6
|
-
RenderOptions,
|
|
7
|
-
TableColumn,
|
|
8
|
-
} from '../types'
|
|
1
|
+
import { sanitizeHref } from "../sanitize"
|
|
2
|
+
import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
|
|
9
3
|
|
|
10
4
|
/**
|
|
11
5
|
* WhatsApp renderer — outputs formatted text using WhatsApp's markup.
|
|
@@ -13,36 +7,32 @@ import type {
|
|
|
13
7
|
*/
|
|
14
8
|
|
|
15
9
|
function resolveColumn(col: string | TableColumn): TableColumn {
|
|
16
|
-
return typeof 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
|
-
|
|
23
|
-
)
|
|
24
|
-
.join('')
|
|
15
|
+
.map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
|
|
16
|
+
.join("")
|
|
25
17
|
}
|
|
26
18
|
|
|
27
19
|
function renderNode(node: DocNode): string {
|
|
28
20
|
const p = node.props
|
|
29
21
|
|
|
30
22
|
switch (node.type) {
|
|
31
|
-
case
|
|
32
|
-
case
|
|
33
|
-
case
|
|
34
|
-
case
|
|
35
|
-
case
|
|
36
|
-
return node.children
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
case 'heading': {
|
|
23
|
+
case "document":
|
|
24
|
+
case "page":
|
|
25
|
+
case "section":
|
|
26
|
+
case "row":
|
|
27
|
+
case "column":
|
|
28
|
+
return node.children.map((c) => (typeof c === "string" ? c : renderNode(c))).join("")
|
|
29
|
+
|
|
30
|
+
case "heading": {
|
|
41
31
|
const text = getTextContent(node.children)
|
|
42
32
|
return `*${text}*\n\n`
|
|
43
33
|
}
|
|
44
34
|
|
|
45
|
-
case
|
|
35
|
+
case "text": {
|
|
46
36
|
let text = getTextContent(node.children)
|
|
47
37
|
if (p.bold) text = `*${text}*`
|
|
48
38
|
if (p.italic) text = `_${text}_`
|
|
@@ -50,68 +40,64 @@ function renderNode(node: DocNode): string {
|
|
|
50
40
|
return `${text}\n\n`
|
|
51
41
|
}
|
|
52
42
|
|
|
53
|
-
case
|
|
43
|
+
case "link": {
|
|
54
44
|
const href = sanitizeHref(p.href as string)
|
|
55
45
|
const text = getTextContent(node.children)
|
|
56
46
|
return `${text}: ${href}\n\n`
|
|
57
47
|
}
|
|
58
48
|
|
|
59
|
-
case
|
|
49
|
+
case "image":
|
|
60
50
|
// WhatsApp doesn't support inline images in text
|
|
61
|
-
return
|
|
51
|
+
return ""
|
|
62
52
|
|
|
63
|
-
case
|
|
64
|
-
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(
|
|
65
|
-
resolveColumn,
|
|
66
|
-
)
|
|
53
|
+
case "table": {
|
|
54
|
+
const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
|
|
67
55
|
const rows = (p.rows ?? []) as (string | number)[][]
|
|
68
56
|
|
|
69
|
-
const header = columns.map((c) => `*${c.header}*`).join(
|
|
70
|
-
const body = rows
|
|
71
|
-
.map((row) => row.map((c) => String(c ?? '')).join(' | '))
|
|
72
|
-
.join('\n')
|
|
57
|
+
const header = columns.map((c) => `*${c.header}*`).join(" | ")
|
|
58
|
+
const body = rows.map((row) => row.map((c) => String(c ?? "")).join(" | ")).join("\n")
|
|
73
59
|
|
|
74
60
|
let result = `${header}\n${body}\n\n`
|
|
75
61
|
if (p.caption) result = `_${p.caption}_\n${result}`
|
|
76
62
|
return result
|
|
77
63
|
}
|
|
78
64
|
|
|
79
|
-
case
|
|
65
|
+
case "list": {
|
|
80
66
|
const ordered = p.ordered as boolean | undefined
|
|
81
67
|
return `${node.children
|
|
82
|
-
.filter((c): c is DocNode => typeof c !==
|
|
68
|
+
.filter((c): c is DocNode => typeof c !== "string")
|
|
83
69
|
.map((item, i) => {
|
|
84
|
-
const prefix = ordered ? `${i + 1}.` :
|
|
70
|
+
const prefix = ordered ? `${i + 1}.` : "•"
|
|
85
71
|
return `${prefix} ${getTextContent(item.children)}`
|
|
86
72
|
})
|
|
87
|
-
.join(
|
|
73
|
+
.join("\n")}\n\n`
|
|
88
74
|
}
|
|
89
75
|
|
|
90
|
-
case
|
|
76
|
+
case "code": {
|
|
91
77
|
const text = getTextContent(node.children)
|
|
92
78
|
return `\`\`\`${text}\`\`\`\n\n`
|
|
93
79
|
}
|
|
94
80
|
|
|
95
|
-
case
|
|
96
|
-
case
|
|
97
|
-
return
|
|
81
|
+
case "divider":
|
|
82
|
+
case "page-break":
|
|
83
|
+
return "───────────\n\n"
|
|
98
84
|
|
|
99
|
-
case
|
|
100
|
-
return
|
|
85
|
+
case "spacer":
|
|
86
|
+
return "\n"
|
|
101
87
|
|
|
102
|
-
case
|
|
88
|
+
case "button": {
|
|
103
89
|
const href = sanitizeHref(p.href as string)
|
|
104
90
|
const text = getTextContent(node.children)
|
|
105
91
|
return `*${text}*: ${href}\n\n`
|
|
106
92
|
}
|
|
107
93
|
|
|
108
|
-
case
|
|
94
|
+
case "quote": {
|
|
109
95
|
const text = getTextContent(node.children)
|
|
110
96
|
return `> ${text}\n\n`
|
|
111
97
|
}
|
|
112
98
|
|
|
113
99
|
default:
|
|
114
|
-
return
|
|
100
|
+
return ""
|
|
115
101
|
}
|
|
116
102
|
}
|
|
117
103
|
|