marked 9.1.6 → 11.0.0

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/lib/marked.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * marked v9.1.6 - a markdown parser
2
+ * marked v11.0.0 - a markdown parser
3
3
  * Copyright (c) 2011-2023, Christopher Jeffrey. (MIT Licensed)
4
4
  * https://github.com/markedjs/marked
5
5
  */
@@ -46,7 +46,7 @@ const escapeReplacements = {
46
46
  "'": '''
47
47
  };
48
48
  const getEscapeReplacement = (ch) => escapeReplacements[ch];
49
- function escape(html, encode) {
49
+ function escape$1(html, encode) {
50
50
  if (encode) {
51
51
  if (escapeTest.test(html)) {
52
52
  return html.replace(escapeReplace, getEscapeReplacement);
@@ -76,17 +76,17 @@ function unescape(html) {
76
76
  }
77
77
  const caret = /(^|[^\[])\^/g;
78
78
  function edit(regex, opt) {
79
- regex = typeof regex === 'string' ? regex : regex.source;
79
+ let source = typeof regex === 'string' ? regex : regex.source;
80
80
  opt = opt || '';
81
81
  const obj = {
82
82
  replace: (name, val) => {
83
- val = typeof val === 'object' && 'source' in val ? val.source : val;
84
- val = val.replace(caret, '$1');
85
- regex = regex.replace(name, val);
83
+ let valSource = typeof val === 'string' ? val : val.source;
84
+ valSource = valSource.replace(caret, '$1');
85
+ source = source.replace(name, valSource);
86
86
  return obj;
87
87
  },
88
88
  getRegex: () => {
89
- return new RegExp(regex, opt);
89
+ return new RegExp(source, opt);
90
90
  }
91
91
  };
92
92
  return obj;
@@ -196,7 +196,7 @@ function findClosingBracket(str, b) {
196
196
 
197
197
  function outputLink(cap, link, raw, lexer) {
198
198
  const href = link.href;
199
- const title = link.title ? escape(link.title) : null;
199
+ const title = link.title ? escape$1(link.title) : null;
200
200
  const text = cap[1].replace(/\\([\[\]])/g, '$1');
201
201
  if (cap[0].charAt(0) !== '!') {
202
202
  lexer.state.inLink = true;
@@ -216,7 +216,7 @@ function outputLink(cap, link, raw, lexer) {
216
216
  raw,
217
217
  href,
218
218
  title,
219
- text: escape(text)
219
+ text: escape$1(text)
220
220
  };
221
221
  }
222
222
  function indentCodeCompensation(raw, text) {
@@ -245,9 +245,8 @@ function indentCodeCompensation(raw, text) {
245
245
  */
246
246
  class _Tokenizer {
247
247
  options;
248
- // TODO: Fix this rules type
249
- rules;
250
- lexer;
248
+ rules; // set by the lexer
249
+ lexer; // set by the lexer
251
250
  constructor(options) {
252
251
  this.options = options || _defaults;
253
252
  }
@@ -282,7 +281,7 @@ class _Tokenizer {
282
281
  return {
283
282
  type: 'code',
284
283
  raw,
285
- lang: cap[2] ? cap[2].trim().replace(this.rules.inline._escapes, '$1') : cap[2],
284
+ lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],
286
285
  text
287
286
  };
288
287
  }
@@ -480,7 +479,7 @@ class _Tokenizer {
480
479
  }
481
480
  // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
482
481
  list.items[list.items.length - 1].raw = raw.trimEnd();
483
- list.items[list.items.length - 1].text = itemContents.trimEnd();
482
+ (list.items[list.items.length - 1]).text = itemContents.trimEnd();
484
483
  list.raw = list.raw.trimEnd();
485
484
  // Item child tokens handled here at end because we needed to have the final item to trim it first
486
485
  for (let i = 0; i < list.items.length; i++) {
@@ -519,8 +518,8 @@ class _Tokenizer {
519
518
  const cap = this.rules.block.def.exec(src);
520
519
  if (cap) {
521
520
  const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
522
- const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline._escapes, '$1') : '';
523
- const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline._escapes, '$1') : cap[3];
521
+ const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';
522
+ const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];
524
523
  return {
525
524
  type: 'def',
526
525
  tag,
@@ -532,63 +531,56 @@ class _Tokenizer {
532
531
  }
533
532
  table(src) {
534
533
  const cap = this.rules.block.table.exec(src);
535
- if (cap) {
536
- if (!/[:|]/.test(cap[2])) {
537
- // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
538
- return;
534
+ if (!cap) {
535
+ return;
536
+ }
537
+ if (!/[:|]/.test(cap[2])) {
538
+ // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
539
+ return;
540
+ }
541
+ const headers = splitCells(cap[1]);
542
+ const aligns = cap[2].replace(/^\||\| *$/g, '').split('|');
543
+ const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : [];
544
+ const item = {
545
+ type: 'table',
546
+ raw: cap[0],
547
+ header: [],
548
+ align: [],
549
+ rows: []
550
+ };
551
+ if (headers.length !== aligns.length) {
552
+ // header and align columns must be equal, rows can be different.
553
+ return;
554
+ }
555
+ for (const align of aligns) {
556
+ if (/^ *-+: *$/.test(align)) {
557
+ item.align.push('right');
539
558
  }
540
- const item = {
541
- type: 'table',
542
- raw: cap[0],
543
- header: splitCells(cap[1]).map(c => {
544
- return { text: c, tokens: [] };
545
- }),
546
- align: cap[2].replace(/^\||\| *$/g, '').split('|'),
547
- rows: cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : []
548
- };
549
- if (item.header.length === item.align.length) {
550
- let l = item.align.length;
551
- let i, j, k, row;
552
- for (i = 0; i < l; i++) {
553
- const align = item.align[i];
554
- if (align) {
555
- if (/^ *-+: *$/.test(align)) {
556
- item.align[i] = 'right';
557
- }
558
- else if (/^ *:-+: *$/.test(align)) {
559
- item.align[i] = 'center';
560
- }
561
- else if (/^ *:-+ *$/.test(align)) {
562
- item.align[i] = 'left';
563
- }
564
- else {
565
- item.align[i] = null;
566
- }
567
- }
568
- }
569
- l = item.rows.length;
570
- for (i = 0; i < l; i++) {
571
- item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => {
572
- return { text: c, tokens: [] };
573
- });
574
- }
575
- // parse child tokens inside headers and cells
576
- // header child tokens
577
- l = item.header.length;
578
- for (j = 0; j < l; j++) {
579
- item.header[j].tokens = this.lexer.inline(item.header[j].text);
580
- }
581
- // cell child tokens
582
- l = item.rows.length;
583
- for (j = 0; j < l; j++) {
584
- row = item.rows[j];
585
- for (k = 0; k < row.length; k++) {
586
- row[k].tokens = this.lexer.inline(row[k].text);
587
- }
588
- }
589
- return item;
559
+ else if (/^ *:-+: *$/.test(align)) {
560
+ item.align.push('center');
561
+ }
562
+ else if (/^ *:-+ *$/.test(align)) {
563
+ item.align.push('left');
590
564
  }
565
+ else {
566
+ item.align.push(null);
567
+ }
568
+ }
569
+ for (const header of headers) {
570
+ item.header.push({
571
+ text: header,
572
+ tokens: this.lexer.inline(header)
573
+ });
591
574
  }
575
+ for (const row of rows) {
576
+ item.rows.push(splitCells(row, item.header.length).map(cell => {
577
+ return {
578
+ text: cell,
579
+ tokens: this.lexer.inline(cell)
580
+ };
581
+ }));
582
+ }
583
+ return item;
592
584
  }
593
585
  lheading(src) {
594
586
  const cap = this.rules.block.lheading.exec(src);
@@ -633,7 +625,7 @@ class _Tokenizer {
633
625
  return {
634
626
  type: 'escape',
635
627
  raw: cap[0],
636
- text: escape(cap[1])
628
+ text: escape$1(cap[1])
637
629
  };
638
630
  }
639
631
  }
@@ -712,8 +704,8 @@ class _Tokenizer {
712
704
  }
713
705
  }
714
706
  return outputLink(cap, {
715
- href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
716
- title: title ? title.replace(this.rules.inline._escapes, '$1') : title
707
+ href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,
708
+ title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title
717
709
  }, cap[0], this.lexer);
718
710
  }
719
711
  }
@@ -721,8 +713,8 @@ class _Tokenizer {
721
713
  let cap;
722
714
  if ((cap = this.rules.inline.reflink.exec(src))
723
715
  || (cap = this.rules.inline.nolink.exec(src))) {
724
- let link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
725
- link = links[link.toLowerCase()];
716
+ const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' ');
717
+ const link = links[linkString.toLowerCase()];
726
718
  if (!link) {
727
719
  const text = cap[0].charAt(0);
728
720
  return {
@@ -735,7 +727,7 @@ class _Tokenizer {
735
727
  }
736
728
  }
737
729
  emStrong(src, maskedSrc, prevChar = '') {
738
- let match = this.rules.inline.emStrong.lDelim.exec(src);
730
+ let match = this.rules.inline.emStrongLDelim.exec(src);
739
731
  if (!match)
740
732
  return;
741
733
  // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
@@ -746,7 +738,7 @@ class _Tokenizer {
746
738
  // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
747
739
  const lLength = [...match[0]].length - 1;
748
740
  let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
749
- const endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
741
+ const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
750
742
  endReg.lastIndex = 0;
751
743
  // Clip maskedSrc to same section of string as src (move to lexer?)
752
744
  maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
@@ -803,7 +795,7 @@ class _Tokenizer {
803
795
  if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
804
796
  text = text.substring(1, text.length - 1);
805
797
  }
806
- text = escape(text, true);
798
+ text = escape$1(text, true);
807
799
  return {
808
800
  type: 'codespan',
809
801
  raw: cap[0],
@@ -836,11 +828,11 @@ class _Tokenizer {
836
828
  if (cap) {
837
829
  let text, href;
838
830
  if (cap[2] === '@') {
839
- text = escape(cap[1]);
831
+ text = escape$1(cap[1]);
840
832
  href = 'mailto:' + text;
841
833
  }
842
834
  else {
843
- text = escape(cap[1]);
835
+ text = escape$1(cap[1]);
844
836
  href = text;
845
837
  }
846
838
  return {
@@ -863,7 +855,7 @@ class _Tokenizer {
863
855
  if (cap = this.rules.inline.url.exec(src)) {
864
856
  let text, href;
865
857
  if (cap[2] === '@') {
866
- text = escape(cap[0]);
858
+ text = escape$1(cap[0]);
867
859
  href = 'mailto:' + text;
868
860
  }
869
861
  else {
@@ -871,9 +863,9 @@ class _Tokenizer {
871
863
  let prevCapZero;
872
864
  do {
873
865
  prevCapZero = cap[0];
874
- cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
866
+ cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';
875
867
  } while (prevCapZero !== cap[0]);
876
- text = escape(cap[0]);
868
+ text = escape$1(cap[0]);
877
869
  if (cap[1] === 'www.') {
878
870
  href = 'http://' + cap[0];
879
871
  }
@@ -904,7 +896,7 @@ class _Tokenizer {
904
896
  text = cap[0];
905
897
  }
906
898
  else {
907
- text = escape(cap[0]);
899
+ text = escape$1(cap[0]);
908
900
  }
909
901
  return {
910
902
  type: 'text',
@@ -918,66 +910,48 @@ class _Tokenizer {
918
910
  /**
919
911
  * Block-Level Grammar
920
912
  */
921
- // Not all rules are defined in the object literal
922
- // @ts-expect-error
923
- const block = {
924
- newline: /^(?: *(?:\n|$))+/,
925
- code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
926
- fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
927
- hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
928
- heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
929
- blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
930
- list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
931
- html: '^ {0,3}(?:' // optional indentation
932
- + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
933
- + '|comment[^\\n]*(\\n+|$)' // (2)
934
- + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
935
- + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
936
- + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
937
- + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
938
- + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
939
- + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
940
- + ')',
941
- def: /^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
942
- table: noopTest,
943
- lheading: /^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
944
- // regex template, placeholders will be replaced according to different paragraph
945
- // interruption rules of commonmark and the original markdown spec:
946
- _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
947
- text: /^[^\n]+/
948
- };
949
- block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
950
- block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
951
- block.def = edit(block.def)
952
- .replace('label', block._label)
953
- .replace('title', block._title)
913
+ const newline = /^(?: *(?:\n|$))+/;
914
+ const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/;
915
+ const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
916
+ const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
917
+ const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
918
+ const bullet = /(?:[*+-]|\d{1,9}[.)])/;
919
+ const lheading = edit(/^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/)
920
+ .replace(/bull/g, bullet) // lists can interrupt
954
921
  .getRegex();
955
- block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
956
- block.listItemStart = edit(/^( *)(bull) */)
957
- .replace('bull', block.bullet)
922
+ const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
923
+ const blockText = /^[^\n]+/;
924
+ const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
925
+ const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/)
926
+ .replace('label', _blockLabel)
927
+ .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/)
958
928
  .getRegex();
959
- block.list = edit(block.list)
960
- .replace(/bull/g, block.bullet)
961
- .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
962
- .replace('def', '\\n+(?=' + block.def.source + ')')
929
+ const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
930
+ .replace(/bull/g, bullet)
963
931
  .getRegex();
964
- block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
932
+ const _tag = 'address|article|aside|base|basefont|blockquote|body|caption'
965
933
  + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
966
934
  + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
967
935
  + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
968
936
  + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
969
937
  + '|track|ul';
970
- block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
971
- block.html = edit(block.html, 'i')
972
- .replace('comment', block._comment)
973
- .replace('tag', block._tag)
938
+ const _comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
939
+ const html = edit('^ {0,3}(?:' // optional indentation
940
+ + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
941
+ + '|comment[^\\n]*(\\n+|$)' // (2)
942
+ + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
943
+ + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
944
+ + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
945
+ + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
946
+ + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
947
+ + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
948
+ + ')', 'i')
949
+ .replace('comment', _comment)
950
+ .replace('tag', _tag)
974
951
  .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
975
952
  .getRegex();
976
- block.lheading = edit(block.lheading)
977
- .replace(/bull/g, block.bullet) // lists can interrupt
978
- .getRegex();
979
- block.paragraph = edit(block._paragraph)
980
- .replace('hr', block.hr)
953
+ const paragraph = edit(_paragraph)
954
+ .replace('hr', hr)
981
955
  .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
982
956
  .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
983
957
  .replace('|table', '')
@@ -985,54 +959,68 @@ block.paragraph = edit(block._paragraph)
985
959
  .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
986
960
  .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
987
961
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
988
- .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
962
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
989
963
  .getRegex();
990
- block.blockquote = edit(block.blockquote)
991
- .replace('paragraph', block.paragraph)
964
+ const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/)
965
+ .replace('paragraph', paragraph)
992
966
  .getRegex();
993
967
  /**
994
968
  * Normal Block Grammar
995
969
  */
996
- block.normal = { ...block };
970
+ const blockNormal = {
971
+ blockquote,
972
+ code: blockCode,
973
+ def,
974
+ fences,
975
+ heading,
976
+ hr,
977
+ html,
978
+ lheading,
979
+ list,
980
+ newline,
981
+ paragraph,
982
+ table: noopTest,
983
+ text: blockText
984
+ };
997
985
  /**
998
986
  * GFM Block Grammar
999
987
  */
1000
- block.gfm = {
1001
- ...block.normal,
1002
- table: '^ *([^\\n ].*)\\n' // Header
1003
- + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
1004
- + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
1005
- };
1006
- block.gfm.table = edit(block.gfm.table)
1007
- .replace('hr', block.hr)
988
+ const gfmTable = edit('^ *([^\\n ].*)\\n' // Header
989
+ + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
990
+ + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells
991
+ .replace('hr', hr)
1008
992
  .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1009
993
  .replace('blockquote', ' {0,3}>')
1010
994
  .replace('code', ' {4}[^\\n]')
1011
995
  .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1012
996
  .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1013
997
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1014
- .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
1015
- .getRegex();
1016
- block.gfm.paragraph = edit(block._paragraph)
1017
- .replace('hr', block.hr)
1018
- .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1019
- .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1020
- .replace('table', block.gfm.table) // interrupt paragraphs with table
1021
- .replace('blockquote', ' {0,3}>')
1022
- .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1023
- .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1024
- .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1025
- .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
998
+ .replace('tag', _tag) // tables can be interrupted by type (6) html blocks
1026
999
  .getRegex();
1000
+ const blockGfm = {
1001
+ ...blockNormal,
1002
+ table: gfmTable,
1003
+ paragraph: edit(_paragraph)
1004
+ .replace('hr', hr)
1005
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1006
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
1007
+ .replace('table', gfmTable) // interrupt paragraphs with table
1008
+ .replace('blockquote', ' {0,3}>')
1009
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1010
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1011
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1012
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
1013
+ .getRegex()
1014
+ };
1027
1015
  /**
1028
1016
  * Pedantic grammar (original John Gruber's loose markdown specification)
1029
1017
  */
1030
- block.pedantic = {
1031
- ...block.normal,
1018
+ const blockPedantic = {
1019
+ ...blockNormal,
1032
1020
  html: edit('^ *(?:comment *(?:\\n|\\s*$)'
1033
1021
  + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
1034
1022
  + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
1035
- .replace('comment', block._comment)
1023
+ .replace('comment', _comment)
1036
1024
  .replace(/tag/g, '(?!(?:'
1037
1025
  + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
1038
1026
  + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
@@ -1040,157 +1028,164 @@ block.pedantic = {
1040
1028
  .getRegex(),
1041
1029
  def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
1042
1030
  heading: /^(#{1,6})(.*)(?:\n+|$)/,
1043
- fences: noopTest,
1031
+ fences: noopTest, // fences not supported
1044
1032
  lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
1045
- paragraph: edit(block.normal._paragraph)
1046
- .replace('hr', block.hr)
1033
+ paragraph: edit(_paragraph)
1034
+ .replace('hr', hr)
1047
1035
  .replace('heading', ' *#{1,6} *[^\n]')
1048
- .replace('lheading', block.lheading)
1036
+ .replace('lheading', lheading)
1037
+ .replace('|table', '')
1049
1038
  .replace('blockquote', ' {0,3}>')
1050
1039
  .replace('|fences', '')
1051
1040
  .replace('|list', '')
1052
1041
  .replace('|html', '')
1042
+ .replace('|tag', '')
1053
1043
  .getRegex()
1054
1044
  };
1055
1045
  /**
1056
1046
  * Inline-Level Grammar
1057
1047
  */
1058
- // Not all rules are defined in the object literal
1059
- // @ts-expect-error
1060
- const inline = {
1061
- escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
1062
- autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
1063
- url: noopTest,
1064
- tag: '^comment'
1065
- + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
1066
- + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
1067
- + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
1068
- + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
1069
- + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
1070
- link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
1071
- reflink: /^!?\[(label)\]\[(ref)\]/,
1072
- nolink: /^!?\[(ref)\](?:\[\])?/,
1073
- reflinkSearch: 'reflink|nolink(?!\\()',
1074
- emStrong: {
1075
- lDelim: /^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,
1076
- // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
1077
- // | Skip orphan inside strong | Consume to delim | (1) #*** | (2) a***#, a*** | (3) #***a, ***a | (4) ***# | (5) #***# | (6) a***a
1078
- rDelimAst: /^[^_*]*?__[^_*]*?\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\*)[punct](\*+)(?=[\s]|$)|[^punct\s](\*+)(?!\*)(?=[punct\s]|$)|(?!\*)[punct\s](\*+)(?=[^punct\s])|[\s](\*+)(?!\*)(?=[punct])|(?!\*)[punct](\*+)(?!\*)(?=[punct])|[^punct\s](\*+)(?=[^punct\s])/,
1079
- rDelimUnd: /^[^_*]*?\*\*[^_*]*?_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\s]|$)|[^punct\s](_+)(?!_)(?=[punct\s]|$)|(?!_)[punct\s](_+)(?=[^punct\s])|[\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])/ // ^- Not allowed for _
1080
- },
1081
- code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
1082
- br: /^( {2,}|\\)\n(?!\s*$)/,
1083
- del: noopTest,
1084
- text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
1085
- punctuation: /^((?![*_])[\spunctuation])/
1086
- };
1048
+ const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
1049
+ const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
1050
+ const br = /^( {2,}|\\)\n(?!\s*$)/;
1051
+ const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
1087
1052
  // list of unicode punctuation marks, plus any missing characters from CommonMark spec
1088
- inline._punctuation = '\\p{P}$+<=>`^|~';
1089
- inline.punctuation = edit(inline.punctuation, 'u').replace(/punctuation/g, inline._punctuation).getRegex();
1053
+ const _punctuation = '\\p{P}$+<=>`^|~';
1054
+ const punctuation = edit(/^((?![*_])[\spunctuation])/, 'u')
1055
+ .replace(/punctuation/g, _punctuation).getRegex();
1090
1056
  // sequences em should skip over [title](link), `code`, <html>
1091
- inline.blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
1092
- inline.anyPunctuation = /\\[punct]/g;
1093
- inline._escapes = /\\([punct])/g;
1094
- inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
1095
- inline.emStrong.lDelim = edit(inline.emStrong.lDelim, 'u')
1096
- .replace(/punct/g, inline._punctuation)
1097
- .getRegex();
1098
- inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'gu')
1099
- .replace(/punct/g, inline._punctuation)
1057
+ const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
1058
+ const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u')
1059
+ .replace(/punct/g, _punctuation)
1100
1060
  .getRegex();
1101
- inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'gu')
1102
- .replace(/punct/g, inline._punctuation)
1061
+ const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong
1062
+ + '|[^*]+(?=[^*])' // Consume to delim
1063
+ + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter
1064
+ + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter
1065
+ + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter
1066
+ + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter
1067
+ + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter
1068
+ + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter
1069
+ .replace(/punct/g, _punctuation)
1103
1070
  .getRegex();
1104
- inline.anyPunctuation = edit(inline.anyPunctuation, 'gu')
1105
- .replace(/punct/g, inline._punctuation)
1071
+ // (6) Not allowed for _
1072
+ const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong
1073
+ + '|[^_]+(?=[^_])' // Consume to delim
1074
+ + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter
1075
+ + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter
1076
+ + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter
1077
+ + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter
1078
+ + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter
1079
+ .replace(/punct/g, _punctuation)
1106
1080
  .getRegex();
1107
- inline._escapes = edit(inline._escapes, 'gu')
1108
- .replace(/punct/g, inline._punctuation)
1081
+ const anyPunctuation = edit(/\\([punct])/, 'gu')
1082
+ .replace(/punct/g, _punctuation)
1109
1083
  .getRegex();
1110
- inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
1111
- inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
1112
- inline.autolink = edit(inline.autolink)
1113
- .replace('scheme', inline._scheme)
1114
- .replace('email', inline._email)
1084
+ const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/)
1085
+ .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)
1086
+ .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)
1115
1087
  .getRegex();
1116
- inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
1117
- inline.tag = edit(inline.tag)
1118
- .replace('comment', inline._comment)
1119
- .replace('attribute', inline._attribute)
1088
+ const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();
1089
+ const tag = edit('^comment'
1090
+ + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
1091
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
1092
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
1093
+ + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
1094
+ + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>') // CDATA section
1095
+ .replace('comment', _inlineComment)
1096
+ .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/)
1120
1097
  .getRegex();
1121
- inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
1122
- inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
1123
- inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
1124
- inline.link = edit(inline.link)
1125
- .replace('label', inline._label)
1126
- .replace('href', inline._href)
1127
- .replace('title', inline._title)
1098
+ const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
1099
+ const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/)
1100
+ .replace('label', _inlineLabel)
1101
+ .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/)
1102
+ .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/)
1128
1103
  .getRegex();
1129
- inline.reflink = edit(inline.reflink)
1130
- .replace('label', inline._label)
1131
- .replace('ref', block._label)
1104
+ const reflink = edit(/^!?\[(label)\]\[(ref)\]/)
1105
+ .replace('label', _inlineLabel)
1106
+ .replace('ref', _blockLabel)
1132
1107
  .getRegex();
1133
- inline.nolink = edit(inline.nolink)
1134
- .replace('ref', block._label)
1108
+ const nolink = edit(/^!?\[(ref)\](?:\[\])?/)
1109
+ .replace('ref', _blockLabel)
1135
1110
  .getRegex();
1136
- inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
1137
- .replace('reflink', inline.reflink)
1138
- .replace('nolink', inline.nolink)
1111
+ const reflinkSearch = edit('reflink|nolink(?!\\()', 'g')
1112
+ .replace('reflink', reflink)
1113
+ .replace('nolink', nolink)
1139
1114
  .getRegex();
1140
1115
  /**
1141
1116
  * Normal Inline Grammar
1142
1117
  */
1143
- inline.normal = { ...inline };
1118
+ const inlineNormal = {
1119
+ _backpedal: noopTest, // only used for GFM url
1120
+ anyPunctuation,
1121
+ autolink,
1122
+ blockSkip,
1123
+ br,
1124
+ code: inlineCode,
1125
+ del: noopTest,
1126
+ emStrongLDelim,
1127
+ emStrongRDelimAst,
1128
+ emStrongRDelimUnd,
1129
+ escape,
1130
+ link,
1131
+ nolink,
1132
+ punctuation,
1133
+ reflink,
1134
+ reflinkSearch,
1135
+ tag,
1136
+ text: inlineText,
1137
+ url: noopTest
1138
+ };
1144
1139
  /**
1145
1140
  * Pedantic Inline Grammar
1146
1141
  */
1147
- inline.pedantic = {
1148
- ...inline.normal,
1149
- strong: {
1150
- start: /^__|\*\*/,
1151
- middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
1152
- endAst: /\*\*(?!\*)/g,
1153
- endUnd: /__(?!_)/g
1154
- },
1155
- em: {
1156
- start: /^_|\*/,
1157
- middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
1158
- endAst: /\*(?!\*)/g,
1159
- endUnd: /_(?!_)/g
1160
- },
1142
+ const inlinePedantic = {
1143
+ ...inlineNormal,
1161
1144
  link: edit(/^!?\[(label)\]\((.*?)\)/)
1162
- .replace('label', inline._label)
1145
+ .replace('label', _inlineLabel)
1163
1146
  .getRegex(),
1164
1147
  reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
1165
- .replace('label', inline._label)
1148
+ .replace('label', _inlineLabel)
1166
1149
  .getRegex()
1167
1150
  };
1168
1151
  /**
1169
1152
  * GFM Inline Grammar
1170
1153
  */
1171
- inline.gfm = {
1172
- ...inline.normal,
1173
- escape: edit(inline.escape).replace('])', '~|])').getRegex(),
1174
- _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
1175
- url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
1154
+ const inlineGfm = {
1155
+ ...inlineNormal,
1156
+ escape: edit(escape).replace('])', '~|])').getRegex(),
1157
+ url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i')
1158
+ .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)
1159
+ .getRegex(),
1176
1160
  _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
1177
1161
  del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
1178
1162
  text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
1179
1163
  };
1180
- inline.gfm.url = edit(inline.gfm.url, 'i')
1181
- .replace('email', inline.gfm._extended_email)
1182
- .getRegex();
1183
1164
  /**
1184
1165
  * GFM + Line Breaks Inline Grammar
1185
1166
  */
1186
- inline.breaks = {
1187
- ...inline.gfm,
1188
- br: edit(inline.br).replace('{2,}', '*').getRegex(),
1189
- text: edit(inline.gfm.text)
1167
+ const inlineBreaks = {
1168
+ ...inlineGfm,
1169
+ br: edit(br).replace('{2,}', '*').getRegex(),
1170
+ text: edit(inlineGfm.text)
1190
1171
  .replace('\\b_', '\\b_| {2,}\\n')
1191
1172
  .replace(/\{2,\}/g, '*')
1192
1173
  .getRegex()
1193
1174
  };
1175
+ /**
1176
+ * exports
1177
+ */
1178
+ const block = {
1179
+ normal: blockNormal,
1180
+ gfm: blockGfm,
1181
+ pedantic: blockPedantic
1182
+ };
1183
+ const inline = {
1184
+ normal: inlineNormal,
1185
+ gfm: inlineGfm,
1186
+ breaks: inlineBreaks,
1187
+ pedantic: inlinePedantic
1188
+ };
1194
1189
 
1195
1190
  /**
1196
1191
  * Block Lexer
@@ -1203,7 +1198,6 @@ class _Lexer {
1203
1198
  inlineQueue;
1204
1199
  constructor(options) {
1205
1200
  // TokenList cannot be created in one go
1206
- // @ts-expect-error
1207
1201
  this.tokens = [];
1208
1202
  this.tokens.links = Object.create(null);
1209
1203
  this.options = options || _defaults;
@@ -1637,13 +1631,13 @@ class _Renderer {
1637
1631
  code = code.replace(/\n$/, '') + '\n';
1638
1632
  if (!lang) {
1639
1633
  return '<pre><code>'
1640
- + (escaped ? code : escape(code, true))
1634
+ + (escaped ? code : escape$1(code, true))
1641
1635
  + '</code></pre>\n';
1642
1636
  }
1643
1637
  return '<pre><code class="language-'
1644
- + escape(lang)
1638
+ + escape$1(lang)
1645
1639
  + '">'
1646
- + (escaped ? code : escape(code, true))
1640
+ + (escaped ? code : escape$1(code, true))
1647
1641
  + '</code></pre>\n';
1648
1642
  }
1649
1643
  blockquote(quote) {
@@ -2167,11 +2161,14 @@ class Marked {
2167
2161
  if (pack.renderer) {
2168
2162
  const renderer = this.defaults.renderer || new _Renderer(this.defaults);
2169
2163
  for (const prop in pack.renderer) {
2170
- const rendererFunc = pack.renderer[prop];
2171
- const rendererKey = prop;
2172
- const prevRenderer = renderer[rendererKey];
2164
+ if (!(prop in renderer) || prop === 'options') {
2165
+ throw new Error(`renderer '${prop}' does not exist`);
2166
+ }
2167
+ const rendererProp = prop;
2168
+ const rendererFunc = pack.renderer[rendererProp];
2169
+ const prevRenderer = renderer[rendererProp];
2173
2170
  // Replace renderer with func to run extension, but fall back if false
2174
- renderer[rendererKey] = (...args) => {
2171
+ renderer[rendererProp] = (...args) => {
2175
2172
  let ret = rendererFunc.apply(renderer, args);
2176
2173
  if (ret === false) {
2177
2174
  ret = prevRenderer.apply(renderer, args);
@@ -2184,11 +2181,15 @@ class Marked {
2184
2181
  if (pack.tokenizer) {
2185
2182
  const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
2186
2183
  for (const prop in pack.tokenizer) {
2187
- const tokenizerFunc = pack.tokenizer[prop];
2188
- const tokenizerKey = prop;
2189
- const prevTokenizer = tokenizer[tokenizerKey];
2184
+ if (!(prop in tokenizer) || ['options', 'rules', 'lexer'].includes(prop)) {
2185
+ throw new Error(`tokenizer '${prop}' does not exist`);
2186
+ }
2187
+ const tokenizerProp = prop;
2188
+ const tokenizerFunc = pack.tokenizer[tokenizerProp];
2189
+ const prevTokenizer = tokenizer[tokenizerProp];
2190
2190
  // Replace tokenizer with func to run extension, but fall back if false
2191
- tokenizer[tokenizerKey] = (...args) => {
2191
+ // @ts-expect-error cannot type tokenizer function dynamically
2192
+ tokenizer[tokenizerProp] = (...args) => {
2192
2193
  let ret = tokenizerFunc.apply(tokenizer, args);
2193
2194
  if (ret === false) {
2194
2195
  ret = prevTokenizer.apply(tokenizer, args);
@@ -2202,11 +2203,14 @@ class Marked {
2202
2203
  if (pack.hooks) {
2203
2204
  const hooks = this.defaults.hooks || new _Hooks();
2204
2205
  for (const prop in pack.hooks) {
2205
- const hooksFunc = pack.hooks[prop];
2206
- const hooksKey = prop;
2207
- const prevHook = hooks[hooksKey];
2206
+ if (!(prop in hooks) || prop === 'options') {
2207
+ throw new Error(`hook '${prop}' does not exist`);
2208
+ }
2209
+ const hooksProp = prop;
2210
+ const hooksFunc = pack.hooks[hooksProp];
2211
+ const prevHook = hooks[hooksProp];
2208
2212
  if (_Hooks.passThroughHooks.has(prop)) {
2209
- hooks[hooksKey] = (arg) => {
2213
+ hooks[hooksProp] = (arg) => {
2210
2214
  if (this.defaults.async) {
2211
2215
  return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {
2212
2216
  return prevHook.call(hooks, ret);
@@ -2217,7 +2221,7 @@ class Marked {
2217
2221
  };
2218
2222
  }
2219
2223
  else {
2220
- hooks[hooksKey] = (...args) => {
2224
+ hooks[hooksProp] = (...args) => {
2221
2225
  let ret = hooksFunc.apply(hooks, args);
2222
2226
  if (ret === false) {
2223
2227
  ret = prevHook.apply(hooks, args);
@@ -2310,7 +2314,7 @@ class Marked {
2310
2314
  e.message += '\nPlease report this to https://github.com/markedjs/marked.';
2311
2315
  if (silent) {
2312
2316
  const msg = '<p>An error occurred:</p><pre>'
2313
- + escape(e.message + '', true)
2317
+ + escape$1(e.message + '', true)
2314
2318
  + '</pre>';
2315
2319
  if (async) {
2316
2320
  return Promise.resolve(msg);