marked 1.0.0 → 1.2.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/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,19 +17,47 @@ 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
  }
31
32
 
33
+ function indentCodeCompensation(raw, text) {
34
+ const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
35
+
36
+ if (matchIndentToCode === null) {
37
+ return text;
38
+ }
39
+
40
+ const indentToCode = matchIndentToCode[1];
41
+
42
+ return text
43
+ .split('\n')
44
+ .map(node => {
45
+ const matchIndentInNode = node.match(/^\s+/);
46
+ if (matchIndentInNode === null) {
47
+ return node;
48
+ }
49
+
50
+ const [indentInNode] = matchIndentInNode;
51
+
52
+ if (indentInNode.length >= indentToCode.length) {
53
+ return node.slice(indentToCode.length);
54
+ }
55
+
56
+ return node;
57
+ })
58
+ .join('\n');
59
+ }
60
+
32
61
  /**
33
62
  * Tokenizer
34
63
  */
@@ -56,32 +85,35 @@ module.exports = class Tokenizer {
56
85
  const lastToken = tokens[tokens.length - 1];
57
86
  // An indented code block cannot interrupt a paragraph.
58
87
  if (lastToken && lastToken.type === 'paragraph') {
59
- tokens.pop();
60
- lastToken.text += '\n' + cap[0].trimRight();
61
- lastToken.raw += '\n' + cap[0];
62
- return lastToken;
63
- } else {
64
- const text = cap[0].replace(/^ {4}/gm, '');
65
88
  return {
66
- type: 'code',
67
89
  raw: cap[0],
68
- codeBlockStyle: 'indented',
69
- text: !this.options.pedantic
70
- ? rtrim(text, '\n')
71
- : text
90
+ text: cap[0].trimRight()
72
91
  };
73
92
  }
93
+
94
+ const text = cap[0].replace(/^ {4}/gm, '');
95
+ return {
96
+ type: 'code',
97
+ raw: cap[0],
98
+ codeBlockStyle: 'indented',
99
+ text: !this.options.pedantic
100
+ ? rtrim(text, '\n')
101
+ : text
102
+ };
74
103
  }
75
104
  }
76
105
 
77
106
  fences(src) {
78
107
  const cap = this.rules.block.fences.exec(src);
79
108
  if (cap) {
109
+ const raw = cap[0];
110
+ const text = indentCodeCompensation(raw, cap[3] || '');
111
+
80
112
  return {
81
113
  type: 'code',
82
- raw: cap[0],
114
+ raw,
83
115
  lang: cap[2] ? cap[2].trim() : cap[2],
84
- text: cap[3] || ''
116
+ text
85
117
  };
86
118
  }
87
119
  }
@@ -163,12 +195,13 @@ module.exports = class Tokenizer {
163
195
  let raw = cap[0];
164
196
  const bull = cap[2];
165
197
  const isordered = bull.length > 1;
198
+ const isparen = bull[bull.length - 1] === ')';
166
199
 
167
200
  const list = {
168
201
  type: 'list',
169
202
  raw,
170
203
  ordered: isordered,
171
- start: isordered ? +bull : '',
204
+ start: isordered ? +bull.slice(0, -1) : '',
172
205
  loose: false,
173
206
  items: []
174
207
  };
@@ -193,7 +226,7 @@ module.exports = class Tokenizer {
193
226
  // Remove the list item's bullet
194
227
  // so it is seen as the next token.
195
228
  space = item.length;
196
- item = item.replace(/^ *([*+-]|\d+\.) */, '');
229
+ item = item.replace(/^ *([*+-]|\d+[.)]) */, '');
197
230
 
198
231
  // Outdent whatever the
199
232
  // list item contains. Hacky.
@@ -208,7 +241,7 @@ module.exports = class Tokenizer {
208
241
  // Backpedal if it does not belong in this list.
209
242
  if (i !== l - 1) {
210
243
  b = this.rules.block.bullet.exec(itemMatch[i + 1])[0];
211
- if (bull.length > 1 ? b.length === 1
244
+ if (isordered ? b.length === 1 || (!isparen && b[b.length - 1] === ')')
212
245
  : (b.length > 1 || (this.options.smartLists && b !== bull))) {
213
246
  addBack = itemMatch.slice(i + 1).join('\n');
214
247
  list.raw = list.raw.substring(0, list.raw.length - addBack.length);
@@ -238,6 +271,7 @@ module.exports = class Tokenizer {
238
271
  }
239
272
 
240
273
  list.items.push({
274
+ type: 'list_item',
241
275
  raw,
242
276
  task: istask,
243
277
  checked: ischecked,
@@ -343,9 +377,17 @@ module.exports = class Tokenizer {
343
377
  }
344
378
  }
345
379
 
346
- text(src) {
380
+ text(src, tokens) {
347
381
  const cap = this.rules.block.text.exec(src);
348
382
  if (cap) {
383
+ const lastToken = tokens[tokens.length - 1];
384
+ if (lastToken && lastToken.type === 'text') {
385
+ return {
386
+ raw: cap[0],
387
+ text: cap[0]
388
+ };
389
+ }
390
+
349
391
  return {
350
392
  type: 'text',
351
393
  raw: cap[0],
@@ -448,35 +490,66 @@ module.exports = class Tokenizer {
448
490
  }
449
491
  }
450
492
 
451
- strong(src) {
452
- const cap = this.rules.inline.strong.exec(src);
453
- if (cap) {
454
- return {
455
- type: 'strong',
456
- raw: cap[0],
457
- text: cap[4] || cap[3] || cap[2] || cap[1]
458
- };
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
+ }
459
513
  }
460
514
  }
461
515
 
462
- em(src) {
463
- const cap = this.rules.inline.em.exec(src);
464
- if (cap) {
465
- return {
466
- type: 'em',
467
- raw: cap[0],
468
- text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]
469
- };
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
+ }
470
536
  }
471
537
  }
472
538
 
473
539
  codespan(src) {
474
540
  const cap = this.rules.inline.code.exec(src);
475
541
  if (cap) {
542
+ let text = cap[2].replace(/\n/g, ' ');
543
+ const hasNonSpaceChars = /[^ ]/.test(text);
544
+ const hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
545
+ if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
546
+ text = text.substring(1, text.length - 1);
547
+ }
548
+ text = escape(text, true);
476
549
  return {
477
550
  type: 'codespan',
478
551
  raw: cap[0],
479
- text: escape(cap[2].trim(), true)
552
+ text
480
553
  };
481
554
  }
482
555
  }
package/src/defaults.js CHANGED
@@ -16,6 +16,7 @@ function getDefaults() {
16
16
  smartLists: false,
17
17
  smartypants: false,
18
18
  tokenizer: null,
19
+ walkTokens: null,
19
20
  xhtml: false
20
21
  };
21
22
  }
package/src/marked.js CHANGED
@@ -28,18 +28,17 @@ function marked(src, opt, callback) {
28
28
  + Object.prototype.toString.call(src) + ', string expected');
29
29
  }
30
30
 
31
- if (callback || typeof opt === 'function') {
32
- if (!callback) {
33
- callback = opt;
34
- opt = null;
35
- }
31
+ if (typeof opt === 'function') {
32
+ callback = opt;
33
+ opt = null;
34
+ }
36
35
 
37
- opt = merge({}, marked.defaults, opt || {});
38
- checkSanitizeDeprecation(opt);
36
+ opt = merge({}, marked.defaults, opt || {});
37
+ checkSanitizeDeprecation(opt);
38
+
39
+ if (callback) {
39
40
  const highlight = opt.highlight;
40
- let tokens,
41
- pending,
42
- i = 0;
41
+ let tokens;
43
42
 
44
43
  try {
45
44
  tokens = Lexer.lex(src, opt);
@@ -47,20 +46,15 @@ function marked(src, opt, callback) {
47
46
  return callback(e);
48
47
  }
49
48
 
50
- pending = tokens.length;
51
-
52
49
  const done = function(err) {
53
- if (err) {
54
- opt.highlight = highlight;
55
- return callback(err);
56
- }
57
-
58
50
  let out;
59
51
 
60
- try {
61
- out = Parser.parse(tokens, opt);
62
- } catch (e) {
63
- err = e;
52
+ if (!err) {
53
+ try {
54
+ out = Parser.parse(tokens, opt);
55
+ } catch (e) {
56
+ err = e;
57
+ }
64
58
  }
65
59
 
66
60
  opt.highlight = highlight;
@@ -76,34 +70,47 @@ function marked(src, opt, callback) {
76
70
 
77
71
  delete opt.highlight;
78
72
 
79
- if (!pending) return done();
73
+ if (!tokens.length) return done();
80
74
 
81
- for (; i < tokens.length; i++) {
82
- (function(token) {
83
- if (token.type !== 'code') {
84
- return --pending || done();
85
- }
86
- return highlight(token.text, token.lang, function(err, code) {
87
- if (err) return done(err);
88
- if (code == null || code === token.text) {
89
- return --pending || done();
90
- }
91
- token.text = code;
92
- token.escaped = true;
93
- --pending || done();
94
- });
95
- })(tokens[i]);
75
+ let pending = 0;
76
+ marked.walkTokens(tokens, function(token) {
77
+ if (token.type === 'code') {
78
+ pending++;
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);
95
+ }
96
+ });
97
+
98
+ if (pending === 0) {
99
+ done();
96
100
  }
97
101
 
98
102
  return;
99
103
  }
104
+
100
105
  try {
101
- opt = merge({}, marked.defaults, opt || {});
102
- checkSanitizeDeprecation(opt);
103
- return Parser.parse(Lexer.lex(src, opt), opt);
106
+ const tokens = Lexer.lex(src, opt);
107
+ if (opt.walkTokens) {
108
+ marked.walkTokens(tokens, opt.walkTokens);
109
+ }
110
+ return Parser.parse(tokens, opt);
104
111
  } catch (e) {
105
112
  e.message += '\nPlease report this to https://github.com/markedjs/marked.';
106
- if ((opt || marked.defaults).silent) {
113
+ if (opt.silent) {
107
114
  return '<p>An error occurred:</p><pre>'
108
115
  + escape(e.message + '', true)
109
116
  + '</pre>';
@@ -161,9 +168,83 @@ marked.use = function(extension) {
161
168
  }
162
169
  opts.tokenizer = tokenizer;
163
170
  }
171
+ if (extension.walkTokens) {
172
+ const walkTokens = marked.defaults.walkTokens;
173
+ opts.walkTokens = (token) => {
174
+ extension.walkTokens(token);
175
+ if (walkTokens) {
176
+ walkTokens(token);
177
+ }
178
+ };
179
+ }
164
180
  marked.setOptions(opts);
165
181
  };
166
182
 
183
+ /**
184
+ * Run callback for every token
185
+ */
186
+
187
+ marked.walkTokens = function(tokens, callback) {
188
+ for (const token of tokens) {
189
+ callback(token);
190
+ switch (token.type) {
191
+ case 'table': {
192
+ for (const cell of token.tokens.header) {
193
+ marked.walkTokens(cell, callback);
194
+ }
195
+ for (const row of token.tokens.cells) {
196
+ for (const cell of row) {
197
+ marked.walkTokens(cell, callback);
198
+ }
199
+ }
200
+ break;
201
+ }
202
+ case 'list': {
203
+ marked.walkTokens(token.items, callback);
204
+ break;
205
+ }
206
+ default: {
207
+ if (token.tokens) {
208
+ marked.walkTokens(token.tokens, callback);
209
+ }
210
+ }
211
+ }
212
+ }
213
+ };
214
+
215
+ /**
216
+ * Parse Inline
217
+ */
218
+ marked.parseInline = function(src, opt) {
219
+ // throw error in case of non string input
220
+ if (typeof src === 'undefined' || src === null) {
221
+ throw new Error('marked.parseInline(): input parameter is undefined or null');
222
+ }
223
+ if (typeof src !== 'string') {
224
+ throw new Error('marked.parseInline(): input parameter is of type '
225
+ + Object.prototype.toString.call(src) + ', string expected');
226
+ }
227
+
228
+ opt = merge({}, marked.defaults, opt || {});
229
+ checkSanitizeDeprecation(opt);
230
+
231
+ try {
232
+ const tokens = Lexer.lexInline(src, opt);
233
+ if (opt.walkTokens) {
234
+ marked.walkTokens(tokens, opt.walkTokens);
235
+ }
236
+ return Parser.parseInline(tokens, opt);
237
+ } catch (e) {
238
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
239
+ if (opt.silent) {
240
+ return '<p>An error occurred:</p><pre>'
241
+ + escape(e.message + '', true)
242
+ + '</pre>';
243
+ }
244
+ throw e;
245
+ }
246
+ };
247
+
167
248
  /**
168
249
  * Expose
169
250
  */
package/src/rules.js CHANGED
@@ -18,9 +18,9 @@ const block = {
18
18
  html: '^ {0,3}(?:' // optional indentation
19
19
  + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
20
20
  + '|comment[^\\n]*(\\n+|$)' // (2)
21
- + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
22
- + '|<![A-Z][\\s\\S]*?>\\n*' // (4)
23
- + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
21
+ + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
22
+ + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
23
+ + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
24
24
  + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
25
25
  + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
26
26
  + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
@@ -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)
@@ -60,7 +60,7 @@ block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
60
60
  + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
61
61
  + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
62
62
  + '|track|ul';
63
- block._comment = /<!--(?!-?>)[\s\S]*?-->/;
63
+ block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
64
64
  block.html = edit(block.html, 'i')
65
65
  .replace('comment', block._comment)
66
66
  .replace('tag', block._tag)
@@ -94,10 +94,10 @@ block.normal = merge({}, block);
94
94
 
95
95
  block.gfm = merge({}, block.normal, {
96
96
  nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
97
- + ' *([-:]+ *\\|[-| :]*)' // Align
97
+ + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
98
98
  + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', // Cells
99
99
  table: '^ *\\|(.+)\\n' // Header
100
- + ' *\\|?( *[-:]+[-| :]*)' // Align
100
+ + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
101
101
  + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
102
102
  });
103
103
 
@@ -168,18 +168,76 @@ 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_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\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: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {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
- inline._punctuation = '!"#$%&\'()*+\\-./:;<=>?@\\[^_{|}~';
182
- 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._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
201
+
202
+ inline.em.start = edit(inline.em.start)
203
+ .replace(/punctuation/g, inline._punctuation)
204
+ .getRegex();
205
+
206
+ inline.em.middle = edit(inline.em.middle)
207
+ .replace(/punctuation/g, inline._punctuation)
208
+ .replace(/overlapSkip/g, inline._overlapSkip)
209
+ .getRegex();
210
+
211
+ inline.em.endAst = edit(inline.em.endAst, 'g')
212
+ .replace(/punctuation/g, inline._punctuation)
213
+ .getRegex();
214
+
215
+ inline.em.endUnd = edit(inline.em.endUnd, 'g')
216
+ .replace(/punctuation/g, inline._punctuation)
217
+ .getRegex();
218
+
219
+ inline.strong.start = edit(inline.strong.start)
220
+ .replace(/punctuation/g, inline._punctuation)
221
+ .getRegex();
222
+
223
+ inline.strong.middle = edit(inline.strong.middle)
224
+ .replace(/punctuation/g, inline._punctuation)
225
+ .replace(/overlapSkip/g, inline._overlapSkip)
226
+ .getRegex();
227
+
228
+ inline.strong.endAst = edit(inline.strong.endAst, 'g')
229
+ .replace(/punctuation/g, inline._punctuation)
230
+ .getRegex();
231
+
232
+ inline.strong.endUnd = edit(inline.strong.endUnd, 'g')
233
+ .replace(/punctuation/g, inline._punctuation)
234
+ .getRegex();
235
+
236
+ inline.blockSkip = edit(inline._blockSkip, 'g')
237
+ .getRegex();
238
+
239
+ inline.overlapSkip = edit(inline._overlapSkip, 'g')
240
+ .getRegex();
183
241
 
184
242
  inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
185
243
 
@@ -193,11 +251,11 @@ inline.autolink = edit(inline.autolink)
193
251
  inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
194
252
 
195
253
  inline.tag = edit(inline.tag)
196
- .replace('comment', block._comment)
254
+ .replace('comment', inline._comment)
197
255
  .replace('attribute', inline._attribute)
198
256
  .getRegex();
199
257
 
200
- inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
258
+ inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
201
259
  inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
202
260
  inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
203
261
 
@@ -211,6 +269,11 @@ inline.reflink = edit(inline.reflink)
211
269
  .replace('label', inline._label)
212
270
  .getRegex();
213
271
 
272
+ inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
273
+ .replace('reflink', inline.reflink)
274
+ .replace('nolink', inline.nolink)
275
+ .getRegex();
276
+
214
277
  /**
215
278
  * Normal Inline Grammar
216
279
  */
@@ -222,8 +285,18 @@ inline.normal = merge({}, inline);
222
285
  */
223
286
 
224
287
  inline.pedantic = merge({}, inline.normal, {
225
- strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
226
- em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
288
+ strong: {
289
+ start: /^__|\*\*/,
290
+ middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
291
+ endAst: /\*\*(?!\*)/g,
292
+ endUnd: /__(?!_)/g
293
+ },
294
+ em: {
295
+ start: /^_|\*/,
296
+ middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
297
+ endAst: /\*(?!\*)/g,
298
+ endUnd: /_(?!_)/g
299
+ },
227
300
  link: edit(/^!?\[(label)\]\((.*?)\)/)
228
301
  .replace('label', inline._label)
229
302
  .getRegex(),
@@ -242,7 +315,7 @@ inline.gfm = merge({}, inline.normal, {
242
315
  url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
243
316
  _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
244
317
  del: /^~+(?=\S)([\s\S]*?\S)~+/,
245
- text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
318
+ text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
246
319
  });
247
320
 
248
321
  inline.gfm.url = edit(inline.gfm.url, 'i')