marked 1.2.7 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/marked.esm.js +161 -154
- package/lib/marked.js +162 -138
- package/marked.min.js +2 -2
- package/package.json +15 -15
- package/src/Lexer.js +47 -26
- package/src/Renderer.js +2 -0
- package/src/Tokenizer.js +85 -66
- package/src/rules.js +23 -56
package/src/Tokenizer.js
CHANGED
|
@@ -79,19 +79,10 @@ module.exports = class Tokenizer {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
code(src
|
|
82
|
+
code(src) {
|
|
83
83
|
const cap = this.rules.block.code.exec(src);
|
|
84
84
|
if (cap) {
|
|
85
|
-
const
|
|
86
|
-
// An indented code block cannot interrupt a paragraph.
|
|
87
|
-
if (lastToken && lastToken.type === 'paragraph') {
|
|
88
|
-
return {
|
|
89
|
-
raw: cap[0],
|
|
90
|
-
text: cap[0].trimRight()
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const text = cap[0].replace(/^ {4}/gm, '');
|
|
85
|
+
const text = cap[0].replace(/^ {1,4}/gm, '');
|
|
95
86
|
return {
|
|
96
87
|
type: 'code',
|
|
97
88
|
raw: cap[0],
|
|
@@ -229,7 +220,8 @@ module.exports = class Tokenizer {
|
|
|
229
220
|
addBack,
|
|
230
221
|
loose,
|
|
231
222
|
istask,
|
|
232
|
-
ischecked
|
|
223
|
+
ischecked,
|
|
224
|
+
endMatch;
|
|
233
225
|
|
|
234
226
|
let l = itemMatch.length;
|
|
235
227
|
bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
|
|
@@ -237,28 +229,42 @@ module.exports = class Tokenizer {
|
|
|
237
229
|
item = itemMatch[i];
|
|
238
230
|
raw = item;
|
|
239
231
|
|
|
232
|
+
if (!this.options.pedantic) {
|
|
233
|
+
// Determine if current item contains the end of the list
|
|
234
|
+
endMatch = item.match(new RegExp('\\n\\s*\\n {0,' + (bcurr[0].length - 1) + '}\\S'));
|
|
235
|
+
if (endMatch) {
|
|
236
|
+
addBack = item.length - endMatch.index + itemMatch.slice(i + 1).join('\n').length;
|
|
237
|
+
list.raw = list.raw.substring(0, list.raw.length - addBack);
|
|
238
|
+
|
|
239
|
+
item = item.substring(0, endMatch.index);
|
|
240
|
+
raw = item;
|
|
241
|
+
l = i + 1;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
240
245
|
// Determine whether the next list item belongs here.
|
|
241
246
|
// Backpedal if it does not belong in this list.
|
|
242
247
|
if (i !== l - 1) {
|
|
243
248
|
bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
249
|
+
if (
|
|
250
|
+
!this.options.pedantic
|
|
251
|
+
? bnext[1].length >= bcurr[0].length || bnext[1].length > 3
|
|
252
|
+
: bnext[1].length > bcurr[1].length
|
|
253
|
+
) {
|
|
254
|
+
// nested list or continuation
|
|
255
|
+
itemMatch.splice(i, 2, itemMatch[i] + (!this.options.pedantic && bnext[1].length < bcurr[0].length && !itemMatch[i].match(/\n$/) ? '' : '\n') + itemMatch[i + 1]);
|
|
248
256
|
i--;
|
|
249
257
|
l--;
|
|
250
258
|
continue;
|
|
251
|
-
} else
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
i = l - 1;
|
|
261
|
-
}
|
|
259
|
+
} else if (
|
|
260
|
+
// different bullet style
|
|
261
|
+
!this.options.pedantic || this.options.smartLists
|
|
262
|
+
? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1]
|
|
263
|
+
: isordered === (bnext[2].length === 1)
|
|
264
|
+
) {
|
|
265
|
+
addBack = itemMatch.slice(i + 1).join('\n').length;
|
|
266
|
+
list.raw = list.raw.substring(0, list.raw.length - addBack);
|
|
267
|
+
i = l - 1;
|
|
262
268
|
}
|
|
263
269
|
bcurr = bnext;
|
|
264
270
|
}
|
|
@@ -277,12 +283,18 @@ module.exports = class Tokenizer {
|
|
|
277
283
|
: item.replace(/^ {1,4}/gm, '');
|
|
278
284
|
}
|
|
279
285
|
|
|
286
|
+
// trim item newlines at end
|
|
287
|
+
item = rtrim(item, '\n');
|
|
288
|
+
if (i !== l - 1) {
|
|
289
|
+
raw = raw + '\n';
|
|
290
|
+
}
|
|
291
|
+
|
|
280
292
|
// Determine whether item is loose or not.
|
|
281
293
|
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
|
|
282
294
|
// for discount behavior.
|
|
283
|
-
loose = next || /\n\n(?!\s*$)/.test(
|
|
295
|
+
loose = next || /\n\n(?!\s*$)/.test(raw);
|
|
284
296
|
if (i !== l - 1) {
|
|
285
|
-
next =
|
|
297
|
+
next = raw.slice(-2) === '\n\n';
|
|
286
298
|
if (!loose) loose = next;
|
|
287
299
|
}
|
|
288
300
|
|
|
@@ -407,17 +419,9 @@ module.exports = class Tokenizer {
|
|
|
407
419
|
}
|
|
408
420
|
}
|
|
409
421
|
|
|
410
|
-
text(src
|
|
422
|
+
text(src) {
|
|
411
423
|
const cap = this.rules.block.text.exec(src);
|
|
412
424
|
if (cap) {
|
|
413
|
-
const lastToken = tokens[tokens.length - 1];
|
|
414
|
-
if (lastToken && lastToken.type === 'text') {
|
|
415
|
-
return {
|
|
416
|
-
raw: cap[0],
|
|
417
|
-
text: cap[0]
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
|
|
421
425
|
return {
|
|
422
426
|
type: 'text',
|
|
423
427
|
raw: cap[0],
|
|
@@ -541,46 +545,61 @@ module.exports = class Tokenizer {
|
|
|
541
545
|
}
|
|
542
546
|
}
|
|
543
547
|
|
|
544
|
-
|
|
545
|
-
let match = this.rules.inline.
|
|
548
|
+
emStrong(src, maskedSrc, prevChar = '') {
|
|
549
|
+
let match = this.rules.inline.emStrong.lDelim.exec(src);
|
|
550
|
+
if (!match) return;
|
|
551
|
+
|
|
552
|
+
if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) return; // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
|
|
553
|
+
|
|
554
|
+
const nextChar = match[1] || match[2] || '';
|
|
546
555
|
|
|
547
|
-
if (
|
|
548
|
-
|
|
549
|
-
|
|
556
|
+
if (!nextChar || (nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
|
|
557
|
+
const lLength = match[0].length - 1;
|
|
558
|
+
let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
|
|
550
559
|
|
|
560
|
+
const endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
|
|
551
561
|
endReg.lastIndex = 0;
|
|
552
562
|
|
|
553
|
-
|
|
563
|
+
maskedSrc = maskedSrc.slice(-1 * src.length + lLength); // Bump maskedSrc to same section of string as src (move to lexer?)
|
|
564
|
+
|
|
554
565
|
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
566
|
+
rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
|
|
567
|
+
|
|
568
|
+
if (!rDelim) continue; // matched the first alternative in rules.js (skip the * in __abc*abc__)
|
|
569
|
+
|
|
570
|
+
rLength = rDelim.length;
|
|
571
|
+
|
|
572
|
+
if (match[3] || match[4]) { // found another Left Delim
|
|
573
|
+
delimTotal += rLength;
|
|
574
|
+
continue;
|
|
575
|
+
} else if (match[5] || match[6]) { // either Left or Right Delim
|
|
576
|
+
if (lLength % 3 && !((lLength + rLength) % 3)) {
|
|
577
|
+
midDelimTotal += rLength;
|
|
578
|
+
continue; // CommonMark Emphasis Rules 9-10
|
|
579
|
+
}
|
|
562
580
|
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
581
|
|
|
567
|
-
|
|
568
|
-
let match = this.rules.inline.em.start.exec(src);
|
|
582
|
+
delimTotal -= rLength;
|
|
569
583
|
|
|
570
|
-
|
|
571
|
-
maskedSrc = maskedSrc.slice(-1 * src.length);
|
|
572
|
-
const endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
|
|
584
|
+
if (delimTotal > 0) continue; // Haven't found enough closing delimiters
|
|
573
585
|
|
|
574
|
-
|
|
586
|
+
// If this is the last rDelimiter, remove extra characters. *a*** -> *a*
|
|
587
|
+
if (delimTotal + midDelimTotal - rLength <= 0 && !maskedSrc.slice(endReg.lastIndex).match(endReg)) {
|
|
588
|
+
rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
|
|
589
|
+
}
|
|
575
590
|
|
|
576
|
-
|
|
577
|
-
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
578
|
-
cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
|
|
579
|
-
if (cap) {
|
|
591
|
+
if (Math.min(lLength, rLength) % 2) {
|
|
580
592
|
return {
|
|
581
593
|
type: 'em',
|
|
582
|
-
raw: src.slice(0,
|
|
583
|
-
text: src.slice(1,
|
|
594
|
+
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
595
|
+
text: src.slice(1, lLength + match.index + rLength)
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
if (Math.min(lLength, rLength) % 2 === 0) {
|
|
599
|
+
return {
|
|
600
|
+
type: 'strong',
|
|
601
|
+
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
602
|
+
text: src.slice(2, lLength + match.index + rLength - 1)
|
|
584
603
|
};
|
|
585
604
|
}
|
|
586
605
|
}
|
package/src/rules.js
CHANGED
|
@@ -8,8 +8,8 @@ const {
|
|
|
8
8
|
* Block-Level Grammar
|
|
9
9
|
*/
|
|
10
10
|
const block = {
|
|
11
|
-
newline:
|
|
12
|
-
code: /^( {4}[^\n]
|
|
11
|
+
newline: /^(?: *(?:\n|$))+/,
|
|
12
|
+
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
|
|
13
13
|
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
|
|
14
14
|
hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
|
|
15
15
|
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
|
|
@@ -31,7 +31,7 @@ const block = {
|
|
|
31
31
|
lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
|
|
32
32
|
// regex template, placeholders will be replaced according to different paragraph
|
|
33
33
|
// interruption rules of commonmark and the original markdown spec:
|
|
34
|
-
_paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
|
|
34
|
+
_paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
|
|
35
35
|
text: /^[^\n]+/
|
|
36
36
|
};
|
|
37
37
|
|
|
@@ -48,7 +48,7 @@ block.item = edit(block.item, 'gm')
|
|
|
48
48
|
.replace(/bull/g, block.bullet)
|
|
49
49
|
.getRegex();
|
|
50
50
|
|
|
51
|
-
block.listItemStart = edit(/^( *)(bull)
|
|
51
|
+
block.listItemStart = edit(/^( *)(bull) */)
|
|
52
52
|
.replace('bull', block.bullet)
|
|
53
53
|
.getRegex();
|
|
54
54
|
|
|
@@ -173,74 +173,41 @@ const inline = {
|
|
|
173
173
|
reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
|
|
174
174
|
nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
|
|
175
175
|
reflinkSearch: 'reflink|nolink(?!\\()',
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
em: {
|
|
183
|
-
start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/, // (1) returns if starts w/ punctuation
|
|
184
|
-
middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
|
|
185
|
-
endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/, // last char can't be punct, or final * must also be followed by punct (or endline)
|
|
186
|
-
endUnd: /[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
|
|
176
|
+
emStrong: {
|
|
177
|
+
lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
|
|
178
|
+
// (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.
|
|
179
|
+
// () Skip other delimiter (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
|
|
180
|
+
rDelimAst: /\_\_[^_]*?\*[^_]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
|
|
181
|
+
rDelimUnd: /\*\*[^*]*?\_[^*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
|
|
187
182
|
},
|
|
188
183
|
code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
|
|
189
184
|
br: /^( {2,}|\\)\n(?!\s*$)/,
|
|
190
185
|
del: noopTest,
|
|
191
|
-
text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,
|
|
192
|
-
punctuation: /^([\
|
|
186
|
+
text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
|
|
187
|
+
punctuation: /^([\spunctuation])/
|
|
193
188
|
};
|
|
194
189
|
|
|
195
|
-
// list of punctuation marks from
|
|
196
|
-
// without * and _ to
|
|
190
|
+
// list of punctuation marks from CommonMark spec
|
|
191
|
+
// without * and _ to handle the different emphasis markers * and _
|
|
197
192
|
inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
|
|
198
193
|
inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
|
|
199
194
|
|
|
200
195
|
// sequences em should skip over [title](link), `code`, <html>
|
|
201
|
-
inline.
|
|
202
|
-
inline.
|
|
196
|
+
inline.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
|
|
197
|
+
inline.escapedEmSt = /\\\*|\\_/g;
|
|
203
198
|
|
|
204
199
|
inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
|
|
205
200
|
|
|
206
|
-
inline.
|
|
207
|
-
.replace(/
|
|
208
|
-
.getRegex();
|
|
209
|
-
|
|
210
|
-
inline.em.middle = edit(inline.em.middle)
|
|
211
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
212
|
-
.replace(/overlapSkip/g, inline._overlapSkip)
|
|
213
|
-
.getRegex();
|
|
214
|
-
|
|
215
|
-
inline.em.endAst = edit(inline.em.endAst, 'g')
|
|
216
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
217
|
-
.getRegex();
|
|
218
|
-
|
|
219
|
-
inline.em.endUnd = edit(inline.em.endUnd, 'g')
|
|
220
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
221
|
-
.getRegex();
|
|
222
|
-
|
|
223
|
-
inline.strong.start = edit(inline.strong.start)
|
|
224
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
225
|
-
.getRegex();
|
|
226
|
-
|
|
227
|
-
inline.strong.middle = edit(inline.strong.middle)
|
|
228
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
229
|
-
.replace(/overlapSkip/g, inline._overlapSkip)
|
|
230
|
-
.getRegex();
|
|
231
|
-
|
|
232
|
-
inline.strong.endAst = edit(inline.strong.endAst, 'g')
|
|
233
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
234
|
-
.getRegex();
|
|
235
|
-
|
|
236
|
-
inline.strong.endUnd = edit(inline.strong.endUnd, 'g')
|
|
237
|
-
.replace(/punctuation/g, inline._punctuation)
|
|
201
|
+
inline.emStrong.lDelim = edit(inline.emStrong.lDelim)
|
|
202
|
+
.replace(/punct/g, inline._punctuation)
|
|
238
203
|
.getRegex();
|
|
239
204
|
|
|
240
|
-
inline.
|
|
205
|
+
inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'g')
|
|
206
|
+
.replace(/punct/g, inline._punctuation)
|
|
241
207
|
.getRegex();
|
|
242
208
|
|
|
243
|
-
inline.
|
|
209
|
+
inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'g')
|
|
210
|
+
.replace(/punct/g, inline._punctuation)
|
|
244
211
|
.getRegex();
|
|
245
212
|
|
|
246
213
|
inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
|
|
@@ -319,7 +286,7 @@ inline.gfm = merge({}, inline.normal, {
|
|
|
319
286
|
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
|
|
320
287
|
_backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
|
|
321
288
|
del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
|
|
322
|
-
text: /^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
|
|
289
|
+
text: /^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
|
|
323
290
|
});
|
|
324
291
|
|
|
325
292
|
inline.gfm.url = edit(inline.gfm.url, 'i')
|