stream-markdown-parser 0.0.47 → 0.0.49

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 CHANGED
@@ -6752,7 +6752,7 @@ function applyContainers(md) {
6752
6752
  const startPos = s.bMarks[startLine] + s.tShift[startLine];
6753
6753
  const lineMax = s.eMarks[startLine];
6754
6754
  const line = s.src.slice(startPos, lineMax);
6755
- const nameMatch = line.match(/^:::(\S+)/);
6755
+ const nameMatch = line.match(/^:::\s*(\S+)/);
6756
6756
  if (!nameMatch) return false;
6757
6757
  const name = nameMatch[1];
6758
6758
  if (!name.trim()) return false;
@@ -6800,13 +6800,12 @@ function applyContainers(md) {
6800
6800
  contentLines.push(s.src.slice(sPos, ePos));
6801
6801
  }
6802
6802
  if (contentLines.some((line$1) => line$1.trim().length > 0)) {
6803
- s.push("paragraph_open", "p", 1);
6804
- const inlineToken = s.push("inline", "", 0);
6805
- inlineToken.content = contentLines.join("\n");
6806
- inlineToken.map = [startLine + 1, nextLine];
6807
- inlineToken.children = [];
6808
- s.md.inline.parse(inlineToken.content, s.md, s.env, inlineToken.children);
6809
- s.push("paragraph_close", "p", -1);
6803
+ let innerSrc = contentLines.join("\n");
6804
+ if (!innerSrc.endsWith("\n")) innerSrc += "\n";
6805
+ if (!innerSrc.endsWith("\n\n")) innerSrc += "\n";
6806
+ const innerTokens = [];
6807
+ s.md.block.parse(innerSrc, s.md, s.env, innerTokens);
6808
+ s.tokens.push(...innerTokens);
6810
6809
  }
6811
6810
  s.push("vmr_container_close", "div", -1);
6812
6811
  s.line = nextLine + 1;
@@ -8499,6 +8498,7 @@ function applyMath(md, mathOpts) {
8499
8498
  const mathInline = (state, silent) => {
8500
8499
  const s = state;
8501
8500
  const strict = !!mathOpts?.strictDelimiters;
8501
+ const allowLoading = !s?.env?.__markstreamFinal;
8502
8502
  if (/^\*[^*]+/.test(s.src)) return false;
8503
8503
  const delimiters = [["$", "$"], ["\\(", "\\)"]];
8504
8504
  let searchPos = 0;
@@ -8544,7 +8544,7 @@ function applyMath(md, mathOpts) {
8544
8544
  continue;
8545
8545
  }
8546
8546
  if (endIdx === -1) {
8547
- if (!strict && isMathLike(content$1) && !content$1.includes("`")) {
8547
+ if (allowLoading && !strict && isMathLike(content$1) && !content$1.includes("`")) {
8548
8548
  searchPos = index + open.length;
8549
8549
  foundAny = true;
8550
8550
  if (!silent) {
@@ -8585,7 +8585,8 @@ function applyMath(md, mathOpts) {
8585
8585
  }
8586
8586
  const content = src.slice(index + open.length, endIdx);
8587
8587
  const hasBacktick = content.includes("`");
8588
- if (strict ? hasBacktick : hasBacktick || !(open === "$") && !isMathLike(content)) {
8588
+ const isEmpty = !content || !content.trim();
8589
+ if (strict ? hasBacktick || isEmpty : hasBacktick || isEmpty || !(open === "$") && !isMathLike(content)) {
8589
8590
  searchPos = endIdx + close.length;
8590
8591
  const text$1 = src.slice(s.pos, searchPos);
8591
8592
  if (!s.pending) pushText(text$1);
@@ -8654,6 +8655,7 @@ function applyMath(md, mathOpts) {
8654
8655
  };
8655
8656
  const mathBlock = (state, startLine, endLine, silent) => {
8656
8657
  const s = state;
8658
+ const allowLoading = !s?.env?.__markstreamFinal;
8657
8659
  const strict = mathOpts?.strictDelimiters;
8658
8660
  const delimiters = strict ? [["\\[", "\\]"], ["$$", "$$"]] : [
8659
8661
  ["\\[", "\\]"],
@@ -8761,7 +8763,7 @@ function applyMath(md, mathOpts) {
8761
8763
  content += (content ? "\n" : "") + currentLine;
8762
8764
  }
8763
8765
  }
8764
- if (strict && !found) return false;
8766
+ if ((!allowLoading || strict) && !found) return false;
8765
8767
  if (!(openDelim === "[" ? isPlainBracketMathLike(content) : isMathLike(content))) return false;
8766
8768
  const token = s.push("math_block", "math", 0);
8767
8769
  token.content = normalizeStandaloneBackslashT(content);
@@ -10273,6 +10275,249 @@ function normalizeSingleLinkResult(raw, nodes) {
10273
10275
  return nodes;
10274
10276
  }
10275
10277
 
10278
+ //#endregion
10279
+ //#region src/parser/node-parsers/list-parser.ts
10280
+ function parseList(tokens, index, options) {
10281
+ const token = tokens[index];
10282
+ const listItems = [];
10283
+ let j = index + 1;
10284
+ while (j < tokens.length && tokens[j].type !== "bullet_list_close" && tokens[j].type !== "ordered_list_close") if (tokens[j].type === "list_item_open") {
10285
+ const itemChildren = [];
10286
+ let k = j + 1;
10287
+ while (k < tokens.length && tokens[k].type !== "list_item_close") if (tokens[k].type === "paragraph_open") {
10288
+ const contentToken = tokens[k + 1];
10289
+ const preToken = tokens[k - 1];
10290
+ const contentStr = String(contentToken.content ?? "");
10291
+ if (/\n\d+$/.test(contentStr)) {
10292
+ contentToken.content = contentStr.replace(/\n\d+$/, "");
10293
+ contentToken.children?.splice(-1, 1);
10294
+ }
10295
+ itemChildren.push({
10296
+ type: "paragraph",
10297
+ children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), preToken, {
10298
+ requireClosingStrong: options?.requireClosingStrong,
10299
+ customHtmlTags: options?.customHtmlTags
10300
+ }),
10301
+ raw: String(contentToken.content ?? "")
10302
+ });
10303
+ k += 3;
10304
+ } else if (tokens[k].type === "blockquote_open") {
10305
+ const [blockquoteNode, newIndex] = parseBlockquote(tokens, k, options);
10306
+ itemChildren.push(blockquoteNode);
10307
+ k = newIndex;
10308
+ } else if (tokens[k].type === "bullet_list_open" || tokens[k].type === "ordered_list_open") {
10309
+ const [nestedListNode, newIndex] = parseList(tokens, k, options);
10310
+ itemChildren.push(nestedListNode);
10311
+ k = newIndex;
10312
+ } else {
10313
+ const handled = parseCommonBlockToken(tokens, k, options, containerTokenHandlers);
10314
+ if (handled) {
10315
+ itemChildren.push(handled[0]);
10316
+ k = handled[1];
10317
+ } else k += 1;
10318
+ }
10319
+ listItems.push({
10320
+ type: "list_item",
10321
+ children: itemChildren,
10322
+ raw: itemChildren.map((child) => child.raw).join("")
10323
+ });
10324
+ j = k + 1;
10325
+ } else j += 1;
10326
+ return [{
10327
+ type: "list",
10328
+ ordered: token.type === "ordered_list_open",
10329
+ start: (() => {
10330
+ if (token.attrs && token.attrs.length) {
10331
+ const found = token.attrs.find((a) => a[0] === "start");
10332
+ if (found) {
10333
+ const parsed = Number(found[1]);
10334
+ return Number.isFinite(parsed) && parsed !== 0 ? parsed : 1;
10335
+ }
10336
+ }
10337
+ })(),
10338
+ items: listItems,
10339
+ raw: listItems.map((item) => item.raw).join("\n")
10340
+ }, j + 1];
10341
+ }
10342
+
10343
+ //#endregion
10344
+ //#region src/parser/node-parsers/admonition-parser.ts
10345
+ function parseAdmonition(tokens, index, match, options) {
10346
+ const kind = String(match[1] ?? "note");
10347
+ const title = String(match[2] ?? kind.charAt(0).toUpperCase() + kind.slice(1));
10348
+ const admonitionChildren = [];
10349
+ let j = index + 1;
10350
+ while (j < tokens.length && tokens[j].type !== "container_close") if (tokens[j].type === "paragraph_open") {
10351
+ const contentToken = tokens[j + 1];
10352
+ if (contentToken) admonitionChildren.push({
10353
+ type: "paragraph",
10354
+ children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
10355
+ requireClosingStrong: options?.requireClosingStrong,
10356
+ customHtmlTags: options?.customHtmlTags
10357
+ }),
10358
+ raw: String(contentToken.content ?? "")
10359
+ });
10360
+ j += 3;
10361
+ } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
10362
+ const [listNode, newIndex] = parseList(tokens, j, options);
10363
+ admonitionChildren.push(listNode);
10364
+ j = newIndex;
10365
+ } else if (tokens[j].type === "blockquote_open") {
10366
+ const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
10367
+ admonitionChildren.push(blockquoteNode);
10368
+ j = newIndex;
10369
+ } else {
10370
+ const handled = parseBasicBlockToken(tokens, j, options);
10371
+ if (handled) {
10372
+ admonitionChildren.push(handled[0]);
10373
+ j = handled[1];
10374
+ } else j++;
10375
+ }
10376
+ return [{
10377
+ type: "admonition",
10378
+ kind,
10379
+ title,
10380
+ children: admonitionChildren,
10381
+ raw: `:::${kind} ${title}\n${admonitionChildren.map((child) => child.raw).join("\n")}\n:::`
10382
+ }, j + 1];
10383
+ }
10384
+
10385
+ //#endregion
10386
+ //#region src/parser/node-parsers/container-parser.ts
10387
+ function parseContainer(tokens, index, options) {
10388
+ const openToken = tokens[index];
10389
+ let kind = "note";
10390
+ let title = "";
10391
+ const typeMatch = openToken.type.match(/^container_(\w+)_open$/);
10392
+ if (typeMatch) {
10393
+ kind = typeMatch[1];
10394
+ const info = String(openToken.info ?? "").trim();
10395
+ if (info && !info.startsWith(":::")) {
10396
+ const maybe = info.replace(/* @__PURE__ */ new RegExp(`^${kind}`), "").trim();
10397
+ if (maybe) title = maybe;
10398
+ }
10399
+ } else {
10400
+ const info = String(openToken.info ?? "").trim();
10401
+ const match = /^:{1,3}\s*(warning|info|note|tip|danger|caution)\s*(.*)$/i.exec(info);
10402
+ if (match) {
10403
+ kind = match[1];
10404
+ title = String(match[2] ?? "");
10405
+ }
10406
+ }
10407
+ if (!title) title = kind.charAt(0).toUpperCase() + kind.slice(1);
10408
+ const children = [];
10409
+ let j = index + 1;
10410
+ const closeType = /* @__PURE__ */ new RegExp(`^container_${kind}_close$`);
10411
+ while (j < tokens.length && tokens[j].type !== "container_close" && !closeType.test(tokens[j].type)) if (tokens[j].type === "paragraph_open") {
10412
+ const contentToken = tokens[j + 1];
10413
+ if (contentToken) {
10414
+ const childrenArr = contentToken.children || [];
10415
+ let i = -1;
10416
+ for (let k = childrenArr.length - 1; k >= 0; k--) {
10417
+ const t = childrenArr[k];
10418
+ if (t.type === "text" && /:+/.test(t.content)) {
10419
+ i = k;
10420
+ break;
10421
+ }
10422
+ }
10423
+ const _children = i !== -1 ? childrenArr.slice(0, i) : childrenArr;
10424
+ children.push({
10425
+ type: "paragraph",
10426
+ children: parseInlineTokens(_children || [], void 0, void 0, {
10427
+ requireClosingStrong: options?.requireClosingStrong,
10428
+ customHtmlTags: options?.customHtmlTags
10429
+ }),
10430
+ raw: String(contentToken.content ?? "").replace(/\n:+$/, "").replace(/\n\s*:::\s*$/, "")
10431
+ });
10432
+ }
10433
+ j += 3;
10434
+ } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
10435
+ const [listNode, newIndex] = parseList(tokens, j, options);
10436
+ children.push(listNode);
10437
+ j = newIndex;
10438
+ } else if (tokens[j].type === "blockquote_open") {
10439
+ const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
10440
+ children.push(blockquoteNode);
10441
+ j = newIndex;
10442
+ } else {
10443
+ const handled = parseBasicBlockToken(tokens, j, options);
10444
+ if (handled) {
10445
+ children.push(handled[0]);
10446
+ j = handled[1];
10447
+ } else j++;
10448
+ }
10449
+ return [{
10450
+ type: "admonition",
10451
+ kind,
10452
+ title,
10453
+ children,
10454
+ raw: `:::${kind} ${title}\n${children.map((c) => c.raw).join("\n")}\n:::`
10455
+ }, j + 1];
10456
+ }
10457
+
10458
+ //#endregion
10459
+ //#region src/parser/node-parsers/container-token-handlers.ts
10460
+ const CONTAINER_REGEX = /^::: ?(warning|info|note|tip|danger|caution|error) ?(.*)$/;
10461
+ function handleContainerOpen(tokens, index, options) {
10462
+ const token = tokens[index];
10463
+ if (token.type !== "container_open") return null;
10464
+ const match = CONTAINER_REGEX.exec(String(token.info ?? ""));
10465
+ if (!match) return null;
10466
+ return parseAdmonition(tokens, index, match, options);
10467
+ }
10468
+ const containerTokenHandlers = {
10469
+ parseContainer: (tokens, index, options) => parseContainer(tokens, index, options),
10470
+ matchAdmonition: handleContainerOpen
10471
+ };
10472
+
10473
+ //#endregion
10474
+ //#region src/parser/node-parsers/blockquote-parser.ts
10475
+ function parseBlockquote(tokens, index, options) {
10476
+ const blockquoteChildren = [];
10477
+ let j = index + 1;
10478
+ while (j < tokens.length && tokens[j].type !== "blockquote_close") switch (tokens[j].type) {
10479
+ case "paragraph_open": {
10480
+ const contentToken = tokens[j + 1];
10481
+ blockquoteChildren.push({
10482
+ type: "paragraph",
10483
+ children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
10484
+ requireClosingStrong: options?.requireClosingStrong,
10485
+ customHtmlTags: options?.customHtmlTags
10486
+ }),
10487
+ raw: String(contentToken.content ?? "")
10488
+ });
10489
+ j += 3;
10490
+ break;
10491
+ }
10492
+ case "bullet_list_open":
10493
+ case "ordered_list_open": {
10494
+ const [listNode, newIndex] = parseList(tokens, j, options);
10495
+ blockquoteChildren.push(listNode);
10496
+ j = newIndex;
10497
+ break;
10498
+ }
10499
+ case "blockquote_open": {
10500
+ const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, options);
10501
+ blockquoteChildren.push(nestedBlockquote);
10502
+ j = newIndex;
10503
+ break;
10504
+ }
10505
+ default: {
10506
+ const handled = parseCommonBlockToken(tokens, j, options, containerTokenHandlers);
10507
+ if (handled) {
10508
+ blockquoteChildren.push(handled[0]);
10509
+ j = handled[1];
10510
+ } else j++;
10511
+ break;
10512
+ }
10513
+ }
10514
+ return [{
10515
+ type: "blockquote",
10516
+ children: blockquoteChildren,
10517
+ raw: blockquoteChildren.map((child) => child.raw).join("\n")
10518
+ }, j + 1];
10519
+ }
10520
+
10276
10521
  //#endregion
10277
10522
  //#region src/parser/node-parsers/code-block-parser.ts
10278
10523
  function parseCodeBlock(token) {
@@ -10550,7 +10795,29 @@ function parseVmrContainer(tokens, index, options) {
10550
10795
  }
10551
10796
  const children = [];
10552
10797
  let j = index + 1;
10553
- while (j < tokens.length && tokens[j].type !== "vmr_container_close") {
10798
+ while (j < tokens.length && tokens[j].type !== "vmr_container_close") if (tokens[j].type === "paragraph_open") {
10799
+ const contentToken = tokens[j + 1];
10800
+ if (contentToken) {
10801
+ const childrenArr = contentToken.children || [];
10802
+ children.push({
10803
+ type: "paragraph",
10804
+ children: parseInlineTokens(childrenArr || [], void 0, void 0, {
10805
+ requireClosingStrong: options?.requireClosingStrong,
10806
+ customHtmlTags: options?.customHtmlTags
10807
+ }),
10808
+ raw: String(contentToken.content ?? "")
10809
+ });
10810
+ }
10811
+ j += 3;
10812
+ } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
10813
+ const [listNode, newIndex] = parseList(tokens, j, options);
10814
+ children.push(listNode);
10815
+ j = newIndex;
10816
+ } else if (tokens[j].type === "blockquote_open") {
10817
+ const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
10818
+ children.push(blockquoteNode);
10819
+ j = newIndex;
10820
+ } else {
10554
10821
  const handled = parseBasicBlockToken(tokens, j, options);
10555
10822
  if (handled) {
10556
10823
  children.push(handled[0]);
@@ -10754,249 +11021,6 @@ function parseCommonBlockToken(tokens, index, options, handlers) {
10754
11021
  return null;
10755
11022
  }
10756
11023
 
10757
- //#endregion
10758
- //#region src/parser/node-parsers/list-parser.ts
10759
- function parseList(tokens, index, options) {
10760
- const token = tokens[index];
10761
- const listItems = [];
10762
- let j = index + 1;
10763
- while (j < tokens.length && tokens[j].type !== "bullet_list_close" && tokens[j].type !== "ordered_list_close") if (tokens[j].type === "list_item_open") {
10764
- const itemChildren = [];
10765
- let k = j + 1;
10766
- while (k < tokens.length && tokens[k].type !== "list_item_close") if (tokens[k].type === "paragraph_open") {
10767
- const contentToken = tokens[k + 1];
10768
- const preToken = tokens[k - 1];
10769
- const contentStr = String(contentToken.content ?? "");
10770
- if (/\n\d+$/.test(contentStr)) {
10771
- contentToken.content = contentStr.replace(/\n\d+$/, "");
10772
- contentToken.children?.splice(-1, 1);
10773
- }
10774
- itemChildren.push({
10775
- type: "paragraph",
10776
- children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), preToken, {
10777
- requireClosingStrong: options?.requireClosingStrong,
10778
- customHtmlTags: options?.customHtmlTags
10779
- }),
10780
- raw: String(contentToken.content ?? "")
10781
- });
10782
- k += 3;
10783
- } else if (tokens[k].type === "blockquote_open") {
10784
- const [blockquoteNode, newIndex] = parseBlockquote(tokens, k, options);
10785
- itemChildren.push(blockquoteNode);
10786
- k = newIndex;
10787
- } else if (tokens[k].type === "bullet_list_open" || tokens[k].type === "ordered_list_open") {
10788
- const [nestedListNode, newIndex] = parseList(tokens, k, options);
10789
- itemChildren.push(nestedListNode);
10790
- k = newIndex;
10791
- } else {
10792
- const handled = parseCommonBlockToken(tokens, k, options, containerTokenHandlers);
10793
- if (handled) {
10794
- itemChildren.push(handled[0]);
10795
- k = handled[1];
10796
- } else k += 1;
10797
- }
10798
- listItems.push({
10799
- type: "list_item",
10800
- children: itemChildren,
10801
- raw: itemChildren.map((child) => child.raw).join("")
10802
- });
10803
- j = k + 1;
10804
- } else j += 1;
10805
- return [{
10806
- type: "list",
10807
- ordered: token.type === "ordered_list_open",
10808
- start: (() => {
10809
- if (token.attrs && token.attrs.length) {
10810
- const found = token.attrs.find((a) => a[0] === "start");
10811
- if (found) {
10812
- const parsed = Number(found[1]);
10813
- return Number.isFinite(parsed) && parsed !== 0 ? parsed : 1;
10814
- }
10815
- }
10816
- })(),
10817
- items: listItems,
10818
- raw: listItems.map((item) => item.raw).join("\n")
10819
- }, j + 1];
10820
- }
10821
-
10822
- //#endregion
10823
- //#region src/parser/node-parsers/admonition-parser.ts
10824
- function parseAdmonition(tokens, index, match, options) {
10825
- const kind = String(match[1] ?? "note");
10826
- const title = String(match[2] ?? kind.charAt(0).toUpperCase() + kind.slice(1));
10827
- const admonitionChildren = [];
10828
- let j = index + 1;
10829
- while (j < tokens.length && tokens[j].type !== "container_close") if (tokens[j].type === "paragraph_open") {
10830
- const contentToken = tokens[j + 1];
10831
- if (contentToken) admonitionChildren.push({
10832
- type: "paragraph",
10833
- children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
10834
- requireClosingStrong: options?.requireClosingStrong,
10835
- customHtmlTags: options?.customHtmlTags
10836
- }),
10837
- raw: String(contentToken.content ?? "")
10838
- });
10839
- j += 3;
10840
- } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
10841
- const [listNode, newIndex] = parseList(tokens, j, options);
10842
- admonitionChildren.push(listNode);
10843
- j = newIndex;
10844
- } else if (tokens[j].type === "blockquote_open") {
10845
- const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
10846
- admonitionChildren.push(blockquoteNode);
10847
- j = newIndex;
10848
- } else {
10849
- const handled = parseBasicBlockToken(tokens, j, options);
10850
- if (handled) {
10851
- admonitionChildren.push(handled[0]);
10852
- j = handled[1];
10853
- } else j++;
10854
- }
10855
- return [{
10856
- type: "admonition",
10857
- kind,
10858
- title,
10859
- children: admonitionChildren,
10860
- raw: `:::${kind} ${title}\n${admonitionChildren.map((child) => child.raw).join("\n")}\n:::`
10861
- }, j + 1];
10862
- }
10863
-
10864
- //#endregion
10865
- //#region src/parser/node-parsers/container-parser.ts
10866
- function parseContainer(tokens, index, options) {
10867
- const openToken = tokens[index];
10868
- let kind = "note";
10869
- let title = "";
10870
- const typeMatch = openToken.type.match(/^container_(\w+)_open$/);
10871
- if (typeMatch) {
10872
- kind = typeMatch[1];
10873
- const info = String(openToken.info ?? "").trim();
10874
- if (info && !info.startsWith(":::")) {
10875
- const maybe = info.replace(/* @__PURE__ */ new RegExp(`^${kind}`), "").trim();
10876
- if (maybe) title = maybe;
10877
- }
10878
- } else {
10879
- const info = String(openToken.info ?? "").trim();
10880
- const match = /^:{1,3}\s*(warning|info|note|tip|danger|caution)\s*(.*)$/i.exec(info);
10881
- if (match) {
10882
- kind = match[1];
10883
- title = String(match[2] ?? "");
10884
- }
10885
- }
10886
- if (!title) title = kind.charAt(0).toUpperCase() + kind.slice(1);
10887
- const children = [];
10888
- let j = index + 1;
10889
- const closeType = /* @__PURE__ */ new RegExp(`^container_${kind}_close$`);
10890
- while (j < tokens.length && tokens[j].type !== "container_close" && !closeType.test(tokens[j].type)) if (tokens[j].type === "paragraph_open") {
10891
- const contentToken = tokens[j + 1];
10892
- if (contentToken) {
10893
- const childrenArr = contentToken.children || [];
10894
- let i = -1;
10895
- for (let k = childrenArr.length - 1; k >= 0; k--) {
10896
- const t = childrenArr[k];
10897
- if (t.type === "text" && /:+/.test(t.content)) {
10898
- i = k;
10899
- break;
10900
- }
10901
- }
10902
- const _children = i !== -1 ? childrenArr.slice(0, i) : childrenArr;
10903
- children.push({
10904
- type: "paragraph",
10905
- children: parseInlineTokens(_children || [], void 0, void 0, {
10906
- requireClosingStrong: options?.requireClosingStrong,
10907
- customHtmlTags: options?.customHtmlTags
10908
- }),
10909
- raw: String(contentToken.content ?? "").replace(/\n:+$/, "").replace(/\n\s*:::\s*$/, "")
10910
- });
10911
- }
10912
- j += 3;
10913
- } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
10914
- const [listNode, newIndex] = parseList(tokens, j, options);
10915
- children.push(listNode);
10916
- j = newIndex;
10917
- } else if (tokens[j].type === "blockquote_open") {
10918
- const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
10919
- children.push(blockquoteNode);
10920
- j = newIndex;
10921
- } else {
10922
- const handled = parseBasicBlockToken(tokens, j, options);
10923
- if (handled) {
10924
- children.push(handled[0]);
10925
- j = handled[1];
10926
- } else j++;
10927
- }
10928
- return [{
10929
- type: "admonition",
10930
- kind,
10931
- title,
10932
- children,
10933
- raw: `:::${kind} ${title}\n${children.map((c) => c.raw).join("\n")}\n:::`
10934
- }, j + 1];
10935
- }
10936
-
10937
- //#endregion
10938
- //#region src/parser/node-parsers/container-token-handlers.ts
10939
- const CONTAINER_REGEX = /^::: ?(warning|info|note|tip|danger|caution|error) ?(.*)$/;
10940
- function handleContainerOpen(tokens, index, options) {
10941
- const token = tokens[index];
10942
- if (token.type !== "container_open") return null;
10943
- const match = CONTAINER_REGEX.exec(String(token.info ?? ""));
10944
- if (!match) return null;
10945
- return parseAdmonition(tokens, index, match, options);
10946
- }
10947
- const containerTokenHandlers = {
10948
- parseContainer: (tokens, index, options) => parseContainer(tokens, index, options),
10949
- matchAdmonition: handleContainerOpen
10950
- };
10951
-
10952
- //#endregion
10953
- //#region src/parser/node-parsers/blockquote-parser.ts
10954
- function parseBlockquote(tokens, index, options) {
10955
- const blockquoteChildren = [];
10956
- let j = index + 1;
10957
- while (j < tokens.length && tokens[j].type !== "blockquote_close") switch (tokens[j].type) {
10958
- case "paragraph_open": {
10959
- const contentToken = tokens[j + 1];
10960
- blockquoteChildren.push({
10961
- type: "paragraph",
10962
- children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
10963
- requireClosingStrong: options?.requireClosingStrong,
10964
- customHtmlTags: options?.customHtmlTags
10965
- }),
10966
- raw: String(contentToken.content ?? "")
10967
- });
10968
- j += 3;
10969
- break;
10970
- }
10971
- case "bullet_list_open":
10972
- case "ordered_list_open": {
10973
- const [listNode, newIndex] = parseList(tokens, j, options);
10974
- blockquoteChildren.push(listNode);
10975
- j = newIndex;
10976
- break;
10977
- }
10978
- case "blockquote_open": {
10979
- const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, options);
10980
- blockquoteChildren.push(nestedBlockquote);
10981
- j = newIndex;
10982
- break;
10983
- }
10984
- default: {
10985
- const handled = parseCommonBlockToken(tokens, j, options, containerTokenHandlers);
10986
- if (handled) {
10987
- blockquoteChildren.push(handled[0]);
10988
- j = handled[1];
10989
- } else j++;
10990
- break;
10991
- }
10992
- }
10993
- return [{
10994
- type: "blockquote",
10995
- children: blockquoteChildren,
10996
- raw: blockquoteChildren.map((child) => child.raw).join("\n")
10997
- }, j + 1];
10998
- }
10999
-
11000
11024
  //#endregion
11001
11025
  //#region src/parser/node-parsers/hardbreak-parser.ts
11002
11026
  function parseHardBreak() {
@@ -11101,19 +11125,22 @@ function stripDanglingHtmlLikeTail(markdown) {
11101
11125
  return s.slice(0, lastLt);
11102
11126
  }
11103
11127
  function parseMarkdownToStructure(markdown, md, options = {}) {
11128
+ const isFinal = !!options.final;
11104
11129
  let safeMarkdown = (markdown ?? "").toString().replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\n(abla|eq|ot|exists)/g, "$1\\n$2");
11105
- if (safeMarkdown.endsWith("- *")) safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*");
11106
- if (/(?:^|\n)\s*-\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => {
11107
- return m.startsWith("\n") ? "\n" : "";
11108
- });
11109
- else if (/(?:^|\n)\s*--\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*--\s*$/, (m) => {
11110
- return m.startsWith("\n") ? "\n" : "";
11111
- });
11112
- else if (/(?:^|\n)\s*>\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*>\s*$/, (m) => {
11113
- return m.startsWith("\n") ? "\n" : "";
11114
- });
11115
- else if (/\n\s*[*+]\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/\n\s*[*+]\s*$/, "\n");
11116
- else if (/\n[[(]\n*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(\n\[|\n\()+\n*$/g, "\n");
11130
+ if (!isFinal) {
11131
+ if (safeMarkdown.endsWith("- *")) safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*");
11132
+ if (/(?:^|\n)\s*-\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => {
11133
+ return m.startsWith("\n") ? "\n" : "";
11134
+ });
11135
+ else if (/(?:^|\n)\s*--\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*--\s*$/, (m) => {
11136
+ return m.startsWith("\n") ? "\n" : "";
11137
+ });
11138
+ else if (/(?:^|\n)\s*>\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*>\s*$/, (m) => {
11139
+ return m.startsWith("\n") ? "\n" : "";
11140
+ });
11141
+ else if (/\n\s*[*+]\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/\n\s*[*+]\s*$/, "\n");
11142
+ else if (/\n[[(]\n*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(\n\[|\n\()+\n*$/g, "\n");
11143
+ }
11117
11144
  if (options.customHtmlTags?.length) {
11118
11145
  const tags = options.customHtmlTags.map((t) => String(t ?? "").trim()).filter(Boolean).map((t) => {
11119
11146
  return (t.match(/^[<\s/]*([A-Z][\w-]*)/i)?.[1] ?? "").toLowerCase();
@@ -11123,8 +11150,8 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
11123
11150
  safeMarkdown = safeMarkdown.replace(re, "$1$2$2");
11124
11151
  }
11125
11152
  }
11126
- safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown);
11127
- const tokens = md.parse(safeMarkdown, {});
11153
+ if (!isFinal) safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown);
11154
+ const tokens = md.parse(safeMarkdown, { __markstreamFinal: isFinal });
11128
11155
  if (!tokens || !Array.isArray(tokens)) return [];
11129
11156
  const pre = options.preTransformTokens;
11130
11157
  const post = options.postTransformTokens;
@@ -11269,7 +11296,9 @@ function getMarkdown(msgId = `editor-${Date.now()}`, options = {}) {
11269
11296
  md.use(footnote_plugin);
11270
11297
  md.core.ruler.after("block", "mark_fence_closed", (state) => {
11271
11298
  const s = state;
11272
- const lines = s.src.split(/\r?\n/);
11299
+ const src = s.src;
11300
+ const envFinal = !!s.env?.__markstreamFinal;
11301
+ const lines = src.split(/\r?\n/);
11273
11302
  for (const token of s.tokens) {
11274
11303
  if (token.type !== "fence" || !token.map || !token.markup) continue;
11275
11304
  const openLine = token.map[0];
@@ -11284,7 +11313,7 @@ function getMarkdown(msgId = `editor-${Date.now()}`, options = {}) {
11284
11313
  while (i + count < line.length && line[i + count] === marker) count++;
11285
11314
  let j = i + count;
11286
11315
  while (j < line.length && (line[j] === " " || line[j] === " ")) j++;
11287
- const closed = endLine > openLine + 1 && count >= minLen && j === line.length;
11316
+ const closed = envFinal ? true : endLine > openLine + 1 && count >= minLen && j === line.length;
11288
11317
  const tokenShape = token;
11289
11318
  tokenShape.meta = tokenShape.meta ?? {};
11290
11319
  tokenShape.meta.unclosed = !closed;