marked 1.1.0 → 1.1.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/src/Lexer.js CHANGED
@@ -319,9 +319,29 @@ module.exports = class Lexer {
319
319
  /**
320
320
  * Lexing/Compiling
321
321
  */
322
- inlineTokens(src, tokens = [], inLink = false, inRawBlock = false) {
322
+ inlineTokens(src, tokens = [], inLink = false, inRawBlock = false, prevChar = '') {
323
323
  let token;
324
324
 
325
+ // String with links masked to avoid interference with em and strong
326
+ let maskedSrc = src;
327
+ let match;
328
+
329
+ // Mask out reflinks
330
+ if (this.tokens.links) {
331
+ const links = Object.keys(this.tokens.links);
332
+ if (links.length > 0) {
333
+ while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
334
+ if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
335
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
336
+ }
337
+ }
338
+ }
339
+ }
340
+ // Mask out other blocks
341
+ while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
342
+ maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
343
+ }
344
+
325
345
  while (src) {
326
346
  // escape
327
347
  if (token = this.tokenizer.escape(src)) {
@@ -360,7 +380,7 @@ module.exports = class Lexer {
360
380
  }
361
381
 
362
382
  // strong
363
- if (token = this.tokenizer.strong(src)) {
383
+ if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
364
384
  src = src.substring(token.raw.length);
365
385
  token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
366
386
  tokens.push(token);
@@ -368,7 +388,7 @@ module.exports = class Lexer {
368
388
  }
369
389
 
370
390
  // em
371
- if (token = this.tokenizer.em(src)) {
391
+ if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {
372
392
  src = src.substring(token.raw.length);
373
393
  token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
374
394
  tokens.push(token);
@@ -414,6 +434,7 @@ module.exports = class Lexer {
414
434
  // text
415
435
  if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
416
436
  src = src.substring(token.raw.length);
437
+ prevChar = token.raw.slice(-1);
417
438
  tokens.push(token);
418
439
  continue;
419
440
  }
package/src/Tokenizer.js CHANGED
@@ -9,6 +9,7 @@ const {
9
9
  function outputLink(cap, link, raw) {
10
10
  const href = link.href;
11
11
  const title = link.title ? escape(link.title) : null;
12
+ const text = cap[1].replace(/\\([\[\]])/g, '$1');
12
13
 
13
14
  if (cap[0].charAt(0) !== '!') {
14
15
  return {
@@ -16,15 +17,15 @@ function outputLink(cap, link, raw) {
16
17
  raw,
17
18
  href,
18
19
  title,
19
- text: cap[1]
20
+ text
20
21
  };
21
22
  } else {
22
23
  return {
23
24
  type: 'image',
24
25
  raw,
25
- text: escape(cap[1]),
26
26
  href,
27
- title
27
+ title,
28
+ text: escape(text)
28
29
  };
29
30
  }
30
31
  }
@@ -194,12 +195,13 @@ module.exports = class Tokenizer {
194
195
  let raw = cap[0];
195
196
  const bull = cap[2];
196
197
  const isordered = bull.length > 1;
198
+ const isparen = bull[bull.length - 1] === ')';
197
199
 
198
200
  const list = {
199
201
  type: 'list',
200
202
  raw,
201
203
  ordered: isordered,
202
- start: isordered ? +bull : '',
204
+ start: isordered ? +bull.slice(0, -1) : '',
203
205
  loose: false,
204
206
  items: []
205
207
  };
@@ -224,7 +226,7 @@ module.exports = class Tokenizer {
224
226
  // Remove the list item's bullet
225
227
  // so it is seen as the next token.
226
228
  space = item.length;
227
- item = item.replace(/^ *([*+-]|\d+\.) */, '');
229
+ item = item.replace(/^ *([*+-]|\d+[.)]) */, '');
228
230
 
229
231
  // Outdent whatever the
230
232
  // list item contains. Hacky.
@@ -239,7 +241,7 @@ module.exports = class Tokenizer {
239
241
  // Backpedal if it does not belong in this list.
240
242
  if (i !== l - 1) {
241
243
  b = this.rules.block.bullet.exec(itemMatch[i + 1])[0];
242
- if (bull.length > 1 ? b.length === 1
244
+ if (isordered ? b.length === 1 || (!isparen && b[b.length - 1] === ')')
243
245
  : (b.length > 1 || (this.options.smartLists && b !== bull))) {
244
246
  addBack = itemMatch.slice(i + 1).join('\n');
245
247
  list.raw = list.raw.substring(0, list.raw.length - addBack.length);
@@ -488,25 +490,49 @@ module.exports = class Tokenizer {
488
490
  }
489
491
  }
490
492
 
491
- strong(src) {
492
- const cap = this.rules.inline.strong.exec(src);
493
- if (cap) {
494
- return {
495
- type: 'strong',
496
- raw: cap[0],
497
- text: cap[4] || cap[3] || cap[2] || cap[1]
498
- };
493
+ strong(src, maskedSrc, prevChar = '') {
494
+ let match = this.rules.inline.strong.start.exec(src);
495
+
496
+ if (match && (!match[1] || (match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))))) {
497
+ maskedSrc = maskedSrc.slice(-1 * src.length);
498
+ const endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
499
+
500
+ endReg.lastIndex = 0;
501
+
502
+ let cap;
503
+ while ((match = endReg.exec(maskedSrc)) != null) {
504
+ cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));
505
+ if (cap) {
506
+ return {
507
+ type: 'strong',
508
+ raw: src.slice(0, cap[0].length),
509
+ text: src.slice(2, cap[0].length - 2)
510
+ };
511
+ }
512
+ }
499
513
  }
500
514
  }
501
515
 
502
- em(src) {
503
- const cap = this.rules.inline.em.exec(src);
504
- if (cap) {
505
- return {
506
- type: 'em',
507
- raw: cap[0],
508
- text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]
509
- };
516
+ em(src, maskedSrc, prevChar = '') {
517
+ let match = this.rules.inline.em.start.exec(src);
518
+
519
+ if (match && (!match[1] || (match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))))) {
520
+ maskedSrc = maskedSrc.slice(-1 * src.length);
521
+ const endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
522
+
523
+ endReg.lastIndex = 0;
524
+
525
+ let cap;
526
+ while ((match = endReg.exec(maskedSrc)) != null) {
527
+ cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
528
+ if (cap) {
529
+ return {
530
+ type: 'em',
531
+ raw: src.slice(0, cap[0].length),
532
+ text: src.slice(1, cap[0].length - 1)
533
+ };
534
+ }
535
+ }
510
536
  }
511
537
  }
512
538
 
package/src/marked.js CHANGED
@@ -76,20 +76,22 @@ function marked(src, opt, callback) {
76
76
  marked.walkTokens(tokens, function(token) {
77
77
  if (token.type === 'code') {
78
78
  pending++;
79
- highlight(token.text, token.lang, function(err, code) {
80
- if (err) {
81
- return done(err);
82
- }
83
- if (code != null && code !== token.text) {
84
- token.text = code;
85
- token.escaped = true;
86
- }
87
-
88
- pending--;
89
- if (pending === 0) {
90
- done();
91
- }
92
- });
79
+ setTimeout(() => {
80
+ highlight(token.text, token.lang, function(err, code) {
81
+ if (err) {
82
+ return done(err);
83
+ }
84
+ if (code != null && code !== token.text) {
85
+ token.text = code;
86
+ token.escaped = true;
87
+ }
88
+
89
+ pending--;
90
+ if (pending === 0) {
91
+ done();
92
+ }
93
+ });
94
+ }, 0);
93
95
  }
94
96
  });
95
97
 
package/src/rules.js CHANGED
@@ -42,7 +42,7 @@ block.def = edit(block.def)
42
42
  .replace('title', block._title)
43
43
  .getRegex();
44
44
 
45
- block.bullet = /(?:[*+-]|\d{1,9}\.)/;
45
+ block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
46
46
  block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
47
47
  block.item = edit(block.item, 'gm')
48
48
  .replace(/bull/g, block.bullet)
@@ -168,19 +168,74 @@ const inline = {
168
168
  link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
169
169
  reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
170
170
  nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
171
- strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
172
- em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\s,punctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\s,punctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,
171
+ reflinkSearch: 'reflink|nolink(?!\\()',
172
+ strong: {
173
+ start: /^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/, // (1) returns if starts w/ punctuation
174
+ middle: /^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,
175
+ endAst: /[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation\s]|$))/, // last char can't be punct, or final * must also be followed by punct (or endline)
176
+ endUnd: /[^\s]__(?!_)(?:(?=[punctuation\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
177
+ },
178
+ em: {
179
+ start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/, // (1) returns if starts w/ punctuation
180
+ middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
181
+ endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation\s]|$))/, // last char can't be punct, or final * must also be followed by punct (or endline)
182
+ endUnd: /[^\s]_(?!_)(?:(?=[punctuation\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
183
+ },
173
184
  code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
174
185
  br: /^( {2,}|\\)\n(?!\s*$)/,
175
186
  del: noopTest,
176
- text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
187
+ text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/,
188
+ punctuation: /^([\s*punctuation])/
177
189
  };
178
190
 
179
191
  // list of punctuation marks from common mark spec
180
- // without ` and ] to workaround Rule 17 (inline code blocks/links)
181
- // without , to work around example 393
182
- inline._punctuation = '!"#$%&\'()*+\\-./:;<=>?@\\[^_{|}~';
183
- inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();
192
+ // without * and _ to workaround cases with double emphasis
193
+ inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
194
+ inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
195
+
196
+ // sequences em should skip over [title](link), `code`, <html>
197
+ inline._blockSkip = '\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>';
198
+ inline._overlapSkip = '__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*';
199
+
200
+ inline.em.start = edit(inline.em.start)
201
+ .replace(/punctuation/g, inline._punctuation)
202
+ .getRegex();
203
+
204
+ inline.em.middle = edit(inline.em.middle)
205
+ .replace(/punctuation/g, inline._punctuation)
206
+ .replace(/overlapSkip/g, inline._overlapSkip)
207
+ .getRegex();
208
+
209
+ inline.em.endAst = edit(inline.em.endAst, 'g')
210
+ .replace(/punctuation/g, inline._punctuation)
211
+ .getRegex();
212
+
213
+ inline.em.endUnd = edit(inline.em.endUnd, 'g')
214
+ .replace(/punctuation/g, inline._punctuation)
215
+ .getRegex();
216
+
217
+ inline.strong.start = edit(inline.strong.start)
218
+ .replace(/punctuation/g, inline._punctuation)
219
+ .getRegex();
220
+
221
+ inline.strong.middle = edit(inline.strong.middle)
222
+ .replace(/punctuation/g, inline._punctuation)
223
+ .replace(/blockSkip/g, inline._blockSkip)
224
+ .getRegex();
225
+
226
+ inline.strong.endAst = edit(inline.strong.endAst, 'g')
227
+ .replace(/punctuation/g, inline._punctuation)
228
+ .getRegex();
229
+
230
+ inline.strong.endUnd = edit(inline.strong.endUnd, 'g')
231
+ .replace(/punctuation/g, inline._punctuation)
232
+ .getRegex();
233
+
234
+ inline.blockSkip = edit(inline._blockSkip, 'g')
235
+ .getRegex();
236
+
237
+ inline.overlapSkip = edit(inline._overlapSkip, 'g')
238
+ .getRegex();
184
239
 
185
240
  inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
186
241
 
@@ -198,7 +253,7 @@ inline.tag = edit(inline.tag)
198
253
  .replace('attribute', inline._attribute)
199
254
  .getRegex();
200
255
 
201
- inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
256
+ inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
202
257
  inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
203
258
  inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
204
259
 
@@ -212,6 +267,11 @@ inline.reflink = edit(inline.reflink)
212
267
  .replace('label', inline._label)
213
268
  .getRegex();
214
269
 
270
+ inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
271
+ .replace('reflink', inline.reflink)
272
+ .replace('nolink', inline.nolink)
273
+ .getRegex();
274
+
215
275
  /**
216
276
  * Normal Inline Grammar
217
277
  */
@@ -223,8 +283,18 @@ inline.normal = merge({}, inline);
223
283
  */
224
284
 
225
285
  inline.pedantic = merge({}, inline.normal, {
226
- strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
227
- em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
286
+ strong: {
287
+ start: /^__|\*\*/,
288
+ middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
289
+ endAst: /\*\*(?!\*)/g,
290
+ endUnd: /__(?!_)/g
291
+ },
292
+ em: {
293
+ start: /^_|\*/,
294
+ middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
295
+ endAst: /\*(?!\*)/g,
296
+ endUnd: /_(?!_)/g
297
+ },
228
298
  link: edit(/^!?\[(label)\]\((.*?)\)/)
229
299
  .replace('label', inline._label)
230
300
  .getRegex(),