stream-markdown-parser 0.0.43 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +435 -39
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6819,6 +6819,7 @@ const BASE_COMMON_HTML_TAGS = new Set([
|
|
|
6819
6819
|
"del",
|
|
6820
6820
|
"dfn",
|
|
6821
6821
|
"em",
|
|
6822
|
+
"font",
|
|
6822
6823
|
"i",
|
|
6823
6824
|
"img",
|
|
6824
6825
|
"input",
|
|
@@ -6874,7 +6875,7 @@ const BASE_COMMON_HTML_TAGS = new Set([
|
|
|
6874
6875
|
const OPEN_TAG_RE = /<([A-Z][\w-]*)(?=[\s/>]|$)/gi;
|
|
6875
6876
|
const CLOSE_TAG_RE = /<\/\s*([A-Z][\w-]*)(?=[\s/>]|$)/gi;
|
|
6876
6877
|
const TAG_NAME_AT_START_RE = /^<\s*(?:\/\s*)?([A-Z][\w-]*)/i;
|
|
6877
|
-
function findTagCloseIndexOutsideQuotes(html) {
|
|
6878
|
+
function findTagCloseIndexOutsideQuotes$1(html) {
|
|
6878
6879
|
let inSingle = false;
|
|
6879
6880
|
let inDouble = false;
|
|
6880
6881
|
for (let i = 0; i < html.length; i++) {
|
|
@@ -6917,8 +6918,8 @@ function findFirstIncompleteTag(content, tagSet) {
|
|
|
6917
6918
|
const idx = m.index ?? -1;
|
|
6918
6919
|
if (idx < 0) continue;
|
|
6919
6920
|
const tag = (m[1] ?? "").toLowerCase();
|
|
6920
|
-
if (!
|
|
6921
|
-
if (findTagCloseIndexOutsideQuotes(content.slice(idx)) !== -1) continue;
|
|
6921
|
+
if (!isCommonHtmlTagOrPrefix(tag, tagSet)) continue;
|
|
6922
|
+
if (findTagCloseIndexOutsideQuotes$1(content.slice(idx)) !== -1) continue;
|
|
6922
6923
|
if (!first || idx < first.index) first = {
|
|
6923
6924
|
index: idx,
|
|
6924
6925
|
tag,
|
|
@@ -6930,7 +6931,7 @@ function findFirstIncompleteTag(content, tagSet) {
|
|
|
6930
6931
|
if (idx < 0) continue;
|
|
6931
6932
|
const tag = (m[1] ?? "").toLowerCase();
|
|
6932
6933
|
if (!isCommonHtmlTagOrPrefix(tag, tagSet)) continue;
|
|
6933
|
-
if (findTagCloseIndexOutsideQuotes(content.slice(idx)) !== -1) continue;
|
|
6934
|
+
if (findTagCloseIndexOutsideQuotes$1(content.slice(idx)) !== -1) continue;
|
|
6934
6935
|
if (!first || idx < first.index) first = {
|
|
6935
6936
|
index: idx,
|
|
6936
6937
|
tag,
|
|
@@ -6996,7 +6997,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
6996
6997
|
cursor = lt + 1;
|
|
6997
6998
|
continue;
|
|
6998
6999
|
}
|
|
6999
|
-
const closeIdx = findTagCloseIndexOutsideQuotes(sub);
|
|
7000
|
+
const closeIdx = findTagCloseIndexOutsideQuotes$1(sub);
|
|
7000
7001
|
if (closeIdx === -1) {
|
|
7001
7002
|
pushTextPart("<", baseToken);
|
|
7002
7003
|
cursor = lt + 1;
|
|
@@ -7034,7 +7035,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
7034
7035
|
if (pending) {
|
|
7035
7036
|
pending.buffer += tokenToRaw$1(child);
|
|
7036
7037
|
pendingAtEnd = pending.buffer;
|
|
7037
|
-
const closeIdx = findTagCloseIndexOutsideQuotes(pending.buffer);
|
|
7038
|
+
const closeIdx = findTagCloseIndexOutsideQuotes$1(pending.buffer);
|
|
7038
7039
|
if (closeIdx === -1) continue;
|
|
7039
7040
|
const tagChunk = pending.buffer.slice(0, closeIdx + 1);
|
|
7040
7041
|
const afterChunk = pending.buffer.slice(closeIdx + 1);
|
|
@@ -7052,7 +7053,7 @@ function fixStreamingHtmlInlineChildren(children, tagSet) {
|
|
|
7052
7053
|
if (child.type === "html_inline") {
|
|
7053
7054
|
const content = tokenToRaw$1(child);
|
|
7054
7055
|
const tagName = (content.match(TAG_NAME_AT_START_RE)?.[1] ?? "").toLowerCase();
|
|
7055
|
-
if (tagName && tagSet.has(tagName) && findTagCloseIndexOutsideQuotes(content) === -1) {
|
|
7056
|
+
if (tagName && tagSet.has(tagName) && findTagCloseIndexOutsideQuotes$1(content) === -1) {
|
|
7056
7057
|
pending = {
|
|
7057
7058
|
tag: tagName,
|
|
7058
7059
|
buffer: content,
|
|
@@ -7132,10 +7133,69 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
7132
7133
|
const tagStack = [];
|
|
7133
7134
|
for (let i = 0; i < toks.length; i++) {
|
|
7134
7135
|
const t = toks[i];
|
|
7136
|
+
if (tagStack.length > 0) {
|
|
7137
|
+
const [openTag, openIndex] = tagStack[tagStack.length - 1];
|
|
7138
|
+
if (i !== openIndex) {
|
|
7139
|
+
if (t.type === "paragraph_open" || t.type === "paragraph_close") {
|
|
7140
|
+
toks.splice(i, 1);
|
|
7141
|
+
i--;
|
|
7142
|
+
continue;
|
|
7143
|
+
}
|
|
7144
|
+
const chunk = String(t.content ?? t.raw ?? "");
|
|
7145
|
+
const closeRe = new RegExp(`<\\s*\\/\\s*${openTag}\\s*>`, "i");
|
|
7146
|
+
const closeMatch = chunk ? closeRe.exec(chunk) : null;
|
|
7147
|
+
const isClosingTag$1 = !!closeMatch;
|
|
7148
|
+
if (chunk) {
|
|
7149
|
+
const openToken = toks[openIndex];
|
|
7150
|
+
if (closeMatch && typeof closeMatch.index === "number") {
|
|
7151
|
+
const end = closeMatch.index + String(closeMatch[0] ?? "").length;
|
|
7152
|
+
const before = chunk.slice(0, end);
|
|
7153
|
+
const after = chunk.slice(end);
|
|
7154
|
+
openToken.content = `${String(openToken.content || "")}\n${before}`;
|
|
7155
|
+
openToken.loading = false;
|
|
7156
|
+
const afterTrimmed = after.replace(/^\s+/, "");
|
|
7157
|
+
toks.splice(i, 1);
|
|
7158
|
+
tagStack.pop();
|
|
7159
|
+
if (afterTrimmed) toks.splice(i, 0, afterTrimmed.startsWith("<") ? {
|
|
7160
|
+
type: "html_block",
|
|
7161
|
+
content: afterTrimmed
|
|
7162
|
+
} : {
|
|
7163
|
+
type: "inline",
|
|
7164
|
+
content: afterTrimmed,
|
|
7165
|
+
children: [{
|
|
7166
|
+
type: "text",
|
|
7167
|
+
content: afterTrimmed,
|
|
7168
|
+
raw: afterTrimmed
|
|
7169
|
+
}]
|
|
7170
|
+
});
|
|
7171
|
+
i--;
|
|
7172
|
+
continue;
|
|
7173
|
+
}
|
|
7174
|
+
openToken.content = `${String(openToken.content || "")}\n${chunk}`;
|
|
7175
|
+
if (openToken.loading !== false) openToken.loading = !isClosingTag$1;
|
|
7176
|
+
}
|
|
7177
|
+
toks.splice(i, 1);
|
|
7178
|
+
i--;
|
|
7179
|
+
if (isClosingTag$1) tagStack.pop();
|
|
7180
|
+
continue;
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7135
7183
|
if (t.type === "html_block") {
|
|
7136
|
-
const
|
|
7137
|
-
|
|
7138
|
-
|
|
7184
|
+
const rawContent = String(t.content || "");
|
|
7185
|
+
const tag = (rawContent.match(/<\s*(?:\/\s*)?([^\s>/]+)/)?.[1] ?? "").toLowerCase();
|
|
7186
|
+
if (!/^\s*<\s*\//.test(rawContent)) {
|
|
7187
|
+
if (tag) {
|
|
7188
|
+
if (!new RegExp(`<\\s*\\/\\s*${tag}\\s*>`, "i").test(rawContent)) tagStack.push([tag, i]);
|
|
7189
|
+
}
|
|
7190
|
+
} else if (tagStack.length > 0 && tag && tagStack[tagStack.length - 1][0] === tag) {
|
|
7191
|
+
const [, openIndex] = tagStack[tagStack.length - 1];
|
|
7192
|
+
const openToken = toks[openIndex];
|
|
7193
|
+
openToken.content = `${String(openToken.content || "")}\n${rawContent}`;
|
|
7194
|
+
openToken.loading = false;
|
|
7195
|
+
tagStack.pop();
|
|
7196
|
+
toks.splice(i, 1);
|
|
7197
|
+
i--;
|
|
7198
|
+
}
|
|
7139
7199
|
continue;
|
|
7140
7200
|
} else if (tagStack.length > 0) {
|
|
7141
7201
|
if (t.type === "paragraph_open" || t.type === "paragraph_close") {
|
|
@@ -7156,10 +7216,153 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
7156
7216
|
i--;
|
|
7157
7217
|
} else continue;
|
|
7158
7218
|
}
|
|
7219
|
+
if (customTagSet.size > 0) {
|
|
7220
|
+
const openReCache = /* @__PURE__ */ new Map();
|
|
7221
|
+
const closeReCache = /* @__PURE__ */ new Map();
|
|
7222
|
+
const getOpenRe = (tag) => {
|
|
7223
|
+
let r = openReCache.get(tag);
|
|
7224
|
+
if (!r) {
|
|
7225
|
+
r = new RegExp(`<\\s*${tag}\\b`, "i");
|
|
7226
|
+
openReCache.set(tag, r);
|
|
7227
|
+
}
|
|
7228
|
+
return r;
|
|
7229
|
+
};
|
|
7230
|
+
const getCloseRe = (tag) => {
|
|
7231
|
+
let r = closeReCache.get(tag);
|
|
7232
|
+
if (!r) {
|
|
7233
|
+
r = new RegExp(`<\\s*\\/\\s*${tag}\\s*>`, "i");
|
|
7234
|
+
closeReCache.set(tag, r);
|
|
7235
|
+
}
|
|
7236
|
+
return r;
|
|
7237
|
+
};
|
|
7238
|
+
const stack = [];
|
|
7239
|
+
for (let i = 0; i < toks.length; i++) {
|
|
7240
|
+
const tok = toks[i];
|
|
7241
|
+
const content = String(tok.content ?? "");
|
|
7242
|
+
if (stack.length > 0) {
|
|
7243
|
+
const top = stack[stack.length - 1];
|
|
7244
|
+
const openTok = toks[top.index];
|
|
7245
|
+
if (tok.type === "html_block" && getCloseRe(top.tag).test(content)) {
|
|
7246
|
+
openTok.content = `${String(openTok.content ?? "")}\n${content}`;
|
|
7247
|
+
if (Array.isArray(openTok.children)) openTok.children.push({
|
|
7248
|
+
type: "html_inline",
|
|
7249
|
+
content: `</${top.tag}>`,
|
|
7250
|
+
raw: `</${top.tag}>`
|
|
7251
|
+
});
|
|
7252
|
+
toks.splice(i, 1);
|
|
7253
|
+
i--;
|
|
7254
|
+
stack.pop();
|
|
7255
|
+
continue;
|
|
7256
|
+
}
|
|
7257
|
+
if (tok.type !== "inline") continue;
|
|
7258
|
+
const children = Array.isArray(tok.children) ? tok.children : [];
|
|
7259
|
+
const closeChildIndex = children.findIndex((c) => {
|
|
7260
|
+
if (!c || c.type !== "html_inline") return false;
|
|
7261
|
+
const cContent = String(c.content ?? "");
|
|
7262
|
+
return /^\s*<\s*\//.test(cContent) && cContent.toLowerCase().includes(top.tag);
|
|
7263
|
+
});
|
|
7264
|
+
if (closeChildIndex !== -1) {
|
|
7265
|
+
const beforeChildren = children.slice(0, closeChildIndex + 1);
|
|
7266
|
+
const afterChildren = children.slice(closeChildIndex + 1);
|
|
7267
|
+
const beforeText = beforeChildren.map((c) => String(c?.content ?? c?.raw ?? "")).join("");
|
|
7268
|
+
openTok.content = `${String(openTok.content ?? "")}\n${beforeText}`;
|
|
7269
|
+
if (Array.isArray(openTok.children)) openTok.children.push(...beforeChildren);
|
|
7270
|
+
if (afterChildren.length) {
|
|
7271
|
+
const afterText = afterChildren.map((c) => String(c.content ?? c.raw ?? "")).join("");
|
|
7272
|
+
if (afterText.trim()) {
|
|
7273
|
+
const trimmed = afterText.replace(/^\s+/, "");
|
|
7274
|
+
if (trimmed.startsWith("<")) toks.splice(i, 1, {
|
|
7275
|
+
type: "html_block",
|
|
7276
|
+
content: trimmed
|
|
7277
|
+
});
|
|
7278
|
+
else toks.splice(i, 1, {
|
|
7279
|
+
type: "paragraph_open",
|
|
7280
|
+
tag: "p",
|
|
7281
|
+
nesting: 1
|
|
7282
|
+
}, {
|
|
7283
|
+
type: "inline",
|
|
7284
|
+
tag: "",
|
|
7285
|
+
nesting: 0,
|
|
7286
|
+
content: afterText,
|
|
7287
|
+
children: [{
|
|
7288
|
+
type: "text",
|
|
7289
|
+
content: afterText,
|
|
7290
|
+
raw: afterText
|
|
7291
|
+
}]
|
|
7292
|
+
}, {
|
|
7293
|
+
type: "paragraph_close",
|
|
7294
|
+
tag: "p",
|
|
7295
|
+
nesting: -1
|
|
7296
|
+
});
|
|
7297
|
+
} else {
|
|
7298
|
+
toks.splice(i, 1);
|
|
7299
|
+
i--;
|
|
7300
|
+
}
|
|
7301
|
+
} else {
|
|
7302
|
+
toks.splice(i, 1);
|
|
7303
|
+
i--;
|
|
7304
|
+
}
|
|
7305
|
+
stack.pop();
|
|
7306
|
+
continue;
|
|
7307
|
+
}
|
|
7308
|
+
openTok.content = `${String(openTok.content ?? "")}\n${content}`;
|
|
7309
|
+
if (Array.isArray(openTok.children)) openTok.children.push(...children);
|
|
7310
|
+
toks.splice(i, 1);
|
|
7311
|
+
i--;
|
|
7312
|
+
continue;
|
|
7313
|
+
}
|
|
7314
|
+
if (tok.type !== "inline") continue;
|
|
7315
|
+
for (const tag of customTagSet) if (getOpenRe(tag).test(content) && !getCloseRe(tag).test(content)) {
|
|
7316
|
+
stack.push({
|
|
7317
|
+
tag,
|
|
7318
|
+
index: i
|
|
7319
|
+
});
|
|
7320
|
+
break;
|
|
7321
|
+
}
|
|
7322
|
+
}
|
|
7323
|
+
}
|
|
7324
|
+
{
|
|
7325
|
+
let depth = 0;
|
|
7326
|
+
for (let i = 0; i < toks.length; i++) {
|
|
7327
|
+
const t = toks[i];
|
|
7328
|
+
if (t.type === "paragraph_open") {
|
|
7329
|
+
depth++;
|
|
7330
|
+
continue;
|
|
7331
|
+
}
|
|
7332
|
+
if (t.type === "paragraph_close") if (depth > 0) depth--;
|
|
7333
|
+
else {
|
|
7334
|
+
toks.splice(i, 1);
|
|
7335
|
+
i--;
|
|
7336
|
+
}
|
|
7337
|
+
}
|
|
7338
|
+
}
|
|
7159
7339
|
for (let i = 0; i < toks.length; i++) {
|
|
7160
7340
|
const t = toks[i];
|
|
7161
7341
|
if (t.type === "html_block") {
|
|
7162
7342
|
const tag = (t.content?.match(/<([^\s>/]+)/)?.[1] ?? "").toLowerCase();
|
|
7343
|
+
if (customTagSet.has(tag)) {
|
|
7344
|
+
const raw$1 = String(t.content ?? "");
|
|
7345
|
+
const closeRe = new RegExp(`<\\/\\s*${tag}\\s*>`, "i");
|
|
7346
|
+
t.loading = closeRe.test(raw$1) ? false : t.loading !== void 0 ? t.loading : true;
|
|
7347
|
+
const closeMatch = closeRe.exec(raw$1);
|
|
7348
|
+
const endTagIndex = closeMatch ? closeMatch.index : -1;
|
|
7349
|
+
const closeLen = closeMatch ? closeMatch[0].length : 0;
|
|
7350
|
+
if (endTagIndex !== -1) {
|
|
7351
|
+
const rawForNode = raw$1.slice(0, endTagIndex + closeLen);
|
|
7352
|
+
t.content = rawForNode;
|
|
7353
|
+
t.raw = rawForNode;
|
|
7354
|
+
const afterTrimmed = (raw$1.slice(endTagIndex + closeLen) || "").replace(/^\s+/, "");
|
|
7355
|
+
if (afterTrimmed) toks.splice(i + 1, 0, afterTrimmed.startsWith("<") ? {
|
|
7356
|
+
type: "html_block",
|
|
7357
|
+
content: afterTrimmed
|
|
7358
|
+
} : {
|
|
7359
|
+
type: "text",
|
|
7360
|
+
content: afterTrimmed,
|
|
7361
|
+
raw: afterTrimmed
|
|
7362
|
+
});
|
|
7363
|
+
}
|
|
7364
|
+
continue;
|
|
7365
|
+
}
|
|
7163
7366
|
if (tag.startsWith("!") || tag.startsWith("?")) {
|
|
7164
7367
|
t.loading = false;
|
|
7165
7368
|
continue;
|
|
@@ -7177,7 +7380,7 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
7177
7380
|
"li"
|
|
7178
7381
|
].includes(tag)) continue;
|
|
7179
7382
|
t.type = "inline";
|
|
7180
|
-
const loading =
|
|
7383
|
+
const loading = new RegExp(`<\\/\\s*${tag}\\s*>`, "i").test(String(t.content ?? "")) ? false : t.loading !== void 0 ? t.loading : true;
|
|
7181
7384
|
const attrs = [];
|
|
7182
7385
|
const attrRegex = /\s([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
|
|
7183
7386
|
let match;
|
|
@@ -7187,24 +7390,36 @@ function applyFixHtmlInlineTokens(md, options = {}) {
|
|
|
7187
7390
|
attrs.push([attrName, attrValue]);
|
|
7188
7391
|
}
|
|
7189
7392
|
if (customTagSet.has(tag)) {
|
|
7190
|
-
const
|
|
7191
|
-
const
|
|
7192
|
-
const
|
|
7193
|
-
const
|
|
7393
|
+
const raw$1 = String(t.content ?? "");
|
|
7394
|
+
const closeMatch = new RegExp(`<\\/\\s*${tag}\\s*>`, "i").exec(raw$1);
|
|
7395
|
+
const endTagIndex = closeMatch ? closeMatch.index : -1;
|
|
7396
|
+
const closeLen = closeMatch ? closeMatch[0].length : 0;
|
|
7397
|
+
const rawForNode = endTagIndex !== -1 ? raw$1.slice(0, endTagIndex + closeLen) : raw$1;
|
|
7398
|
+
let inner = "";
|
|
7399
|
+
const openEnd = findTagCloseIndexOutsideQuotes$1(raw$1);
|
|
7400
|
+
if (openEnd !== -1) {
|
|
7401
|
+
if (endTagIndex !== -1 && openEnd < endTagIndex) inner = raw$1.slice(openEnd + 1, endTagIndex);
|
|
7402
|
+
else if (endTagIndex === -1) inner = raw$1.slice(openEnd + 1).replace(/<.*$/, "");
|
|
7403
|
+
}
|
|
7194
7404
|
t.children = [{
|
|
7195
7405
|
type: tag,
|
|
7196
|
-
content:
|
|
7197
|
-
raw:
|
|
7406
|
+
content: inner,
|
|
7407
|
+
raw: rawForNode,
|
|
7198
7408
|
attrs,
|
|
7199
7409
|
tag,
|
|
7200
7410
|
loading
|
|
7201
7411
|
}];
|
|
7202
7412
|
if (endTagIndex !== -1) {
|
|
7203
|
-
|
|
7204
|
-
|
|
7413
|
+
t.content = rawForNode;
|
|
7414
|
+
t.raw = rawForNode;
|
|
7415
|
+
const afterTrimmed = (raw$1.slice(endTagIndex + closeLen) || "").replace(/^\s+/, "");
|
|
7416
|
+
if (afterTrimmed) toks.splice(i + 1, 0, afterTrimmed.startsWith("<") ? {
|
|
7417
|
+
type: "html_block",
|
|
7418
|
+
content: afterTrimmed
|
|
7419
|
+
} : {
|
|
7205
7420
|
type: "text",
|
|
7206
|
-
content:
|
|
7207
|
-
raw:
|
|
7421
|
+
content: afterTrimmed,
|
|
7422
|
+
raw: afterTrimmed
|
|
7208
7423
|
});
|
|
7209
7424
|
}
|
|
7210
7425
|
} else t.children = [{
|
|
@@ -7961,7 +8176,7 @@ function fixTableTokens(tokens) {
|
|
|
7961
8176
|
if (token.type === "inline") {
|
|
7962
8177
|
const tcontent = String(token.content ?? "");
|
|
7963
8178
|
const childContent = String(token.children?.[0]?.content ?? "");
|
|
7964
|
-
if (/^\|(?:[^|\n]+\|?)+/.test(tcontent)) {
|
|
8179
|
+
if (!tcontent.includes("\n") && /^\|(?:[^|\n]+\|?)+/.test(tcontent)) {
|
|
7965
8180
|
const body = childContent.slice(1).split("|").map((i$1) => i$1.trim()).filter(Boolean).flatMap((i$1) => createTh(i$1));
|
|
7966
8181
|
const insert = [
|
|
7967
8182
|
...createStart(),
|
|
@@ -8213,6 +8428,16 @@ function countUnescapedStrong(s) {
|
|
|
8213
8428
|
while (re.exec(s) !== null) c++;
|
|
8214
8429
|
return c;
|
|
8215
8430
|
}
|
|
8431
|
+
function findLastUnescapedStrongMarker(s) {
|
|
8432
|
+
const re = /(^|[^\\])(__|\*\*)/g;
|
|
8433
|
+
let m;
|
|
8434
|
+
let last = null;
|
|
8435
|
+
while ((m = re.exec(s)) !== null) last = {
|
|
8436
|
+
marker: m[2],
|
|
8437
|
+
index: m.index + (m[1]?.length ?? 0)
|
|
8438
|
+
};
|
|
8439
|
+
return last;
|
|
8440
|
+
}
|
|
8216
8441
|
function normalizeStandaloneBackslashT(s, opts) {
|
|
8217
8442
|
const commands = opts?.commands ?? KATEX_COMMANDS;
|
|
8218
8443
|
const escapeExclamation = opts?.escapeExclamation ?? true;
|
|
@@ -8297,7 +8522,8 @@ function applyMath(md, mathOpts) {
|
|
|
8297
8522
|
foundAny = true;
|
|
8298
8523
|
if (!silent) {
|
|
8299
8524
|
s.pending = "";
|
|
8300
|
-
const
|
|
8525
|
+
const toPushBefore = preMathPos ? src.slice(preMathPos, searchPos) : src.slice(0, searchPos);
|
|
8526
|
+
const isStrongPrefix = countUnescapedStrong(toPushBefore) % 2 === 1;
|
|
8301
8527
|
if (preMathPos) pushText(src.slice(preMathPos, searchPos));
|
|
8302
8528
|
else {
|
|
8303
8529
|
let text$1 = src.slice(0, searchPos);
|
|
@@ -8305,8 +8531,9 @@ function applyMath(md, mathOpts) {
|
|
|
8305
8531
|
pushText(text$1);
|
|
8306
8532
|
}
|
|
8307
8533
|
if (isStrongPrefix) {
|
|
8534
|
+
const strongMarker = findLastUnescapedStrongMarker(toPushBefore)?.marker ?? "**";
|
|
8308
8535
|
const strongToken = s.push("strong_open", "", 0);
|
|
8309
|
-
strongToken.markup =
|
|
8536
|
+
strongToken.markup = strongMarker;
|
|
8310
8537
|
const token = s.push("math_inline", "math", 0);
|
|
8311
8538
|
token.content = normalizeStandaloneBackslashT(content$1, mathOpts);
|
|
8312
8539
|
token.markup = open === "$$" ? "$$" : open === "\\(" ? "\\(\\)" : open === "$" ? "$" : "()";
|
|
@@ -8343,29 +8570,31 @@ function applyMath(md, mathOpts) {
|
|
|
8343
8570
|
let toPushBefore = src.slice(0, searchPos) ? src.slice(preMathPos, index) : before;
|
|
8344
8571
|
const isStrongPrefix = countUnescapedStrong(toPushBefore) % 2 === 1;
|
|
8345
8572
|
if (index !== s.pos && isStrongPrefix) toPushBefore = s.pending + src.slice(s.pos, index);
|
|
8573
|
+
const strongMarkerInfo = isStrongPrefix ? findLastUnescapedStrongMarker(toPushBefore) : null;
|
|
8574
|
+
const strongMarker = strongMarkerInfo?.marker ?? "**";
|
|
8346
8575
|
if (s.pending !== toPushBefore) {
|
|
8347
8576
|
s.pending = "";
|
|
8348
|
-
if (isStrongPrefix) {
|
|
8349
|
-
const
|
|
8350
|
-
|
|
8351
|
-
pushText(toPushBefore.slice(0, _match.index));
|
|
8577
|
+
if (isStrongPrefix) if (strongMarkerInfo) {
|
|
8578
|
+
const after = toPushBefore.slice(strongMarkerInfo.index + strongMarker.length);
|
|
8579
|
+
pushText(toPushBefore.slice(0, strongMarkerInfo.index));
|
|
8352
8580
|
const strongToken = s.push("strong_open", "", 0);
|
|
8353
|
-
strongToken.markup =
|
|
8581
|
+
strongToken.markup = strongMarker;
|
|
8354
8582
|
const textToken$1 = s.push("text", "", 0);
|
|
8355
8583
|
textToken$1.content = after;
|
|
8356
8584
|
s.push("strong_close", "", 0);
|
|
8357
8585
|
} else pushText(toPushBefore);
|
|
8586
|
+
else pushText(toPushBefore);
|
|
8358
8587
|
}
|
|
8359
8588
|
if (isStrongPrefix) {
|
|
8360
8589
|
const strongToken = s.push("strong_open", "", 0);
|
|
8361
|
-
strongToken.markup =
|
|
8590
|
+
strongToken.markup = strongMarker;
|
|
8362
8591
|
const token = s.push("math_inline", "math", 0);
|
|
8363
8592
|
token.content = normalizeStandaloneBackslashT(content, mathOpts);
|
|
8364
8593
|
token.markup = open === "$$" ? "$$" : open === "\\(" ? "\\(\\)" : open === "$" ? "$" : "()";
|
|
8365
8594
|
token.raw = `${open}${content}${close}`;
|
|
8366
8595
|
token.loading = false;
|
|
8367
8596
|
const raw = src.slice(endIdx + close.length);
|
|
8368
|
-
const isBeforeClose = raw.startsWith(
|
|
8597
|
+
const isBeforeClose = raw.startsWith(strongMarker);
|
|
8369
8598
|
if (isBeforeClose) s.push("strong_close", "", 0);
|
|
8370
8599
|
if (raw) {
|
|
8371
8600
|
s.pos = endIdx + close.length;
|
|
@@ -8908,6 +9137,7 @@ function parseHtmlInlineCodeToken(token, tokens, i, parseInlineTokens$1, raw, pP
|
|
|
8908
9137
|
tag,
|
|
8909
9138
|
attrs,
|
|
8910
9139
|
content: fragment.innerTokens.length ? stringifyTokens(fragment.innerTokens) : "",
|
|
9140
|
+
children: fragment.innerTokens.length ? parseInlineTokens$1(fragment.innerTokens, raw, pPreToken, options) : [],
|
|
8911
9141
|
raw: content,
|
|
8912
9142
|
loading: token.loading || loading,
|
|
8913
9143
|
autoClosed
|
|
@@ -9255,7 +9485,7 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
|
|
|
9255
9485
|
i++;
|
|
9256
9486
|
return true;
|
|
9257
9487
|
}
|
|
9258
|
-
if (/\*\*/.test(content)
|
|
9488
|
+
if (/\*\*/.test(content)) {
|
|
9259
9489
|
const openIdx = content.indexOf("**");
|
|
9260
9490
|
const beforeText = openIdx > -1 ? content.slice(0, openIdx) : "";
|
|
9261
9491
|
if (beforeText) pushText(beforeText, beforeText);
|
|
@@ -10169,7 +10399,7 @@ function parseHtmlBlock(token) {
|
|
|
10169
10399
|
const isVoid = VOID_TAGS.has(tag);
|
|
10170
10400
|
let closeRe = CLOSE_TAG_RE_CACHE.get(tag);
|
|
10171
10401
|
if (!closeRe) {
|
|
10172
|
-
closeRe = new RegExp(
|
|
10402
|
+
closeRe = new RegExp(`<\\s*\\/\\s*${tag}\\s*>`, "i");
|
|
10173
10403
|
CLOSE_TAG_RE_CACHE.set(tag, closeRe);
|
|
10174
10404
|
}
|
|
10175
10405
|
const hasClosing = closeRe.test(raw);
|
|
@@ -10278,6 +10508,98 @@ function parseThematicBreak() {
|
|
|
10278
10508
|
|
|
10279
10509
|
//#endregion
|
|
10280
10510
|
//#region src/parser/node-parsers/block-token-parser.ts
|
|
10511
|
+
function findTagCloseIndexOutsideQuotes(input) {
|
|
10512
|
+
let inSingle = false;
|
|
10513
|
+
let inDouble = false;
|
|
10514
|
+
for (let i = 0; i < input.length; i++) {
|
|
10515
|
+
const ch = input[i];
|
|
10516
|
+
if (ch === "\\") {
|
|
10517
|
+
i++;
|
|
10518
|
+
continue;
|
|
10519
|
+
}
|
|
10520
|
+
if (!inDouble && ch === "'") {
|
|
10521
|
+
inSingle = !inSingle;
|
|
10522
|
+
continue;
|
|
10523
|
+
}
|
|
10524
|
+
if (!inSingle && ch === "\"") {
|
|
10525
|
+
inDouble = !inDouble;
|
|
10526
|
+
continue;
|
|
10527
|
+
}
|
|
10528
|
+
if (!inSingle && !inDouble && ch === ">") return i;
|
|
10529
|
+
}
|
|
10530
|
+
return -1;
|
|
10531
|
+
}
|
|
10532
|
+
function stripWrapperNewlines(s) {
|
|
10533
|
+
return s.replace(/^\r?\n/, "").replace(/\r?\n$/, "");
|
|
10534
|
+
}
|
|
10535
|
+
function stripTrailingPartialClosingTag(inner, tag) {
|
|
10536
|
+
if (!inner || !tag) return inner;
|
|
10537
|
+
const re = new RegExp(String.raw`[\t ]*<\s*\/\s*${tag}[^>]*$`, "i");
|
|
10538
|
+
return inner.replace(re, "");
|
|
10539
|
+
}
|
|
10540
|
+
function findNextCustomHtmlBlockFromSource(source, tag, startIndex) {
|
|
10541
|
+
if (!source || !tag) return null;
|
|
10542
|
+
const lowerTag = tag.toLowerCase();
|
|
10543
|
+
const openRe = new RegExp(String.raw`<\s*${lowerTag}(?=\s|>|/)`, "gi");
|
|
10544
|
+
openRe.lastIndex = Math.max(0, startIndex || 0);
|
|
10545
|
+
const openMatch = openRe.exec(source);
|
|
10546
|
+
if (!openMatch || openMatch.index == null) return null;
|
|
10547
|
+
const openStart = openMatch.index;
|
|
10548
|
+
const openSlice = source.slice(openStart);
|
|
10549
|
+
const openEndRel = findTagCloseIndexOutsideQuotes(openSlice);
|
|
10550
|
+
if (openEndRel === -1) return null;
|
|
10551
|
+
const openEnd = openStart + openEndRel;
|
|
10552
|
+
if (/\/\s*>\s*$/.test(openSlice.slice(0, openEndRel + 1))) {
|
|
10553
|
+
const end = openEnd + 1;
|
|
10554
|
+
return {
|
|
10555
|
+
raw: source.slice(openStart, end),
|
|
10556
|
+
end
|
|
10557
|
+
};
|
|
10558
|
+
}
|
|
10559
|
+
let depth = 1;
|
|
10560
|
+
let i = openEnd + 1;
|
|
10561
|
+
const isOpenAt = (pos) => {
|
|
10562
|
+
const s = source.slice(pos);
|
|
10563
|
+
return new RegExp(String.raw`^<\s*${lowerTag}(?=\s|>|/)`, "i").test(s);
|
|
10564
|
+
};
|
|
10565
|
+
const isCloseAt = (pos) => {
|
|
10566
|
+
const s = source.slice(pos);
|
|
10567
|
+
return new RegExp(String.raw`^<\s*\/\s*${lowerTag}(?=\s|>)`, "i").test(s);
|
|
10568
|
+
};
|
|
10569
|
+
while (i < source.length) {
|
|
10570
|
+
const lt = source.indexOf("<", i);
|
|
10571
|
+
if (lt === -1) return {
|
|
10572
|
+
raw: source.slice(openStart),
|
|
10573
|
+
end: source.length
|
|
10574
|
+
};
|
|
10575
|
+
if (isCloseAt(lt)) {
|
|
10576
|
+
const gt = source.indexOf(">", lt);
|
|
10577
|
+
if (gt === -1) return null;
|
|
10578
|
+
depth--;
|
|
10579
|
+
if (depth === 0) {
|
|
10580
|
+
const end = gt + 1;
|
|
10581
|
+
return {
|
|
10582
|
+
raw: source.slice(openStart, end),
|
|
10583
|
+
end
|
|
10584
|
+
};
|
|
10585
|
+
}
|
|
10586
|
+
i = gt + 1;
|
|
10587
|
+
continue;
|
|
10588
|
+
}
|
|
10589
|
+
if (isOpenAt(lt)) {
|
|
10590
|
+
const rel = findTagCloseIndexOutsideQuotes(source.slice(lt));
|
|
10591
|
+
if (rel === -1) return null;
|
|
10592
|
+
depth++;
|
|
10593
|
+
i = lt + rel + 1;
|
|
10594
|
+
continue;
|
|
10595
|
+
}
|
|
10596
|
+
i = lt + 1;
|
|
10597
|
+
}
|
|
10598
|
+
return {
|
|
10599
|
+
raw: source.slice(openStart),
|
|
10600
|
+
end: source.length
|
|
10601
|
+
};
|
|
10602
|
+
}
|
|
10281
10603
|
function parseBasicBlockToken(tokens, index, options) {
|
|
10282
10604
|
const token = tokens[index];
|
|
10283
10605
|
switch (token.type) {
|
|
@@ -10291,10 +10613,37 @@ function parseBasicBlockToken(tokens, index, options) {
|
|
|
10291
10613
|
if (new Set(options.customHtmlTags.map((t) => {
|
|
10292
10614
|
const m = String(t ?? "").trim().match(/^[<\s/]*([A-Z][\w-]*)/i);
|
|
10293
10615
|
return m ? m[1].toLowerCase() : "";
|
|
10294
|
-
}).filter(Boolean)).has(htmlBlockNode.tag))
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10616
|
+
}).filter(Boolean)).has(htmlBlockNode.tag)) {
|
|
10617
|
+
const tag = htmlBlockNode.tag;
|
|
10618
|
+
const fromSource = findNextCustomHtmlBlockFromSource(String(options?.__sourceMarkdown ?? ""), tag, Number(options?.__customHtmlBlockCursor ?? 0));
|
|
10619
|
+
if (fromSource) options.__customHtmlBlockCursor = fromSource.end;
|
|
10620
|
+
const rawHtml = String(fromSource?.raw ?? htmlBlockNode.content ?? "");
|
|
10621
|
+
const openEnd = findTagCloseIndexOutsideQuotes(rawHtml);
|
|
10622
|
+
const closeMatch = new RegExp(`<\\s*\\/\\s*${tag}\\s*>`, "i").exec(rawHtml);
|
|
10623
|
+
const closeIndex = closeMatch ? closeMatch.index : -1;
|
|
10624
|
+
let inner = "";
|
|
10625
|
+
if (openEnd !== -1) if (closeIndex !== -1 && openEnd < closeIndex) inner = rawHtml.slice(openEnd + 1, closeIndex);
|
|
10626
|
+
else inner = rawHtml.slice(openEnd + 1);
|
|
10627
|
+
if (closeIndex === -1) inner = stripTrailingPartialClosingTag(inner, tag);
|
|
10628
|
+
const attrs = [];
|
|
10629
|
+
const openTag = openEnd !== -1 ? rawHtml.slice(0, openEnd + 1) : rawHtml;
|
|
10630
|
+
const attrRegex = /\s([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
|
|
10631
|
+
let m;
|
|
10632
|
+
while ((m = attrRegex.exec(openTag)) !== null) {
|
|
10633
|
+
const name = m[1];
|
|
10634
|
+
if (!name || name.toLowerCase() === tag) continue;
|
|
10635
|
+
const value = m[2] || m[3] || m[4] || "";
|
|
10636
|
+
attrs.push([name, value]);
|
|
10637
|
+
}
|
|
10638
|
+
return [{
|
|
10639
|
+
type: tag,
|
|
10640
|
+
tag,
|
|
10641
|
+
content: stripWrapperNewlines(inner),
|
|
10642
|
+
raw: String(fromSource?.raw ?? htmlBlockNode.raw ?? rawHtml),
|
|
10643
|
+
loading: htmlBlockNode.loading,
|
|
10644
|
+
attrs: attrs.length ? attrs : void 0
|
|
10645
|
+
}, index + 1];
|
|
10646
|
+
}
|
|
10298
10647
|
}
|
|
10299
10648
|
return [htmlBlockNode, index + 1];
|
|
10300
10649
|
}
|
|
@@ -10608,18 +10957,51 @@ function parseParagraph(tokens, index, options) {
|
|
|
10608
10957
|
|
|
10609
10958
|
//#endregion
|
|
10610
10959
|
//#region src/parser/index.ts
|
|
10960
|
+
function stripDanglingHtmlLikeTail(markdown) {
|
|
10961
|
+
const s = String(markdown ?? "");
|
|
10962
|
+
const lastLt = s.lastIndexOf("<");
|
|
10963
|
+
if (lastLt === -1) return s;
|
|
10964
|
+
const tail = s.slice(lastLt);
|
|
10965
|
+
if (tail.includes(">")) return s;
|
|
10966
|
+
if (!/^<\s*(?:\/\s*)?[A-Z!][\s\S]*$/i.test(tail)) return s;
|
|
10967
|
+
return s.slice(0, lastLt);
|
|
10968
|
+
}
|
|
10611
10969
|
function parseMarkdownToStructure(markdown, md, options = {}) {
|
|
10612
10970
|
let safeMarkdown = (markdown ?? "").toString().replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\n(abla|eq|ot|exists)/g, "$1\\n$2");
|
|
10613
10971
|
if (safeMarkdown.endsWith("- *")) safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*");
|
|
10614
|
-
if (
|
|
10972
|
+
if (/(?:^|\n)\s*-\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => {
|
|
10973
|
+
return m.startsWith("\n") ? "\n" : "";
|
|
10974
|
+
});
|
|
10975
|
+
else if (/(?:^|\n)\s*--\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*--\s*$/, (m) => {
|
|
10976
|
+
return m.startsWith("\n") ? "\n" : "";
|
|
10977
|
+
});
|
|
10978
|
+
else if (/(?:^|\n)\s*>\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*>\s*$/, (m) => {
|
|
10979
|
+
return m.startsWith("\n") ? "\n" : "";
|
|
10980
|
+
});
|
|
10981
|
+
else if (/\n\s*[*+]\s*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/\n\s*[*+]\s*$/, "\n");
|
|
10615
10982
|
else if (/\n[[(]\n*$/.test(safeMarkdown)) safeMarkdown = safeMarkdown.replace(/(\n\[|\n\()+\n*$/g, "\n");
|
|
10983
|
+
if (options.customHtmlTags?.length) {
|
|
10984
|
+
const tags = options.customHtmlTags.map((t) => String(t ?? "").trim()).filter(Boolean).map((t) => {
|
|
10985
|
+
return (t.match(/^[<\s/]*([A-Z][\w-]*)/i)?.[1] ?? "").toLowerCase();
|
|
10986
|
+
}).filter(Boolean);
|
|
10987
|
+
if (tags.length) if (!safeMarkdown.includes("</")) {} else for (const tag of tags) {
|
|
10988
|
+
const re = new RegExp(String.raw`(^[\t ]*<\s*\/\s*${tag}\s*>[\t ]*)(\r?\n)(?![\t ]*\r?\n|$)`, "gim");
|
|
10989
|
+
safeMarkdown = safeMarkdown.replace(re, "$1$2$2");
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown);
|
|
10616
10993
|
const tokens = md.parse(safeMarkdown, {});
|
|
10617
10994
|
if (!tokens || !Array.isArray(tokens)) return [];
|
|
10618
10995
|
const pre = options.preTransformTokens;
|
|
10619
10996
|
const post = options.postTransformTokens;
|
|
10620
10997
|
let transformedTokens = tokens;
|
|
10621
10998
|
if (pre && typeof pre === "function") transformedTokens = pre(transformedTokens) || transformedTokens;
|
|
10622
|
-
|
|
10999
|
+
const internalOptions = {
|
|
11000
|
+
...options,
|
|
11001
|
+
__sourceMarkdown: safeMarkdown,
|
|
11002
|
+
__customHtmlBlockCursor: 0
|
|
11003
|
+
};
|
|
11004
|
+
let result = processTokens(transformedTokens, internalOptions);
|
|
10623
11005
|
if (post && typeof post === "function") {
|
|
10624
11006
|
const postResult = post(transformedTokens);
|
|
10625
11007
|
if (Array.isArray(postResult)) {
|
|
@@ -10677,6 +11059,20 @@ function processTokens(tokens, options) {
|
|
|
10677
11059
|
result.push(parseHardBreak());
|
|
10678
11060
|
i++;
|
|
10679
11061
|
break;
|
|
11062
|
+
case "text": {
|
|
11063
|
+
const content = String(token.content ?? "");
|
|
11064
|
+
result.push({
|
|
11065
|
+
type: "paragraph",
|
|
11066
|
+
raw: content,
|
|
11067
|
+
children: content ? [{
|
|
11068
|
+
type: "text",
|
|
11069
|
+
content,
|
|
11070
|
+
raw: content
|
|
11071
|
+
}] : []
|
|
11072
|
+
});
|
|
11073
|
+
i++;
|
|
11074
|
+
break;
|
|
11075
|
+
}
|
|
10680
11076
|
case "inline":
|
|
10681
11077
|
result.push(...parseInlineTokens(token.children || [], String(token.content ?? ""), void 0, {
|
|
10682
11078
|
requireClosingStrong: options?.requireClosingStrong,
|