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