stream-markdown-parser 0.0.8 → 0.0.10

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.js CHANGED
@@ -75,6 +75,424 @@ 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/plugins/fixLinkTokens.ts
110
+ function applyFixLinkTokens(md) {
111
+ md.core.ruler.after("inline", "fix_link_tokens", (state) => {
112
+ const toks = state.tokens ?? [];
113
+ for (let i = 0; i < toks.length; i++) {
114
+ const t = toks[i];
115
+ if (t && t.type === "inline" && Array.isArray(t.children)) try {
116
+ t.children = fixLinkToken(t.children);
117
+ } catch (e) {
118
+ console.error("[applyFixLinkTokens] failed to fix inline children", e);
119
+ }
120
+ }
121
+ });
122
+ }
123
+ function isTextToken(t) {
124
+ return !!t && t.type === "text" && typeof t.content === "string";
125
+ }
126
+ function fixLinkToken(tokens) {
127
+ const tokensAny = tokens;
128
+ tokens = fixLinkToken4(fixLinkToken3(tokens));
129
+ if (tokens.length < 5) return tokens;
130
+ const first = tokens[tokens.length - 5];
131
+ const firstAny = first;
132
+ const firstContent = String(firstAny.content ?? "");
133
+ if (first.type !== "text" || !firstContent.endsWith("[")) return fixLinkTokens2(tokens);
134
+ if (tokens[tokens.length - 4].tag !== "em") return fixLinkTokens2(tokens);
135
+ const last = tokens[tokens.length - 1];
136
+ const lastAny = last;
137
+ const lastContent = String(lastAny.content ?? "");
138
+ if (last?.type === "text" && !lastContent.startsWith("]")) return fixLinkTokens2(tokens);
139
+ const thirdAny = tokens[tokens.length - 3];
140
+ const thirdContent = String(thirdAny.content ?? "");
141
+ const href = lastContent.replace(/^\]\(*/, "");
142
+ const loading = !lastContent.includes(")");
143
+ tokensAny[tokens.length - 5].content = firstContent.replace(/\[$/, "");
144
+ tokens.splice(tokens.length - 3, 1, {
145
+ type: "link",
146
+ href,
147
+ text: thirdContent,
148
+ children: [{
149
+ type: "text",
150
+ content: thirdContent,
151
+ raw: thirdContent
152
+ }],
153
+ loading
154
+ });
155
+ tokens.splice(tokens.length - 1, 1);
156
+ return tokens;
157
+ }
158
+ function fixLinkTokens2(tokens) {
159
+ const tokensAny = tokens;
160
+ if (tokens.length < 8) return tokens;
161
+ let length = tokens.length;
162
+ let last = tokens[length - 1];
163
+ if (!last) return tokens;
164
+ if (last.type !== "link_close") {
165
+ length--;
166
+ last = tokens[length - 1];
167
+ if (last.type !== "link_close") return tokens;
168
+ }
169
+ if (tokens[length - 7].type !== "em_open") return tokens;
170
+ const third = tokens[length - 6];
171
+ const first = tokens[length - 8];
172
+ if (first.type !== "text") return tokens;
173
+ let href = String(tokensAny[length - 2]?.content ?? "");
174
+ let count = 4;
175
+ if (length !== tokens.length) {
176
+ href += String(last.content ?? "");
177
+ count++;
178
+ }
179
+ tokens.splice(length - 4, count);
180
+ const thirdAny = third;
181
+ const content = String(thirdAny.content ?? "");
182
+ length -= 4;
183
+ const firstAny = first;
184
+ tokensAny[length - 8].content = String(firstAny.content ?? "").replace(/\[$/, "");
185
+ tokens.splice(length - 2, 1, {
186
+ type: "link",
187
+ href,
188
+ text: content,
189
+ children: [{
190
+ type: "text",
191
+ content,
192
+ raw: content
193
+ }],
194
+ loading: true
195
+ });
196
+ return tokens;
197
+ }
198
+ function fixLinkToken3(tokens) {
199
+ const tokensAny = tokens;
200
+ const last = tokens[tokens.length - 1];
201
+ const preLast = tokens[tokens.length - 2];
202
+ const fixedTokens = [...tokens];
203
+ if (!last) return tokens;
204
+ if (last.type !== "text" || !last.content?.startsWith(")")) return tokens;
205
+ if (preLast.type !== "link_close") return tokens;
206
+ if (isTextToken(tokens[tokens.length - 5]) && String(tokens[tokens.length - 5].content ?? "").endsWith("(")) {
207
+ const a = tokensAny[tokens.length - 5];
208
+ const b = tokensAny[tokens.length - 3];
209
+ const content = String(a.content ?? "") + String(b.content ?? "") + String(last.content ?? "");
210
+ fixedTokens.splice(tokens.length - 5, 5, {
211
+ type: "text",
212
+ content,
213
+ raw: content
214
+ });
215
+ } else {
216
+ const lc = (last.content ?? "").slice(1);
217
+ fixedTokens[fixedTokens.length - 1] = {
218
+ ...last,
219
+ content: lc
220
+ };
221
+ }
222
+ return fixedTokens;
223
+ }
224
+ function fixLinkToken4(tokens) {
225
+ const tokensAny = tokens;
226
+ const fixedTokens = [...tokens];
227
+ for (let i = tokens.length - 1; i >= 3; i--) {
228
+ const token = tokens[i];
229
+ if (token && token.type === "link_close") {
230
+ if (tokens[i - 3]?.content?.endsWith("(")) {
231
+ const nextToken = tokens[i + 1];
232
+ if (nextToken && nextToken?.type === "text") {
233
+ if (tokens[i - 1].type === "text" && tokens[i - 3]?.type === "text") {
234
+ const nextTokenContent = String(nextToken.content ?? "");
235
+ const a = tokensAny[i - 3];
236
+ const b = tokensAny[i - 1];
237
+ const content = String(a.content ?? "") + String(b.content ?? "") + nextTokenContent;
238
+ fixedTokens.splice(i - 3, 5, {
239
+ type: "text",
240
+ content,
241
+ raw: content
242
+ });
243
+ i -= 3;
244
+ }
245
+ } else {
246
+ if (tokens[i - 1].type === "text" && tokens[i - 3]?.type === "text") {
247
+ const a = tokensAny[i - 3];
248
+ const b = tokensAny[i - 1];
249
+ const content = String(a.content ?? "") + String(b.content ?? "");
250
+ fixedTokens.splice(i - 3, 4, {
251
+ type: "text",
252
+ content,
253
+ raw: content
254
+ });
255
+ }
256
+ i -= 3;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ return fixedTokens;
262
+ }
263
+
264
+ //#endregion
265
+ //#region src/plugins/fixListItem.ts
266
+ function applyFixListItem(md) {
267
+ md.core.ruler.after("inline", "fix_list_item_tokens", (state) => {
268
+ const toks = state.tokens ?? [];
269
+ for (let i = 0; i < toks.length; i++) {
270
+ const t = toks[i];
271
+ if (t && t.type === "inline" && Array.isArray(t.children)) try {
272
+ t.children = fixListItem(t.children);
273
+ } catch (e) {
274
+ console.error("[applyFixListItem] failed to fix inline children", e);
275
+ }
276
+ }
277
+ });
278
+ }
279
+ function fixListItem(tokens) {
280
+ const last = tokens[tokens.length - 1];
281
+ const lastContent = String(last?.content ?? "");
282
+ if (last?.type === "text" && /^\s*\d+\.\s*$/.test(lastContent) && tokens[tokens.length - 2]?.tag === "br") tokens.splice(tokens.length - 1, 1);
283
+ return tokens;
284
+ }
285
+
286
+ //#endregion
287
+ //#region src/plugins/fixStrongTokens.ts
288
+ function applyFixStrongTokens(md) {
289
+ md.core.ruler.after("inline", "fix_strong_tokens", (state) => {
290
+ const toks = state.tokens ?? [];
291
+ for (let i = 0; i < toks.length; i++) {
292
+ const t = toks[i];
293
+ if (t && t.type === "inline" && Array.isArray(t.children)) try {
294
+ t.children = fixStrongTokens(t.children);
295
+ } catch (e) {
296
+ console.error("[applyFixStrongTokens] failed to fix inline children", e);
297
+ }
298
+ }
299
+ });
300
+ }
301
+ function fixStrongTokens(tokens) {
302
+ const fixedTokens = [...tokens];
303
+ if (tokens.length < 4) return fixedTokens;
304
+ const i = tokens.length - 4;
305
+ const token = tokens[i];
306
+ const nextToken = tokens[i + 1];
307
+ const tokenContent = String(token.content ?? "");
308
+ if (token.type === "text" && tokenContent.endsWith("*") && nextToken.type === "em_open") {
309
+ const _nextToken = tokens[i + 2];
310
+ const count = _nextToken?.type === "text" ? 4 : 3;
311
+ const insert = [
312
+ {
313
+ type: "strong_open",
314
+ tag: "strong",
315
+ attrs: null,
316
+ map: null,
317
+ children: null,
318
+ content: "",
319
+ markup: "**",
320
+ info: "",
321
+ meta: null
322
+ },
323
+ {
324
+ type: "text",
325
+ content: _nextToken?.type === "text" ? String(_nextToken.content ?? "") : ""
326
+ },
327
+ {
328
+ type: "strong_close",
329
+ tag: "strong",
330
+ attrs: null,
331
+ map: null,
332
+ children: null,
333
+ content: "",
334
+ markup: "**",
335
+ info: "",
336
+ meta: null
337
+ }
338
+ ];
339
+ const beforeText = tokenContent.slice(0, -1);
340
+ if (beforeText) insert.unshift({
341
+ type: "text",
342
+ content: beforeText,
343
+ raw: beforeText
344
+ });
345
+ fixedTokens.splice(i, count, ...insert);
346
+ return fixedTokens;
347
+ }
348
+ return fixedTokens;
349
+ }
350
+
351
+ //#endregion
352
+ //#region src/plugins/fixTableTokens.ts
353
+ function applyFixTableTokens(md) {
354
+ md.core.ruler.after("block", "fix_table_tokens", (state) => {
355
+ const s = state;
356
+ try {
357
+ const fixed = fixTableTokens(s.tokens ?? []);
358
+ if (Array.isArray(fixed)) s.tokens = fixed;
359
+ } catch (e) {
360
+ console.error("[applyFixTableTokens] failed to fix table tokens", e);
361
+ }
362
+ });
363
+ }
364
+ function createStart() {
365
+ return [
366
+ {
367
+ type: "table_open",
368
+ tag: "table",
369
+ attrs: null,
370
+ map: null,
371
+ children: null,
372
+ content: "",
373
+ markup: "",
374
+ info: "",
375
+ level: 0,
376
+ loading: true,
377
+ meta: null
378
+ },
379
+ {
380
+ type: "thead_open",
381
+ tag: "thead",
382
+ attrs: null,
383
+ block: true,
384
+ level: 1,
385
+ children: null
386
+ },
387
+ {
388
+ type: "tr_open",
389
+ tag: "tr",
390
+ attrs: null,
391
+ block: true,
392
+ level: 2,
393
+ children: null
394
+ }
395
+ ];
396
+ }
397
+ function createEnd() {
398
+ return [
399
+ {
400
+ type: "tr_close",
401
+ tag: "tr",
402
+ attrs: null,
403
+ block: true,
404
+ level: 2,
405
+ children: null
406
+ },
407
+ {
408
+ type: "thead_close",
409
+ tag: "thead",
410
+ attrs: null,
411
+ block: true,
412
+ level: 1,
413
+ children: null
414
+ },
415
+ {
416
+ type: "table_close",
417
+ tag: "table",
418
+ attrs: null,
419
+ map: null,
420
+ children: null,
421
+ content: "",
422
+ markup: "",
423
+ info: "",
424
+ level: 0,
425
+ meta: null
426
+ }
427
+ ];
428
+ }
429
+ function createTh(text) {
430
+ return [
431
+ {
432
+ type: "th_open",
433
+ tag: "th",
434
+ attrs: null,
435
+ block: true,
436
+ level: 3,
437
+ children: null
438
+ },
439
+ {
440
+ type: "inline",
441
+ tag: "",
442
+ children: [{
443
+ tag: "",
444
+ type: "text",
445
+ block: false,
446
+ content: text,
447
+ children: null
448
+ }],
449
+ content: text,
450
+ level: 4,
451
+ attrs: null,
452
+ block: true
453
+ },
454
+ {
455
+ type: "th_close",
456
+ tag: "th",
457
+ attrs: null,
458
+ block: true,
459
+ level: 3,
460
+ children: null
461
+ }
462
+ ];
463
+ }
464
+ function fixTableTokens(tokens) {
465
+ const fixedTokens = [...tokens];
466
+ if (tokens.length < 3) return fixedTokens;
467
+ const i = tokens.length - 2;
468
+ const token = tokens[i];
469
+ if (token.type === "inline") {
470
+ const tcontent = String(token.content ?? "");
471
+ const childContent = String(token.children?.[0]?.content ?? "");
472
+ if (/^\|(?:[^|\n]+\|?)+/.test(tcontent)) {
473
+ const body = childContent.slice(1).split("|").map((i$1) => i$1.trim()).filter(Boolean).flatMap((i$1) => createTh(i$1));
474
+ const insert = [
475
+ ...createStart(),
476
+ ...body,
477
+ ...createEnd()
478
+ ];
479
+ fixedTokens.splice(i - 1, 3, ...insert);
480
+ } else if (/^\|(?:[^|\n]+\|)+\n\|:?-/.test(tcontent)) {
481
+ const body = childContent.slice(1, -1).split("|").map((i$1) => i$1.trim()).flatMap((i$1) => createTh(i$1));
482
+ const insert = [
483
+ ...createStart(),
484
+ ...body,
485
+ ...createEnd()
486
+ ];
487
+ fixedTokens.splice(i - 1, 3, ...insert);
488
+ } else if (/^\|(?:[^|\n:]+\|)+\n\|:?$/.test(tcontent)) {
489
+ token.content = tcontent.slice(0, -2);
490
+ token.children.splice(2, 1);
491
+ }
492
+ }
493
+ return fixedTokens;
494
+ }
495
+
78
496
  //#endregion
79
497
  //#region src/findMatchingClose.ts
80
498
  function findMatchingClose(src, startIdx, open, close) {
@@ -472,218 +890,89 @@ function applyMath(md, mathOpts) {
472
890
  let content = "";
473
891
  let found = false;
474
892
  const firstLineContent = lineText === openDelim ? "" : lineText.slice(openDelim.length);
475
- if (firstLineContent.includes(closeDelim)) {
476
- const endIndex = firstLineContent.indexOf(closeDelim);
477
- content = firstLineContent.slice(0, endIndex);
478
- found = true;
479
- nextLine = startLine;
480
- } else {
481
- if (firstLineContent) content = firstLineContent;
482
- for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
483
- const lineStart = s.bMarks[nextLine] + s.tShift[nextLine];
484
- const lineEnd = s.eMarks[nextLine];
485
- const currentLine = s.src.slice(lineStart - 1, lineEnd);
486
- if (currentLine.trim() === closeDelim) {
487
- found = true;
488
- break;
489
- } else if (currentLine.includes(closeDelim)) {
490
- found = true;
491
- const endIndex = currentLine.indexOf(closeDelim);
492
- content += (content ? "\n" : "") + currentLine.slice(0, endIndex);
493
- break;
494
- }
495
- content += (content ? "\n" : "") + currentLine;
496
- }
497
- }
498
- const token = s.push("math_block", "math", 0);
499
- token.content = normalizeStandaloneBackslashT(content);
500
- token.markup = openDelim === "$$" ? "$$" : openDelim === "[" ? "[]" : "\\[\\]";
501
- token.raw = `${openDelim}${content}${content.startsWith("\n") ? "\n" : ""}${closeDelim}`;
502
- token.map = [startLine, nextLine + 1];
503
- token.block = true;
504
- token.loading = !found;
505
- s.line = nextLine + 1;
506
- return true;
507
- };
508
- md.inline.ruler.before("escape", "math", mathInline);
509
- md.block.ruler.before("paragraph", "math_block", mathBlock, { alt: [
510
- "paragraph",
511
- "reference",
512
- "blockquote",
513
- "list"
514
- ] });
515
- }
516
-
517
- //#endregion
518
- //#region src/renderers/index.ts
519
- function applyRenderRules(md) {
520
- const defaultImage = md.renderer.rules.image || function(tokens, idx, options, env, self) {
521
- const tokensAny = tokens;
522
- const selfShape = self;
523
- return selfShape.renderToken ? selfShape.renderToken(tokensAny, idx, options) : "";
524
- };
525
- md.renderer.rules.image = (tokens, idx, options, env, self) => {
526
- 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
- ];
656
- }
657
- function fixTableTokens(tokens) {
658
- const fixedTokens = [...tokens];
659
- if (tokens.length < 3) return fixedTokens;
660
- const i = tokens.length - 2;
661
- const token = tokens[i];
662
- if (token.type === "inline") {
663
- const tcontent = String(token.content ?? "");
664
- const childContent = String(token.children?.[0]?.content ?? "");
665
- if (/^\|(?:[^|\n]+\|?)+/.test(tcontent)) {
666
- const body = childContent.slice(1).split("|").map((i$1) => i$1.trim()).filter(Boolean).flatMap((i$1) => createTh(i$1));
667
- const insert = [
668
- ...createStart(),
669
- ...body,
670
- ...createEnd()
671
- ];
672
- fixedTokens.splice(i - 1, 3, ...insert);
673
- } else if (/^\|(?:[^|\n]+\|)+\n\|:?-/.test(tcontent)) {
674
- const body = childContent.slice(1, -1).split("|").map((i$1) => i$1.trim()).flatMap((i$1) => createTh(i$1));
675
- const insert = [
676
- ...createStart(),
677
- ...body,
678
- ...createEnd()
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);
893
+ if (firstLineContent.includes(closeDelim)) {
894
+ const endIndex = firstLineContent.indexOf(closeDelim);
895
+ content = firstLineContent.slice(0, endIndex);
896
+ found = true;
897
+ nextLine = startLine;
898
+ } else {
899
+ if (firstLineContent) content = firstLineContent;
900
+ for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
901
+ const lineStart = s.bMarks[nextLine] + s.tShift[nextLine];
902
+ const lineEnd = s.eMarks[nextLine];
903
+ const currentLine = s.src.slice(lineStart - 1, lineEnd);
904
+ if (currentLine.trim() === closeDelim) {
905
+ found = true;
906
+ break;
907
+ } else if (currentLine.includes(closeDelim)) {
908
+ found = true;
909
+ const endIndex = currentLine.indexOf(closeDelim);
910
+ content += (content ? "\n" : "") + currentLine.slice(0, endIndex);
911
+ break;
912
+ }
913
+ content += (content ? "\n" : "") + currentLine;
914
+ }
684
915
  }
685
- }
686
- return fixedTokens;
916
+ const token = s.push("math_block", "math", 0);
917
+ token.content = normalizeStandaloneBackslashT(content);
918
+ token.markup = openDelim === "$$" ? "$$" : openDelim === "[" ? "[]" : "\\[\\]";
919
+ token.raw = `${openDelim}${content}${content.startsWith("\n") ? "\n" : ""}${closeDelim}`;
920
+ token.map = [startLine, nextLine + 1];
921
+ token.block = true;
922
+ token.loading = !found;
923
+ s.line = nextLine + 1;
924
+ return true;
925
+ };
926
+ md.inline.ruler.before("escape", "math", mathInline);
927
+ md.block.ruler.before("paragraph", "math_block", mathBlock, { alt: [
928
+ "paragraph",
929
+ "reference",
930
+ "blockquote",
931
+ "list"
932
+ ] });
933
+ }
934
+
935
+ //#endregion
936
+ //#region src/renderers/index.ts
937
+ function applyRenderRules(md) {
938
+ const defaultImage = md.renderer.rules.image || function(tokens, idx, options, env, self) {
939
+ const tokensAny = tokens;
940
+ const selfShape = self;
941
+ return selfShape.renderToken ? selfShape.renderToken(tokensAny, idx, options) : "";
942
+ };
943
+ md.renderer.rules.image = (tokens, idx, options, env, self) => {
944
+ const tokensAny = tokens;
945
+ tokensAny[idx].attrSet?.("loading", "lazy");
946
+ return defaultImage(tokensAny, idx, options, env, self);
947
+ };
948
+ md.renderer.rules.fence = md.renderer.rules.fence || ((tokens, idx) => {
949
+ const tokenShape = tokens[idx];
950
+ const info = String(tokenShape.info ?? "").trim();
951
+ return `<pre class="${info ? `language-${md.utils.escapeHtml(info.split(/\s+/g)[0])}` : ""}"><code>${md.utils.escapeHtml(String(tokenShape.content ?? ""))}</code></pre>`;
952
+ });
953
+ }
954
+
955
+ //#endregion
956
+ //#region src/factory.ts
957
+ function factory(opts = {}) {
958
+ const md = new MarkdownIt({
959
+ html: true,
960
+ linkify: true,
961
+ typographer: true,
962
+ ...opts.markdownItOptions ?? {}
963
+ });
964
+ if (opts.enableMath ?? true) applyMath(md, {
965
+ ...getDefaultMathOptions() ?? {},
966
+ ...opts.mathOptions ?? {}
967
+ });
968
+ if (opts.enableContainers ?? true) applyContainers(md);
969
+ applyFixLinkInline(md);
970
+ applyFixLinkTokens(md);
971
+ applyFixStrongTokens(md);
972
+ applyFixListItem(md);
973
+ applyFixTableTokens(md);
974
+ applyRenderRules(md);
975
+ return md;
687
976
  }
688
977
 
689
978
  //#endregion
@@ -795,205 +1084,6 @@ function parseFenceToken(token) {
795
1084
  };
796
1085
  }
797
1086
 
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
1087
  //#endregion
998
1088
  //#region src/parser/inline-parsers/footnote-ref-parser.ts
999
1089
  function parseFootnoteRefToken(token) {
@@ -1280,9 +1370,6 @@ function parseInlineTokens(tokens, raw, pPreToken) {
1280
1370
  const result = [];
1281
1371
  let currentTextNode = null;
1282
1372
  let i = 0;
1283
- tokens = fixStrongTokens(tokens);
1284
- tokens = fixListItem(tokens);
1285
- tokens = fixLinkToken(tokens);
1286
1373
  function resetCurrentTextNode() {
1287
1374
  currentTextNode = null;
1288
1375
  }
@@ -1747,7 +1834,17 @@ function parseInlineTokens(tokens, raw, pPreToken) {
1747
1834
  }
1748
1835
  const { node, nextIndex } = parseLinkToken(tokens, i);
1749
1836
  i = nextIndex;
1750
- node.loading = false;
1837
+ const hrefAttr = token.attrs?.find(([name]) => name === "href")?.[1];
1838
+ const hrefStr = String(hrefAttr ?? "");
1839
+ if (raw && hrefStr) {
1840
+ const openIdx = raw.indexOf("](");
1841
+ if (openIdx === -1) {} else {
1842
+ const closeIdx = raw.indexOf(")", openIdx + 2);
1843
+ if (closeIdx === -1) node.loading = true;
1844
+ else if (raw.slice(openIdx + 2, closeIdx).includes(hrefStr)) node.loading = false;
1845
+ else node.loading = true;
1846
+ }
1847
+ }
1751
1848
  pushParsed(node);
1752
1849
  }
1753
1850
  function handleReference(token) {
@@ -2359,7 +2456,6 @@ function processTokens(tokens) {
2359
2456
  if (!tokens || !Array.isArray(tokens)) return [];
2360
2457
  const result = [];
2361
2458
  let i = 0;
2362
- tokens = fixTableTokens(tokens);
2363
2459
  while (i < tokens.length) {
2364
2460
  const token = tokens[i];
2365
2461
  switch (token.type) {