@pyreon/document 0.11.4 → 0.11.6

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 (50) hide show
  1. package/README.md +7 -4
  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/docx-uNAel545.js.map +1 -1
  6. package/lib/email-D0bbfWq4.js.map +1 -1
  7. package/lib/google-chat-CkKCBUWC.js.map +1 -1
  8. package/lib/html-B5biprN2.js.map +1 -1
  9. package/lib/index.js.map +1 -1
  10. package/lib/markdown-CdtlFGC0.js.map +1 -1
  11. package/lib/notion-iG2C5bEY.js.map +1 -1
  12. package/lib/pdf-IuBgTb3T.js.map +1 -1
  13. package/lib/pptx-DXiMiYFM.js.map +1 -1
  14. package/lib/sanitize-O_3j1mNJ.js.map +1 -1
  15. package/lib/slack-BI3EQwYm.js.map +1 -1
  16. package/lib/svg-BKxumy-p.js.map +1 -1
  17. package/lib/teams-Cwz9lce0.js.map +1 -1
  18. package/lib/telegram-gYFqyMXb.js.map +1 -1
  19. package/lib/text-l1XNXBOC.js.map +1 -1
  20. package/lib/types/index.d.ts +27 -27
  21. package/lib/whatsapp-CjSGoOKx.js.map +1 -1
  22. package/lib/xlsx-Cvu4LBNy.js.map +1 -1
  23. package/package.json +21 -21
  24. package/src/builder.ts +36 -36
  25. package/src/download.ts +32 -32
  26. package/src/index.ts +5 -10
  27. package/src/nodes.ts +45 -45
  28. package/src/render.ts +43 -43
  29. package/src/renderers/confluence.ts +63 -63
  30. package/src/renderers/csv.ts +10 -10
  31. package/src/renderers/discord.ts +37 -37
  32. package/src/renderers/docx.ts +57 -57
  33. package/src/renderers/email.ts +72 -72
  34. package/src/renderers/google-chat.ts +34 -34
  35. package/src/renderers/html.ts +76 -76
  36. package/src/renderers/markdown.ts +42 -42
  37. package/src/renderers/notion.ts +60 -60
  38. package/src/renderers/pdf.ts +78 -78
  39. package/src/renderers/pptx.ts +51 -51
  40. package/src/renderers/slack.ts +48 -48
  41. package/src/renderers/svg.ts +47 -47
  42. package/src/renderers/teams.ts +67 -67
  43. package/src/renderers/telegram.ts +39 -39
  44. package/src/renderers/text.ts +43 -43
  45. package/src/renderers/whatsapp.ts +33 -33
  46. package/src/renderers/xlsx.ts +35 -35
  47. package/src/sanitize.ts +20 -20
  48. package/src/tests/document.test.ts +1302 -1302
  49. package/src/tests/stress.test.ts +110 -110
  50. package/src/types.ts +61 -61
@@ -1,5 +1,5 @@
1
- import { sanitizeColor, sanitizeHref, sanitizeImageSrc } from "../sanitize"
2
- import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
1
+ import { sanitizeColor, sanitizeHref, sanitizeImageSrc } from '../sanitize'
2
+ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from '../types'
3
3
 
4
4
  /**
5
5
  * SVG renderer — generates a standalone SVG document from the node tree.
@@ -8,21 +8,21 @@ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn }
8
8
  */
9
9
 
10
10
  function resolveColumn(col: string | TableColumn): TableColumn {
11
- return typeof col === "string" ? { header: col } : col
11
+ return typeof col === 'string' ? { header: col } : col
12
12
  }
13
13
 
14
14
  function escapeXml(str: string): string {
15
15
  return str
16
- .replace(/&/g, "&")
17
- .replace(/</g, "&lt;")
18
- .replace(/>/g, "&gt;")
19
- .replace(/"/g, "&quot;")
16
+ .replace(/&/g, '&amp;')
17
+ .replace(/</g, '&lt;')
18
+ .replace(/>/g, '&gt;')
19
+ .replace(/"/g, '&quot;')
20
20
  }
21
21
 
22
22
  function getTextContent(children: DocChild[]): string {
23
23
  return children
24
- .map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
25
- .join("")
24
+ .map((c) => (typeof c === 'string' ? c : getTextContent((c as DocNode).children)))
25
+ .join('')
26
26
  }
27
27
 
28
28
  interface RenderContext {
@@ -34,22 +34,22 @@ interface RenderContext {
34
34
  function renderNode(node: DocNode, ctx: RenderContext): string {
35
35
  const p = node.props
36
36
  const contentWidth = ctx.width - ctx.padding * 2
37
- let svg = ""
37
+ let svg = ''
38
38
 
39
39
  switch (node.type) {
40
- case "document":
41
- case "page":
42
- case "section":
43
- case "row":
44
- case "column":
40
+ case 'document':
41
+ case 'page':
42
+ case 'section':
43
+ case 'row':
44
+ case 'column':
45
45
  for (const child of node.children) {
46
- if (typeof child !== "string") {
46
+ if (typeof child !== 'string') {
47
47
  svg += renderNode(child, ctx)
48
48
  }
49
49
  }
50
50
  break
51
51
 
52
- case "heading": {
52
+ case 'heading': {
53
53
  const level = (p.level as number) ?? 1
54
54
  const sizes: Record<number, number> = {
55
55
  1: 28,
@@ -60,7 +60,7 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
60
60
  6: 14,
61
61
  }
62
62
  const size = sizes[level] ?? 24
63
- const color = sanitizeColor((p.color as string) ?? "#000000")
63
+ const color = sanitizeColor((p.color as string) ?? '#000000')
64
64
  const text = escapeXml(getTextContent(node.children))
65
65
  ctx.y += size + 8
66
66
  svg += `<text x="${ctx.padding}" y="${ctx.y}" font-size="${size}" font-weight="bold" fill="${color}" font-family="system-ui, -apple-system, sans-serif">${text}</text>`
@@ -68,11 +68,11 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
68
68
  break
69
69
  }
70
70
 
71
- case "text": {
71
+ case 'text': {
72
72
  const size = (p.size as number) ?? 14
73
- const color = sanitizeColor((p.color as string) ?? "#333333")
74
- const weight = p.bold ? "bold" : "normal"
75
- const style = p.italic ? "italic" : "normal"
73
+ const color = sanitizeColor((p.color as string) ?? '#333333')
74
+ const weight = p.bold ? 'bold' : 'normal'
75
+ const style = p.italic ? 'italic' : 'normal'
76
76
  const text = escapeXml(getTextContent(node.children))
77
77
  ctx.y += size + 4
78
78
  svg += `<text x="${ctx.padding}" y="${ctx.y}" font-size="${size}" font-weight="${weight}" font-style="${style}" fill="${color}" font-family="system-ui, -apple-system, sans-serif">${text}</text>`
@@ -80,27 +80,27 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
80
80
  break
81
81
  }
82
82
 
83
- case "link": {
83
+ case 'link': {
84
84
  const href = sanitizeHref(p.href as string)
85
85
  const text = escapeXml(getTextContent(node.children))
86
- const color = sanitizeColor((p.color as string) ?? "#4f46e5")
86
+ const color = sanitizeColor((p.color as string) ?? '#4f46e5')
87
87
  ctx.y += 18
88
88
  svg += `<a href="${escapeXml(href)}"><text x="${ctx.padding}" y="${ctx.y}" font-size="14" fill="${color}" text-decoration="underline" font-family="system-ui, -apple-system, sans-serif">${text}</text></a>`
89
89
  ctx.y += 10
90
90
  break
91
91
  }
92
92
 
93
- case "image": {
93
+ case 'image': {
94
94
  const width = (p.width as number) ?? Math.min(contentWidth, 400)
95
95
  const height = (p.height as number) ?? 200
96
96
  const src = sanitizeImageSrc(p.src as string)
97
97
 
98
- if (src.startsWith("data:") || src.startsWith("http")) {
98
+ if (src.startsWith('data:') || src.startsWith('http')) {
99
99
  svg += `<image x="${ctx.padding}" y="${ctx.y}" width="${width}" height="${height}" href="${escapeXml(src)}" />`
100
100
  } else {
101
101
  // Placeholder rectangle for local paths
102
102
  svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${width}" height="${height}" fill="#f0f0f0" stroke="#ddd" rx="4" />`
103
- svg += `<text x="${ctx.padding + width / 2}" y="${ctx.y + height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999" font-family="system-ui, sans-serif">${escapeXml((p.alt as string) ?? "Image")}</text>`
103
+ svg += `<text x="${ctx.padding + width / 2}" y="${ctx.y + height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999" font-family="system-ui, sans-serif">${escapeXml((p.alt as string) ?? 'Image')}</text>`
104
104
  }
105
105
  ctx.y += height + 8
106
106
 
@@ -112,7 +112,7 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
112
112
  break
113
113
  }
114
114
 
115
- case "table": {
115
+ case 'table': {
116
116
  const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
117
117
  const rows = (p.rows ?? []) as (string | number)[][]
118
118
  const hs = p.headerStyle as { background?: string; color?: string } | undefined
@@ -120,8 +120,8 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
120
120
 
121
121
  const colWidth = contentWidth / columns.length
122
122
  const rowHeight = 28
123
- const headerBg = sanitizeColor(hs?.background ?? "#f5f5f5")
124
- const headerColor = sanitizeColor(hs?.color ?? "#000000")
123
+ const headerBg = sanitizeColor(hs?.background ?? '#f5f5f5')
124
+ const headerColor = sanitizeColor(hs?.color ?? '#000000')
125
125
 
126
126
  // Header
127
127
  svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${rowHeight}" fill="${headerBg}" />`
@@ -138,7 +138,7 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
138
138
  svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${rowHeight}" fill="#f9f9f9" />`
139
139
  }
140
140
  for (let c = 0; c < columns.length; c++) {
141
- svg += `<text x="${ctx.padding + c * colWidth + 8}" y="${ctx.y + 18}" font-size="12" fill="#333" font-family="system-ui, sans-serif">${escapeXml(String(rows[r]?.[c] ?? ""))}</text>`
141
+ svg += `<text x="${ctx.padding + c * colWidth + 8}" y="${ctx.y + 18}" font-size="12" fill="#333" font-family="system-ui, sans-serif">${escapeXml(String(rows[r]?.[c] ?? ''))}</text>`
142
142
  }
143
143
  ctx.y += rowHeight
144
144
  }
@@ -149,13 +149,13 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
149
149
  break
150
150
  }
151
151
 
152
- case "list": {
152
+ case 'list': {
153
153
  const ordered = p.ordered as boolean | undefined
154
- const items = node.children.filter((c): c is DocNode => typeof c !== "string")
154
+ const items = node.children.filter((c): c is DocNode => typeof c !== 'string')
155
155
  for (let i = 0; i < items.length; i++) {
156
156
  const item = items[i]
157
157
  if (!item) continue
158
- const prefix = ordered ? `${i + 1}.` : ""
158
+ const prefix = ordered ? `${i + 1}.` : ''
159
159
  const text = escapeXml(getTextContent(item.children))
160
160
  ctx.y += 18
161
161
  svg += `<text x="${ctx.padding + 16}" y="${ctx.y}" font-size="13" fill="#333" font-family="system-ui, sans-serif">${prefix} ${text}</text>`
@@ -164,20 +164,20 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
164
164
  break
165
165
  }
166
166
 
167
- case "code": {
167
+ case 'code': {
168
168
  const text = getTextContent(node.children)
169
- const lines = text.split("\n")
169
+ const lines = text.split('\n')
170
170
  const codeHeight = lines.length * 18 + 16
171
171
  svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="${contentWidth}" height="${codeHeight}" fill="#f5f5f5" rx="4" />`
172
172
  for (let i = 0; i < lines.length; i++) {
173
- svg += `<text x="${ctx.padding + 12}" y="${ctx.y + 20 + i * 18}" font-size="12" fill="#333" font-family="monospace">${escapeXml(lines[i] ?? "")}</text>`
173
+ svg += `<text x="${ctx.padding + 12}" y="${ctx.y + 20 + i * 18}" font-size="12" fill="#333" font-family="monospace">${escapeXml(lines[i] ?? '')}</text>`
174
174
  }
175
175
  ctx.y += codeHeight + 8
176
176
  break
177
177
  }
178
178
 
179
- case "divider": {
180
- const color = sanitizeColor((p.color as string) ?? "#ddd")
179
+ case 'divider': {
180
+ const color = sanitizeColor((p.color as string) ?? '#ddd')
181
181
  const thickness = (p.thickness as number) ?? 1
182
182
  ctx.y += 12
183
183
  svg += `<line x1="${ctx.padding}" y1="${ctx.y}" x2="${ctx.padding + contentWidth}" y2="${ctx.y}" stroke="${color}" stroke-width="${thickness}" />`
@@ -185,19 +185,19 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
185
185
  break
186
186
  }
187
187
 
188
- case "page-break":
188
+ case 'page-break':
189
189
  ctx.y += 16
190
190
  svg += `<line x1="${ctx.padding}" y1="${ctx.y}" x2="${ctx.padding + contentWidth}" y2="${ctx.y}" stroke="#ccc" stroke-width="2" stroke-dasharray="8,4" />`
191
191
  ctx.y += 16
192
192
  break
193
193
 
194
- case "spacer":
194
+ case 'spacer':
195
195
  ctx.y += (p.height as number) ?? 12
196
196
  break
197
197
 
198
- case "button": {
199
- const bg = sanitizeColor((p.background as string) ?? "#4f46e5")
200
- const color = sanitizeColor((p.color as string) ?? "#ffffff")
198
+ case 'button': {
199
+ const bg = sanitizeColor((p.background as string) ?? '#4f46e5')
200
+ const color = sanitizeColor((p.color as string) ?? '#ffffff')
201
201
  const text = escapeXml(getTextContent(node.children))
202
202
  const btnWidth = Math.min(text.length * 10 + 48, contentWidth)
203
203
  const btnHeight = 40
@@ -208,8 +208,8 @@ function renderNode(node: DocNode, ctx: RenderContext): string {
208
208
  break
209
209
  }
210
210
 
211
- case "quote": {
212
- const borderColor = sanitizeColor((p.borderColor as string) ?? "#ddd")
211
+ case 'quote': {
212
+ const borderColor = sanitizeColor((p.borderColor as string) ?? '#ddd')
213
213
  const text = escapeXml(getTextContent(node.children))
214
214
  ctx.y += 4
215
215
  svg += `<rect x="${ctx.padding}" y="${ctx.y}" width="4" height="20" fill="${borderColor}" />`
@@ -231,7 +231,7 @@ export const svgRenderer: DocumentRenderer = {
231
231
  const content = renderNode(node, ctx)
232
232
  const height = ctx.y + padding
233
233
 
234
- const dir = options?.direction === "rtl" ? ' direction="rtl"' : ""
234
+ const dir = options?.direction === 'rtl' ? ' direction="rtl"' : ''
235
235
 
236
236
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"${dir}>
237
237
  <rect width="${width}" height="${height}" fill="#ffffff" />
@@ -1,5 +1,5 @@
1
- import { sanitizeHref, sanitizeImageSrc } from "../sanitize"
2
- import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from "../types"
1
+ import { sanitizeHref, sanitizeImageSrc } from '../sanitize'
2
+ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from '../types'
3
3
 
4
4
  /**
5
5
  * Microsoft Teams renderer — outputs Adaptive Cards JSON.
@@ -7,13 +7,13 @@ import type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn }
7
7
  */
8
8
 
9
9
  function resolveColumn(col: string | TableColumn): TableColumn {
10
- return typeof col === "string" ? { header: col } : col
10
+ return typeof col === 'string' ? { header: col } : col
11
11
  }
12
12
 
13
13
  function getTextContent(children: DocChild[]): string {
14
14
  return children
15
- .map((c) => (typeof c === "string" ? c : getTextContent((c as DocNode).children)))
16
- .join("")
15
+ .map((c) => (typeof c === 'string' ? c : getTextContent((c as DocNode).children)))
16
+ .join('')
17
17
  }
18
18
 
19
19
  interface AdaptiveElement {
@@ -26,95 +26,95 @@ function nodeToElements(node: DocNode): AdaptiveElement[] {
26
26
  const elements: AdaptiveElement[] = []
27
27
 
28
28
  switch (node.type) {
29
- case "document":
30
- case "page":
31
- case "section":
32
- case "row":
33
- case "column":
29
+ case 'document':
30
+ case 'page':
31
+ case 'section':
32
+ case 'row':
33
+ case 'column':
34
34
  for (const child of node.children) {
35
- if (typeof child !== "string") {
35
+ if (typeof child !== 'string') {
36
36
  elements.push(...nodeToElements(child))
37
37
  }
38
38
  }
39
39
  break
40
40
 
41
- case "heading": {
41
+ case 'heading': {
42
42
  const level = (p.level as number) ?? 1
43
43
  const sizeMap: Record<number, string> = {
44
- 1: "extraLarge",
45
- 2: "large",
46
- 3: "medium",
47
- 4: "default",
48
- 5: "small",
49
- 6: "small",
44
+ 1: 'extraLarge',
45
+ 2: 'large',
46
+ 3: 'medium',
47
+ 4: 'default',
48
+ 5: 'small',
49
+ 6: 'small',
50
50
  }
51
51
  elements.push({
52
- type: "TextBlock",
52
+ type: 'TextBlock',
53
53
  text: getTextContent(node.children),
54
- size: sizeMap[level] ?? "large",
55
- weight: "bolder",
54
+ size: sizeMap[level] ?? 'large',
55
+ weight: 'bolder',
56
56
  wrap: true,
57
57
  })
58
58
  break
59
59
  }
60
60
 
61
- case "text": {
61
+ case 'text': {
62
62
  let text = getTextContent(node.children)
63
63
  if (p.bold) text = `**${text}**`
64
64
  if (p.italic) text = `_${text}_`
65
65
  if (p.strikethrough) text = `~~${text}~~`
66
66
  elements.push({
67
- type: "TextBlock",
67
+ type: 'TextBlock',
68
68
  text,
69
69
  wrap: true,
70
- ...(p.color ? { color: "default" } : {}),
71
- ...(p.size ? { size: (p.size as number) >= 18 ? "large" : "default" } : {}),
70
+ ...(p.color ? { color: 'default' } : {}),
71
+ ...(p.size ? { size: (p.size as number) >= 18 ? 'large' : 'default' } : {}),
72
72
  })
73
73
  break
74
74
  }
75
75
 
76
- case "link": {
76
+ case 'link': {
77
77
  const href = sanitizeHref(p.href as string)
78
78
  const text = getTextContent(node.children)
79
79
  elements.push({
80
- type: "TextBlock",
80
+ type: 'TextBlock',
81
81
  text: `[${text}](${href})`,
82
82
  wrap: true,
83
83
  })
84
84
  break
85
85
  }
86
86
 
87
- case "image": {
87
+ case 'image': {
88
88
  const src = sanitizeImageSrc(p.src as string)
89
- if (src.startsWith("http")) {
89
+ if (src.startsWith('http')) {
90
90
  elements.push({
91
- type: "Image",
91
+ type: 'Image',
92
92
  url: src,
93
- altText: (p.alt as string) ?? "Image",
94
- size: "large",
93
+ altText: (p.alt as string) ?? 'Image',
94
+ size: 'large',
95
95
  })
96
96
  }
97
97
  break
98
98
  }
99
99
 
100
- case "table": {
100
+ case 'table': {
101
101
  const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)
102
102
  const rows = (p.rows ?? []) as (string | number)[][]
103
103
 
104
104
  // Adaptive Cards have native Table support (schema 1.5+)
105
105
  const tableColumns = columns.map((col) => ({
106
- type: "Column",
107
- width: "stretch",
106
+ type: 'Column',
107
+ width: 'stretch',
108
108
  items: [
109
109
  {
110
- type: "TextBlock",
110
+ type: 'TextBlock',
111
111
  text: `**${col.header}**`,
112
- weight: "bolder",
112
+ weight: 'bolder',
113
113
  wrap: true,
114
114
  },
115
115
  ...rows.map((row, i) => ({
116
- type: "TextBlock",
117
- text: String(row[columns.indexOf(col)] ?? ""),
116
+ type: 'TextBlock',
117
+ text: String(row[columns.indexOf(col)] ?? ''),
118
118
  wrap: true,
119
119
  separator: i === 0,
120
120
  })),
@@ -122,80 +122,80 @@ function nodeToElements(node: DocNode): AdaptiveElement[] {
122
122
  }))
123
123
 
124
124
  elements.push({
125
- type: "ColumnSet",
125
+ type: 'ColumnSet',
126
126
  columns: tableColumns,
127
127
  })
128
128
  break
129
129
  }
130
130
 
131
- case "list": {
131
+ case 'list': {
132
132
  const ordered = p.ordered as boolean | undefined
133
133
  const items = node.children
134
- .filter((c): c is DocNode => typeof c !== "string")
134
+ .filter((c): c is DocNode => typeof c !== 'string')
135
135
  .map((item, i) => {
136
- const prefix = ordered ? `${i + 1}.` : ""
136
+ const prefix = ordered ? `${i + 1}.` : ''
137
137
  return `${prefix} ${getTextContent(item.children)}`
138
138
  })
139
- .join("\n")
139
+ .join('\n')
140
140
  elements.push({
141
- type: "TextBlock",
141
+ type: 'TextBlock',
142
142
  text: items,
143
143
  wrap: true,
144
144
  })
145
145
  break
146
146
  }
147
147
 
148
- case "code": {
148
+ case 'code': {
149
149
  const text = getTextContent(node.children)
150
150
  elements.push({
151
- type: "TextBlock",
151
+ type: 'TextBlock',
152
152
  text: `\`\`\`\n${text}\n\`\`\``,
153
- fontType: "monospace",
153
+ fontType: 'monospace',
154
154
  wrap: true,
155
155
  })
156
156
  break
157
157
  }
158
158
 
159
- case "divider":
160
- case "page-break":
159
+ case 'divider':
160
+ case 'page-break':
161
161
  elements.push({
162
- type: "TextBlock",
163
- text: " ",
162
+ type: 'TextBlock',
163
+ text: ' ',
164
164
  separator: true,
165
165
  })
166
166
  break
167
167
 
168
- case "spacer":
168
+ case 'spacer':
169
169
  elements.push({
170
- type: "TextBlock",
171
- text: " ",
172
- spacing: "large",
170
+ type: 'TextBlock',
171
+ text: ' ',
172
+ spacing: 'large',
173
173
  })
174
174
  break
175
175
 
176
- case "button": {
176
+ case 'button': {
177
177
  elements.push({
178
- type: "ActionSet",
178
+ type: 'ActionSet',
179
179
  actions: [
180
180
  {
181
- type: "Action.OpenUrl",
181
+ type: 'Action.OpenUrl',
182
182
  title: getTextContent(node.children),
183
183
  url: sanitizeHref(p.href as string),
184
- style: "positive",
184
+ style: 'positive',
185
185
  },
186
186
  ],
187
187
  })
188
188
  break
189
189
  }
190
190
 
191
- case "quote": {
191
+ case 'quote': {
192
192
  const text = getTextContent(node.children)
193
193
  elements.push({
194
- type: "Container",
195
- style: "emphasis",
194
+ type: 'Container',
195
+ style: 'emphasis',
196
196
  items: [
197
197
  {
198
- type: "TextBlock",
198
+ type: 'TextBlock',
199
199
  text: `_${text}_`,
200
200
  wrap: true,
201
201
  isSubtle: true,
@@ -213,9 +213,9 @@ export const teamsRenderer: DocumentRenderer = {
213
213
  async render(node: DocNode, _options?: RenderOptions): Promise<string> {
214
214
  const body = nodeToElements(node)
215
215
  const card = {
216
- type: "AdaptiveCard",
217
- $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
218
- version: "1.5",
216
+ type: 'AdaptiveCard',
217
+ $schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
218
+ version: '1.5',
219
219
  body,
220
220
  }
221
221
  return JSON.stringify(card, null, 2)