marked 1.2.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/marked.esm.js +108 -124
- package/lib/marked.js +113 -112
- package/marked.min.js +1 -1
- package/package.json +1 -1
- package/src/Lexer.js +44 -25
- package/src/Tokenizer.js +45 -47
- package/src/rules.js +19 -52
package/src/Lexer.js
CHANGED
|
@@ -136,14 +136,15 @@ module.exports = class Lexer {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// code
|
|
139
|
-
if (token = this.tokenizer.code(src
|
|
139
|
+
if (token = this.tokenizer.code(src)) {
|
|
140
140
|
src = src.substring(token.raw.length);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
lastToken = tokens[tokens.length - 1];
|
|
141
|
+
lastToken = tokens[tokens.length - 1];
|
|
142
|
+
// An indented code block cannot interrupt a paragraph.
|
|
143
|
+
if (lastToken && lastToken.type === 'paragraph') {
|
|
145
144
|
lastToken.raw += '\n' + token.raw;
|
|
146
145
|
lastToken.text += '\n' + token.text;
|
|
146
|
+
} else {
|
|
147
|
+
tokens.push(token);
|
|
147
148
|
}
|
|
148
149
|
continue;
|
|
149
150
|
}
|
|
@@ -236,14 +237,14 @@ module.exports = class Lexer {
|
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
// text
|
|
239
|
-
if (token = this.tokenizer.text(src
|
|
240
|
+
if (token = this.tokenizer.text(src)) {
|
|
240
241
|
src = src.substring(token.raw.length);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
} else {
|
|
244
|
-
lastToken = tokens[tokens.length - 1];
|
|
242
|
+
lastToken = tokens[tokens.length - 1];
|
|
243
|
+
if (lastToken && lastToken.type === 'text') {
|
|
245
244
|
lastToken.raw += '\n' + token.raw;
|
|
246
245
|
lastToken.text += '\n' + token.text;
|
|
246
|
+
} else {
|
|
247
|
+
tokens.push(token);
|
|
247
248
|
}
|
|
248
249
|
continue;
|
|
249
250
|
}
|
|
@@ -331,7 +332,7 @@ module.exports = class Lexer {
|
|
|
331
332
|
* Lexing/Compiling
|
|
332
333
|
*/
|
|
333
334
|
inlineTokens(src, tokens = [], inLink = false, inRawBlock = false) {
|
|
334
|
-
let token;
|
|
335
|
+
let token, lastToken;
|
|
335
336
|
|
|
336
337
|
// String with links masked to avoid interference with em and strong
|
|
337
338
|
let maskedSrc = src;
|
|
@@ -354,11 +355,17 @@ module.exports = class Lexer {
|
|
|
354
355
|
maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
|
|
355
356
|
}
|
|
356
357
|
|
|
358
|
+
// Mask out escaped em & strong delimiters
|
|
359
|
+
while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
|
|
360
|
+
maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
|
|
361
|
+
}
|
|
362
|
+
|
|
357
363
|
while (src) {
|
|
358
364
|
if (!keepPrevChar) {
|
|
359
365
|
prevChar = '';
|
|
360
366
|
}
|
|
361
367
|
keepPrevChar = false;
|
|
368
|
+
|
|
362
369
|
// escape
|
|
363
370
|
if (token = this.tokenizer.escape(src)) {
|
|
364
371
|
src = src.substring(token.raw.length);
|
|
@@ -371,7 +378,13 @@ module.exports = class Lexer {
|
|
|
371
378
|
src = src.substring(token.raw.length);
|
|
372
379
|
inLink = token.inLink;
|
|
373
380
|
inRawBlock = token.inRawBlock;
|
|
374
|
-
tokens.
|
|
381
|
+
const lastToken = tokens[tokens.length - 1];
|
|
382
|
+
if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
383
|
+
lastToken.raw += token.raw;
|
|
384
|
+
lastToken.text += token.text;
|
|
385
|
+
} else {
|
|
386
|
+
tokens.push(token);
|
|
387
|
+
}
|
|
375
388
|
continue;
|
|
376
389
|
}
|
|
377
390
|
|
|
@@ -388,23 +401,21 @@ module.exports = class Lexer {
|
|
|
388
401
|
// reflink, nolink
|
|
389
402
|
if (token = this.tokenizer.reflink(src, this.tokens.links)) {
|
|
390
403
|
src = src.substring(token.raw.length);
|
|
404
|
+
const lastToken = tokens[tokens.length - 1];
|
|
391
405
|
if (token.type === 'link') {
|
|
392
406
|
token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
|
|
407
|
+
tokens.push(token);
|
|
408
|
+
} else if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
409
|
+
lastToken.raw += token.raw;
|
|
410
|
+
lastToken.text += token.text;
|
|
411
|
+
} else {
|
|
412
|
+
tokens.push(token);
|
|
393
413
|
}
|
|
394
|
-
tokens.push(token);
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// strong
|
|
399
|
-
if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
|
|
400
|
-
src = src.substring(token.raw.length);
|
|
401
|
-
token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
|
|
402
|
-
tokens.push(token);
|
|
403
414
|
continue;
|
|
404
415
|
}
|
|
405
416
|
|
|
406
|
-
// em
|
|
407
|
-
if (token = this.tokenizer.
|
|
417
|
+
// em & strong
|
|
418
|
+
if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
|
|
408
419
|
src = src.substring(token.raw.length);
|
|
409
420
|
token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
|
|
410
421
|
tokens.push(token);
|
|
@@ -450,9 +461,17 @@ module.exports = class Lexer {
|
|
|
450
461
|
// text
|
|
451
462
|
if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
|
|
452
463
|
src = src.substring(token.raw.length);
|
|
453
|
-
|
|
464
|
+
if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
|
|
465
|
+
prevChar = token.raw.slice(-1);
|
|
466
|
+
}
|
|
454
467
|
keepPrevChar = true;
|
|
455
|
-
tokens.
|
|
468
|
+
lastToken = tokens[tokens.length - 1];
|
|
469
|
+
if (lastToken && lastToken.type === 'text') {
|
|
470
|
+
lastToken.raw += token.raw;
|
|
471
|
+
lastToken.text += token.text;
|
|
472
|
+
} else {
|
|
473
|
+
tokens.push(token);
|
|
474
|
+
}
|
|
456
475
|
continue;
|
|
457
476
|
}
|
|
458
477
|
|
package/src/Tokenizer.js
CHANGED
|
@@ -79,18 +79,9 @@ 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 lastToken = tokens[tokens.length - 1];
|
|
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
85
|
const text = cap[0].replace(/^ {1,4}/gm, '');
|
|
95
86
|
return {
|
|
96
87
|
type: 'code',
|
|
@@ -410,17 +401,9 @@ module.exports = class Tokenizer {
|
|
|
410
401
|
}
|
|
411
402
|
}
|
|
412
403
|
|
|
413
|
-
text(src
|
|
404
|
+
text(src) {
|
|
414
405
|
const cap = this.rules.block.text.exec(src);
|
|
415
406
|
if (cap) {
|
|
416
|
-
const lastToken = tokens[tokens.length - 1];
|
|
417
|
-
if (lastToken && lastToken.type === 'text') {
|
|
418
|
-
return {
|
|
419
|
-
raw: cap[0],
|
|
420
|
-
text: cap[0]
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
407
|
return {
|
|
425
408
|
type: 'text',
|
|
426
409
|
raw: cap[0],
|
|
@@ -544,46 +527,61 @@ module.exports = class Tokenizer {
|
|
|
544
527
|
}
|
|
545
528
|
}
|
|
546
529
|
|
|
547
|
-
|
|
548
|
-
let match = this.rules.inline.
|
|
530
|
+
emStrong(src, maskedSrc, prevChar = '') {
|
|
531
|
+
let match = this.rules.inline.emStrong.lDelim.exec(src);
|
|
532
|
+
if (!match) return;
|
|
533
|
+
|
|
534
|
+
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
|
|
549
535
|
|
|
550
|
-
|
|
551
|
-
maskedSrc = maskedSrc.slice(-1 * src.length);
|
|
552
|
-
const endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
|
|
536
|
+
const nextChar = match[1] || match[2] || '';
|
|
553
537
|
|
|
538
|
+
if (!nextChar || (nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
|
|
539
|
+
const lLength = match[0].length - 1;
|
|
540
|
+
let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
|
|
541
|
+
|
|
542
|
+
const endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
|
|
554
543
|
endReg.lastIndex = 0;
|
|
555
544
|
|
|
556
|
-
|
|
545
|
+
maskedSrc = maskedSrc.slice(-1 * src.length + lLength); // Bump maskedSrc to same section of string as src (move to lexer?)
|
|
546
|
+
|
|
557
547
|
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
548
|
+
rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
|
|
549
|
+
|
|
550
|
+
if (!rDelim) continue; // matched the first alternative in rules.js (skip the * in __abc*abc__)
|
|
551
|
+
|
|
552
|
+
rLength = rDelim.length;
|
|
553
|
+
|
|
554
|
+
if (match[3] || match[4]) { // found another Left Delim
|
|
555
|
+
delimTotal += rLength;
|
|
556
|
+
continue;
|
|
557
|
+
} else if (match[5] || match[6]) { // either Left or Right Delim
|
|
558
|
+
if (lLength % 3 && !((lLength + rLength) % 3)) {
|
|
559
|
+
midDelimTotal += rLength;
|
|
560
|
+
continue; // CommonMark Emphasis Rules 9-10
|
|
561
|
+
}
|
|
565
562
|
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
563
|
|
|
570
|
-
|
|
571
|
-
let match = this.rules.inline.em.start.exec(src);
|
|
564
|
+
delimTotal -= rLength;
|
|
572
565
|
|
|
573
|
-
|
|
574
|
-
maskedSrc = maskedSrc.slice(-1 * src.length);
|
|
575
|
-
const endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
|
|
566
|
+
if (delimTotal > 0) continue; // Haven't found enough closing delimiters
|
|
576
567
|
|
|
577
|
-
|
|
568
|
+
// If this is the last rDelimiter, remove extra characters. *a*** -> *a*
|
|
569
|
+
if (delimTotal + midDelimTotal - rLength <= 0 && !maskedSrc.slice(endReg.lastIndex).match(endReg)) {
|
|
570
|
+
rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
|
|
571
|
+
}
|
|
578
572
|
|
|
579
|
-
|
|
580
|
-
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
581
|
-
cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
|
|
582
|
-
if (cap) {
|
|
573
|
+
if (Math.min(lLength, rLength) % 2) {
|
|
583
574
|
return {
|
|
584
575
|
type: 'em',
|
|
585
|
-
raw: src.slice(0,
|
|
586
|
-
text: src.slice(1,
|
|
576
|
+
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
577
|
+
text: src.slice(1, lLength + match.index + rLength)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
if (Math.min(lLength, rLength) % 2 === 0) {
|
|
581
|
+
return {
|
|
582
|
+
type: 'strong',
|
|
583
|
+
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
584
|
+
text: src.slice(2, lLength + match.index + rLength - 1)
|
|
587
585
|
};
|
|
588
586
|
}
|
|
589
587
|
}
|
package/src/rules.js
CHANGED
|
@@ -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')
|