@rathkit/rte-core 0.1.0-alpha.0 → 0.1.0-alpha.4

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 (55) hide show
  1. package/dist/dom/render.js +25 -14
  2. package/dist/dom/view.d.ts +5 -3
  3. package/dist/dom/view.js +41 -23
  4. package/dist/edit.js +6 -3
  5. package/dist/engine.d.ts +7 -1
  6. package/dist/engine.js +19 -3
  7. package/dist/export.d.ts +2 -2
  8. package/dist/export.js +22 -6
  9. package/dist/footnotes/index.d.ts +2 -0
  10. package/dist/footnotes/index.js +2 -0
  11. package/dist/footnotes/plugin.d.ts +6 -0
  12. package/dist/footnotes/plugin.js +130 -0
  13. package/dist/footnotes/reconcile.d.ts +4 -0
  14. package/dist/footnotes/reconcile.js +155 -0
  15. package/dist/images/images.js +4 -3
  16. package/dist/images/index.d.ts +5 -1
  17. package/dist/images/index.js +3 -1
  18. package/dist/{dom/imageview.d.ts → images/view.d.ts} +8 -5
  19. package/dist/{dom/imageview.js → images/view.js} +16 -10
  20. package/dist/import.js +55 -18
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +1 -0
  23. package/dist/lists/lists.js +45 -30
  24. package/dist/markdown/detect.d.ts +1 -0
  25. package/dist/markdown/detect.js +81 -0
  26. package/dist/markdown/export.d.ts +10 -0
  27. package/dist/markdown/export.js +252 -0
  28. package/dist/markdown/index.d.ts +5 -0
  29. package/dist/markdown/index.js +4 -0
  30. package/dist/markdown/inline.d.ts +35 -0
  31. package/dist/markdown/inline.js +604 -0
  32. package/dist/markdown/parse.d.ts +4 -0
  33. package/dist/markdown/parse.js +586 -0
  34. package/dist/markdown/plugin.d.ts +20 -0
  35. package/dist/markdown/plugin.js +53 -0
  36. package/dist/model.d.ts +25 -2
  37. package/dist/model.js +2 -0
  38. package/dist/notes.d.ts +6 -0
  39. package/dist/notes.js +49 -0
  40. package/dist/ops.d.ts +6 -1
  41. package/dist/ops.js +5 -4
  42. package/dist/path.d.ts +3 -1
  43. package/dist/path.js +91 -5
  44. package/dist/plugin.d.ts +52 -1
  45. package/dist/standard/index.d.ts +5 -2
  46. package/dist/standard/index.js +6 -4
  47. package/dist/{dom/tableview.d.ts → tables/cells.d.ts} +6 -5
  48. package/dist/{dom/tableview.js → tables/cells.js} +13 -9
  49. package/dist/{dom/tablegrips.d.ts → tables/grips.d.ts} +5 -4
  50. package/dist/{dom/tablegrips.js → tables/grips.js} +8 -7
  51. package/dist/tables/index.d.ts +5 -1
  52. package/dist/tables/index.js +3 -1
  53. package/dist/tables/view.d.ts +2 -0
  54. package/dist/tables/view.js +15 -0
  55. package/package.json +23 -1
@@ -0,0 +1,604 @@
1
+ import { decodeEntities } from "../html/entities.js";
2
+ import { checkImageSrc, safeUrl } from "../import.js";
3
+ import { normalizeInline } from "../model.js";
4
+ export const NOTE_LABEL = /^[\p{L}\p{N}_.-]{1,64}$/u;
5
+ export const refLabel = (label) => label.trim().replace(/\s+/g, " ").toLowerCase();
6
+ const DEFAULT_SCHEMES = ["http", "https", "mailto", "tel"];
7
+ const MAX_DESTINATION = 2000;
8
+ const MAX_TITLE = 1000;
9
+ const MAX_PAREN_DEPTH = 32;
10
+ const MAX_BRACKETS = 64;
11
+ const HTML_TAGS = {
12
+ u: "underline", ins: "underline", sup: "sup", sub: "sub", b: "bold", strong: "bold", i: "italic", em: "italic",
13
+ s: "strike", del: "strike", strike: "strike", kbd: "code", code: "code",
14
+ };
15
+ const isSpace = (ch) => ch === "" || /\s/u.test(ch);
16
+ const isPunct = (ch) => ch !== "" && /[\p{P}\p{S}]/u.test(ch);
17
+ const isAsciiPunct = (ch) => ch.length === 1 && "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".includes(ch);
18
+ const before = (s, i) => {
19
+ if (i <= 0)
20
+ return "";
21
+ const low = s.charCodeAt(i - 1);
22
+ if (low >= 0xdc00 && low <= 0xdfff && i >= 2)
23
+ return s.slice(i - 2, i);
24
+ return s.charAt(i - 1);
25
+ };
26
+ const after = (s, i) => {
27
+ if (i >= s.length)
28
+ return "";
29
+ const high = s.charCodeAt(i);
30
+ if (high >= 0xd800 && high <= 0xdbff && i + 1 < s.length)
31
+ return s.slice(i, i + 2);
32
+ return s.charAt(i);
33
+ };
34
+ const MARK_ORDER = ["link", "bold", "italic", "underline", "strike", "code", "sup", "sub"];
35
+ export function parseInline(src, options = {}) {
36
+ const schemes = new Set(options.linkSchemes ?? DEFAULT_SCHEMES);
37
+ const pieces = [];
38
+ const brackets = [];
39
+ let head = null;
40
+ let tail = null;
41
+ let buffer = "";
42
+ const flush = () => {
43
+ if (buffer !== "") {
44
+ pieces.push({ k: "t", s: buffer });
45
+ buffer = "";
46
+ }
47
+ };
48
+ const unlink = (d) => {
49
+ if (d.prev)
50
+ d.prev.next = d.next;
51
+ else
52
+ head = d.next;
53
+ if (d.next)
54
+ d.next.prev = d.prev;
55
+ else
56
+ tail = d.prev;
57
+ };
58
+ const processEmphasis = (bottom) => {
59
+ const floors = new Map();
60
+ let closer = bottom ? bottom.next : head;
61
+ while (closer) {
62
+ if (!closer.close) {
63
+ closer = closer.next;
64
+ continue;
65
+ }
66
+ const key = `${closer.ch}${closer.n % 3}${closer.open ? 1 : 0}`;
67
+ const floor = floors.has(key) ? floors.get(key) ?? null : bottom;
68
+ let opener = closer.prev;
69
+ let found = null;
70
+ while (opener && opener !== bottom && opener !== floor) {
71
+ if (opener.ch === closer.ch && opener.open) {
72
+ const tilde = closer.ch === "~";
73
+ const odd = (opener.close || closer.open) && (opener.n + closer.n) % 3 === 0 && !(opener.n % 3 === 0 && closer.n % 3 === 0);
74
+ if (tilde ? opener.n === closer.n : !odd) {
75
+ found = opener;
76
+ break;
77
+ }
78
+ }
79
+ opener = opener.prev;
80
+ }
81
+ if (!found) {
82
+ floors.set(key, closer.prev);
83
+ const next = closer.next;
84
+ if (!closer.open)
85
+ unlink(closer);
86
+ closer = next;
87
+ continue;
88
+ }
89
+ const tilde = closer.ch === "~";
90
+ const use = tilde ? closer.n : closer.n >= 2 && found.n >= 2 ? 2 : 1;
91
+ const mark = tilde ? "strike" : use === 2 ? "bold" : "italic";
92
+ found.n -= use;
93
+ closer.n -= use;
94
+ found.opens.push(mark);
95
+ closer.closes.push(mark);
96
+ found.next = closer;
97
+ closer.prev = found;
98
+ if (found.n === 0)
99
+ unlink(found);
100
+ if (closer.n === 0) {
101
+ const next = closer.next;
102
+ unlink(closer);
103
+ closer = next;
104
+ }
105
+ }
106
+ if (bottom) {
107
+ bottom.next = null;
108
+ tail = bottom;
109
+ }
110
+ else {
111
+ head = null;
112
+ tail = null;
113
+ }
114
+ };
115
+ const linkTail = (p) => {
116
+ let i = p + 1;
117
+ const skip = () => { while (i < src.length && (src[i] === " " || src[i] === "\t" || src[i] === "\n"))
118
+ i++; };
119
+ skip();
120
+ let raw = "";
121
+ if (src[i] === "<") {
122
+ i++;
123
+ const from = i;
124
+ while (i < src.length && src[i] !== ">" && src[i] !== "\n" && src[i] !== "<" && i - from < MAX_DESTINATION)
125
+ i++;
126
+ if (src[i] !== ">")
127
+ return undefined;
128
+ raw = src.slice(from, i);
129
+ i++;
130
+ }
131
+ else {
132
+ const from = i;
133
+ let depth = 0;
134
+ while (i < src.length && i - from < MAX_DESTINATION) {
135
+ const c = src[i];
136
+ if (c === "\\" && i + 1 < src.length && isAsciiPunct(src[i + 1])) {
137
+ i += 2;
138
+ continue;
139
+ }
140
+ if (c === " " || c === "\t" || c === "\n" || c < " ")
141
+ break;
142
+ if (c === "(") {
143
+ if (++depth > MAX_PAREN_DEPTH)
144
+ return undefined;
145
+ }
146
+ else if (c === ")") {
147
+ if (depth === 0)
148
+ break;
149
+ depth--;
150
+ }
151
+ i++;
152
+ }
153
+ if (depth !== 0)
154
+ return undefined;
155
+ raw = src.slice(from, i);
156
+ }
157
+ skip();
158
+ const quote = src[i];
159
+ if (quote === '"' || quote === "'" || quote === "(") {
160
+ const closing = quote === "(" ? ")" : quote;
161
+ const from = ++i;
162
+ while (i < src.length && src[i] !== closing && i - from < MAX_TITLE) {
163
+ if (src[i] === "\\")
164
+ i++;
165
+ i++;
166
+ }
167
+ if (src[i] !== closing)
168
+ return undefined;
169
+ i++;
170
+ skip();
171
+ }
172
+ if (src[i] !== ")")
173
+ return undefined;
174
+ return { dest: unescape(raw), end: i + 1 };
175
+ };
176
+ let i = 0;
177
+ while (i < src.length) {
178
+ const c = src[i];
179
+ if (c === "\\") {
180
+ const n = src[i + 1] ?? "";
181
+ if (n === "\n") {
182
+ flush();
183
+ pieces.push({ k: "br" });
184
+ i += 2;
185
+ while (src[i] === " " || src[i] === "\t")
186
+ i++;
187
+ continue;
188
+ }
189
+ if (isAsciiPunct(n)) {
190
+ buffer += n;
191
+ i += 2;
192
+ continue;
193
+ }
194
+ buffer += c;
195
+ i++;
196
+ continue;
197
+ }
198
+ if (c === "\n") {
199
+ let spaces = 0;
200
+ const kept = buffer.trimEnd().length;
201
+ spaces = buffer.length - kept;
202
+ buffer = buffer.slice(0, kept);
203
+ if (spaces >= 2) {
204
+ flush();
205
+ pieces.push({ k: "br" });
206
+ }
207
+ else
208
+ buffer += " ";
209
+ i++;
210
+ while (src[i] === " " || src[i] === "\t")
211
+ i++;
212
+ continue;
213
+ }
214
+ if (c === "&") {
215
+ const m = /^&(?:#\d{1,7}|#[xX][0-9a-fA-F]{1,6}|[A-Za-z][A-Za-z0-9]{1,31});/.exec(src.slice(i, i + 40));
216
+ if (m) {
217
+ buffer += decodeEntities(m[0]);
218
+ i += m[0].length;
219
+ continue;
220
+ }
221
+ buffer += c;
222
+ i++;
223
+ continue;
224
+ }
225
+ if (c === "`") {
226
+ let run = 1;
227
+ while (src[i + run] === "`")
228
+ run++;
229
+ const end = closingTicks(src, i + run, run);
230
+ if (end === -1) {
231
+ buffer += "`".repeat(run);
232
+ i += run;
233
+ continue;
234
+ }
235
+ flush();
236
+ let body = src.slice(i + run, end).replace(/\n/g, " ");
237
+ if (body.length >= 2 && body.startsWith(" ") && body.endsWith(" ") && body.trim() !== "")
238
+ body = body.slice(1, -1);
239
+ pieces.push({ k: "code", s: body });
240
+ i = end + run;
241
+ continue;
242
+ }
243
+ if (c === "*" || c === "_" || c === "~") {
244
+ let run = 1;
245
+ while (src[i + run] === c)
246
+ run++;
247
+ if (c === "~" && run > 2) {
248
+ buffer += c.repeat(run);
249
+ i += run;
250
+ continue;
251
+ }
252
+ const prev = before(src, i);
253
+ const next = after(src, i + run);
254
+ const left = !isSpace(next) && (!isPunct(next) || isSpace(prev) || isPunct(prev));
255
+ const right = !isSpace(prev) && (!isPunct(prev) || isSpace(next) || isPunct(next));
256
+ const open = c === "_" ? left && (!right || isPunct(prev)) : left;
257
+ const close = c === "_" ? right && (!left || isPunct(next)) : right;
258
+ flush();
259
+ const d = { k: "d", ch: c, n: run, open, close, opens: [], closes: [], prev: tail, next: null };
260
+ if (tail)
261
+ tail.next = d;
262
+ else
263
+ head = d;
264
+ tail = d;
265
+ pieces.push(d);
266
+ i += run;
267
+ continue;
268
+ }
269
+ if (c === "[" || (c === "!" && src[i + 1] === "[")) {
270
+ const image = c === "!";
271
+ flush();
272
+ if (brackets.length >= MAX_BRACKETS) {
273
+ buffer += image ? "![" : "[";
274
+ i += image ? 2 : 1;
275
+ continue;
276
+ }
277
+ const b = { k: "lb", image, active: true, index: pieces.length, textStart: i + (image ? 2 : 1), delimBefore: tail };
278
+ pieces.push(b);
279
+ brackets.push(b);
280
+ i += image ? 2 : 1;
281
+ continue;
282
+ }
283
+ if (c === "]") {
284
+ const top = brackets.pop();
285
+ if (!top) {
286
+ buffer += c;
287
+ i++;
288
+ continue;
289
+ }
290
+ if (!top.active) {
291
+ flush();
292
+ asText(top);
293
+ buffer += c;
294
+ i++;
295
+ continue;
296
+ }
297
+ const label = !top.image && src[top.textStart] === "^" ? src.slice(top.textStart + 1, i) : "";
298
+ const noteId = options.notes && NOTE_LABEL.test(label) ? options.notes.use(refLabel(label)) : undefined;
299
+ if (noteId !== undefined) {
300
+ flush();
301
+ processEmphasis(top.delimBefore);
302
+ for (let k = top.index + 1; k < pieces.length; k++)
303
+ pieces[k].dead = true;
304
+ Object.assign(top, { k: "note", id: noteId });
305
+ i++;
306
+ continue;
307
+ }
308
+ let tailInfo = src[i + 1] === "(" ? linkTail(i + 1) : undefined;
309
+ if (!tailInfo && options.refs && options.refs.size > 0)
310
+ tailInfo = referenceTail(src, i, top.textStart, options.refs);
311
+ if (!tailInfo) {
312
+ flush();
313
+ asText(top);
314
+ buffer += c;
315
+ i++;
316
+ continue;
317
+ }
318
+ flush();
319
+ processEmphasis(top.delimBefore);
320
+ if (top.image) {
321
+ let alt = "";
322
+ for (let k = top.index + 1; k < pieces.length; k++) {
323
+ const p = pieces[k];
324
+ if (!p.dead) {
325
+ if (p.k === "t" || p.k === "code")
326
+ alt += p.s;
327
+ else if (p.k === "img")
328
+ alt += p.alt;
329
+ else if (p.k === "d")
330
+ alt += p.ch.repeat(p.n);
331
+ }
332
+ p.dead = true;
333
+ }
334
+ const safe = checkImageSrc(decodeEntities(tailInfo.dest), options.maxDataImageLength, options.sanitizeSvg);
335
+ const img = top;
336
+ if (safe) {
337
+ Object.assign(img, { k: "img", src: safe, alt });
338
+ }
339
+ else
340
+ Object.assign(img, { k: "t", s: alt });
341
+ }
342
+ else {
343
+ const href = safeUrl(decodeEntities(tailInfo.dest), schemes);
344
+ Object.assign(top, { k: "lopen", href });
345
+ pieces.push({ k: "lclose" });
346
+ for (const earlier of brackets)
347
+ if (!earlier.image)
348
+ earlier.active = false;
349
+ }
350
+ i = tailInfo.end;
351
+ continue;
352
+ }
353
+ if (c === "<") {
354
+ const auto = autolink(src, i, schemes);
355
+ if (auto) {
356
+ flush();
357
+ pieces.push({ k: "lopen", href: auto.href }, { k: "t", s: auto.text }, { k: "lclose" });
358
+ i = auto.end;
359
+ continue;
360
+ }
361
+ const tag = htmlTag(src, i);
362
+ if (tag) {
363
+ flush();
364
+ if (tag.mark === "br")
365
+ pieces.push({ k: "br" });
366
+ else
367
+ pieces.push({ k: "tag", mark: tag.mark, close: tag.close, raw: src.slice(i, tag.end) });
368
+ i = tag.end;
369
+ continue;
370
+ }
371
+ buffer += c;
372
+ i++;
373
+ continue;
374
+ }
375
+ if ((c === "h" || c === "w") && brackets.length === 0 && !/[A-Za-z0-9]/.test(before(src, i))) {
376
+ const bare = bareUrl(src, i, schemes);
377
+ if (bare) {
378
+ flush();
379
+ pieces.push({ k: "lopen", href: bare.href }, { k: "t", s: bare.text }, { k: "lclose" });
380
+ i = bare.end;
381
+ continue;
382
+ }
383
+ }
384
+ buffer += c;
385
+ i++;
386
+ }
387
+ flush();
388
+ processEmphasis(null);
389
+ for (const b of brackets)
390
+ asText(b);
391
+ pairTags(pieces);
392
+ return render(pieces);
393
+ }
394
+ function referenceTail(src, close, textStart, refs) {
395
+ const text = src.slice(textStart, close);
396
+ if (text.length > 999)
397
+ return undefined;
398
+ let label = text;
399
+ let end = close + 1;
400
+ if (src[close + 1] === "[") {
401
+ let k = close + 2;
402
+ while (k < src.length && k - close < 1002 && src[k] !== "]" && src[k] !== "[")
403
+ k++;
404
+ if (src[k] !== "]")
405
+ return undefined;
406
+ const given = src.slice(close + 2, k);
407
+ if (given !== "")
408
+ label = given;
409
+ end = k + 1;
410
+ }
411
+ if (label.trim() === "")
412
+ return undefined;
413
+ const def = refs.get(refLabel(label));
414
+ return def ? { dest: def.dest, end } : undefined;
415
+ }
416
+ function htmlTag(src, at) {
417
+ let i = at + 1;
418
+ const close = src[i] === "/";
419
+ if (close)
420
+ i++;
421
+ const from = i;
422
+ while (i < src.length && i - from < 8 && /[A-Za-z]/.test(src.charAt(i)))
423
+ i++;
424
+ const name = src.slice(from, i).toLowerCase();
425
+ const mark = name === "br" ? "br" : HTML_TAGS[name];
426
+ if (!mark || (mark === "br" && close))
427
+ return undefined;
428
+ while (src[i] === " " || src[i] === "\t")
429
+ i++;
430
+ if (mark === "br" && src[i] === "/")
431
+ i++;
432
+ if (src[i] !== ">")
433
+ return undefined;
434
+ return { mark, close, end: i + 1 };
435
+ }
436
+ function pairTags(pieces) {
437
+ const open = new Map();
438
+ for (const p of pieces) {
439
+ if (p.dead || p.k !== "tag")
440
+ continue;
441
+ if (!p.close) {
442
+ const list = open.get(p.mark) ?? [];
443
+ list.push(p);
444
+ open.set(p.mark, list);
445
+ continue;
446
+ }
447
+ const mate = open.get(p.mark)?.pop();
448
+ if (mate && mate.k === "tag") {
449
+ mate.paired = true;
450
+ p.paired = true;
451
+ }
452
+ }
453
+ }
454
+ function asText(b) {
455
+ Object.assign(b, { k: "t", s: b.image ? "![" : "[" });
456
+ }
457
+ function closingTicks(src, from, len) {
458
+ let i = from;
459
+ while (i < src.length) {
460
+ const at = src.indexOf("`", i);
461
+ if (at === -1)
462
+ return -1;
463
+ let run = 1;
464
+ while (src[at + run] === "`")
465
+ run++;
466
+ if (run === len)
467
+ return at;
468
+ i = at + run;
469
+ }
470
+ return -1;
471
+ }
472
+ export function unescape(raw) {
473
+ let out = "";
474
+ for (let i = 0; i < raw.length; i++) {
475
+ const c = raw[i];
476
+ if (c === "\\" && isAsciiPunct(raw[i + 1] ?? "")) {
477
+ out += raw[i + 1];
478
+ i++;
479
+ }
480
+ else
481
+ out += c;
482
+ }
483
+ return out;
484
+ }
485
+ function autolink(src, at, schemes) {
486
+ let i = at + 1;
487
+ const limit = Math.min(src.length, at + MAX_DESTINATION);
488
+ while (i < limit && src[i] !== ">" && src[i] !== "<" && src[i] !== " " && src[i] !== "\n" && src[i] !== "\t")
489
+ i++;
490
+ if (src[i] !== ">" || i === at + 1)
491
+ return undefined;
492
+ const body = src.slice(at + 1, i);
493
+ const scheme = /^([A-Za-z][A-Za-z0-9+.-]{1,31}):/.exec(body.slice(0, 40));
494
+ if (scheme)
495
+ return { href: safeUrl(body, schemes), text: body, end: i + 1 };
496
+ const email = body.indexOf("@");
497
+ if (email > 0 && email === body.lastIndexOf("@") && body.indexOf(".", email) > email + 1 && !body.endsWith("."))
498
+ return { href: safeUrl(`mailto:${body}`, schemes), text: body, end: i + 1 };
499
+ return undefined;
500
+ }
501
+ function bareUrl(src, at, schemes) {
502
+ const head = src.slice(at, at + 8).toLowerCase();
503
+ const prefix = head.startsWith("https://") ? 8 : head.startsWith("http://") ? 7 : head.startsWith("www.") ? 4 : 0;
504
+ if (prefix === 0)
505
+ return undefined;
506
+ let end = at + prefix;
507
+ while (end < src.length && end - at < MAX_DESTINATION && !/[\s<]/.test(src.charAt(end)))
508
+ end++;
509
+ let trimming = true;
510
+ while (trimming && end > at + prefix) {
511
+ const last = src.charAt(end - 1);
512
+ if ("?!.,:*_~'\";".includes(last))
513
+ end--;
514
+ else if (last === ")") {
515
+ let open = 0, close = 0;
516
+ for (let k = at; k < end; k++) {
517
+ const ch = src.charAt(k);
518
+ if (ch === "(")
519
+ open++;
520
+ else if (ch === ")")
521
+ close++;
522
+ }
523
+ if (close > open)
524
+ end--;
525
+ else
526
+ trimming = false;
527
+ }
528
+ else
529
+ trimming = false;
530
+ }
531
+ if (end <= at + prefix)
532
+ return undefined;
533
+ const text = src.slice(at, end);
534
+ return { href: safeUrl(prefix === 4 ? `https://${text}` : text, schemes), text, end };
535
+ }
536
+ function render(pieces) {
537
+ const out = [];
538
+ const counts = { bold: 0, italic: 0, strike: 0, underline: 0, sup: 0, sub: 0, code: 0 };
539
+ let link;
540
+ const marks = (code) => {
541
+ const list = [];
542
+ for (const type of MARK_ORDER) {
543
+ if (type === "link") {
544
+ if (link !== undefined)
545
+ list.push({ type: "link", href: link });
546
+ }
547
+ else if (type === "code") {
548
+ if (code || counts.code > 0)
549
+ list.push({ type: "code" });
550
+ }
551
+ else if (counts[type] > 0)
552
+ list.push({ type });
553
+ }
554
+ return list;
555
+ };
556
+ const emit = (text, code = false) => { if (text !== "")
557
+ out.push({ type: "text", text, marks: marks(code) }); };
558
+ for (const p of pieces) {
559
+ if (p.dead)
560
+ continue;
561
+ switch (p.k) {
562
+ case "t":
563
+ emit(p.s);
564
+ break;
565
+ case "code":
566
+ emit(p.s, true);
567
+ break;
568
+ case "br":
569
+ out.push({ type: "br" });
570
+ break;
571
+ case "img":
572
+ out.push({ type: "image", src: p.src, ...(p.alt ? { alt: p.alt } : {}) });
573
+ break;
574
+ case "lopen":
575
+ link = p.href;
576
+ break;
577
+ case "lclose":
578
+ link = undefined;
579
+ break;
580
+ case "d":
581
+ for (const m of p.closes)
582
+ counts[m]--;
583
+ emit(p.ch.repeat(p.n));
584
+ for (const m of p.opens)
585
+ counts[m]++;
586
+ break;
587
+ case "tag":
588
+ if (!p.paired)
589
+ emit(p.raw);
590
+ else
591
+ counts[p.mark] += p.close ? -1 : 1;
592
+ break;
593
+ case "lb":
594
+ emit(p.image ? "![" : "[");
595
+ break;
596
+ case "note":
597
+ out.push({ type: "note", id: p.id });
598
+ break;
599
+ }
600
+ }
601
+ while (out[out.length - 1]?.type === "br")
602
+ out.pop();
603
+ return normalizeInline(out);
604
+ }
@@ -0,0 +1,4 @@
1
+ import { type Block } from "../model.ts";
2
+ import { type MarkdownOptions } from "./inline.ts";
3
+ /** Reads Markdown into blocks ready to insert. Never throws; anything it does not understand stays text. */
4
+ export declare function parseMarkdown(source: string, options?: MarkdownOptions): Block[];