marked 0.3.17 → 0.5.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * marked - a markdown parser
3
3
  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4
- * https://github.com/chjj/marked
4
+ * https://github.com/markedjs/marked
5
5
  */
6
6
 
7
7
  ;(function(root) {
@@ -16,20 +16,29 @@ var block = {
16
16
  code: /^( {4}[^\n]+\n*)+/,
17
17
  fences: noop,
18
18
  hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
19
- heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
19
+ heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
20
20
  nptable: noop,
21
21
  blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
22
22
  list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
23
- html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
23
+ html: '^ {0,3}(?:' // optional indentation
24
+ + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
25
+ + '|comment[^\\n]*(\\n+|$)' // (2)
26
+ + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
27
+ + '|<![A-Z][\\s\\S]*?>\\n*' // (4)
28
+ + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
29
+ + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
30
+ + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
31
+ + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
32
+ + ')',
24
33
  def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
25
34
  table: noop,
26
35
  lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
27
- paragraph: /^([^\n]+(?:\n?(?!hr|heading|lheading| {0,3}>|tag)[^\n]+)+)/,
36
+ paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,
28
37
  text: /^[^\n]+/
29
38
  };
30
39
 
31
- block._label = /(?:\\[\[\]]|[^\[\]])+/;
32
- block._title = /(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/;
40
+ block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
41
+ block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
33
42
  block.def = edit(block.def)
34
43
  .replace('label', block._label)
35
44
  .replace('title', block._title)
@@ -47,23 +56,24 @@ block.list = edit(block.list)
47
56
  .replace('def', '\\n+(?=' + block.def.source + ')')
48
57
  .getRegex();
49
58
 
50
- block._tag = '(?!(?:'
51
- + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
52
- + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
53
- + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b';
54
-
55
- block.html = edit(block.html)
56
- .replace('comment', /<!--[\s\S]*?-->/)
57
- .replace('closed', /<(tag)[\s\S]+?<\/\1>/)
58
- .replace('closing', /<tag(?:"[^"]*"|'[^']*'|\s[^'"\/>\s]*)*?\/?>/)
59
- .replace(/tag/g, block._tag)
59
+ block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
60
+ + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
61
+ + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
62
+ + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
63
+ + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
64
+ + '|track|ul';
65
+ block._comment = /<!--(?!-?>)[\s\S]*?-->/;
66
+ block.html = edit(block.html, 'i')
67
+ .replace('comment', block._comment)
68
+ .replace('tag', block._tag)
69
+ .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
60
70
  .getRegex();
61
71
 
62
72
  block.paragraph = edit(block.paragraph)
63
73
  .replace('hr', block.hr)
64
74
  .replace('heading', block.heading)
65
75
  .replace('lheading', block.lheading)
66
- .replace('tag', '<' + block._tag)
76
+ .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
67
77
  .getRegex();
68
78
 
69
79
  block.blockquote = edit(block.blockquote)
@@ -97,8 +107,26 @@ block.gfm.paragraph = edit(block.paragraph)
97
107
  */
98
108
 
99
109
  block.tables = merge({}, block.gfm, {
100
- nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
101
- table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
110
+ nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,
111
+ table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/
112
+ });
113
+
114
+ /**
115
+ * Pedantic grammar
116
+ */
117
+
118
+ block.pedantic = merge({}, block.normal, {
119
+ html: edit(
120
+ '^ *(?:comment *(?:\\n|\\s*$)'
121
+ + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
122
+ + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
123
+ .replace('comment', block._comment)
124
+ .replace(/tag/g, '(?!(?:'
125
+ + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
126
+ + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
127
+ + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
128
+ .getRegex(),
129
+ def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/
102
130
  });
103
131
 
104
132
  /**
@@ -107,11 +135,13 @@ block.tables = merge({}, block.gfm, {
107
135
 
108
136
  function Lexer(options) {
109
137
  this.tokens = [];
110
- this.tokens.links = {};
138
+ this.tokens.links = Object.create(null);
111
139
  this.options = options || marked.defaults;
112
140
  this.rules = block.normal;
113
141
 
114
- if (this.options.gfm) {
142
+ if (this.options.pedantic) {
143
+ this.rules = block.pedantic;
144
+ } else if (this.options.gfm) {
115
145
  if (this.options.tables) {
116
146
  this.rules = block.tables;
117
147
  } else {
@@ -161,10 +191,16 @@ Lexer.prototype.token = function(src, top) {
161
191
  bull,
162
192
  b,
163
193
  item,
194
+ listStart,
195
+ listItems,
196
+ t,
164
197
  space,
165
198
  i,
166
199
  tag,
167
- l;
200
+ l,
201
+ isordered,
202
+ istask,
203
+ ischecked;
168
204
 
169
205
  while (src) {
170
206
  // newline
@@ -184,7 +220,7 @@ Lexer.prototype.token = function(src, top) {
184
220
  this.tokens.push({
185
221
  type: 'code',
186
222
  text: !this.options.pedantic
187
- ? cap.replace(/\n+$/, '')
223
+ ? rtrim(cap, '\n')
188
224
  : cap
189
225
  });
190
226
  continue;
@@ -214,34 +250,36 @@ Lexer.prototype.token = function(src, top) {
214
250
 
215
251
  // table no leading pipe (gfm)
216
252
  if (top && (cap = this.rules.nptable.exec(src))) {
217
- src = src.substring(cap[0].length);
218
-
219
253
  item = {
220
254
  type: 'table',
221
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
255
+ header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
222
256
  align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
223
- cells: cap[3].replace(/\n$/, '').split('\n')
257
+ cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
224
258
  };
225
259
 
226
- for (i = 0; i < item.align.length; i++) {
227
- if (/^ *-+: *$/.test(item.align[i])) {
228
- item.align[i] = 'right';
229
- } else if (/^ *:-+: *$/.test(item.align[i])) {
230
- item.align[i] = 'center';
231
- } else if (/^ *:-+ *$/.test(item.align[i])) {
232
- item.align[i] = 'left';
233
- } else {
234
- item.align[i] = null;
260
+ if (item.header.length === item.align.length) {
261
+ src = src.substring(cap[0].length);
262
+
263
+ for (i = 0; i < item.align.length; i++) {
264
+ if (/^ *-+: *$/.test(item.align[i])) {
265
+ item.align[i] = 'right';
266
+ } else if (/^ *:-+: *$/.test(item.align[i])) {
267
+ item.align[i] = 'center';
268
+ } else if (/^ *:-+ *$/.test(item.align[i])) {
269
+ item.align[i] = 'left';
270
+ } else {
271
+ item.align[i] = null;
272
+ }
235
273
  }
236
- }
237
274
 
238
- for (i = 0; i < item.cells.length; i++) {
239
- item.cells[i] = item.cells[i].split(/ *\| */);
240
- }
275
+ for (i = 0; i < item.cells.length; i++) {
276
+ item.cells[i] = splitCells(item.cells[i], item.header.length);
277
+ }
241
278
 
242
- this.tokens.push(item);
279
+ this.tokens.push(item);
243
280
 
244
- continue;
281
+ continue;
282
+ }
245
283
  }
246
284
 
247
285
  // hr
@@ -279,15 +317,21 @@ Lexer.prototype.token = function(src, top) {
279
317
  if (cap = this.rules.list.exec(src)) {
280
318
  src = src.substring(cap[0].length);
281
319
  bull = cap[2];
320
+ isordered = bull.length > 1;
282
321
 
283
- this.tokens.push({
322
+ listStart = {
284
323
  type: 'list_start',
285
- ordered: bull.length > 1
286
- });
324
+ ordered: isordered,
325
+ start: isordered ? +bull : '',
326
+ loose: false
327
+ };
328
+
329
+ this.tokens.push(listStart);
287
330
 
288
331
  // Get each top-level item.
289
332
  cap = cap[0].match(this.rules.item);
290
333
 
334
+ listItems = [];
291
335
  next = false;
292
336
  l = cap.length;
293
337
  i = 0;
@@ -328,11 +372,27 @@ Lexer.prototype.token = function(src, top) {
328
372
  if (!loose) loose = next;
329
373
  }
330
374
 
331
- this.tokens.push({
332
- type: loose
333
- ? 'loose_item_start'
334
- : 'list_item_start'
335
- });
375
+ if (loose) {
376
+ listStart.loose = true;
377
+ }
378
+
379
+ // Check for task list items
380
+ istask = /^\[[ xX]\] /.test(item);
381
+ ischecked = undefined;
382
+ if (istask) {
383
+ ischecked = item[1] !== ' ';
384
+ item = item.replace(/^\[[ xX]\] +/, '');
385
+ }
386
+
387
+ t = {
388
+ type: 'list_item_start',
389
+ task: istask,
390
+ checked: ischecked,
391
+ loose: loose
392
+ };
393
+
394
+ listItems.push(t);
395
+ this.tokens.push(t);
336
396
 
337
397
  // Recurse.
338
398
  this.token(item, false);
@@ -342,6 +402,14 @@ Lexer.prototype.token = function(src, top) {
342
402
  });
343
403
  }
344
404
 
405
+ if (listStart.loose) {
406
+ l = listItems.length;
407
+ i = 0;
408
+ for (; i < l; i++) {
409
+ listItems[i].loose = true;
410
+ }
411
+ }
412
+
345
413
  this.tokens.push({
346
414
  type: 'list_end'
347
415
  });
@@ -367,7 +435,7 @@ Lexer.prototype.token = function(src, top) {
367
435
  if (top && (cap = this.rules.def.exec(src))) {
368
436
  src = src.substring(cap[0].length);
369
437
  if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
370
- tag = cap[1].toLowerCase();
438
+ tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
371
439
  if (!this.tokens.links[tag]) {
372
440
  this.tokens.links[tag] = {
373
441
  href: cap[2],
@@ -379,36 +447,38 @@ Lexer.prototype.token = function(src, top) {
379
447
 
380
448
  // table (gfm)
381
449
  if (top && (cap = this.rules.table.exec(src))) {
382
- src = src.substring(cap[0].length);
383
-
384
450
  item = {
385
451
  type: 'table',
386
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
452
+ header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
387
453
  align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
388
- cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
454
+ cells: cap[3] ? cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') : []
389
455
  };
390
456
 
391
- for (i = 0; i < item.align.length; i++) {
392
- if (/^ *-+: *$/.test(item.align[i])) {
393
- item.align[i] = 'right';
394
- } else if (/^ *:-+: *$/.test(item.align[i])) {
395
- item.align[i] = 'center';
396
- } else if (/^ *:-+ *$/.test(item.align[i])) {
397
- item.align[i] = 'left';
398
- } else {
399
- item.align[i] = null;
457
+ if (item.header.length === item.align.length) {
458
+ src = src.substring(cap[0].length);
459
+
460
+ for (i = 0; i < item.align.length; i++) {
461
+ if (/^ *-+: *$/.test(item.align[i])) {
462
+ item.align[i] = 'right';
463
+ } else if (/^ *:-+: *$/.test(item.align[i])) {
464
+ item.align[i] = 'center';
465
+ } else if (/^ *:-+ *$/.test(item.align[i])) {
466
+ item.align[i] = 'left';
467
+ } else {
468
+ item.align[i] = null;
469
+ }
400
470
  }
401
- }
402
471
 
403
- for (i = 0; i < item.cells.length; i++) {
404
- item.cells[i] = item.cells[i]
405
- .replace(/^ *\| *| *\| *$/g, '')
406
- .split(/ *\| */);
407
- }
472
+ for (i = 0; i < item.cells.length; i++) {
473
+ item.cells[i] = splitCells(
474
+ item.cells[i].replace(/^ *\| *| *\| *$/g, ''),
475
+ item.header.length);
476
+ }
408
477
 
409
- this.tokens.push(item);
478
+ this.tokens.push(item);
410
479
 
411
- continue;
480
+ continue;
481
+ }
412
482
  }
413
483
 
414
484
  // lheading
@@ -458,39 +528,54 @@ Lexer.prototype.token = function(src, top) {
458
528
  */
459
529
 
460
530
  var inline = {
461
- escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
531
+ escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
462
532
  autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
463
533
  url: noop,
464
- tag: /^<!--[\s\S]*?-->|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/\s]*)*?\/?>/,
465
- link: /^!?\[(inside)\]\(href\)/,
466
- reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
467
- nolink: /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\]/,
468
- strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
469
- em: /^_([^\s_](?:[^_]|__)+?[^\s_])_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)/,
534
+ tag: '^comment'
535
+ + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
536
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
537
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
538
+ + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
539
+ + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
540
+ link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,
541
+ reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
542
+ nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
543
+ strong: /^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
544
+ em: /^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
470
545
  code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,
471
- br: /^ {2,}\n(?!\s*$)/,
546
+ br: /^( {2,}|\\)\n(?!\s*$)/,
472
547
  del: noop,
473
548
  text: /^[\s\S]+?(?=[\\<!\[`*]|\b_| {2,}\n|$)/
474
549
  };
475
550
 
551
+ inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
552
+
476
553
  inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
477
554
  inline._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])?)+(?![-_])/;
478
-
479
555
  inline.autolink = edit(inline.autolink)
480
556
  .replace('scheme', inline._scheme)
481
557
  .replace('email', inline._email)
482
- .getRegex()
558
+ .getRegex();
483
559
 
484
- inline._inside = /(?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]]|\](?=[^\[]*\]))*/;
485
- inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
560
+ inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
561
+
562
+ inline.tag = edit(inline.tag)
563
+ .replace('comment', block._comment)
564
+ .replace('attribute', inline._attribute)
565
+ .getRegex();
566
+
567
+ inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
568
+ inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/;
569
+ inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
486
570
 
487
571
  inline.link = edit(inline.link)
488
- .replace('inside', inline._inside)
572
+ .replace('label', inline._label)
489
573
  .replace('href', inline._href)
574
+ .replace('title', inline._title)
490
575
  .getRegex();
491
576
 
492
577
  inline.reflink = edit(inline.reflink)
493
- .replace('inside', inline._inside)
578
+ .replace('label', inline._label)
494
579
  .getRegex();
495
580
 
496
581
  /**
@@ -505,7 +590,13 @@ inline.normal = merge({}, inline);
505
590
 
506
591
  inline.pedantic = merge({}, inline.normal, {
507
592
  strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
508
- em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
593
+ em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
594
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
595
+ .replace('label', inline._label)
596
+ .getRegex(),
597
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
598
+ .replace('label', inline._label)
599
+ .getRegex()
509
600
  });
510
601
 
511
602
  /**
@@ -518,7 +609,7 @@ inline.gfm = merge({}, inline.normal, {
518
609
  .replace('email', inline._email)
519
610
  .getRegex(),
520
611
  _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
521
- del: /^~~(?=\S)([\s\S]*?\S)~~/,
612
+ del: /^~+(?=\S)([\s\S]*?\S)~+/,
522
613
  text: edit(inline.text)
523
614
  .replace(']|', '~]|')
524
615
  .replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|')
@@ -549,14 +640,14 @@ function InlineLexer(links, options) {
549
640
  throw new Error('Tokens array requires a `links` property.');
550
641
  }
551
642
 
552
- if (this.options.gfm) {
643
+ if (this.options.pedantic) {
644
+ this.rules = inline.pedantic;
645
+ } else if (this.options.gfm) {
553
646
  if (this.options.breaks) {
554
647
  this.rules = inline.breaks;
555
648
  } else {
556
649
  this.rules = inline.gfm;
557
650
  }
558
- } else if (this.options.pedantic) {
559
- this.rules = inline.pedantic;
560
651
  }
561
652
  }
562
653
 
@@ -584,7 +675,9 @@ InlineLexer.prototype.output = function(src) {
584
675
  link,
585
676
  text,
586
677
  href,
587
- cap;
678
+ title,
679
+ cap,
680
+ prevCapZero;
588
681
 
589
682
  while (src) {
590
683
  // escape
@@ -610,7 +703,10 @@ InlineLexer.prototype.output = function(src) {
610
703
 
611
704
  // url (gfm)
612
705
  if (!this.inLink && (cap = this.rules.url.exec(src))) {
613
- cap[0] = this.rules._backpedal.exec(cap[0])[0];
706
+ do {
707
+ prevCapZero = cap[0];
708
+ cap[0] = this.rules._backpedal.exec(cap[0])[0];
709
+ } while (prevCapZero !== cap[0]);
614
710
  src = src.substring(cap[0].length);
615
711
  if (cap[2] === '@') {
616
712
  text = escape(cap[0]);
@@ -647,9 +743,23 @@ InlineLexer.prototype.output = function(src) {
647
743
  if (cap = this.rules.link.exec(src)) {
648
744
  src = src.substring(cap[0].length);
649
745
  this.inLink = true;
746
+ href = cap[2];
747
+ if (this.options.pedantic) {
748
+ link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
749
+
750
+ if (link) {
751
+ href = link[1];
752
+ title = link[3];
753
+ } else {
754
+ title = '';
755
+ }
756
+ } else {
757
+ title = cap[3] ? cap[3].slice(1, -1) : '';
758
+ }
759
+ href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
650
760
  out += this.outputLink(cap, {
651
- href: cap[2],
652
- title: cap[3]
761
+ href: InlineLexer.escapes(href),
762
+ title: InlineLexer.escapes(title)
653
763
  });
654
764
  this.inLink = false;
655
765
  continue;
@@ -675,14 +785,14 @@ InlineLexer.prototype.output = function(src) {
675
785
  // strong
676
786
  if (cap = this.rules.strong.exec(src)) {
677
787
  src = src.substring(cap[0].length);
678
- out += this.renderer.strong(this.output(cap[2] || cap[1]));
788
+ out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1]));
679
789
  continue;
680
790
  }
681
791
 
682
792
  // em
683
793
  if (cap = this.rules.em.exec(src)) {
684
794
  src = src.substring(cap[0].length);
685
- out += this.renderer.em(this.output(cap[2] || cap[1]));
795
+ out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]));
686
796
  continue;
687
797
  }
688
798
 
@@ -722,12 +832,16 @@ InlineLexer.prototype.output = function(src) {
722
832
  return out;
723
833
  };
724
834
 
835
+ InlineLexer.escapes = function(text) {
836
+ return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
837
+ }
838
+
725
839
  /**
726
840
  * Compile Link
727
841
  */
728
842
 
729
843
  InlineLexer.prototype.outputLink = function(cap, link) {
730
- var href = escape(link.href),
844
+ var href = link.href,
731
845
  title = link.title ? escape(link.title) : null;
732
846
 
733
847
  return cap[0].charAt(0) !== '!'
@@ -785,7 +899,7 @@ InlineLexer.prototype.mangle = function(text) {
785
899
  */
786
900
 
787
901
  function Renderer(options) {
788
- this.options = options || {};
902
+ this.options = options || marked.defaults;
789
903
  }
790
904
 
791
905
  Renderer.prototype.code = function(code, lang, escaped) {
@@ -800,7 +914,7 @@ Renderer.prototype.code = function(code, lang, escaped) {
800
914
  if (!lang) {
801
915
  return '<pre><code>'
802
916
  + (escaped ? code : escape(code, true))
803
- + '\n</code></pre>';
917
+ + '</code></pre>';
804
918
  }
805
919
 
806
920
  return '<pre><code class="'
@@ -808,7 +922,7 @@ Renderer.prototype.code = function(code, lang, escaped) {
808
922
  + escape(lang, true)
809
923
  + '">'
810
924
  + (escaped ? code : escape(code, true))
811
- + '\n</code></pre>\n';
925
+ + '</code></pre>\n';
812
926
  };
813
927
 
814
928
  Renderer.prototype.blockquote = function(quote) {
@@ -820,43 +934,56 @@ Renderer.prototype.html = function(html) {
820
934
  };
821
935
 
822
936
  Renderer.prototype.heading = function(text, level, raw) {
823
- return '<h'
824
- + level
825
- + ' id="'
826
- + this.options.headerPrefix
827
- + raw.toLowerCase().replace(/[^\w]+/g, '-')
828
- + '">'
829
- + text
830
- + '</h'
831
- + level
832
- + '>\n';
937
+ if (this.options.headerIds) {
938
+ return '<h'
939
+ + level
940
+ + ' id="'
941
+ + this.options.headerPrefix
942
+ + raw.toLowerCase().replace(/[^\w]+/g, '-')
943
+ + '">'
944
+ + text
945
+ + '</h'
946
+ + level
947
+ + '>\n';
948
+ }
949
+ // ignore IDs
950
+ return '<h' + level + '>' + text + '</h' + level + '>\n';
833
951
  };
834
952
 
835
953
  Renderer.prototype.hr = function() {
836
954
  return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
837
955
  };
838
956
 
839
- Renderer.prototype.list = function(body, ordered) {
840
- var type = ordered ? 'ol' : 'ul';
841
- return '<' + type + '>\n' + body + '</' + type + '>\n';
957
+ Renderer.prototype.list = function(body, ordered, start) {
958
+ var type = ordered ? 'ol' : 'ul',
959
+ startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
960
+ return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
842
961
  };
843
962
 
844
963
  Renderer.prototype.listitem = function(text) {
845
964
  return '<li>' + text + '</li>\n';
846
965
  };
847
966
 
967
+ Renderer.prototype.checkbox = function(checked) {
968
+ return '<input '
969
+ + (checked ? 'checked="" ' : '')
970
+ + 'disabled="" type="checkbox"'
971
+ + (this.options.xhtml ? ' /' : '')
972
+ + '> ';
973
+ }
974
+
848
975
  Renderer.prototype.paragraph = function(text) {
849
976
  return '<p>' + text + '</p>\n';
850
977
  };
851
978
 
852
979
  Renderer.prototype.table = function(header, body) {
980
+ if (body) body = '<tbody>' + body + '</tbody>';
981
+
853
982
  return '<table>\n'
854
983
  + '<thead>\n'
855
984
  + header
856
985
  + '</thead>\n'
857
- + '<tbody>\n'
858
986
  + body
859
- + '</tbody>\n'
860
987
  + '</table>\n';
861
988
  };
862
989
 
@@ -867,7 +994,7 @@ Renderer.prototype.tablerow = function(content) {
867
994
  Renderer.prototype.tablecell = function(content, flags) {
868
995
  var type = flags.header ? 'th' : 'td';
869
996
  var tag = flags.align
870
- ? '<' + type + ' style="text-align:' + flags.align + '">'
997
+ ? '<' + type + ' align="' + flags.align + '">'
871
998
  : '<' + type + '>';
872
999
  return tag + content + '</' + type + '>\n';
873
1000
  };
@@ -909,7 +1036,12 @@ Renderer.prototype.link = function(href, title, text) {
909
1036
  if (this.options.baseUrl && !originIndependentUrl.test(href)) {
910
1037
  href = resolveUrl(this.options.baseUrl, href);
911
1038
  }
912
- var out = '<a href="' + href + '"';
1039
+ try {
1040
+ href = encodeURI(href).replace(/%25/g, '%');
1041
+ } catch (e) {
1042
+ return text;
1043
+ }
1044
+ var out = '<a href="' + escape(href) + '"';
913
1045
  if (title) {
914
1046
  out += ' title="' + title + '"';
915
1047
  }
@@ -1099,39 +1231,34 @@ Parser.prototype.tok = function() {
1099
1231
  }
1100
1232
  case 'list_start': {
1101
1233
  body = '';
1102
- var ordered = this.token.ordered;
1234
+ var ordered = this.token.ordered,
1235
+ start = this.token.start;
1103
1236
 
1104
1237
  while (this.next().type !== 'list_end') {
1105
1238
  body += this.tok();
1106
1239
  }
1107
1240
 
1108
- return this.renderer.list(body, ordered);
1241
+ return this.renderer.list(body, ordered, start);
1109
1242
  }
1110
1243
  case 'list_item_start': {
1111
1244
  body = '';
1245
+ var loose = this.token.loose;
1112
1246
 
1113
- while (this.next().type !== 'list_item_end') {
1114
- body += this.token.type === 'text'
1115
- ? this.parseText()
1116
- : this.tok();
1247
+ if (this.token.task) {
1248
+ body += this.renderer.checkbox(this.token.checked);
1117
1249
  }
1118
1250
 
1119
- return this.renderer.listitem(body);
1120
- }
1121
- case 'loose_item_start': {
1122
- body = '';
1123
-
1124
1251
  while (this.next().type !== 'list_item_end') {
1125
- body += this.tok();
1252
+ body += !loose && this.token.type === 'text'
1253
+ ? this.parseText()
1254
+ : this.tok();
1126
1255
  }
1127
1256
 
1128
1257
  return this.renderer.listitem(body);
1129
1258
  }
1130
1259
  case 'html': {
1131
- var html = !this.token.pre && !this.options.pedantic
1132
- ? this.inline.output(this.token.text)
1133
- : this.token.text;
1134
- return this.renderer.html(html);
1260
+ // TODO parse inline content if parameter markdown=1
1261
+ return this.renderer.html(this.token.text);
1135
1262
  }
1136
1263
  case 'paragraph': {
1137
1264
  return this.renderer.paragraph(this.inline.output(this.token.text));
@@ -1170,7 +1297,7 @@ function unescape(html) {
1170
1297
  }
1171
1298
 
1172
1299
  function edit(regex, opt) {
1173
- regex = regex.source;
1300
+ regex = regex.source || regex;
1174
1301
  opt = opt || '';
1175
1302
  return {
1176
1303
  replace: function(name, val) {
@@ -1193,7 +1320,7 @@ function resolveUrl(base, href) {
1193
1320
  if (/^[^:]+:\/*[^/]*$/.test(base)) {
1194
1321
  baseUrls[' ' + base] = base + '/';
1195
1322
  } else {
1196
- baseUrls[' ' + base] = base.replace(/[^/]*$/, '');
1323
+ baseUrls[' ' + base] = rtrim(base, '/', true);
1197
1324
  }
1198
1325
  }
1199
1326
  base = baseUrls[' ' + base];
@@ -1229,6 +1356,64 @@ function merge(obj) {
1229
1356
  return obj;
1230
1357
  }
1231
1358
 
1359
+ function splitCells(tableRow, count) {
1360
+ // ensure that every cell-delimiting pipe has a space
1361
+ // before it to distinguish it from an escaped pipe
1362
+ var row = tableRow.replace(/\|/g, function (match, offset, str) {
1363
+ var escaped = false,
1364
+ curr = offset;
1365
+ while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
1366
+ if (escaped) {
1367
+ // odd number of slashes means | is escaped
1368
+ // so we leave it alone
1369
+ return '|';
1370
+ } else {
1371
+ // add space before unescaped |
1372
+ return ' |';
1373
+ }
1374
+ }),
1375
+ cells = row.split(/ \|/),
1376
+ i = 0;
1377
+
1378
+ if (cells.length > count) {
1379
+ cells.splice(count);
1380
+ } else {
1381
+ while (cells.length < count) cells.push('');
1382
+ }
1383
+
1384
+ for (; i < cells.length; i++) {
1385
+ // leading or trailing whitespace is ignored per the gfm spec
1386
+ cells[i] = cells[i].trim().replace(/\\\|/g, '|');
1387
+ }
1388
+ return cells;
1389
+ }
1390
+
1391
+ // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
1392
+ // /c*$/ is vulnerable to REDOS.
1393
+ // invert: Remove suffix of non-c chars instead. Default falsey.
1394
+ function rtrim(str, c, invert) {
1395
+ if (str.length === 0) {
1396
+ return '';
1397
+ }
1398
+
1399
+ // Length of suffix matching the invert condition.
1400
+ var suffLen = 0;
1401
+
1402
+ // Step left until we fail to match the invert condition.
1403
+ while (suffLen < str.length) {
1404
+ var currChar = str.charAt(str.length - suffLen - 1);
1405
+ if (currChar === c && !invert) {
1406
+ suffLen++;
1407
+ } else if (currChar !== c && invert) {
1408
+ suffLen++;
1409
+ } else {
1410
+ break;
1411
+ }
1412
+ }
1413
+
1414
+ return str.substr(0, str.length - suffLen);
1415
+ }
1416
+
1232
1417
  /**
1233
1418
  * Marked
1234
1419
  */
@@ -1316,7 +1501,7 @@ function marked(src, opt, callback) {
1316
1501
  if (opt) opt = merge({}, marked.defaults, opt);
1317
1502
  return Parser.parse(Lexer.lex(src, opt), opt);
1318
1503
  } catch (e) {
1319
- e.message += '\nPlease report this to https://github.com/chjj/marked.';
1504
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
1320
1505
  if ((opt || marked.defaults).silent) {
1321
1506
  return '<p>An error occurred:</p><pre>'
1322
1507
  + escape(e.message + '', true)
@@ -1336,24 +1521,29 @@ marked.setOptions = function(opt) {
1336
1521
  return marked;
1337
1522
  };
1338
1523
 
1339
- marked.defaults = {
1340
- gfm: true,
1341
- tables: true,
1342
- breaks: false,
1343
- pedantic: false,
1344
- sanitize: false,
1345
- sanitizer: null,
1346
- mangle: true,
1347
- smartLists: false,
1348
- silent: false,
1349
- highlight: null,
1350
- langPrefix: 'lang-',
1351
- smartypants: false,
1352
- headerPrefix: '',
1353
- renderer: new Renderer(),
1354
- xhtml: false,
1355
- baseUrl: null
1356
- };
1524
+ marked.getDefaults = function () {
1525
+ return {
1526
+ baseUrl: null,
1527
+ breaks: false,
1528
+ gfm: true,
1529
+ headerIds: true,
1530
+ headerPrefix: '',
1531
+ highlight: null,
1532
+ langPrefix: 'language-',
1533
+ mangle: true,
1534
+ pedantic: false,
1535
+ renderer: new Renderer(),
1536
+ sanitize: false,
1537
+ sanitizer: null,
1538
+ silent: false,
1539
+ smartLists: false,
1540
+ smartypants: false,
1541
+ tables: true,
1542
+ xhtml: false
1543
+ };
1544
+ }
1545
+
1546
+ marked.defaults = marked.getDefaults();
1357
1547
 
1358
1548
  /**
1359
1549
  * Expose