stream-markdown-parser 1.0.2 → 1.0.5
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 +19847 -0
- package/dist/index.d.cts +623 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +403 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -10193,7 +10193,14 @@ const NON_STRUCTURING_HTML_TAG_NAMES = [
|
|
|
10193
10193
|
"pre",
|
|
10194
10194
|
"script",
|
|
10195
10195
|
"style",
|
|
10196
|
+
"table",
|
|
10197
|
+
"tbody",
|
|
10198
|
+
"td",
|
|
10199
|
+
"tfoot",
|
|
10200
|
+
"th",
|
|
10201
|
+
"thead",
|
|
10196
10202
|
"textarea",
|
|
10203
|
+
"tr",
|
|
10197
10204
|
"title"
|
|
10198
10205
|
];
|
|
10199
10206
|
const VOID_HTML_TAGS = new Set(VOID_HTML_TAG_NAMES);
|
|
@@ -12712,6 +12719,16 @@ function isMathLike(s) {
|
|
|
12712
12719
|
|
|
12713
12720
|
//#endregion
|
|
12714
12721
|
//#region src/plugins/math.ts
|
|
12722
|
+
const MARKSTREAM_MATH_PLUGIN_APPLIED = "__markstreamMathPluginApplied";
|
|
12723
|
+
const TOLERANT_BOUNDARY_SCAN_MAX_LINES = 80;
|
|
12724
|
+
const TOLERANT_BOUNDARY_SCAN_MAX_CHARS = 2e4;
|
|
12725
|
+
const TOLERANT_BOUNDARY_SCAN_TAIL_CHARS = TOLERANT_BOUNDARY_SCAN_MAX_CHARS + 4096;
|
|
12726
|
+
function hasMarkstreamMathPlugin(md) {
|
|
12727
|
+
return !!md[MARKSTREAM_MATH_PLUGIN_APPLIED];
|
|
12728
|
+
}
|
|
12729
|
+
function markMarkstreamMathPluginApplied(md) {
|
|
12730
|
+
md[MARKSTREAM_MATH_PLUGIN_APPLIED] = true;
|
|
12731
|
+
}
|
|
12715
12732
|
const KATEX_COMMANDS = [
|
|
12716
12733
|
"ldots",
|
|
12717
12734
|
"cdots",
|
|
@@ -12985,6 +13002,233 @@ function findSingleDollarClose(src, startIdx) {
|
|
|
12985
13002
|
}
|
|
12986
13003
|
return -1;
|
|
12987
13004
|
}
|
|
13005
|
+
function findUnescapedDelimiter(src, delimiter$1, startIdx = 0) {
|
|
13006
|
+
let searchPos = Math.max(0, startIdx);
|
|
13007
|
+
while (searchPos < src.length) {
|
|
13008
|
+
const index = src.indexOf(delimiter$1, searchPos);
|
|
13009
|
+
if (index === -1) return -1;
|
|
13010
|
+
if (!isEscapedAt(src, index)) return index;
|
|
13011
|
+
searchPos = index + Math.max(1, delimiter$1.length);
|
|
13012
|
+
}
|
|
13013
|
+
return -1;
|
|
13014
|
+
}
|
|
13015
|
+
function countUnescapedDelimiter(src, delimiter$1, startIdx = 0, endIdx = src.length, excludedRanges = []) {
|
|
13016
|
+
let count = 0;
|
|
13017
|
+
let searchPos = Math.max(0, startIdx);
|
|
13018
|
+
const end = Math.min(src.length, Math.max(0, endIdx));
|
|
13019
|
+
while (searchPos < end) {
|
|
13020
|
+
const index = src.indexOf(delimiter$1, searchPos);
|
|
13021
|
+
if (index === -1 || index >= end) break;
|
|
13022
|
+
const excluded = findRangeAt(excludedRanges, index);
|
|
13023
|
+
if (excluded) {
|
|
13024
|
+
searchPos = Math.max(index + Math.max(1, delimiter$1.length), excluded[1]);
|
|
13025
|
+
continue;
|
|
13026
|
+
}
|
|
13027
|
+
if (!isEscapedAt(src, index)) count++;
|
|
13028
|
+
searchPos = index + Math.max(1, delimiter$1.length);
|
|
13029
|
+
}
|
|
13030
|
+
return count;
|
|
13031
|
+
}
|
|
13032
|
+
function getTolerantBoundaryLineEndOpenIndex(line, openDelim, closeDelim) {
|
|
13033
|
+
const source = trimRightSpaceOrTab(String(line ?? ""));
|
|
13034
|
+
if (!source.endsWith(openDelim)) return -1;
|
|
13035
|
+
const openIndex = source.length - openDelim.length;
|
|
13036
|
+
if (openIndex <= 0) return -1;
|
|
13037
|
+
if (!trimRightSpaceOrTab(source.slice(0, openIndex)).trim()) return -1;
|
|
13038
|
+
if (isEscapedAt(source, openIndex)) return -1;
|
|
13039
|
+
const codeSpanRanges = buildCodeSpanRanges(source);
|
|
13040
|
+
if (findRangeAt(codeSpanRanges, openIndex)) return -1;
|
|
13041
|
+
const previousOpenCount = countUnescapedDelimiter(source, openDelim, 0, openIndex, codeSpanRanges);
|
|
13042
|
+
if (openDelim === "$$") {
|
|
13043
|
+
if (previousOpenCount % 2 === 1) return -1;
|
|
13044
|
+
} else if (previousOpenCount > countUnescapedDelimiter(source, closeDelim, 0, openIndex, codeSpanRanges)) return -1;
|
|
13045
|
+
return openIndex;
|
|
13046
|
+
}
|
|
13047
|
+
function isSpaceOrTab(ch) {
|
|
13048
|
+
return ch === " " || ch === " ";
|
|
13049
|
+
}
|
|
13050
|
+
function trimRightSpaceOrTab(value) {
|
|
13051
|
+
let end = value.length;
|
|
13052
|
+
while (end > 0 && isSpaceOrTab(value[end - 1])) end--;
|
|
13053
|
+
return value.slice(0, end);
|
|
13054
|
+
}
|
|
13055
|
+
function countLineBreaks(value) {
|
|
13056
|
+
let count = 0;
|
|
13057
|
+
for (let index = 0; index < value.length; index++) if (value[index] === "\n") count++;
|
|
13058
|
+
return count;
|
|
13059
|
+
}
|
|
13060
|
+
function isAsciiDigit(ch) {
|
|
13061
|
+
if (!ch) return false;
|
|
13062
|
+
const code$1 = ch.charCodeAt(0);
|
|
13063
|
+
return code$1 >= 48 && code$1 <= 57;
|
|
13064
|
+
}
|
|
13065
|
+
function isThematicLikeLine(trimmed) {
|
|
13066
|
+
if (trimmed.length < 3) return false;
|
|
13067
|
+
const marker = trimmed[0];
|
|
13068
|
+
if (marker !== "-" && marker !== "*" && marker !== "_" && marker !== "=") return false;
|
|
13069
|
+
let markerCount = 0;
|
|
13070
|
+
for (let index = 0; index < trimmed.length; index++) {
|
|
13071
|
+
const ch = trimmed[index];
|
|
13072
|
+
if (ch === marker) {
|
|
13073
|
+
markerCount++;
|
|
13074
|
+
continue;
|
|
13075
|
+
}
|
|
13076
|
+
if (isSpaceOrTab(ch)) continue;
|
|
13077
|
+
return false;
|
|
13078
|
+
}
|
|
13079
|
+
return markerCount >= 3;
|
|
13080
|
+
}
|
|
13081
|
+
function isMarkdownTableDelimiterCell(cell) {
|
|
13082
|
+
const value = cell.trim();
|
|
13083
|
+
if (!value) return false;
|
|
13084
|
+
let index = 0;
|
|
13085
|
+
if (value[index] === ":") index++;
|
|
13086
|
+
let dashCount = 0;
|
|
13087
|
+
while (value[index] === "-") {
|
|
13088
|
+
dashCount++;
|
|
13089
|
+
index++;
|
|
13090
|
+
}
|
|
13091
|
+
if (dashCount < 3) return false;
|
|
13092
|
+
if (value[index] === ":") index++;
|
|
13093
|
+
return index === value.length;
|
|
13094
|
+
}
|
|
13095
|
+
function isMarkdownTableDelimiterLine(trimmed) {
|
|
13096
|
+
if (!trimmed.includes("|")) return false;
|
|
13097
|
+
const withoutLeadingPipe = trimmed[0] === "|" ? trimmed.slice(1) : trimmed;
|
|
13098
|
+
return (withoutLeadingPipe.endsWith("|") ? withoutLeadingPipe.slice(0, -1) : withoutLeadingPipe).split("|").every(isMarkdownTableDelimiterCell);
|
|
13099
|
+
}
|
|
13100
|
+
function isOrderedListBoundaryLine(trimmed) {
|
|
13101
|
+
let index = 0;
|
|
13102
|
+
if (!isAsciiDigit(trimmed[index])) return false;
|
|
13103
|
+
while (isAsciiDigit(trimmed[index])) index++;
|
|
13104
|
+
if (trimmed[index] !== "." && trimmed[index] !== ")") return false;
|
|
13105
|
+
return isSpaceOrTab(trimmed[index + 1]);
|
|
13106
|
+
}
|
|
13107
|
+
function isTolerantBoundaryStopLine(line) {
|
|
13108
|
+
const trimmed = line.trimStart();
|
|
13109
|
+
if (!trimmed) return true;
|
|
13110
|
+
if (trimmed.startsWith("```") || trimmed.startsWith("~~~") || trimmed.startsWith(":::")) return true;
|
|
13111
|
+
if (trimmed[0] === ">" || trimmed[0] === "<") return true;
|
|
13112
|
+
if (trimmed[0] === "#") {
|
|
13113
|
+
let level = 0;
|
|
13114
|
+
while (trimmed[level] === "#") level++;
|
|
13115
|
+
if (level >= 1 && level <= 6 && isSpaceOrTab(trimmed[level])) return true;
|
|
13116
|
+
}
|
|
13117
|
+
if ((trimmed[0] === "-" || trimmed[0] === "+" || trimmed[0] === "*") && isSpaceOrTab(trimmed[1])) return true;
|
|
13118
|
+
if (isOrderedListBoundaryLine(trimmed)) return true;
|
|
13119
|
+
if (isThematicLikeLine(trimmed)) return true;
|
|
13120
|
+
if (isMarkdownTableDelimiterLine(trimmed)) return true;
|
|
13121
|
+
return false;
|
|
13122
|
+
}
|
|
13123
|
+
function appendTolerantBoundaryContent(content, line) {
|
|
13124
|
+
if (!content) return line;
|
|
13125
|
+
if (!line) return content;
|
|
13126
|
+
return `${content}\n${line}`;
|
|
13127
|
+
}
|
|
13128
|
+
function isTolerantMathBlockContent(content) {
|
|
13129
|
+
const stripped = String(content ?? "").trim();
|
|
13130
|
+
if (!stripped) return false;
|
|
13131
|
+
return isMathLike(stripped);
|
|
13132
|
+
}
|
|
13133
|
+
function hashTolerantBoundaryContent(content) {
|
|
13134
|
+
let hash = 0;
|
|
13135
|
+
for (let index = 0; index < content.length; index++) hash = hash * 31 + content.charCodeAt(index) | 0;
|
|
13136
|
+
return hash.toString(36);
|
|
13137
|
+
}
|
|
13138
|
+
function getTolerantBoundaryScanWindow(source) {
|
|
13139
|
+
if (source.length <= TOLERANT_BOUNDARY_SCAN_TAIL_CHARS) return {
|
|
13140
|
+
source,
|
|
13141
|
+
lineOffset: 0
|
|
13142
|
+
};
|
|
13143
|
+
let start = source.length - TOLERANT_BOUNDARY_SCAN_TAIL_CHARS;
|
|
13144
|
+
const nextLineBreak = source.indexOf("\n", start);
|
|
13145
|
+
if (nextLineBreak === -1) return {
|
|
13146
|
+
source: "",
|
|
13147
|
+
lineOffset: countLineBreaks(source)
|
|
13148
|
+
};
|
|
13149
|
+
start = nextLineBreak + 1;
|
|
13150
|
+
return {
|
|
13151
|
+
source: source.slice(start),
|
|
13152
|
+
lineOffset: countLineBreaks(source.slice(0, start))
|
|
13153
|
+
};
|
|
13154
|
+
}
|
|
13155
|
+
function mayContainTolerantMathBlockBoundaryOpener(markdown) {
|
|
13156
|
+
const fullSource = String(markdown ?? "");
|
|
13157
|
+
if (!fullSource || !fullSource.includes("$$") && !fullSource.includes("\\[")) return false;
|
|
13158
|
+
const { source } = getTolerantBoundaryScanWindow(fullSource);
|
|
13159
|
+
if (!source) return false;
|
|
13160
|
+
const lines = source.split(/\r?\n/);
|
|
13161
|
+
const startLine = Math.max(0, lines.length - TOLERANT_BOUNDARY_SCAN_MAX_LINES - 2);
|
|
13162
|
+
const delimiters = [["$$", "$$"], ["\\[", "\\]"]];
|
|
13163
|
+
for (let line = startLine; line < lines.length; line++) {
|
|
13164
|
+
const openingLine = trimRightSpaceOrTab(lines[line]);
|
|
13165
|
+
if (!openingLine) continue;
|
|
13166
|
+
if (isTolerantBoundaryStopLine(openingLine)) continue;
|
|
13167
|
+
for (const [openDelim, closeDelim] of delimiters) if (getTolerantBoundaryLineEndOpenIndex(openingLine, openDelim, closeDelim) !== -1) return true;
|
|
13168
|
+
}
|
|
13169
|
+
return false;
|
|
13170
|
+
}
|
|
13171
|
+
function getTolerantMathBlockBoundaryStreamKey(markdown) {
|
|
13172
|
+
const fullSource = String(markdown ?? "");
|
|
13173
|
+
if (!fullSource || !fullSource.includes("$$") && !fullSource.includes("\\[")) return null;
|
|
13174
|
+
const { source, lineOffset } = getTolerantBoundaryScanWindow(fullSource);
|
|
13175
|
+
if (!source) return null;
|
|
13176
|
+
const lines = source.split(/\r?\n/);
|
|
13177
|
+
const startLine = Math.max(0, lines.length - TOLERANT_BOUNDARY_SCAN_MAX_LINES - 2);
|
|
13178
|
+
const delimiters = [["$$", "$$"], ["\\[", "\\]"]];
|
|
13179
|
+
for (let line = startLine; line < lines.length - 1; line++) {
|
|
13180
|
+
const openingLine = trimRightSpaceOrTab(lines[line]);
|
|
13181
|
+
for (const [openDelim, closeDelim] of delimiters) {
|
|
13182
|
+
const openIndex = getTolerantBoundaryLineEndOpenIndex(openingLine, openDelim, closeDelim);
|
|
13183
|
+
if (openIndex === -1) continue;
|
|
13184
|
+
let content = "";
|
|
13185
|
+
let stopped = false;
|
|
13186
|
+
for (let currentLine = line + 1; currentLine < lines.length; currentLine++) {
|
|
13187
|
+
if (currentLine - line > TOLERANT_BOUNDARY_SCAN_MAX_LINES) {
|
|
13188
|
+
stopped = true;
|
|
13189
|
+
break;
|
|
13190
|
+
}
|
|
13191
|
+
const current = lines[currentLine];
|
|
13192
|
+
const closeIndex = findUnescapedDelimiter(current, closeDelim);
|
|
13193
|
+
if (closeIndex !== -1) {
|
|
13194
|
+
const nextContent = appendTolerantBoundaryContent(content, current.slice(0, closeIndex));
|
|
13195
|
+
if (!isTolerantMathBlockContent(nextContent)) {
|
|
13196
|
+
stopped = true;
|
|
13197
|
+
break;
|
|
13198
|
+
}
|
|
13199
|
+
const suffix = current.slice(closeIndex + closeDelim.length);
|
|
13200
|
+
const suffixKey = suffix.trim() ? `suffix:${hashTolerantBoundaryContent(suffix)}` : "nosuffix";
|
|
13201
|
+
return [
|
|
13202
|
+
"closed",
|
|
13203
|
+
openDelim,
|
|
13204
|
+
lineOffset + line,
|
|
13205
|
+
openIndex,
|
|
13206
|
+
lineOffset + currentLine,
|
|
13207
|
+
closeIndex,
|
|
13208
|
+
hashTolerantBoundaryContent(nextContent),
|
|
13209
|
+
suffixKey
|
|
13210
|
+
].join(":");
|
|
13211
|
+
}
|
|
13212
|
+
if (isTolerantBoundaryStopLine(current)) {
|
|
13213
|
+
stopped = true;
|
|
13214
|
+
break;
|
|
13215
|
+
}
|
|
13216
|
+
content = appendTolerantBoundaryContent(content, current);
|
|
13217
|
+
if (content.length > TOLERANT_BOUNDARY_SCAN_MAX_CHARS) {
|
|
13218
|
+
stopped = true;
|
|
13219
|
+
break;
|
|
13220
|
+
}
|
|
13221
|
+
}
|
|
13222
|
+
if (!stopped && isTolerantMathBlockContent(content)) return [
|
|
13223
|
+
"pending",
|
|
13224
|
+
openDelim,
|
|
13225
|
+
lineOffset + line,
|
|
13226
|
+
openIndex
|
|
13227
|
+
].join(":");
|
|
13228
|
+
}
|
|
13229
|
+
}
|
|
13230
|
+
return null;
|
|
13231
|
+
}
|
|
12988
13232
|
function isLikelyCurrencyRangeDollar(content, nextChar) {
|
|
12989
13233
|
const stripped = String(content ?? "").trim();
|
|
12990
13234
|
if (!stripped) return false;
|
|
@@ -13005,6 +13249,18 @@ function isLikelyPlaceholderDollar(content) {
|
|
|
13005
13249
|
return /^(?:\.{3,}|…+)$/.test(stripped);
|
|
13006
13250
|
}
|
|
13007
13251
|
function applyMath(md, mathOpts) {
|
|
13252
|
+
markMarkstreamMathPluginApplied(md);
|
|
13253
|
+
const pushInlineParagraph = (s, content, line) => {
|
|
13254
|
+
const paragraphContent = String(content ?? "").replace(/^[\t ]+/, "").replace(/[\t ]+$/, "");
|
|
13255
|
+
if (!paragraphContent) return;
|
|
13256
|
+
const paragraphOpen = s.push("paragraph_open", "p", 1);
|
|
13257
|
+
paragraphOpen.map = [line, line + 1];
|
|
13258
|
+
const inlineToken = s.push("inline", "", 0);
|
|
13259
|
+
inlineToken.content = paragraphContent;
|
|
13260
|
+
inlineToken.map = [line, line + 1];
|
|
13261
|
+
inlineToken.children = [];
|
|
13262
|
+
s.push("paragraph_close", "p", -1);
|
|
13263
|
+
};
|
|
13008
13264
|
const mathInline = (state, silent) => {
|
|
13009
13265
|
const s = state;
|
|
13010
13266
|
const strict = !!mathOpts?.strictDelimiters;
|
|
@@ -13020,6 +13276,18 @@ function applyMath(md, mathOpts) {
|
|
|
13020
13276
|
return end;
|
|
13021
13277
|
};
|
|
13022
13278
|
if (/^\*[^*]+/.test(s.src)) return false;
|
|
13279
|
+
if (s.src[s.pos] === "$") {
|
|
13280
|
+
let dollarRunEnd = s.pos + 1;
|
|
13281
|
+
while (s.src[dollarRunEnd] === "$") dollarRunEnd++;
|
|
13282
|
+
const dollarRunLength = dollarRunEnd - s.pos;
|
|
13283
|
+
const nextChar = s.src[dollarRunEnd];
|
|
13284
|
+
if (dollarRunLength >= 3 && (!nextChar || /\s/.test(nextChar))) {
|
|
13285
|
+
const token = s.push("text", "", 0);
|
|
13286
|
+
token.content = s.src.slice(s.pos, dollarRunEnd);
|
|
13287
|
+
s.pos = dollarRunEnd;
|
|
13288
|
+
return true;
|
|
13289
|
+
}
|
|
13290
|
+
}
|
|
13023
13291
|
const delimiters = [
|
|
13024
13292
|
["$$", "$$"],
|
|
13025
13293
|
["$", "$"],
|
|
@@ -13383,6 +13651,8 @@ function applyMath(md, mathOpts) {
|
|
|
13383
13651
|
let openDelim = "";
|
|
13384
13652
|
let closeDelim = "";
|
|
13385
13653
|
let skipFirstLine = false;
|
|
13654
|
+
let prefixBeforeOpen = "";
|
|
13655
|
+
let tolerantBoundary = false;
|
|
13386
13656
|
for (const [open, close] of delimiters) if (lineText.startsWith(open)) if (open.includes("[")) if (mathOpts?.strictDelimiters) {
|
|
13387
13657
|
if (lineText.replace("\\", "") === "[") {
|
|
13388
13658
|
if (startLine + 1 < endLine) {
|
|
@@ -13423,8 +13693,11 @@ function applyMath(md, mathOpts) {
|
|
|
13423
13693
|
closeDelim = close;
|
|
13424
13694
|
break;
|
|
13425
13695
|
}
|
|
13426
|
-
else if (open === "$$"
|
|
13427
|
-
|
|
13696
|
+
else if ((open === "$$" || open === "\\[") && lineText.endsWith(open) && startLine + 1 < endLine) {
|
|
13697
|
+
const openIndex = getTolerantBoundaryLineEndOpenIndex(lineText, open, close);
|
|
13698
|
+
if (openIndex === -1) continue;
|
|
13699
|
+
prefixBeforeOpen = trimRightSpaceOrTab(lineText.slice(0, openIndex));
|
|
13700
|
+
tolerantBoundary = true;
|
|
13428
13701
|
const nextLineStartPos = s.bMarks[startLine + 1] + s.tShift[startLine + 1];
|
|
13429
13702
|
lineText = s.src.slice(nextLineStartPos, s.eMarks[startLine + 1]).trim();
|
|
13430
13703
|
skipFirstLine = true;
|
|
@@ -13434,49 +13707,77 @@ function applyMath(md, mathOpts) {
|
|
|
13434
13707
|
break;
|
|
13435
13708
|
}
|
|
13436
13709
|
if (!matched) return false;
|
|
13437
|
-
if (silent) return true;
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13710
|
+
if (silent && !tolerantBoundary) return true;
|
|
13711
|
+
const startDelimIndex = lineText.indexOf(openDelim);
|
|
13712
|
+
const closeSearchStart = startDelimIndex + openDelim.length;
|
|
13713
|
+
const escapedPlainBracketCloseIndex = !strict && openDelim === "[" ? lineText.indexOf("\\]", closeSearchStart) : -1;
|
|
13714
|
+
const sameLineCloseDelim = escapedPlainBracketCloseIndex >= 0 ? "\\]" : closeDelim;
|
|
13715
|
+
const sameLineCloseIndex = escapedPlainBracketCloseIndex >= 0 ? escapedPlainBracketCloseIndex : findUnescapedDelimiter(lineText, closeDelim, closeSearchStart);
|
|
13716
|
+
if (!skipFirstLine && sameLineCloseIndex > openDelim.length) {
|
|
13717
|
+
const content$1 = lineText.slice(startDelimIndex + openDelim.length, sameLineCloseIndex);
|
|
13442
13718
|
const token$1 = s.push("math_block", "math", 0);
|
|
13443
13719
|
token$1.content = normalizeStandaloneBackslashT(content$1);
|
|
13444
13720
|
token$1.markup = openDelim === "$$" ? "$$" : openDelim === "[" ? "[]" : "\\[\\]";
|
|
13445
13721
|
token$1.map = [startLine, startLine + 1];
|
|
13446
|
-
token$1.raw = `${openDelim}${content$1}${
|
|
13722
|
+
token$1.raw = `${openDelim}${content$1}${sameLineCloseDelim}`;
|
|
13447
13723
|
token$1.block = true;
|
|
13448
13724
|
token$1.loading = false;
|
|
13449
13725
|
s.line = startLine + 1;
|
|
13726
|
+
const trailingAfterClose$1 = lineText.slice(sameLineCloseIndex + sameLineCloseDelim.length);
|
|
13727
|
+
if (trailingAfterClose$1.trim()) pushInlineParagraph(s, trailingAfterClose$1, startLine);
|
|
13450
13728
|
return true;
|
|
13451
13729
|
}
|
|
13452
13730
|
let nextLine = startLine;
|
|
13453
13731
|
let content = "";
|
|
13454
13732
|
let found = false;
|
|
13455
|
-
|
|
13733
|
+
let trailingAfterClose = "";
|
|
13734
|
+
let trailingAfterCloseLine = startLine;
|
|
13735
|
+
const firstLineContent = skipFirstLine ? lineText : lineText === openDelim ? "" : lineText.slice(openDelim.length);
|
|
13456
13736
|
const fallbackPlainBracketClose = !strict && openDelim === "\\[" ? "]" : "";
|
|
13457
|
-
|
|
13458
|
-
|
|
13737
|
+
const firstLineCloseIndex = findUnescapedDelimiter(firstLineContent, closeDelim);
|
|
13738
|
+
if (firstLineCloseIndex !== -1) {
|
|
13739
|
+
const endIndex = firstLineCloseIndex;
|
|
13459
13740
|
content = firstLineContent.slice(0, endIndex);
|
|
13741
|
+
trailingAfterClose = firstLineContent.slice(endIndex + closeDelim.length);
|
|
13742
|
+
trailingAfterCloseLine = skipFirstLine ? startLine + 1 : startLine;
|
|
13460
13743
|
found = true;
|
|
13461
|
-
nextLine =
|
|
13744
|
+
nextLine = trailingAfterCloseLine;
|
|
13462
13745
|
} else {
|
|
13463
13746
|
if (firstLineContent && !skipFirstLine) content = firstLineContent;
|
|
13464
13747
|
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
|
|
13465
13748
|
const lineStart = s.bMarks[nextLine] + s.tShift[nextLine];
|
|
13466
13749
|
const lineEnd = s.eMarks[nextLine];
|
|
13467
13750
|
const currentLine = s.src.slice(lineStart, lineEnd);
|
|
13751
|
+
const currentLineTrimmed = currentLine.trim();
|
|
13752
|
+
if (!strict && openDelim === "[" && currentLineTrimmed === "\\]") {
|
|
13753
|
+
closeDelim = "\\]";
|
|
13754
|
+
found = true;
|
|
13755
|
+
break;
|
|
13756
|
+
}
|
|
13468
13757
|
if (fallbackPlainBracketClose && currentLine.trim() === fallbackPlainBracketClose) {
|
|
13469
13758
|
closeDelim = fallbackPlainBracketClose;
|
|
13470
13759
|
found = true;
|
|
13471
13760
|
break;
|
|
13472
13761
|
}
|
|
13473
|
-
if (
|
|
13762
|
+
if (currentLineTrimmed === closeDelim) {
|
|
13763
|
+
found = true;
|
|
13764
|
+
break;
|
|
13765
|
+
} else if (!strict && openDelim === "[" && currentLine.includes("\\]")) {
|
|
13474
13766
|
found = true;
|
|
13767
|
+
const endIndex = currentLine.indexOf("\\]");
|
|
13768
|
+
closeDelim = "\\]";
|
|
13769
|
+
const beforeClose = currentLine.slice(0, endIndex);
|
|
13770
|
+
if (beforeClose) content += (content ? "\n" : "") + beforeClose;
|
|
13771
|
+
trailingAfterClose = currentLine.slice(endIndex + closeDelim.length);
|
|
13772
|
+
trailingAfterCloseLine = nextLine;
|
|
13475
13773
|
break;
|
|
13476
|
-
} else if (currentLine
|
|
13774
|
+
} else if (findUnescapedDelimiter(currentLine, closeDelim) !== -1) {
|
|
13477
13775
|
found = true;
|
|
13478
|
-
const endIndex = currentLine
|
|
13479
|
-
|
|
13776
|
+
const endIndex = findUnescapedDelimiter(currentLine, closeDelim);
|
|
13777
|
+
const beforeClose = currentLine.slice(0, endIndex);
|
|
13778
|
+
if (beforeClose) content += (content ? "\n" : "") + beforeClose;
|
|
13779
|
+
trailingAfterClose = currentLine.slice(endIndex + closeDelim.length);
|
|
13780
|
+
trailingAfterCloseLine = nextLine;
|
|
13480
13781
|
break;
|
|
13481
13782
|
}
|
|
13482
13783
|
content += (content ? "\n" : "") + currentLine;
|
|
@@ -13484,7 +13785,9 @@ function applyMath(md, mathOpts) {
|
|
|
13484
13785
|
}
|
|
13485
13786
|
if ((!allowLoading || strict) && !found) return false;
|
|
13486
13787
|
const hasMarkdownPrefix = /^\s*!\[/.test(content);
|
|
13487
|
-
if (!(openDelim === "$$" ? !hasMarkdownPrefix : openDelim === "[" ? isPlainBracketMathLike(content) : isMathLike(content))) return false;
|
|
13788
|
+
if (!(tolerantBoundary ? !hasMarkdownPrefix && isTolerantMathBlockContent(content) : openDelim === "$$" ? !hasMarkdownPrefix : openDelim === "[" ? isPlainBracketMathLike(content) : isMathLike(content))) return false;
|
|
13789
|
+
if (silent) return true;
|
|
13790
|
+
if (prefixBeforeOpen) pushInlineParagraph(s, prefixBeforeOpen, startLine);
|
|
13488
13791
|
const token = s.push("math_block", "math", 0);
|
|
13489
13792
|
token.content = normalizeStandaloneBackslashT(content);
|
|
13490
13793
|
token.markup = openDelim === "$$" ? "$$" : openDelim === "[" ? "[]" : "\\[\\]";
|
|
@@ -13493,6 +13796,7 @@ function applyMath(md, mathOpts) {
|
|
|
13493
13796
|
token.block = true;
|
|
13494
13797
|
token.loading = !found;
|
|
13495
13798
|
s.line = nextLine + 1;
|
|
13799
|
+
if (trailingAfterClose.trim()) pushInlineParagraph(s, trailingAfterClose, trailingAfterCloseLine);
|
|
13496
13800
|
return true;
|
|
13497
13801
|
};
|
|
13498
13802
|
const explicitMathBlockBeforeSetext = (state, startLine, endLine, silent) => {
|
|
@@ -16833,6 +17137,8 @@ function parseParagraph(tokens, index, options) {
|
|
|
16833
17137
|
//#endregion
|
|
16834
17138
|
//#region src/parser/index.ts
|
|
16835
17139
|
const streamParseEnvCache = /* @__PURE__ */ new WeakMap();
|
|
17140
|
+
const tolerantMathBoundaryStreamCache = /* @__PURE__ */ new WeakMap();
|
|
17141
|
+
const TOLERANT_BOUNDARY_SPLIT_OPENERS = ["$$", "\\["];
|
|
16836
17142
|
function getNodeFields(node) {
|
|
16837
17143
|
return node;
|
|
16838
17144
|
}
|
|
@@ -17012,13 +17318,89 @@ function shouldResetTopLevelStreamCacheForFinalAutoParse(md, options) {
|
|
|
17012
17318
|
const stream = md.stream;
|
|
17013
17319
|
return options.final === true && streamParse === "auto" && internalOptions.__disableStreamParse !== true && stream?.enabled === true && typeof stream.reset === "function";
|
|
17014
17320
|
}
|
|
17321
|
+
function clearTolerantMathBoundaryStreamCache(md) {
|
|
17322
|
+
tolerantMathBoundaryStreamCache.delete(md);
|
|
17323
|
+
}
|
|
17324
|
+
function setTolerantMathBoundaryStreamCache(md, source, key) {
|
|
17325
|
+
tolerantMathBoundaryStreamCache.set(md, {
|
|
17326
|
+
source,
|
|
17327
|
+
key,
|
|
17328
|
+
pendingCandidate: key === null && mayContainTolerantMathBlockBoundaryOpener(source)
|
|
17329
|
+
});
|
|
17330
|
+
}
|
|
17331
|
+
function sourceEndsWithSplitTolerantBoundaryPrefix(source) {
|
|
17332
|
+
return source.endsWith("$") || source.endsWith("\\");
|
|
17333
|
+
}
|
|
17334
|
+
function sourceEndsWithCompleteTolerantBoundaryOpener(source) {
|
|
17335
|
+
const lastLineStart = Math.max(source.lastIndexOf("\n") + 1, 0);
|
|
17336
|
+
const lastLine = source.slice(lastLineStart).replace(/[\t ]+$/, "");
|
|
17337
|
+
return TOLERANT_BOUNDARY_SPLIT_OPENERS.some((open) => lastLine.endsWith(open));
|
|
17338
|
+
}
|
|
17339
|
+
function appendedChunkMayAffectTolerantMathBoundary(previousSource, appended) {
|
|
17340
|
+
if (!appended) return false;
|
|
17341
|
+
if (appended.includes("$$") || appended.includes("\\[") || appended.includes("\\]")) return true;
|
|
17342
|
+
if (previousSource.endsWith("$") && appended[0] === "$") return true;
|
|
17343
|
+
if (previousSource.endsWith("\\") && (appended[0] === "[" || appended[0] === "]")) return true;
|
|
17344
|
+
if (sourceEndsWithCompleteTolerantBoundaryOpener(previousSource) && /[\r\n]/.test(appended)) return true;
|
|
17345
|
+
return false;
|
|
17346
|
+
}
|
|
17347
|
+
function syncTolerantMathBoundaryStreamCache(md, source) {
|
|
17348
|
+
if (!hasMarkstreamMathPlugin(md)) return;
|
|
17349
|
+
const stream = md.stream;
|
|
17350
|
+
if (typeof stream?.reset !== "function") return;
|
|
17351
|
+
const owner = md;
|
|
17352
|
+
const previous = tolerantMathBoundaryStreamCache.get(owner);
|
|
17353
|
+
if (previous?.source === source) return;
|
|
17354
|
+
if (previous && source.startsWith(previous.source)) {
|
|
17355
|
+
const appended = source.slice(previous.source.length);
|
|
17356
|
+
if (previous.key === null && previous.pendingCandidate === false && !appendedChunkMayAffectTolerantMathBoundary(previous.source, appended) && !sourceEndsWithSplitTolerantBoundaryPrefix(source)) {
|
|
17357
|
+
previous.source = source;
|
|
17358
|
+
return;
|
|
17359
|
+
}
|
|
17360
|
+
}
|
|
17361
|
+
const nextKey = getTolerantMathBlockBoundaryStreamKey(source);
|
|
17362
|
+
const sourceWasReplaced = previous ? !source.startsWith(previous.source) : false;
|
|
17363
|
+
if (previous && (sourceWasReplaced || previous.key !== nextKey)) stream.reset();
|
|
17364
|
+
else if (!previous && nextKey) stream.reset();
|
|
17365
|
+
setTolerantMathBoundaryStreamCache(md, source, nextKey);
|
|
17366
|
+
}
|
|
17015
17367
|
function shouldCloneTopLevelStreamTokens(options) {
|
|
17016
17368
|
return typeof options.preTransformTokens === "function" || typeof options.postTransformTokens === "function";
|
|
17017
17369
|
}
|
|
17370
|
+
function sameTokenMap(left, right) {
|
|
17371
|
+
const leftMap = left?.map;
|
|
17372
|
+
const rightMap = right?.map;
|
|
17373
|
+
if (leftMap === rightMap) return true;
|
|
17374
|
+
if (!Array.isArray(leftMap) || !Array.isArray(rightMap)) return false;
|
|
17375
|
+
return leftMap.length === rightMap.length && leftMap.every((value, index) => value === rightMap[index]);
|
|
17376
|
+
}
|
|
17377
|
+
function isSameTokenShape(left, right) {
|
|
17378
|
+
return !!left && !!right && left.type === right.type && left.tag === right.tag && left.nesting === right.nesting && left.markup === right.markup && left.content === right.content && sameTokenMap(left, right);
|
|
17379
|
+
}
|
|
17380
|
+
function isParagraphTokenTriplet(tokens, index) {
|
|
17381
|
+
return tokens[index]?.type === "paragraph_open" && tokens[index + 1]?.type === "inline" && tokens[index + 2]?.type === "paragraph_close";
|
|
17382
|
+
}
|
|
17383
|
+
function hasAdjacentDuplicateParagraphTokenTriplet(tokens) {
|
|
17384
|
+
for (let index = 0; index + 5 < tokens.length; index++) if (isParagraphTokenTriplet(tokens, index) && isParagraphTokenTriplet(tokens, index + 3) && isSameTokenShape(tokens[index], tokens[index + 3]) && isSameTokenShape(tokens[index + 1], tokens[index + 4]) && isSameTokenShape(tokens[index + 2], tokens[index + 5])) return true;
|
|
17385
|
+
return false;
|
|
17386
|
+
}
|
|
17387
|
+
function shouldFallbackDuplicateTolerantMathStreamTokens(md, source, tokens) {
|
|
17388
|
+
return hasMarkstreamMathPlugin(md) && mayContainTolerantMathBlockBoundaryOpener(source) && hasAdjacentDuplicateParagraphTokenTriplet(tokens);
|
|
17389
|
+
}
|
|
17390
|
+
function shouldUseSyncParseForPendingTolerantMathBoundary(md) {
|
|
17391
|
+
const cache = tolerantMathBoundaryStreamCache.get(md);
|
|
17392
|
+
return typeof cache?.key === "string" && cache.key.startsWith("pending:");
|
|
17393
|
+
}
|
|
17018
17394
|
function parseTopLevelTokens(md, source, env, options) {
|
|
17019
17395
|
if (options.customHtmlTags?.length) env.__markstreamCustomHtmlTags = options.customHtmlTags;
|
|
17020
17396
|
if (!shouldUseTopLevelStreamParse(md, options)) return md.parse(source, env);
|
|
17397
|
+
syncTolerantMathBoundaryStreamCache(md, source);
|
|
17398
|
+
if (shouldUseSyncParseForPendingTolerantMathBoundary(md)) return md.parse(source, env);
|
|
17021
17399
|
const tokens = md.stream.parse(source, getStableStreamEnv(md, env));
|
|
17400
|
+
if (shouldFallbackDuplicateTolerantMathStreamTokens(md, source, tokens)) {
|
|
17401
|
+
md.stream?.reset?.();
|
|
17402
|
+
return md.parse(source, env);
|
|
17403
|
+
}
|
|
17022
17404
|
if (!shouldCloneTopLevelStreamTokens(options)) return tokens;
|
|
17023
17405
|
const timing = getParseTiming(options);
|
|
17024
17406
|
if (!timing) return cloneMarkdownTokens(tokens, true);
|
|
@@ -18224,7 +18606,10 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
|
18224
18606
|
const parseStartedAt = timing ? getParserNow() : 0;
|
|
18225
18607
|
const isFinal = !!options.final;
|
|
18226
18608
|
let safeMarkdown = (markdown ?? "").toString().replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\n(abla|eq|ot|exists)/g, "$1\\n$2");
|
|
18227
|
-
if (shouldResetTopLevelStreamCacheForFinalAutoParse(md, options))
|
|
18609
|
+
if (shouldResetTopLevelStreamCacheForFinalAutoParse(md, options)) {
|
|
18610
|
+
md.stream.reset();
|
|
18611
|
+
clearTolerantMathBoundaryStreamCache(md);
|
|
18612
|
+
}
|
|
18228
18613
|
if (!isFinal) {
|
|
18229
18614
|
if (safeMarkdown.endsWith("- *")) safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*");
|
|
18230
18615
|
if (/(?:^|\n)\s*-\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => {
|