stream-markdown-parser 1.0.0-rc.0 → 1.0.1
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/README.md +17 -0
- package/README.zh-CN.md +16 -0
- package/dist/index.d.ts +23 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +807 -154
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
package/dist/index.js
CHANGED
|
@@ -1621,14 +1621,14 @@ const hasOwn$2 = Object.prototype.hasOwnProperty;
|
|
|
1621
1621
|
function isGlobalMarkdownStateReason(value) {
|
|
1622
1622
|
return value === "reference-definition" || value === "footnote-definition" || value === "abbreviation-definition";
|
|
1623
1623
|
}
|
|
1624
|
-
function isPlainObject(value) {
|
|
1624
|
+
function isPlainObject$1(value) {
|
|
1625
1625
|
if (!value || typeof value !== "object") return false;
|
|
1626
1626
|
const proto = Object.getPrototypeOf(value);
|
|
1627
1627
|
return proto === Object.prototype || proto === null;
|
|
1628
1628
|
}
|
|
1629
1629
|
function cloneSnapshotValue(value) {
|
|
1630
1630
|
if (Array.isArray(value)) return value.map((item) => cloneSnapshotValue(item));
|
|
1631
|
-
if (isPlainObject(value)) {
|
|
1631
|
+
if (isPlainObject$1(value)) {
|
|
1632
1632
|
const out = {};
|
|
1633
1633
|
for (const key of Object.keys(value)) out[key] = cloneSnapshotValue(value[key]);
|
|
1634
1634
|
return out;
|
|
@@ -1637,7 +1637,7 @@ function cloneSnapshotValue(value) {
|
|
|
1637
1637
|
}
|
|
1638
1638
|
function ownKeys(value) {
|
|
1639
1639
|
if (Array.isArray(value)) return value.map((_, index) => String(index));
|
|
1640
|
-
if (isPlainObject(value)) return Object.keys(value);
|
|
1640
|
+
if (isPlainObject$1(value)) return Object.keys(value);
|
|
1641
1641
|
return [];
|
|
1642
1642
|
}
|
|
1643
1643
|
function snapshotValueEquals(left, right) {
|
|
@@ -1647,8 +1647,8 @@ function snapshotValueEquals(left, right) {
|
|
|
1647
1647
|
for (let i = 0; i < left.length; i++) if (!snapshotValueEquals(left[i], right[i])) return false;
|
|
1648
1648
|
return true;
|
|
1649
1649
|
}
|
|
1650
|
-
if (isPlainObject(left) || isPlainObject(right)) {
|
|
1651
|
-
if (!isPlainObject(left) || !isPlainObject(right)) return false;
|
|
1650
|
+
if (isPlainObject$1(left) || isPlainObject$1(right)) {
|
|
1651
|
+
if (!isPlainObject$1(left) || !isPlainObject$1(right)) return false;
|
|
1652
1652
|
const leftKeys = Object.keys(left);
|
|
1653
1653
|
const rightKeys = Object.keys(right);
|
|
1654
1654
|
if (leftKeys.length !== rightKeys.length) return false;
|
|
@@ -1659,7 +1659,7 @@ function snapshotValueEquals(left, right) {
|
|
|
1659
1659
|
}
|
|
1660
1660
|
function getSnapshotKeyValue(value, key) {
|
|
1661
1661
|
if (Array.isArray(value)) return value[Number(key)];
|
|
1662
|
-
if (isPlainObject(value)) return value[key];
|
|
1662
|
+
if (isPlainObject$1(value)) return value[key];
|
|
1663
1663
|
}
|
|
1664
1664
|
function restoreSnapshotValue(target, snapshot) {
|
|
1665
1665
|
if (Array.isArray(target) && Array.isArray(snapshot)) {
|
|
@@ -1667,7 +1667,7 @@ function restoreSnapshotValue(target, snapshot) {
|
|
|
1667
1667
|
for (let i = 0; i < snapshot.length; i++) target[i] = cloneSnapshotValue(snapshot[i]);
|
|
1668
1668
|
return target;
|
|
1669
1669
|
}
|
|
1670
|
-
if (isPlainObject(target) && isPlainObject(snapshot)) {
|
|
1670
|
+
if (isPlainObject$1(target) && isPlainObject$1(snapshot)) {
|
|
1671
1671
|
for (const key of Object.keys(target)) if (!hasOwn$2.call(snapshot, key)) delete target[key];
|
|
1672
1672
|
for (const key of Object.keys(snapshot)) target[key] = cloneSnapshotValue(snapshot[key]);
|
|
1673
1673
|
return target;
|
|
@@ -1677,7 +1677,7 @@ function restoreSnapshotValue(target, snapshot) {
|
|
|
1677
1677
|
function resetOwnedSnapshotValue(env, key, entry) {
|
|
1678
1678
|
const ownedKeys = entry.ownedKeys ?? [];
|
|
1679
1679
|
const target = env[key];
|
|
1680
|
-
if (isPlainObject(target) || Array.isArray(target)) {
|
|
1680
|
+
if (isPlainObject$1(target) || Array.isArray(target)) {
|
|
1681
1681
|
const snapshotKeys = new Set(ownKeys(entry.value));
|
|
1682
1682
|
for (const ownedKey of ownedKeys) if (entry.existed && snapshotKeys.has(ownedKey)) target[ownedKey] = cloneSnapshotValue(getSnapshotKeyValue(entry.value, ownedKey));
|
|
1683
1683
|
else delete target[ownedKey];
|
|
@@ -1749,7 +1749,7 @@ function finalizeKnownGlobalMarkdownState(env) {
|
|
|
1749
1749
|
if (!entry) continue;
|
|
1750
1750
|
entry.ownedKeys = [];
|
|
1751
1751
|
const after = env[key];
|
|
1752
|
-
if (!isPlainObject(after) && !Array.isArray(after)) continue;
|
|
1752
|
+
if (!isPlainObject$1(after) && !Array.isArray(after)) continue;
|
|
1753
1753
|
const beforeKeys = new Set(ownKeys(entry.existed ? entry.value : void 0));
|
|
1754
1754
|
entry.ownedKeys = ownKeys(after).filter((name) => {
|
|
1755
1755
|
if (!beforeKeys.has(name)) return true;
|
|
@@ -10507,6 +10507,134 @@ function tokenToRaw$1(token) {
|
|
|
10507
10507
|
const shape = token;
|
|
10508
10508
|
return String(shape.raw ?? shape.content ?? shape.markup ?? "");
|
|
10509
10509
|
}
|
|
10510
|
+
function getMutableMeta(token) {
|
|
10511
|
+
const target = token;
|
|
10512
|
+
if (!target.meta) target.meta = {};
|
|
10513
|
+
return target.meta;
|
|
10514
|
+
}
|
|
10515
|
+
function setCustomHtmlSourceMeta(token, raw, inner) {
|
|
10516
|
+
const meta = getMutableMeta(token);
|
|
10517
|
+
meta.markstreamCustomHtmlRaw = raw;
|
|
10518
|
+
meta.markstreamCustomHtmlInner = inner;
|
|
10519
|
+
}
|
|
10520
|
+
function attachCustomHtmlSourceMeta(tokens, customTagSet) {
|
|
10521
|
+
if (!customTagSet.size) return;
|
|
10522
|
+
const customTagOpenRes = Array.from(customTagSet, (tag) => new RegExp(String.raw`<\s*${escapeTagForRegExp(tag)}(?=[\s>/])`, "i"));
|
|
10523
|
+
const stack = [];
|
|
10524
|
+
let needsTopLevelSeparator = false;
|
|
10525
|
+
const mayOpenCustomTag = (source) => {
|
|
10526
|
+
if (!source) return false;
|
|
10527
|
+
return customTagOpenRes.some((re) => re.test(source));
|
|
10528
|
+
};
|
|
10529
|
+
const appendToOpenFrames = (raw) => {
|
|
10530
|
+
if (!raw || !stack.length) return;
|
|
10531
|
+
for (const frame of stack) {
|
|
10532
|
+
frame.raw += raw;
|
|
10533
|
+
frame.inner += raw;
|
|
10534
|
+
}
|
|
10535
|
+
};
|
|
10536
|
+
const appendTopLevelSeparator = () => {
|
|
10537
|
+
if (!stack.length || !needsTopLevelSeparator) return;
|
|
10538
|
+
appendToOpenFrames("\n");
|
|
10539
|
+
needsTopLevelSeparator = false;
|
|
10540
|
+
};
|
|
10541
|
+
const appendSourceGap = (gap) => {
|
|
10542
|
+
appendToOpenFrames(gap);
|
|
10543
|
+
};
|
|
10544
|
+
const closeTopFrameWithRaw = (raw) => {
|
|
10545
|
+
for (let i = 0; i < stack.length; i++) {
|
|
10546
|
+
stack[i].raw += raw;
|
|
10547
|
+
if (i < stack.length - 1) stack[i].inner += raw;
|
|
10548
|
+
}
|
|
10549
|
+
const frame = stack.pop();
|
|
10550
|
+
setCustomHtmlSourceMeta(frame.token, frame.raw, frame.inner);
|
|
10551
|
+
};
|
|
10552
|
+
const getTopFrameClosePrefix = (raw) => {
|
|
10553
|
+
const tag = stack[stack.length - 1]?.tag;
|
|
10554
|
+
if (!tag) return null;
|
|
10555
|
+
const closePrefixRe = new RegExp(String.raw`^\s*<\s*\/\s*${escapeTagForRegExp(tag)}\s*>`, "i");
|
|
10556
|
+
return raw.match(closePrefixRe)?.[0] ?? null;
|
|
10557
|
+
};
|
|
10558
|
+
const startsWithTopFrameClose = (source) => {
|
|
10559
|
+
return !!getTopFrameClosePrefix(source);
|
|
10560
|
+
};
|
|
10561
|
+
const handleToken = (child, raw, knownTag) => {
|
|
10562
|
+
const tag = knownTag ?? (child.type === "html_inline" ? getHtmlInlineTagName(raw) : "");
|
|
10563
|
+
if (!(tag && customTagSet.has(tag))) {
|
|
10564
|
+
appendToOpenFrames(raw);
|
|
10565
|
+
return;
|
|
10566
|
+
}
|
|
10567
|
+
const closing = isHtmlInlineClosingTag(raw);
|
|
10568
|
+
const selfClosing = !closing && isSelfClosingHtmlInline(raw, tag);
|
|
10569
|
+
if (closing) {
|
|
10570
|
+
if (!stack.length || stack[stack.length - 1].tag !== tag) {
|
|
10571
|
+
appendToOpenFrames(raw);
|
|
10572
|
+
return;
|
|
10573
|
+
}
|
|
10574
|
+
closeTopFrameWithRaw(raw);
|
|
10575
|
+
return;
|
|
10576
|
+
}
|
|
10577
|
+
appendToOpenFrames(raw);
|
|
10578
|
+
if (selfClosing) {
|
|
10579
|
+
setCustomHtmlSourceMeta(child, raw, "");
|
|
10580
|
+
return;
|
|
10581
|
+
}
|
|
10582
|
+
stack.push({
|
|
10583
|
+
tag,
|
|
10584
|
+
token: child,
|
|
10585
|
+
raw,
|
|
10586
|
+
inner: ""
|
|
10587
|
+
});
|
|
10588
|
+
};
|
|
10589
|
+
for (const token of tokens) {
|
|
10590
|
+
if (token.type === "inline" && Array.isArray(token.children)) {
|
|
10591
|
+
const source = String(token.content ?? "");
|
|
10592
|
+
if (startsWithTopFrameClose(source)) needsTopLevelSeparator = false;
|
|
10593
|
+
else appendTopLevelSeparator();
|
|
10594
|
+
if (!stack.length && !mayOpenCustomTag(source)) {
|
|
10595
|
+
needsTopLevelSeparator = false;
|
|
10596
|
+
continue;
|
|
10597
|
+
}
|
|
10598
|
+
let cursor = 0;
|
|
10599
|
+
let sourceReliable = true;
|
|
10600
|
+
for (const child of token.children) {
|
|
10601
|
+
const childRaw = tokenToRaw$1(child);
|
|
10602
|
+
const tag = child.type === "html_inline" ? getHtmlInlineTagName(childRaw) : "";
|
|
10603
|
+
const isCustomTag = tag && customTagSet.has(tag);
|
|
10604
|
+
let raw = childRaw;
|
|
10605
|
+
if (sourceReliable && source && childRaw && (stack.length || isCustomTag)) {
|
|
10606
|
+
const index = source.indexOf(childRaw, cursor);
|
|
10607
|
+
if (index !== -1) {
|
|
10608
|
+
appendSourceGap(source.slice(cursor, index));
|
|
10609
|
+
raw = source.slice(index, index + childRaw.length);
|
|
10610
|
+
cursor = index + childRaw.length;
|
|
10611
|
+
} else {
|
|
10612
|
+
if (stack.length && !isCustomTag) continue;
|
|
10613
|
+
sourceReliable = false;
|
|
10614
|
+
}
|
|
10615
|
+
}
|
|
10616
|
+
handleToken(child, raw, tag);
|
|
10617
|
+
}
|
|
10618
|
+
if (sourceReliable && source && cursor < source.length && stack.length) appendSourceGap(source.slice(cursor));
|
|
10619
|
+
needsTopLevelSeparator = stack.length > 0;
|
|
10620
|
+
continue;
|
|
10621
|
+
}
|
|
10622
|
+
if (stack.length && typeof token.content === "string") {
|
|
10623
|
+
const raw = tokenToRaw$1(token);
|
|
10624
|
+
const closePrefix = token.type === "html_block" ? getTopFrameClosePrefix(raw) : null;
|
|
10625
|
+
if (closePrefix) {
|
|
10626
|
+
closeTopFrameWithRaw(`${needsTopLevelSeparator ? "\n" : ""}${closePrefix}`);
|
|
10627
|
+
needsTopLevelSeparator = stack.length > 0;
|
|
10628
|
+
continue;
|
|
10629
|
+
}
|
|
10630
|
+
if (!token.content) continue;
|
|
10631
|
+
appendTopLevelSeparator();
|
|
10632
|
+
appendToOpenFrames(token.content);
|
|
10633
|
+
needsTopLevelSeparator = true;
|
|
10634
|
+
}
|
|
10635
|
+
}
|
|
10636
|
+
for (const frame of stack) setCustomHtmlSourceMeta(frame.token, frame.raw, frame.inner);
|
|
10637
|
+
}
|
|
10510
10638
|
function isNonElementHtmlBlock(content) {
|
|
10511
10639
|
return /^\s*<\s*[!?]/.test(content);
|
|
10512
10640
|
}
|
|
@@ -10693,25 +10821,41 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
10693
10821
|
pendingBuffer: pendingAtEnd ?? void 0
|
|
10694
10822
|
};
|
|
10695
10823
|
}
|
|
10824
|
+
const BASE_AUTO_CLOSE_INLINE_TAGS = [
|
|
10825
|
+
"a",
|
|
10826
|
+
"span",
|
|
10827
|
+
"strong",
|
|
10828
|
+
"em",
|
|
10829
|
+
"b",
|
|
10830
|
+
"i",
|
|
10831
|
+
"u"
|
|
10832
|
+
];
|
|
10696
10833
|
function applyFixHtmlInlineTokens(md, options = {}) {
|
|
10697
|
-
const
|
|
10698
|
-
const autoCloseInlineTagSet = new Set([
|
|
10699
|
-
"a",
|
|
10700
|
-
"span",
|
|
10701
|
-
"strong",
|
|
10702
|
-
"em",
|
|
10703
|
-
"b",
|
|
10704
|
-
"i",
|
|
10705
|
-
"u"
|
|
10706
|
-
]);
|
|
10707
|
-
const customTagSet = /* @__PURE__ */ new Set();
|
|
10834
|
+
const configuredCustomTagSet = /* @__PURE__ */ new Set();
|
|
10708
10835
|
if (options.customHtmlTags?.length) for (const t of options.customHtmlTags) {
|
|
10709
10836
|
const name = normalizeCustomHtmlTagName(t);
|
|
10710
10837
|
if (!name) continue;
|
|
10711
|
-
|
|
10712
|
-
autoCloseInlineTagSet.add(name);
|
|
10838
|
+
configuredCustomTagSet.add(name);
|
|
10713
10839
|
}
|
|
10714
|
-
const
|
|
10840
|
+
const getRuleContext = (state) => {
|
|
10841
|
+
const s = state;
|
|
10842
|
+
const customTagSet = new Set(configuredCustomTagSet);
|
|
10843
|
+
const envTags = Array.isArray(s.env?.__markstreamCustomHtmlTags) ? s.env.__markstreamCustomHtmlTags : [];
|
|
10844
|
+
for (const t of envTags) {
|
|
10845
|
+
const name = normalizeCustomHtmlTagName(String(t ?? ""));
|
|
10846
|
+
if (name) customTagSet.add(name);
|
|
10847
|
+
}
|
|
10848
|
+
const commonHtmlTags = buildCommonHtmlTagSet(Array.from(customTagSet));
|
|
10849
|
+
const autoCloseInlineTagSet = new Set(BASE_AUTO_CLOSE_INLINE_TAGS);
|
|
10850
|
+
for (const tag of customTagSet) autoCloseInlineTagSet.add(tag);
|
|
10851
|
+
const shouldMergeHtmlBlockTag = (tag) => customTagSet.has(tag) || !commonHtmlTags.has(tag) || BLOCK_LEVEL_HTML_TAGS.has(tag);
|
|
10852
|
+
return {
|
|
10853
|
+
autoCloseInlineTagSet,
|
|
10854
|
+
commonHtmlTags,
|
|
10855
|
+
customTagSet,
|
|
10856
|
+
shouldMergeHtmlBlockTag
|
|
10857
|
+
};
|
|
10858
|
+
};
|
|
10715
10859
|
const getHtmlBlockCarrierContent = (token) => {
|
|
10716
10860
|
if (token.type === "html_block") return String(token.content ?? "");
|
|
10717
10861
|
if (token.type !== "inline" || !Array.isArray(token.children) || token.children.length !== 1) return "";
|
|
@@ -10725,8 +10869,71 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10725
10869
|
token.raw = content;
|
|
10726
10870
|
token.children = [];
|
|
10727
10871
|
};
|
|
10872
|
+
const stripLeadingLineSeparators = (content) => content.replace(/^(?:\r?\n)+/, "");
|
|
10873
|
+
const isIndentedCodeTrailingContent = (content) => /^(?: {4}|\t)/.test(content);
|
|
10874
|
+
const normalizeIndentedCodeTrailingContent = (content) => content.replace(/^(?: {4}|\t)/gm, "");
|
|
10875
|
+
const createTrailingContentTokens = (content, textMode) => {
|
|
10876
|
+
const source = stripLeadingLineSeparators(content);
|
|
10877
|
+
if (!/\S/.test(source)) return [];
|
|
10878
|
+
if (isIndentedCodeTrailingContent(source)) return [{
|
|
10879
|
+
type: "code_block",
|
|
10880
|
+
content: normalizeIndentedCodeTrailingContent(source),
|
|
10881
|
+
raw: source
|
|
10882
|
+
}];
|
|
10883
|
+
const text$1 = source.replace(/^[\t ]+/, "");
|
|
10884
|
+
if (!text$1) return [];
|
|
10885
|
+
if (text$1.startsWith("<")) return [{
|
|
10886
|
+
type: "html_block",
|
|
10887
|
+
content: text$1
|
|
10888
|
+
}];
|
|
10889
|
+
const inlineToken = {
|
|
10890
|
+
type: "inline",
|
|
10891
|
+
tag: "",
|
|
10892
|
+
nesting: 0,
|
|
10893
|
+
content: text$1,
|
|
10894
|
+
children: [{
|
|
10895
|
+
type: "text",
|
|
10896
|
+
content: text$1,
|
|
10897
|
+
raw: text$1
|
|
10898
|
+
}]
|
|
10899
|
+
};
|
|
10900
|
+
if (textMode === "paragraph") return [
|
|
10901
|
+
{
|
|
10902
|
+
type: "paragraph_open",
|
|
10903
|
+
tag: "p",
|
|
10904
|
+
nesting: 1
|
|
10905
|
+
},
|
|
10906
|
+
inlineToken,
|
|
10907
|
+
{
|
|
10908
|
+
type: "paragraph_close",
|
|
10909
|
+
tag: "p",
|
|
10910
|
+
nesting: -1
|
|
10911
|
+
}
|
|
10912
|
+
];
|
|
10913
|
+
if (textMode === "text") return [{
|
|
10914
|
+
type: "text",
|
|
10915
|
+
content: text$1,
|
|
10916
|
+
raw: text$1
|
|
10917
|
+
}];
|
|
10918
|
+
return [inlineToken];
|
|
10919
|
+
};
|
|
10920
|
+
const getTrailingContentTextMode = (tokens, index, fallback) => {
|
|
10921
|
+
return tokens[index - 1]?.type === "paragraph_open" && tokens[index + 1]?.type === "paragraph_close" ? "inline" : fallback;
|
|
10922
|
+
};
|
|
10923
|
+
const appendTrailingInlineContent = (token, content) => {
|
|
10924
|
+
const source = stripLeadingLineSeparators(content);
|
|
10925
|
+
if (!/\S/.test(source) || token.type !== "inline" || !Array.isArray(token.children)) return false;
|
|
10926
|
+
token.content = `${String(token.content ?? "")}${source}`;
|
|
10927
|
+
token.children.push({
|
|
10928
|
+
type: "text",
|
|
10929
|
+
content: source,
|
|
10930
|
+
raw: source
|
|
10931
|
+
});
|
|
10932
|
+
return true;
|
|
10933
|
+
};
|
|
10728
10934
|
md.core.ruler.after("inline", "fix_html_inline_streaming", (state) => {
|
|
10729
10935
|
const toks = state.tokens ?? [];
|
|
10936
|
+
const { commonHtmlTags, customTagSet } = getRuleContext(state);
|
|
10730
10937
|
for (const t of toks) {
|
|
10731
10938
|
const tok = t;
|
|
10732
10939
|
if (tok.type !== "inline" || !Array.isArray(tok.children)) continue;
|
|
@@ -10752,9 +10959,11 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10752
10959
|
console.error("[applyFixHtmlInlineTokens] failed to fix streaming html inline", e);
|
|
10753
10960
|
}
|
|
10754
10961
|
}
|
|
10962
|
+
attachCustomHtmlSourceMeta(toks, customTagSet);
|
|
10755
10963
|
});
|
|
10756
10964
|
md.core.ruler.push("fix_html_inline_tokens", (state) => {
|
|
10757
10965
|
const toks = state.tokens ?? [];
|
|
10966
|
+
const { autoCloseInlineTagSet, customTagSet, shouldMergeHtmlBlockTag } = getRuleContext(state);
|
|
10758
10967
|
const tagStack = [];
|
|
10759
10968
|
for (let i = 0; i < toks.length; i++) {
|
|
10760
10969
|
const t = toks[i];
|
|
@@ -10777,21 +10986,10 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10777
10986
|
const after = mergedContent.slice(closeRange.end);
|
|
10778
10987
|
openToken.content = before;
|
|
10779
10988
|
openToken.loading = false;
|
|
10780
|
-
const afterTrimmed = after.replace(/^\s+/, "");
|
|
10781
10989
|
toks.splice(i, 1);
|
|
10782
10990
|
tagStack.pop();
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
content: afterTrimmed
|
|
10786
|
-
} : {
|
|
10787
|
-
type: "inline",
|
|
10788
|
-
content: afterTrimmed,
|
|
10789
|
-
children: [{
|
|
10790
|
-
type: "text",
|
|
10791
|
-
content: afterTrimmed,
|
|
10792
|
-
raw: afterTrimmed
|
|
10793
|
-
}]
|
|
10794
|
-
});
|
|
10991
|
+
const replacement = appendTrailingInlineContent(openToken, after) ? [] : createTrailingContentTokens(after, getTrailingContentTextMode(toks, i, "paragraph"));
|
|
10992
|
+
if (replacement.length) toks.splice(i, 0, ...replacement);
|
|
10795
10993
|
i--;
|
|
10796
10994
|
continue;
|
|
10797
10995
|
}
|
|
@@ -10869,16 +11067,24 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10869
11067
|
if (stack.length > 0) {
|
|
10870
11068
|
const top = stack[stack.length - 1];
|
|
10871
11069
|
const openTok = toks[top.index];
|
|
10872
|
-
|
|
10873
|
-
|
|
11070
|
+
const htmlBlockCloseMatch = tok.type === "html_block" ? getCloseRe(top.tag).exec(content) : null;
|
|
11071
|
+
if (htmlBlockCloseMatch) {
|
|
11072
|
+
const closeEnd = htmlBlockCloseMatch.index + htmlBlockCloseMatch[0].length;
|
|
11073
|
+
const closeContent = content.slice(0, closeEnd);
|
|
11074
|
+
const afterContent = content.slice(closeEnd);
|
|
11075
|
+
openTok.content = `${String(openTok.content ?? "")}\n${closeContent}`;
|
|
10874
11076
|
if (Array.isArray(openTok.children)) openTok.children.push({
|
|
10875
11077
|
type: "html_inline",
|
|
10876
11078
|
content: `</${top.tag}>`,
|
|
10877
11079
|
raw: `</${top.tag}>`
|
|
10878
11080
|
});
|
|
10879
|
-
toks.splice(i, 1);
|
|
10880
|
-
i--;
|
|
10881
11081
|
stack.pop();
|
|
11082
|
+
const replacement = appendTrailingInlineContent(openTok, afterContent) ? [] : createTrailingContentTokens(afterContent, getTrailingContentTextMode(toks, i, "paragraph"));
|
|
11083
|
+
if (replacement.length) toks.splice(i, 1, ...replacement);
|
|
11084
|
+
else {
|
|
11085
|
+
toks.splice(i, 1);
|
|
11086
|
+
i--;
|
|
11087
|
+
}
|
|
10882
11088
|
continue;
|
|
10883
11089
|
}
|
|
10884
11090
|
if (tok.type !== "inline") continue;
|
|
@@ -10894,29 +11100,17 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10894
11100
|
const afterText = afterChildren.map((c) => String(c.content ?? c.raw ?? "")).join("");
|
|
10895
11101
|
if (afterText.trim()) {
|
|
10896
11102
|
const trimmed = afterText.replace(/^\s+/, "");
|
|
10897
|
-
if (
|
|
11103
|
+
if (appendTrailingInlineContent(openTok, afterText)) {
|
|
11104
|
+
toks.splice(i, 1);
|
|
11105
|
+
i--;
|
|
11106
|
+
} else if (trimmed.startsWith("<")) toks.splice(i, 1, {
|
|
10898
11107
|
type: "html_block",
|
|
10899
11108
|
content: trimmed
|
|
10900
11109
|
});
|
|
10901
|
-
else
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
}, {
|
|
10906
|
-
type: "inline",
|
|
10907
|
-
tag: "",
|
|
10908
|
-
nesting: 0,
|
|
10909
|
-
content: afterText,
|
|
10910
|
-
children: [{
|
|
10911
|
-
type: "text",
|
|
10912
|
-
content: afterText,
|
|
10913
|
-
raw: afterText
|
|
10914
|
-
}]
|
|
10915
|
-
}, {
|
|
10916
|
-
type: "paragraph_close",
|
|
10917
|
-
tag: "p",
|
|
10918
|
-
nesting: -1
|
|
10919
|
-
});
|
|
11110
|
+
else {
|
|
11111
|
+
const replacement = createTrailingContentTokens(afterText, getTrailingContentTextMode(toks, i, "paragraph"));
|
|
11112
|
+
toks.splice(i, 1, ...replacement);
|
|
11113
|
+
}
|
|
10920
11114
|
} else {
|
|
10921
11115
|
toks.splice(i, 1);
|
|
10922
11116
|
i--;
|
|
@@ -10989,15 +11183,8 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10989
11183
|
}];
|
|
10990
11184
|
t.content = rawForNode;
|
|
10991
11185
|
t.raw = rawForNode;
|
|
10992
|
-
const
|
|
10993
|
-
if (
|
|
10994
|
-
type: "html_block",
|
|
10995
|
-
content: afterTrimmed
|
|
10996
|
-
} : {
|
|
10997
|
-
type: "text",
|
|
10998
|
-
content: afterTrimmed,
|
|
10999
|
-
raw: afterTrimmed
|
|
11000
|
-
});
|
|
11186
|
+
const replacement = createTrailingContentTokens(raw$2.slice(endTagIndex$1 + closeLen$1) || "", "text");
|
|
11187
|
+
if (replacement.length) toks.splice(i + 1, 0, ...replacement);
|
|
11001
11188
|
} else t.children = [{
|
|
11002
11189
|
type: tag,
|
|
11003
11190
|
content: "",
|
|
@@ -11194,7 +11381,7 @@ function applyFixIndentedCodeBlock(md, options = {}) {
|
|
|
11194
11381
|
|
|
11195
11382
|
//#endregion
|
|
11196
11383
|
//#region src/parser/linkifyHeuristics.ts
|
|
11197
|
-
const FILENAMEISH_EXTENSION_RE = /\.([a-z0-9]{1,
|
|
11384
|
+
const FILENAMEISH_EXTENSION_RE = /\.([a-z0-9]{1,15})$/i;
|
|
11198
11385
|
const FILENAMEISH_SEGMENT_RE = /[_()[\]{}<>]/u;
|
|
11199
11386
|
const URL_PREFIX_HINT_RE = /^(?:https?:\/\/|ftp:\/\/|mailto:|www\.)/i;
|
|
11200
11387
|
const URL_QUERY_OR_AUTH_HINT_RE = /[?#@]/u;
|
|
@@ -11202,7 +11389,11 @@ const PATH_SEPARATOR_RE = /[\\/]/u;
|
|
|
11202
11389
|
const DOMAINISH_TEXT_RE = /^[\p{L}\p{N}./\\-]+$/u;
|
|
11203
11390
|
const DOMAIN_LABEL_RE = /^[A-Za-z0-9-]{1,63}$/u;
|
|
11204
11391
|
const PUNYCODE_TLD_RE = /^xn--[a-z0-9-]{2,59}$/i;
|
|
11205
|
-
const
|
|
11392
|
+
const MARKET_TICKER_SYMBOL_RE = /^(?:[A-Z]{1,6}|\d{1,8})$/u;
|
|
11393
|
+
const MARKET_TICKER_CONTEXT_SYMBOL_RE = /^(?=.{1,12}$)[A-Z0-9]+(?:[-.][A-Z0-9]+)*$/iu;
|
|
11394
|
+
const EXPLICIT_FILENAME_CONTEXT_RE = /文件名\s*[::]?|附件\s*[::]?|路径\s*[::]?|路徑\s*[::]?|文件列表\s*[::]?|文档列表\s*[::]?|文檔列表\s*[::]?|\bfile\s*names?\b\s*[::]?|\battachments?\b\s*[::]?|\bpaths?\b\s*[::]?|\bfile\s+lists?\b\s*[::]?|\bdocument\s+lists?\b\s*[::]?/iu;
|
|
11395
|
+
const FILENAME_CONTEXT_RE = /文件名\s*[::]?|文件\s*[::]?|附件\s*[::]?|档案\s*[::]?|檔案\s*[::]?|文档\s*[::]?|文檔\s*[::]?|资料\s*[::]?|資料\s*[::]?|路径\s*[::]?|路徑\s*[::]?|\bfile\s*name\b\s*[::]?|\battachments?\b\s*[::]?|\bfiles?\b\s*[::]?|\bdocuments?\b\s*[::]?|\bdocs?\b\s*[::]?|\bpaths?\b\s*[::]?/iu;
|
|
11396
|
+
const MARKET_TICKER_CONTEXT_RE = /股票代码|股票代碼|证券代码|證券代碼|(?:代码|代碼|交易所|后缀|後綴|市场|市場)(?=$|[\s::/|,,、()()])|\btickers?\b|\bsymbols?\b|\bexchanges?\b/iu;
|
|
11206
11397
|
const AMBIGUOUS_BARE_DOMAIN_EXTENSIONS = new Set([
|
|
11207
11398
|
"ai",
|
|
11208
11399
|
"md",
|
|
@@ -11211,6 +11402,57 @@ const AMBIGUOUS_BARE_DOMAIN_EXTENSIONS = new Set([
|
|
|
11211
11402
|
"sh",
|
|
11212
11403
|
"zip"
|
|
11213
11404
|
]);
|
|
11405
|
+
const MARKET_TICKER_SUFFIXES = new Set([
|
|
11406
|
+
"as",
|
|
11407
|
+
"bj",
|
|
11408
|
+
"de",
|
|
11409
|
+
"hk",
|
|
11410
|
+
"l",
|
|
11411
|
+
"ln",
|
|
11412
|
+
"ny",
|
|
11413
|
+
"pa",
|
|
11414
|
+
"sh",
|
|
11415
|
+
"ss",
|
|
11416
|
+
"sz",
|
|
11417
|
+
"t",
|
|
11418
|
+
"us"
|
|
11419
|
+
]);
|
|
11420
|
+
const MARKET_TICKER_CONTEXT_SUFFIXES = new Set([
|
|
11421
|
+
...MARKET_TICKER_SUFFIXES,
|
|
11422
|
+
"at",
|
|
11423
|
+
"ax",
|
|
11424
|
+
"cn",
|
|
11425
|
+
"co",
|
|
11426
|
+
"it",
|
|
11427
|
+
"jp",
|
|
11428
|
+
"ks",
|
|
11429
|
+
"mc",
|
|
11430
|
+
"mx",
|
|
11431
|
+
"nz",
|
|
11432
|
+
"pl",
|
|
11433
|
+
"sa",
|
|
11434
|
+
"si",
|
|
11435
|
+
"to",
|
|
11436
|
+
"tw"
|
|
11437
|
+
]);
|
|
11438
|
+
const EXPLICIT_FILENAME_CONTEXT_ONLY_EXTENSIONS = new Set([
|
|
11439
|
+
"com",
|
|
11440
|
+
"dev",
|
|
11441
|
+
"io",
|
|
11442
|
+
"page",
|
|
11443
|
+
"site"
|
|
11444
|
+
]);
|
|
11445
|
+
const FILENAME_CONTEXT_ONLY_EXTENSIONS = new Set([
|
|
11446
|
+
"app",
|
|
11447
|
+
"apk",
|
|
11448
|
+
"dmg",
|
|
11449
|
+
"exe",
|
|
11450
|
+
"ipa",
|
|
11451
|
+
"lock",
|
|
11452
|
+
"log",
|
|
11453
|
+
"markdown",
|
|
11454
|
+
"webmanifest"
|
|
11455
|
+
]);
|
|
11214
11456
|
const FILENAMEISH_LINK_EXTENSIONS = new Set([
|
|
11215
11457
|
"7z",
|
|
11216
11458
|
"ai",
|
|
@@ -11278,6 +11520,65 @@ const FILENAMEISH_LINK_EXTENSIONS = new Set([
|
|
|
11278
11520
|
"zip",
|
|
11279
11521
|
"zsh"
|
|
11280
11522
|
]);
|
|
11523
|
+
function hasLinkifyDemotionContext(context) {
|
|
11524
|
+
return context?.filename === true || context?.explicitFilename === true || context?.marketTicker === true;
|
|
11525
|
+
}
|
|
11526
|
+
function mergeLinkifyDemotionContext(left, right) {
|
|
11527
|
+
const merged = {
|
|
11528
|
+
filename: left?.filename || right?.filename,
|
|
11529
|
+
explicitFilename: left?.explicitFilename || right?.explicitFilename,
|
|
11530
|
+
marketTicker: left?.marketTicker || right?.marketTicker
|
|
11531
|
+
};
|
|
11532
|
+
return hasLinkifyDemotionContext(merged) ? merged : void 0;
|
|
11533
|
+
}
|
|
11534
|
+
function withLinkifyDemotionContext(options, context) {
|
|
11535
|
+
if (!hasLinkifyDemotionContext(context)) return options;
|
|
11536
|
+
const inheritedContext = options?.__linkifyDemotionContext;
|
|
11537
|
+
return {
|
|
11538
|
+
...options,
|
|
11539
|
+
__linkifyDemotionContext: {
|
|
11540
|
+
filename: inheritedContext?.filename || context?.filename,
|
|
11541
|
+
explicitFilename: inheritedContext?.explicitFilename || context?.explicitFilename,
|
|
11542
|
+
marketTicker: inheritedContext?.marketTicker || context?.marketTicker
|
|
11543
|
+
}
|
|
11544
|
+
};
|
|
11545
|
+
}
|
|
11546
|
+
function inferNextBlockLinkifyContext(raw) {
|
|
11547
|
+
const context = inferLinkifyDemotionContext(raw);
|
|
11548
|
+
return hasLinkifyDemotionContext(context) ? context : void 0;
|
|
11549
|
+
}
|
|
11550
|
+
function normalizeStandaloneContinuationText(text$1) {
|
|
11551
|
+
return text$1.replace(/^[\s>*_`[\]((【《"'“‘]+/u, "").replace(/[\s<*_`\]))】》"'.。;;,,、::!?!?]+$/u, "");
|
|
11552
|
+
}
|
|
11553
|
+
function inferContinuationLinkifyContext(raw, inherited) {
|
|
11554
|
+
if (!hasLinkifyDemotionContext(inherited)) return void 0;
|
|
11555
|
+
const parts = String(raw ?? "").trim().split(/\s+/u).map(normalizeStandaloneContinuationText).filter(Boolean);
|
|
11556
|
+
if (parts.length === 0) return void 0;
|
|
11557
|
+
const continuation = {};
|
|
11558
|
+
if (inherited?.filename && parts.every((part) => shouldDemoteFilenameLikeLinkify(part, {
|
|
11559
|
+
filename: true,
|
|
11560
|
+
explicitFilename: inherited.explicitFilename
|
|
11561
|
+
}))) continuation.filename = true;
|
|
11562
|
+
if (inherited?.explicitFilename && continuation.filename) continuation.explicitFilename = true;
|
|
11563
|
+
if (inherited?.marketTicker && parts.every((part) => shouldDemoteFilenameLikeLinkify(part, { marketTicker: true }))) continuation.marketTicker = true;
|
|
11564
|
+
return hasLinkifyDemotionContext(continuation) ? continuation : void 0;
|
|
11565
|
+
}
|
|
11566
|
+
function createLinkifyDemotionContextTracker(options, sticky = false) {
|
|
11567
|
+
let context;
|
|
11568
|
+
return {
|
|
11569
|
+
options(raw) {
|
|
11570
|
+
if (sticky || raw == null) return withLinkifyDemotionContext(options, context);
|
|
11571
|
+
return withLinkifyDemotionContext(options, mergeLinkifyDemotionContext(inferNextBlockLinkifyContext(raw), inferContinuationLinkifyContext(raw, context)));
|
|
11572
|
+
},
|
|
11573
|
+
remember(raw) {
|
|
11574
|
+
const nextContext = inferNextBlockLinkifyContext(raw);
|
|
11575
|
+
context = sticky ? mergeLinkifyDemotionContext(context, nextContext) : mergeLinkifyDemotionContext(nextContext, inferContinuationLinkifyContext(raw, context));
|
|
11576
|
+
},
|
|
11577
|
+
reset() {
|
|
11578
|
+
context = void 0;
|
|
11579
|
+
}
|
|
11580
|
+
};
|
|
11581
|
+
}
|
|
11281
11582
|
function isValidDomainLabel(label) {
|
|
11282
11583
|
return DOMAIN_LABEL_RE.test(label) && !label.startsWith("-") && !label.endsWith("-");
|
|
11283
11584
|
}
|
|
@@ -11288,6 +11589,27 @@ function isPlausibleBareDomain(text$1) {
|
|
|
11288
11589
|
if (!(isValidDomainLabel(tld) || PUNYCODE_TLD_RE.test(tld))) return false;
|
|
11289
11590
|
return labels.every(isValidDomainLabel);
|
|
11290
11591
|
}
|
|
11592
|
+
function hasNonAsciiText(input) {
|
|
11593
|
+
return Array.from(input).some((char) => char.charCodeAt(0) > 127);
|
|
11594
|
+
}
|
|
11595
|
+
function getHrefAuthority(href) {
|
|
11596
|
+
return href.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").split(/[/?#]/, 1)[0] ?? "";
|
|
11597
|
+
}
|
|
11598
|
+
function hasPunycodeAuthorityLabel(authority) {
|
|
11599
|
+
return authority.split(".").some((label) => label.toLowerCase().startsWith("xn--"));
|
|
11600
|
+
}
|
|
11601
|
+
function isDecodedFromRawPunycode(linkText, href, raw) {
|
|
11602
|
+
const authority = getHrefAuthority(href);
|
|
11603
|
+
return hasNonAsciiText(linkText) && hasPunycodeAuthorityLabel(authority) && String(raw ?? "").toLowerCase().includes(authority.toLowerCase());
|
|
11604
|
+
}
|
|
11605
|
+
function inferLinkifyDemotionContext(contextText) {
|
|
11606
|
+
const text$1 = String(contextText ?? "");
|
|
11607
|
+
return {
|
|
11608
|
+
explicitFilename: EXPLICIT_FILENAME_CONTEXT_RE.test(text$1),
|
|
11609
|
+
filename: FILENAME_CONTEXT_RE.test(text$1),
|
|
11610
|
+
marketTicker: MARKET_TICKER_CONTEXT_RE.test(text$1)
|
|
11611
|
+
};
|
|
11612
|
+
}
|
|
11291
11613
|
function hasDomainAuthorityPrefix(text$1) {
|
|
11292
11614
|
return isPlausibleBareDomain(text$1.split(/[\\/]/)[0] ?? "");
|
|
11293
11615
|
}
|
|
@@ -11300,16 +11622,28 @@ function hasStrongFilenameSignals(linkText) {
|
|
|
11300
11622
|
if (!DOMAINISH_TEXT_RE.test(linkText)) return true;
|
|
11301
11623
|
if (PATH_SEPARATOR_RE.test(linkText)) return !hasDomainAuthorityPrefix(linkText);
|
|
11302
11624
|
const extensionless = linkText.replace(FILENAMEISH_EXTENSION_RE, "");
|
|
11303
|
-
if (
|
|
11625
|
+
if (hasNonAsciiText(extensionless)) return true;
|
|
11304
11626
|
return extensionless.split(".").filter(Boolean).some(isUppercaseFilenameSegment);
|
|
11305
11627
|
}
|
|
11306
|
-
function
|
|
11628
|
+
function isMarketTickerLikeText(linkText, extension, hasMarketTickerContext) {
|
|
11629
|
+
if (!(hasMarketTickerContext ? MARKET_TICKER_CONTEXT_SUFFIXES : MARKET_TICKER_SUFFIXES).has(extension)) return false;
|
|
11630
|
+
const symbol = linkText.slice(0, -(extension.length + 1));
|
|
11631
|
+
if (symbol === "") return linkText.startsWith(".");
|
|
11632
|
+
return (hasMarketTickerContext ? MARKET_TICKER_CONTEXT_SYMBOL_RE : MARKET_TICKER_SYMBOL_RE).test(symbol);
|
|
11633
|
+
}
|
|
11634
|
+
function shouldDemoteFilenameLikeLinkify(linkText, context = {}) {
|
|
11307
11635
|
if (!linkText || URL_PREFIX_HINT_RE.test(linkText) || URL_QUERY_OR_AUTH_HINT_RE.test(linkText)) return false;
|
|
11308
11636
|
const extensionMatch = linkText.match(FILENAMEISH_EXTENSION_RE);
|
|
11309
11637
|
if (!extensionMatch) return false;
|
|
11310
11638
|
const extension = String(extensionMatch[1] ?? "").toLowerCase();
|
|
11311
|
-
if (
|
|
11639
|
+
if (isMarketTickerLikeText(linkText, extension, context.marketTicker === true)) return true;
|
|
11640
|
+
if (!FILENAMEISH_LINK_EXTENSIONS.has(extension)) {
|
|
11641
|
+
if (context.explicitFilename && EXPLICIT_FILENAME_CONTEXT_ONLY_EXTENSIONS.has(extension)) return true;
|
|
11642
|
+
if (context.filename && FILENAME_CONTEXT_ONLY_EXTENSIONS.has(extension)) return true;
|
|
11643
|
+
return false;
|
|
11644
|
+
}
|
|
11312
11645
|
if (!AMBIGUOUS_BARE_DOMAIN_EXTENSIONS.has(extension)) return true;
|
|
11646
|
+
if (context.filename) return true;
|
|
11313
11647
|
return hasStrongFilenameSignals(linkText);
|
|
11314
11648
|
}
|
|
11315
11649
|
|
|
@@ -11439,16 +11773,17 @@ function applyFixLinkTokens(md) {
|
|
|
11439
11773
|
for (let i = 0; i < toks.length; i++) {
|
|
11440
11774
|
const t = toks[i];
|
|
11441
11775
|
if (t && t.type === "inline" && Array.isArray(t.children)) try {
|
|
11442
|
-
t.children = fixLinkToken(t.children);
|
|
11776
|
+
t.children = fixLinkToken(t.children, typeof t.content === "string" ? t.content : void 0);
|
|
11443
11777
|
} catch (e) {
|
|
11444
11778
|
console.error("[applyFixLinkTokens] failed to fix inline children", e);
|
|
11445
11779
|
}
|
|
11446
11780
|
}
|
|
11447
11781
|
});
|
|
11448
11782
|
}
|
|
11449
|
-
function fixLinkToken(tokens) {
|
|
11783
|
+
function fixLinkToken(tokens, raw) {
|
|
11450
11784
|
if (tokens.length < 3) return tokens;
|
|
11451
11785
|
if (tokens.some((token) => token.type === "code_inline")) return tokens;
|
|
11786
|
+
const linkifyDemotionContext = inferLinkifyDemotionContext(raw);
|
|
11452
11787
|
for (let i = 0; i <= tokens.length - 1; i++) {
|
|
11453
11788
|
if (i < 0) i = 0;
|
|
11454
11789
|
const curToken = tokens[i];
|
|
@@ -11461,11 +11796,11 @@ function fixLinkToken(tokens) {
|
|
|
11461
11796
|
}
|
|
11462
11797
|
if (closeIdx !== -1) {
|
|
11463
11798
|
const linkText = collectLinkifyText(tokens, i, closeIdx);
|
|
11464
|
-
|
|
11799
|
+
const href = getHrefFromLinkOpen(curToken);
|
|
11800
|
+
if (curToken.markup === "linkify" && linkText && !isDecodedFromRawPunycode(linkText, href, raw) && shouldDemoteFilenameLikeLinkify(linkText, linkifyDemotionContext)) {
|
|
11465
11801
|
tokens.splice(i, closeIdx - i + 1, textToken(linkText));
|
|
11466
11802
|
continue;
|
|
11467
11803
|
}
|
|
11468
|
-
const href = getHrefFromLinkOpen(curToken);
|
|
11469
11804
|
const hrefStop = firstIndexOfAny(href, LINKIFY_HARD_STOP_CHARS);
|
|
11470
11805
|
for (let j = i + 1; j < closeIdx; j++) {
|
|
11471
11806
|
const t = tokens[j];
|
|
@@ -13111,6 +13446,7 @@ function applyMath(md, mathOpts) {
|
|
|
13111
13446
|
let content = "";
|
|
13112
13447
|
let found = false;
|
|
13113
13448
|
const firstLineContent = lineText === openDelim ? "" : lineText.slice(openDelim.length);
|
|
13449
|
+
const fallbackPlainBracketClose = !strict && openDelim === "\\[" ? "]" : "";
|
|
13114
13450
|
if (firstLineContent.includes(closeDelim)) {
|
|
13115
13451
|
const endIndex = firstLineContent.indexOf(closeDelim);
|
|
13116
13452
|
content = firstLineContent.slice(0, endIndex);
|
|
@@ -13122,6 +13458,11 @@ function applyMath(md, mathOpts) {
|
|
|
13122
13458
|
const lineStart = s.bMarks[nextLine] + s.tShift[nextLine];
|
|
13123
13459
|
const lineEnd = s.eMarks[nextLine];
|
|
13124
13460
|
const currentLine = s.src.slice(lineStart, lineEnd);
|
|
13461
|
+
if (fallbackPlainBracketClose && currentLine.trim() === fallbackPlainBracketClose) {
|
|
13462
|
+
closeDelim = fallbackPlainBracketClose;
|
|
13463
|
+
found = true;
|
|
13464
|
+
break;
|
|
13465
|
+
}
|
|
13125
13466
|
if (currentLine.trim() === closeDelim) {
|
|
13126
13467
|
found = true;
|
|
13127
13468
|
break;
|
|
@@ -13288,6 +13629,11 @@ const DIFF_HEADER_PREFIXES = [
|
|
|
13288
13629
|
"@@ "
|
|
13289
13630
|
];
|
|
13290
13631
|
const NEWLINE_RE = /\r?\n/;
|
|
13632
|
+
function isPotentialDiffMetadataTail(line) {
|
|
13633
|
+
const value = String(line ?? "");
|
|
13634
|
+
if (!value) return false;
|
|
13635
|
+
return DIFF_HEADER_PREFIXES.some((prefix) => prefix.startsWith(value) || value.startsWith(prefix));
|
|
13636
|
+
}
|
|
13291
13637
|
function flushPendingDiffHunk(orig, updated, pendingOrig, pendingUpdated) {
|
|
13292
13638
|
if (pendingOrig.length > 0) orig.push(...pendingOrig);
|
|
13293
13639
|
if (pendingUpdated.length > 0) updated.push(...pendingUpdated);
|
|
@@ -13300,7 +13646,7 @@ function splitUnifiedDiff(content, closed) {
|
|
|
13300
13646
|
const pendingOrig = [];
|
|
13301
13647
|
const pendingUpdated = [];
|
|
13302
13648
|
const lines = content.split(NEWLINE_RE);
|
|
13303
|
-
const
|
|
13649
|
+
const endsWithNewline = /\r?\n$/.test(content);
|
|
13304
13650
|
const hasUnifiedDiffHeaders = lines.some((line) => line.startsWith("diff ") || line.startsWith("--- ") || line.startsWith("+++ ") || line.startsWith("@@ "));
|
|
13305
13651
|
const processLine = (rawLine) => {
|
|
13306
13652
|
const line = rawLine;
|
|
@@ -13318,18 +13664,25 @@ function splitUnifiedDiff(content, closed) {
|
|
|
13318
13664
|
updated.push(contextLine);
|
|
13319
13665
|
}
|
|
13320
13666
|
};
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
13667
|
+
const lineCountToProcess = endsWithNewline ? Math.max(0, lines.length - 1) : lines.length;
|
|
13668
|
+
for (let index = 0; index < lineCountToProcess; index++) {
|
|
13669
|
+
const line = lines[index] ?? "";
|
|
13670
|
+
if (!closed && !endsWithNewline && index === lineCountToProcess - 1 && isPotentialDiffMetadataTail(line)) continue;
|
|
13671
|
+
processLine(line);
|
|
13672
|
+
}
|
|
13673
|
+
if (closed || pendingOrig.length > 0 || pendingUpdated.length > 0) flushPendingDiffHunk(orig, updated, pendingOrig, pendingUpdated);
|
|
13674
|
+
const originalCode = orig.join("\n");
|
|
13675
|
+
const updatedCode = updated.join("\n");
|
|
13324
13676
|
return {
|
|
13325
|
-
original:
|
|
13326
|
-
updated:
|
|
13677
|
+
original: closed && endsWithNewline && originalCode ? `${originalCode}\n` : originalCode,
|
|
13678
|
+
updated: closed && endsWithNewline && updatedCode ? `${updatedCode}\n` : updatedCode
|
|
13327
13679
|
};
|
|
13328
13680
|
}
|
|
13329
13681
|
function parseFenceToken(token) {
|
|
13330
13682
|
const hasMap = Array.isArray(token.map) && token.map.length === 2;
|
|
13331
13683
|
const tokenMeta = token.meta ?? {};
|
|
13332
|
-
const
|
|
13684
|
+
const metaClosed = typeof tokenMeta.closed === "boolean" ? tokenMeta.closed : void 0;
|
|
13685
|
+
const closed = metaClosed === true || metaClosed !== false && hasMap;
|
|
13333
13686
|
const info = String(token.info ?? "");
|
|
13334
13687
|
const diff = info.startsWith("diff");
|
|
13335
13688
|
const language = diff ? (() => {
|
|
@@ -13347,7 +13700,7 @@ function parseFenceToken(token) {
|
|
|
13347
13700
|
code: String(updated ?? ""),
|
|
13348
13701
|
raw: String(content ?? ""),
|
|
13349
13702
|
diff,
|
|
13350
|
-
loading:
|
|
13703
|
+
loading: metaClosed === true ? false : metaClosed === false ? true : !hasMap,
|
|
13351
13704
|
originalCode: original,
|
|
13352
13705
|
updatedCode: updated
|
|
13353
13706
|
};
|
|
@@ -13358,7 +13711,7 @@ function parseFenceToken(token) {
|
|
|
13358
13711
|
code: String(content ?? ""),
|
|
13359
13712
|
raw: String(content ?? ""),
|
|
13360
13713
|
diff,
|
|
13361
|
-
loading:
|
|
13714
|
+
loading: metaClosed === true ? false : metaClosed === false ? true : !hasMap
|
|
13362
13715
|
};
|
|
13363
13716
|
}
|
|
13364
13717
|
|
|
@@ -13448,6 +13801,15 @@ function tokenToRaw(token) {
|
|
|
13448
13801
|
const raw = shape.raw ?? shape.content ?? shape.markup ?? "";
|
|
13449
13802
|
return String(raw ?? "");
|
|
13450
13803
|
}
|
|
13804
|
+
function getCustomHtmlSourceMeta(token) {
|
|
13805
|
+
const meta = token.meta;
|
|
13806
|
+
const raw = meta?.markstreamCustomHtmlRaw;
|
|
13807
|
+
const inner = meta?.markstreamCustomHtmlInner;
|
|
13808
|
+
return typeof raw === "string" && typeof inner === "string" ? {
|
|
13809
|
+
raw,
|
|
13810
|
+
inner
|
|
13811
|
+
} : null;
|
|
13812
|
+
}
|
|
13451
13813
|
function getAttrValue$1(attrs, name) {
|
|
13452
13814
|
const lowerName = name.toLowerCase();
|
|
13453
13815
|
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
@@ -13632,16 +13994,19 @@ function parseHtmlInlineCodeToken(token, tokens, i, parseInlineTokens$1, raw, pP
|
|
|
13632
13994
|
const attrValue = match[2] || match[3] || match[4] || "";
|
|
13633
13995
|
attrs.push([attrName, attrValue]);
|
|
13634
13996
|
}
|
|
13635
|
-
if (customTagSet?.has(tag))
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13997
|
+
if (customTagSet?.has(tag)) {
|
|
13998
|
+
const sourceMeta = getCustomHtmlSourceMeta(token);
|
|
13999
|
+
return [{
|
|
14000
|
+
type: tag,
|
|
14001
|
+
tag,
|
|
14002
|
+
attrs,
|
|
14003
|
+
content: sourceMeta ? sourceMeta.inner : fragment.innerTokens.length ? stringifyTokens(fragment.innerTokens) : "",
|
|
14004
|
+
children: fragment.innerTokens.length ? parseInlineTokens$1(fragment.innerTokens, raw, pPreToken, options) : [],
|
|
14005
|
+
raw: sourceMeta?.raw ?? content,
|
|
14006
|
+
loading: token.loading || loading,
|
|
14007
|
+
autoClosed
|
|
14008
|
+
}, fragment.nextIndex];
|
|
14009
|
+
}
|
|
13645
14010
|
return [{
|
|
13646
14011
|
type: "html_inline",
|
|
13647
14012
|
tag,
|
|
@@ -14189,6 +14554,17 @@ function recoverTrailingMarkdownLinkLabel(raw, href) {
|
|
|
14189
14554
|
}
|
|
14190
14555
|
function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
14191
14556
|
if (!tokens || tokens.length === 0) return [];
|
|
14557
|
+
const inheritedContext = options?.__linkifyDemotionContext;
|
|
14558
|
+
const inferredContext = inferLinkifyDemotionContext(raw);
|
|
14559
|
+
const linkifyDemotionContext = {
|
|
14560
|
+
filename: inheritedContext?.filename || inferredContext.filename,
|
|
14561
|
+
explicitFilename: inheritedContext?.explicitFilename || inferredContext.explicitFilename,
|
|
14562
|
+
marketTicker: inheritedContext?.marketTicker || inferredContext.marketTicker
|
|
14563
|
+
};
|
|
14564
|
+
if (linkifyDemotionContext.filename || linkifyDemotionContext.explicitFilename || linkifyDemotionContext.marketTicker) options = {
|
|
14565
|
+
...options,
|
|
14566
|
+
__linkifyDemotionContext: linkifyDemotionContext
|
|
14567
|
+
};
|
|
14192
14568
|
const internalOptions = options;
|
|
14193
14569
|
const result = [];
|
|
14194
14570
|
let currentTextNode = null;
|
|
@@ -14981,8 +15357,9 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
14981
15357
|
resetCurrentTextNode();
|
|
14982
15358
|
const { node, nextIndex } = parseLinkToken(tokens, i, options);
|
|
14983
15359
|
i = nextIndex;
|
|
14984
|
-
|
|
14985
|
-
|
|
15360
|
+
const linkText = node.text || node.href || "";
|
|
15361
|
+
if (token.markup === "linkify" && !isDecodedFromRawPunycode(linkText, node.href, raw) && shouldDemoteFilenameLikeLinkify(linkText, internalOptions?.__linkifyDemotionContext)) {
|
|
15362
|
+
pushText(linkText, linkText);
|
|
14986
15363
|
return;
|
|
14987
15364
|
}
|
|
14988
15365
|
const hasSingleTextChild = node.children.length === 1 && node.children[0]?.type === "text";
|
|
@@ -15454,6 +15831,7 @@ function stripLeakedOrderedListMarkerSuffix(token) {
|
|
|
15454
15831
|
function parseList(tokens, index, options) {
|
|
15455
15832
|
const token = tokens[index];
|
|
15456
15833
|
const listItems = [];
|
|
15834
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15457
15835
|
let j = index + 1;
|
|
15458
15836
|
while (j < tokens.length && tokens[j].type !== "bullet_list_close" && tokens[j].type !== "ordered_list_close") if (tokens[j].type === "list_item_open") {
|
|
15459
15837
|
const itemChildren = [];
|
|
@@ -15465,22 +15843,26 @@ function parseList(tokens, index, options) {
|
|
|
15465
15843
|
trimInlineTokenTail(contentToken);
|
|
15466
15844
|
itemChildren.push({
|
|
15467
15845
|
type: "paragraph",
|
|
15468
|
-
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), preToken, options),
|
|
15846
|
+
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), preToken, linkifyContext.options()),
|
|
15469
15847
|
raw: String(contentToken.content ?? "")
|
|
15470
15848
|
});
|
|
15849
|
+
linkifyContext.remember(String(contentToken.content ?? ""));
|
|
15471
15850
|
k += 3;
|
|
15472
15851
|
} else if (tokens[k].type === "blockquote_open") {
|
|
15473
|
-
const [blockquoteNode, newIndex] = parseBlockquote(tokens, k, options);
|
|
15852
|
+
const [blockquoteNode, newIndex] = parseBlockquote(tokens, k, linkifyContext.options());
|
|
15474
15853
|
itemChildren.push(blockquoteNode);
|
|
15854
|
+
linkifyContext.remember(blockquoteNode.raw);
|
|
15475
15855
|
k = newIndex;
|
|
15476
15856
|
} else if (tokens[k].type === "bullet_list_open" || tokens[k].type === "ordered_list_open") {
|
|
15477
|
-
const [nestedListNode, newIndex] = parseList(tokens, k, options);
|
|
15857
|
+
const [nestedListNode, newIndex] = parseList(tokens, k, linkifyContext.options());
|
|
15478
15858
|
itemChildren.push(nestedListNode);
|
|
15859
|
+
linkifyContext.remember(nestedListNode.raw);
|
|
15479
15860
|
k = newIndex;
|
|
15480
15861
|
} else {
|
|
15481
|
-
const handled = parseCommonBlockToken(tokens, k, options, containerTokenHandlers);
|
|
15862
|
+
const handled = parseCommonBlockToken(tokens, k, linkifyContext.options(), containerTokenHandlers);
|
|
15482
15863
|
if (handled) {
|
|
15483
15864
|
itemChildren.push(handled[0]);
|
|
15865
|
+
linkifyContext.remember(handled[0].raw);
|
|
15484
15866
|
k = handled[1];
|
|
15485
15867
|
} else k += 1;
|
|
15486
15868
|
}
|
|
@@ -15514,27 +15896,35 @@ function parseAdmonition(tokens, index, match, options) {
|
|
|
15514
15896
|
const kind = String(match[1] ?? "note");
|
|
15515
15897
|
const title = String(match[2] ?? kind.charAt(0).toUpperCase() + kind.slice(1));
|
|
15516
15898
|
const admonitionChildren = [];
|
|
15899
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15517
15900
|
let j = index + 1;
|
|
15518
15901
|
while (j < tokens.length && tokens[j].type !== "container_close") if (tokens[j].type === "paragraph_open") {
|
|
15519
15902
|
const contentToken = tokens[j + 1];
|
|
15520
|
-
if (contentToken)
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15903
|
+
if (contentToken) {
|
|
15904
|
+
const paragraphNode = {
|
|
15905
|
+
type: "paragraph",
|
|
15906
|
+
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
|
|
15907
|
+
raw: String(contentToken.content ?? "")
|
|
15908
|
+
};
|
|
15909
|
+
admonitionChildren.push(paragraphNode);
|
|
15910
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
15911
|
+
}
|
|
15525
15912
|
j += 3;
|
|
15526
15913
|
} else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
|
|
15527
|
-
const [listNode, newIndex] = parseList(tokens, j, options);
|
|
15914
|
+
const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
|
|
15528
15915
|
admonitionChildren.push(listNode);
|
|
15916
|
+
linkifyContext.remember(listNode.raw);
|
|
15529
15917
|
j = newIndex;
|
|
15530
15918
|
} else if (tokens[j].type === "blockquote_open") {
|
|
15531
|
-
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
|
|
15919
|
+
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
|
|
15532
15920
|
admonitionChildren.push(blockquoteNode);
|
|
15921
|
+
linkifyContext.remember(blockquoteNode.raw);
|
|
15533
15922
|
j = newIndex;
|
|
15534
15923
|
} else {
|
|
15535
|
-
const handled = parseBasicBlockToken(tokens, j, options);
|
|
15924
|
+
const handled = parseBasicBlockToken(tokens, j, linkifyContext.options());
|
|
15536
15925
|
if (handled) {
|
|
15537
15926
|
admonitionChildren.push(handled[0]);
|
|
15927
|
+
linkifyContext.remember(handled[0].raw);
|
|
15538
15928
|
j = handled[1];
|
|
15539
15929
|
} else j++;
|
|
15540
15930
|
}
|
|
@@ -15594,6 +15984,7 @@ function parseContainer(tokens, index, options) {
|
|
|
15594
15984
|
}
|
|
15595
15985
|
if (!title) title = kind.charAt(0).toUpperCase() + kind.slice(1);
|
|
15596
15986
|
const children = [];
|
|
15987
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15597
15988
|
let j = index + 1;
|
|
15598
15989
|
const closeType = /* @__PURE__ */ new RegExp(`^container_${kind}_close$`);
|
|
15599
15990
|
while (j < tokens.length && tokens[j].type !== "container_close" && !closeType.test(tokens[j].type)) if (tokens[j].type === "paragraph_open") {
|
|
@@ -15608,26 +15999,30 @@ function parseContainer(tokens, index, options) {
|
|
|
15608
15999
|
break;
|
|
15609
16000
|
}
|
|
15610
16001
|
}
|
|
15611
|
-
const
|
|
15612
|
-
children.push({
|
|
16002
|
+
const paragraphNode = {
|
|
15613
16003
|
type: "paragraph",
|
|
15614
|
-
children: parseInlineTokens(
|
|
16004
|
+
children: parseInlineTokens((i !== -1 ? childrenArr.slice(0, i) : childrenArr) || [], void 0, void 0, linkifyContext.options()),
|
|
15615
16005
|
raw: String(contentToken.content ?? "").replace(/\n:+$/, "").replace(/\n\s*:::\s*$/, "")
|
|
15616
|
-
}
|
|
16006
|
+
};
|
|
16007
|
+
children.push(paragraphNode);
|
|
16008
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
15617
16009
|
}
|
|
15618
16010
|
j += 3;
|
|
15619
16011
|
} else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
|
|
15620
|
-
const [listNode, newIndex] = parseList(tokens, j, options);
|
|
16012
|
+
const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
|
|
15621
16013
|
children.push(listNode);
|
|
16014
|
+
linkifyContext.remember(listNode.raw);
|
|
15622
16015
|
j = newIndex;
|
|
15623
16016
|
} else if (tokens[j].type === "blockquote_open") {
|
|
15624
|
-
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
|
|
16017
|
+
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
|
|
15625
16018
|
children.push(blockquoteNode);
|
|
16019
|
+
linkifyContext.remember(blockquoteNode.raw);
|
|
15626
16020
|
j = newIndex;
|
|
15627
16021
|
} else {
|
|
15628
|
-
const handled = parseBasicBlockToken(tokens, j, options);
|
|
16022
|
+
const handled = parseBasicBlockToken(tokens, j, linkifyContext.options());
|
|
15629
16023
|
if (handled) {
|
|
15630
16024
|
children.push(handled[0]);
|
|
16025
|
+
linkifyContext.remember(handled[0].raw);
|
|
15631
16026
|
j = handled[1];
|
|
15632
16027
|
} else j++;
|
|
15633
16028
|
}
|
|
@@ -15659,35 +16054,41 @@ const containerTokenHandlers = {
|
|
|
15659
16054
|
//#region src/parser/node-parsers/blockquote-parser.ts
|
|
15660
16055
|
function parseBlockquote(tokens, index, options) {
|
|
15661
16056
|
const blockquoteChildren = [];
|
|
16057
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15662
16058
|
let j = index + 1;
|
|
15663
16059
|
while (j < tokens.length && tokens[j].type !== "blockquote_close") switch (tokens[j].type) {
|
|
15664
16060
|
case "paragraph_open": {
|
|
15665
16061
|
const contentToken = tokens[j + 1];
|
|
15666
|
-
|
|
16062
|
+
const paragraphNode = {
|
|
15667
16063
|
type: "paragraph",
|
|
15668
|
-
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, options),
|
|
16064
|
+
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
|
|
15669
16065
|
raw: String(contentToken.content ?? "")
|
|
15670
|
-
}
|
|
16066
|
+
};
|
|
16067
|
+
blockquoteChildren.push(paragraphNode);
|
|
16068
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
15671
16069
|
j += 3;
|
|
15672
16070
|
break;
|
|
15673
16071
|
}
|
|
15674
16072
|
case "bullet_list_open":
|
|
15675
16073
|
case "ordered_list_open": {
|
|
15676
|
-
const [listNode, newIndex] = parseList(tokens, j, options);
|
|
16074
|
+
const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
|
|
15677
16075
|
blockquoteChildren.push(listNode);
|
|
16076
|
+
linkifyContext.remember(listNode.raw);
|
|
15678
16077
|
j = newIndex;
|
|
15679
16078
|
break;
|
|
15680
16079
|
}
|
|
15681
16080
|
case "blockquote_open": {
|
|
15682
|
-
const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, options);
|
|
16081
|
+
const [nestedBlockquote, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
|
|
15683
16082
|
blockquoteChildren.push(nestedBlockquote);
|
|
16083
|
+
linkifyContext.remember(nestedBlockquote.raw);
|
|
15684
16084
|
j = newIndex;
|
|
15685
16085
|
break;
|
|
15686
16086
|
}
|
|
15687
16087
|
default: {
|
|
15688
|
-
const handled = parseCommonBlockToken(tokens, j, options, containerTokenHandlers);
|
|
16088
|
+
const handled = parseCommonBlockToken(tokens, j, linkifyContext.options(), containerTokenHandlers);
|
|
15689
16089
|
if (handled) {
|
|
15690
16090
|
blockquoteChildren.push(handled[0]);
|
|
16091
|
+
linkifyContext.remember(handled[0].raw);
|
|
15691
16092
|
j = handled[1];
|
|
15692
16093
|
} else j++;
|
|
15693
16094
|
break;
|
|
@@ -15724,9 +16125,11 @@ function parseDefinitionList(tokens, index, options) {
|
|
|
15724
16125
|
let j = index + 1;
|
|
15725
16126
|
let termNodes = [];
|
|
15726
16127
|
let definitionNodes = [];
|
|
16128
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15727
16129
|
while (j < tokens.length && tokens[j].type !== "dl_close") if (tokens[j].type === "dt_open") {
|
|
15728
16130
|
const termToken = tokens[j + 1];
|
|
15729
|
-
termNodes = parseInlineTokens(termToken.children || [], void 0, void 0, options);
|
|
16131
|
+
termNodes = parseInlineTokens(termToken.children || [], void 0, void 0, linkifyContext.options());
|
|
16132
|
+
linkifyContext.remember(termNodes.map((term) => term.raw).join(""));
|
|
15730
16133
|
j += 3;
|
|
15731
16134
|
} else if (tokens[j].type === "dd_open") {
|
|
15732
16135
|
let k = j + 1;
|
|
@@ -15735,9 +16138,10 @@ function parseDefinitionList(tokens, index, options) {
|
|
|
15735
16138
|
const contentToken = tokens[k + 1];
|
|
15736
16139
|
definitionNodes.push({
|
|
15737
16140
|
type: "paragraph",
|
|
15738
|
-
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, options),
|
|
16141
|
+
children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, linkifyContext.options()),
|
|
15739
16142
|
raw: String(contentToken.content ?? "")
|
|
15740
16143
|
});
|
|
16144
|
+
linkifyContext.remember(String(contentToken.content ?? ""));
|
|
15741
16145
|
k += 3;
|
|
15742
16146
|
} else k++;
|
|
15743
16147
|
if (termNodes.length > 0) {
|
|
@@ -15764,16 +16168,19 @@ function parseFootnote(tokens, index, options) {
|
|
|
15764
16168
|
const meta = tokens[index].meta ?? {};
|
|
15765
16169
|
const id = String(meta?.label ?? "0");
|
|
15766
16170
|
const footnoteChildren = [];
|
|
16171
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
15767
16172
|
let j = index + 1;
|
|
15768
16173
|
while (j < tokens.length && tokens[j].type !== "footnote_close") if (tokens[j].type === "paragraph_open") {
|
|
15769
16174
|
const contentToken = tokens[j + 1];
|
|
15770
16175
|
const children = contentToken.children ? [...contentToken.children] : [];
|
|
15771
16176
|
if (tokens[j + 2].type === "footnote_anchor") children.push(tokens[j + 2]);
|
|
15772
|
-
|
|
16177
|
+
const paragraphNode = {
|
|
15773
16178
|
type: "paragraph",
|
|
15774
|
-
children: parseInlineTokens(children, String(contentToken.content ?? ""), void 0, options),
|
|
16179
|
+
children: parseInlineTokens(children, String(contentToken.content ?? ""), void 0, linkifyContext.options()),
|
|
15775
16180
|
raw: String(contentToken.content ?? "")
|
|
15776
|
-
}
|
|
16181
|
+
};
|
|
16182
|
+
footnoteChildren.push(paragraphNode);
|
|
16183
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
15777
16184
|
j += 3;
|
|
15778
16185
|
} else j++;
|
|
15779
16186
|
return [{
|
|
@@ -15900,6 +16307,30 @@ function extractAlign(attrs) {
|
|
|
15900
16307
|
}
|
|
15901
16308
|
return "left";
|
|
15902
16309
|
}
|
|
16310
|
+
function hasTableCellContext(context) {
|
|
16311
|
+
return context?.filename === true || context?.explicitFilename === true || context?.marketTicker === true;
|
|
16312
|
+
}
|
|
16313
|
+
function mergeTableCellContext(left, right) {
|
|
16314
|
+
const merged = {
|
|
16315
|
+
filename: left?.filename || right?.filename,
|
|
16316
|
+
explicitFilename: left?.explicitFilename || right?.explicitFilename,
|
|
16317
|
+
marketTicker: left?.marketTicker || right?.marketTicker
|
|
16318
|
+
};
|
|
16319
|
+
return hasTableCellContext(merged) ? merged : void 0;
|
|
16320
|
+
}
|
|
16321
|
+
function parseOptionsForTableCell(options, headerRaw, rowContext) {
|
|
16322
|
+
const cellContext = mergeTableCellContext(inferLinkifyDemotionContext(headerRaw), rowContext);
|
|
16323
|
+
if (!hasTableCellContext(cellContext)) return options;
|
|
16324
|
+
const inheritedContext = options?.__linkifyDemotionContext;
|
|
16325
|
+
return {
|
|
16326
|
+
...options,
|
|
16327
|
+
__linkifyDemotionContext: {
|
|
16328
|
+
filename: inheritedContext?.filename || cellContext?.filename,
|
|
16329
|
+
explicitFilename: inheritedContext?.explicitFilename || cellContext?.explicitFilename,
|
|
16330
|
+
marketTicker: inheritedContext?.marketTicker || cellContext?.marketTicker
|
|
16331
|
+
}
|
|
16332
|
+
};
|
|
16333
|
+
}
|
|
15903
16334
|
function parseTable(tokens, index, options) {
|
|
15904
16335
|
let j = index + 1;
|
|
15905
16336
|
let headerRow = null;
|
|
@@ -15915,18 +16346,23 @@ function parseTable(tokens, index, options) {
|
|
|
15915
16346
|
else if (tokens[j].type === "tr_open") {
|
|
15916
16347
|
const cells = [];
|
|
15917
16348
|
let k = j + 1;
|
|
16349
|
+
let rowContext;
|
|
15918
16350
|
while (k < tokens.length && tokens[k].type !== "tr_close") if (tokens[k].type === "th_open" || tokens[k].type === "td_open") {
|
|
15919
16351
|
const isHeaderCell = tokens[k].type === "th_open";
|
|
15920
16352
|
const contentToken = tokens[k + 1];
|
|
15921
16353
|
const content = String(contentToken.content ?? "");
|
|
15922
16354
|
const align = extractAlign(tokens[k].attrs);
|
|
16355
|
+
const cellIndex = cells.length;
|
|
16356
|
+
const isBodyCell = !isHeaderCell && !isHeader;
|
|
16357
|
+
const headerRaw = isBodyCell ? headerRow?.cells[cellIndex]?.raw : void 0;
|
|
15923
16358
|
cells.push({
|
|
15924
16359
|
type: "table_cell",
|
|
15925
16360
|
header: isHeaderCell || isHeader,
|
|
15926
|
-
children: parseInlineTokens(contentToken.children || [], content, void 0, options),
|
|
16361
|
+
children: parseInlineTokens(contentToken.children || [], content, void 0, parseOptionsForTableCell(options, headerRaw, isBodyCell ? rowContext : void 0)),
|
|
15927
16362
|
raw: content,
|
|
15928
16363
|
align
|
|
15929
16364
|
});
|
|
16365
|
+
if (isBodyCell) rowContext = mergeTableCellContext(rowContext, inferLinkifyDemotionContext(content));
|
|
15930
16366
|
k += 3;
|
|
15931
16367
|
} else k++;
|
|
15932
16368
|
const rowNode = {
|
|
@@ -15943,11 +16379,12 @@ function parseTable(tokens, index, options) {
|
|
|
15943
16379
|
cells: [],
|
|
15944
16380
|
raw: ""
|
|
15945
16381
|
};
|
|
16382
|
+
const tokenLoading = tokens[index].loading === true;
|
|
15946
16383
|
return [{
|
|
15947
16384
|
type: "table",
|
|
15948
16385
|
header: headerRow,
|
|
15949
16386
|
rows,
|
|
15950
|
-
loading:
|
|
16387
|
+
loading: tokenLoading && !options?.final && rows.length === 0,
|
|
15951
16388
|
raw: [headerRow, ...rows].map((row) => row.raw).join("\n")
|
|
15952
16389
|
}, j + 1];
|
|
15953
16390
|
}
|
|
@@ -16008,30 +16445,35 @@ function parseVmrContainer(tokens, index, options) {
|
|
|
16008
16445
|
}
|
|
16009
16446
|
}
|
|
16010
16447
|
const children = [];
|
|
16448
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options, true);
|
|
16011
16449
|
let j = index + 1;
|
|
16012
16450
|
while (j < tokens.length && tokens[j].type !== "vmr_container_close") if (tokens[j].type === "paragraph_open") {
|
|
16013
16451
|
const contentToken = tokens[j + 1];
|
|
16014
16452
|
if (contentToken) {
|
|
16015
|
-
const
|
|
16016
|
-
children.push({
|
|
16453
|
+
const paragraphNode = {
|
|
16017
16454
|
type: "paragraph",
|
|
16018
|
-
children: parseInlineTokens(
|
|
16455
|
+
children: parseInlineTokens(contentToken.children || [], void 0, void 0, linkifyContext.options()),
|
|
16019
16456
|
raw: String(contentToken.content ?? "")
|
|
16020
|
-
}
|
|
16457
|
+
};
|
|
16458
|
+
children.push(paragraphNode);
|
|
16459
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
16021
16460
|
}
|
|
16022
16461
|
j += 3;
|
|
16023
16462
|
} else if (tokens[j].type === "bullet_list_open" || tokens[j].type === "ordered_list_open") {
|
|
16024
|
-
const [listNode, newIndex] = parseList(tokens, j, options);
|
|
16463
|
+
const [listNode, newIndex] = parseList(tokens, j, linkifyContext.options());
|
|
16025
16464
|
children.push(listNode);
|
|
16465
|
+
linkifyContext.remember(listNode.raw);
|
|
16026
16466
|
j = newIndex;
|
|
16027
16467
|
} else if (tokens[j].type === "blockquote_open") {
|
|
16028
|
-
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, options);
|
|
16468
|
+
const [blockquoteNode, newIndex] = parseBlockquote(tokens, j, linkifyContext.options());
|
|
16029
16469
|
children.push(blockquoteNode);
|
|
16470
|
+
linkifyContext.remember(blockquoteNode.raw);
|
|
16030
16471
|
j = newIndex;
|
|
16031
16472
|
} else {
|
|
16032
|
-
const handled = parseBasicBlockToken(tokens, j, options);
|
|
16473
|
+
const handled = parseBasicBlockToken(tokens, j, linkifyContext.options());
|
|
16033
16474
|
if (handled) {
|
|
16034
16475
|
children.push(handled[0]);
|
|
16476
|
+
linkifyContext.remember(handled[0].raw);
|
|
16035
16477
|
j = handled[1];
|
|
16036
16478
|
} else j++;
|
|
16037
16479
|
}
|
|
@@ -16297,15 +16739,207 @@ function parseParagraph(tokens, index, options) {
|
|
|
16297
16739
|
|
|
16298
16740
|
//#endregion
|
|
16299
16741
|
//#region src/parser/index.ts
|
|
16742
|
+
const streamParseEnvCache = /* @__PURE__ */ new WeakMap();
|
|
16300
16743
|
function getNodeFields(node) {
|
|
16301
16744
|
return node;
|
|
16302
16745
|
}
|
|
16746
|
+
function getParserNow() {
|
|
16747
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
16748
|
+
}
|
|
16749
|
+
function addTiming(metrics, key, value) {
|
|
16750
|
+
if (!metrics) return;
|
|
16751
|
+
metrics[key] = (metrics[key] ?? 0) + value;
|
|
16752
|
+
}
|
|
16753
|
+
function getParseTiming(options) {
|
|
16754
|
+
return options.__timing;
|
|
16755
|
+
}
|
|
16756
|
+
function finishTimedParse(result, timing, startedAt) {
|
|
16757
|
+
if (timing) addTiming(timing, "parseMarkdownToStructureTotalMs", getParserNow() - startedAt);
|
|
16758
|
+
return result;
|
|
16759
|
+
}
|
|
16760
|
+
function processTokensWithTiming(tokens, options, timing) {
|
|
16761
|
+
if (!timing) return processTokens(tokens, options);
|
|
16762
|
+
const startedAt = getParserNow();
|
|
16763
|
+
const result = processTokens(tokens, options);
|
|
16764
|
+
addTiming(timing, "processTokensMs", getParserNow() - startedAt);
|
|
16765
|
+
return result;
|
|
16766
|
+
}
|
|
16303
16767
|
function getCustomHtmlTagSet(options) {
|
|
16304
16768
|
const custom = options?.customHtmlTags;
|
|
16305
16769
|
if (!Array.isArray(custom) || custom.length === 0) return null;
|
|
16306
16770
|
const normalized = normalizeCustomHtmlTags(custom);
|
|
16307
16771
|
return normalized.length ? new Set(normalized) : null;
|
|
16308
16772
|
}
|
|
16773
|
+
function getStableStreamEnv(md, env) {
|
|
16774
|
+
const mdKey = md;
|
|
16775
|
+
let byMode = streamParseEnvCache.get(mdKey);
|
|
16776
|
+
if (!byMode) {
|
|
16777
|
+
byMode = /* @__PURE__ */ new Map();
|
|
16778
|
+
streamParseEnvCache.set(mdKey, byMode);
|
|
16779
|
+
}
|
|
16780
|
+
const modeKey = env.__markstreamFinal === true ? "final" : "streaming";
|
|
16781
|
+
let stableEnv = byMode.get(modeKey);
|
|
16782
|
+
if (!stableEnv) {
|
|
16783
|
+
stableEnv = {};
|
|
16784
|
+
byMode.set(modeKey, stableEnv);
|
|
16785
|
+
}
|
|
16786
|
+
for (const key of Object.keys(stableEnv)) if (!Object.prototype.hasOwnProperty.call(env, key)) delete stableEnv[key];
|
|
16787
|
+
Object.assign(stableEnv, env);
|
|
16788
|
+
return stableEnv;
|
|
16789
|
+
}
|
|
16790
|
+
function isPlainObject(value) {
|
|
16791
|
+
if (!value || typeof value !== "object") return false;
|
|
16792
|
+
const proto = Object.getPrototypeOf(value);
|
|
16793
|
+
return proto === Object.prototype || proto === null;
|
|
16794
|
+
}
|
|
16795
|
+
function copyCloneableOwnDataProperties(source, target, seen) {
|
|
16796
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
16797
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
16798
|
+
if (!descriptor || !("value" in descriptor)) continue;
|
|
16799
|
+
const targetDescriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
16800
|
+
if (targetDescriptor && (!("value" in targetDescriptor) || targetDescriptor.writable === false)) continue;
|
|
16801
|
+
target[key] = safeCloneTokenField(descriptor.value, seen);
|
|
16802
|
+
}
|
|
16803
|
+
}
|
|
16804
|
+
function safeCloneTokenField(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
16805
|
+
if (!value || typeof value !== "object") return value;
|
|
16806
|
+
const object = value;
|
|
16807
|
+
const existing = seen.get(object);
|
|
16808
|
+
if (existing) return existing;
|
|
16809
|
+
if (Array.isArray(value)) {
|
|
16810
|
+
const cloned$1 = [];
|
|
16811
|
+
seen.set(object, cloned$1);
|
|
16812
|
+
for (const item of value) cloned$1.push(safeCloneTokenField(item, seen));
|
|
16813
|
+
return cloned$1;
|
|
16814
|
+
}
|
|
16815
|
+
if (value instanceof Map) {
|
|
16816
|
+
const cloned$1 = /* @__PURE__ */ new Map();
|
|
16817
|
+
seen.set(object, cloned$1);
|
|
16818
|
+
for (const [key, item] of value) cloned$1.set(safeCloneTokenField(key, seen), safeCloneTokenField(item, seen));
|
|
16819
|
+
return cloned$1;
|
|
16820
|
+
}
|
|
16821
|
+
if (value instanceof Set) {
|
|
16822
|
+
const cloned$1 = /* @__PURE__ */ new Set();
|
|
16823
|
+
seen.set(object, cloned$1);
|
|
16824
|
+
for (const item of value) cloned$1.add(safeCloneTokenField(item, seen));
|
|
16825
|
+
return cloned$1;
|
|
16826
|
+
}
|
|
16827
|
+
if (value instanceof Date) {
|
|
16828
|
+
const cloned$1 = new Date(value.getTime());
|
|
16829
|
+
seen.set(object, cloned$1);
|
|
16830
|
+
return cloned$1;
|
|
16831
|
+
}
|
|
16832
|
+
if (value instanceof RegExp) {
|
|
16833
|
+
const cloned$1 = new RegExp(value.source, value.flags);
|
|
16834
|
+
cloned$1.lastIndex = value.lastIndex;
|
|
16835
|
+
seen.set(object, cloned$1);
|
|
16836
|
+
return cloned$1;
|
|
16837
|
+
}
|
|
16838
|
+
if (typeof URL !== "undefined" && value instanceof URL) {
|
|
16839
|
+
const cloned$1 = new URL(value.href);
|
|
16840
|
+
seen.set(object, cloned$1);
|
|
16841
|
+
copyCloneableOwnDataProperties(object, cloned$1, seen);
|
|
16842
|
+
return cloned$1;
|
|
16843
|
+
}
|
|
16844
|
+
if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) {
|
|
16845
|
+
const cloned$1 = new URLSearchParams(value.toString());
|
|
16846
|
+
seen.set(object, cloned$1);
|
|
16847
|
+
copyCloneableOwnDataProperties(object, cloned$1, seen);
|
|
16848
|
+
return cloned$1;
|
|
16849
|
+
}
|
|
16850
|
+
if (value instanceof Error) {
|
|
16851
|
+
let cloned$1;
|
|
16852
|
+
const ErrorCtor = value.constructor;
|
|
16853
|
+
try {
|
|
16854
|
+
cloned$1 = new ErrorCtor(value.message);
|
|
16855
|
+
} catch {
|
|
16856
|
+
cloned$1 = new Error(value.message);
|
|
16857
|
+
}
|
|
16858
|
+
Object.setPrototypeOf(cloned$1, Object.getPrototypeOf(value));
|
|
16859
|
+
seen.set(object, cloned$1);
|
|
16860
|
+
copyCloneableOwnDataProperties(object, cloned$1, seen);
|
|
16861
|
+
return cloned$1;
|
|
16862
|
+
}
|
|
16863
|
+
if (typeof Promise !== "undefined" && value instanceof Promise) {
|
|
16864
|
+
seen.set(object, value);
|
|
16865
|
+
return value;
|
|
16866
|
+
}
|
|
16867
|
+
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
16868
|
+
seen.set(object, value);
|
|
16869
|
+
return value;
|
|
16870
|
+
}
|
|
16871
|
+
if (!isPlainObject(value)) {
|
|
16872
|
+
const cloned$1 = Object.create(Object.getPrototypeOf(value));
|
|
16873
|
+
seen.set(object, cloned$1);
|
|
16874
|
+
copyCloneableOwnDataProperties(object, cloned$1, seen);
|
|
16875
|
+
return cloned$1;
|
|
16876
|
+
}
|
|
16877
|
+
const cloned = {};
|
|
16878
|
+
seen.set(object, cloned);
|
|
16879
|
+
const record = value;
|
|
16880
|
+
for (const key of Object.keys(record)) cloned[key] = safeCloneTokenField(record[key], seen);
|
|
16881
|
+
return cloned;
|
|
16882
|
+
}
|
|
16883
|
+
function cloneMarkdownToken(token, cloneObjectFields = true) {
|
|
16884
|
+
if (!cloneObjectFields) {
|
|
16885
|
+
const cloned$1 = Object.assign(Object.create(Object.getPrototypeOf(token)), token);
|
|
16886
|
+
if (Array.isArray(token.attrs)) cloned$1.attrs = token.attrs.map((attr) => [...attr]);
|
|
16887
|
+
if (Array.isArray(token.map)) cloned$1.map = [...token.map];
|
|
16888
|
+
if (Array.isArray(token.children)) cloned$1.children = token.children.map((child) => cloneMarkdownToken(child, cloneObjectFields));
|
|
16889
|
+
return cloned$1;
|
|
16890
|
+
}
|
|
16891
|
+
const cloned = Object.create(Object.getPrototypeOf(token));
|
|
16892
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
16893
|
+
for (const key of Reflect.ownKeys(token)) {
|
|
16894
|
+
const descriptor = Object.getOwnPropertyDescriptor(token, key);
|
|
16895
|
+
if (!descriptor) continue;
|
|
16896
|
+
if (!("value" in descriptor)) {
|
|
16897
|
+
Object.defineProperty(cloned, key, descriptor);
|
|
16898
|
+
continue;
|
|
16899
|
+
}
|
|
16900
|
+
const value = descriptor.value;
|
|
16901
|
+
let clonedValue = value;
|
|
16902
|
+
if (key === "attrs" && Array.isArray(value)) clonedValue = value.map((attr) => [...attr]);
|
|
16903
|
+
else if (key === "map" && Array.isArray(value)) clonedValue = [...value];
|
|
16904
|
+
else if (key === "children" && Array.isArray(value)) clonedValue = value.map((child) => cloneMarkdownToken(child, cloneObjectFields));
|
|
16905
|
+
else if (cloneObjectFields && value && typeof value === "object") clonedValue = safeCloneTokenField(value, seen);
|
|
16906
|
+
Object.defineProperty(cloned, key, {
|
|
16907
|
+
...descriptor,
|
|
16908
|
+
value: clonedValue
|
|
16909
|
+
});
|
|
16910
|
+
}
|
|
16911
|
+
return cloned;
|
|
16912
|
+
}
|
|
16913
|
+
function cloneMarkdownTokens(tokens, cloneObjectFields = true) {
|
|
16914
|
+
return tokens.map((token) => cloneMarkdownToken(token, cloneObjectFields));
|
|
16915
|
+
}
|
|
16916
|
+
function shouldUseTopLevelStreamParse(md, options) {
|
|
16917
|
+
const internalOptions = options;
|
|
16918
|
+
const stream = md.stream;
|
|
16919
|
+
const streamParse = options.streamParse ?? "auto";
|
|
16920
|
+
return internalOptions.__disableStreamParse !== true && (streamParse === true || streamParse === "auto" && options.final !== true) && stream?.enabled === true && typeof stream.parse === "function";
|
|
16921
|
+
}
|
|
16922
|
+
function shouldResetTopLevelStreamCacheForFinalAutoParse(md, options) {
|
|
16923
|
+
const internalOptions = options;
|
|
16924
|
+
const streamParse = options.streamParse ?? "auto";
|
|
16925
|
+
const stream = md.stream;
|
|
16926
|
+
return options.final === true && streamParse === "auto" && internalOptions.__disableStreamParse !== true && stream?.enabled === true && typeof stream.reset === "function";
|
|
16927
|
+
}
|
|
16928
|
+
function shouldCloneTopLevelStreamTokenObjectFields(options) {
|
|
16929
|
+
return typeof options.preTransformTokens === "function" || typeof options.postTransformTokens === "function";
|
|
16930
|
+
}
|
|
16931
|
+
function parseTopLevelTokens(md, source, env, options) {
|
|
16932
|
+
if (options.customHtmlTags?.length) env.__markstreamCustomHtmlTags = options.customHtmlTags;
|
|
16933
|
+
if (!shouldUseTopLevelStreamParse(md, options)) return md.parse(source, env);
|
|
16934
|
+
const tokens = md.stream.parse(source, getStableStreamEnv(md, env));
|
|
16935
|
+
const cloneObjectFields = shouldCloneTopLevelStreamTokenObjectFields(options);
|
|
16936
|
+
const timing = getParseTiming(options);
|
|
16937
|
+
if (!timing) return cloneMarkdownTokens(tokens, cloneObjectFields);
|
|
16938
|
+
const startedAt = getParserNow();
|
|
16939
|
+
const cloned = cloneMarkdownTokens(tokens, cloneObjectFields);
|
|
16940
|
+
addTiming(timing, "tokenCloneMs", getParserNow() - startedAt);
|
|
16941
|
+
return cloned;
|
|
16942
|
+
}
|
|
16309
16943
|
function buildAllowedHtmlTagSet(options) {
|
|
16310
16944
|
const custom = options?.customHtmlTags;
|
|
16311
16945
|
if (!Array.isArray(custom) || custom.length === 0) return STANDARD_HTML_TAGS;
|
|
@@ -16511,6 +17145,7 @@ function findLastClosingTagStart(raw, tag) {
|
|
|
16511
17145
|
function buildDetailsChildParseOptions(options, final) {
|
|
16512
17146
|
return {
|
|
16513
17147
|
final,
|
|
17148
|
+
__disableStreamParse: true,
|
|
16514
17149
|
requireClosingStrong: options.requireClosingStrong,
|
|
16515
17150
|
customHtmlTags: options.customHtmlTags,
|
|
16516
17151
|
validateLink: options.validateLink
|
|
@@ -16568,7 +17203,10 @@ function structureGenericHtmlBlockChildren(nodes, md, options, final) {
|
|
|
16568
17203
|
}
|
|
16569
17204
|
function parseDetailsFragmentChildren(fragment, md, options) {
|
|
16570
17205
|
if (!fragment.trim()) return [];
|
|
16571
|
-
return parseMarkdownToStructure(fragment, md,
|
|
17206
|
+
return parseMarkdownToStructure(fragment, md, {
|
|
17207
|
+
...options,
|
|
17208
|
+
__disableStreamParse: true
|
|
17209
|
+
});
|
|
16572
17210
|
}
|
|
16573
17211
|
function parseSummaryChildren(fragment, md, options) {
|
|
16574
17212
|
const children = parseDetailsFragmentChildren(fragment, md, options);
|
|
@@ -17495,8 +18133,11 @@ function ensureBlankLineBeforeCustomHtmlBlocks(markdown, tags) {
|
|
|
17495
18133
|
return out;
|
|
17496
18134
|
}
|
|
17497
18135
|
function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
18136
|
+
const timing = getParseTiming(options);
|
|
18137
|
+
const parseStartedAt = timing ? getParserNow() : 0;
|
|
17498
18138
|
const isFinal = !!options.final;
|
|
17499
18139
|
let safeMarkdown = (markdown ?? "").toString().replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\n(abla|eq|ot|exists)/g, "$1\\n$2");
|
|
18140
|
+
if (shouldResetTopLevelStreamCacheForFinalAutoParse(md, options)) md.stream.reset();
|
|
17500
18141
|
if (!isFinal) {
|
|
17501
18142
|
if (safeMarkdown.endsWith("- *")) safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*");
|
|
17502
18143
|
if (/(?:^|\n)\s*-\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => {
|
|
@@ -17537,15 +18178,15 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
|
17537
18178
|
if (standaloneHtmlDocument) {
|
|
17538
18179
|
const preHook = options.preTransformTokens;
|
|
17539
18180
|
const postHook = options.postTransformTokens;
|
|
17540
|
-
if (typeof preHook === "function" || typeof postHook === "function") {
|
|
17541
|
-
const rawTokens = md
|
|
18181
|
+
if (shouldUseTopLevelStreamParse(md, options) || typeof preHook === "function" || typeof postHook === "function") {
|
|
18182
|
+
const rawTokens = parseTopLevelTokens(md, safeMarkdown, { __markstreamFinal: isFinal }, options);
|
|
17542
18183
|
const hookedTokens = typeof preHook === "function" ? preHook(rawTokens) || rawTokens : rawTokens;
|
|
17543
18184
|
if (typeof postHook === "function") postHook(hookedTokens);
|
|
17544
18185
|
}
|
|
17545
|
-
return standaloneHtmlDocument;
|
|
18186
|
+
return finishTimedParse(standaloneHtmlDocument, timing, parseStartedAt);
|
|
17546
18187
|
}
|
|
17547
|
-
const tokens = md
|
|
17548
|
-
if (!tokens || !Array.isArray(tokens)) return [];
|
|
18188
|
+
const tokens = parseTopLevelTokens(md, safeMarkdown, { __markstreamFinal: isFinal }, options);
|
|
18189
|
+
if (!tokens || !Array.isArray(tokens)) return finishTimedParse([], timing, parseStartedAt);
|
|
17549
18190
|
const pre = options.preTransformTokens;
|
|
17550
18191
|
const post = options.postTransformTokens;
|
|
17551
18192
|
let transformedTokens = tokens;
|
|
@@ -17559,13 +18200,13 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
|
17559
18200
|
__sourceMarkdown: safeMarkdown,
|
|
17560
18201
|
__customHtmlBlockCursor: 0
|
|
17561
18202
|
};
|
|
17562
|
-
let result =
|
|
18203
|
+
let result = processTokensWithTiming(transformedTokens, internalOptions, timing);
|
|
17563
18204
|
if (post && typeof post === "function") {
|
|
17564
18205
|
const postResult = post(transformedTokens);
|
|
17565
18206
|
if (Array.isArray(postResult)) {
|
|
17566
18207
|
const first = postResult[0];
|
|
17567
18208
|
const firstType = first?.type;
|
|
17568
|
-
if (first && typeof firstType === "string") result =
|
|
18209
|
+
if (first && typeof firstType === "string") result = processTokensWithTiming(postResult, void 0, timing);
|
|
17569
18210
|
else result = postResult;
|
|
17570
18211
|
}
|
|
17571
18212
|
}
|
|
@@ -17589,39 +18230,45 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
|
17589
18230
|
finalizeHtmlBlockLoading(result);
|
|
17590
18231
|
}
|
|
17591
18232
|
if (options.debug) console.log("Parsed Markdown Tree Structure:", result);
|
|
17592
|
-
return result;
|
|
18233
|
+
return finishTimedParse(result, timing, parseStartedAt);
|
|
17593
18234
|
}
|
|
17594
18235
|
function processTokens(tokens, options) {
|
|
17595
18236
|
if (!tokens || !Array.isArray(tokens)) return [];
|
|
17596
18237
|
const result = [];
|
|
18238
|
+
const linkifyContext = createLinkifyDemotionContextTracker(options);
|
|
17597
18239
|
let i = 0;
|
|
17598
18240
|
while (i < tokens.length) {
|
|
17599
|
-
const handled = parseCommonBlockToken(tokens, i, options, containerTokenHandlers);
|
|
18241
|
+
const handled = parseCommonBlockToken(tokens, i, linkifyContext.options(), containerTokenHandlers);
|
|
17600
18242
|
if (handled) {
|
|
17601
18243
|
result.push(handled[0]);
|
|
18244
|
+
linkifyContext.remember(handled[0].raw);
|
|
17602
18245
|
i = handled[1];
|
|
17603
18246
|
continue;
|
|
17604
18247
|
}
|
|
17605
18248
|
const token = tokens[i];
|
|
17606
18249
|
switch (token.type) {
|
|
17607
18250
|
case "paragraph_open": {
|
|
17608
|
-
const
|
|
18251
|
+
const paragraphRaw = String(tokens[i + 1]?.content ?? "");
|
|
18252
|
+
const paragraphNode = parseParagraph(tokens, i, linkifyContext.options(paragraphRaw));
|
|
17609
18253
|
const promoted = maybePromoteCustomNodeFromParagraph(paragraphNode, options);
|
|
17610
18254
|
if (promoted) result.push(...promoted);
|
|
17611
18255
|
else result.push(paragraphNode);
|
|
18256
|
+
linkifyContext.remember(paragraphNode.raw);
|
|
17612
18257
|
i += 3;
|
|
17613
18258
|
break;
|
|
17614
18259
|
}
|
|
17615
18260
|
case "bullet_list_open":
|
|
17616
18261
|
case "ordered_list_open": {
|
|
17617
|
-
const [listNode, newIndex] = parseList(tokens, i, options);
|
|
18262
|
+
const [listNode, newIndex] = parseList(tokens, i, linkifyContext.options());
|
|
17618
18263
|
result.push(listNode);
|
|
18264
|
+
linkifyContext.remember(listNode.raw);
|
|
17619
18265
|
i = newIndex;
|
|
17620
18266
|
break;
|
|
17621
18267
|
}
|
|
17622
18268
|
case "blockquote_open": {
|
|
17623
|
-
const [blockquoteNode, newIndex] = parseBlockquote(tokens, i, options);
|
|
18269
|
+
const [blockquoteNode, newIndex] = parseBlockquote(tokens, i, linkifyContext.options());
|
|
17624
18270
|
result.push(blockquoteNode);
|
|
18271
|
+
linkifyContext.remember(blockquoteNode.raw);
|
|
17625
18272
|
i = newIndex;
|
|
17626
18273
|
break;
|
|
17627
18274
|
}
|
|
@@ -17633,11 +18280,13 @@ function processTokens(tokens, options) {
|
|
|
17633
18280
|
id,
|
|
17634
18281
|
raw: String(token.content ?? "")
|
|
17635
18282
|
});
|
|
18283
|
+
linkifyContext.remember(String(token.content ?? ""));
|
|
17636
18284
|
i++;
|
|
17637
18285
|
break;
|
|
17638
18286
|
}
|
|
17639
18287
|
case "hardbreak":
|
|
17640
18288
|
result.push(parseHardBreak());
|
|
18289
|
+
linkifyContext.reset();
|
|
17641
18290
|
i++;
|
|
17642
18291
|
break;
|
|
17643
18292
|
case "text": {
|
|
@@ -17651,23 +18300,26 @@ function processTokens(tokens, options) {
|
|
|
17651
18300
|
raw: content
|
|
17652
18301
|
}] : []
|
|
17653
18302
|
});
|
|
18303
|
+
linkifyContext.remember(content);
|
|
17654
18304
|
i++;
|
|
17655
18305
|
break;
|
|
17656
18306
|
}
|
|
17657
18307
|
case "inline":
|
|
17658
18308
|
{
|
|
17659
|
-
const
|
|
18309
|
+
const raw = String(token.content ?? "");
|
|
18310
|
+
const parsed = parseInlineTokens(token.children || [], raw, void 0, linkifyContext.options(raw));
|
|
17660
18311
|
if (parsed.length === 0) {} else if (parsed.every((n) => n.type === "html_block")) result.push(...parsed);
|
|
17661
18312
|
else {
|
|
17662
18313
|
const paragraphNode = {
|
|
17663
18314
|
type: "paragraph",
|
|
17664
|
-
raw
|
|
18315
|
+
raw,
|
|
17665
18316
|
children: parsed
|
|
17666
18317
|
};
|
|
17667
18318
|
const promoted = maybePromoteCustomNodeFromParagraph(paragraphNode, options);
|
|
17668
18319
|
if (promoted) result.push(...promoted);
|
|
17669
18320
|
else result.push(paragraphNode);
|
|
17670
18321
|
}
|
|
18322
|
+
linkifyContext.remember(raw);
|
|
17671
18323
|
}
|
|
17672
18324
|
i += 1;
|
|
17673
18325
|
break;
|
|
@@ -18554,7 +19206,8 @@ function getMarkdown(msgId = `editor-${Date.now()}`, options = {}) {
|
|
|
18554
19206
|
md.use(sub_plugin);
|
|
18555
19207
|
md.use(sup_plugin);
|
|
18556
19208
|
md.use(ins_plugin$1);
|
|
18557
|
-
const
|
|
19209
|
+
const checkboxModule = import_markdown_it_task_checkbox;
|
|
19210
|
+
const markdownItCheckboxPlugin = checkboxModule.default ?? checkboxModule;
|
|
18558
19211
|
md.use(markdownItCheckboxPlugin);
|
|
18559
19212
|
md.use(ins_plugin);
|
|
18560
19213
|
md.use(footnote_plugin);
|