@pre-markdown/renderer 0.2.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/dist/index.js ADDED
@@ -0,0 +1,715 @@
1
+ // src/index.ts
2
+ var ESCAPE_HTML_RE = /[&<>"]/;
3
+ function escapeHtml(str) {
4
+ if (!ESCAPE_HTML_RE.test(str)) return str;
5
+ let out = "";
6
+ let last = 0;
7
+ for (let i = 0; i < str.length; i++) {
8
+ const ch = str.charCodeAt(i);
9
+ let esc;
10
+ if (ch === 38) esc = "&amp;";
11
+ else if (ch === 60) esc = "&lt;";
12
+ else if (ch === 62) esc = "&gt;";
13
+ else if (ch === 34) esc = "&quot;";
14
+ if (esc !== void 0) {
15
+ if (last < i) out += str.slice(last, i);
16
+ out += esc;
17
+ last = i + 1;
18
+ }
19
+ }
20
+ if (last === 0) return str;
21
+ if (last < str.length) out += str.slice(last);
22
+ return out;
23
+ }
24
+ function escapeAttr(str) {
25
+ if (!ESCAPE_HTML_RE.test(str) && !str.includes("'")) return str;
26
+ let out = "";
27
+ let last = 0;
28
+ for (let i = 0; i < str.length; i++) {
29
+ const ch = str.charCodeAt(i);
30
+ let esc;
31
+ if (ch === 38) esc = "&amp;";
32
+ else if (ch === 34) esc = "&quot;";
33
+ else if (ch === 39) esc = "&#39;";
34
+ else if (ch === 60) esc = "&lt;";
35
+ else if (ch === 62) esc = "&gt;";
36
+ if (esc !== void 0) {
37
+ if (last < i) out += str.slice(last, i);
38
+ out += esc;
39
+ last = i + 1;
40
+ }
41
+ }
42
+ if (last === 0) return str;
43
+ if (last < str.length) out += str.slice(last);
44
+ return out;
45
+ }
46
+ function renderToHtml(doc, options) {
47
+ const opts = {
48
+ sanitize: true,
49
+ highlight: escapeHtml,
50
+ headingId: null,
51
+ baseUrl: "",
52
+ inlineParser: null,
53
+ plugins: null,
54
+ ...options
55
+ };
56
+ let finalDoc = doc;
57
+ if (opts.plugins && opts.plugins.hasTransformHooks()) {
58
+ finalDoc = opts.plugins.applyTransforms(doc);
59
+ }
60
+ return renderBlockNodes(finalDoc.children, opts);
61
+ }
62
+ function resolveInline(node, opts) {
63
+ if (node._raw !== void 0 && node.children.length === 0 && opts.inlineParser) {
64
+ node.children = opts.inlineParser(node._raw);
65
+ node._raw = void 0;
66
+ }
67
+ return node.children;
68
+ }
69
+ function renderBlockNodes(nodes, opts) {
70
+ const len = nodes.length;
71
+ if (len === 0) return "";
72
+ if (len === 1) return renderBlockNode(nodes[0], opts);
73
+ const parts = new Array(len);
74
+ for (let i = 0; i < len; i++) {
75
+ parts[i] = renderBlockNode(nodes[i], opts);
76
+ }
77
+ return parts.join("");
78
+ }
79
+ function renderBlockNode(node, opts) {
80
+ if (opts.plugins && opts.plugins.hasRenderHook(node.type)) {
81
+ const defaultHtml = renderBlockNodeDefault(node, opts);
82
+ const pluginResult = opts.plugins.tryRender({
83
+ node,
84
+ defaultHtml,
85
+ renderChildren: (children) => {
86
+ if (children.length > 0 && "type" in children[0]) {
87
+ const first = children[0];
88
+ if (first.type === "text" || first.type === "emphasis" || first.type === "strong" || first.type === "inlineCode" || first.type === "link" || first.type === "image") {
89
+ return renderInlineNodes(children, opts);
90
+ }
91
+ }
92
+ return renderBlockNodes(children, opts);
93
+ }
94
+ });
95
+ if (pluginResult !== void 0) return pluginResult;
96
+ return defaultHtml;
97
+ }
98
+ return renderBlockNodeDefault(node, opts);
99
+ }
100
+ function renderBlockNodeDefault(node, opts) {
101
+ switch (node.type) {
102
+ case "heading":
103
+ return renderHeading(node, opts);
104
+ case "paragraph":
105
+ return renderParagraph(node, opts);
106
+ case "blockquote":
107
+ return renderBlockquote(node, opts);
108
+ case "list":
109
+ return renderList(node, opts);
110
+ case "listItem":
111
+ return renderListItem(node, opts);
112
+ case "codeBlock":
113
+ return renderCodeBlock(node, opts);
114
+ case "thematicBreak":
115
+ return "<hr />\n";
116
+ case "htmlBlock":
117
+ return (opts.sanitize ? escapeHtml(node.value) : node.value) + "\n";
118
+ case "table":
119
+ return renderTable(node, opts);
120
+ case "tableRow":
121
+ return "";
122
+ case "tableCell":
123
+ return "<td>" + renderInlineNodes(resolveInline(node, opts), opts) + "</td>";
124
+ case "mathBlock":
125
+ return '<div class="math-block">' + escapeHtml(node.value) + "</div>\n";
126
+ case "container":
127
+ return renderContainer(node, opts);
128
+ case "details":
129
+ return renderDetails(node, opts);
130
+ case "toc":
131
+ return '<nav class="toc" data-toc></nav>\n';
132
+ case "footnoteDefinition":
133
+ return '<div class="footnote" id="fn-' + escapeHtml(node.identifier) + '"><sup>' + escapeHtml(node.label) + "</sup>" + renderBlockNodes(node.children, opts) + "</div>\n";
134
+ default:
135
+ return "";
136
+ }
137
+ }
138
+ function renderHeading(node, opts) {
139
+ const children = resolveInline(node, opts);
140
+ const inner = renderInlineNodes(children, opts);
141
+ if (opts.headingId) {
142
+ const text = getPlainText(children);
143
+ const id = opts.headingId(text, node.depth);
144
+ if (id) return "<h" + node.depth + ' id="' + escapeAttr(id) + '">' + inner + "</h" + node.depth + ">\n";
145
+ }
146
+ return "<h" + node.depth + ">" + inner + "</h" + node.depth + ">\n";
147
+ }
148
+ function renderParagraph(node, opts) {
149
+ return "<p>" + renderInlineNodes(resolveInline(node, opts), opts) + "</p>\n";
150
+ }
151
+ function renderBlockquote(node, opts) {
152
+ return "<blockquote>\n" + renderBlockNodes(node.children, opts) + "</blockquote>\n";
153
+ }
154
+ function renderList(node, opts) {
155
+ const tag = node.ordered ? "ol" : "ul";
156
+ const startAttr = node.ordered && node.start !== void 0 && node.start !== 1 ? ' start="' + node.start + '"' : "";
157
+ const len = node.children.length;
158
+ const parts = new Array(len);
159
+ const loose = node.spread;
160
+ for (let i = 0; i < len; i++) {
161
+ parts[i] = renderListItem(node.children[i], opts, loose);
162
+ }
163
+ return "<" + tag + startAttr + ">\n" + parts.join("") + "</" + tag + ">\n";
164
+ }
165
+ function renderListItem(node, opts, loose = true) {
166
+ let content;
167
+ if (!loose && node.children.length === 1 && node.children[0].type === "paragraph") {
168
+ content = renderInlineNodes(resolveInline(node.children[0], opts), opts);
169
+ } else if (!loose && node.children.every((c) => c.type === "paragraph")) {
170
+ content = node.children.map((c) => renderInlineNodes(resolveInline(c, opts), opts)).join("\n");
171
+ } else {
172
+ content = "\n" + renderBlockNodes(node.children, opts);
173
+ }
174
+ if (node.checked !== void 0) {
175
+ const checked = node.checked ? " checked disabled" : " disabled";
176
+ return '<li class="task-list-item"><input type="checkbox"' + checked + " /> " + content + "</li>\n";
177
+ }
178
+ return "<li>" + content + "</li>\n";
179
+ }
180
+ function renderCodeBlock(node, opts) {
181
+ let code = node.value;
182
+ if (code.length > 0 && code.charCodeAt(code.length - 1) !== 10) {
183
+ code += "\n";
184
+ }
185
+ const highlighted = opts.highlight(code, node.lang);
186
+ if (node.lang) {
187
+ return '<pre><code class="language-' + escapeAttr(node.lang) + '">' + highlighted + "</code></pre>\n";
188
+ }
189
+ return "<pre><code>" + highlighted + "</code></pre>\n";
190
+ }
191
+ function renderTable(node, opts) {
192
+ const parts = ["<table>"];
193
+ let inHeader = true;
194
+ for (let i = 0; i < node.children.length; i++) {
195
+ const row = node.children[i];
196
+ if (row.isHeader) {
197
+ if (i === 0) parts.push("<thead>");
198
+ } else if (inHeader) {
199
+ parts.push("</thead><tbody>");
200
+ inHeader = false;
201
+ }
202
+ parts.push("<tr>");
203
+ const cellTag = row.isHeader ? "th" : "td";
204
+ for (let j = 0; j < row.children.length; j++) {
205
+ const cell = row.children[j];
206
+ const align = node.align[j];
207
+ const cellChildren = resolveInline(cell, opts);
208
+ if (align) {
209
+ parts.push("<" + cellTag + ' style="text-align:' + align + '">' + renderInlineNodes(cellChildren, opts) + "</" + cellTag + ">");
210
+ } else {
211
+ parts.push("<" + cellTag + ">" + renderInlineNodes(cellChildren, opts) + "</" + cellTag + ">");
212
+ }
213
+ }
214
+ parts.push("</tr>");
215
+ }
216
+ if (inHeader && node.children.some((r) => r.isHeader)) {
217
+ parts.push("</thead>");
218
+ } else if (!inHeader) {
219
+ parts.push("</tbody>");
220
+ }
221
+ parts.push("</table>\n");
222
+ return parts.join("");
223
+ }
224
+ function renderContainer(node, opts) {
225
+ const title = node.title ? '<p class="container-title">' + escapeHtml(node.title) + "</p>" : "";
226
+ return '<div class="container container-' + escapeAttr(node.kind) + '">' + title + renderBlockNodes(node.children, opts) + "</div>\n";
227
+ }
228
+ function renderDetails(node, opts) {
229
+ return "<details><summary>" + escapeHtml(node.summary) + "</summary>" + renderBlockNodes(node.children, opts) + "</details>\n";
230
+ }
231
+ function renderInlineNodes(nodes, opts) {
232
+ const len = nodes.length;
233
+ if (len === 0) return "";
234
+ if (len === 1) return renderInlineNode(nodes[0], opts);
235
+ let out = "";
236
+ for (let i = 0; i < len; i++) {
237
+ out += renderInlineNode(nodes[i], opts);
238
+ }
239
+ return out;
240
+ }
241
+ function renderInlineNode(node, opts) {
242
+ if (opts.plugins && opts.plugins.hasRenderHook(node.type)) {
243
+ const defaultHtml = renderInlineNodeDefault(node, opts);
244
+ const pluginResult = opts.plugins.tryRender({
245
+ node,
246
+ defaultHtml,
247
+ renderChildren: (children) => renderInlineNodes(children, opts)
248
+ });
249
+ if (pluginResult !== void 0) return pluginResult;
250
+ return defaultHtml;
251
+ }
252
+ return renderInlineNodeDefault(node, opts);
253
+ }
254
+ function renderInlineNodeDefault(node, opts) {
255
+ switch (node.type) {
256
+ case "text":
257
+ return escapeHtml(node.value);
258
+ case "emphasis":
259
+ return "<em>" + renderInlineNodes(node.children, opts) + "</em>";
260
+ case "strong":
261
+ return "<strong>" + renderInlineNodes(node.children, opts) + "</strong>";
262
+ case "strikethrough":
263
+ return "<del>" + renderInlineNodes(node.children, opts) + "</del>";
264
+ case "inlineCode":
265
+ return "<code>" + escapeHtml(node.value) + "</code>";
266
+ case "link": {
267
+ const safeUrl = opts.sanitize ? sanitizeUrl(node.url) : node.url;
268
+ let r = '<a href="' + escapeAttr(encodeUrl(safeUrl)) + '"';
269
+ if (node.title) r += ' title="' + escapeAttr(node.title) + '"';
270
+ return r + ">" + renderInlineNodes(node.children, opts) + "</a>";
271
+ }
272
+ case "image": {
273
+ const safeSrc = opts.sanitize ? sanitizeUrl(node.url) : node.url;
274
+ let r = '<img src="' + escapeAttr(encodeUrl(safeSrc)) + '" alt="' + escapeAttr(node.alt) + '"';
275
+ if (node.title) r += ' title="' + escapeAttr(node.title) + '"';
276
+ if (node.width) r += ' width="' + node.width + '"';
277
+ if (node.height) r += ' height="' + node.height + '"';
278
+ return r + " />";
279
+ }
280
+ case "htmlInline":
281
+ return opts.sanitize ? escapeHtml(node.value) : node.value;
282
+ case "break":
283
+ return "<br />\n";
284
+ case "softBreak":
285
+ return "\n";
286
+ case "footnoteReference":
287
+ return '<sup class="footnote-ref"><a href="#fn-' + escapeAttr(node.identifier) + '">[' + escapeHtml(node.label) + "]</a></sup>";
288
+ case "mathInline":
289
+ return '<span class="math-inline">' + escapeHtml(node.value) + "</span>";
290
+ case "highlight":
291
+ return "<mark>" + renderInlineNodes(node.children, opts) + "</mark>";
292
+ case "superscript":
293
+ return "<sup>" + renderInlineNodes(node.children, opts) + "</sup>";
294
+ case "subscript":
295
+ return "<sub>" + renderInlineNodes(node.children, opts) + "</sub>";
296
+ case "fontColor": {
297
+ const safeColor = opts.sanitize ? sanitizeCssValue(node.color) : node.color;
298
+ return '<span style="color:' + escapeAttr(safeColor) + '">' + renderInlineNodes(node.children, opts) + "</span>";
299
+ }
300
+ case "fontSize": {
301
+ const safeSize = opts.sanitize ? sanitizeCssValue(node.size) : node.size;
302
+ return '<span style="font-size:' + escapeAttr(safeSize) + '">' + renderInlineNodes(node.children, opts) + "</span>";
303
+ }
304
+ case "fontBgColor": {
305
+ const safeBgColor = opts.sanitize ? sanitizeCssValue(node.color) : node.color;
306
+ return '<span style="background-color:' + escapeAttr(safeBgColor) + '">' + renderInlineNodes(node.children, opts) + "</span>";
307
+ }
308
+ case "ruby":
309
+ return "<ruby>" + escapeHtml(node.base) + "<rp>(</rp><rt>" + escapeHtml(node.annotation) + "</rt><rp>)</rp></ruby>";
310
+ case "emoji":
311
+ return node.value;
312
+ case "audio": {
313
+ const safeAudioUrl = opts.sanitize ? sanitizeUrl(node.url) : node.url;
314
+ let r = '<audio controls preload="metadata" src="' + escapeAttr(safeAudioUrl) + '"';
315
+ if (node.title) r += ' title="' + escapeAttr(node.title) + '"';
316
+ const audioAlt = node.title || "Audio";
317
+ return r + ">" + escapeHtml(audioAlt) + "</audio>";
318
+ }
319
+ case "video": {
320
+ const safeVideoUrl = opts.sanitize ? sanitizeUrl(node.url) : node.url;
321
+ let r = '<video controls preload="metadata" src="' + escapeAttr(safeVideoUrl) + '"';
322
+ if (node.title) r += ' title="' + escapeAttr(node.title) + '"';
323
+ const videoAlt = node.title || "Video";
324
+ return r + ">" + escapeHtml(videoAlt) + "</video>";
325
+ }
326
+ case "autolink":
327
+ return '<a href="' + escapeAttr(node.url) + '">' + escapeHtml(node.url.replace(/^mailto:/, "")) + "</a>";
328
+ case "underline":
329
+ return '<span style="text-decoration:underline">' + renderInlineNodes(node.children, opts) + "</span>";
330
+ default:
331
+ return "";
332
+ }
333
+ }
334
+ function sanitizeUrl(url) {
335
+ const trimmed = url.trim().toLowerCase();
336
+ if (trimmed.startsWith("javascript:") || trimmed.startsWith("vbscript:") || trimmed.startsWith("data:") && !trimmed.startsWith("data:image/")) {
337
+ return "";
338
+ }
339
+ return url;
340
+ }
341
+ function encodeUrl(url) {
342
+ try {
343
+ return url.replace(/[^\x21-\x7E]/g, (ch) => {
344
+ try {
345
+ return encodeURIComponent(ch);
346
+ } catch {
347
+ return ch;
348
+ }
349
+ });
350
+ } catch {
351
+ return url;
352
+ }
353
+ }
354
+ function sanitizeCssValue(value) {
355
+ return value.replace(/expression\s*\(/gi, "").replace(/url\s*\(/gi, "").replace(/javascript\s*:/gi, "").replace(/;[^}]*$/g, "");
356
+ }
357
+ function getPlainText(nodes) {
358
+ let out = "";
359
+ for (let i = 0; i < nodes.length; i++) {
360
+ const node = nodes[i];
361
+ if (node.type === "text") out += node.value;
362
+ else if (node.type === "inlineCode") out += node.value;
363
+ else if ("children" in node) out += getPlainText(node.children);
364
+ }
365
+ return out;
366
+ }
367
+ function renderToDOM(doc, options) {
368
+ const opts = {
369
+ sanitize: true,
370
+ highlight: escapeHtml,
371
+ headingId: null,
372
+ baseUrl: "",
373
+ inlineParser: null,
374
+ plugins: null,
375
+ ...options
376
+ };
377
+ let finalDoc = doc;
378
+ if (opts.plugins && opts.plugins.hasTransformHooks()) {
379
+ finalDoc = opts.plugins.applyTransforms(doc);
380
+ }
381
+ const frag = document.createDocumentFragment();
382
+ for (let i = 0; i < finalDoc.children.length; i++) {
383
+ const el = renderBlockToDOM(finalDoc.children[i], opts);
384
+ if (el) frag.appendChild(el);
385
+ }
386
+ return frag;
387
+ }
388
+ function renderBlockToDOM(node, opts) {
389
+ switch (node.type) {
390
+ case "heading": {
391
+ const el = document.createElement("h" + node.depth);
392
+ const children = resolveInline(node, opts);
393
+ appendInlineToDOM(el, children, opts);
394
+ if (opts.headingId) {
395
+ const text = getPlainText(children);
396
+ const id = opts.headingId(text, node.depth);
397
+ if (id) el.setAttribute("id", id);
398
+ }
399
+ return el;
400
+ }
401
+ case "paragraph": {
402
+ const el = document.createElement("p");
403
+ appendInlineToDOM(el, resolveInline(node, opts), opts);
404
+ return el;
405
+ }
406
+ case "blockquote": {
407
+ const el = document.createElement("blockquote");
408
+ appendBlocksToDOM(el, node.children, opts);
409
+ return el;
410
+ }
411
+ case "list": {
412
+ const el = document.createElement(node.ordered ? "ol" : "ul");
413
+ if (node.ordered && node.start !== void 0 && node.start !== 1) {
414
+ el.setAttribute("start", String(node.start));
415
+ }
416
+ for (let i = 0; i < node.children.length; i++) {
417
+ const li = renderListItemToDOM(node.children[i], opts, node.spread);
418
+ if (li) el.appendChild(li);
419
+ }
420
+ return el;
421
+ }
422
+ case "codeBlock": {
423
+ const pre = document.createElement("pre");
424
+ const code = document.createElement("code");
425
+ if (node.lang) code.className = "language-" + node.lang;
426
+ let content = node.value;
427
+ if (content.length > 0 && content.charCodeAt(content.length - 1) !== 10) {
428
+ content += "\n";
429
+ }
430
+ code.innerHTML = opts.highlight(content, node.lang);
431
+ pre.appendChild(code);
432
+ return pre;
433
+ }
434
+ case "thematicBreak":
435
+ return document.createElement("hr");
436
+ case "htmlBlock": {
437
+ if (opts.sanitize) {
438
+ const span = document.createElement("span");
439
+ span.textContent = node.value;
440
+ return span;
441
+ }
442
+ const tmpl = document.createElement("template");
443
+ tmpl.innerHTML = node.value;
444
+ return tmpl.content;
445
+ }
446
+ case "table":
447
+ return renderTableToDOM(node, opts);
448
+ case "mathBlock": {
449
+ const div = document.createElement("div");
450
+ div.className = "math-block";
451
+ div.textContent = node.value;
452
+ return div;
453
+ }
454
+ case "container": {
455
+ const div = document.createElement("div");
456
+ div.className = "container container-" + node.kind;
457
+ if (node.title) {
458
+ const p = document.createElement("p");
459
+ p.className = "container-title";
460
+ p.textContent = node.title;
461
+ div.appendChild(p);
462
+ }
463
+ appendBlocksToDOM(div, node.children, opts);
464
+ return div;
465
+ }
466
+ case "details": {
467
+ const details = document.createElement("details");
468
+ const summary = document.createElement("summary");
469
+ summary.textContent = node.summary;
470
+ details.appendChild(summary);
471
+ appendBlocksToDOM(details, node.children, opts);
472
+ return details;
473
+ }
474
+ case "toc": {
475
+ const nav = document.createElement("nav");
476
+ nav.className = "toc";
477
+ nav.setAttribute("data-toc", "");
478
+ return nav;
479
+ }
480
+ case "footnoteDefinition": {
481
+ const div = document.createElement("div");
482
+ div.className = "footnote";
483
+ div.id = "fn-" + node.identifier;
484
+ const sup = document.createElement("sup");
485
+ sup.textContent = node.label;
486
+ div.appendChild(sup);
487
+ appendBlocksToDOM(div, node.children, opts);
488
+ return div;
489
+ }
490
+ default:
491
+ return null;
492
+ }
493
+ }
494
+ function renderListItemToDOM(node, opts, loose) {
495
+ const li = document.createElement("li");
496
+ if (node.checked !== void 0) {
497
+ li.className = "task-list-item";
498
+ const cb = document.createElement("input");
499
+ cb.type = "checkbox";
500
+ cb.disabled = true;
501
+ if (node.checked) cb.checked = true;
502
+ li.appendChild(cb);
503
+ li.appendChild(document.createTextNode(" "));
504
+ }
505
+ if (!loose && node.children.length === 1 && node.children[0].type === "paragraph") {
506
+ appendInlineToDOM(li, resolveInline(node.children[0], opts), opts);
507
+ } else if (!loose && node.children.every((c) => c.type === "paragraph")) {
508
+ for (let i = 0; i < node.children.length; i++) {
509
+ if (i > 0) li.appendChild(document.createTextNode("\n"));
510
+ appendInlineToDOM(li, resolveInline(node.children[i], opts), opts);
511
+ }
512
+ } else {
513
+ appendBlocksToDOM(li, node.children, opts);
514
+ }
515
+ return li;
516
+ }
517
+ function renderTableToDOM(node, opts) {
518
+ const table = document.createElement("table");
519
+ let thead = null;
520
+ let tbody = null;
521
+ for (let i = 0; i < node.children.length; i++) {
522
+ const row = node.children[i];
523
+ const tr = document.createElement("tr");
524
+ for (let j = 0; j < row.children.length; j++) {
525
+ const cell = row.children[j];
526
+ const cellEl = document.createElement(row.isHeader ? "th" : "td");
527
+ const align = node.align[j];
528
+ if (align) cellEl.style.textAlign = align;
529
+ appendInlineToDOM(cellEl, resolveInline(cell, opts), opts);
530
+ tr.appendChild(cellEl);
531
+ }
532
+ if (row.isHeader) {
533
+ if (!thead) {
534
+ thead = document.createElement("thead");
535
+ table.appendChild(thead);
536
+ }
537
+ thead.appendChild(tr);
538
+ } else {
539
+ if (!tbody) {
540
+ tbody = document.createElement("tbody");
541
+ table.appendChild(tbody);
542
+ }
543
+ tbody.appendChild(tr);
544
+ }
545
+ }
546
+ return table;
547
+ }
548
+ function appendBlocksToDOM(parent, blocks, opts) {
549
+ for (let i = 0; i < blocks.length; i++) {
550
+ const el = renderBlockToDOM(blocks[i], opts);
551
+ if (el) parent.appendChild(el);
552
+ }
553
+ }
554
+ function appendInlineToDOM(parent, nodes, opts) {
555
+ for (let i = 0; i < nodes.length; i++) {
556
+ const node = nodes[i];
557
+ const el = renderInlineToDOM(node, opts);
558
+ if (el) parent.appendChild(el);
559
+ }
560
+ }
561
+ function renderInlineToDOM(node, opts) {
562
+ switch (node.type) {
563
+ case "text":
564
+ return document.createTextNode(node.value);
565
+ case "emphasis": {
566
+ const em = document.createElement("em");
567
+ appendInlineToDOM(em, node.children, opts);
568
+ return em;
569
+ }
570
+ case "strong": {
571
+ const strong = document.createElement("strong");
572
+ appendInlineToDOM(strong, node.children, opts);
573
+ return strong;
574
+ }
575
+ case "strikethrough": {
576
+ const del = document.createElement("del");
577
+ appendInlineToDOM(del, node.children, opts);
578
+ return del;
579
+ }
580
+ case "inlineCode": {
581
+ const code = document.createElement("code");
582
+ code.textContent = node.value;
583
+ return code;
584
+ }
585
+ case "link": {
586
+ const a = document.createElement("a");
587
+ const safeUrl = opts.sanitize ? sanitizeUrl(node.url) : node.url;
588
+ a.href = encodeUrl(opts.baseUrl ? opts.baseUrl + safeUrl : safeUrl);
589
+ if (node.title) a.title = node.title;
590
+ appendInlineToDOM(a, node.children, opts);
591
+ return a;
592
+ }
593
+ case "image": {
594
+ const img = document.createElement("img");
595
+ const safeSrc = opts.sanitize ? sanitizeUrl(node.url) : node.url;
596
+ img.src = encodeUrl(opts.baseUrl ? opts.baseUrl + safeSrc : safeSrc);
597
+ img.alt = node.alt;
598
+ if (node.title) img.title = node.title;
599
+ return img;
600
+ }
601
+ case "break":
602
+ return document.createElement("br");
603
+ case "softBreak":
604
+ return document.createTextNode("\n");
605
+ case "htmlInline": {
606
+ if (opts.sanitize) return document.createTextNode(node.value);
607
+ const span = document.createElement("span");
608
+ span.innerHTML = node.value;
609
+ return span;
610
+ }
611
+ case "mathInline": {
612
+ const span = document.createElement("span");
613
+ span.className = "math-inline";
614
+ span.textContent = node.value;
615
+ return span;
616
+ }
617
+ case "highlight": {
618
+ const mark = document.createElement("mark");
619
+ appendInlineToDOM(mark, node.children, opts);
620
+ return mark;
621
+ }
622
+ case "superscript": {
623
+ const sup = document.createElement("sup");
624
+ appendInlineToDOM(sup, node.children, opts);
625
+ return sup;
626
+ }
627
+ case "subscript": {
628
+ const sub = document.createElement("sub");
629
+ appendInlineToDOM(sub, node.children, opts);
630
+ return sub;
631
+ }
632
+ case "fontColor": {
633
+ const span = document.createElement("span");
634
+ span.style.color = opts.sanitize ? sanitizeCssValue(node.color) : node.color;
635
+ appendInlineToDOM(span, node.children, opts);
636
+ return span;
637
+ }
638
+ case "fontSize": {
639
+ const span = document.createElement("span");
640
+ const size = /^\d+$/.test(node.size) ? node.size + "px" : node.size;
641
+ span.style.fontSize = opts.sanitize ? sanitizeCssValue(size) : size;
642
+ appendInlineToDOM(span, node.children, opts);
643
+ return span;
644
+ }
645
+ case "fontBgColor": {
646
+ const span = document.createElement("span");
647
+ span.style.backgroundColor = opts.sanitize ? sanitizeCssValue(node.color) : node.color;
648
+ appendInlineToDOM(span, node.children, opts);
649
+ return span;
650
+ }
651
+ case "footnoteReference": {
652
+ const sup = document.createElement("sup");
653
+ const a = document.createElement("a");
654
+ a.href = "#fn-" + node.identifier;
655
+ a.className = "footnote-ref";
656
+ a.textContent = node.label;
657
+ sup.appendChild(a);
658
+ return sup;
659
+ }
660
+ case "autolink": {
661
+ const a = document.createElement("a");
662
+ a.href = node.isEmail ? "mailto:" + node.url : node.url;
663
+ a.textContent = node.url;
664
+ return a;
665
+ }
666
+ case "emoji": {
667
+ const span = document.createElement("span");
668
+ span.className = "emoji";
669
+ span.textContent = node.value || ":" + node.shortcode + ":";
670
+ return span;
671
+ }
672
+ case "ruby": {
673
+ const ruby = document.createElement("ruby");
674
+ ruby.appendChild(document.createTextNode(node.base));
675
+ const rp1 = document.createElement("rp");
676
+ rp1.textContent = "(";
677
+ ruby.appendChild(rp1);
678
+ const rt = document.createElement("rt");
679
+ rt.textContent = node.annotation;
680
+ ruby.appendChild(rt);
681
+ const rp2 = document.createElement("rp");
682
+ rp2.textContent = ")";
683
+ ruby.appendChild(rp2);
684
+ return ruby;
685
+ }
686
+ case "audio": {
687
+ const audio = document.createElement("audio");
688
+ audio.controls = true;
689
+ audio.preload = "metadata";
690
+ audio.src = node.url;
691
+ audio.textContent = node.title || "Audio";
692
+ return audio;
693
+ }
694
+ case "video": {
695
+ const video = document.createElement("video");
696
+ video.controls = true;
697
+ video.preload = "metadata";
698
+ video.src = node.url;
699
+ video.textContent = node.title || "Video";
700
+ return video;
701
+ }
702
+ case "underline": {
703
+ const u = document.createElement("u");
704
+ appendInlineToDOM(u, node.children, opts);
705
+ return u;
706
+ }
707
+ default:
708
+ return null;
709
+ }
710
+ }
711
+ export {
712
+ renderToDOM,
713
+ renderToHtml
714
+ };
715
+ //# sourceMappingURL=index.js.map