stream-markdown-parser 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +466 -363
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -75,6 +75,431 @@ function applyContainers(md) {
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/plugins/fixLinkInline.ts
|
|
80
|
+
function applyFixLinkInline(md) {
|
|
81
|
+
const rule = (state, silent) => {
|
|
82
|
+
const s = state;
|
|
83
|
+
const start = s.pos;
|
|
84
|
+
if (s.src[start] !== "[") return false;
|
|
85
|
+
if (start > 0 && s.src[start - 1] === "!") return false;
|
|
86
|
+
const rest = s.src.slice(start);
|
|
87
|
+
const m = /^\[([^\]]*)\]\(([^)\s]*)?/.exec(rest);
|
|
88
|
+
if (!m) return false;
|
|
89
|
+
if (silent) return true;
|
|
90
|
+
const text = m[1] ?? "";
|
|
91
|
+
const href = m[2] ?? "";
|
|
92
|
+
if (text.includes("*") || text.includes(":")) return false;
|
|
93
|
+
const idxClose = rest.indexOf(")");
|
|
94
|
+
const hasClosingParen = idxClose !== -1;
|
|
95
|
+
const open = s.push("link_open", "a", 1);
|
|
96
|
+
open.attrs = [["href", href]];
|
|
97
|
+
const txt = s.push("text", "", 0);
|
|
98
|
+
txt.content = text;
|
|
99
|
+
if (hasClosingParen) {
|
|
100
|
+
s.push("link_close", "a", -1);
|
|
101
|
+
s.pos += idxClose + 1;
|
|
102
|
+
} else s.pos += m[0].length;
|
|
103
|
+
return true;
|
|
104
|
+
};
|
|
105
|
+
md.inline.ruler.before("link", "fix_link_inline", rule);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/parser/inline-parsers/fixLinkToken.ts
|
|
110
|
+
function isTextToken(t) {
|
|
111
|
+
return !!t && t.type === "text" && typeof t.content === "string";
|
|
112
|
+
}
|
|
113
|
+
function fixLinkToken(tokens) {
|
|
114
|
+
const tokensAny = tokens;
|
|
115
|
+
tokens = fixLinkToken4(fixLinkToken3(tokens));
|
|
116
|
+
if (tokens.length < 5) return tokens;
|
|
117
|
+
const first = tokens[tokens.length - 5];
|
|
118
|
+
const firstAny = first;
|
|
119
|
+
const firstContent = String(firstAny.content ?? "");
|
|
120
|
+
if (first.type !== "text" || !firstContent.endsWith("[")) return fixLinkTokens2(tokens);
|
|
121
|
+
if (tokens[tokens.length - 4].tag !== "em") return fixLinkTokens2(tokens);
|
|
122
|
+
const last = tokens[tokens.length - 1];
|
|
123
|
+
const lastAny = last;
|
|
124
|
+
const lastContent = String(lastAny.content ?? "");
|
|
125
|
+
if (last?.type === "text" && !lastContent.startsWith("]")) return fixLinkTokens2(tokens);
|
|
126
|
+
const thirdAny = tokens[tokens.length - 3];
|
|
127
|
+
const thirdContent = String(thirdAny.content ?? "");
|
|
128
|
+
const href = lastContent.replace(/^\]\(*/, "");
|
|
129
|
+
const loading = !lastContent.includes(")");
|
|
130
|
+
tokensAny[tokens.length - 5].content = firstContent.replace(/\[$/, "");
|
|
131
|
+
tokens.splice(tokens.length - 3, 1, {
|
|
132
|
+
type: "link",
|
|
133
|
+
href,
|
|
134
|
+
text: thirdContent,
|
|
135
|
+
children: [{
|
|
136
|
+
type: "text",
|
|
137
|
+
content: thirdContent,
|
|
138
|
+
raw: thirdContent
|
|
139
|
+
}],
|
|
140
|
+
loading
|
|
141
|
+
});
|
|
142
|
+
tokens.splice(tokens.length - 1, 1);
|
|
143
|
+
return tokens;
|
|
144
|
+
}
|
|
145
|
+
function fixLinkTokens2(tokens) {
|
|
146
|
+
const tokensAny = tokens;
|
|
147
|
+
if (tokens.length < 8) return tokens;
|
|
148
|
+
let length = tokens.length;
|
|
149
|
+
let last = tokens[length - 1];
|
|
150
|
+
if (last.type !== "link_close") {
|
|
151
|
+
length--;
|
|
152
|
+
last = tokens[length - 1];
|
|
153
|
+
if (last.type !== "link_close") return tokens;
|
|
154
|
+
}
|
|
155
|
+
if (tokens[length - 7].type !== "em_open") return tokens;
|
|
156
|
+
const third = tokens[length - 6];
|
|
157
|
+
const first = tokens[length - 8];
|
|
158
|
+
if (first.type !== "text") return tokens;
|
|
159
|
+
let href = String(tokensAny[length - 2]?.content ?? "");
|
|
160
|
+
let count = 4;
|
|
161
|
+
if (length !== tokens.length) {
|
|
162
|
+
href += String(last.content ?? "");
|
|
163
|
+
count++;
|
|
164
|
+
}
|
|
165
|
+
tokens.splice(length - 4, count);
|
|
166
|
+
const thirdAny = third;
|
|
167
|
+
const content = String(thirdAny.content ?? "");
|
|
168
|
+
length -= 4;
|
|
169
|
+
const firstAny = first;
|
|
170
|
+
tokensAny[length - 8].content = String(firstAny.content ?? "").replace(/\[$/, "");
|
|
171
|
+
tokens.splice(length - 2, 1, {
|
|
172
|
+
type: "link",
|
|
173
|
+
href,
|
|
174
|
+
text: content,
|
|
175
|
+
children: [{
|
|
176
|
+
type: "text",
|
|
177
|
+
content,
|
|
178
|
+
raw: content
|
|
179
|
+
}],
|
|
180
|
+
loading: true
|
|
181
|
+
});
|
|
182
|
+
return tokens;
|
|
183
|
+
}
|
|
184
|
+
function fixLinkToken3(tokens) {
|
|
185
|
+
const tokensAny = tokens;
|
|
186
|
+
const last = tokens[tokens.length - 1];
|
|
187
|
+
const preLast = tokens[tokens.length - 2];
|
|
188
|
+
const fixedTokens = [...tokens];
|
|
189
|
+
if (last.type !== "text" || !last.content?.startsWith(")")) return tokens;
|
|
190
|
+
if (preLast.type !== "link_close") return tokens;
|
|
191
|
+
if (isTextToken(tokens[tokens.length - 5]) && String(tokens[tokens.length - 5].content ?? "").endsWith("(")) {
|
|
192
|
+
const a = tokensAny[tokens.length - 5];
|
|
193
|
+
const b = tokensAny[tokens.length - 3];
|
|
194
|
+
const content = String(a.content ?? "") + String(b.content ?? "") + String(last.content ?? "");
|
|
195
|
+
fixedTokens.splice(tokens.length - 5, 5, {
|
|
196
|
+
type: "text",
|
|
197
|
+
content,
|
|
198
|
+
raw: content
|
|
199
|
+
});
|
|
200
|
+
} else {
|
|
201
|
+
const lc = (last.content ?? "").slice(1);
|
|
202
|
+
fixedTokens[fixedTokens.length - 1] = {
|
|
203
|
+
...last,
|
|
204
|
+
content: lc
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return fixedTokens;
|
|
208
|
+
}
|
|
209
|
+
function fixLinkToken4(tokens) {
|
|
210
|
+
const tokensAny = tokens;
|
|
211
|
+
const fixedTokens = [...tokens];
|
|
212
|
+
for (let i = tokens.length - 1; i >= 3; i--) if (tokens[i].type === "link_close") {
|
|
213
|
+
if (tokens[i - 3]?.content?.endsWith("(")) {
|
|
214
|
+
const nextToken = tokens[i + 1];
|
|
215
|
+
if (nextToken?.type === "text") {
|
|
216
|
+
if (tokens[i - 1].type === "text" && tokens[i - 3].type === "text") {
|
|
217
|
+
const nextTokenContent = String(nextToken.content ?? "");
|
|
218
|
+
const a = tokensAny[i - 3];
|
|
219
|
+
const b = tokensAny[i - 1];
|
|
220
|
+
const content = String(a.content ?? "") + String(b.content ?? "") + nextTokenContent;
|
|
221
|
+
fixedTokens.splice(i - 3, 5, {
|
|
222
|
+
type: "text",
|
|
223
|
+
content,
|
|
224
|
+
raw: content
|
|
225
|
+
});
|
|
226
|
+
i -= 3;
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
if (tokens[i - 1].type === "text" && tokens[i - 3].type === "text") {
|
|
230
|
+
const a = tokensAny[i - 3];
|
|
231
|
+
const b = tokensAny[i - 1];
|
|
232
|
+
const content = String(a.content ?? "") + String(b.content ?? "");
|
|
233
|
+
fixedTokens.splice(i - 3, 4, {
|
|
234
|
+
type: "text",
|
|
235
|
+
content,
|
|
236
|
+
raw: content
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
i -= 3;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return fixedTokens;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/plugins/fixLinkTokens.ts
|
|
248
|
+
function applyFixLinkTokens(md) {
|
|
249
|
+
md.core.ruler.after("inline", "fix_link_tokens", (state) => {
|
|
250
|
+
const toks = state.tokens ?? [];
|
|
251
|
+
for (let i = 0; i < toks.length; i++) {
|
|
252
|
+
const t = toks[i];
|
|
253
|
+
if (t && t.type === "inline" && Array.isArray(t.children)) try {
|
|
254
|
+
t.children = fixLinkToken(t.children);
|
|
255
|
+
} catch (e) {
|
|
256
|
+
console.error("[applyFixLinkTokens] failed to fix inline children", e);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/parser/inline-parsers/fixListItem.ts
|
|
264
|
+
function fixListItem(tokens) {
|
|
265
|
+
const last = tokens[tokens.length - 1];
|
|
266
|
+
const lastContent = String(last?.content ?? "");
|
|
267
|
+
if (last?.type === "text" && /^\s*\d+\.\s*$/.test(lastContent) && tokens[tokens.length - 2]?.tag === "br") tokens.splice(tokens.length - 1, 1);
|
|
268
|
+
return tokens;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/plugins/fixListItem.ts
|
|
273
|
+
function applyFixListItem(md) {
|
|
274
|
+
md.core.ruler.after("inline", "fix_list_item_tokens", (state) => {
|
|
275
|
+
const toks = state.tokens ?? [];
|
|
276
|
+
for (let i = 0; i < toks.length; i++) {
|
|
277
|
+
const t = toks[i];
|
|
278
|
+
if (t && t.type === "inline" && Array.isArray(t.children)) try {
|
|
279
|
+
t.children = fixListItem(t.children);
|
|
280
|
+
} catch (e) {
|
|
281
|
+
console.error("[applyFixListItem] failed to fix inline children", e);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/parser/inline-parsers/fixStrongTokens.ts
|
|
289
|
+
function fixStrongTokens(tokens) {
|
|
290
|
+
const fixedTokens = [...tokens];
|
|
291
|
+
if (tokens.length < 4) return fixedTokens;
|
|
292
|
+
const i = tokens.length - 4;
|
|
293
|
+
const token = tokens[i];
|
|
294
|
+
const nextToken = tokens[i + 1];
|
|
295
|
+
const tokenContent = String(token.content ?? "");
|
|
296
|
+
if (token.type === "text" && tokenContent.endsWith("*") && nextToken.type === "em_open") {
|
|
297
|
+
const _nextToken = tokens[i + 2];
|
|
298
|
+
const count = _nextToken?.type === "text" ? 4 : 3;
|
|
299
|
+
const insert = [
|
|
300
|
+
{
|
|
301
|
+
type: "strong_open",
|
|
302
|
+
tag: "strong",
|
|
303
|
+
attrs: null,
|
|
304
|
+
map: null,
|
|
305
|
+
children: null,
|
|
306
|
+
content: "",
|
|
307
|
+
markup: "**",
|
|
308
|
+
info: "",
|
|
309
|
+
meta: null
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
type: "text",
|
|
313
|
+
content: _nextToken?.type === "text" ? String(_nextToken.content ?? "") : ""
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
type: "strong_close",
|
|
317
|
+
tag: "strong",
|
|
318
|
+
attrs: null,
|
|
319
|
+
map: null,
|
|
320
|
+
children: null,
|
|
321
|
+
content: "",
|
|
322
|
+
markup: "**",
|
|
323
|
+
info: "",
|
|
324
|
+
meta: null
|
|
325
|
+
}
|
|
326
|
+
];
|
|
327
|
+
const beforeText = tokenContent.slice(0, -1);
|
|
328
|
+
if (beforeText) insert.unshift({
|
|
329
|
+
type: "text",
|
|
330
|
+
content: beforeText,
|
|
331
|
+
raw: beforeText
|
|
332
|
+
});
|
|
333
|
+
fixedTokens.splice(i, count, ...insert);
|
|
334
|
+
return fixedTokens;
|
|
335
|
+
}
|
|
336
|
+
return fixedTokens;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/plugins/fixStrongTokens.ts
|
|
341
|
+
function applyFixStrongTokens(md) {
|
|
342
|
+
md.core.ruler.after("inline", "fix_strong_tokens", (state) => {
|
|
343
|
+
const toks = state.tokens ?? [];
|
|
344
|
+
for (let i = 0; i < toks.length; i++) {
|
|
345
|
+
const t = toks[i];
|
|
346
|
+
if (t && t.type === "inline" && Array.isArray(t.children)) try {
|
|
347
|
+
t.children = fixStrongTokens(t.children);
|
|
348
|
+
} catch (e) {
|
|
349
|
+
console.error("[applyFixStrongTokens] failed to fix inline children", e);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/parser/fixTableTokens.ts
|
|
357
|
+
function createStart() {
|
|
358
|
+
return [
|
|
359
|
+
{
|
|
360
|
+
type: "table_open",
|
|
361
|
+
tag: "table",
|
|
362
|
+
attrs: null,
|
|
363
|
+
map: null,
|
|
364
|
+
children: null,
|
|
365
|
+
content: "",
|
|
366
|
+
markup: "",
|
|
367
|
+
info: "",
|
|
368
|
+
level: 0,
|
|
369
|
+
loading: true,
|
|
370
|
+
meta: null
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
type: "thead_open",
|
|
374
|
+
tag: "thead",
|
|
375
|
+
attrs: null,
|
|
376
|
+
block: true,
|
|
377
|
+
level: 1,
|
|
378
|
+
children: null
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
type: "tr_open",
|
|
382
|
+
tag: "tr",
|
|
383
|
+
attrs: null,
|
|
384
|
+
block: true,
|
|
385
|
+
level: 2,
|
|
386
|
+
children: null
|
|
387
|
+
}
|
|
388
|
+
];
|
|
389
|
+
}
|
|
390
|
+
function createEnd() {
|
|
391
|
+
return [
|
|
392
|
+
{
|
|
393
|
+
type: "tr_close",
|
|
394
|
+
tag: "tr",
|
|
395
|
+
attrs: null,
|
|
396
|
+
block: true,
|
|
397
|
+
level: 2,
|
|
398
|
+
children: null
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
type: "thead_close",
|
|
402
|
+
tag: "thead",
|
|
403
|
+
attrs: null,
|
|
404
|
+
block: true,
|
|
405
|
+
level: 1,
|
|
406
|
+
children: null
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
type: "table_close",
|
|
410
|
+
tag: "table",
|
|
411
|
+
attrs: null,
|
|
412
|
+
map: null,
|
|
413
|
+
children: null,
|
|
414
|
+
content: "",
|
|
415
|
+
markup: "",
|
|
416
|
+
info: "",
|
|
417
|
+
level: 0,
|
|
418
|
+
meta: null
|
|
419
|
+
}
|
|
420
|
+
];
|
|
421
|
+
}
|
|
422
|
+
function createTh(text) {
|
|
423
|
+
return [
|
|
424
|
+
{
|
|
425
|
+
type: "th_open",
|
|
426
|
+
tag: "th",
|
|
427
|
+
attrs: null,
|
|
428
|
+
block: true,
|
|
429
|
+
level: 3,
|
|
430
|
+
children: null
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
type: "inline",
|
|
434
|
+
tag: "",
|
|
435
|
+
children: [{
|
|
436
|
+
tag: "",
|
|
437
|
+
type: "text",
|
|
438
|
+
block: false,
|
|
439
|
+
content: text,
|
|
440
|
+
children: null
|
|
441
|
+
}],
|
|
442
|
+
content: text,
|
|
443
|
+
level: 4,
|
|
444
|
+
attrs: null,
|
|
445
|
+
block: true
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
type: "th_close",
|
|
449
|
+
tag: "th",
|
|
450
|
+
attrs: null,
|
|
451
|
+
block: true,
|
|
452
|
+
level: 3,
|
|
453
|
+
children: null
|
|
454
|
+
}
|
|
455
|
+
];
|
|
456
|
+
}
|
|
457
|
+
function fixTableTokens(tokens) {
|
|
458
|
+
const fixedTokens = [...tokens];
|
|
459
|
+
if (tokens.length < 3) return fixedTokens;
|
|
460
|
+
const i = tokens.length - 2;
|
|
461
|
+
const token = tokens[i];
|
|
462
|
+
if (token.type === "inline") {
|
|
463
|
+
const tcontent = String(token.content ?? "");
|
|
464
|
+
const childContent = String(token.children?.[0]?.content ?? "");
|
|
465
|
+
if (/^\|(?:[^|\n]+\|?)+/.test(tcontent)) {
|
|
466
|
+
const body = childContent.slice(1).split("|").map((i$1) => i$1.trim()).filter(Boolean).flatMap((i$1) => createTh(i$1));
|
|
467
|
+
const insert = [
|
|
468
|
+
...createStart(),
|
|
469
|
+
...body,
|
|
470
|
+
...createEnd()
|
|
471
|
+
];
|
|
472
|
+
fixedTokens.splice(i - 1, 3, ...insert);
|
|
473
|
+
} else if (/^\|(?:[^|\n]+\|)+\n\|:?-/.test(tcontent)) {
|
|
474
|
+
const body = childContent.slice(1, -1).split("|").map((i$1) => i$1.trim()).flatMap((i$1) => createTh(i$1));
|
|
475
|
+
const insert = [
|
|
476
|
+
...createStart(),
|
|
477
|
+
...body,
|
|
478
|
+
...createEnd()
|
|
479
|
+
];
|
|
480
|
+
fixedTokens.splice(i - 1, 3, ...insert);
|
|
481
|
+
} else if (/^\|(?:[^|\n:]+\|)+\n\|:?$/.test(tcontent)) {
|
|
482
|
+
token.content = tcontent.slice(0, -2);
|
|
483
|
+
token.children.splice(2, 1);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return fixedTokens;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/plugins/fixTableTokens.ts
|
|
491
|
+
function applyFixTableTokens(md) {
|
|
492
|
+
md.core.ruler.after("block", "fix_table_tokens", (state) => {
|
|
493
|
+
const s = state;
|
|
494
|
+
try {
|
|
495
|
+
const fixed = fixTableTokens(s.tokens ?? []);
|
|
496
|
+
if (Array.isArray(fixed)) s.tokens = fixed;
|
|
497
|
+
} catch (e) {
|
|
498
|
+
console.error("[applyFixTableTokens] failed to fix table tokens", e);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
78
503
|
//#endregion
|
|
79
504
|
//#region src/findMatchingClose.ts
|
|
80
505
|
function findMatchingClose(src, startIdx, open, close) {
|
|
@@ -524,166 +949,37 @@ function applyRenderRules(md) {
|
|
|
524
949
|
};
|
|
525
950
|
md.renderer.rules.image = (tokens, idx, options, env, self) => {
|
|
526
951
|
const tokensAny = tokens;
|
|
527
|
-
tokensAny[idx].attrSet?.("loading", "lazy");
|
|
528
|
-
return defaultImage(tokensAny, idx, options, env, self);
|
|
529
|
-
};
|
|
530
|
-
md.renderer.rules.fence = md.renderer.rules.fence || ((tokens, idx) => {
|
|
531
|
-
const tokenShape = tokens[idx];
|
|
532
|
-
const info = String(tokenShape.info ?? "").trim();
|
|
533
|
-
return `<pre class="${info ? `language-${md.utils.escapeHtml(info.split(/\s+/g)[0])}` : ""}"><code>${md.utils.escapeHtml(String(tokenShape.content ?? ""))}</code></pre>`;
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
//#endregion
|
|
538
|
-
//#region src/factory.ts
|
|
539
|
-
function factory(opts = {}) {
|
|
540
|
-
const md = new MarkdownIt({
|
|
541
|
-
html: true,
|
|
542
|
-
linkify: true,
|
|
543
|
-
typographer: true,
|
|
544
|
-
...opts.markdownItOptions ?? {}
|
|
545
|
-
});
|
|
546
|
-
if (opts.enableMath ?? true) applyMath(md, {
|
|
547
|
-
...getDefaultMathOptions() ?? {},
|
|
548
|
-
...opts.mathOptions ?? {}
|
|
549
|
-
});
|
|
550
|
-
if (opts.enableContainers ?? true) applyContainers(md);
|
|
551
|
-
applyRenderRules(md);
|
|
552
|
-
return md;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
//#endregion
|
|
556
|
-
//#region src/parser/fixTableTokens.ts
|
|
557
|
-
function createStart() {
|
|
558
|
-
return [
|
|
559
|
-
{
|
|
560
|
-
type: "table_open",
|
|
561
|
-
tag: "table",
|
|
562
|
-
attrs: null,
|
|
563
|
-
map: null,
|
|
564
|
-
children: null,
|
|
565
|
-
content: "",
|
|
566
|
-
markup: "",
|
|
567
|
-
info: "",
|
|
568
|
-
level: 0,
|
|
569
|
-
loading: true,
|
|
570
|
-
meta: null
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
type: "thead_open",
|
|
574
|
-
tag: "thead",
|
|
575
|
-
attrs: null,
|
|
576
|
-
block: true,
|
|
577
|
-
level: 1,
|
|
578
|
-
children: null
|
|
579
|
-
},
|
|
580
|
-
{
|
|
581
|
-
type: "tr_open",
|
|
582
|
-
tag: "tr",
|
|
583
|
-
attrs: null,
|
|
584
|
-
block: true,
|
|
585
|
-
level: 2,
|
|
586
|
-
children: null
|
|
587
|
-
}
|
|
588
|
-
];
|
|
589
|
-
}
|
|
590
|
-
function createEnd() {
|
|
591
|
-
return [
|
|
592
|
-
{
|
|
593
|
-
type: "tr_close",
|
|
594
|
-
tag: "tr",
|
|
595
|
-
attrs: null,
|
|
596
|
-
block: true,
|
|
597
|
-
level: 2,
|
|
598
|
-
children: null
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
type: "thead_close",
|
|
602
|
-
tag: "thead",
|
|
603
|
-
attrs: null,
|
|
604
|
-
block: true,
|
|
605
|
-
level: 1,
|
|
606
|
-
children: null
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
type: "table_close",
|
|
610
|
-
tag: "table",
|
|
611
|
-
attrs: null,
|
|
612
|
-
map: null,
|
|
613
|
-
children: null,
|
|
614
|
-
content: "",
|
|
615
|
-
markup: "",
|
|
616
|
-
info: "",
|
|
617
|
-
level: 0,
|
|
618
|
-
meta: null
|
|
619
|
-
}
|
|
620
|
-
];
|
|
621
|
-
}
|
|
622
|
-
function createTh(text) {
|
|
623
|
-
return [
|
|
624
|
-
{
|
|
625
|
-
type: "th_open",
|
|
626
|
-
tag: "th",
|
|
627
|
-
attrs: null,
|
|
628
|
-
block: true,
|
|
629
|
-
level: 3,
|
|
630
|
-
children: null
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
type: "inline",
|
|
634
|
-
tag: "",
|
|
635
|
-
children: [{
|
|
636
|
-
tag: "",
|
|
637
|
-
type: "text",
|
|
638
|
-
block: false,
|
|
639
|
-
content: text,
|
|
640
|
-
children: null
|
|
641
|
-
}],
|
|
642
|
-
content: text,
|
|
643
|
-
level: 4,
|
|
644
|
-
attrs: null,
|
|
645
|
-
block: true
|
|
646
|
-
},
|
|
647
|
-
{
|
|
648
|
-
type: "th_close",
|
|
649
|
-
tag: "th",
|
|
650
|
-
attrs: null,
|
|
651
|
-
block: true,
|
|
652
|
-
level: 3,
|
|
653
|
-
children: null
|
|
654
|
-
}
|
|
655
|
-
];
|
|
952
|
+
tokensAny[idx].attrSet?.("loading", "lazy");
|
|
953
|
+
return defaultImage(tokensAny, idx, options, env, self);
|
|
954
|
+
};
|
|
955
|
+
md.renderer.rules.fence = md.renderer.rules.fence || ((tokens, idx) => {
|
|
956
|
+
const tokenShape = tokens[idx];
|
|
957
|
+
const info = String(tokenShape.info ?? "").trim();
|
|
958
|
+
return `<pre class="${info ? `language-${md.utils.escapeHtml(info.split(/\s+/g)[0])}` : ""}"><code>${md.utils.escapeHtml(String(tokenShape.content ?? ""))}</code></pre>`;
|
|
959
|
+
});
|
|
656
960
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
];
|
|
680
|
-
fixedTokens.splice(i - 1, 3, ...insert);
|
|
681
|
-
} else if (/^\|(?:[^|\n:]+\|)+\n\|:?$/.test(tcontent)) {
|
|
682
|
-
token.content = tcontent.slice(0, -2);
|
|
683
|
-
token.children.splice(2, 1);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return fixedTokens;
|
|
961
|
+
|
|
962
|
+
//#endregion
|
|
963
|
+
//#region src/factory.ts
|
|
964
|
+
function factory(opts = {}) {
|
|
965
|
+
const md = new MarkdownIt({
|
|
966
|
+
html: true,
|
|
967
|
+
linkify: true,
|
|
968
|
+
typographer: true,
|
|
969
|
+
...opts.markdownItOptions ?? {}
|
|
970
|
+
});
|
|
971
|
+
if (opts.enableMath ?? true) applyMath(md, {
|
|
972
|
+
...getDefaultMathOptions() ?? {},
|
|
973
|
+
...opts.mathOptions ?? {}
|
|
974
|
+
});
|
|
975
|
+
if (opts.enableContainers ?? true) applyContainers(md);
|
|
976
|
+
applyFixLinkInline(md);
|
|
977
|
+
applyFixLinkTokens(md);
|
|
978
|
+
applyFixStrongTokens(md);
|
|
979
|
+
applyFixListItem(md);
|
|
980
|
+
applyFixTableTokens(md);
|
|
981
|
+
applyRenderRules(md);
|
|
982
|
+
return md;
|
|
687
983
|
}
|
|
688
984
|
|
|
689
985
|
//#endregion
|
|
@@ -795,205 +1091,6 @@ function parseFenceToken(token) {
|
|
|
795
1091
|
};
|
|
796
1092
|
}
|
|
797
1093
|
|
|
798
|
-
//#endregion
|
|
799
|
-
//#region src/parser/inline-parsers/fixLinkToken.ts
|
|
800
|
-
function isTextToken(t) {
|
|
801
|
-
return !!t && t.type === "text" && typeof t.content === "string";
|
|
802
|
-
}
|
|
803
|
-
function fixLinkToken(tokens) {
|
|
804
|
-
const tokensAny = tokens;
|
|
805
|
-
tokens = fixLinkToken4(fixLinkToken3(tokens));
|
|
806
|
-
if (tokens.length < 5) return tokens;
|
|
807
|
-
const first = tokens[tokens.length - 5];
|
|
808
|
-
const firstAny = first;
|
|
809
|
-
const firstContent = String(firstAny.content ?? "");
|
|
810
|
-
if (first.type !== "text" || !firstContent.endsWith("[")) return fixLinkTokens2(tokens);
|
|
811
|
-
if (tokens[tokens.length - 4].tag !== "em") return fixLinkTokens2(tokens);
|
|
812
|
-
const last = tokens[tokens.length - 1];
|
|
813
|
-
const lastAny = last;
|
|
814
|
-
const lastContent = String(lastAny.content ?? "");
|
|
815
|
-
if (last?.type === "text" && !lastContent.startsWith("]")) return fixLinkTokens2(tokens);
|
|
816
|
-
const thirdAny = tokens[tokens.length - 3];
|
|
817
|
-
const thirdContent = String(thirdAny.content ?? "");
|
|
818
|
-
const href = lastContent.replace(/^\]\(*/, "");
|
|
819
|
-
const loading = !lastContent.includes(")");
|
|
820
|
-
tokensAny[tokens.length - 5].content = firstContent.replace(/\[$/, "");
|
|
821
|
-
tokens.splice(tokens.length - 3, 1, {
|
|
822
|
-
type: "link",
|
|
823
|
-
href,
|
|
824
|
-
text: thirdContent,
|
|
825
|
-
children: [{
|
|
826
|
-
type: "text",
|
|
827
|
-
content: thirdContent,
|
|
828
|
-
raw: thirdContent
|
|
829
|
-
}],
|
|
830
|
-
loading
|
|
831
|
-
});
|
|
832
|
-
tokens.splice(tokens.length - 1, 1);
|
|
833
|
-
return tokens;
|
|
834
|
-
}
|
|
835
|
-
function fixLinkTokens2(tokens) {
|
|
836
|
-
const tokensAny = tokens;
|
|
837
|
-
if (tokens.length < 8) return tokens;
|
|
838
|
-
let length = tokens.length;
|
|
839
|
-
let last = tokens[length - 1];
|
|
840
|
-
if (last.type !== "link_close") {
|
|
841
|
-
length--;
|
|
842
|
-
last = tokens[length - 1];
|
|
843
|
-
if (last.type !== "link_close") return tokens;
|
|
844
|
-
}
|
|
845
|
-
if (tokens[length - 7].type !== "em_open") return tokens;
|
|
846
|
-
const third = tokens[length - 6];
|
|
847
|
-
const first = tokens[length - 8];
|
|
848
|
-
if (first.type !== "text") return tokens;
|
|
849
|
-
let href = String(tokensAny[length - 2]?.content ?? "");
|
|
850
|
-
let count = 4;
|
|
851
|
-
if (length !== tokens.length) {
|
|
852
|
-
href += String(last.content ?? "");
|
|
853
|
-
count++;
|
|
854
|
-
}
|
|
855
|
-
tokens.splice(length - 4, count);
|
|
856
|
-
const thirdAny = third;
|
|
857
|
-
const content = String(thirdAny.content ?? "");
|
|
858
|
-
length -= 4;
|
|
859
|
-
const firstAny = first;
|
|
860
|
-
tokensAny[length - 8].content = String(firstAny.content ?? "").replace(/\[$/, "");
|
|
861
|
-
tokens.splice(length - 2, 1, {
|
|
862
|
-
type: "link",
|
|
863
|
-
href,
|
|
864
|
-
text: content,
|
|
865
|
-
children: [{
|
|
866
|
-
type: "text",
|
|
867
|
-
content,
|
|
868
|
-
raw: content
|
|
869
|
-
}],
|
|
870
|
-
loading: true
|
|
871
|
-
});
|
|
872
|
-
return tokens;
|
|
873
|
-
}
|
|
874
|
-
function fixLinkToken3(tokens) {
|
|
875
|
-
const tokensAny = tokens;
|
|
876
|
-
const last = tokens[tokens.length - 1];
|
|
877
|
-
const preLast = tokens[tokens.length - 2];
|
|
878
|
-
const fixedTokens = [...tokens];
|
|
879
|
-
if (last.type !== "text" || !last.content?.startsWith(")")) return tokens;
|
|
880
|
-
if (preLast.type !== "link_close") return tokens;
|
|
881
|
-
if (isTextToken(tokens[tokens.length - 5]) && String(tokens[tokens.length - 5].content ?? "").endsWith("(")) {
|
|
882
|
-
const a = tokensAny[tokens.length - 5];
|
|
883
|
-
const b = tokensAny[tokens.length - 3];
|
|
884
|
-
const content = String(a.content ?? "") + String(b.content ?? "") + String(last.content ?? "");
|
|
885
|
-
fixedTokens.splice(tokens.length - 5, 5, {
|
|
886
|
-
type: "text",
|
|
887
|
-
content,
|
|
888
|
-
raw: content
|
|
889
|
-
});
|
|
890
|
-
} else {
|
|
891
|
-
const lc = (last.content ?? "").slice(1);
|
|
892
|
-
fixedTokens[fixedTokens.length - 1] = {
|
|
893
|
-
...last,
|
|
894
|
-
content: lc
|
|
895
|
-
};
|
|
896
|
-
}
|
|
897
|
-
return fixedTokens;
|
|
898
|
-
}
|
|
899
|
-
function fixLinkToken4(tokens) {
|
|
900
|
-
const tokensAny = tokens;
|
|
901
|
-
const fixedTokens = [...tokens];
|
|
902
|
-
for (let i = tokens.length - 1; i >= 3; i--) if (tokens[i].type === "link_close") {
|
|
903
|
-
if (tokens[i - 3]?.content?.endsWith("(")) {
|
|
904
|
-
const nextToken = tokens[i + 1];
|
|
905
|
-
if (nextToken?.type === "text") {
|
|
906
|
-
if (tokens[i - 1].type === "text" && tokens[i - 3].type === "text") {
|
|
907
|
-
const nextTokenContent = String(nextToken.content ?? "");
|
|
908
|
-
const a = tokensAny[i - 3];
|
|
909
|
-
const b = tokensAny[i - 1];
|
|
910
|
-
const content = String(a.content ?? "") + String(b.content ?? "") + nextTokenContent;
|
|
911
|
-
fixedTokens.splice(i - 3, 5, {
|
|
912
|
-
type: "text",
|
|
913
|
-
content,
|
|
914
|
-
raw: content
|
|
915
|
-
});
|
|
916
|
-
i -= 3;
|
|
917
|
-
}
|
|
918
|
-
} else {
|
|
919
|
-
if (tokens[i - 1].type === "text" && tokens[i - 3].type === "text") {
|
|
920
|
-
const a = tokensAny[i - 3];
|
|
921
|
-
const b = tokensAny[i - 1];
|
|
922
|
-
const content = String(a.content ?? "") + String(b.content ?? "");
|
|
923
|
-
fixedTokens.splice(i - 3, 4, {
|
|
924
|
-
type: "text",
|
|
925
|
-
content,
|
|
926
|
-
raw: content
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
i -= 3;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
return fixedTokens;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
//#endregion
|
|
937
|
-
//#region src/parser/inline-parsers/fixListItem.ts
|
|
938
|
-
function fixListItem(tokens) {
|
|
939
|
-
const last = tokens[tokens.length - 1];
|
|
940
|
-
const lastContent = String(last?.content ?? "");
|
|
941
|
-
if (last?.type === "text" && /^\s*\d+\.\s*$/.test(lastContent) && tokens[tokens.length - 2]?.tag === "br") tokens.splice(tokens.length - 1, 1);
|
|
942
|
-
return tokens;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
//#endregion
|
|
946
|
-
//#region src/parser/inline-parsers/fixStrongTokens.ts
|
|
947
|
-
function fixStrongTokens(tokens) {
|
|
948
|
-
const fixedTokens = [...tokens];
|
|
949
|
-
if (tokens.length < 4) return fixedTokens;
|
|
950
|
-
const i = tokens.length - 4;
|
|
951
|
-
const token = tokens[i];
|
|
952
|
-
const nextToken = tokens[i + 1];
|
|
953
|
-
const tokenContent = String(token.content ?? "");
|
|
954
|
-
if (token.type === "text" && tokenContent.endsWith("*") && nextToken.type === "em_open") {
|
|
955
|
-
const _nextToken = tokens[i + 2];
|
|
956
|
-
const count = _nextToken?.type === "text" ? 4 : 3;
|
|
957
|
-
const insert = [
|
|
958
|
-
{
|
|
959
|
-
type: "strong_open",
|
|
960
|
-
tag: "strong",
|
|
961
|
-
attrs: null,
|
|
962
|
-
map: null,
|
|
963
|
-
children: null,
|
|
964
|
-
content: "",
|
|
965
|
-
markup: "**",
|
|
966
|
-
info: "",
|
|
967
|
-
meta: null
|
|
968
|
-
},
|
|
969
|
-
{
|
|
970
|
-
type: "text",
|
|
971
|
-
content: _nextToken?.type === "text" ? String(_nextToken.content ?? "") : ""
|
|
972
|
-
},
|
|
973
|
-
{
|
|
974
|
-
type: "strong_close",
|
|
975
|
-
tag: "strong",
|
|
976
|
-
attrs: null,
|
|
977
|
-
map: null,
|
|
978
|
-
children: null,
|
|
979
|
-
content: "",
|
|
980
|
-
markup: "**",
|
|
981
|
-
info: "",
|
|
982
|
-
meta: null
|
|
983
|
-
}
|
|
984
|
-
];
|
|
985
|
-
const beforeText = tokenContent.slice(0, -1);
|
|
986
|
-
if (beforeText) insert.unshift({
|
|
987
|
-
type: "text",
|
|
988
|
-
content: beforeText,
|
|
989
|
-
raw: beforeText
|
|
990
|
-
});
|
|
991
|
-
fixedTokens.splice(i, count, ...insert);
|
|
992
|
-
return fixedTokens;
|
|
993
|
-
}
|
|
994
|
-
return fixedTokens;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
1094
|
//#endregion
|
|
998
1095
|
//#region src/parser/inline-parsers/footnote-ref-parser.ts
|
|
999
1096
|
function parseFootnoteRefToken(token) {
|
|
@@ -1280,9 +1377,6 @@ function parseInlineTokens(tokens, raw, pPreToken) {
|
|
|
1280
1377
|
const result = [];
|
|
1281
1378
|
let currentTextNode = null;
|
|
1282
1379
|
let i = 0;
|
|
1283
|
-
tokens = fixStrongTokens(tokens);
|
|
1284
|
-
tokens = fixListItem(tokens);
|
|
1285
|
-
tokens = fixLinkToken(tokens);
|
|
1286
1380
|
function resetCurrentTextNode() {
|
|
1287
1381
|
currentTextNode = null;
|
|
1288
1382
|
}
|
|
@@ -1747,7 +1841,17 @@ function parseInlineTokens(tokens, raw, pPreToken) {
|
|
|
1747
1841
|
}
|
|
1748
1842
|
const { node, nextIndex } = parseLinkToken(tokens, i);
|
|
1749
1843
|
i = nextIndex;
|
|
1750
|
-
|
|
1844
|
+
const hrefAttr = token.attrs?.find(([name]) => name === "href")?.[1];
|
|
1845
|
+
const hrefStr = String(hrefAttr ?? "");
|
|
1846
|
+
if (raw && hrefStr) {
|
|
1847
|
+
const openIdx = raw.indexOf("](");
|
|
1848
|
+
if (openIdx === -1) {} else {
|
|
1849
|
+
const closeIdx = raw.indexOf(")", openIdx + 2);
|
|
1850
|
+
if (closeIdx === -1) node.loading = true;
|
|
1851
|
+
else if (raw.slice(openIdx + 2, closeIdx).includes(hrefStr)) node.loading = false;
|
|
1852
|
+
else node.loading = true;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1751
1855
|
pushParsed(node);
|
|
1752
1856
|
}
|
|
1753
1857
|
function handleReference(token) {
|
|
@@ -2359,7 +2463,6 @@ function processTokens(tokens) {
|
|
|
2359
2463
|
if (!tokens || !Array.isArray(tokens)) return [];
|
|
2360
2464
|
const result = [];
|
|
2361
2465
|
let i = 0;
|
|
2362
|
-
tokens = fixTableTokens(tokens);
|
|
2363
2466
|
while (i < tokens.length) {
|
|
2364
2467
|
const token = tokens[i];
|
|
2365
2468
|
switch (token.type) {
|