stream-markdown-parser 0.0.80 → 0.0.82
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 +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +552 -237
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6489,7 +6489,7 @@ const DEFAULT_RENDERER_OPTIONS = {
|
|
|
6489
6489
|
xhtmlOut: false,
|
|
6490
6490
|
breaks: false
|
|
6491
6491
|
};
|
|
6492
|
-
const hasOwn = Object.prototype.hasOwnProperty;
|
|
6492
|
+
const hasOwn$1 = Object.prototype.hasOwnProperty;
|
|
6493
6493
|
const defaultRules = {
|
|
6494
6494
|
code_inline(tokens, idx) {
|
|
6495
6495
|
return renderCodeInlineToken(tokens[idx]);
|
|
@@ -6889,16 +6889,16 @@ var Renderer = class {
|
|
|
6889
6889
|
if (!merged) merged = { ...base$1 };
|
|
6890
6890
|
return merged;
|
|
6891
6891
|
};
|
|
6892
|
-
if (hasOwn.call(overrides, "highlight") && overrides.highlight !== base$1.highlight) ensureMerged().highlight = overrides.highlight;
|
|
6893
|
-
if (hasOwn.call(overrides, "langPrefix")) {
|
|
6892
|
+
if (hasOwn$1.call(overrides, "highlight") && overrides.highlight !== base$1.highlight) ensureMerged().highlight = overrides.highlight;
|
|
6893
|
+
if (hasOwn$1.call(overrides, "langPrefix")) {
|
|
6894
6894
|
const value = overrides.langPrefix;
|
|
6895
6895
|
if (value !== base$1.langPrefix) ensureMerged().langPrefix = value;
|
|
6896
6896
|
}
|
|
6897
|
-
if (hasOwn.call(overrides, "xhtmlOut")) {
|
|
6897
|
+
if (hasOwn$1.call(overrides, "xhtmlOut")) {
|
|
6898
6898
|
const value = overrides.xhtmlOut;
|
|
6899
6899
|
if (value !== base$1.xhtmlOut) ensureMerged().xhtmlOut = value;
|
|
6900
6900
|
}
|
|
6901
|
-
if (hasOwn.call(overrides, "breaks")) {
|
|
6901
|
+
if (hasOwn$1.call(overrides, "breaks")) {
|
|
6902
6902
|
const value = overrides.breaks;
|
|
6903
6903
|
if (value !== base$1.breaks) ensureMerged().breaks = value;
|
|
6904
6904
|
}
|
|
@@ -8733,10 +8733,10 @@ const config = {
|
|
|
8733
8733
|
commonmark: commonmark_default
|
|
8734
8734
|
};
|
|
8735
8735
|
function hasExplicitChunkOverride(presetOptions, userOptions, keys) {
|
|
8736
|
-
const hasOwn$1 = (obj, key) => !!obj && Object.prototype.hasOwnProperty.call(obj, key) && obj[key] !== void 0;
|
|
8736
|
+
const hasOwn$1$1 = (obj, key) => !!obj && Object.prototype.hasOwnProperty.call(obj, key) && obj[key] !== void 0;
|
|
8737
8737
|
for (let i = 0; i < keys.length; i++) {
|
|
8738
8738
|
const key = keys[i];
|
|
8739
|
-
if (hasOwn$1(userOptions, key) || hasOwn$1(presetOptions, key)) return true;
|
|
8739
|
+
if (hasOwn$1$1(userOptions, key) || hasOwn$1$1(presetOptions, key)) return true;
|
|
8740
8740
|
}
|
|
8741
8741
|
return false;
|
|
8742
8742
|
}
|
|
@@ -9602,6 +9602,124 @@ function isUnsafeHtmlUrl(value) {
|
|
|
9602
9602
|
return false;
|
|
9603
9603
|
}
|
|
9604
9604
|
|
|
9605
|
+
//#endregion
|
|
9606
|
+
//#region src/htmlTagUtils.ts
|
|
9607
|
+
function escapeTagForRegExp(tag) {
|
|
9608
|
+
return tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9609
|
+
}
|
|
9610
|
+
function findTagCloseIndexOutsideQuotes(input) {
|
|
9611
|
+
let inSingle = false;
|
|
9612
|
+
let inDouble = false;
|
|
9613
|
+
for (let i = 0; i < input.length; i++) {
|
|
9614
|
+
const ch = input[i];
|
|
9615
|
+
if (ch === "\\") {
|
|
9616
|
+
i++;
|
|
9617
|
+
continue;
|
|
9618
|
+
}
|
|
9619
|
+
if (!inDouble && ch === "'") {
|
|
9620
|
+
inSingle = !inSingle;
|
|
9621
|
+
continue;
|
|
9622
|
+
}
|
|
9623
|
+
if (!inSingle && ch === "\"") {
|
|
9624
|
+
inDouble = !inDouble;
|
|
9625
|
+
continue;
|
|
9626
|
+
}
|
|
9627
|
+
if (!inSingle && !inDouble && ch === ">") return i;
|
|
9628
|
+
}
|
|
9629
|
+
return -1;
|
|
9630
|
+
}
|
|
9631
|
+
function parseTagAttrs(openTag) {
|
|
9632
|
+
const attrs = [];
|
|
9633
|
+
const attrRegex = /\s([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
|
|
9634
|
+
let match;
|
|
9635
|
+
while ((match = attrRegex.exec(openTag)) !== null) {
|
|
9636
|
+
const attrName = match[1];
|
|
9637
|
+
if (!attrName) continue;
|
|
9638
|
+
const attrValue = match[2] || match[3] || match[4] || "";
|
|
9639
|
+
attrs.push([attrName, attrValue]);
|
|
9640
|
+
}
|
|
9641
|
+
return attrs;
|
|
9642
|
+
}
|
|
9643
|
+
|
|
9644
|
+
//#endregion
|
|
9645
|
+
//#region src/customHtmlTags.ts
|
|
9646
|
+
const HTML_LIKE_TAG_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
9647
|
+
function isHtmlLikeTagName(tag) {
|
|
9648
|
+
return HTML_LIKE_TAG_NAME_RE.test(String(tag ?? "").trim().toLowerCase());
|
|
9649
|
+
}
|
|
9650
|
+
function normalizeCustomHtmlTagName(value) {
|
|
9651
|
+
const raw = String(value ?? "").trim();
|
|
9652
|
+
if (!raw) return "";
|
|
9653
|
+
if (!raw.startsWith("<")) return isHtmlLikeTagName(raw) ? raw.toLowerCase() : "";
|
|
9654
|
+
let index = 1;
|
|
9655
|
+
while (index < raw.length && /\s/.test(raw[index])) index++;
|
|
9656
|
+
if (raw[index] === "/") {
|
|
9657
|
+
index++;
|
|
9658
|
+
while (index < raw.length && /\s/.test(raw[index])) index++;
|
|
9659
|
+
}
|
|
9660
|
+
const start = index;
|
|
9661
|
+
while (index < raw.length && /[\w-]/.test(raw[index])) index++;
|
|
9662
|
+
const normalized = raw.slice(start, index).toLowerCase();
|
|
9663
|
+
const next = raw[index] ?? "";
|
|
9664
|
+
if (next && !/[\s/>]/.test(next)) return "";
|
|
9665
|
+
return isHtmlLikeTagName(normalized) ? normalized : "";
|
|
9666
|
+
}
|
|
9667
|
+
function normalizeCustomHtmlTags(tags) {
|
|
9668
|
+
if (!tags || tags.length === 0) return [];
|
|
9669
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9670
|
+
const normalized = [];
|
|
9671
|
+
for (const tag of tags) {
|
|
9672
|
+
const value = normalizeCustomHtmlTagName(tag);
|
|
9673
|
+
if (!value || seen.has(value)) continue;
|
|
9674
|
+
seen.add(value);
|
|
9675
|
+
normalized.push(value);
|
|
9676
|
+
}
|
|
9677
|
+
return normalized;
|
|
9678
|
+
}
|
|
9679
|
+
function mergeCustomHtmlTags(...lists) {
|
|
9680
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9681
|
+
const normalized = [];
|
|
9682
|
+
for (const list$1 of lists) for (const tag of normalizeCustomHtmlTags(list$1)) {
|
|
9683
|
+
if (seen.has(tag)) continue;
|
|
9684
|
+
seen.add(tag);
|
|
9685
|
+
normalized.push(tag);
|
|
9686
|
+
}
|
|
9687
|
+
return normalized;
|
|
9688
|
+
}
|
|
9689
|
+
function resolveCustomHtmlTags(tags) {
|
|
9690
|
+
const normalized = normalizeCustomHtmlTags(tags);
|
|
9691
|
+
return {
|
|
9692
|
+
key: normalized.join(","),
|
|
9693
|
+
tags: normalized
|
|
9694
|
+
};
|
|
9695
|
+
}
|
|
9696
|
+
function getHtmlTagFromContent(html) {
|
|
9697
|
+
return normalizeCustomHtmlTagName(html);
|
|
9698
|
+
}
|
|
9699
|
+
function hasCompleteHtmlTagContent(html, tag) {
|
|
9700
|
+
const raw = String(html ?? "");
|
|
9701
|
+
const normalizedTag = normalizeCustomHtmlTagName(tag);
|
|
9702
|
+
if (!normalizedTag) return false;
|
|
9703
|
+
const escaped = escapeTagForRegExp(normalizedTag);
|
|
9704
|
+
const openMatch = raw.match(new RegExp(String.raw`^\s*<\s*${escaped}(?:\s[^>]*)?(\s*\/)?>`, "i"));
|
|
9705
|
+
if (!openMatch) return false;
|
|
9706
|
+
if (openMatch[1]) return true;
|
|
9707
|
+
return new RegExp(String.raw`<\s*\/\s*${escaped}\s*>`, "i").test(raw);
|
|
9708
|
+
}
|
|
9709
|
+
function shouldRenderUnknownHtmlTagAsText(html, tag) {
|
|
9710
|
+
const normalizedTag = normalizeCustomHtmlTagName(tag);
|
|
9711
|
+
return Boolean(normalizedTag) && !STANDARD_HTML_TAGS.has(normalizedTag) && !hasCompleteHtmlTagContent(html, normalizedTag);
|
|
9712
|
+
}
|
|
9713
|
+
function stripCustomHtmlWrapper(html, tag) {
|
|
9714
|
+
const raw = String(html ?? "");
|
|
9715
|
+
const normalizedTag = normalizeCustomHtmlTagName(tag);
|
|
9716
|
+
if (!normalizedTag) return raw;
|
|
9717
|
+
const escaped = escapeTagForRegExp(normalizedTag);
|
|
9718
|
+
const openRe = new RegExp(String.raw`^\s*<\s*${escaped}(?:\s[^>]*)?>\s*`, "i");
|
|
9719
|
+
const closeRe = new RegExp(String.raw`\s*<\s*\/\s*${escaped}\s*>\s*$`, "i");
|
|
9720
|
+
return raw.replace(openRe, "").replace(closeRe, "");
|
|
9721
|
+
}
|
|
9722
|
+
|
|
9605
9723
|
//#endregion
|
|
9606
9724
|
//#region src/plugins/fixHtmlInline.ts
|
|
9607
9725
|
const VOID_TAGS = VOID_HTML_TAGS;
|
|
@@ -9621,9 +9739,6 @@ function isHtmlInlineClosingTag(content) {
|
|
|
9621
9739
|
function isSelfClosingHtmlInline(content, tag) {
|
|
9622
9740
|
return VOID_TAGS.has(tag) || /\/\s*>\s*$/.test(content);
|
|
9623
9741
|
}
|
|
9624
|
-
function escapeRegex$2(value) {
|
|
9625
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9626
|
-
}
|
|
9627
9742
|
function findMatchingCloseChildIndex(children, tag) {
|
|
9628
9743
|
let depth = 0;
|
|
9629
9744
|
for (let index = 0; index < children.length; index++) {
|
|
@@ -9657,7 +9772,7 @@ function getTrailingOpenDepth(children, tag) {
|
|
|
9657
9772
|
return depth;
|
|
9658
9773
|
}
|
|
9659
9774
|
function findMatchingCloseRangeInHtml(content, tag, startIndex = 0) {
|
|
9660
|
-
const tokenRe = new RegExp(String.raw`<\s*(\/?)\s*${
|
|
9775
|
+
const tokenRe = new RegExp(String.raw`<\s*(\/?)\s*${escapeTagForRegExp(tag)}(?=[\s>/])[^>]*>`, "gi");
|
|
9661
9776
|
tokenRe.lastIndex = Math.max(0, startIndex);
|
|
9662
9777
|
let depth = 0;
|
|
9663
9778
|
let match;
|
|
@@ -9678,7 +9793,7 @@ function findMatchingCloseRangeInHtml(content, tag, startIndex = 0) {
|
|
|
9678
9793
|
return null;
|
|
9679
9794
|
}
|
|
9680
9795
|
function getTrailingCustomTagDepthInHtml(content, tag) {
|
|
9681
|
-
const tokenRe = new RegExp(String.raw`<\s*(\/?)\s*${
|
|
9796
|
+
const tokenRe = new RegExp(String.raw`<\s*(\/?)\s*${escapeTagForRegExp(tag)}(?=[\s>/])[^>]*>`, "gi");
|
|
9682
9797
|
let depth = 0;
|
|
9683
9798
|
let match;
|
|
9684
9799
|
while ((match = tokenRe.exec(content)) !== null) {
|
|
@@ -9693,23 +9808,6 @@ function getTrailingCustomTagDepthInHtml(content, tag) {
|
|
|
9693
9808
|
}
|
|
9694
9809
|
return depth;
|
|
9695
9810
|
}
|
|
9696
|
-
function findTagCloseIndexOutsideQuotes$3(html) {
|
|
9697
|
-
let inSingle = false;
|
|
9698
|
-
let inDouble = false;
|
|
9699
|
-
for (let i = 0; i < html.length; i++) {
|
|
9700
|
-
const ch = html[i];
|
|
9701
|
-
if (ch === "\"" && !inSingle) {
|
|
9702
|
-
inDouble = !inDouble;
|
|
9703
|
-
continue;
|
|
9704
|
-
}
|
|
9705
|
-
if (ch === "'" && !inDouble) {
|
|
9706
|
-
inSingle = !inSingle;
|
|
9707
|
-
continue;
|
|
9708
|
-
}
|
|
9709
|
-
if (ch === ">" && !inSingle && !inDouble) return i;
|
|
9710
|
-
}
|
|
9711
|
-
return -1;
|
|
9712
|
-
}
|
|
9713
9811
|
function tokenToRaw$1(token) {
|
|
9714
9812
|
const shape = token;
|
|
9715
9813
|
return String(shape.raw ?? shape.content ?? shape.markup ?? "");
|
|
@@ -9737,7 +9835,7 @@ function findFirstIncompleteTag(content, tagSet) {
|
|
|
9737
9835
|
if (idx < 0) continue;
|
|
9738
9836
|
const tag = (m[1] ?? "").toLowerCase();
|
|
9739
9837
|
if (!isCommonHtmlTagOrPrefix(tag, tagSet)) continue;
|
|
9740
|
-
if (findTagCloseIndexOutsideQuotes
|
|
9838
|
+
if (findTagCloseIndexOutsideQuotes(content.slice(idx)) !== -1) continue;
|
|
9741
9839
|
if (!first || idx < first.index) first = {
|
|
9742
9840
|
index: idx,
|
|
9743
9841
|
tag,
|
|
@@ -9749,7 +9847,7 @@ function findFirstIncompleteTag(content, tagSet) {
|
|
|
9749
9847
|
if (idx < 0) continue;
|
|
9750
9848
|
const tag = (m[1] ?? "").toLowerCase();
|
|
9751
9849
|
if (!isCommonHtmlTagOrPrefix(tag, tagSet)) continue;
|
|
9752
|
-
if (findTagCloseIndexOutsideQuotes
|
|
9850
|
+
if (findTagCloseIndexOutsideQuotes(content.slice(idx)) !== -1) continue;
|
|
9753
9851
|
if (!first || idx < first.index) first = {
|
|
9754
9852
|
index: idx,
|
|
9755
9853
|
tag,
|
|
@@ -9815,7 +9913,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
9815
9913
|
cursor = lt + 1;
|
|
9816
9914
|
continue;
|
|
9817
9915
|
}
|
|
9818
|
-
const closeIdx = findTagCloseIndexOutsideQuotes
|
|
9916
|
+
const closeIdx = findTagCloseIndexOutsideQuotes(sub);
|
|
9819
9917
|
if (closeIdx === -1) {
|
|
9820
9918
|
pushTextPart("<", baseToken);
|
|
9821
9919
|
cursor = lt + 1;
|
|
@@ -9853,7 +9951,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
9853
9951
|
if (pending) {
|
|
9854
9952
|
pending.buffer += tokenToRaw$1(child);
|
|
9855
9953
|
pendingAtEnd = pending.buffer;
|
|
9856
|
-
const closeIdx = findTagCloseIndexOutsideQuotes
|
|
9954
|
+
const closeIdx = findTagCloseIndexOutsideQuotes(pending.buffer);
|
|
9857
9955
|
if (closeIdx === -1) continue;
|
|
9858
9956
|
const tagChunk = pending.buffer.slice(0, closeIdx + 1);
|
|
9859
9957
|
const afterChunk = pending.buffer.slice(closeIdx + 1);
|
|
@@ -9871,7 +9969,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
9871
9969
|
if (child.type === "html_inline") {
|
|
9872
9970
|
const content = tokenToRaw$1(child);
|
|
9873
9971
|
const tagName = (content.match(TAG_NAME_AT_START_RE)?.[1] ?? "").toLowerCase();
|
|
9874
|
-
if (tagName && tagSet.has(tagName) && findTagCloseIndexOutsideQuotes
|
|
9972
|
+
if (tagName && tagSet.has(tagName) && findTagCloseIndexOutsideQuotes(content) === -1) {
|
|
9875
9973
|
pending = {
|
|
9876
9974
|
tag: tagName,
|
|
9877
9975
|
buffer: content,
|
|
@@ -9910,11 +10008,8 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
9910
10008
|
]);
|
|
9911
10009
|
const customTagSet = /* @__PURE__ */ new Set();
|
|
9912
10010
|
if (options.customHtmlTags?.length) for (const t of options.customHtmlTags) {
|
|
9913
|
-
const
|
|
9914
|
-
if (!
|
|
9915
|
-
const m = raw.match(/^[<\s/]*([A-Z][\w-]*)/i);
|
|
9916
|
-
if (!m) continue;
|
|
9917
|
-
const name = m[1].toLowerCase();
|
|
10011
|
+
const name = normalizeCustomHtmlTagName(t);
|
|
10012
|
+
if (!name) continue;
|
|
9918
10013
|
customTagSet.add(name);
|
|
9919
10014
|
autoCloseInlineTagSet.add(name);
|
|
9920
10015
|
}
|
|
@@ -9977,7 +10072,7 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
9977
10072
|
if (chunk) {
|
|
9978
10073
|
const openToken = toks[openIndex];
|
|
9979
10074
|
const mergedContent = `${String(openToken.content || "")}\n${chunk}`;
|
|
9980
|
-
const openEnd = findTagCloseIndexOutsideQuotes
|
|
10075
|
+
const openEnd = findTagCloseIndexOutsideQuotes(mergedContent);
|
|
9981
10076
|
const closeRange = openEnd === -1 ? null : findMatchingCloseRangeInHtml(mergedContent, openTag, openEnd + 1);
|
|
9982
10077
|
if (closeRange) {
|
|
9983
10078
|
const before = mergedContent.slice(0, closeRange.end);
|
|
@@ -10176,7 +10271,7 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
10176
10271
|
}
|
|
10177
10272
|
if (customTagSet.has(tag)) {
|
|
10178
10273
|
const raw$2 = String(t.content ?? "");
|
|
10179
|
-
const openEnd = findTagCloseIndexOutsideQuotes
|
|
10274
|
+
const openEnd = findTagCloseIndexOutsideQuotes(raw$2);
|
|
10180
10275
|
const closeRange = openEnd === -1 ? null : findMatchingCloseRangeInHtml(raw$2, tag, openEnd + 1);
|
|
10181
10276
|
t.loading = !!closeRange ? false : t.loading !== void 0 ? t.loading : true;
|
|
10182
10277
|
const endTagIndex$1 = closeRange?.start ?? -1;
|
|
@@ -12222,19 +12317,33 @@ const DIFF_HEADER_PREFIXES = [
|
|
|
12222
12317
|
"@@ "
|
|
12223
12318
|
];
|
|
12224
12319
|
const NEWLINE_RE = /\r?\n/;
|
|
12225
|
-
function
|
|
12320
|
+
function flushPendingDiffHunk(orig, updated, pendingOrig, pendingUpdated) {
|
|
12321
|
+
if (pendingOrig.length > 0) orig.push(...pendingOrig);
|
|
12322
|
+
if (pendingUpdated.length > 0) updated.push(...pendingUpdated);
|
|
12323
|
+
pendingOrig.length = 0;
|
|
12324
|
+
pendingUpdated.length = 0;
|
|
12325
|
+
}
|
|
12326
|
+
function splitUnifiedDiff(content, closed) {
|
|
12226
12327
|
const orig = [];
|
|
12227
12328
|
const updated = [];
|
|
12228
|
-
|
|
12329
|
+
const pendingOrig = [];
|
|
12330
|
+
const pendingUpdated = [];
|
|
12331
|
+
const lines = content.split(NEWLINE_RE);
|
|
12332
|
+
const stableLineCount = Math.max(0, lines.length - 1);
|
|
12333
|
+
const processLine = (rawLine) => {
|
|
12229
12334
|
const line = rawLine;
|
|
12230
|
-
if (DIFF_HEADER_PREFIXES.some((p) => line.startsWith(p)))
|
|
12231
|
-
if (line.length >= 2 && line[0] === "-" && line[1] === " ")
|
|
12232
|
-
else if (line.length >= 2 && line[0] === "+" && line[1] === " ")
|
|
12335
|
+
if (DIFF_HEADER_PREFIXES.some((p) => line.startsWith(p))) return;
|
|
12336
|
+
if (line.length >= 2 && line[0] === "-" && line[1] === " ") pendingOrig.push(` ${line.slice(1)}`);
|
|
12337
|
+
else if (line.length >= 2 && line[0] === "+" && line[1] === " ") pendingUpdated.push(` ${line.slice(1)}`);
|
|
12233
12338
|
else {
|
|
12339
|
+
flushPendingDiffHunk(orig, updated, pendingOrig, pendingUpdated);
|
|
12234
12340
|
orig.push(line);
|
|
12235
12341
|
updated.push(line);
|
|
12236
12342
|
}
|
|
12237
|
-
}
|
|
12343
|
+
};
|
|
12344
|
+
for (let index = 0; index < stableLineCount; index++) processLine(lines[index] ?? "");
|
|
12345
|
+
if (closed && stableLineCount < lines.length) processLine(lines[lines.length - 1] ?? "");
|
|
12346
|
+
if (closed || pendingOrig.length > 0 && pendingUpdated.length > 0) flushPendingDiffHunk(orig, updated, pendingOrig, pendingUpdated);
|
|
12238
12347
|
return {
|
|
12239
12348
|
original: orig.join("\n"),
|
|
12240
12349
|
updated: updated.join("\n")
|
|
@@ -12254,7 +12363,7 @@ function parseFenceToken(token) {
|
|
|
12254
12363
|
let content = String(token.content ?? "");
|
|
12255
12364
|
if (TRAILING_FENCE_LINE_RE.test(content)) content = content.replace(TRAILING_FENCE_LINE_RE, "");
|
|
12256
12365
|
if (diff) {
|
|
12257
|
-
const { original, updated } = splitUnifiedDiff(content);
|
|
12366
|
+
const { original, updated } = splitUnifiedDiff(content, closed === true);
|
|
12258
12367
|
return {
|
|
12259
12368
|
type: "code_block",
|
|
12260
12369
|
language,
|
|
@@ -12340,17 +12449,11 @@ function isClosingTag(html) {
|
|
|
12340
12449
|
function isSelfClosing(tag, html) {
|
|
12341
12450
|
return /\/\s*>\s*$/.test(html) || VOID_HTML_TAGS.has(tag);
|
|
12342
12451
|
}
|
|
12343
|
-
function normalizeCustomTag$1(t) {
|
|
12344
|
-
const raw = String(t ?? "").trim();
|
|
12345
|
-
if (!raw) return "";
|
|
12346
|
-
const m = raw.match(/^[<\s/]*([A-Z][\w-]*)/i);
|
|
12347
|
-
return m ? m[1].toLowerCase() : "";
|
|
12348
|
-
}
|
|
12349
12452
|
function getTagSets(customTags) {
|
|
12350
12453
|
if (!customTags || customTags.length === 0) return getEmptyTagSets();
|
|
12351
12454
|
const cached = TAG_SET_CACHE.get(customTags);
|
|
12352
12455
|
if (cached) return cached;
|
|
12353
|
-
const normalized = customTags.map(
|
|
12456
|
+
const normalized = customTags.map(normalizeCustomHtmlTagName).filter(Boolean);
|
|
12354
12457
|
if (!normalized.length) {
|
|
12355
12458
|
const entry$1 = getEmptyTagSets();
|
|
12356
12459
|
TAG_SET_CACHE.set(customTags, entry$1);
|
|
@@ -12368,18 +12471,6 @@ function tokenToRaw(token) {
|
|
|
12368
12471
|
const raw = shape.raw ?? shape.content ?? shape.markup ?? "";
|
|
12369
12472
|
return String(raw ?? "");
|
|
12370
12473
|
}
|
|
12371
|
-
function parseTagAttrs$1(openTag) {
|
|
12372
|
-
const attrs = [];
|
|
12373
|
-
const attrRegex = /\s([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
|
|
12374
|
-
let match;
|
|
12375
|
-
while ((match = attrRegex.exec(openTag)) !== null) {
|
|
12376
|
-
const attrName = match[1];
|
|
12377
|
-
if (!attrName) continue;
|
|
12378
|
-
const attrValue = match[2] || match[3] || match[4] || "";
|
|
12379
|
-
attrs.push([attrName, attrValue]);
|
|
12380
|
-
}
|
|
12381
|
-
return attrs;
|
|
12382
|
-
}
|
|
12383
12474
|
function getAttrValue$1(attrs, name) {
|
|
12384
12475
|
const lowerName = name.toLowerCase();
|
|
12385
12476
|
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
@@ -12474,7 +12565,7 @@ function parseHtmlInlineCodeToken(token, tokens, i, parseInlineTokens$1, raw, pP
|
|
|
12474
12565
|
}, i + 1];
|
|
12475
12566
|
if (tag === "a") {
|
|
12476
12567
|
const fragment$1 = collectHtmlFragment(tokens, i, tag);
|
|
12477
|
-
const attrs$1 = parseTagAttrs
|
|
12568
|
+
const attrs$1 = parseTagAttrs(code$1);
|
|
12478
12569
|
const innerTokens = fragment$1.innerTokens;
|
|
12479
12570
|
const href = String(getAttrValue$1(attrs$1, "href") ?? "");
|
|
12480
12571
|
const titleAttr = getAttrValue$1(attrs$1, "title");
|
|
@@ -12914,6 +13005,30 @@ function decodeVisibleTextFromRaw(rawText) {
|
|
|
12914
13005
|
}
|
|
12915
13006
|
return output;
|
|
12916
13007
|
}
|
|
13008
|
+
function getRawIndexForVisibleIndex(rawText, visibleIndex) {
|
|
13009
|
+
let outputIndex = 0;
|
|
13010
|
+
for (let rawIndex = 0; rawIndex < rawText.length; rawIndex++) {
|
|
13011
|
+
const char = rawText[rawIndex];
|
|
13012
|
+
const nextChar = rawText[rawIndex + 1];
|
|
13013
|
+
if (char === "\\" && nextChar && ESCAPABLE_PUNCTUATION.has(nextChar)) {
|
|
13014
|
+
if (outputIndex === visibleIndex) return rawIndex + 1;
|
|
13015
|
+
outputIndex++;
|
|
13016
|
+
rawIndex++;
|
|
13017
|
+
continue;
|
|
13018
|
+
}
|
|
13019
|
+
if (outputIndex === visibleIndex) return rawIndex;
|
|
13020
|
+
outputIndex++;
|
|
13021
|
+
}
|
|
13022
|
+
return -1;
|
|
13023
|
+
}
|
|
13024
|
+
function isEscapedVisibleChar(rawText, visibleIndex, expectedChar) {
|
|
13025
|
+
const rawIndex = getRawIndexForVisibleIndex(rawText, visibleIndex);
|
|
13026
|
+
if (rawIndex === -1) return false;
|
|
13027
|
+
if (expectedChar && rawText[rawIndex] !== expectedChar) return false;
|
|
13028
|
+
let slashCount = 0;
|
|
13029
|
+
for (let i = rawIndex - 1; i >= 0 && rawText[i] === "\\"; i--) slashCount++;
|
|
13030
|
+
return slashCount % 2 === 1;
|
|
13031
|
+
}
|
|
12917
13032
|
const WORD_CHAR_RE = /[\p{L}\p{N}]/u;
|
|
12918
13033
|
const WORD_ONLY_RE = /^[\p{L}\p{N}]+$/u;
|
|
12919
13034
|
function isWordChar(ch) {
|
|
@@ -13359,9 +13474,11 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13359
13474
|
handleLinkOpen(token);
|
|
13360
13475
|
break;
|
|
13361
13476
|
case "image":
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13477
|
+
if (!recoverOuterImageLinkStartFromImageToken(token)) {
|
|
13478
|
+
resetCurrentTextNode();
|
|
13479
|
+
pushNode(parseImageToken(token));
|
|
13480
|
+
i++;
|
|
13481
|
+
}
|
|
13365
13482
|
break;
|
|
13366
13483
|
case "strong_open": {
|
|
13367
13484
|
resetCurrentTextNode();
|
|
@@ -13506,7 +13623,9 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13506
13623
|
const displayText = String(token.text ?? "");
|
|
13507
13624
|
pushText(displayText, displayText);
|
|
13508
13625
|
i++;
|
|
13509
|
-
} else if (
|
|
13626
|
+
} else if (recoverOuterImageLinkFromSyntheticLinkToken(token)) i++;
|
|
13627
|
+
else if (recoverMarkdownImageFromTrailingBang(token)) i++;
|
|
13628
|
+
else if (recoverMarkdownLinkFromTrailingText(token)) i++;
|
|
13510
13629
|
else {
|
|
13511
13630
|
pushToken(token);
|
|
13512
13631
|
i++;
|
|
@@ -13567,6 +13686,8 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13567
13686
|
i++;
|
|
13568
13687
|
return;
|
|
13569
13688
|
}
|
|
13689
|
+
if (recoverOuterImageLinkFromRawText(content)) return;
|
|
13690
|
+
if (recoverOuterImageLinkMidStateFromText(content)) return;
|
|
13570
13691
|
if (!(content.includes("*") || content.includes("_") || content.includes("~") || content.includes("`") || content.includes("[") || content.includes("!") || content.includes("$") || content.includes("|") || content.includes("("))) {
|
|
13571
13692
|
commitTextNode(content, token, tokens[i - 1], nextToken);
|
|
13572
13693
|
i++;
|
|
@@ -13574,12 +13695,12 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13574
13695
|
}
|
|
13575
13696
|
if (handleCheckboxLike(content)) return;
|
|
13576
13697
|
const preToken = tokens[i - 1];
|
|
13577
|
-
if (content === "[" && !nextToken?.markup?.includes("*") || content === "]" && !preToken?.markup?.includes("*")) {
|
|
13698
|
+
if (content === "[" && !nextToken?.markup?.includes("*") && !hasEscapedMarkup(token, "\\[") || content === "]" && !preToken?.markup?.includes("*") && !hasEscapedMarkup(token, "\\]")) {
|
|
13578
13699
|
i++;
|
|
13579
13700
|
return;
|
|
13580
13701
|
}
|
|
13581
13702
|
if (handleInlineCodeContent(rawContent, token)) return;
|
|
13582
|
-
if (handleInlineImageContent(content
|
|
13703
|
+
if (handleInlineImageContent(content)) return;
|
|
13583
13704
|
if (tokens[i + 1]?.type !== "link_open" && handleInlineLinkContent(content, token)) return;
|
|
13584
13705
|
const reparsedNodes = tryReparseCollapsedInlineText(rawContent);
|
|
13585
13706
|
if (reparsedNodes) {
|
|
@@ -13593,6 +13714,13 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13593
13714
|
i++;
|
|
13594
13715
|
}
|
|
13595
13716
|
function handleLinkOpen(token) {
|
|
13717
|
+
if (shouldTreatLinkOpenAsTextInEscapedOuterImageTail()) {
|
|
13718
|
+
const { node: node$1, nextIndex: nextIndex$1 } = parseLinkToken(tokens, i, options);
|
|
13719
|
+
const text$1 = String(node$1.text || node$1.href || "");
|
|
13720
|
+
pushText(text$1, text$1);
|
|
13721
|
+
i = nextIndex$1;
|
|
13722
|
+
return;
|
|
13723
|
+
}
|
|
13596
13724
|
resetCurrentTextNode();
|
|
13597
13725
|
const { node, nextIndex } = parseLinkToken(tokens, i, options);
|
|
13598
13726
|
i = nextIndex;
|
|
@@ -13662,6 +13790,149 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13662
13790
|
});
|
|
13663
13791
|
return true;
|
|
13664
13792
|
}
|
|
13793
|
+
function recoverMarkdownImageFromTrailingBang(token) {
|
|
13794
|
+
if (token.type !== "link") return false;
|
|
13795
|
+
const previous = result[result.length - 1];
|
|
13796
|
+
const previousToken = tokens[i - 1];
|
|
13797
|
+
if (!previous || previous.type !== "text" || previousToken?.type !== "text") return false;
|
|
13798
|
+
const previousContent = String(previous.content ?? "");
|
|
13799
|
+
const previousTokenContent = String(previousToken.content ?? "");
|
|
13800
|
+
if (!previousContent.endsWith("!") || !previousTokenContent.endsWith("!")) return false;
|
|
13801
|
+
if (hasEscapedMarkup(previousToken, "\\!")) return false;
|
|
13802
|
+
const before = previousContent.slice(0, -1);
|
|
13803
|
+
if (before) {
|
|
13804
|
+
previous.content = before;
|
|
13805
|
+
previous.raw = before;
|
|
13806
|
+
currentTextNode = previous;
|
|
13807
|
+
} else {
|
|
13808
|
+
result.pop();
|
|
13809
|
+
currentTextNode = null;
|
|
13810
|
+
}
|
|
13811
|
+
const linkToken = token;
|
|
13812
|
+
const alt = String(linkToken.text ?? linkToken.children?.map((child) => String(child?.content ?? child?.raw ?? "")).join("") ?? "");
|
|
13813
|
+
const href = String(linkToken.href ?? "");
|
|
13814
|
+
const title = linkToken.title == null || linkToken.title === "" ? null : String(linkToken.title);
|
|
13815
|
+
pushParsed({
|
|
13816
|
+
type: "image",
|
|
13817
|
+
src: href,
|
|
13818
|
+
alt,
|
|
13819
|
+
title,
|
|
13820
|
+
raw: String(``),
|
|
13821
|
+
loading: Boolean(linkToken.loading)
|
|
13822
|
+
});
|
|
13823
|
+
return true;
|
|
13824
|
+
}
|
|
13825
|
+
function buildLoadingOuterImageLinkNode(imageNode, href = "", title = null) {
|
|
13826
|
+
const text$1 = String(imageNode.alt ?? imageNode.raw ?? "");
|
|
13827
|
+
return {
|
|
13828
|
+
type: "link",
|
|
13829
|
+
href,
|
|
13830
|
+
title,
|
|
13831
|
+
text: text$1,
|
|
13832
|
+
children: [imageNode],
|
|
13833
|
+
raw: String(`[${text$1}](${href}${title ? ` "${title}"` : ""})`),
|
|
13834
|
+
loading: true
|
|
13835
|
+
};
|
|
13836
|
+
}
|
|
13837
|
+
function buildLoadingImageNodeFromRaw(raw$1) {
|
|
13838
|
+
const normalizedRaw = raw$1.startsWith(";
|
|
13841
|
+
return {
|
|
13842
|
+
type: "image",
|
|
13843
|
+
src: "",
|
|
13844
|
+
alt: closeIdx === -1 ? innerRaw.replace(/\]$/, "") : innerRaw.slice(0, closeIdx),
|
|
13845
|
+
title: null,
|
|
13846
|
+
raw: normalizedRaw,
|
|
13847
|
+
loading: true
|
|
13848
|
+
};
|
|
13849
|
+
}
|
|
13850
|
+
function recoverOuterImageLinkFromRawText(content) {
|
|
13851
|
+
const outerStart = content.indexOf("[![");
|
|
13852
|
+
if (outerStart === -1) return false;
|
|
13853
|
+
if (typeof raw === "string" && tokens.length === 1 && isEscapedVisibleChar(raw, outerStart, "[")) return false;
|
|
13854
|
+
const before = content.slice(0, outerStart);
|
|
13855
|
+
if (before) pushText(before, before);
|
|
13856
|
+
pushParsed(buildLoadingOuterImageLinkNode(buildLoadingImageNodeFromRaw(content.slice(outerStart + 1))));
|
|
13857
|
+
i++;
|
|
13858
|
+
return true;
|
|
13859
|
+
}
|
|
13860
|
+
function recoverOuterImageLinkStartFromImageToken(token) {
|
|
13861
|
+
if (options?.final) return false;
|
|
13862
|
+
const previousToken = tokens[i - 1];
|
|
13863
|
+
if (previousToken?.type !== "text") return false;
|
|
13864
|
+
if (!String(previousToken.content ?? "").endsWith("[")) return false;
|
|
13865
|
+
if (hasEscapedMarkup(previousToken, "\\[")) return false;
|
|
13866
|
+
const previous = result[result.length - 1];
|
|
13867
|
+
if (previous?.type === "text" && previous.content.endsWith("[")) {
|
|
13868
|
+
const before = previous.content.slice(0, -1);
|
|
13869
|
+
if (before) {
|
|
13870
|
+
previous.content = before;
|
|
13871
|
+
previous.raw = before;
|
|
13872
|
+
currentTextNode = previous;
|
|
13873
|
+
} else {
|
|
13874
|
+
result.pop();
|
|
13875
|
+
currentTextNode = null;
|
|
13876
|
+
}
|
|
13877
|
+
}
|
|
13878
|
+
pushParsed(buildLoadingOuterImageLinkNode(parseImageToken(token)));
|
|
13879
|
+
i++;
|
|
13880
|
+
return true;
|
|
13881
|
+
}
|
|
13882
|
+
function recoverOuterImageLinkFromSyntheticLinkToken(token) {
|
|
13883
|
+
if (token.type !== "link") return false;
|
|
13884
|
+
const linkToken = token;
|
|
13885
|
+
const raw$1 = String(linkToken.raw ?? "");
|
|
13886
|
+
const text$1 = String(linkToken.text ?? "");
|
|
13887
|
+
if (!raw$1.startsWith("[![") && !text$1.startsWith("![")) return false;
|
|
13888
|
+
const imageTitle = linkToken.title == null || linkToken.title === "" ? null : String(linkToken.title);
|
|
13889
|
+
pushParsed(buildLoadingOuterImageLinkNode({
|
|
13890
|
+
type: "image",
|
|
13891
|
+
src: String(linkToken.href ?? ""),
|
|
13892
|
+
alt: text$1.replace(/^!\[/, "").replace(/\]$/, ""),
|
|
13893
|
+
title: imageTitle,
|
|
13894
|
+
raw: raw$1.startsWith("[) return false;
|
|
13901
|
+
const outerOpenToken = tokens[i - 2];
|
|
13902
|
+
if (outerOpenToken?.type === "text" && String(outerOpenToken.content ?? "").endsWith("[") && hasEscapedMarkup(outerOpenToken, "\\[")) return false;
|
|
13903
|
+
const previous = result[result.length - 1];
|
|
13904
|
+
if (previous?.type !== "image" && previous?.type !== "link") return false;
|
|
13905
|
+
const previousLink = previous?.type === "link" && Array.isArray(previous.children) && previous.children.length === 1 && previous.children[0]?.type === "image" ? result.pop() : null;
|
|
13906
|
+
const imageNode = previousLink ? previousLink.children[0] : result.pop();
|
|
13907
|
+
if (!imageNode || imageNode.type !== "image") return false;
|
|
13908
|
+
const nextToken = tokens[i + 1];
|
|
13909
|
+
let href = String(previousLink?.href ?? "");
|
|
13910
|
+
let title = previousLink?.title == null ? null : String(previousLink.title);
|
|
13911
|
+
let loading = true;
|
|
13912
|
+
if (nextToken?.type === "link_open") {
|
|
13913
|
+
const { node, nextIndex } = parseLinkToken(tokens, i + 1, options);
|
|
13914
|
+
href = node.href;
|
|
13915
|
+
title = node.title;
|
|
13916
|
+
loading = true;
|
|
13917
|
+
i = nextIndex;
|
|
13918
|
+
} else {
|
|
13919
|
+
href = content.slice(2);
|
|
13920
|
+
if (href.includes("\"")) {
|
|
13921
|
+
const parts = href.split("\"");
|
|
13922
|
+
href = String(parts[0] ?? "").trim();
|
|
13923
|
+
title = parts[1] == null ? null : String(parts[1]).trim();
|
|
13924
|
+
}
|
|
13925
|
+
i++;
|
|
13926
|
+
}
|
|
13927
|
+
const linkNode = buildLoadingOuterImageLinkNode(imageNode, href, title);
|
|
13928
|
+
linkNode.loading = loading;
|
|
13929
|
+
pushParsed(linkNode);
|
|
13930
|
+
return true;
|
|
13931
|
+
}
|
|
13932
|
+
function shouldTreatLinkOpenAsTextInEscapedOuterImageTail() {
|
|
13933
|
+
const outerOpenToken = tokens[i - 3];
|
|
13934
|
+
return tokens[i - 2]?.type === "image" && tokens[i - 1]?.type === "text" && String(tokens[i - 1].content ?? "") === "](" && outerOpenToken?.type === "text" && String(outerOpenToken.content ?? "").endsWith("[") && hasEscapedMarkup(outerOpenToken, "\\[");
|
|
13935
|
+
}
|
|
13665
13936
|
function handleInlineLinkContent(content, _token) {
|
|
13666
13937
|
const linkStart = content.indexOf("[");
|
|
13667
13938
|
if (linkStart === -1) return false;
|
|
@@ -13808,19 +14079,21 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
13808
14079
|
}
|
|
13809
14080
|
return false;
|
|
13810
14081
|
}
|
|
13811
|
-
function handleInlineImageContent(content
|
|
14082
|
+
function handleInlineImageContent(content) {
|
|
13812
14083
|
const imageStart = content.indexOf("![");
|
|
13813
14084
|
if (imageStart === -1) return false;
|
|
13814
14085
|
const textNodeContent = content.slice(0, imageStart);
|
|
13815
|
-
if (!currentTextNode) currentTextNode = {
|
|
14086
|
+
if (textNodeContent && !currentTextNode) currentTextNode = {
|
|
13816
14087
|
type: "text",
|
|
13817
14088
|
content: textNodeContent,
|
|
13818
14089
|
raw: textNodeContent
|
|
13819
14090
|
};
|
|
13820
|
-
else currentTextNode.content += textNodeContent;
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
14091
|
+
else if (textNodeContent && currentTextNode) currentTextNode.content += textNodeContent;
|
|
14092
|
+
if (currentTextNode) {
|
|
14093
|
+
result.push(currentTextNode);
|
|
14094
|
+
currentTextNode = null;
|
|
14095
|
+
}
|
|
14096
|
+
pushParsed(buildLoadingImageNodeFromRaw(content.slice(imageStart)));
|
|
13824
14097
|
i++;
|
|
13825
14098
|
return true;
|
|
13826
14099
|
}
|
|
@@ -14264,27 +14537,6 @@ function parseHeading(tokens, index, options) {
|
|
|
14264
14537
|
|
|
14265
14538
|
//#endregion
|
|
14266
14539
|
//#region src/parser/node-parsers/html-block-parser.ts
|
|
14267
|
-
function findTagCloseIndexOutsideQuotes$2(input) {
|
|
14268
|
-
let inSingle = false;
|
|
14269
|
-
let inDouble = false;
|
|
14270
|
-
for (let i = 0; i < input.length; i++) {
|
|
14271
|
-
const ch = input[i];
|
|
14272
|
-
if (ch === "\\") {
|
|
14273
|
-
i++;
|
|
14274
|
-
continue;
|
|
14275
|
-
}
|
|
14276
|
-
if (!inDouble && ch === "'") {
|
|
14277
|
-
inSingle = !inSingle;
|
|
14278
|
-
continue;
|
|
14279
|
-
}
|
|
14280
|
-
if (!inSingle && ch === "\"") {
|
|
14281
|
-
inDouble = !inDouble;
|
|
14282
|
-
continue;
|
|
14283
|
-
}
|
|
14284
|
-
if (!inSingle && !inDouble && ch === ">") return i;
|
|
14285
|
-
}
|
|
14286
|
-
return -1;
|
|
14287
|
-
}
|
|
14288
14540
|
function findMatchingCloseTagEnd(rawHtml, tag, startIndex) {
|
|
14289
14541
|
const lowerTag = tag.toLowerCase();
|
|
14290
14542
|
const openTagRe = new RegExp(String.raw`^<\s*${lowerTag}(?=\s|>|/)`, "i");
|
|
@@ -14296,7 +14548,7 @@ function findMatchingCloseTagEnd(rawHtml, tag, startIndex) {
|
|
|
14296
14548
|
if (lt === -1) return -1;
|
|
14297
14549
|
const slice = rawHtml.slice(lt);
|
|
14298
14550
|
if (closeTagRe.test(slice)) {
|
|
14299
|
-
const endRel = findTagCloseIndexOutsideQuotes
|
|
14551
|
+
const endRel = findTagCloseIndexOutsideQuotes(slice);
|
|
14300
14552
|
if (endRel === -1) return -1;
|
|
14301
14553
|
if (depth === 0) return lt + endRel + 1;
|
|
14302
14554
|
depth--;
|
|
@@ -14304,7 +14556,7 @@ function findMatchingCloseTagEnd(rawHtml, tag, startIndex) {
|
|
|
14304
14556
|
continue;
|
|
14305
14557
|
}
|
|
14306
14558
|
if (openTagRe.test(slice)) {
|
|
14307
|
-
const endRel = findTagCloseIndexOutsideQuotes
|
|
14559
|
+
const endRel = findTagCloseIndexOutsideQuotes(slice);
|
|
14308
14560
|
if (endRel === -1) return -1;
|
|
14309
14561
|
const rawTag = slice.slice(0, endRel + 1);
|
|
14310
14562
|
if (!/\/\s*>$/.test(rawTag)) depth++;
|
|
@@ -14315,18 +14567,6 @@ function findMatchingCloseTagEnd(rawHtml, tag, startIndex) {
|
|
|
14315
14567
|
}
|
|
14316
14568
|
return -1;
|
|
14317
14569
|
}
|
|
14318
|
-
function parseTagAttrs(openTag) {
|
|
14319
|
-
const attrs = [];
|
|
14320
|
-
const attrRegex = /\s([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
|
|
14321
|
-
let match;
|
|
14322
|
-
while ((match = attrRegex.exec(openTag)) !== null) {
|
|
14323
|
-
const attrName = match[1];
|
|
14324
|
-
if (!attrName) continue;
|
|
14325
|
-
const attrValue = match[2] || match[3] || match[4] || "";
|
|
14326
|
-
attrs.push([attrName, attrValue]);
|
|
14327
|
-
}
|
|
14328
|
-
return attrs;
|
|
14329
|
-
}
|
|
14330
14570
|
function parseHtmlBlock(token) {
|
|
14331
14571
|
const raw = String(token.content ?? "");
|
|
14332
14572
|
if (/^\s*<!--/.test(raw) || /^\s*<!/.test(raw) || /^\s*<\?/.test(raw)) return {
|
|
@@ -14344,7 +14584,7 @@ function parseHtmlBlock(token) {
|
|
|
14344
14584
|
tag: "",
|
|
14345
14585
|
loading: false
|
|
14346
14586
|
};
|
|
14347
|
-
const openEnd = findTagCloseIndexOutsideQuotes
|
|
14587
|
+
const openEnd = findTagCloseIndexOutsideQuotes(raw);
|
|
14348
14588
|
const openTag = openEnd === -1 ? raw : raw.slice(0, openEnd + 1);
|
|
14349
14589
|
const selfClosing = openEnd !== -1 && /\/\s*>$/.test(openTag);
|
|
14350
14590
|
const isVoid = VOID_HTML_TAGS.has(tag);
|
|
@@ -14463,17 +14703,11 @@ function getEmptyHtmlTagSets() {
|
|
|
14463
14703
|
};
|
|
14464
14704
|
return emptyHtmlTagSets;
|
|
14465
14705
|
}
|
|
14466
|
-
function normalizeCustomTag(t) {
|
|
14467
|
-
const raw = String(t ?? "").trim();
|
|
14468
|
-
if (!raw) return "";
|
|
14469
|
-
const m = raw.match(/^[<\s/]*([A-Z][\w-]*)/i);
|
|
14470
|
-
return m ? m[1].toLowerCase() : "";
|
|
14471
|
-
}
|
|
14472
14706
|
function getHtmlTagSets(customTags) {
|
|
14473
14707
|
if (!customTags || customTags.length === 0) return getEmptyHtmlTagSets();
|
|
14474
14708
|
const cached = HTML_TAG_SET_CACHE.get(customTags);
|
|
14475
14709
|
if (cached) return cached;
|
|
14476
|
-
const normalized = customTags.map(
|
|
14710
|
+
const normalized = customTags.map(normalizeCustomHtmlTagName).filter(Boolean);
|
|
14477
14711
|
if (!normalized.length) {
|
|
14478
14712
|
const entry$1 = getEmptyHtmlTagSets();
|
|
14479
14713
|
HTML_TAG_SET_CACHE.set(customTags, entry$1);
|
|
@@ -14551,27 +14785,6 @@ function parseVmrContainer(tokens, index, options) {
|
|
|
14551
14785
|
raw
|
|
14552
14786
|
}, hasCloseToken ? j + 1 : j];
|
|
14553
14787
|
}
|
|
14554
|
-
function findTagCloseIndexOutsideQuotes$1(input) {
|
|
14555
|
-
let inSingle = false;
|
|
14556
|
-
let inDouble = false;
|
|
14557
|
-
for (let i = 0; i < input.length; i++) {
|
|
14558
|
-
const ch = input[i];
|
|
14559
|
-
if (ch === "\\") {
|
|
14560
|
-
i++;
|
|
14561
|
-
continue;
|
|
14562
|
-
}
|
|
14563
|
-
if (!inDouble && ch === "'") {
|
|
14564
|
-
inSingle = !inSingle;
|
|
14565
|
-
continue;
|
|
14566
|
-
}
|
|
14567
|
-
if (!inSingle && ch === "\"") {
|
|
14568
|
-
inDouble = !inDouble;
|
|
14569
|
-
continue;
|
|
14570
|
-
}
|
|
14571
|
-
if (!inSingle && !inDouble && ch === ">") return i;
|
|
14572
|
-
}
|
|
14573
|
-
return -1;
|
|
14574
|
-
}
|
|
14575
14788
|
function stripWrapperNewlines(s) {
|
|
14576
14789
|
return s.replace(/^\r?\n/, "").replace(/\r?\n$/, "");
|
|
14577
14790
|
}
|
|
@@ -14580,14 +14793,11 @@ function stripTrailingPartialClosingTag(inner, tag) {
|
|
|
14580
14793
|
const re = new RegExp(String.raw`[\t ]*<\s*\/\s*${tag}[^>]*$`, "i");
|
|
14581
14794
|
return inner.replace(re, "");
|
|
14582
14795
|
}
|
|
14583
|
-
function escapeRegex$1(value) {
|
|
14584
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14585
|
-
}
|
|
14586
14796
|
function findMatchingCloseTagRange(rawHtml, tag, startIndex) {
|
|
14587
14797
|
if (!rawHtml || !tag) return null;
|
|
14588
14798
|
const lowerTag = tag.toLowerCase();
|
|
14589
|
-
const openTagRe = new RegExp(String.raw`^<\s*${
|
|
14590
|
-
const closeTagRe = new RegExp(String.raw`^<\s*\/\s*${
|
|
14799
|
+
const openTagRe = new RegExp(String.raw`^<\s*${escapeTagForRegExp(lowerTag)}(?=\s|>|/)`, "i");
|
|
14800
|
+
const closeTagRe = new RegExp(String.raw`^<\s*\/\s*${escapeTagForRegExp(lowerTag)}(?=\s|>)`, "i");
|
|
14591
14801
|
let depth = 0;
|
|
14592
14802
|
let index = Math.max(0, startIndex);
|
|
14593
14803
|
while (index < rawHtml.length) {
|
|
@@ -14595,7 +14805,7 @@ function findMatchingCloseTagRange(rawHtml, tag, startIndex) {
|
|
|
14595
14805
|
if (lt === -1) break;
|
|
14596
14806
|
const slice = rawHtml.slice(lt);
|
|
14597
14807
|
if (closeTagRe.test(slice)) {
|
|
14598
|
-
const endRel = findTagCloseIndexOutsideQuotes
|
|
14808
|
+
const endRel = findTagCloseIndexOutsideQuotes(slice);
|
|
14599
14809
|
if (endRel === -1) return null;
|
|
14600
14810
|
if (depth === 0) return {
|
|
14601
14811
|
start: lt,
|
|
@@ -14606,7 +14816,7 @@ function findMatchingCloseTagRange(rawHtml, tag, startIndex) {
|
|
|
14606
14816
|
continue;
|
|
14607
14817
|
}
|
|
14608
14818
|
if (openTagRe.test(slice)) {
|
|
14609
|
-
const endRel = findTagCloseIndexOutsideQuotes
|
|
14819
|
+
const endRel = findTagCloseIndexOutsideQuotes(slice);
|
|
14610
14820
|
if (endRel === -1) return null;
|
|
14611
14821
|
const raw = slice.slice(0, endRel + 1);
|
|
14612
14822
|
if (!/\/\s*>$/.test(raw)) depth++;
|
|
@@ -14626,7 +14836,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
|
|
|
14626
14836
|
if (!openMatch || openMatch.index == null) return null;
|
|
14627
14837
|
const openStart = openMatch.index;
|
|
14628
14838
|
const openSlice = source.slice(openStart);
|
|
14629
|
-
const openEndRel = findTagCloseIndexOutsideQuotes
|
|
14839
|
+
const openEndRel = findTagCloseIndexOutsideQuotes(openSlice);
|
|
14630
14840
|
if (openEndRel === -1) return null;
|
|
14631
14841
|
const openEnd = openStart + openEndRel;
|
|
14632
14842
|
if (/\/\s*>\s*$/.test(openSlice.slice(0, openEndRel + 1))) {
|
|
@@ -14667,7 +14877,7 @@ function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
|
|
|
14667
14877
|
continue;
|
|
14668
14878
|
}
|
|
14669
14879
|
if (isOpenAt(lt)) {
|
|
14670
|
-
const rel = findTagCloseIndexOutsideQuotes
|
|
14880
|
+
const rel = findTagCloseIndexOutsideQuotes(source.slice(lt));
|
|
14671
14881
|
if (rel === -1) return null;
|
|
14672
14882
|
depth++;
|
|
14673
14883
|
i = lt + rel + 1;
|
|
@@ -14723,7 +14933,7 @@ function parseBasicBlockToken(tokens, index, options) {
|
|
|
14723
14933
|
const fromSource = findNextCustomHtmlBlockFromSource(source, tag, Math.max(clampNonNegative(cursor), clampNonNegative(mappedLineStart)));
|
|
14724
14934
|
if (fromSource) options.__customHtmlBlockCursor = fromSource.end;
|
|
14725
14935
|
const rawHtml = String(fromSource?.raw ?? htmlBlockNode.raw ?? "");
|
|
14726
|
-
const openEnd = findTagCloseIndexOutsideQuotes
|
|
14936
|
+
const openEnd = findTagCloseIndexOutsideQuotes(rawHtml);
|
|
14727
14937
|
const openTag = openEnd !== -1 ? rawHtml.slice(0, openEnd + 1) : rawHtml;
|
|
14728
14938
|
const selfClosing = openEnd !== -1 && /\/\s*>\s*$/.test(openTag);
|
|
14729
14939
|
const closeRange = openEnd === -1 ? null : findMatchingCloseTagRange(rawHtml, tag, openEnd + 1);
|
|
@@ -14818,26 +15028,17 @@ function parseParagraph(tokens, index, options) {
|
|
|
14818
15028
|
|
|
14819
15029
|
//#endregion
|
|
14820
15030
|
//#region src/parser/index.ts
|
|
14821
|
-
function normalizeTagName(t) {
|
|
14822
|
-
const raw = String(t ?? "").trim();
|
|
14823
|
-
if (!raw) return "";
|
|
14824
|
-
const m = raw.match(/^[<\s/]*([A-Z][\w-]*)/i);
|
|
14825
|
-
return m ? m[1].toLowerCase() : "";
|
|
14826
|
-
}
|
|
14827
15031
|
function getCustomHtmlTagSet(options) {
|
|
14828
15032
|
const custom = options?.customHtmlTags;
|
|
14829
15033
|
if (!Array.isArray(custom) || custom.length === 0) return null;
|
|
14830
|
-
const normalized = custom
|
|
15034
|
+
const normalized = normalizeCustomHtmlTags(custom);
|
|
14831
15035
|
return normalized.length ? new Set(normalized) : null;
|
|
14832
15036
|
}
|
|
14833
15037
|
function buildAllowedHtmlTagSet(options) {
|
|
14834
15038
|
const custom = options?.customHtmlTags;
|
|
14835
15039
|
if (!Array.isArray(custom) || custom.length === 0) return STANDARD_HTML_TAGS;
|
|
14836
15040
|
const set = new Set(STANDARD_HTML_TAGS);
|
|
14837
|
-
for (const
|
|
14838
|
-
const name = normalizeTagName(t);
|
|
14839
|
-
if (name) set.add(name);
|
|
14840
|
-
}
|
|
15041
|
+
for (const name of normalizeCustomHtmlTags(custom)) if (name) set.add(name);
|
|
14841
15042
|
return set;
|
|
14842
15043
|
}
|
|
14843
15044
|
function stringifyInlineNodeRaw(node) {
|
|
@@ -14896,30 +15097,6 @@ function parseStandaloneHtmlDocument(markdown) {
|
|
|
14896
15097
|
loading: false
|
|
14897
15098
|
}];
|
|
14898
15099
|
}
|
|
14899
|
-
function escapeRegex(value) {
|
|
14900
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14901
|
-
}
|
|
14902
|
-
function findTagCloseIndexOutsideQuotes(input) {
|
|
14903
|
-
let inSingle = false;
|
|
14904
|
-
let inDouble = false;
|
|
14905
|
-
for (let i = 0; i < input.length; i++) {
|
|
14906
|
-
const ch = input[i];
|
|
14907
|
-
if (ch === "\\") {
|
|
14908
|
-
i++;
|
|
14909
|
-
continue;
|
|
14910
|
-
}
|
|
14911
|
-
if (!inDouble && ch === "'") {
|
|
14912
|
-
inSingle = !inSingle;
|
|
14913
|
-
continue;
|
|
14914
|
-
}
|
|
14915
|
-
if (!inSingle && ch === "\"") {
|
|
14916
|
-
inDouble = !inDouble;
|
|
14917
|
-
continue;
|
|
14918
|
-
}
|
|
14919
|
-
if (!inSingle && !inDouble && ch === ">") return i;
|
|
14920
|
-
}
|
|
14921
|
-
return -1;
|
|
14922
|
-
}
|
|
14923
15100
|
function getMergeableNodeRaw(node) {
|
|
14924
15101
|
const raw = node?.raw;
|
|
14925
15102
|
if (typeof raw === "string") return raw;
|
|
@@ -14927,41 +15104,15 @@ function getMergeableNodeRaw(node) {
|
|
|
14927
15104
|
if (typeof content === "string") return content;
|
|
14928
15105
|
return "";
|
|
14929
15106
|
}
|
|
14930
|
-
|
|
14931
|
-
"
|
|
14932
|
-
"
|
|
14933
|
-
"
|
|
14934
|
-
|
|
14935
|
-
"figcaption",
|
|
14936
|
-
"figure",
|
|
14937
|
-
"footer",
|
|
14938
|
-
"h1",
|
|
14939
|
-
"h2",
|
|
14940
|
-
"h3",
|
|
14941
|
-
"h4",
|
|
14942
|
-
"h5",
|
|
14943
|
-
"h6",
|
|
14944
|
-
"header",
|
|
14945
|
-
"li",
|
|
14946
|
-
"main",
|
|
14947
|
-
"nav",
|
|
14948
|
-
"ol",
|
|
14949
|
-
"p",
|
|
14950
|
-
"pre",
|
|
14951
|
-
"section",
|
|
14952
|
-
"summary",
|
|
14953
|
-
"table",
|
|
14954
|
-
"tbody",
|
|
14955
|
-
"td",
|
|
14956
|
-
"th",
|
|
14957
|
-
"thead",
|
|
14958
|
-
"tr",
|
|
14959
|
-
"ul"
|
|
14960
|
-
]);
|
|
15107
|
+
function isCloseOnlyHtmlBlockForTag(node, tag) {
|
|
15108
|
+
if (node.type !== "html_block" || !tag) return false;
|
|
15109
|
+
const raw = String(node?.raw ?? node?.content ?? "");
|
|
15110
|
+
return new RegExp(String.raw`^\s*<\s*\/\s*${escapeTagForRegExp(tag)}\s*>\s*$`, "i").test(raw);
|
|
15111
|
+
}
|
|
14961
15112
|
function findNextHtmlBlockFromSource(source, tag, startIndex) {
|
|
14962
15113
|
if (!source || !tag) return null;
|
|
14963
15114
|
const lowerTag = tag.toLowerCase();
|
|
14964
|
-
const openRe = new RegExp(String.raw`<\s*${
|
|
15115
|
+
const openRe = new RegExp(String.raw`<\s*${escapeTagForRegExp(lowerTag)}(?=\s|>|/)`, "gi");
|
|
14965
15116
|
openRe.lastIndex = Math.max(0, startIndex);
|
|
14966
15117
|
const openMatch = openRe.exec(source);
|
|
14967
15118
|
if (!openMatch || openMatch.index == null) return null;
|
|
@@ -14980,11 +15131,11 @@ function findNextHtmlBlockFromSource(source, tag, startIndex) {
|
|
|
14980
15131
|
let index = openEnd + 1;
|
|
14981
15132
|
const isOpenAt = (pos) => {
|
|
14982
15133
|
const slice = source.slice(pos);
|
|
14983
|
-
return new RegExp(String.raw`^<\s*${
|
|
15134
|
+
return new RegExp(String.raw`^<\s*${escapeTagForRegExp(lowerTag)}(?=\s|>|/)`, "i").test(slice);
|
|
14984
15135
|
};
|
|
14985
15136
|
const isCloseAt = (pos) => {
|
|
14986
15137
|
const slice = source.slice(pos);
|
|
14987
|
-
return new RegExp(String.raw`^<\s*\/\s*${
|
|
15138
|
+
return new RegExp(String.raw`^<\s*\/\s*${escapeTagForRegExp(lowerTag)}(?=\s|>)`, "i").test(slice);
|
|
14988
15139
|
};
|
|
14989
15140
|
while (index < source.length) {
|
|
14990
15141
|
const lt = source.indexOf("<", index);
|
|
@@ -15070,7 +15221,7 @@ function isDetailsCloseHtmlBlock(node) {
|
|
|
15070
15221
|
return /^\s*<\/details\b/i.test(raw);
|
|
15071
15222
|
}
|
|
15072
15223
|
function findLastClosingTagStart(raw, tag) {
|
|
15073
|
-
const closeRe = new RegExp(String.raw`<\s*\/\s*${
|
|
15224
|
+
const closeRe = new RegExp(String.raw`<\s*\/\s*${escapeTagForRegExp(tag)}(?=\s|>)`, "gi");
|
|
15074
15225
|
let last = -1;
|
|
15075
15226
|
let match;
|
|
15076
15227
|
while ((match = closeRe.exec(raw)) !== null) last = match.index;
|
|
@@ -15196,14 +15347,22 @@ function mergeSplitTopLevelHtmlBlocks(nodes, final, source) {
|
|
|
15196
15347
|
let sourceHtmlCursor = 0;
|
|
15197
15348
|
for (let i = 0; i < merged.length; i++) {
|
|
15198
15349
|
const node = merged[i];
|
|
15199
|
-
|
|
15350
|
+
const nodeRaw = getMergeableNodeRaw(node);
|
|
15351
|
+
const nodePos = nodeRaw ? source.indexOf(nodeRaw, sourceHtmlCursor) : -1;
|
|
15352
|
+
if (node?.type !== "html_block") {
|
|
15353
|
+
if (nodePos !== -1) sourceHtmlCursor = nodePos + nodeRaw.length;
|
|
15354
|
+
continue;
|
|
15355
|
+
}
|
|
15200
15356
|
const tag = String(node?.tag ?? "").toLowerCase();
|
|
15201
15357
|
if (!tag) continue;
|
|
15202
|
-
if (
|
|
15203
|
-
|
|
15358
|
+
if (tag === "details") {
|
|
15359
|
+
if (nodePos !== -1) sourceHtmlCursor = nodePos + nodeRaw.length;
|
|
15360
|
+
continue;
|
|
15361
|
+
}
|
|
15362
|
+
const exact = findNextHtmlBlockFromSource(source, tag, nodePos !== -1 ? nodePos : sourceHtmlCursor);
|
|
15204
15363
|
if (!exact) continue;
|
|
15205
15364
|
sourceHtmlCursor = exact.end;
|
|
15206
|
-
const currentContent = String(node?.content ??
|
|
15365
|
+
const currentContent = String(node?.content ?? nodeRaw);
|
|
15207
15366
|
const currentRaw = String(node?.raw ?? currentContent);
|
|
15208
15367
|
const nextContent = buildHtmlBlockContent(exact.raw, tag, exact.closed);
|
|
15209
15368
|
const desiredLoading = !final && !exact.closed;
|
|
@@ -15212,10 +15371,14 @@ function mergeSplitTopLevelHtmlBlocks(nodes, final, source) {
|
|
|
15212
15371
|
node.raw = exact.raw;
|
|
15213
15372
|
node.loading = desiredLoading;
|
|
15214
15373
|
if (!needsExpansion) continue;
|
|
15215
|
-
let tailCursor = findApproximateConsumedPrefixEnd(exact.raw,
|
|
15374
|
+
let tailCursor = findApproximateConsumedPrefixEnd(exact.raw, currentRaw);
|
|
15216
15375
|
if (tailCursor === -1) tailCursor = 0;
|
|
15217
15376
|
const j = i + 1;
|
|
15218
15377
|
while (j < merged.length) {
|
|
15378
|
+
if (exact.closed && isCloseOnlyHtmlBlockForTag(merged[j], tag)) {
|
|
15379
|
+
merged.splice(j, 1);
|
|
15380
|
+
continue;
|
|
15381
|
+
}
|
|
15219
15382
|
const nextRaw = getMergeableNodeRaw(merged[j]);
|
|
15220
15383
|
if (!nextRaw) break;
|
|
15221
15384
|
const nextPos = exact.raw.indexOf(nextRaw, tailCursor);
|
|
@@ -15394,7 +15557,7 @@ function ensureBlankLineBeforeInlineMultilineCustomHtmlBlocks(markdown, tags) {
|
|
|
15394
15557
|
}
|
|
15395
15558
|
return false;
|
|
15396
15559
|
};
|
|
15397
|
-
const findTagCloseIndexOutsideQuotes$
|
|
15560
|
+
const findTagCloseIndexOutsideQuotes$1 = (input) => {
|
|
15398
15561
|
let inSingle = false;
|
|
15399
15562
|
let inDouble = false;
|
|
15400
15563
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -15443,7 +15606,7 @@ function ensureBlankLineBeforeInlineMultilineCustomHtmlBlocks(markdown, tags) {
|
|
|
15443
15606
|
i++;
|
|
15444
15607
|
continue;
|
|
15445
15608
|
}
|
|
15446
|
-
const closeIdxRel = findTagCloseIndexOutsideQuotes$
|
|
15609
|
+
const closeIdxRel = findTagCloseIndexOutsideQuotes$1(line.slice(i));
|
|
15447
15610
|
if (closeIdxRel === -1) {
|
|
15448
15611
|
hasRenderablePrefix = true;
|
|
15449
15612
|
i++;
|
|
@@ -15547,7 +15710,7 @@ function normalizeCustomHtmlOpeningTagSameLine(markdown, tags) {
|
|
|
15547
15710
|
while (i < s.length && isIndentWs(s[i])) i++;
|
|
15548
15711
|
return s.slice(i);
|
|
15549
15712
|
};
|
|
15550
|
-
const findTagCloseIndexOutsideQuotes$
|
|
15713
|
+
const findTagCloseIndexOutsideQuotes$1 = (input) => {
|
|
15551
15714
|
let inSingle = false;
|
|
15552
15715
|
let inDouble = false;
|
|
15553
15716
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -15619,7 +15782,7 @@ function normalizeCustomHtmlOpeningTagSameLine(markdown, tags) {
|
|
|
15619
15782
|
if (i === nameStart) return line;
|
|
15620
15783
|
const tagName = line.slice(nameStart, i).toLowerCase();
|
|
15621
15784
|
if (!tagSet.has(tagName)) return line;
|
|
15622
|
-
const gtRel = findTagCloseIndexOutsideQuotes$
|
|
15785
|
+
const gtRel = findTagCloseIndexOutsideQuotes$1(line.slice(i));
|
|
15623
15786
|
if (gtRel === -1) return line;
|
|
15624
15787
|
const gt = i + gtRel;
|
|
15625
15788
|
if (hasClosingTagOnLine(line, gt + 1, tagName)) return line;
|
|
@@ -16012,9 +16175,7 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
|
16012
16175
|
else if (/\n[[(]\n*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(\n\[|\n\()+\n*$/g, "\n");
|
|
16013
16176
|
}
|
|
16014
16177
|
if (options.customHtmlTags?.length && safeMarkdown.includes("<")) {
|
|
16015
|
-
const tags = options.customHtmlTags
|
|
16016
|
-
return (t.match(/^[<\s/]*([A-Z][\w-]*)/i)?.[1] ?? "").toLowerCase();
|
|
16017
|
-
}).filter(Boolean);
|
|
16178
|
+
const tags = normalizeCustomHtmlTags(options.customHtmlTags);
|
|
16018
16179
|
if (tags.length) {
|
|
16019
16180
|
safeMarkdown = ensureBlankLineBeforeInlineMultilineCustomHtmlBlocks(safeMarkdown, tags);
|
|
16020
16181
|
safeMarkdown = normalizeCustomHtmlOpeningTagSameLine(safeMarkdown, tags);
|
|
@@ -16172,6 +16333,160 @@ function processTokens(tokens, options) {
|
|
|
16172
16333
|
return result;
|
|
16173
16334
|
}
|
|
16174
16335
|
|
|
16336
|
+
//#endregion
|
|
16337
|
+
//#region src/htmlRenderUtils.ts
|
|
16338
|
+
const CUSTOM_TAG_REGEX = /<([a-z][a-z0-9-]*)\b[^>]*>/gi;
|
|
16339
|
+
function hasOwn(obj, key) {
|
|
16340
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
16341
|
+
}
|
|
16342
|
+
function isCustomHtmlComponentTag(tagName, customComponents) {
|
|
16343
|
+
const lowerTag = tagName.toLowerCase();
|
|
16344
|
+
if (EXTENDED_STANDARD_HTML_TAGS.has(lowerTag)) return false;
|
|
16345
|
+
return hasOwn(customComponents, lowerTag) || hasOwn(customComponents, tagName);
|
|
16346
|
+
}
|
|
16347
|
+
function sanitizeHtmlAttrs(attrs) {
|
|
16348
|
+
const clean = {};
|
|
16349
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
16350
|
+
const lowerKey = key.toLowerCase();
|
|
16351
|
+
if (DANGEROUS_HTML_ATTRS.has(lowerKey)) continue;
|
|
16352
|
+
if (URL_HTML_ATTRS.has(lowerKey) && value && isUnsafeHtmlUrl(value)) continue;
|
|
16353
|
+
clean[key] = value;
|
|
16354
|
+
}
|
|
16355
|
+
return clean;
|
|
16356
|
+
}
|
|
16357
|
+
function convertHtmlPropValue(value, key) {
|
|
16358
|
+
const lowerKey = key.toLowerCase();
|
|
16359
|
+
if ([
|
|
16360
|
+
"checked",
|
|
16361
|
+
"disabled",
|
|
16362
|
+
"readonly",
|
|
16363
|
+
"required",
|
|
16364
|
+
"autofocus",
|
|
16365
|
+
"multiple",
|
|
16366
|
+
"hidden"
|
|
16367
|
+
].includes(lowerKey)) return value === "true" || value === "" || value === key;
|
|
16368
|
+
if ([
|
|
16369
|
+
"value",
|
|
16370
|
+
"min",
|
|
16371
|
+
"max",
|
|
16372
|
+
"step",
|
|
16373
|
+
"width",
|
|
16374
|
+
"height",
|
|
16375
|
+
"size",
|
|
16376
|
+
"maxlength"
|
|
16377
|
+
].includes(lowerKey)) {
|
|
16378
|
+
const num = Number(value);
|
|
16379
|
+
if (value !== "" && !Number.isNaN(num)) return num;
|
|
16380
|
+
}
|
|
16381
|
+
return value;
|
|
16382
|
+
}
|
|
16383
|
+
function convertHtmlAttrsToProps(attrs) {
|
|
16384
|
+
const result = {};
|
|
16385
|
+
for (const [key, value] of Object.entries(attrs)) result[key] = convertHtmlPropValue(value, key);
|
|
16386
|
+
return result;
|
|
16387
|
+
}
|
|
16388
|
+
function isMeaningfulText(text$1) {
|
|
16389
|
+
return text$1.trim().length > 0;
|
|
16390
|
+
}
|
|
16391
|
+
function tokenizeHtml(html) {
|
|
16392
|
+
const tokens = [];
|
|
16393
|
+
let pos = 0;
|
|
16394
|
+
while (pos < html.length) {
|
|
16395
|
+
if (html.startsWith("<!--", pos)) {
|
|
16396
|
+
const commentEnd = html.indexOf("-->", pos);
|
|
16397
|
+
if (commentEnd !== -1) {
|
|
16398
|
+
pos = commentEnd + 3;
|
|
16399
|
+
continue;
|
|
16400
|
+
}
|
|
16401
|
+
break;
|
|
16402
|
+
}
|
|
16403
|
+
const tagStart = html.indexOf("<", pos);
|
|
16404
|
+
if (tagStart === -1) {
|
|
16405
|
+
if (pos < html.length) {
|
|
16406
|
+
const remainingText = html.slice(pos);
|
|
16407
|
+
if (isMeaningfulText(remainingText)) tokens.push({
|
|
16408
|
+
type: "text",
|
|
16409
|
+
content: remainingText
|
|
16410
|
+
});
|
|
16411
|
+
}
|
|
16412
|
+
break;
|
|
16413
|
+
}
|
|
16414
|
+
if (tagStart > pos) {
|
|
16415
|
+
const textContent = html.slice(pos, tagStart);
|
|
16416
|
+
if (isMeaningfulText(textContent)) tokens.push({
|
|
16417
|
+
type: "text",
|
|
16418
|
+
content: textContent
|
|
16419
|
+
});
|
|
16420
|
+
}
|
|
16421
|
+
if (html.startsWith("![CDATA[", tagStart + 1)) {
|
|
16422
|
+
const cdataEnd = html.indexOf("]]>", tagStart);
|
|
16423
|
+
if (cdataEnd !== -1) {
|
|
16424
|
+
tokens.push({
|
|
16425
|
+
type: "text",
|
|
16426
|
+
content: html.slice(tagStart, cdataEnd + 3)
|
|
16427
|
+
});
|
|
16428
|
+
pos = cdataEnd + 3;
|
|
16429
|
+
continue;
|
|
16430
|
+
}
|
|
16431
|
+
break;
|
|
16432
|
+
}
|
|
16433
|
+
if (html.startsWith("!", tagStart + 1)) {
|
|
16434
|
+
const specialEnd = html.indexOf(">", tagStart);
|
|
16435
|
+
if (specialEnd !== -1) {
|
|
16436
|
+
pos = specialEnd + 1;
|
|
16437
|
+
continue;
|
|
16438
|
+
}
|
|
16439
|
+
break;
|
|
16440
|
+
}
|
|
16441
|
+
const tagEnd = html.indexOf(">", tagStart);
|
|
16442
|
+
if (tagEnd === -1) break;
|
|
16443
|
+
const tagContent = html.slice(tagStart + 1, tagEnd).trim();
|
|
16444
|
+
const isClosingTag$1 = tagContent.startsWith("/");
|
|
16445
|
+
const isSelfClosing$1 = tagContent.endsWith("/");
|
|
16446
|
+
if (isClosingTag$1) {
|
|
16447
|
+
const tagName = tagContent.slice(1).trim();
|
|
16448
|
+
tokens.push({
|
|
16449
|
+
type: "tag_close",
|
|
16450
|
+
tagName
|
|
16451
|
+
});
|
|
16452
|
+
} else {
|
|
16453
|
+
const spaceIndex = tagContent.indexOf(" ");
|
|
16454
|
+
let tagName;
|
|
16455
|
+
let attrsStr = "";
|
|
16456
|
+
if (spaceIndex === -1) tagName = isSelfClosing$1 ? tagContent.slice(0, -1).trim() : tagContent.trim();
|
|
16457
|
+
else {
|
|
16458
|
+
tagName = tagContent.slice(0, spaceIndex).trim();
|
|
16459
|
+
attrsStr = tagContent.slice(spaceIndex + 1);
|
|
16460
|
+
}
|
|
16461
|
+
const attrs = {};
|
|
16462
|
+
if (attrsStr) {
|
|
16463
|
+
const attrRegex = /([^\s=]+)(?:=(?:"([^"]*)"|'([^']*)'|(\S*)))?/g;
|
|
16464
|
+
let attrMatch;
|
|
16465
|
+
while ((attrMatch = attrRegex.exec(attrsStr)) !== null) {
|
|
16466
|
+
const name = attrMatch[1];
|
|
16467
|
+
const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
16468
|
+
if (name && !name.endsWith("/")) attrs[name] = value;
|
|
16469
|
+
}
|
|
16470
|
+
}
|
|
16471
|
+
tokens.push({
|
|
16472
|
+
type: isSelfClosing$1 || VOID_HTML_TAGS.has(tagName.toLowerCase()) ? "self_closing" : "tag_open",
|
|
16473
|
+
tagName,
|
|
16474
|
+
attrs
|
|
16475
|
+
});
|
|
16476
|
+
}
|
|
16477
|
+
pos = tagEnd + 1;
|
|
16478
|
+
}
|
|
16479
|
+
return tokens;
|
|
16480
|
+
}
|
|
16481
|
+
function hasCustomHtmlComponents(content, customComponents) {
|
|
16482
|
+
if (!content || !content.includes("<")) return false;
|
|
16483
|
+
if (!customComponents || Object.keys(customComponents).length === 0) return false;
|
|
16484
|
+
CUSTOM_TAG_REGEX.lastIndex = 0;
|
|
16485
|
+
let match;
|
|
16486
|
+
while ((match = CUSTOM_TAG_REGEX.exec(content)) !== null) if (isCustomHtmlComponentTag(match[1], customComponents)) return true;
|
|
16487
|
+
return false;
|
|
16488
|
+
}
|
|
16489
|
+
|
|
16175
16490
|
//#endregion
|
|
16176
16491
|
//#region src/index.ts
|
|
16177
16492
|
const _registeredMarkdownPlugins = [];
|
|
@@ -16312,5 +16627,5 @@ function getMarkdown(msgId = `editor-${Date.now()}`, options = {}) {
|
|
|
16312
16627
|
}
|
|
16313
16628
|
|
|
16314
16629
|
//#endregion
|
|
16315
|
-
export { BLOCKED_HTML_TAGS, BLOCKED_HTML_TAG_NAMES, BLOCK_HTML_TAG_NAMES, DANGEROUS_HTML_ATTRS, DANGEROUS_HTML_ATTR_NAMES, ESCAPED_TEX_BRACE_COMMANDS, EXTENDED_STANDARD_HTML_TAGS, EXTENDED_STANDARD_HTML_TAG_NAMES, INLINE_HTML_TAG_NAMES, KATEX_COMMANDS, STANDARD_BLOCK_HTML_TAGS, STANDARD_HTML_TAGS, SVG_HTML_TAG_NAMES, TEX_BRACE_COMMANDS, URL_HTML_ATTRS, URL_HTML_ATTR_NAMES, VOID_HTML_TAGS, VOID_HTML_TAG_NAMES, applyContainers, applyMath, clearRegisteredMarkdownPlugins, findMatchingClose, getMarkdown, isMathLike, isUnsafeHtmlUrl, normalizeStandaloneBackslashT, parseFenceToken, parseInlineTokens, parseMarkdownToStructure, processTokens, registerMarkdownPlugin, setDefaultMathOptions, stripHtmlControlAndWhitespace };
|
|
16630
|
+
export { BLOCKED_HTML_TAGS, BLOCKED_HTML_TAG_NAMES, BLOCK_HTML_TAG_NAMES, DANGEROUS_HTML_ATTRS, DANGEROUS_HTML_ATTR_NAMES, ESCAPED_TEX_BRACE_COMMANDS, EXTENDED_STANDARD_HTML_TAGS, EXTENDED_STANDARD_HTML_TAG_NAMES, INLINE_HTML_TAG_NAMES, KATEX_COMMANDS, STANDARD_BLOCK_HTML_TAGS, STANDARD_HTML_TAGS, SVG_HTML_TAG_NAMES, TEX_BRACE_COMMANDS, URL_HTML_ATTRS, URL_HTML_ATTR_NAMES, VOID_HTML_TAGS, VOID_HTML_TAG_NAMES, applyContainers, applyMath, clearRegisteredMarkdownPlugins, convertHtmlAttrsToProps, convertHtmlPropValue, findMatchingClose, getHtmlTagFromContent, getMarkdown, hasCompleteHtmlTagContent, hasCustomHtmlComponents, isCustomHtmlComponentTag, isHtmlLikeTagName, isMathLike, isUnsafeHtmlUrl, mergeCustomHtmlTags, normalizeCustomHtmlTagName, normalizeCustomHtmlTags, normalizeStandaloneBackslashT, parseFenceToken, parseInlineTokens, parseMarkdownToStructure, processTokens, registerMarkdownPlugin, resolveCustomHtmlTags, sanitizeHtmlAttrs, setDefaultMathOptions, shouldRenderUnknownHtmlTagAsText, stripCustomHtmlWrapper, stripHtmlControlAndWhitespace, tokenizeHtml };
|
|
16316
16631
|
//# sourceMappingURL=index.js.map
|