marked 14.1.3 → 15.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.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * marked v14.1.3 - a markdown parser
2
+ * marked v15.0.0 - a markdown parser
3
3
  * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)
4
4
  * https://github.com/markedjs/marked
5
5
  */
@@ -37,42 +37,13 @@
37
37
  exports.defaults = newDefaults;
38
38
  }
39
39
 
40
- /**
41
- * Helpers
42
- */
43
- const escapeTest = /[&<>"']/;
44
- const escapeReplace = new RegExp(escapeTest.source, 'g');
45
- const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
46
- const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
47
- const escapeReplacements = {
48
- '&': '&amp;',
49
- '<': '&lt;',
50
- '>': '&gt;',
51
- '"': '&quot;',
52
- "'": '&#39;',
53
- };
54
- const getEscapeReplacement = (ch) => escapeReplacements[ch];
55
- function escape$1(html, encode) {
56
- if (encode) {
57
- if (escapeTest.test(html)) {
58
- return html.replace(escapeReplace, getEscapeReplacement);
59
- }
60
- }
61
- else {
62
- if (escapeTestNoEncode.test(html)) {
63
- return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
64
- }
65
- }
66
- return html;
67
- }
68
- const caret = /(^|[^\[])\^/g;
69
- function edit(regex, opt) {
40
+ const noopTest = { exec: () => null };
41
+ function edit(regex, opt = '') {
70
42
  let source = typeof regex === 'string' ? regex : regex.source;
71
- opt = opt || '';
72
43
  const obj = {
73
44
  replace: (name, val) => {
74
45
  let valSource = typeof val === 'string' ? val : val.source;
75
- valSource = valSource.replace(caret, '$1');
46
+ valSource = valSource.replace(other.caret, '$1');
76
47
  source = source.replace(name, valSource);
77
48
  return obj;
78
49
  },
@@ -82,230 +53,596 @@
82
53
  };
83
54
  return obj;
84
55
  }
85
- function cleanUrl(href) {
86
- try {
87
- href = encodeURI(href).replace(/%25/g, '%');
88
- }
89
- catch {
90
- return null;
91
- }
92
- return href;
93
- }
94
- const noopTest = { exec: () => null };
95
- function splitCells(tableRow, count) {
96
- // ensure that every cell-delimiting pipe has a space
97
- // before it to distinguish it from an escaped pipe
98
- const row = tableRow.replace(/\|/g, (match, offset, str) => {
99
- let escaped = false;
100
- let curr = offset;
101
- while (--curr >= 0 && str[curr] === '\\')
102
- escaped = !escaped;
103
- if (escaped) {
104
- // odd number of slashes means | is escaped
105
- // so we leave it alone
106
- return '|';
107
- }
108
- else {
109
- // add space before unescaped |
110
- return ' |';
111
- }
112
- }), cells = row.split(/ \|/);
113
- let i = 0;
114
- // First/last cell in a row cannot be empty if it has no leading/trailing pipe
115
- if (!cells[0].trim()) {
116
- cells.shift();
117
- }
118
- if (cells.length > 0 && !cells[cells.length - 1].trim()) {
119
- cells.pop();
120
- }
121
- if (count) {
122
- if (cells.length > count) {
123
- cells.splice(count);
124
- }
125
- else {
126
- while (cells.length < count)
127
- cells.push('');
128
- }
129
- }
130
- for (; i < cells.length; i++) {
131
- // leading or trailing whitespace is ignored per the gfm spec
132
- cells[i] = cells[i].trim().replace(/\\\|/g, '|');
133
- }
134
- return cells;
135
- }
56
+ const other = {
57
+ codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm,
58
+ outputLinkReplace: /\\([\[\]])/g,
59
+ indentCodeCompensation: /^(\s+)(?:```)/,
60
+ beginningSpace: /^\s+/,
61
+ endingHash: /#$/,
62
+ startingSpaceChar: /^ /,
63
+ endingSpaceChar: / $/,
64
+ nonSpaceChar: /[^ ]/,
65
+ newLineCharGlobal: /\n/g,
66
+ tabCharGlobal: /\t/g,
67
+ multipleSpaceGlobal: /\s+/g,
68
+ blankLine: /^[ \t]*$/,
69
+ doubleBlankLine: /\n[ \t]*\n[ \t]*$/,
70
+ blockquoteStart: /^ {0,3}>/,
71
+ blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g,
72
+ blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm,
73
+ listReplaceTabs: /^\t+/,
74
+ listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g,
75
+ listIsTask: /^\[[ xX]\] /,
76
+ listReplaceTask: /^\[[ xX]\] +/,
77
+ anyLine: /\n.*\n/,
78
+ hrefBrackets: /^<(.*)>$/,
79
+ tableDelimiter: /[:|]/,
80
+ tableAlignChars: /^\||\| *$/g,
81
+ tableRowBlankLine: /\n[ \t]*$/,
82
+ tableAlignRight: /^ *-+: *$/,
83
+ tableAlignCenter: /^ *:-+: *$/,
84
+ tableAlignLeft: /^ *:-+ *$/,
85
+ startATag: /^<a /i,
86
+ endATag: /^<\/a>/i,
87
+ startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i,
88
+ endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i,
89
+ startAngleBracket: /^</,
90
+ endAngleBracket: />$/,
91
+ pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/,
92
+ unicodeAlphaNumeric: /[\p{L}\p{N}]/u,
93
+ escapeTest: /[&<>"']/,
94
+ escapeReplace: /[&<>"']/g,
95
+ escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,
96
+ escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,
97
+ unescapeTest: /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,
98
+ caret: /(^|[^\[])\^/g,
99
+ percentDecode: /%25/g,
100
+ findPipe: /\|/g,
101
+ splitPipe: / \|/,
102
+ slashPipe: /\\\|/g,
103
+ carriageReturn: /\r\n|\r/g,
104
+ spaceLine: /^ +$/gm,
105
+ notSpaceStart: /^\S*/,
106
+ endingNewline: /\n$/,
107
+ listItemRegex: (bull) => new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`),
108
+ nextBulletRegex: (indent) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),
109
+ hrRegex: (indent) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),
110
+ fencesBeginRegex: (indent) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`),
111
+ headingBeginRegex: (indent) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`),
112
+ htmlBeginRegex: (indent) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}<(?:[a-z].*>|!--)`, 'i'),
113
+ };
136
114
  /**
137
- * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
138
- * /c*$/ is vulnerable to REDOS.
139
- *
140
- * @param str
141
- * @param c
142
- * @param invert Remove suffix of non-c chars instead. Default falsey.
115
+ * Block-Level Grammar
143
116
  */
144
- function rtrim(str, c, invert) {
145
- const l = str.length;
146
- if (l === 0) {
147
- return '';
148
- }
149
- // Length of suffix matching the invert condition.
150
- let suffLen = 0;
151
- // Step left until we fail to match the invert condition.
152
- while (suffLen < l) {
153
- const currChar = str.charAt(l - suffLen - 1);
154
- if (currChar === c && !invert) {
155
- suffLen++;
156
- }
157
- else if (currChar !== c && invert) {
158
- suffLen++;
159
- }
160
- else {
161
- break;
162
- }
163
- }
164
- return str.slice(0, l - suffLen);
165
- }
166
- function findClosingBracket(str, b) {
167
- if (str.indexOf(b[1]) === -1) {
168
- return -1;
169
- }
170
- let level = 0;
171
- for (let i = 0; i < str.length; i++) {
172
- if (str[i] === '\\') {
173
- i++;
174
- }
175
- else if (str[i] === b[0]) {
176
- level++;
177
- }
178
- else if (str[i] === b[1]) {
179
- level--;
180
- if (level < 0) {
181
- return i;
182
- }
183
- }
184
- }
185
- return -1;
186
- }
187
-
188
- function outputLink(cap, link, raw, lexer) {
189
- const href = link.href;
190
- const title = link.title ? escape$1(link.title) : null;
191
- const text = cap[1].replace(/\\([\[\]])/g, '$1');
192
- if (cap[0].charAt(0) !== '!') {
193
- lexer.state.inLink = true;
194
- const token = {
195
- type: 'link',
196
- raw,
197
- href,
198
- title,
199
- text,
200
- tokens: lexer.inlineTokens(text),
201
- };
202
- lexer.state.inLink = false;
203
- return token;
204
- }
205
- return {
206
- type: 'image',
207
- raw,
208
- href,
209
- title,
210
- text: escape$1(text),
211
- };
212
- }
213
- function indentCodeCompensation(raw, text) {
214
- const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
215
- if (matchIndentToCode === null) {
216
- return text;
217
- }
218
- const indentToCode = matchIndentToCode[1];
219
- return text
220
- .split('\n')
221
- .map(node => {
222
- const matchIndentInNode = node.match(/^\s+/);
223
- if (matchIndentInNode === null) {
224
- return node;
225
- }
226
- const [indentInNode] = matchIndentInNode;
227
- if (indentInNode.length >= indentToCode.length) {
228
- return node.slice(indentToCode.length);
229
- }
230
- return node;
231
- })
232
- .join('\n');
233
- }
117
+ const newline = /^(?:[ \t]*(?:\n|$))+/;
118
+ const blockCode = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
119
+ const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
120
+ const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
121
+ const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
122
+ const bullet = /(?:[*+-]|\d{1,9}[.)])/;
123
+ const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/)
124
+ .replace(/bull/g, bullet) // lists can interrupt
125
+ .replace(/blockCode/g, /(?: {4}| {0,3}\t)/) // indented code blocks can interrupt
126
+ .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt
127
+ .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt
128
+ .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt
129
+ .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt
130
+ .getRegex();
131
+ const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
132
+ const blockText = /^[^\n]+/;
133
+ const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
134
+ const def = edit(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/)
135
+ .replace('label', _blockLabel)
136
+ .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/)
137
+ .getRegex();
138
+ const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
139
+ .replace(/bull/g, bullet)
140
+ .getRegex();
141
+ const _tag = 'address|article|aside|base|basefont|blockquote|body|caption'
142
+ + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
143
+ + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
144
+ + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
145
+ + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'
146
+ + '|tr|track|ul';
147
+ const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
148
+ const html = edit('^ {0,3}(?:' // optional indentation
149
+ + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
150
+ + '|comment[^\\n]*(\\n+|$)' // (2)
151
+ + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
152
+ + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
153
+ + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
154
+ + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (6)
155
+ + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) open tag
156
+ + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) closing tag
157
+ + ')', 'i')
158
+ .replace('comment', _comment)
159
+ .replace('tag', _tag)
160
+ .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
161
+ .getRegex();
162
+ const paragraph = edit(_paragraph)
163
+ .replace('hr', hr)
164
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
165
+ .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
166
+ .replace('|table', '')
167
+ .replace('blockquote', ' {0,3}>')
168
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
169
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
170
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
171
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
172
+ .getRegex();
173
+ const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/)
174
+ .replace('paragraph', paragraph)
175
+ .getRegex();
234
176
  /**
235
- * Tokenizer
177
+ * Normal Block Grammar
236
178
  */
237
- class _Tokenizer {
238
- options;
239
- rules; // set by the lexer
240
- lexer; // set by the lexer
241
- constructor(options) {
242
- this.options = options || exports.defaults;
243
- }
244
- space(src) {
245
- const cap = this.rules.block.newline.exec(src);
246
- if (cap && cap[0].length > 0) {
247
- return {
248
- type: 'space',
249
- raw: cap[0],
250
- };
251
- }
252
- }
253
- code(src) {
254
- const cap = this.rules.block.code.exec(src);
255
- if (cap) {
256
- const text = cap[0].replace(/^(?: {1,4}| {0,3}\t)/gm, '');
257
- return {
258
- type: 'code',
259
- raw: cap[0],
260
- codeBlockStyle: 'indented',
261
- text: !this.options.pedantic
262
- ? rtrim(text, '\n')
263
- : text,
264
- };
265
- }
266
- }
267
- fences(src) {
268
- const cap = this.rules.block.fences.exec(src);
269
- if (cap) {
270
- const raw = cap[0];
271
- const text = indentCodeCompensation(raw, cap[3] || '');
272
- return {
273
- type: 'code',
274
- raw,
275
- lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],
276
- text,
277
- };
179
+ const blockNormal = {
180
+ blockquote,
181
+ code: blockCode,
182
+ def,
183
+ fences,
184
+ heading,
185
+ hr,
186
+ html,
187
+ lheading,
188
+ list,
189
+ newline,
190
+ paragraph,
191
+ table: noopTest,
192
+ text: blockText,
193
+ };
194
+ /**
195
+ * GFM Block Grammar
196
+ */
197
+ const gfmTable = edit('^ *([^\\n ].*)\\n' // Header
198
+ + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
199
+ + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells
200
+ .replace('hr', hr)
201
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
202
+ .replace('blockquote', ' {0,3}>')
203
+ .replace('code', '(?: {4}| {0,3}\t)[^\\n]')
204
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
205
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
206
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
207
+ .replace('tag', _tag) // tables can be interrupted by type (6) html blocks
208
+ .getRegex();
209
+ const blockGfm = {
210
+ ...blockNormal,
211
+ table: gfmTable,
212
+ paragraph: edit(_paragraph)
213
+ .replace('hr', hr)
214
+ .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
215
+ .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
216
+ .replace('table', gfmTable) // interrupt paragraphs with table
217
+ .replace('blockquote', ' {0,3}>')
218
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
219
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
220
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
221
+ .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
222
+ .getRegex(),
223
+ };
224
+ /**
225
+ * Pedantic grammar (original John Gruber's loose markdown specification)
226
+ */
227
+ const blockPedantic = {
228
+ ...blockNormal,
229
+ html: edit('^ *(?:comment *(?:\\n|\\s*$)'
230
+ + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
231
+ + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
232
+ .replace('comment', _comment)
233
+ .replace(/tag/g, '(?!(?:'
234
+ + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
235
+ + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
236
+ + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
237
+ .getRegex(),
238
+ def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
239
+ heading: /^(#{1,6})(.*)(?:\n+|$)/,
240
+ fences: noopTest, // fences not supported
241
+ lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
242
+ paragraph: edit(_paragraph)
243
+ .replace('hr', hr)
244
+ .replace('heading', ' *#{1,6} *[^\n]')
245
+ .replace('lheading', lheading)
246
+ .replace('|table', '')
247
+ .replace('blockquote', ' {0,3}>')
248
+ .replace('|fences', '')
249
+ .replace('|list', '')
250
+ .replace('|html', '')
251
+ .replace('|tag', '')
252
+ .getRegex(),
253
+ };
254
+ /**
255
+ * Inline-Level Grammar
256
+ */
257
+ const escape$1 = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
258
+ const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
259
+ const br = /^( {2,}|\\)\n(?!\s*$)/;
260
+ const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
261
+ // list of unicode punctuation marks, plus any missing characters from CommonMark spec
262
+ const _punctuation = '\\p{P}\\p{S}';
263
+ const punctuation = edit(/^((?![*_])[\spunctuation])/, 'u')
264
+ .replace(/punctuation/g, _punctuation).getRegex();
265
+ // sequences em should skip over [title](link), `code`, <html>
266
+ const blockSkip = /\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g;
267
+ const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u')
268
+ .replace(/punct/g, _punctuation)
269
+ .getRegex();
270
+ const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong
271
+ + '|[^*]+(?=[^*])' // Consume to delim
272
+ + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter
273
+ + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter
274
+ + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter
275
+ + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter
276
+ + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter
277
+ + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter
278
+ .replace(/punct/g, _punctuation)
279
+ .getRegex();
280
+ // (6) Not allowed for _
281
+ const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong
282
+ + '|[^_]+(?=[^_])' // Consume to delim
283
+ + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter
284
+ + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter
285
+ + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter
286
+ + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter
287
+ + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter
288
+ .replace(/punct/g, _punctuation)
289
+ .getRegex();
290
+ const anyPunctuation = edit(/\\([punct])/, 'gu')
291
+ .replace(/punct/g, _punctuation)
292
+ .getRegex();
293
+ const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/)
294
+ .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)
295
+ .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])?)+(?![-_])/)
296
+ .getRegex();
297
+ const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();
298
+ const tag = edit('^comment'
299
+ + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
300
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
301
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
302
+ + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
303
+ + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>') // CDATA section
304
+ .replace('comment', _inlineComment)
305
+ .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/)
306
+ .getRegex();
307
+ const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
308
+ const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/)
309
+ .replace('label', _inlineLabel)
310
+ .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/)
311
+ .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/)
312
+ .getRegex();
313
+ const reflink = edit(/^!?\[(label)\]\[(ref)\]/)
314
+ .replace('label', _inlineLabel)
315
+ .replace('ref', _blockLabel)
316
+ .getRegex();
317
+ const nolink = edit(/^!?\[(ref)\](?:\[\])?/)
318
+ .replace('ref', _blockLabel)
319
+ .getRegex();
320
+ const reflinkSearch = edit('reflink|nolink(?!\\()', 'g')
321
+ .replace('reflink', reflink)
322
+ .replace('nolink', nolink)
323
+ .getRegex();
324
+ /**
325
+ * Normal Inline Grammar
326
+ */
327
+ const inlineNormal = {
328
+ _backpedal: noopTest, // only used for GFM url
329
+ anyPunctuation,
330
+ autolink,
331
+ blockSkip,
332
+ br,
333
+ code: inlineCode,
334
+ del: noopTest,
335
+ emStrongLDelim,
336
+ emStrongRDelimAst,
337
+ emStrongRDelimUnd,
338
+ escape: escape$1,
339
+ link,
340
+ nolink,
341
+ punctuation,
342
+ reflink,
343
+ reflinkSearch,
344
+ tag,
345
+ text: inlineText,
346
+ url: noopTest,
347
+ };
348
+ /**
349
+ * Pedantic Inline Grammar
350
+ */
351
+ const inlinePedantic = {
352
+ ...inlineNormal,
353
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
354
+ .replace('label', _inlineLabel)
355
+ .getRegex(),
356
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
357
+ .replace('label', _inlineLabel)
358
+ .getRegex(),
359
+ };
360
+ /**
361
+ * GFM Inline Grammar
362
+ */
363
+ const inlineGfm = {
364
+ ...inlineNormal,
365
+ escape: edit(escape$1).replace('])', '~|])').getRegex(),
366
+ url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i')
367
+ .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)
368
+ .getRegex(),
369
+ _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
370
+ del: /^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,
371
+ text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/,
372
+ };
373
+ /**
374
+ * GFM + Line Breaks Inline Grammar
375
+ */
376
+ const inlineBreaks = {
377
+ ...inlineGfm,
378
+ br: edit(br).replace('{2,}', '*').getRegex(),
379
+ text: edit(inlineGfm.text)
380
+ .replace('\\b_', '\\b_| {2,}\\n')
381
+ .replace(/\{2,\}/g, '*')
382
+ .getRegex(),
383
+ };
384
+ /**
385
+ * exports
386
+ */
387
+ const block = {
388
+ normal: blockNormal,
389
+ gfm: blockGfm,
390
+ pedantic: blockPedantic,
391
+ };
392
+ const inline = {
393
+ normal: inlineNormal,
394
+ gfm: inlineGfm,
395
+ breaks: inlineBreaks,
396
+ pedantic: inlinePedantic,
397
+ };
398
+
399
+ /**
400
+ * Helpers
401
+ */
402
+ const escapeReplacements = {
403
+ '&': '&amp;',
404
+ '<': '&lt;',
405
+ '>': '&gt;',
406
+ '"': '&quot;',
407
+ "'": '&#39;',
408
+ };
409
+ const getEscapeReplacement = (ch) => escapeReplacements[ch];
410
+ function escape(html, encode) {
411
+ if (encode) {
412
+ if (other.escapeTest.test(html)) {
413
+ return html.replace(other.escapeReplace, getEscapeReplacement);
278
414
  }
279
415
  }
280
- heading(src) {
281
- const cap = this.rules.block.heading.exec(src);
282
- if (cap) {
283
- let text = cap[2].trim();
284
- // remove trailing #s
285
- if (/#$/.test(text)) {
286
- const trimmed = rtrim(text, '#');
287
- if (this.options.pedantic) {
288
- text = trimmed.trim();
289
- }
290
- else if (!trimmed || / $/.test(trimmed)) {
291
- // CommonMark requires space before trailing #s
292
- text = trimmed.trim();
293
- }
294
- }
295
- return {
296
- type: 'heading',
297
- raw: cap[0],
298
- depth: cap[1].length,
299
- text,
300
- tokens: this.lexer.inline(text),
301
- };
416
+ else {
417
+ if (other.escapeTestNoEncode.test(html)) {
418
+ return html.replace(other.escapeReplaceNoEncode, getEscapeReplacement);
302
419
  }
303
420
  }
304
- hr(src) {
305
- const cap = this.rules.block.hr.exec(src);
306
- if (cap) {
307
- return {
308
- type: 'hr',
421
+ return html;
422
+ }
423
+ function cleanUrl(href) {
424
+ try {
425
+ href = encodeURI(href).replace(other.percentDecode, '%');
426
+ }
427
+ catch {
428
+ return null;
429
+ }
430
+ return href;
431
+ }
432
+ function splitCells(tableRow, count) {
433
+ // ensure that every cell-delimiting pipe has a space
434
+ // before it to distinguish it from an escaped pipe
435
+ const row = tableRow.replace(other.findPipe, (match, offset, str) => {
436
+ let escaped = false;
437
+ let curr = offset;
438
+ while (--curr >= 0 && str[curr] === '\\')
439
+ escaped = !escaped;
440
+ if (escaped) {
441
+ // odd number of slashes means | is escaped
442
+ // so we leave it alone
443
+ return '|';
444
+ }
445
+ else {
446
+ // add space before unescaped |
447
+ return ' |';
448
+ }
449
+ }), cells = row.split(other.splitPipe);
450
+ let i = 0;
451
+ // First/last cell in a row cannot be empty if it has no leading/trailing pipe
452
+ if (!cells[0].trim()) {
453
+ cells.shift();
454
+ }
455
+ if (cells.length > 0 && !cells[cells.length - 1].trim()) {
456
+ cells.pop();
457
+ }
458
+ if (count) {
459
+ if (cells.length > count) {
460
+ cells.splice(count);
461
+ }
462
+ else {
463
+ while (cells.length < count)
464
+ cells.push('');
465
+ }
466
+ }
467
+ for (; i < cells.length; i++) {
468
+ // leading or trailing whitespace is ignored per the gfm spec
469
+ cells[i] = cells[i].trim().replace(other.slashPipe, '|');
470
+ }
471
+ return cells;
472
+ }
473
+ /**
474
+ * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
475
+ * /c*$/ is vulnerable to REDOS.
476
+ *
477
+ * @param str
478
+ * @param c
479
+ * @param invert Remove suffix of non-c chars instead. Default falsey.
480
+ */
481
+ function rtrim(str, c, invert) {
482
+ const l = str.length;
483
+ if (l === 0) {
484
+ return '';
485
+ }
486
+ // Length of suffix matching the invert condition.
487
+ let suffLen = 0;
488
+ // Step left until we fail to match the invert condition.
489
+ while (suffLen < l) {
490
+ const currChar = str.charAt(l - suffLen - 1);
491
+ if (currChar === c && !invert) {
492
+ suffLen++;
493
+ }
494
+ else if (currChar !== c && invert) {
495
+ suffLen++;
496
+ }
497
+ else {
498
+ break;
499
+ }
500
+ }
501
+ return str.slice(0, l - suffLen);
502
+ }
503
+ function findClosingBracket(str, b) {
504
+ if (str.indexOf(b[1]) === -1) {
505
+ return -1;
506
+ }
507
+ let level = 0;
508
+ for (let i = 0; i < str.length; i++) {
509
+ if (str[i] === '\\') {
510
+ i++;
511
+ }
512
+ else if (str[i] === b[0]) {
513
+ level++;
514
+ }
515
+ else if (str[i] === b[1]) {
516
+ level--;
517
+ if (level < 0) {
518
+ return i;
519
+ }
520
+ }
521
+ }
522
+ return -1;
523
+ }
524
+
525
+ function outputLink(cap, link, raw, lexer, rules) {
526
+ const href = link.href;
527
+ const title = link.title || null;
528
+ const text = cap[1].replace(rules.other.outputLinkReplace, '$1');
529
+ if (cap[0].charAt(0) !== '!') {
530
+ lexer.state.inLink = true;
531
+ const token = {
532
+ type: 'link',
533
+ raw,
534
+ href,
535
+ title,
536
+ text,
537
+ tokens: lexer.inlineTokens(text),
538
+ };
539
+ lexer.state.inLink = false;
540
+ return token;
541
+ }
542
+ return {
543
+ type: 'image',
544
+ raw,
545
+ href,
546
+ title,
547
+ text,
548
+ };
549
+ }
550
+ function indentCodeCompensation(raw, text, rules) {
551
+ const matchIndentToCode = raw.match(rules.other.indentCodeCompensation);
552
+ if (matchIndentToCode === null) {
553
+ return text;
554
+ }
555
+ const indentToCode = matchIndentToCode[1];
556
+ return text
557
+ .split('\n')
558
+ .map(node => {
559
+ const matchIndentInNode = node.match(rules.other.beginningSpace);
560
+ if (matchIndentInNode === null) {
561
+ return node;
562
+ }
563
+ const [indentInNode] = matchIndentInNode;
564
+ if (indentInNode.length >= indentToCode.length) {
565
+ return node.slice(indentToCode.length);
566
+ }
567
+ return node;
568
+ })
569
+ .join('\n');
570
+ }
571
+ /**
572
+ * Tokenizer
573
+ */
574
+ class _Tokenizer {
575
+ options;
576
+ rules; // set by the lexer
577
+ lexer; // set by the lexer
578
+ constructor(options) {
579
+ this.options = options || exports.defaults;
580
+ }
581
+ space(src) {
582
+ const cap = this.rules.block.newline.exec(src);
583
+ if (cap && cap[0].length > 0) {
584
+ return {
585
+ type: 'space',
586
+ raw: cap[0],
587
+ };
588
+ }
589
+ }
590
+ code(src) {
591
+ const cap = this.rules.block.code.exec(src);
592
+ if (cap) {
593
+ const text = cap[0].replace(this.rules.other.codeRemoveIndent, '');
594
+ return {
595
+ type: 'code',
596
+ raw: cap[0],
597
+ codeBlockStyle: 'indented',
598
+ text: !this.options.pedantic
599
+ ? rtrim(text, '\n')
600
+ : text,
601
+ };
602
+ }
603
+ }
604
+ fences(src) {
605
+ const cap = this.rules.block.fences.exec(src);
606
+ if (cap) {
607
+ const raw = cap[0];
608
+ const text = indentCodeCompensation(raw, cap[3] || '', this.rules);
609
+ return {
610
+ type: 'code',
611
+ raw,
612
+ lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],
613
+ text,
614
+ };
615
+ }
616
+ }
617
+ heading(src) {
618
+ const cap = this.rules.block.heading.exec(src);
619
+ if (cap) {
620
+ let text = cap[2].trim();
621
+ // remove trailing #s
622
+ if (this.rules.other.endingHash.test(text)) {
623
+ const trimmed = rtrim(text, '#');
624
+ if (this.options.pedantic) {
625
+ text = trimmed.trim();
626
+ }
627
+ else if (!trimmed || this.rules.other.endingSpaceChar.test(trimmed)) {
628
+ // CommonMark requires space before trailing #s
629
+ text = trimmed.trim();
630
+ }
631
+ }
632
+ return {
633
+ type: 'heading',
634
+ raw: cap[0],
635
+ depth: cap[1].length,
636
+ text,
637
+ tokens: this.lexer.inline(text),
638
+ };
639
+ }
640
+ }
641
+ hr(src) {
642
+ const cap = this.rules.block.hr.exec(src);
643
+ if (cap) {
644
+ return {
645
+ type: 'hr',
309
646
  raw: rtrim(cap[0], '\n'),
310
647
  };
311
648
  }
@@ -323,7 +660,7 @@
323
660
  let i;
324
661
  for (i = 0; i < lines.length; i++) {
325
662
  // get lines up to a continuation
326
- if (/^ {0,3}>/.test(lines[i])) {
663
+ if (this.rules.other.blockquoteStart.test(lines[i])) {
327
664
  currentLines.push(lines[i]);
328
665
  inBlockquote = true;
329
666
  }
@@ -338,8 +675,8 @@
338
675
  const currentRaw = currentLines.join('\n');
339
676
  const currentText = currentRaw
340
677
  // precede setext continuation with 4 spaces so it isn't a setext
341
- .replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, '\n $1')
342
- .replace(/^ {0,3}>[ \t]?/gm, '');
678
+ .replace(this.rules.other.blockquoteSetextReplace, '\n $1')
679
+ .replace(this.rules.other.blockquoteSetextReplace2, '');
343
680
  raw = raw ? `${raw}\n${currentRaw}` : currentRaw;
344
681
  text = text ? `${text}\n${currentText}` : currentText;
345
682
  // parse blockquote lines as top level tokens
@@ -405,7 +742,7 @@
405
742
  bull = isordered ? bull : '[*+-]';
406
743
  }
407
744
  // Get next list item
408
- const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
745
+ const itemRegex = this.rules.other.listItemRegex(bull);
409
746
  let endsWithBlankLine = false;
410
747
  // Check if current bullet point can start a new List Item
411
748
  while (src) {
@@ -420,7 +757,7 @@
420
757
  }
421
758
  raw = cap[0];
422
759
  src = src.substring(raw.length);
423
- let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length));
760
+ let line = cap[2].split('\n', 1)[0].replace(this.rules.other.listReplaceTabs, (t) => ' '.repeat(3 * t.length));
424
761
  let nextLine = src.split('\n', 1)[0];
425
762
  let blankLine = !line.trim();
426
763
  let indent = 0;
@@ -432,22 +769,22 @@
432
769
  indent = cap[1].length + 1;
433
770
  }
434
771
  else {
435
- indent = cap[2].search(/[^ ]/); // Find first non-space char
772
+ indent = cap[2].search(this.rules.other.nonSpaceChar); // Find first non-space char
436
773
  indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
437
774
  itemContents = line.slice(indent);
438
775
  indent += cap[1].length;
439
776
  }
440
- if (blankLine && /^[ \t]*$/.test(nextLine)) { // Items begin with at most one blank line
777
+ if (blankLine && this.rules.other.blankLine.test(nextLine)) { // Items begin with at most one blank line
441
778
  raw += nextLine + '\n';
442
779
  src = src.substring(nextLine.length + 1);
443
780
  endEarly = true;
444
781
  }
445
782
  if (!endEarly) {
446
- const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`);
447
- const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
448
- const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
449
- const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
450
- const htmlBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}<[a-z].*>`, 'i');
783
+ const nextBulletRegex = this.rules.other.nextBulletRegex(indent);
784
+ const hrRegex = this.rules.other.hrRegex(indent);
785
+ const fencesBeginRegex = this.rules.other.fencesBeginRegex(indent);
786
+ const headingBeginRegex = this.rules.other.headingBeginRegex(indent);
787
+ const htmlBeginRegex = this.rules.other.htmlBeginRegex(indent);
451
788
  // Check if following lines should be included in List Item
452
789
  while (src) {
453
790
  const rawLine = src.split('\n', 1)[0];
@@ -455,11 +792,11 @@
455
792
  nextLine = rawLine;
456
793
  // Re-align to follow commonmark nesting rules
457
794
  if (this.options.pedantic) {
458
- nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
795
+ nextLine = nextLine.replace(this.rules.other.listReplaceNesting, ' ');
459
796
  nextLineWithoutTabs = nextLine;
460
797
  }
461
798
  else {
462
- nextLineWithoutTabs = nextLine.replace(/\t/g, ' ');
799
+ nextLineWithoutTabs = nextLine.replace(this.rules.other.tabCharGlobal, ' ');
463
800
  }
464
801
  // End list item if found code fences
465
802
  if (fencesBeginRegex.test(nextLine)) {
@@ -481,7 +818,7 @@
481
818
  if (hrRegex.test(nextLine)) {
482
819
  break;
483
820
  }
484
- if (nextLineWithoutTabs.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible
821
+ if (nextLineWithoutTabs.search(this.rules.other.nonSpaceChar) >= indent || !nextLine.trim()) { // Dedent if possible
485
822
  itemContents += '\n' + nextLineWithoutTabs.slice(indent);
486
823
  }
487
824
  else {
@@ -490,7 +827,7 @@
490
827
  break;
491
828
  }
492
829
  // paragraph continuation unless last line was a different block level element
493
- if (line.replace(/\t/g, ' ').search(/[^ ]/) >= 4) { // indented code block
830
+ if (line.replace(this.rules.other.tabCharGlobal, ' ').search(this.rules.other.nonSpaceChar) >= 4) { // indented code block
494
831
  break;
495
832
  }
496
833
  if (fencesBeginRegex.test(line)) {
@@ -517,7 +854,7 @@
517
854
  if (endsWithBlankLine) {
518
855
  list.loose = true;
519
856
  }
520
- else if (/\n[ \t]*\n[ \t]*$/.test(raw)) {
857
+ else if (this.rules.other.doubleBlankLine.test(raw)) {
521
858
  endsWithBlankLine = true;
522
859
  }
523
860
  }
@@ -525,10 +862,10 @@
525
862
  let ischecked;
526
863
  // Check for task list items
527
864
  if (this.options.gfm) {
528
- istask = /^\[[ xX]\] /.exec(itemContents);
865
+ istask = this.rules.other.listIsTask.exec(itemContents);
529
866
  if (istask) {
530
867
  ischecked = istask[0] !== '[ ] ';
531
- itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
868
+ itemContents = itemContents.replace(this.rules.other.listReplaceTask, '');
532
869
  }
533
870
  }
534
871
  list.items.push({
@@ -553,7 +890,7 @@
553
890
  if (!list.loose) {
554
891
  // Check if list should be loose
555
892
  const spacers = list.items[i].tokens.filter(t => t.type === 'space');
556
- const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw));
893
+ const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => this.rules.other.anyLine.test(t.raw));
557
894
  list.loose = hasMultipleLineBreaks;
558
895
  }
559
896
  }
@@ -582,8 +919,8 @@
582
919
  def(src) {
583
920
  const cap = this.rules.block.def.exec(src);
584
921
  if (cap) {
585
- const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
586
- const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';
922
+ const tag = cap[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, ' ');
923
+ const href = cap[2] ? cap[2].replace(this.rules.other.hrefBrackets, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';
587
924
  const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];
588
925
  return {
589
926
  type: 'def',
@@ -599,13 +936,13 @@
599
936
  if (!cap) {
600
937
  return;
601
938
  }
602
- if (!/[:|]/.test(cap[2])) {
939
+ if (!this.rules.other.tableDelimiter.test(cap[2])) {
603
940
  // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
604
941
  return;
605
942
  }
606
943
  const headers = splitCells(cap[1]);
607
- const aligns = cap[2].replace(/^\||\| *$/g, '').split('|');
608
- const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : [];
944
+ const aligns = cap[2].replace(this.rules.other.tableAlignChars, '').split('|');
945
+ const rows = cap[3] && cap[3].trim() ? cap[3].replace(this.rules.other.tableRowBlankLine, '').split('\n') : [];
609
946
  const item = {
610
947
  type: 'table',
611
948
  raw: cap[0],
@@ -618,13 +955,13 @@
618
955
  return;
619
956
  }
620
957
  for (const align of aligns) {
621
- if (/^ *-+: *$/.test(align)) {
958
+ if (this.rules.other.tableAlignRight.test(align)) {
622
959
  item.align.push('right');
623
960
  }
624
- else if (/^ *:-+: *$/.test(align)) {
961
+ else if (this.rules.other.tableAlignCenter.test(align)) {
625
962
  item.align.push('center');
626
963
  }
627
- else if (/^ *:-+ *$/.test(align)) {
964
+ else if (this.rules.other.tableAlignLeft.test(align)) {
628
965
  item.align.push('left');
629
966
  }
630
967
  else {
@@ -694,572 +1031,281 @@
694
1031
  return {
695
1032
  type: 'escape',
696
1033
  raw: cap[0],
697
- text: escape$1(cap[1]),
1034
+ text: cap[1],
698
1035
  };
699
1036
  }
700
1037
  }
701
1038
  tag(src) {
702
1039
  const cap = this.rules.inline.tag.exec(src);
703
1040
  if (cap) {
704
- if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
1041
+ if (!this.lexer.state.inLink && this.rules.other.startATag.test(cap[0])) {
705
1042
  this.lexer.state.inLink = true;
706
- }
707
- else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
708
- this.lexer.state.inLink = false;
709
- }
710
- if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
711
- this.lexer.state.inRawBlock = true;
712
- }
713
- else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
714
- this.lexer.state.inRawBlock = false;
715
- }
716
- return {
717
- type: 'html',
718
- raw: cap[0],
719
- inLink: this.lexer.state.inLink,
720
- inRawBlock: this.lexer.state.inRawBlock,
721
- block: false,
722
- text: cap[0],
723
- };
724
- }
725
- }
726
- link(src) {
727
- const cap = this.rules.inline.link.exec(src);
728
- if (cap) {
729
- const trimmedUrl = cap[2].trim();
730
- if (!this.options.pedantic && /^</.test(trimmedUrl)) {
731
- // commonmark requires matching angle brackets
732
- if (!(/>$/.test(trimmedUrl))) {
733
- return;
734
- }
735
- // ending angle bracket cannot be escaped
736
- const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
737
- if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
738
- return;
739
- }
740
- }
741
- else {
742
- // find closing parenthesis
743
- const lastParenIndex = findClosingBracket(cap[2], '()');
744
- if (lastParenIndex > -1) {
745
- const start = cap[0].indexOf('!') === 0 ? 5 : 4;
746
- const linkLen = start + cap[1].length + lastParenIndex;
747
- cap[2] = cap[2].substring(0, lastParenIndex);
748
- cap[0] = cap[0].substring(0, linkLen).trim();
749
- cap[3] = '';
750
- }
751
- }
752
- let href = cap[2];
753
- let title = '';
754
- if (this.options.pedantic) {
755
- // split pedantic href and title
756
- const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
757
- if (link) {
758
- href = link[1];
759
- title = link[3];
760
- }
761
- }
762
- else {
763
- title = cap[3] ? cap[3].slice(1, -1) : '';
764
- }
765
- href = href.trim();
766
- if (/^</.test(href)) {
767
- if (this.options.pedantic && !(/>$/.test(trimmedUrl))) {
768
- // pedantic allows starting angle bracket without ending angle bracket
769
- href = href.slice(1);
770
- }
771
- else {
772
- href = href.slice(1, -1);
773
- }
774
- }
775
- return outputLink(cap, {
776
- href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,
777
- title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title,
778
- }, cap[0], this.lexer);
779
- }
780
- }
781
- reflink(src, links) {
782
- let cap;
783
- if ((cap = this.rules.inline.reflink.exec(src))
784
- || (cap = this.rules.inline.nolink.exec(src))) {
785
- const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' ');
786
- const link = links[linkString.toLowerCase()];
787
- if (!link) {
788
- const text = cap[0].charAt(0);
789
- return {
790
- type: 'text',
791
- raw: text,
792
- text,
793
- };
794
- }
795
- return outputLink(cap, link, cap[0], this.lexer);
796
- }
797
- }
798
- emStrong(src, maskedSrc, prevChar = '') {
799
- let match = this.rules.inline.emStrongLDelim.exec(src);
800
- if (!match)
801
- return;
802
- // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
803
- if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
804
- return;
805
- const nextChar = match[1] || match[2] || '';
806
- if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
807
- // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
808
- const lLength = [...match[0]].length - 1;
809
- let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
810
- const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
811
- endReg.lastIndex = 0;
812
- // Clip maskedSrc to same section of string as src (move to lexer?)
813
- maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
814
- while ((match = endReg.exec(maskedSrc)) != null) {
815
- rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
816
- if (!rDelim)
817
- continue; // skip single * in __abc*abc__
818
- rLength = [...rDelim].length;
819
- if (match[3] || match[4]) { // found another Left Delim
820
- delimTotal += rLength;
821
- continue;
822
- }
823
- else if (match[5] || match[6]) { // either Left or Right Delim
824
- if (lLength % 3 && !((lLength + rLength) % 3)) {
825
- midDelimTotal += rLength;
826
- continue; // CommonMark Emphasis Rules 9-10
827
- }
828
- }
829
- delimTotal -= rLength;
830
- if (delimTotal > 0)
831
- continue; // Haven't found enough closing delimiters
832
- // Remove extra characters. *a*** -> *a*
833
- rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
834
- // char length can be >1 for unicode characters;
835
- const lastCharLength = [...match[0]][0].length;
836
- const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
837
- // Create `em` if smallest delimiter has odd char count. *a***
838
- if (Math.min(lLength, rLength) % 2) {
839
- const text = raw.slice(1, -1);
840
- return {
841
- type: 'em',
842
- raw,
843
- text,
844
- tokens: this.lexer.inlineTokens(text),
845
- };
846
- }
847
- // Create 'strong' if smallest delimiter has even char count. **a***
848
- const text = raw.slice(2, -2);
849
- return {
850
- type: 'strong',
851
- raw,
852
- text,
853
- tokens: this.lexer.inlineTokens(text),
854
- };
855
- }
856
- }
857
- }
858
- codespan(src) {
859
- const cap = this.rules.inline.code.exec(src);
860
- if (cap) {
861
- let text = cap[2].replace(/\n/g, ' ');
862
- const hasNonSpaceChars = /[^ ]/.test(text);
863
- const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
864
- if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
865
- text = text.substring(1, text.length - 1);
866
- }
867
- text = escape$1(text, true);
868
- return {
869
- type: 'codespan',
870
- raw: cap[0],
871
- text,
872
- };
873
- }
874
- }
875
- br(src) {
876
- const cap = this.rules.inline.br.exec(src);
877
- if (cap) {
878
- return {
879
- type: 'br',
880
- raw: cap[0],
881
- };
882
- }
883
- }
884
- del(src) {
885
- const cap = this.rules.inline.del.exec(src);
886
- if (cap) {
887
- return {
888
- type: 'del',
889
- raw: cap[0],
890
- text: cap[2],
891
- tokens: this.lexer.inlineTokens(cap[2]),
892
- };
893
- }
894
- }
895
- autolink(src) {
896
- const cap = this.rules.inline.autolink.exec(src);
897
- if (cap) {
898
- let text, href;
899
- if (cap[2] === '@') {
900
- text = escape$1(cap[1]);
901
- href = 'mailto:' + text;
902
- }
903
- else {
904
- text = escape$1(cap[1]);
905
- href = text;
906
- }
907
- return {
908
- type: 'link',
909
- raw: cap[0],
910
- text,
911
- href,
912
- tokens: [
913
- {
914
- type: 'text',
915
- raw: text,
916
- text,
917
- },
918
- ],
919
- };
920
- }
921
- }
922
- url(src) {
923
- let cap;
924
- if (cap = this.rules.inline.url.exec(src)) {
925
- let text, href;
926
- if (cap[2] === '@') {
927
- text = escape$1(cap[0]);
928
- href = 'mailto:' + text;
929
- }
930
- else {
931
- // do extended autolink path validation
932
- let prevCapZero;
933
- do {
934
- prevCapZero = cap[0];
935
- cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';
936
- } while (prevCapZero !== cap[0]);
937
- text = escape$1(cap[0]);
938
- if (cap[1] === 'www.') {
939
- href = 'http://' + cap[0];
940
- }
941
- else {
942
- href = cap[0];
943
- }
944
- }
945
- return {
946
- type: 'link',
947
- raw: cap[0],
948
- text,
949
- href,
950
- tokens: [
951
- {
952
- type: 'text',
953
- raw: text,
954
- text,
955
- },
956
- ],
957
- };
958
- }
959
- }
960
- inlineText(src) {
961
- const cap = this.rules.inline.text.exec(src);
962
- if (cap) {
963
- let text;
964
- if (this.lexer.state.inRawBlock) {
965
- text = cap[0];
966
- }
967
- else {
968
- text = escape$1(cap[0]);
969
- }
970
- return {
971
- type: 'text',
972
- raw: cap[0],
973
- text,
974
- };
975
- }
976
- }
977
- }
978
-
979
- /**
980
- * Block-Level Grammar
981
- */
982
- const newline = /^(?:[ \t]*(?:\n|$))+/;
983
- const blockCode = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
984
- const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
985
- const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
986
- const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
987
- const bullet = /(?:[*+-]|\d{1,9}[.)])/;
988
- const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/)
989
- .replace(/bull/g, bullet) // lists can interrupt
990
- .replace(/blockCode/g, /(?: {4}| {0,3}\t)/) // indented code blocks can interrupt
991
- .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt
992
- .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt
993
- .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt
994
- .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt
995
- .getRegex();
996
- const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
997
- const blockText = /^[^\n]+/;
998
- const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
999
- const def = edit(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/)
1000
- .replace('label', _blockLabel)
1001
- .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/)
1002
- .getRegex();
1003
- const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
1004
- .replace(/bull/g, bullet)
1005
- .getRegex();
1006
- const _tag = 'address|article|aside|base|basefont|blockquote|body|caption'
1007
- + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
1008
- + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
1009
- + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
1010
- + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'
1011
- + '|tr|track|ul';
1012
- const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
1013
- const html = edit('^ {0,3}(?:' // optional indentation
1014
- + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
1015
- + '|comment[^\\n]*(\\n+|$)' // (2)
1016
- + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
1017
- + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
1018
- + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
1019
- + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (6)
1020
- + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) open tag
1021
- + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) closing tag
1022
- + ')', 'i')
1023
- .replace('comment', _comment)
1024
- .replace('tag', _tag)
1025
- .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
1026
- .getRegex();
1027
- const paragraph = edit(_paragraph)
1028
- .replace('hr', hr)
1029
- .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1030
- .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
1031
- .replace('|table', '')
1032
- .replace('blockquote', ' {0,3}>')
1033
- .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1034
- .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1035
- .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1036
- .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
1037
- .getRegex();
1038
- const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/)
1039
- .replace('paragraph', paragraph)
1040
- .getRegex();
1041
- /**
1042
- * Normal Block Grammar
1043
- */
1044
- const blockNormal = {
1045
- blockquote,
1046
- code: blockCode,
1047
- def,
1048
- fences,
1049
- heading,
1050
- hr,
1051
- html,
1052
- lheading,
1053
- list,
1054
- newline,
1055
- paragraph,
1056
- table: noopTest,
1057
- text: blockText,
1058
- };
1059
- /**
1060
- * GFM Block Grammar
1061
- */
1062
- const gfmTable = edit('^ *([^\\n ].*)\\n' // Header
1063
- + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
1064
- + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells
1065
- .replace('hr', hr)
1066
- .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1067
- .replace('blockquote', ' {0,3}>')
1068
- .replace('code', '(?: {4}| {0,3}\t)[^\\n]')
1069
- .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1070
- .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1071
- .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1072
- .replace('tag', _tag) // tables can be interrupted by type (6) html blocks
1073
- .getRegex();
1074
- const blockGfm = {
1075
- ...blockNormal,
1076
- table: gfmTable,
1077
- paragraph: edit(_paragraph)
1078
- .replace('hr', hr)
1079
- .replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
1080
- .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
1081
- .replace('table', gfmTable) // interrupt paragraphs with table
1082
- .replace('blockquote', ' {0,3}>')
1083
- .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
1084
- .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
1085
- .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
1086
- .replace('tag', _tag) // pars can be interrupted by type (6) html blocks
1087
- .getRegex(),
1088
- };
1089
- /**
1090
- * Pedantic grammar (original John Gruber's loose markdown specification)
1091
- */
1092
- const blockPedantic = {
1093
- ...blockNormal,
1094
- html: edit('^ *(?:comment *(?:\\n|\\s*$)'
1095
- + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
1096
- + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
1097
- .replace('comment', _comment)
1098
- .replace(/tag/g, '(?!(?:'
1099
- + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
1100
- + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
1101
- + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
1102
- .getRegex(),
1103
- def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
1104
- heading: /^(#{1,6})(.*)(?:\n+|$)/,
1105
- fences: noopTest, // fences not supported
1106
- lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
1107
- paragraph: edit(_paragraph)
1108
- .replace('hr', hr)
1109
- .replace('heading', ' *#{1,6} *[^\n]')
1110
- .replace('lheading', lheading)
1111
- .replace('|table', '')
1112
- .replace('blockquote', ' {0,3}>')
1113
- .replace('|fences', '')
1114
- .replace('|list', '')
1115
- .replace('|html', '')
1116
- .replace('|tag', '')
1117
- .getRegex(),
1118
- };
1119
- /**
1120
- * Inline-Level Grammar
1121
- */
1122
- const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
1123
- const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
1124
- const br = /^( {2,}|\\)\n(?!\s*$)/;
1125
- const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
1126
- // list of unicode punctuation marks, plus any missing characters from CommonMark spec
1127
- const _punctuation = '\\p{P}\\p{S}';
1128
- const punctuation = edit(/^((?![*_])[\spunctuation])/, 'u')
1129
- .replace(/punctuation/g, _punctuation).getRegex();
1130
- // sequences em should skip over [title](link), `code`, <html>
1131
- const blockSkip = /\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g;
1132
- const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u')
1133
- .replace(/punct/g, _punctuation)
1134
- .getRegex();
1135
- const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong
1136
- + '|[^*]+(?=[^*])' // Consume to delim
1137
- + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter
1138
- + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter
1139
- + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter
1140
- + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter
1141
- + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter
1142
- + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter
1143
- .replace(/punct/g, _punctuation)
1144
- .getRegex();
1145
- // (6) Not allowed for _
1146
- const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong
1147
- + '|[^_]+(?=[^_])' // Consume to delim
1148
- + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter
1149
- + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter
1150
- + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter
1151
- + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter
1152
- + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter
1153
- .replace(/punct/g, _punctuation)
1154
- .getRegex();
1155
- const anyPunctuation = edit(/\\([punct])/, 'gu')
1156
- .replace(/punct/g, _punctuation)
1157
- .getRegex();
1158
- const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/)
1159
- .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)
1160
- .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])?)+(?![-_])/)
1161
- .getRegex();
1162
- const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();
1163
- const tag = edit('^comment'
1164
- + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
1165
- + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
1166
- + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
1167
- + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
1168
- + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>') // CDATA section
1169
- .replace('comment', _inlineComment)
1170
- .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/)
1171
- .getRegex();
1172
- const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
1173
- const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/)
1174
- .replace('label', _inlineLabel)
1175
- .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/)
1176
- .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/)
1177
- .getRegex();
1178
- const reflink = edit(/^!?\[(label)\]\[(ref)\]/)
1179
- .replace('label', _inlineLabel)
1180
- .replace('ref', _blockLabel)
1181
- .getRegex();
1182
- const nolink = edit(/^!?\[(ref)\](?:\[\])?/)
1183
- .replace('ref', _blockLabel)
1184
- .getRegex();
1185
- const reflinkSearch = edit('reflink|nolink(?!\\()', 'g')
1186
- .replace('reflink', reflink)
1187
- .replace('nolink', nolink)
1188
- .getRegex();
1189
- /**
1190
- * Normal Inline Grammar
1191
- */
1192
- const inlineNormal = {
1193
- _backpedal: noopTest, // only used for GFM url
1194
- anyPunctuation,
1195
- autolink,
1196
- blockSkip,
1197
- br,
1198
- code: inlineCode,
1199
- del: noopTest,
1200
- emStrongLDelim,
1201
- emStrongRDelimAst,
1202
- emStrongRDelimUnd,
1203
- escape,
1204
- link,
1205
- nolink,
1206
- punctuation,
1207
- reflink,
1208
- reflinkSearch,
1209
- tag,
1210
- text: inlineText,
1211
- url: noopTest,
1212
- };
1213
- /**
1214
- * Pedantic Inline Grammar
1215
- */
1216
- const inlinePedantic = {
1217
- ...inlineNormal,
1218
- link: edit(/^!?\[(label)\]\((.*?)\)/)
1219
- .replace('label', _inlineLabel)
1220
- .getRegex(),
1221
- reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
1222
- .replace('label', _inlineLabel)
1223
- .getRegex(),
1224
- };
1225
- /**
1226
- * GFM Inline Grammar
1227
- */
1228
- const inlineGfm = {
1229
- ...inlineNormal,
1230
- escape: edit(escape).replace('])', '~|])').getRegex(),
1231
- url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i')
1232
- .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)
1233
- .getRegex(),
1234
- _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
1235
- del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
1236
- text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/,
1237
- };
1238
- /**
1239
- * GFM + Line Breaks Inline Grammar
1240
- */
1241
- const inlineBreaks = {
1242
- ...inlineGfm,
1243
- br: edit(br).replace('{2,}', '*').getRegex(),
1244
- text: edit(inlineGfm.text)
1245
- .replace('\\b_', '\\b_| {2,}\\n')
1246
- .replace(/\{2,\}/g, '*')
1247
- .getRegex(),
1248
- };
1249
- /**
1250
- * exports
1251
- */
1252
- const block = {
1253
- normal: blockNormal,
1254
- gfm: blockGfm,
1255
- pedantic: blockPedantic,
1256
- };
1257
- const inline = {
1258
- normal: inlineNormal,
1259
- gfm: inlineGfm,
1260
- breaks: inlineBreaks,
1261
- pedantic: inlinePedantic,
1262
- };
1043
+ }
1044
+ else if (this.lexer.state.inLink && this.rules.other.endATag.test(cap[0])) {
1045
+ this.lexer.state.inLink = false;
1046
+ }
1047
+ if (!this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(cap[0])) {
1048
+ this.lexer.state.inRawBlock = true;
1049
+ }
1050
+ else if (this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(cap[0])) {
1051
+ this.lexer.state.inRawBlock = false;
1052
+ }
1053
+ return {
1054
+ type: 'html',
1055
+ raw: cap[0],
1056
+ inLink: this.lexer.state.inLink,
1057
+ inRawBlock: this.lexer.state.inRawBlock,
1058
+ block: false,
1059
+ text: cap[0],
1060
+ };
1061
+ }
1062
+ }
1063
+ link(src) {
1064
+ const cap = this.rules.inline.link.exec(src);
1065
+ if (cap) {
1066
+ const trimmedUrl = cap[2].trim();
1067
+ if (!this.options.pedantic && this.rules.other.startAngleBracket.test(trimmedUrl)) {
1068
+ // commonmark requires matching angle brackets
1069
+ if (!(this.rules.other.endAngleBracket.test(trimmedUrl))) {
1070
+ return;
1071
+ }
1072
+ // ending angle bracket cannot be escaped
1073
+ const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
1074
+ if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
1075
+ return;
1076
+ }
1077
+ }
1078
+ else {
1079
+ // find closing parenthesis
1080
+ const lastParenIndex = findClosingBracket(cap[2], '()');
1081
+ if (lastParenIndex > -1) {
1082
+ const start = cap[0].indexOf('!') === 0 ? 5 : 4;
1083
+ const linkLen = start + cap[1].length + lastParenIndex;
1084
+ cap[2] = cap[2].substring(0, lastParenIndex);
1085
+ cap[0] = cap[0].substring(0, linkLen).trim();
1086
+ cap[3] = '';
1087
+ }
1088
+ }
1089
+ let href = cap[2];
1090
+ let title = '';
1091
+ if (this.options.pedantic) {
1092
+ // split pedantic href and title
1093
+ const link = this.rules.other.pedanticHrefTitle.exec(href);
1094
+ if (link) {
1095
+ href = link[1];
1096
+ title = link[3];
1097
+ }
1098
+ }
1099
+ else {
1100
+ title = cap[3] ? cap[3].slice(1, -1) : '';
1101
+ }
1102
+ href = href.trim();
1103
+ if (this.rules.other.startAngleBracket.test(href)) {
1104
+ if (this.options.pedantic && !(this.rules.other.endAngleBracket.test(trimmedUrl))) {
1105
+ // pedantic allows starting angle bracket without ending angle bracket
1106
+ href = href.slice(1);
1107
+ }
1108
+ else {
1109
+ href = href.slice(1, -1);
1110
+ }
1111
+ }
1112
+ return outputLink(cap, {
1113
+ href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,
1114
+ title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title,
1115
+ }, cap[0], this.lexer, this.rules);
1116
+ }
1117
+ }
1118
+ reflink(src, links) {
1119
+ let cap;
1120
+ if ((cap = this.rules.inline.reflink.exec(src))
1121
+ || (cap = this.rules.inline.nolink.exec(src))) {
1122
+ const linkString = (cap[2] || cap[1]).replace(this.rules.other.multipleSpaceGlobal, ' ');
1123
+ const link = links[linkString.toLowerCase()];
1124
+ if (!link) {
1125
+ const text = cap[0].charAt(0);
1126
+ return {
1127
+ type: 'text',
1128
+ raw: text,
1129
+ text,
1130
+ };
1131
+ }
1132
+ return outputLink(cap, link, cap[0], this.lexer, this.rules);
1133
+ }
1134
+ }
1135
+ emStrong(src, maskedSrc, prevChar = '') {
1136
+ let match = this.rules.inline.emStrongLDelim.exec(src);
1137
+ if (!match)
1138
+ return;
1139
+ // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
1140
+ if (match[3] && prevChar.match(this.rules.other.unicodeAlphaNumeric))
1141
+ return;
1142
+ const nextChar = match[1] || match[2] || '';
1143
+ if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
1144
+ // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
1145
+ const lLength = [...match[0]].length - 1;
1146
+ let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
1147
+ const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
1148
+ endReg.lastIndex = 0;
1149
+ // Clip maskedSrc to same section of string as src (move to lexer?)
1150
+ maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
1151
+ while ((match = endReg.exec(maskedSrc)) != null) {
1152
+ rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
1153
+ if (!rDelim)
1154
+ continue; // skip single * in __abc*abc__
1155
+ rLength = [...rDelim].length;
1156
+ if (match[3] || match[4]) { // found another Left Delim
1157
+ delimTotal += rLength;
1158
+ continue;
1159
+ }
1160
+ else if (match[5] || match[6]) { // either Left or Right Delim
1161
+ if (lLength % 3 && !((lLength + rLength) % 3)) {
1162
+ midDelimTotal += rLength;
1163
+ continue; // CommonMark Emphasis Rules 9-10
1164
+ }
1165
+ }
1166
+ delimTotal -= rLength;
1167
+ if (delimTotal > 0)
1168
+ continue; // Haven't found enough closing delimiters
1169
+ // Remove extra characters. *a*** -> *a*
1170
+ rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
1171
+ // char length can be >1 for unicode characters;
1172
+ const lastCharLength = [...match[0]][0].length;
1173
+ const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
1174
+ // Create `em` if smallest delimiter has odd char count. *a***
1175
+ if (Math.min(lLength, rLength) % 2) {
1176
+ const text = raw.slice(1, -1);
1177
+ return {
1178
+ type: 'em',
1179
+ raw,
1180
+ text,
1181
+ tokens: this.lexer.inlineTokens(text),
1182
+ };
1183
+ }
1184
+ // Create 'strong' if smallest delimiter has even char count. **a***
1185
+ const text = raw.slice(2, -2);
1186
+ return {
1187
+ type: 'strong',
1188
+ raw,
1189
+ text,
1190
+ tokens: this.lexer.inlineTokens(text),
1191
+ };
1192
+ }
1193
+ }
1194
+ }
1195
+ codespan(src) {
1196
+ const cap = this.rules.inline.code.exec(src);
1197
+ if (cap) {
1198
+ let text = cap[2].replace(this.rules.other.newLineCharGlobal, ' ');
1199
+ const hasNonSpaceChars = this.rules.other.nonSpaceChar.test(text);
1200
+ const hasSpaceCharsOnBothEnds = this.rules.other.startingSpaceChar.test(text) && this.rules.other.endingSpaceChar.test(text);
1201
+ if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
1202
+ text = text.substring(1, text.length - 1);
1203
+ }
1204
+ return {
1205
+ type: 'codespan',
1206
+ raw: cap[0],
1207
+ text,
1208
+ };
1209
+ }
1210
+ }
1211
+ br(src) {
1212
+ const cap = this.rules.inline.br.exec(src);
1213
+ if (cap) {
1214
+ return {
1215
+ type: 'br',
1216
+ raw: cap[0],
1217
+ };
1218
+ }
1219
+ }
1220
+ del(src) {
1221
+ const cap = this.rules.inline.del.exec(src);
1222
+ if (cap) {
1223
+ return {
1224
+ type: 'del',
1225
+ raw: cap[0],
1226
+ text: cap[2],
1227
+ tokens: this.lexer.inlineTokens(cap[2]),
1228
+ };
1229
+ }
1230
+ }
1231
+ autolink(src) {
1232
+ const cap = this.rules.inline.autolink.exec(src);
1233
+ if (cap) {
1234
+ let text, href;
1235
+ if (cap[2] === '@') {
1236
+ text = cap[1];
1237
+ href = 'mailto:' + text;
1238
+ }
1239
+ else {
1240
+ text = cap[1];
1241
+ href = text;
1242
+ }
1243
+ return {
1244
+ type: 'link',
1245
+ raw: cap[0],
1246
+ text,
1247
+ href,
1248
+ tokens: [
1249
+ {
1250
+ type: 'text',
1251
+ raw: text,
1252
+ text,
1253
+ },
1254
+ ],
1255
+ };
1256
+ }
1257
+ }
1258
+ url(src) {
1259
+ let cap;
1260
+ if (cap = this.rules.inline.url.exec(src)) {
1261
+ let text, href;
1262
+ if (cap[2] === '@') {
1263
+ text = cap[0];
1264
+ href = 'mailto:' + text;
1265
+ }
1266
+ else {
1267
+ // do extended autolink path validation
1268
+ let prevCapZero;
1269
+ do {
1270
+ prevCapZero = cap[0];
1271
+ cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';
1272
+ } while (prevCapZero !== cap[0]);
1273
+ text = cap[0];
1274
+ if (cap[1] === 'www.') {
1275
+ href = 'http://' + cap[0];
1276
+ }
1277
+ else {
1278
+ href = cap[0];
1279
+ }
1280
+ }
1281
+ return {
1282
+ type: 'link',
1283
+ raw: cap[0],
1284
+ text,
1285
+ href,
1286
+ tokens: [
1287
+ {
1288
+ type: 'text',
1289
+ raw: text,
1290
+ text,
1291
+ },
1292
+ ],
1293
+ };
1294
+ }
1295
+ }
1296
+ inlineText(src) {
1297
+ const cap = this.rules.inline.text.exec(src);
1298
+ if (cap) {
1299
+ const escaped = this.lexer.state.inRawBlock;
1300
+ return {
1301
+ type: 'text',
1302
+ raw: cap[0],
1303
+ text: cap[0],
1304
+ escaped,
1305
+ };
1306
+ }
1307
+ }
1308
+ }
1263
1309
 
1264
1310
  /**
1265
1311
  * Block Lexer
@@ -1286,6 +1332,7 @@
1286
1332
  top: true,
1287
1333
  };
1288
1334
  const rules = {
1335
+ other,
1289
1336
  block: block.normal,
1290
1337
  inline: inline.normal,
1291
1338
  };
@@ -1332,7 +1379,7 @@
1332
1379
  */
1333
1380
  lex(src) {
1334
1381
  src = src
1335
- .replace(/\r\n|\r/g, '\n');
1382
+ .replace(other.carriageReturn, '\n');
1336
1383
  this.blockTokens(src, this.tokens);
1337
1384
  for (let i = 0; i < this.inlineQueue.length; i++) {
1338
1385
  const next = this.inlineQueue[i];
@@ -1343,7 +1390,7 @@
1343
1390
  }
1344
1391
  blockTokens(src, tokens = [], lastParagraphClipped = false) {
1345
1392
  if (this.options.pedantic) {
1346
- src = src.replace(/\t/g, ' ').replace(/^ +$/gm, '');
1393
+ src = src.replace(other.tabCharGlobal, ' ').replace(other.spaceLine, '');
1347
1394
  }
1348
1395
  let token;
1349
1396
  let lastToken;
@@ -1575,13 +1622,7 @@
1575
1622
  if (token = this.tokenizer.tag(src)) {
1576
1623
  src = src.substring(token.raw.length);
1577
1624
  lastToken = tokens[tokens.length - 1];
1578
- if (lastToken && token.type === 'text' && lastToken.type === 'text') {
1579
- lastToken.raw += token.raw;
1580
- lastToken.text += token.text;
1581
- }
1582
- else {
1583
- tokens.push(token);
1584
- }
1625
+ tokens.push(token);
1585
1626
  continue;
1586
1627
  }
1587
1628
  // link
@@ -1700,17 +1741,17 @@
1700
1741
  return '';
1701
1742
  }
1702
1743
  code({ text, lang, escaped }) {
1703
- const langString = (lang || '').match(/^\S*/)?.[0];
1704
- const code = text.replace(/\n$/, '') + '\n';
1744
+ const langString = (lang || '').match(other.notSpaceStart)?.[0];
1745
+ const code = text.replace(other.endingNewline, '') + '\n';
1705
1746
  if (!langString) {
1706
1747
  return '<pre><code>'
1707
- + (escaped ? code : escape$1(code, true))
1748
+ + (escaped ? code : escape(code, true))
1708
1749
  + '</code></pre>\n';
1709
1750
  }
1710
1751
  return '<pre><code class="language-'
1711
- + escape$1(langString)
1752
+ + escape(langString)
1712
1753
  + '">'
1713
- + (escaped ? code : escape$1(code, true))
1754
+ + (escaped ? code : escape(code, true))
1714
1755
  + '</code></pre>\n';
1715
1756
  }
1716
1757
  blockquote({ tokens }) {
@@ -1746,7 +1787,8 @@
1746
1787
  if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
1747
1788
  item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
1748
1789
  if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
1749
- item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
1790
+ item.tokens[0].tokens[0].text = checkbox + ' ' + escape(item.tokens[0].tokens[0].text);
1791
+ item.tokens[0].tokens[0].escaped = true;
1750
1792
  }
1751
1793
  }
1752
1794
  else {
@@ -1754,6 +1796,7 @@
1754
1796
  type: 'text',
1755
1797
  raw: checkbox + ' ',
1756
1798
  text: checkbox + ' ',
1799
+ escaped: true,
1757
1800
  });
1758
1801
  }
1759
1802
  }
@@ -1819,7 +1862,7 @@
1819
1862
  return `<em>${this.parser.parseInline(tokens)}</em>`;
1820
1863
  }
1821
1864
  codespan({ text }) {
1822
- return `<code>${text}</code>`;
1865
+ return `<code>${escape(text, true)}</code>`;
1823
1866
  }
1824
1867
  br(token) {
1825
1868
  return '<br>';
@@ -1836,7 +1879,7 @@
1836
1879
  href = cleanHref;
1837
1880
  let out = '<a href="' + href + '"';
1838
1881
  if (title) {
1839
- out += ' title="' + title + '"';
1882
+ out += ' title="' + (escape(title)) + '"';
1840
1883
  }
1841
1884
  out += '>' + text + '</a>';
1842
1885
  return out;
@@ -1844,18 +1887,20 @@
1844
1887
  image({ href, title, text }) {
1845
1888
  const cleanHref = cleanUrl(href);
1846
1889
  if (cleanHref === null) {
1847
- return text;
1890
+ return escape(text);
1848
1891
  }
1849
1892
  href = cleanHref;
1850
1893
  let out = `<img src="${href}" alt="${text}"`;
1851
1894
  if (title) {
1852
- out += ` title="${title}"`;
1895
+ out += ` title="${escape(title)}"`;
1853
1896
  }
1854
1897
  out += '>';
1855
1898
  return out;
1856
1899
  }
1857
1900
  text(token) {
1858
- return 'tokens' in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text;
1901
+ return 'tokens' in token && token.tokens
1902
+ ? this.parser.parseInline(token.tokens)
1903
+ : ('escaped' in token && token.escaped ? token.text : escape(token.text));
1859
1904
  }
1860
1905
  }
1861
1906
 
@@ -1989,7 +2034,7 @@
1989
2034
  type: 'paragraph',
1990
2035
  raw: body,
1991
2036
  text: body,
1992
- tokens: [{ type: 'text', raw: body, text: body }],
2037
+ tokens: [{ type: 'text', raw: body, text: body, escaped: true }],
1993
2038
  });
1994
2039
  }
1995
2040
  else {
@@ -2425,7 +2470,7 @@
2425
2470
  e.message += '\nPlease report this to https://github.com/markedjs/marked.';
2426
2471
  if (silent) {
2427
2472
  const msg = '<p>An error occurred:</p><pre>'
2428
- + escape$1(e.message + '', true)
2473
+ + escape(e.message + '', true)
2429
2474
  + '</pre>';
2430
2475
  if (async) {
2431
2476
  return Promise.resolve(msg);