stream-markdown-parser 1.0.8 → 1.0.9

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.cjs CHANGED
@@ -10899,6 +10899,18 @@ function parseLooseInlineAttrs(input) {
10899
10899
  }
10900
10900
  return out;
10901
10901
  }
10902
+ function offsetTokenMaps(tokens, lineOffset, maxEndLine) {
10903
+ for (const token of tokens) {
10904
+ const mappedToken = token;
10905
+ const map$1 = mappedToken.map;
10906
+ if (Array.isArray(map$1) && map$1.length >= 2) {
10907
+ const startLine = Number(map$1[0]);
10908
+ const endLine = Number(map$1[1]);
10909
+ if (Number.isFinite(startLine) && Number.isFinite(endLine)) mappedToken.map = [startLine + lineOffset, Math.min(endLine + lineOffset, maxEndLine)];
10910
+ }
10911
+ if (Array.isArray(mappedToken.children)) offsetTokenMaps(mappedToken.children, lineOffset, maxEndLine);
10912
+ }
10913
+ }
10902
10914
  function applyContainers(md) {
10903
10915
  [
10904
10916
  "admonition",
@@ -10963,6 +10975,7 @@ function applyContainers(md) {
10963
10975
  if (!found) nextLine = endLine;
10964
10976
  const tokenOpen = s.push("vmr_container_open", "div", 1);
10965
10977
  tokenOpen.attrSet("class", `vmr-container vmr-container-${name}`);
10978
+ tokenOpen.map = [startLine, found ? nextLine : endLine];
10966
10979
  tokenOpen.meta = {
10967
10980
  ...tokenOpen.meta ?? {},
10968
10981
  unclosed: !found && !envFinal
@@ -10996,6 +11009,7 @@ function applyContainers(md) {
10996
11009
  if (prevToken) prevToken.raw = innerSrc;
10997
11010
  const innerTokens = [];
10998
11011
  s.md.block.parse(innerSrc, s.md, s.env, innerTokens);
11012
+ offsetTokenMaps(innerTokens, startLine + 1, startLine + 1 + contentLines.length);
10999
11013
  s.tokens.push(...innerTokens);
11000
11014
  }
11001
11015
  if (found) s.push("vmr_container_close", "div", -1);
@@ -13508,6 +13522,7 @@ const SPAN_CURLY_RE = /span\{([^}]+)\}/;
13508
13522
  const OPERATORNAME_SPAN_RE = /\\operatorname\{span\}\{((?:[^{}]|\{[^}]*\})+)\}/;
13509
13523
  const SINGLE_BACKSLASH_NEWLINE_RE = /(^|[^\\])\\\r?\n/g;
13510
13524
  const ENDING_SINGLE_BACKSLASH_RE = /(^|[^\\])\\$/g;
13525
+ const FACTORIAL_PRECEDING_RE = /[\p{L}\p{M}\p{N}\p{Pe}\p{Pf}'′″‴|‖]/u;
13511
13526
  const DEFAULT_MATH_RE = new RegExp(`(${CONTROL_CHARS_CLASS})|(${ESCAPED_KATEX_COMMANDS})\\b`, "g");
13512
13527
  const MATH_RE_CACHE = /* @__PURE__ */ new Map();
13513
13528
  const BRACE_CMD_RE_CACHE = /* @__PURE__ */ new Map();
@@ -13547,6 +13562,13 @@ function countUnescapedStrong(s) {
13547
13562
  while (re.exec(s) !== null) c++;
13548
13563
  return c;
13549
13564
  }
13565
+ function escapeStandaloneExclamation(value) {
13566
+ return value.replace(/(^|[^\\])!+/gu, (match, prefix) => {
13567
+ if (prefix && FACTORIAL_PRECEDING_RE.test(prefix)) return match;
13568
+ const marks = prefix ? match.slice(prefix.length) : match;
13569
+ return `${prefix}${"\\!".repeat(marks.length)}`;
13570
+ });
13571
+ }
13550
13572
  function findLastUnescapedStrongMarker(s) {
13551
13573
  const re = /(^|[^\\])(__|\*\*)/g;
13552
13574
  let m;
@@ -13571,7 +13593,7 @@ function normalizeStandaloneBackslashT(s, opts) {
13571
13593
  }
13572
13594
  return m;
13573
13595
  });
13574
- if (escapeExclamation) out = out.replace(/(^|[^\\])!/g, "$1\\!");
13596
+ if (escapeExclamation) out = escapeStandaloneExclamation(out);
13575
13597
  let result = out;
13576
13598
  const braceCmdRe = getBraceCmdRegex(useDefault, useDefault ? void 0 : commands);
13577
13599
  result = result.replace(braceCmdRe, (_m, p1, p2) => `${p1}\\${p2}{`);
@@ -16863,6 +16885,74 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
16863
16885
  return result;
16864
16886
  }
16865
16887
 
16888
+ //#endregion
16889
+ //#region src/parser/node-source-map.ts
16890
+ function mapSourceLineRange(startLine, endLine, options) {
16891
+ const mapper = options?.__sourceLineMapper;
16892
+ if (!mapper) return {
16893
+ startLine,
16894
+ endLine
16895
+ };
16896
+ const mappedStartRange = mapper(startLine);
16897
+ const mappedEndLine = endLine > startLine ? mapper(endLine - 1).endLine : mapper(endLine).startLine;
16898
+ return {
16899
+ startLine: mappedStartRange.startLine,
16900
+ endLine: Math.max(mappedStartRange.startLine, mappedEndLine)
16901
+ };
16902
+ }
16903
+ function lineAtOffset(source, offset) {
16904
+ const target = Math.max(0, Math.min(source.length, Math.trunc(offset)));
16905
+ let line = 0;
16906
+ for (let i = 0; i < target; i++) if (source[i] === "\n") line++;
16907
+ return line;
16908
+ }
16909
+ function sourceLineRangeFromOffsets(source, start, end) {
16910
+ const startIndex = Math.max(0, Math.min(source.length, Math.trunc(start)));
16911
+ const endIndex = Math.max(startIndex, Math.min(source.length, Math.trunc(end)));
16912
+ const startLine = lineAtOffset(source, startIndex);
16913
+ let endLine = lineAtOffset(source, endIndex);
16914
+ if (endIndex > startIndex && source[endIndex - 1] !== "\n") endLine++;
16915
+ return {
16916
+ startLine,
16917
+ endLine
16918
+ };
16919
+ }
16920
+ function createSourceMapFromOffsets(source, start, end, options) {
16921
+ const range = sourceLineRangeFromOffsets(source, start, end);
16922
+ return mapSourceLineRange(range.startLine, range.endLine, options);
16923
+ }
16924
+ function readSourceMap(token, options) {
16925
+ const map$1 = token?.map;
16926
+ if (!Array.isArray(map$1) || map$1.length < 2) return null;
16927
+ const startLine = Number(map$1[0]);
16928
+ const endLine = Number(map$1[1]);
16929
+ if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) return null;
16930
+ return mapSourceLineRange(startLine, endLine, options);
16931
+ }
16932
+ function applyNodeSourceMap(node, token, options) {
16933
+ if (!options?.includeSourceMap) return node;
16934
+ const sourceMap = readSourceMap(token, options);
16935
+ if (!sourceMap) return node;
16936
+ node.sourceMap = sourceMap;
16937
+ if (node.type === "code_block") {
16938
+ const codeNode = node;
16939
+ codeNode.startLine = sourceMap.startLine;
16940
+ codeNode.endLine = sourceMap.endLine;
16941
+ }
16942
+ return node;
16943
+ }
16944
+ function applyNodeSourceMapRange(node, token, endLine, options) {
16945
+ if (!options?.includeSourceMap) return node;
16946
+ const map$1 = token?.map;
16947
+ if (!Array.isArray(map$1) || map$1.length < 2) return node;
16948
+ const startLine = Number(map$1[0]);
16949
+ const tokenEndLine = Number(map$1[1]);
16950
+ const rangeEndLine = Number(endLine);
16951
+ if (!Number.isFinite(startLine) || !Number.isFinite(tokenEndLine) || !Number.isFinite(rangeEndLine)) return node;
16952
+ node.sourceMap = mapSourceLineRange(startLine, Math.max(tokenEndLine, rangeEndLine), options);
16953
+ return node;
16954
+ }
16955
+
16866
16956
  //#endregion
16867
16957
  //#region src/parser/node-parsers/list-parser.ts
16868
16958
  function trimInlineTokenTail(token) {
@@ -16947,11 +17037,13 @@ function parseList(tokens, index, options) {
16947
17037
  trimInlineTokenTail(contentToken);
16948
17038
  }
16949
17039
  const paragraphRaw = String(contentToken.content ?? "");
16950
- itemChildren.push({
17040
+ const paragraphNode = {
16951
17041
  type: "paragraph",
16952
17042
  children: parseInlineTokens(contentToken.children || [], paragraphRaw, preToken, linkifyContext.options()),
16953
17043
  raw: paragraphRaw
16954
- });
17044
+ };
17045
+ if (options?.includeSourceMap) applyNodeSourceMap(paragraphNode, tokens[k], options);
17046
+ itemChildren.push(paragraphNode);
16955
17047
  linkifyContext.remember(paragraphRaw);
16956
17048
  k += 3;
16957
17049
  } else if (tokens[k].type === "blockquote_open") {
@@ -16972,14 +17064,16 @@ function parseList(tokens, index, options) {
16972
17064
  k = handled[1];
16973
17065
  } else k += 1;
16974
17066
  }
16975
- listItems.push({
17067
+ const listItemNode = {
16976
17068
  type: "list_item",
16977
17069
  children: itemChildren,
16978
17070
  raw: itemChildren.map((child) => child.raw).join("")
16979
- });
17071
+ };
17072
+ if (options?.includeSourceMap) applyNodeSourceMap(listItemNode, tokens[j], options);
17073
+ listItems.push(listItemNode);
16980
17074
  j = k + 1;
16981
17075
  } else j += 1;
16982
- return [{
17076
+ const listNode = {
16983
17077
  type: "list",
16984
17078
  ordered: token.type === "ordered_list_open",
16985
17079
  start: (() => {
@@ -16993,7 +17087,9 @@ function parseList(tokens, index, options) {
16993
17087
  })(),
16994
17088
  items: listItems,
16995
17089
  raw: listItems.map((item) => item.raw).join("\n")
16996
- }, j + 1];
17090
+ };
17091
+ if (options?.includeSourceMap) applyNodeSourceMap(listNode, token, options);
17092
+ return [listNode, j + 1];
16997
17093
  }
16998
17094
 
16999
17095
  //#endregion
@@ -17012,17 +17108,20 @@ function parseAdmonition(tokens, index, match, options) {
17012
17108
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
17013
17109
  raw: String(contentToken.content ?? "")
17014
17110
  };
17111
+ if (options?.includeSourceMap) applyNodeSourceMap(paragraphNode, tokens[j], options);
17015
17112
  admonitionChildren.push(paragraphNode);
17016
17113
  linkifyContext.remember(paragraphNode.raw);
17017
17114
  }
17018
17115
  j += 3;
17019
17116
  } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
17020
17117
  const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
17118
+ if (options?.includeSourceMap) applyNodeSourceMap(listNode, tokens[j], options);
17021
17119
  admonitionChildren.push(listNode);
17022
17120
  linkifyContext.remember(listNode.raw);
17023
17121
  j = newIndex;
17024
17122
  } else if (tokens[j].type === "blockquote_open") {
17025
17123
  const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
17124
+ if (options?.includeSourceMap) applyNodeSourceMap(blockquoteNode, tokens[j], options);
17026
17125
  admonitionChildren.push(blockquoteNode);
17027
17126
  linkifyContext.remember(blockquoteNode.raw);
17028
17127
  j = newIndex;
@@ -17110,17 +17209,20 @@ function parseContainer(tokens, index, options) {
17110
17209
  children: parseInlineTokens((i !== -1 ? childrenArr.slice(0, i) : childrenArr) || [], void 0, void 0, linkifyContext.options()),
17111
17210
  raw: String(contentToken.content ?? "").replace(/\n:+$/, "").replace(/\n\s*:::\s*$/, "")
17112
17211
  };
17212
+ if (options?.includeSourceMap) applyNodeSourceMap(paragraphNode, tokens[j], options);
17113
17213
  children.push(paragraphNode);
17114
17214
  linkifyContext.remember(paragraphNode.raw);
17115
17215
  }
17116
17216
  j += 3;
17117
17217
  } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
17118
17218
  const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
17219
+ if (options?.includeSourceMap) applyNodeSourceMap(listNode, tokens[j], options);
17119
17220
  children.push(listNode);
17120
17221
  linkifyContext.remember(listNode.raw);
17121
17222
  j = newIndex;
17122
17223
  } else if (tokens[j].type === "blockquote_open") {
17123
17224
  const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
17225
+ if (options?.includeSourceMap) applyNodeSourceMap(blockquoteNode, tokens[j], options);
17124
17226
  children.push(blockquoteNode);
17125
17227
  linkifyContext.remember(blockquoteNode.raw);
17126
17228
  j = newIndex;
@@ -17162,49 +17264,55 @@ function parseBlockquote(tokens, index, options) {
17162
17264
  const blockquoteChildren = [];
17163
17265
  const linkifyContext = createLinkifyDemotionContextTracker(options, true);
17164
17266
  let j = index + 1;
17165
- while (j < tokens.length && tokens[j].type !== "blockquote_close") switch (tokens[j].type) {
17166
- case "paragraph_open": {
17167
- const contentToken = tokens[j + 1];
17168
- const paragraphNode = {
17169
- type: "paragraph",
17170
- children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
17171
- raw: String(contentToken.content ?? "")
17172
- };
17173
- blockquoteChildren.push(paragraphNode);
17174
- linkifyContext.remember(paragraphNode.raw);
17175
- j += 3;
17176
- break;
17177
- }
17178
- case "bullet_list_open":
17179
- case "ordered_list_open": {
17180
- const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
17181
- blockquoteChildren.push(listNode);
17182
- linkifyContext.remember(listNode.raw);
17183
- j = newIndex;
17184
- break;
17185
- }
17186
- case "blockquote_open": {
17187
- const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
17188
- blockquoteChildren.push(nestedBlockquote);
17189
- linkifyContext.remember(nestedBlockquote.raw);
17190
- j = newIndex;
17191
- break;
17192
- }
17193
- default: {
17194
- const handled = parseCommonBlockToken(tokens, j, linkifyContext.options(), containerTokenHandlers);
17195
- if (handled) {
17196
- blockquoteChildren.push(handled[0]);
17197
- linkifyContext.remember(handled[0].raw);
17198
- j = handled[1];
17199
- } else j++;
17200
- break;
17267
+ while (j < tokens.length && tokens[j].type !== "blockquote_close") {
17268
+ const token = tokens[j];
17269
+ switch (token.type) {
17270
+ case "paragraph_open": {
17271
+ const contentToken = tokens[j + 1];
17272
+ const paragraphNode = {
17273
+ type: "paragraph",
17274
+ children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
17275
+ raw: String(contentToken.content ?? "")
17276
+ };
17277
+ if (options?.includeSourceMap) applyNodeSourceMap(paragraphNode, token, options);
17278
+ blockquoteChildren.push(paragraphNode);
17279
+ linkifyContext.remember(paragraphNode.raw);
17280
+ j += 3;
17281
+ break;
17282
+ }
17283
+ case "bullet_list_open":
17284
+ case "ordered_list_open": {
17285
+ const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
17286
+ blockquoteChildren.push(listNode);
17287
+ linkifyContext.remember(listNode.raw);
17288
+ j = newIndex;
17289
+ break;
17290
+ }
17291
+ case "blockquote_open": {
17292
+ const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
17293
+ blockquoteChildren.push(nestedBlockquote);
17294
+ linkifyContext.remember(nestedBlockquote.raw);
17295
+ j = newIndex;
17296
+ break;
17297
+ }
17298
+ default: {
17299
+ const handled = parseCommonBlockToken(tokens, j, linkifyContext.options(), containerTokenHandlers);
17300
+ if (handled) {
17301
+ blockquoteChildren.push(handled[0]);
17302
+ linkifyContext.remember(handled[0].raw);
17303
+ j = handled[1];
17304
+ } else j++;
17305
+ break;
17306
+ }
17201
17307
  }
17202
17308
  }
17203
- return [{
17309
+ const blockquoteNode = {
17204
17310
  type: "blockquote",
17205
17311
  children: blockquoteChildren,
17206
17312
  raw: blockquoteChildren.map((child) => child.raw).join("\n")
17207
- }, j + 1];
17313
+ };
17314
+ if (options?.includeSourceMap) applyNodeSourceMap(blockquoteNode, tokens[index], options);
17315
+ return [blockquoteNode, j + 1];
17208
17316
  }
17209
17317
 
17210
17318
  //#endregion
@@ -17562,17 +17670,20 @@ function parseVmrContainer(tokens, index, options) {
17562
17670
  children: parseInlineTokens(contentToken.children || [], void 0, void 0, linkifyContext.options()),
17563
17671
  raw: String(contentToken.content ?? "")
17564
17672
  };
17673
+ if (options?.includeSourceMap) applyNodeSourceMap(paragraphNode, tokens[j], options);
17565
17674
  children.push(paragraphNode);
17566
17675
  linkifyContext.remember(paragraphNode.raw);
17567
17676
  }
17568
17677
  j += 3;
17569
17678
  } else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
17570
17679
  const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
17680
+ if (options?.includeSourceMap) applyNodeSourceMap(listNode, tokens[j], options);
17571
17681
  children.push(listNode);
17572
17682
  linkifyContext.remember(listNode.raw);
17573
17683
  j = newIndex;
17574
17684
  } else if (tokens[j].type === "blockquote_open") {
17575
17685
  const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
17686
+ if (options?.includeSourceMap) applyNodeSourceMap(blockquoteNode, tokens[j], options);
17576
17687
  children.push(blockquoteNode);
17577
17688
  linkifyContext.remember(blockquoteNode.raw);
17578
17689
  j = newIndex;
@@ -17603,6 +17714,14 @@ function parseVmrContainer(tokens, index, options) {
17603
17714
  raw
17604
17715
  }, hasCloseToken ? j + 1 : j];
17605
17716
  }
17717
+ function applyPairedBlockSourceMap(node, openToken, closeToken, options) {
17718
+ if (closeToken?.type.endsWith("_close")) {
17719
+ let endLine = Array.isArray(closeToken.map) ? Number(closeToken.map[1]) : NaN;
17720
+ if (!Number.isFinite(endLine)) endLine = Array.isArray(openToken.map) ? Number(openToken.map[1]) + 1 : NaN;
17721
+ return applyNodeSourceMapRange(node, openToken, endLine, options);
17722
+ }
17723
+ return applyNodeSourceMap(node, openToken, options);
17724
+ }
17606
17725
  function stripWrapperNewlines(s) {
17607
17726
  return s.replace(/^\r?\n/, "").replace(/\r?\n$/, "");
17608
17727
  }
@@ -17661,6 +17780,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
17661
17780
  const end = openEnd + 1;
17662
17781
  return {
17663
17782
  raw: source.slice(openStart, end),
17783
+ start: openStart,
17664
17784
  end
17665
17785
  };
17666
17786
  }
@@ -17678,6 +17798,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
17678
17798
  const lt = source.indexOf("<", i);
17679
17799
  if (lt === -1) return {
17680
17800
  raw: source.slice(openStart),
17801
+ start: openStart,
17681
17802
  end: source.length
17682
17803
  };
17683
17804
  if (isCloseAt(lt)) {
@@ -17688,6 +17809,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
17688
17809
  const end = gt + 1;
17689
17810
  return {
17690
17811
  raw: source.slice(openStart, end),
17812
+ start: openStart,
17691
17813
  end
17692
17814
  };
17693
17815
  }
@@ -17705,6 +17827,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
17705
17827
  }
17706
17828
  return {
17707
17829
  raw: source.slice(openStart),
17830
+ start: openStart,
17708
17831
  end: source.length
17709
17832
  };
17710
17833
  }
@@ -17723,17 +17846,34 @@ function lineToIndex(source, line) {
17723
17846
  }
17724
17847
  function parseBasicBlockToken(tokens, index, options) {
17725
17848
  const token = tokens[index];
17849
+ const includeSourceMap = options?.includeSourceMap === true;
17726
17850
  switch (token.type) {
17727
- case "heading_open": return [parseHeading(tokens, index, options), index + 3];
17728
- case "code_block": return [parseCodeBlock(token), index + 1];
17729
- case "fence": return [parseFenceToken(token), index + 1];
17730
- case "math_block": return [parseMathBlock(token), index + 1];
17851
+ case "heading_open": {
17852
+ const node = parseHeading(tokens, index, options);
17853
+ if (includeSourceMap) applyNodeSourceMap(node, token, options);
17854
+ return [node, index + 3];
17855
+ }
17856
+ case "code_block": {
17857
+ const node = parseCodeBlock(token);
17858
+ if (includeSourceMap) applyNodeSourceMap(node, token, options);
17859
+ return [node, index + 1];
17860
+ }
17861
+ case "fence": {
17862
+ const node = parseFenceToken(token);
17863
+ if (includeSourceMap) applyNodeSourceMap(node, token, options);
17864
+ return [node, index + 1];
17865
+ }
17866
+ case "math_block": {
17867
+ const node = parseMathBlock(token);
17868
+ if (includeSourceMap) applyNodeSourceMap(node, token, options);
17869
+ return [node, index + 1];
17870
+ }
17731
17871
  case "html_block": {
17732
17872
  const htmlBlockNode = parseHtmlBlock(token);
17733
17873
  const tagSets = htmlBlockNode.tag ? getHtmlTagSets(options?.customHtmlTags) : null;
17734
17874
  if (htmlBlockNode.tag && htmlBlockNode.loading && tagSets && !tagSets.allowedTagSet.has(htmlBlockNode.tag)) {
17735
17875
  const content = String(token.content ?? "").replace(/\n+$/, "");
17736
- return [{
17876
+ const paragraphNode = {
17737
17877
  type: "paragraph",
17738
17878
  children: content ? [{
17739
17879
  type: "text",
@@ -17741,7 +17881,9 @@ function parseBasicBlockToken(tokens, index, options) {
17741
17881
  raw: content
17742
17882
  }] : [],
17743
17883
  raw: content
17744
- }, index + 1];
17884
+ };
17885
+ if (includeSourceMap) applyNodeSourceMap(paragraphNode, token, options);
17886
+ return [paragraphNode, index + 1];
17745
17887
  }
17746
17888
  if (htmlBlockNode.tag && tagSets?.customTagSet?.has(htmlBlockNode.tag)) {
17747
17889
  const tag = htmlBlockNode.tag;
@@ -17770,30 +17912,41 @@ function parseBasicBlockToken(tokens, index, options) {
17770
17912
  attrs.push([name, value]);
17771
17913
  }
17772
17914
  const loading = !options?.final && !selfClosing && closeRange == null;
17773
- return [{
17915
+ const customNode = {
17774
17916
  type: tag,
17775
17917
  tag,
17776
17918
  content: stripWrapperNewlines(inner),
17777
17919
  raw: String(fromSource?.raw ?? htmlBlockNode.raw ?? rawHtml),
17778
17920
  loading,
17779
17921
  attrs: attrs.length ? attrs : void 0
17780
- }, index + 1];
17922
+ };
17923
+ if (includeSourceMap) if (fromSource) customNode.sourceMap = createSourceMapFromOffsets(source, fromSource.start, fromSource.end, options);
17924
+ else applyNodeSourceMap(customNode, token, options);
17925
+ return [customNode, index + 1];
17781
17926
  }
17927
+ if (includeSourceMap) applyNodeSourceMap(htmlBlockNode, token, options);
17782
17928
  return [htmlBlockNode, index + 1];
17783
17929
  }
17784
17930
  case "table_open": {
17785
17931
  const [tableNode, newIndex] = parseTable(tokens, index, options);
17932
+ if (includeSourceMap) applyNodeSourceMap(tableNode, token, options);
17786
17933
  return [tableNode, newIndex];
17787
17934
  }
17788
17935
  case "dl_open": {
17789
17936
  const [definitionListNode, newIndex] = parseDefinitionList(tokens, index, options);
17937
+ if (includeSourceMap) applyNodeSourceMap(definitionListNode, token, options);
17790
17938
  return [definitionListNode, newIndex];
17791
17939
  }
17792
17940
  case "footnote_open": {
17793
17941
  const [footnoteNode, newIndex] = parseFootnote(tokens, index, options);
17942
+ if (includeSourceMap) applyNodeSourceMap(footnoteNode, token, options);
17794
17943
  return [footnoteNode, newIndex];
17795
17944
  }
17796
- case "hr": return [parseThematicBreak(), index + 1];
17945
+ case "hr": {
17946
+ const node = parseThematicBreak();
17947
+ if (includeSourceMap) applyNodeSourceMap(node, token, options);
17948
+ return [node, index + 1];
17949
+ }
17797
17950
  default: break;
17798
17951
  }
17799
17952
  return null;
@@ -17801,7 +17954,9 @@ function parseBasicBlockToken(tokens, index, options) {
17801
17954
  function parseCommonBlockToken(tokens, index, options, handlers) {
17802
17955
  const basicResult = parseBasicBlockToken(tokens, index, options);
17803
17956
  if (basicResult) return basicResult;
17804
- switch (tokens[index].type) {
17957
+ const token = tokens[index];
17958
+ const includeSourceMap = options?.includeSourceMap === true;
17959
+ switch (token.type) {
17805
17960
  case "container_warning_open":
17806
17961
  case "container_info_open":
17807
17962
  case "container_note_open":
@@ -17809,15 +17964,26 @@ function parseCommonBlockToken(tokens, index, options, handlers) {
17809
17964
  case "container_danger_open":
17810
17965
  case "container_caution_open":
17811
17966
  case "container_error_open":
17812
- if (handlers?.parseContainer) return handlers.parseContainer(tokens, index, options);
17967
+ if (handlers?.parseContainer) {
17968
+ const result = handlers.parseContainer(tokens, index, options);
17969
+ if (includeSourceMap) applyPairedBlockSourceMap(result[0], token, tokens[result[1] - 1], options);
17970
+ return result;
17971
+ }
17813
17972
  break;
17814
17973
  case "container_open":
17815
17974
  if (handlers?.matchAdmonition) {
17816
17975
  const result = handlers.matchAdmonition(tokens, index, options);
17817
- if (result) return result;
17976
+ if (result) {
17977
+ if (includeSourceMap) applyPairedBlockSourceMap(result[0], token, tokens[result[1] - 1], options);
17978
+ return result;
17979
+ }
17818
17980
  }
17819
17981
  break;
17820
- case "vmr_container_open": return parseVmrContainer(tokens, index, options);
17982
+ case "vmr_container_open": {
17983
+ const result = parseVmrContainer(tokens, index, options);
17984
+ if (includeSourceMap) applyPairedBlockSourceMap(result[0], token, tokens[result[1] - 1], options);
17985
+ return result;
17986
+ }
17821
17987
  default: break;
17822
17988
  }
17823
17989
  return null;
@@ -17866,6 +18032,15 @@ function finishTimedParse(result, timing, startedAt) {
17866
18032
  if (timing) addTiming(timing, "parseMarkdownToStructureTotalMs", getParserNow() - startedAt);
17867
18033
  return result;
17868
18034
  }
18035
+ function applyPostTransformNodes(nodes, options) {
18036
+ const transform = options.postTransformNodes;
18037
+ if (typeof transform !== "function") return nodes;
18038
+ const transformed = transform(nodes);
18039
+ return Array.isArray(transformed) ? transformed : nodes;
18040
+ }
18041
+ function finishParsedNodes(result, options, timing, startedAt) {
18042
+ return finishTimedParse(applyPostTransformNodes(result, options), timing, startedAt);
18043
+ }
17869
18044
  function processTokensWithTiming(tokens, options, timing) {
17870
18045
  if (!timing) return processTokens(tokens, options);
17871
18046
  const startedAt = getParserNow();
@@ -18031,8 +18206,24 @@ function shouldResetTopLevelStreamCacheForFinalAutoParse(md, options) {
18031
18206
  function clearTolerantMathBoundaryStreamCache(md) {
18032
18207
  tolerantMathBoundaryStreamCache.delete(md);
18033
18208
  }
18034
- function setTolerantMathBoundaryStreamCache(md, source, key) {
18209
+ function createExplicitBracketMathContext() {
18210
+ return {
18211
+ fenceChar: "",
18212
+ fenceInBlockquote: false,
18213
+ fenceInList: false,
18214
+ fenceLen: 0,
18215
+ fenceListIndent: 0,
18216
+ inFence: false,
18217
+ inMath: false,
18218
+ listContentIndent: null
18219
+ };
18220
+ }
18221
+ function cloneExplicitBracketMathContext(context) {
18222
+ return { ...context };
18223
+ }
18224
+ function setTolerantMathBoundaryStreamCache(md, source, key, explicitBracketMath = scanExplicitBracketMathStreamState(source).state) {
18035
18225
  tolerantMathBoundaryStreamCache.set(md, {
18226
+ explicitBracketMath,
18036
18227
  source,
18037
18228
  key,
18038
18229
  pendingCandidate: key === null && mayContainTolerantMathBlockBoundaryOpener(source)
@@ -18048,12 +18239,235 @@ function sourceEndsWithCompleteTolerantBoundaryOpener(source) {
18048
18239
  }
18049
18240
  function appendedChunkMayAffectTolerantMathBoundary(previousSource, appended) {
18050
18241
  if (!appended) return false;
18051
- if (appended.includes("$$") || appended.includes("\\[") || appended.includes("\\]")) return true;
18242
+ if (appended.includes("$$") || appended.includes("\\[")) return true;
18052
18243
  if (previousSource.endsWith("$") && appended[0] === "$") return true;
18053
- if (previousSource.endsWith("\\") && (appended[0] === "[" || appended[0] === "]")) return true;
18244
+ if (previousSource.endsWith("\\") && appended[0] === "[") return true;
18054
18245
  if (sourceEndsWithCompleteTolerantBoundaryOpener(previousSource) && /[\r\n]/.test(appended)) return true;
18055
18246
  return false;
18056
18247
  }
18248
+ function isEscapedDelimiterAt(source, index) {
18249
+ let cursor = index - 1;
18250
+ let backslashes = 0;
18251
+ while (cursor >= 0 && source[cursor] === "\\") {
18252
+ backslashes++;
18253
+ cursor--;
18254
+ }
18255
+ return backslashes % 2 === 1;
18256
+ }
18257
+ function isIndentWhitespace(ch) {
18258
+ return ch === " " || ch === " ";
18259
+ }
18260
+ function advanceMarkdownIndentColumn(column, ch) {
18261
+ return ch === " " ? column + 1 : column + 4 - column % 4;
18262
+ }
18263
+ function getMarkdownIndent(line) {
18264
+ let index = 0;
18265
+ let column = 0;
18266
+ while (index < line.length && isIndentWhitespace(line[index])) {
18267
+ column = advanceMarkdownIndentColumn(column, line[index]);
18268
+ index++;
18269
+ }
18270
+ return {
18271
+ index,
18272
+ column
18273
+ };
18274
+ }
18275
+ function consumeMarkdownIndent(line) {
18276
+ const indent = getMarkdownIndent(line);
18277
+ return indent.column > 3 ? null : indent;
18278
+ }
18279
+ function parseMarkdownFenceMarker(line) {
18280
+ const indent = consumeMarkdownIndent(line);
18281
+ if (!indent) return null;
18282
+ const index = indent.index;
18283
+ const markerChar = line[index];
18284
+ if (markerChar !== "`" && markerChar !== "~") return null;
18285
+ let markerEnd = index;
18286
+ while (markerEnd < line.length && line[markerEnd] === markerChar) markerEnd++;
18287
+ const markerLen = markerEnd - index;
18288
+ if (markerLen < 3) return null;
18289
+ const rest = line.slice(markerEnd);
18290
+ if (markerChar === "`" && rest.includes("`")) return null;
18291
+ return {
18292
+ markerChar,
18293
+ markerLen,
18294
+ rest
18295
+ };
18296
+ }
18297
+ function stripMarkdownListPrefix(line) {
18298
+ const indent = consumeMarkdownIndent(line);
18299
+ if (!indent) return null;
18300
+ const rest = line.slice(indent.index);
18301
+ const marker = /^(?:[-+*]|\d{1,9}[.)])(?=[\t ]|$)/.exec(rest)?.[0];
18302
+ if (!marker) return null;
18303
+ let index = indent.index + marker.length;
18304
+ let column = indent.column + marker.length;
18305
+ if (!isIndentWhitespace(line[index])) return null;
18306
+ while (index < line.length && isIndentWhitespace(line[index])) {
18307
+ column = advanceMarkdownIndentColumn(column, line[index]);
18308
+ index++;
18309
+ }
18310
+ return {
18311
+ content: line.slice(index),
18312
+ contentIndent: column
18313
+ };
18314
+ }
18315
+ function stripMarkdownBlockquotePrefix(line) {
18316
+ let rest = line;
18317
+ let saw = false;
18318
+ while (true) {
18319
+ const indent = consumeMarkdownIndent(rest);
18320
+ if (!indent) return saw ? rest : null;
18321
+ let index = indent.index;
18322
+ if (rest[index] !== ">") return saw ? rest : null;
18323
+ saw = true;
18324
+ index++;
18325
+ if (rest[index] === " " || rest[index] === " ") index++;
18326
+ rest = rest.slice(index);
18327
+ }
18328
+ }
18329
+ function matchMarkdownFenceMarker(line) {
18330
+ const direct = parseMarkdownFenceMarker(line);
18331
+ if (direct) return {
18332
+ ...direct,
18333
+ inBlockquote: false,
18334
+ inList: false,
18335
+ listIndent: 0
18336
+ };
18337
+ const quoted = stripMarkdownBlockquotePrefix(line);
18338
+ const quotedMarker = quoted == null ? null : parseMarkdownFenceMarker(quoted);
18339
+ if (quotedMarker) return {
18340
+ ...quotedMarker,
18341
+ inBlockquote: true,
18342
+ inList: false,
18343
+ listIndent: 0
18344
+ };
18345
+ const listed = stripMarkdownListPrefix(line);
18346
+ if (!listed) return null;
18347
+ const listedMarker = parseMarkdownFenceMarker(listed.content);
18348
+ return listedMarker == null ? null : {
18349
+ ...listedMarker,
18350
+ inBlockquote: false,
18351
+ inList: true,
18352
+ listIndent: listed.contentIndent
18353
+ };
18354
+ }
18355
+ function countRepeatedChar(source, index, ch) {
18356
+ let end = index;
18357
+ while (end < source.length && source[end] === ch) end++;
18358
+ return end - index;
18359
+ }
18360
+ function findCodeSpanCloseIndex(line, start, markerLen) {
18361
+ let index = start;
18362
+ while (index < line.length) {
18363
+ const next = line.indexOf("`", index);
18364
+ if (next === -1) return -1;
18365
+ const runLen = countRepeatedChar(line, next, "`");
18366
+ if (runLen === markerLen) return next;
18367
+ index = next + runLen;
18368
+ }
18369
+ return -1;
18370
+ }
18371
+ function resetExplicitBracketFenceContext(context) {
18372
+ context.inFence = false;
18373
+ context.fenceChar = "";
18374
+ context.fenceLen = 0;
18375
+ context.fenceInBlockquote = false;
18376
+ context.fenceInList = false;
18377
+ context.fenceListIndent = 0;
18378
+ }
18379
+ function scanLineForExplicitBracketMathState(line, context, lineStart, appendStart, openAtAppendStart) {
18380
+ let index = 0;
18381
+ let closedOpenMath = false;
18382
+ while (index < line.length) {
18383
+ const sourceIndex = index;
18384
+ if (context.inMath) {
18385
+ if (line.startsWith("\\]", index) && !isEscapedDelimiterAt(line, sourceIndex)) {
18386
+ if (appendStart != null && openAtAppendStart && lineStart + index + 2 > appendStart) closedOpenMath = true;
18387
+ context.inMath = false;
18388
+ index += 2;
18389
+ continue;
18390
+ }
18391
+ index++;
18392
+ continue;
18393
+ }
18394
+ if (line[index] === "`" && !isEscapedDelimiterAt(line, sourceIndex)) {
18395
+ const markerLen = countRepeatedChar(line, index, "`");
18396
+ const closeIndex = findCodeSpanCloseIndex(line, index + markerLen, markerLen);
18397
+ if (closeIndex === -1) break;
18398
+ index = closeIndex + markerLen;
18399
+ continue;
18400
+ }
18401
+ if (line.startsWith("\\[", index) && !isEscapedDelimiterAt(line, sourceIndex)) {
18402
+ context.inMath = true;
18403
+ index += 2;
18404
+ continue;
18405
+ }
18406
+ index++;
18407
+ }
18408
+ return closedOpenMath;
18409
+ }
18410
+ function scanExplicitBracketMathLine(line, context, lineStart, appendStart, openAtAppendStart) {
18411
+ const lineIndent = getMarkdownIndent(line);
18412
+ const listPrefix = stripMarkdownListPrefix(line);
18413
+ if (context.inFence && context.fenceInBlockquote && line.trim() && stripMarkdownBlockquotePrefix(line) == null) resetExplicitBracketFenceContext(context);
18414
+ if (context.inFence && context.fenceInList && line.trim() && lineIndent.column < context.fenceListIndent && !listPrefix) resetExplicitBracketFenceContext(context);
18415
+ if (listPrefix) context.listContentIndent = listPrefix.contentIndent;
18416
+ else if (line.trim() && context.listContentIndent != null && lineIndent.column < context.listContentIndent && !context.inFence) context.listContentIndent = null;
18417
+ if (!context.inMath) {
18418
+ const fenceMatch = matchMarkdownFenceMarker(line);
18419
+ if (fenceMatch) if (context.inFence) {
18420
+ if (fenceMatch.markerChar === context.fenceChar && fenceMatch.markerLen >= context.fenceLen && /^\s*$/.test(fenceMatch.rest)) resetExplicitBracketFenceContext(context);
18421
+ } else {
18422
+ context.inFence = true;
18423
+ context.fenceChar = fenceMatch.markerChar;
18424
+ context.fenceLen = fenceMatch.markerLen;
18425
+ context.fenceInBlockquote = fenceMatch.inBlockquote;
18426
+ context.fenceInList = fenceMatch.inList || context.listContentIndent != null && !fenceMatch.inBlockquote && lineIndent.column >= context.listContentIndent;
18427
+ context.fenceListIndent = fenceMatch.listIndent || context.listContentIndent || 0;
18428
+ }
18429
+ else if (!context.inFence) return scanLineForExplicitBracketMathState(line, context, lineStart, appendStart, openAtAppendStart);
18430
+ } else return scanLineForExplicitBracketMathState(line, context, lineStart, appendStart, openAtAppendStart);
18431
+ return false;
18432
+ }
18433
+ function scanExplicitBracketMathStreamState(source, initialContext = createExplicitBracketMathContext(), appendStart = null, openAtAppendStart = false) {
18434
+ const context = cloneExplicitBracketMathContext(initialContext);
18435
+ let committedContext = cloneExplicitBracketMathContext(initialContext);
18436
+ let lineBuffer = "";
18437
+ let closedOpenMath = false;
18438
+ let index = 0;
18439
+ while (index < source.length) {
18440
+ const newlineIndex = source.indexOf("\n", index);
18441
+ const hasNewline = newlineIndex !== -1;
18442
+ const lineEnd$2 = hasNewline && newlineIndex > index && source[newlineIndex - 1] === "\r" ? newlineIndex - 1 : hasNewline ? newlineIndex : source.length;
18443
+ const line = source.slice(index, lineEnd$2);
18444
+ if (scanExplicitBracketMathLine(line, context, index, appendStart, openAtAppendStart)) closedOpenMath = true;
18445
+ if (hasNewline) {
18446
+ committedContext = cloneExplicitBracketMathContext(context);
18447
+ lineBuffer = "";
18448
+ } else lineBuffer = line;
18449
+ index = hasNewline ? newlineIndex + 1 : source.length;
18450
+ }
18451
+ return {
18452
+ closedOpenMath,
18453
+ state: {
18454
+ committedContext,
18455
+ context,
18456
+ lineBuffer
18457
+ }
18458
+ };
18459
+ }
18460
+ function updateExplicitBracketMathStreamState(previous, appended) {
18461
+ if (appended && !previous.context.inMath && !previous.context.inFence && !previous.committedContext.inFence && !/[\\`~\r\n]/.test(appended) && !(previous.lineBuffer.endsWith("\\") && (appended[0] === "[" || appended[0] === "]"))) return {
18462
+ closedOpenMath: false,
18463
+ state: {
18464
+ committedContext: cloneExplicitBracketMathContext(previous.committedContext),
18465
+ context: cloneExplicitBracketMathContext(previous.context),
18466
+ lineBuffer: previous.lineBuffer + appended
18467
+ }
18468
+ };
18469
+ return scanExplicitBracketMathStreamState(previous.lineBuffer + appended, previous.committedContext, previous.lineBuffer.length, previous.context.inMath);
18470
+ }
18057
18471
  function syncTolerantMathBoundaryStreamCache(md, source) {
18058
18472
  if (!hasMarkstreamMathPlugin(md)) return;
18059
18473
  const stream = md.stream;
@@ -18061,18 +18475,22 @@ function syncTolerantMathBoundaryStreamCache(md, source) {
18061
18475
  const owner = md;
18062
18476
  const previous = tolerantMathBoundaryStreamCache.get(owner);
18063
18477
  if (previous?.source === source) return;
18064
- if (previous && source.startsWith(previous.source)) {
18065
- const appended = source.slice(previous.source.length);
18066
- if (previous.key === null && previous.pendingCandidate === false && !appendedChunkMayAffectTolerantMathBoundary(previous.source, appended) && !sourceEndsWithSplitTolerantBoundaryPrefix(source)) {
18478
+ const sourceExtendsPrevious = previous ? source.startsWith(previous.source) : false;
18479
+ const appended = sourceExtendsPrevious && previous ? source.slice(previous.source.length) : "";
18480
+ const explicitBracketMathUpdate = sourceExtendsPrevious && previous ? updateExplicitBracketMathStreamState(previous.explicitBracketMath, appended) : scanExplicitBracketMathStreamState(source);
18481
+ const nextExplicitBracketMath = explicitBracketMathUpdate.state;
18482
+ const completesExplicitBracketMathClose = sourceExtendsPrevious && previous ? explicitBracketMathUpdate.closedOpenMath : false;
18483
+ if (previous && sourceExtendsPrevious) {
18484
+ if (previous.key === null && previous.pendingCandidate === false && !completesExplicitBracketMathClose && !appendedChunkMayAffectTolerantMathBoundary(previous.source, appended) && !sourceEndsWithSplitTolerantBoundaryPrefix(source)) {
18067
18485
  previous.source = source;
18486
+ previous.explicitBracketMath = nextExplicitBracketMath;
18068
18487
  return;
18069
18488
  }
18070
18489
  }
18071
18490
  const nextKey = getTolerantMathBlockBoundaryStreamKey(source);
18072
- const sourceWasReplaced = previous ? !source.startsWith(previous.source) : false;
18073
- if (previous && (sourceWasReplaced || previous.key !== nextKey)) stream.reset();
18491
+ if (previous && ((previous ? !sourceExtendsPrevious : false) || previous.key !== nextKey || completesExplicitBracketMathClose)) stream.reset();
18074
18492
  else if (!previous && nextKey) stream.reset();
18075
- setTolerantMathBoundaryStreamCache(md, source, nextKey);
18493
+ setTolerantMathBoundaryStreamCache(md, source, nextKey, nextExplicitBracketMath);
18076
18494
  }
18077
18495
  function shouldCloneTopLevelStreamTokens(options) {
18078
18496
  return typeof options.preTransformTokens === "function" || typeof options.postTransformTokens === "function";
@@ -18141,6 +18559,10 @@ function buildParagraphFromInlineChildren(children) {
18141
18559
  raw: children.map(stringifyInlineNodeRaw).join("")
18142
18560
  };
18143
18561
  }
18562
+ function inheritSourceMap(nodes, sourceNode) {
18563
+ if (!sourceNode.sourceMap) return;
18564
+ for (const node of nodes) if (!node.sourceMap) node.sourceMap = sourceNode.sourceMap;
18565
+ }
18144
18566
  function maybePromoteCustomNodeFromParagraph(node, options) {
18145
18567
  if (node.type !== "paragraph") return null;
18146
18568
  const nodeChildren = getNodeFields(node).children;
@@ -18480,7 +18902,7 @@ function combineStructuredDetailsHtmlBlocks(nodes, source, md, options, final, s
18480
18902
  const renderedCloseRaw = explicitClose ? source.slice(closeStart, closeSliceEnd) : closeRaw;
18481
18903
  const mergedRaw = explicitClose ? source.slice(openStart, closeSliceEnd) : source.slice(openStart);
18482
18904
  const contentPrefix = selfContained && openTagEndIndex !== -1 ? openRaw.slice(0, openTagEndIndex + 1) : openRaw;
18483
- merged.push({
18905
+ const detailsNode = {
18484
18906
  ...node,
18485
18907
  tag: "details",
18486
18908
  attrs: parseTagAttrs(openRaw.slice(0, openTagEndIndex + 1)),
@@ -18488,14 +18910,16 @@ function combineStructuredDetailsHtmlBlocks(nodes, source, md, options, final, s
18488
18910
  content: `${contentPrefix}${renderedMiddle}${renderedCloseRaw}`,
18489
18911
  children: [...prefixChildren, ...children],
18490
18912
  loading: !final && !explicitClose
18491
- });
18913
+ };
18914
+ if (options.includeSourceMap) detailsNode.sourceMap = createSourceMapFromOffsets(source, openStart, explicitClose ? closeSliceEnd : source.length, options);
18915
+ merged.push(detailsNode);
18492
18916
  cursor = explicitClose ? closeSliceEnd : source.length;
18493
18917
  if (closeIndex === -1 && !selfContained) break;
18494
18918
  if (closeIndex !== -1) i = closeIndex;
18495
18919
  }
18496
18920
  return [merged, cursor];
18497
18921
  }
18498
- function mergeSplitTopLevelHtmlBlocks(nodes, final, source) {
18922
+ function mergeSplitTopLevelHtmlBlocks(nodes, final, source, options) {
18499
18923
  if (!source) return nodes;
18500
18924
  const merged = nodes.slice();
18501
18925
  let sourceHtmlCursor = 0;
@@ -18528,6 +18952,7 @@ function mergeSplitTopLevelHtmlBlocks(nodes, final, source) {
18528
18952
  node.raw = exact.raw;
18529
18953
  node.loading = desiredLoading;
18530
18954
  node.attrs = exactAttrs.length ? exactAttrs : void 0;
18955
+ if (options?.includeSourceMap) node.sourceMap = createSourceMapFromOffsets(source, exact.start, exact.end, options);
18531
18956
  if (!needsExpansion) continue;
18532
18957
  let tailCursor = findApproximateConsumedPrefixEnd(exact.raw, currentRaw);
18533
18958
  if (tailCursor === -1) tailCursor = 0;
@@ -18694,6 +19119,106 @@ function stripDanglingHtmlLikeTail(markdown) {
18694
19119
  if (!isLikelyHtmlTagPrefix(tail)) return s;
18695
19120
  return s.slice(0, lastLt);
18696
19121
  }
19122
+ function createSourceLineMapper(source, parsedSource) {
19123
+ if (source === parsedSource) return void 0;
19124
+ const sourceLines = source.split(/\r?\n/);
19125
+ const parsedLines = parsedSource.split(/\r?\n/);
19126
+ const mappedLines = [];
19127
+ let sourceCursor = 0;
19128
+ for (let parsedLine = 0; parsedLine < parsedLines.length; parsedLine++) {
19129
+ const line = parsedLines[parsedLine] ?? "";
19130
+ if (sourceLines[sourceCursor] === line) {
19131
+ mappedLines[parsedLine] = {
19132
+ startLine: sourceCursor,
19133
+ endLine: sourceCursor + 1
19134
+ };
19135
+ sourceCursor++;
19136
+ continue;
19137
+ }
19138
+ const sourceLine = sourceLines[sourceCursor] ?? "";
19139
+ if (line !== "" && sourceLine !== line && sourceLine.startsWith(line)) {
19140
+ let joinedLine = line;
19141
+ let splitEnd = -1;
19142
+ for (let nextParsedLine = parsedLine + 1; nextParsedLine < parsedLines.length; nextParsedLine++) {
19143
+ joinedLine += parsedLines[nextParsedLine] ?? "";
19144
+ if (joinedLine === sourceLine) {
19145
+ splitEnd = nextParsedLine;
19146
+ break;
19147
+ }
19148
+ if (!sourceLine.startsWith(joinedLine)) break;
19149
+ }
19150
+ if (splitEnd !== -1) {
19151
+ for (let mappedLine = parsedLine; mappedLine <= splitEnd; mappedLine++) mappedLines[mappedLine] = {
19152
+ startLine: sourceCursor,
19153
+ endLine: sourceCursor + 1
19154
+ };
19155
+ sourceCursor++;
19156
+ parsedLine = splitEnd;
19157
+ continue;
19158
+ }
19159
+ mappedLines[parsedLine] = {
19160
+ startLine: sourceCursor,
19161
+ endLine: sourceCursor + 1
19162
+ };
19163
+ continue;
19164
+ }
19165
+ let collapsedLine = sourceLines[sourceCursor] ?? "";
19166
+ let collapsedEnd = -1;
19167
+ for (let sourceLine$1 = sourceCursor + 1; sourceLine$1 < sourceLines.length; sourceLine$1++) {
19168
+ collapsedLine += `\\n${sourceLines[sourceLine$1] ?? ""}`;
19169
+ if (collapsedLine === line) {
19170
+ collapsedEnd = sourceLine$1 + 1;
19171
+ break;
19172
+ }
19173
+ if (!line.startsWith(collapsedLine)) break;
19174
+ }
19175
+ if (collapsedEnd !== -1) {
19176
+ mappedLines[parsedLine] = {
19177
+ startLine: sourceCursor,
19178
+ endLine: collapsedEnd
19179
+ };
19180
+ sourceCursor = collapsedEnd;
19181
+ continue;
19182
+ }
19183
+ let found = -1;
19184
+ if (line !== "") {
19185
+ const searchEnd = Math.min(sourceLines.length, sourceCursor + 80);
19186
+ for (let sourceLine$1 = sourceCursor; sourceLine$1 < searchEnd; sourceLine$1++) if (sourceLines[sourceLine$1] === line) {
19187
+ found = sourceLine$1;
19188
+ break;
19189
+ }
19190
+ }
19191
+ if (found !== -1) {
19192
+ mappedLines[parsedLine] = {
19193
+ startLine: found,
19194
+ endLine: found + 1
19195
+ };
19196
+ sourceCursor = found + 1;
19197
+ continue;
19198
+ }
19199
+ const fallbackLine = Math.min(Math.max(0, sourceLines.length - 1), Math.max(0, sourceCursor - 1));
19200
+ mappedLines[parsedLine] = {
19201
+ startLine: fallbackLine,
19202
+ endLine: fallbackLine + 1
19203
+ };
19204
+ }
19205
+ return (line) => {
19206
+ const index = Number.isFinite(line) ? Math.max(0, Math.trunc(line)) : 0;
19207
+ if (index < mappedLines.length) return mappedLines[index] ?? {
19208
+ startLine: 0,
19209
+ endLine: 0
19210
+ };
19211
+ const lastMapped = mappedLines[mappedLines.length - 1] ?? {
19212
+ startLine: Math.max(0, sourceLines.length - 1),
19213
+ endLine: sourceLines.length
19214
+ };
19215
+ const startLine = Math.min(sourceLines.length, lastMapped.endLine + index - mappedLines.length);
19216
+ return {
19217
+ startLine,
19218
+ endLine: Math.min(sourceLines.length, startLine + 1)
19219
+ };
19220
+ };
19221
+ }
18697
19222
  function ensureBlankLineBeforeInlineMultilineCustomHtmlBlocks(markdown, tags) {
18698
19223
  if (!markdown || !tags.length) return markdown;
18699
19224
  const tagSet = new Set(tags.map((t) => String(t ?? "").toLowerCase()).filter(Boolean));
@@ -19315,7 +19840,8 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19315
19840
  const timing = getParseTiming(options);
19316
19841
  const parseStartedAt = timing ? getParserNow() : 0;
19317
19842
  const isFinal = !!options.final;
19318
- let safeMarkdown = (markdown ?? "").toString().replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\n(abla|eq|ot|exists)/g, "$1\\n$2");
19843
+ const sourceMarkdown = (markdown ?? "").toString();
19844
+ let safeMarkdown = sourceMarkdown.replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\r?\n(abla|eq|ot|exists)/g, "$1\\n$2");
19319
19845
  if (shouldResetTopLevelStreamCacheForFinalAutoParse(md, options)) {
19320
19846
  md.stream.reset();
19321
19847
  clearTolerantMathBoundaryStreamCache(md);
@@ -19358,6 +19884,13 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19358
19884
  if (!isFinal) safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown);
19359
19885
  const standaloneHtmlDocument = parseStandaloneHtmlDocument(safeMarkdown);
19360
19886
  if (standaloneHtmlDocument) {
19887
+ if (options.includeSourceMap) {
19888
+ const sourceMapOptions = {
19889
+ ...options,
19890
+ __sourceLineMapper: createSourceLineMapper(sourceMarkdown, safeMarkdown)
19891
+ };
19892
+ standaloneHtmlDocument[0].sourceMap = createSourceMapFromOffsets(safeMarkdown, 0, safeMarkdown.length, sourceMapOptions);
19893
+ }
19361
19894
  const preHook = options.preTransformTokens;
19362
19895
  const postHook = options.postTransformTokens;
19363
19896
  if (shouldUseTopLevelStreamParse(md, options) || typeof preHook === "function" || typeof postHook === "function") {
@@ -19365,10 +19898,10 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19365
19898
  const hookedTokens = typeof preHook === "function" ? preHook(rawTokens) || rawTokens : rawTokens;
19366
19899
  if (typeof postHook === "function") postHook(hookedTokens);
19367
19900
  }
19368
- return finishTimedParse(standaloneHtmlDocument, timing, parseStartedAt);
19901
+ return finishParsedNodes(standaloneHtmlDocument, options, timing, parseStartedAt);
19369
19902
  }
19370
19903
  const tokens = parseTopLevelTokens(md, safeMarkdown, { __markstreamFinal: isFinal }, options);
19371
- if (!tokens || !Array.isArray(tokens)) return finishTimedParse([], timing, parseStartedAt);
19904
+ if (!tokens || !Array.isArray(tokens)) return finishParsedNodes([], options, timing, parseStartedAt);
19372
19905
  const pre = options.preTransformTokens;
19373
19906
  const post = options.postTransformTokens;
19374
19907
  let transformedTokens = tokens;
@@ -19379,6 +19912,7 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19379
19912
  ...options,
19380
19913
  validateLink: validateLink$1,
19381
19914
  __markdownIt: md,
19915
+ __sourceLineMapper: options.includeSourceMap === true ? createSourceLineMapper(sourceMarkdown, safeMarkdown) : void 0,
19382
19916
  __sourceMarkdown: safeMarkdown,
19383
19917
  __customHtmlBlockCursor: 0
19384
19918
  };
@@ -19388,13 +19922,16 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19388
19922
  if (Array.isArray(postResult)) {
19389
19923
  const first = postResult[0];
19390
19924
  const firstType = first?.type;
19391
- if (first && typeof firstType === "string") result = processTokensWithTiming(postResult, void 0, timing);
19925
+ if (first && typeof firstType === "string") result = processTokensWithTiming(postResult, {
19926
+ ...internalOptions,
19927
+ __customHtmlBlockCursor: 0
19928
+ }, timing);
19392
19929
  else result = postResult;
19393
19930
  }
19394
19931
  }
19395
- result = mergeSplitTopLevelHtmlBlocks(result, isFinal, safeMarkdown);
19396
- result = combineStructuredDetailsHtmlBlocks(result, safeMarkdown, md, options, isFinal)[0];
19397
- result = structureGenericHtmlBlockChildren(result, md, options, isFinal);
19932
+ result = mergeSplitTopLevelHtmlBlocks(result, isFinal, safeMarkdown, internalOptions);
19933
+ result = combineStructuredDetailsHtmlBlocks(result, safeMarkdown, md, internalOptions, isFinal)[0];
19934
+ result = structureGenericHtmlBlockChildren(result, md, internalOptions, isFinal);
19398
19935
  if (isFinal) {
19399
19936
  const seen = /* @__PURE__ */ new WeakSet();
19400
19937
  const finalizeHtmlBlockLoading = (value) => {
@@ -19411,6 +19948,7 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
19411
19948
  };
19412
19949
  finalizeHtmlBlockLoading(result);
19413
19950
  }
19951
+ result = applyPostTransformNodes(result, options);
19414
19952
  if (options.debug) console.log("Parsed Markdown Tree Structure:", result);
19415
19953
  return finishTimedParse(result, timing, parseStartedAt);
19416
19954
  }
@@ -19418,6 +19956,7 @@ function processTokens(tokens, options) {
19418
19956
  if (!tokens || !Array.isArray(tokens)) return [];
19419
19957
  const result = [];
19420
19958
  const linkifyContext = createLinkifyDemotionContextTracker(options);
19959
+ const includeSourceMap = options?.includeSourceMap === true;
19421
19960
  let i = 0;
19422
19961
  while (i < tokens.length) {
19423
19962
  const handled = parseCommonBlockToken(tokens, i, linkifyContext.options(), containerTokenHandlers);
@@ -19432,9 +19971,12 @@ function processTokens(tokens, options) {
19432
19971
  case "paragraph_open": {
19433
19972
  const paragraphRaw = String(tokens[i + 1]?.content ?? "");
19434
19973
  const paragraphNode = parseParagraph(tokens, i, linkifyContext.options(paragraphRaw));
19974
+ if (includeSourceMap) applyNodeSourceMap(paragraphNode, token, options);
19435
19975
  const promoted = maybePromoteCustomNodeFromParagraph(paragraphNode, options);
19436
- if (promoted) result.push(...promoted);
19437
- else result.push(paragraphNode);
19976
+ if (promoted) {
19977
+ if (includeSourceMap) inheritSourceMap(promoted, paragraphNode);
19978
+ result.push(...promoted);
19979
+ } else result.push(paragraphNode);
19438
19980
  linkifyContext.remember(paragraphNode.raw);
19439
19981
  i += 3;
19440
19982
  break;
@@ -19442,6 +19984,7 @@ function processTokens(tokens, options) {
19442
19984
  case "bullet_list_open":
19443
19985
  case "ordered_list_open": {
19444
19986
  const [listNode, newIndex] = parseList(tokens, i, linkifyContext.options());
19987
+ if (includeSourceMap) applyNodeSourceMap(listNode, token, options);
19445
19988
  result.push(listNode);
19446
19989
  linkifyContext.remember(listNode.raw);
19447
19990
  i = newIndex;
@@ -19449,6 +19992,7 @@ function processTokens(tokens, options) {
19449
19992
  }
19450
19993
  case "blockquote_open": {
19451
19994
  const [blockquoteNode, newIndex] = parseBlockquote(tokens, i, linkifyContext.options());
19995
+ if (includeSourceMap) applyNodeSourceMap(blockquoteNode, token, options);
19452
19996
  result.push(blockquoteNode);
19453
19997
  linkifyContext.remember(blockquoteNode.raw);
19454
19998
  i = newIndex;
@@ -19456,12 +20000,13 @@ function processTokens(tokens, options) {
19456
20000
  }
19457
20001
  case "footnote_anchor": {
19458
20002
  const meta = token.meta ?? {};
19459
- const id = String(meta.label ?? token.content ?? "");
19460
- result.push({
20003
+ const footnoteAnchorNode = {
19461
20004
  type: "footnote_anchor",
19462
- id,
20005
+ id: String(meta.label ?? token.content ?? ""),
19463
20006
  raw: String(token.content ?? "")
19464
- });
20007
+ };
20008
+ if (includeSourceMap) applyNodeSourceMap(footnoteAnchorNode, token, options);
20009
+ result.push(footnoteAnchorNode);
19465
20010
  linkifyContext.remember(String(token.content ?? ""));
19466
20011
  i++;
19467
20012
  break;
@@ -19473,7 +20018,7 @@ function processTokens(tokens, options) {
19473
20018
  break;
19474
20019
  case "text": {
19475
20020
  const content = String(token.content ?? "");
19476
- result.push({
20021
+ const paragraphNode = {
19477
20022
  type: "paragraph",
19478
20023
  raw: content,
19479
20024
  children: content ? [{
@@ -19481,7 +20026,9 @@ function processTokens(tokens, options) {
19481
20026
  content,
19482
20027
  raw: content
19483
20028
  }] : []
19484
- });
20029
+ };
20030
+ if (includeSourceMap) applyNodeSourceMap(paragraphNode, token, options);
20031
+ result.push(paragraphNode);
19485
20032
  linkifyContext.remember(content);
19486
20033
  i++;
19487
20034
  break;
@@ -19490,16 +20037,21 @@ function processTokens(tokens, options) {
19490
20037
  {
19491
20038
  const raw = String(token.content ?? "");
19492
20039
  const parsed = parseInlineTokens(token.children || [], raw, void 0, linkifyContext.options(raw));
19493
- if (parsed.length === 0) {} else if (parsed.every((n) => n.type === "html_block")) result.push(...parsed);
19494
- else {
20040
+ if (parsed.length === 0) {} else if (parsed.every((n) => n.type === "html_block")) {
20041
+ if (includeSourceMap) for (const node of parsed) applyNodeSourceMap(node, token, options);
20042
+ result.push(...parsed);
20043
+ } else {
19495
20044
  const paragraphNode = {
19496
20045
  type: "paragraph",
19497
20046
  raw,
19498
20047
  children: parsed
19499
20048
  };
20049
+ if (includeSourceMap) applyNodeSourceMap(paragraphNode, token, options);
19500
20050
  const promoted = maybePromoteCustomNodeFromParagraph(paragraphNode, options);
19501
- if (promoted) result.push(...promoted);
19502
- else result.push(paragraphNode);
20051
+ if (promoted) {
20052
+ if (includeSourceMap) inheritSourceMap(promoted, paragraphNode);
20053
+ result.push(...promoted);
20054
+ } else result.push(paragraphNode);
19503
20055
  }
19504
20056
  linkifyContext.remember(raw);
19505
20057
  }