marked 0.2.9 → 0.3.2

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,6 +1,6 @@
1
1
  /**
2
2
  * marked - a markdown parser
3
- * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
3
+ * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4
4
  * https://github.com/chjj/marked
5
5
  */
6
6
 
@@ -17,9 +17,9 @@ var block = {
17
17
  hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18
18
  heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
19
19
  nptable: noop,
20
- lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
21
- blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
22
- list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
20
+ lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
21
+ blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
22
+ list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
23
23
  html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
24
24
  def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
25
25
  table: noop,
@@ -35,13 +35,18 @@ block.item = replace(block.item, 'gm')
35
35
 
36
36
  block.list = replace(block.list)
37
37
  (/bull/g, block.bullet)
38
- ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
38
+ ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
39
+ ('def', '\\n+(?=' + block.def.source + ')')
40
+ ();
41
+
42
+ block.blockquote = replace(block.blockquote)
43
+ ('def', block.def)
39
44
  ();
40
45
 
41
46
  block._tag = '(?!(?:'
42
47
  + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
43
48
  + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
44
- + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
49
+ + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
45
50
 
46
51
  block.html = replace(block.html)
47
52
  ('comment', /<!--[\s\S]*?-->/)
@@ -75,7 +80,9 @@ block.gfm = merge({}, block.normal, {
75
80
  });
76
81
 
77
82
  block.gfm.paragraph = replace(block.paragraph)
78
- ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
83
+ ('(?!', '(?!'
84
+ + block.gfm.fences.source.replace('\\1', '\\2') + '|'
85
+ + block.list.source.replace('\\1', '\\3') + '|')
79
86
  ();
80
87
 
81
88
  /**
@@ -139,7 +146,7 @@ Lexer.prototype.lex = function(src) {
139
146
  * Lexing
140
147
  */
141
148
 
142
- Lexer.prototype.token = function(src, top) {
149
+ Lexer.prototype.token = function(src, top, bq) {
143
150
  var src = src.replace(/^ +$/gm, '')
144
151
  , next
145
152
  , loose
@@ -262,7 +269,7 @@ Lexer.prototype.token = function(src, top) {
262
269
  // Pass `top` to keep the current
263
270
  // "toplevel" state. This is exactly
264
271
  // how markdown.pl works.
265
- this.token(cap, top);
272
+ this.token(cap, top, true);
266
273
 
267
274
  this.tokens.push({
268
275
  type: 'blockquote_end'
@@ -308,7 +315,7 @@ Lexer.prototype.token = function(src, top) {
308
315
  // Determine whether the next list item belongs here.
309
316
  // Backpedal if it does not belong in this list.
310
317
  if (this.options.smartLists && i !== l - 1) {
311
- b = block.bullet.exec(cap[i+1])[0];
318
+ b = block.bullet.exec(cap[i + 1])[0];
312
319
  if (bull !== b && !(bull.length > 1 && b.length > 1)) {
313
320
  src = cap.slice(i + 1).join('\n') + src;
314
321
  i = l - 1;
@@ -320,7 +327,7 @@ Lexer.prototype.token = function(src, top) {
320
327
  // for discount behavior.
321
328
  loose = next || /\n\n(?!\s*$)/.test(item);
322
329
  if (i !== l - 1) {
323
- next = item[item.length-1] === '\n';
330
+ next = item.charAt(item.length - 1) === '\n';
324
331
  if (!loose) loose = next;
325
332
  }
326
333
 
@@ -331,7 +338,7 @@ Lexer.prototype.token = function(src, top) {
331
338
  });
332
339
 
333
340
  // Recurse.
334
- this.token(item, false);
341
+ this.token(item, false, bq);
335
342
 
336
343
  this.tokens.push({
337
344
  type: 'list_item_end'
@@ -352,14 +359,14 @@ Lexer.prototype.token = function(src, top) {
352
359
  type: this.options.sanitize
353
360
  ? 'paragraph'
354
361
  : 'html',
355
- pre: cap[1] === 'pre' || cap[1] === 'script',
362
+ pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
356
363
  text: cap[0]
357
364
  });
358
365
  continue;
359
366
  }
360
367
 
361
368
  // def
362
- if (top && (cap = this.rules.def.exec(src))) {
369
+ if ((!bq && top) && (cap = this.rules.def.exec(src))) {
363
370
  src = src.substring(cap[0].length);
364
371
  this.tokens.links[cap[1].toLowerCase()] = {
365
372
  href: cap[2],
@@ -407,7 +414,7 @@ Lexer.prototype.token = function(src, top) {
407
414
  src = src.substring(cap[0].length);
408
415
  this.tokens.push({
409
416
  type: 'paragraph',
410
- text: cap[1][cap[1].length-1] === '\n'
417
+ text: cap[1].charAt(cap[1].length - 1) === '\n'
411
418
  ? cap[1].slice(0, -1)
412
419
  : cap[1]
413
420
  });
@@ -454,8 +461,8 @@ var inline = {
454
461
  text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
455
462
  };
456
463
 
457
- inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
458
- inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
464
+ inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
465
+ inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
459
466
 
460
467
  inline.link = replace(inline.link)
461
468
  ('inside', inline._inside)
@@ -512,6 +519,8 @@ function InlineLexer(links, options) {
512
519
  this.options = options || marked.defaults;
513
520
  this.links = links;
514
521
  this.rules = inline.normal;
522
+ this.renderer = this.options.renderer || new Renderer;
523
+ this.renderer.options = this.options;
515
524
 
516
525
  if (!this.links) {
517
526
  throw new
@@ -567,7 +576,7 @@ InlineLexer.prototype.output = function(src) {
567
576
  if (cap = this.rules.autolink.exec(src)) {
568
577
  src = src.substring(cap[0].length);
569
578
  if (cap[2] === '@') {
570
- text = cap[1][6] === ':'
579
+ text = cap[1].charAt(6) === ':'
571
580
  ? this.mangle(cap[1].substring(7))
572
581
  : this.mangle(cap[1]);
573
582
  href = this.mangle('mailto:') + text;
@@ -575,29 +584,26 @@ InlineLexer.prototype.output = function(src) {
575
584
  text = escape(cap[1]);
576
585
  href = text;
577
586
  }
578
- out += '<a href="'
579
- + href
580
- + '">'
581
- + text
582
- + '</a>';
587
+ out += this.renderer.link(href, null, text);
583
588
  continue;
584
589
  }
585
590
 
586
591
  // url (gfm)
587
- if (cap = this.rules.url.exec(src)) {
592
+ if (!this.inLink && (cap = this.rules.url.exec(src))) {
588
593
  src = src.substring(cap[0].length);
589
594
  text = escape(cap[1]);
590
595
  href = text;
591
- out += '<a href="'
592
- + href
593
- + '">'
594
- + text
595
- + '</a>';
596
+ out += this.renderer.link(href, null, text);
596
597
  continue;
597
598
  }
598
599
 
599
600
  // tag
600
601
  if (cap = this.rules.tag.exec(src)) {
602
+ if (!this.inLink && /^<a /i.test(cap[0])) {
603
+ this.inLink = true;
604
+ } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
605
+ this.inLink = false;
606
+ }
601
607
  src = src.substring(cap[0].length);
602
608
  out += this.options.sanitize
603
609
  ? escape(cap[0])
@@ -608,10 +614,12 @@ InlineLexer.prototype.output = function(src) {
608
614
  // link
609
615
  if (cap = this.rules.link.exec(src)) {
610
616
  src = src.substring(cap[0].length);
617
+ this.inLink = true;
611
618
  out += this.outputLink(cap, {
612
619
  href: cap[2],
613
620
  title: cap[3]
614
621
  });
622
+ this.inLink = false;
615
623
  continue;
616
624
  }
617
625
 
@@ -622,54 +630,48 @@ InlineLexer.prototype.output = function(src) {
622
630
  link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
623
631
  link = this.links[link.toLowerCase()];
624
632
  if (!link || !link.href) {
625
- out += cap[0][0];
633
+ out += cap[0].charAt(0);
626
634
  src = cap[0].substring(1) + src;
627
635
  continue;
628
636
  }
637
+ this.inLink = true;
629
638
  out += this.outputLink(cap, link);
639
+ this.inLink = false;
630
640
  continue;
631
641
  }
632
642
 
633
643
  // strong
634
644
  if (cap = this.rules.strong.exec(src)) {
635
645
  src = src.substring(cap[0].length);
636
- out += '<strong>'
637
- + this.output(cap[2] || cap[1])
638
- + '</strong>';
646
+ out += this.renderer.strong(this.output(cap[2] || cap[1]));
639
647
  continue;
640
648
  }
641
649
 
642
650
  // em
643
651
  if (cap = this.rules.em.exec(src)) {
644
652
  src = src.substring(cap[0].length);
645
- out += '<em>'
646
- + this.output(cap[2] || cap[1])
647
- + '</em>';
653
+ out += this.renderer.em(this.output(cap[2] || cap[1]));
648
654
  continue;
649
655
  }
650
656
 
651
657
  // code
652
658
  if (cap = this.rules.code.exec(src)) {
653
659
  src = src.substring(cap[0].length);
654
- out += '<code>'
655
- + escape(cap[2], true)
656
- + '</code>';
660
+ out += this.renderer.codespan(escape(cap[2], true));
657
661
  continue;
658
662
  }
659
663
 
660
664
  // br
661
665
  if (cap = this.rules.br.exec(src)) {
662
666
  src = src.substring(cap[0].length);
663
- out += '<br>';
667
+ out += this.renderer.br();
664
668
  continue;
665
669
  }
666
670
 
667
671
  // del (gfm)
668
672
  if (cap = this.rules.del.exec(src)) {
669
673
  src = src.substring(cap[0].length);
670
- out += '<del>'
671
- + this.output(cap[1])
672
- + '</del>';
674
+ out += this.renderer.del(this.output(cap[1]));
673
675
  continue;
674
676
  }
675
677
 
@@ -694,31 +696,12 @@ InlineLexer.prototype.output = function(src) {
694
696
  */
695
697
 
696
698
  InlineLexer.prototype.outputLink = function(cap, link) {
697
- if (cap[0][0] !== '!') {
698
- return '<a href="'
699
- + escape(link.href)
700
- + '"'
701
- + (link.title
702
- ? ' title="'
703
- + escape(link.title)
704
- + '"'
705
- : '')
706
- + '>'
707
- + this.output(cap[1])
708
- + '</a>';
709
- } else {
710
- return '<img src="'
711
- + escape(link.href)
712
- + '" alt="'
713
- + escape(cap[1])
714
- + '"'
715
- + (link.title
716
- ? ' title="'
717
- + escape(link.title)
718
- + '"'
719
- : '')
720
- + '>';
721
- }
699
+ var href = escape(link.href)
700
+ , title = link.title ? escape(link.title) : null;
701
+
702
+ return cap[0].charAt(0) !== '!'
703
+ ? this.renderer.link(href, title, this.output(cap[1]))
704
+ : this.renderer.image(href, title, escape(cap[1]));
722
705
  };
723
706
 
724
707
  /**
@@ -728,9 +711,17 @@ InlineLexer.prototype.outputLink = function(cap, link) {
728
711
  InlineLexer.prototype.smartypants = function(text) {
729
712
  if (!this.options.smartypants) return text;
730
713
  return text
714
+ // em-dashes
731
715
  .replace(/--/g, '\u2014')
732
- .replace(/'([^']*)'/g, '\u2018$1\u2019')
733
- .replace(/"([^"]*)"/g, '\u201C$1\u201D')
716
+ // opening singles
717
+ .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
718
+ // closing singles & apostrophes
719
+ .replace(/'/g, '\u2019')
720
+ // opening doubles
721
+ .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
722
+ // closing doubles
723
+ .replace(/"/g, '\u201d')
724
+ // ellipses
734
725
  .replace(/\.{3}/g, '\u2026');
735
726
  };
736
727
 
@@ -755,6 +746,149 @@ InlineLexer.prototype.mangle = function(text) {
755
746
  return out;
756
747
  };
757
748
 
749
+ /**
750
+ * Renderer
751
+ */
752
+
753
+ function Renderer(options) {
754
+ this.options = options || {};
755
+ }
756
+
757
+ Renderer.prototype.code = function(code, lang, escaped) {
758
+ if (this.options.highlight) {
759
+ var out = this.options.highlight(code, lang);
760
+ if (out != null && out !== code) {
761
+ escaped = true;
762
+ code = out;
763
+ }
764
+ }
765
+
766
+ if (!lang) {
767
+ return '<pre><code>'
768
+ + (escaped ? code : escape(code, true))
769
+ + '\n</code></pre>';
770
+ }
771
+
772
+ return '<pre><code class="'
773
+ + this.options.langPrefix
774
+ + escape(lang, true)
775
+ + '">'
776
+ + (escaped ? code : escape(code, true))
777
+ + '\n</code></pre>\n';
778
+ };
779
+
780
+ Renderer.prototype.blockquote = function(quote) {
781
+ return '<blockquote>\n' + quote + '</blockquote>\n';
782
+ };
783
+
784
+ Renderer.prototype.html = function(html) {
785
+ return html;
786
+ };
787
+
788
+ Renderer.prototype.heading = function(text, level, raw) {
789
+ return '<h'
790
+ + level
791
+ + ' id="'
792
+ + this.options.headerPrefix
793
+ + raw.toLowerCase().replace(/[^\w]+/g, '-')
794
+ + '">'
795
+ + text
796
+ + '</h'
797
+ + level
798
+ + '>\n';
799
+ };
800
+
801
+ Renderer.prototype.hr = function() {
802
+ return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
803
+ };
804
+
805
+ Renderer.prototype.list = function(body, ordered) {
806
+ var type = ordered ? 'ol' : 'ul';
807
+ return '<' + type + '>\n' + body + '</' + type + '>\n';
808
+ };
809
+
810
+ Renderer.prototype.listitem = function(text) {
811
+ return '<li>' + text + '</li>\n';
812
+ };
813
+
814
+ Renderer.prototype.paragraph = function(text) {
815
+ return '<p>' + text + '</p>\n';
816
+ };
817
+
818
+ Renderer.prototype.table = function(header, body) {
819
+ return '<table>\n'
820
+ + '<thead>\n'
821
+ + header
822
+ + '</thead>\n'
823
+ + '<tbody>\n'
824
+ + body
825
+ + '</tbody>\n'
826
+ + '</table>\n';
827
+ };
828
+
829
+ Renderer.prototype.tablerow = function(content) {
830
+ return '<tr>\n' + content + '</tr>\n';
831
+ };
832
+
833
+ Renderer.prototype.tablecell = function(content, flags) {
834
+ var type = flags.header ? 'th' : 'td';
835
+ var tag = flags.align
836
+ ? '<' + type + ' style="text-align:' + flags.align + '">'
837
+ : '<' + type + '>';
838
+ return tag + content + '</' + type + '>\n';
839
+ };
840
+
841
+ // span level renderer
842
+ Renderer.prototype.strong = function(text) {
843
+ return '<strong>' + text + '</strong>';
844
+ };
845
+
846
+ Renderer.prototype.em = function(text) {
847
+ return '<em>' + text + '</em>';
848
+ };
849
+
850
+ Renderer.prototype.codespan = function(text) {
851
+ return '<code>' + text + '</code>';
852
+ };
853
+
854
+ Renderer.prototype.br = function() {
855
+ return this.options.xhtml ? '<br/>' : '<br>';
856
+ };
857
+
858
+ Renderer.prototype.del = function(text) {
859
+ return '<del>' + text + '</del>';
860
+ };
861
+
862
+ Renderer.prototype.link = function(href, title, text) {
863
+ if (this.options.sanitize) {
864
+ try {
865
+ var prot = decodeURIComponent(unescape(href))
866
+ .replace(/[^\w:]/g, '')
867
+ .toLowerCase();
868
+ } catch (e) {
869
+ return '';
870
+ }
871
+ if (prot.indexOf('javascript:') === 0) {
872
+ return '';
873
+ }
874
+ }
875
+ var out = '<a href="' + href + '"';
876
+ if (title) {
877
+ out += ' title="' + title + '"';
878
+ }
879
+ out += '>' + text + '</a>';
880
+ return out;
881
+ };
882
+
883
+ Renderer.prototype.image = function(href, title, text) {
884
+ var out = '<img src="' + href + '" alt="' + text + '"';
885
+ if (title) {
886
+ out += ' title="' + title + '"';
887
+ }
888
+ out += this.options.xhtml ? '/>' : '>';
889
+ return out;
890
+ };
891
+
758
892
  /**
759
893
  * Parsing & Compiling
760
894
  */
@@ -763,14 +897,17 @@ function Parser(options) {
763
897
  this.tokens = [];
764
898
  this.token = null;
765
899
  this.options = options || marked.defaults;
900
+ this.options.renderer = this.options.renderer || new Renderer;
901
+ this.renderer = this.options.renderer;
902
+ this.renderer.options = this.options;
766
903
  }
767
904
 
768
905
  /**
769
906
  * Static Parse Method
770
907
  */
771
908
 
772
- Parser.parse = function(src, options) {
773
- var parser = new Parser(options);
909
+ Parser.parse = function(src, options, renderer) {
910
+ var parser = new Parser(options, renderer);
774
911
  return parser.parse(src);
775
912
  };
776
913
 
@@ -779,7 +916,7 @@ Parser.parse = function(src, options) {
779
916
  */
780
917
 
781
918
  Parser.prototype.parse = function(src) {
782
- this.inline = new InlineLexer(src.links, this.options);
919
+ this.inline = new InlineLexer(src.links, this.options, this.renderer);
783
920
  this.tokens = src.reverse();
784
921
 
785
922
  var out = '';
@@ -803,7 +940,7 @@ Parser.prototype.next = function() {
803
940
  */
804
941
 
805
942
  Parser.prototype.peek = function() {
806
- return this.tokens[this.tokens.length-1] || 0;
943
+ return this.tokens[this.tokens.length - 1] || 0;
807
944
  };
808
945
 
809
946
  /**
@@ -830,77 +967,53 @@ Parser.prototype.tok = function() {
830
967
  return '';
831
968
  }
832
969
  case 'hr': {
833
- return '<hr>\n';
970
+ return this.renderer.hr();
834
971
  }
835
972
  case 'heading': {
836
- return '<h'
837
- + this.token.depth
838
- + '>'
839
- + this.inline.output(this.token.text)
840
- + '</h'
841
- + this.token.depth
842
- + '>\n';
973
+ return this.renderer.heading(
974
+ this.inline.output(this.token.text),
975
+ this.token.depth,
976
+ this.token.text);
843
977
  }
844
978
  case 'code': {
845
- if (this.options.highlight) {
846
- var code = this.options.highlight(this.token.text, this.token.lang);
847
- if (code != null && code !== this.token.text) {
848
- this.token.escaped = true;
849
- this.token.text = code;
850
- }
851
- }
852
-
853
- if (!this.token.escaped) {
854
- this.token.text = escape(this.token.text, true);
855
- }
856
-
857
- return '<pre><code'
858
- + (this.token.lang
859
- ? ' class="'
860
- + this.options.langPrefix
861
- + this.token.lang
862
- + '"'
863
- : '')
864
- + '>'
865
- + this.token.text
866
- + '</code></pre>\n';
979
+ return this.renderer.code(this.token.text,
980
+ this.token.lang,
981
+ this.token.escaped);
867
982
  }
868
983
  case 'table': {
869
- var body = ''
870
- , heading
984
+ var header = ''
985
+ , body = ''
871
986
  , i
872
987
  , row
873
988
  , cell
989
+ , flags
874
990
  , j;
875
991
 
876
992
  // header
877
- body += '<thead>\n<tr>\n';
993
+ cell = '';
878
994
  for (i = 0; i < this.token.header.length; i++) {
879
- heading = this.inline.output(this.token.header[i]);
880
- body += this.token.align[i]
881
- ? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
882
- : '<th>' + heading + '</th>\n';
995
+ flags = { header: true, align: this.token.align[i] };
996
+ cell += this.renderer.tablecell(
997
+ this.inline.output(this.token.header[i]),
998
+ { header: true, align: this.token.align[i] }
999
+ );
883
1000
  }
884
- body += '</tr>\n</thead>\n';
1001
+ header += this.renderer.tablerow(cell);
885
1002
 
886
- // body
887
- body += '<tbody>\n'
888
1003
  for (i = 0; i < this.token.cells.length; i++) {
889
1004
  row = this.token.cells[i];
890
- body += '<tr>\n';
1005
+
1006
+ cell = '';
891
1007
  for (j = 0; j < row.length; j++) {
892
- cell = this.inline.output(row[j]);
893
- body += this.token.align[j]
894
- ? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
895
- : '<td>' + cell + '</td>\n';
1008
+ cell += this.renderer.tablecell(
1009
+ this.inline.output(row[j]),
1010
+ { header: false, align: this.token.align[j] }
1011
+ );
896
1012
  }
897
- body += '</tr>\n';
898
- }
899
- body += '</tbody>\n';
900
1013
 
901
- return '<table>\n'
902
- + body
903
- + '</table>\n';
1014
+ body += this.renderer.tablerow(cell);
1015
+ }
1016
+ return this.renderer.table(header, body);
904
1017
  }
905
1018
  case 'blockquote_start': {
906
1019
  var body = '';
@@ -909,25 +1022,17 @@ Parser.prototype.tok = function() {
909
1022
  body += this.tok();
910
1023
  }
911
1024
 
912
- return '<blockquote>\n'
913
- + body
914
- + '</blockquote>\n';
1025
+ return this.renderer.blockquote(body);
915
1026
  }
916
1027
  case 'list_start': {
917
- var type = this.token.ordered ? 'ol' : 'ul'
918
- , body = '';
1028
+ var body = ''
1029
+ , ordered = this.token.ordered;
919
1030
 
920
1031
  while (this.next().type !== 'list_end') {
921
1032
  body += this.tok();
922
1033
  }
923
1034
 
924
- return '<'
925
- + type
926
- + '>\n'
927
- + body
928
- + '</'
929
- + type
930
- + '>\n';
1035
+ return this.renderer.list(body, ordered);
931
1036
  }
932
1037
  case 'list_item_start': {
933
1038
  var body = '';
@@ -938,9 +1043,7 @@ Parser.prototype.tok = function() {
938
1043
  : this.tok();
939
1044
  }
940
1045
 
941
- return '<li>'
942
- + body
943
- + '</li>\n';
1046
+ return this.renderer.listitem(body);
944
1047
  }
945
1048
  case 'loose_item_start': {
946
1049
  var body = '';
@@ -949,24 +1052,19 @@ Parser.prototype.tok = function() {
949
1052
  body += this.tok();
950
1053
  }
951
1054
 
952
- return '<li>'
953
- + body
954
- + '</li>\n';
1055
+ return this.renderer.listitem(body);
955
1056
  }
956
1057
  case 'html': {
957
- return !this.token.pre && !this.options.pedantic
1058
+ var html = !this.token.pre && !this.options.pedantic
958
1059
  ? this.inline.output(this.token.text)
959
1060
  : this.token.text;
1061
+ return this.renderer.html(html);
960
1062
  }
961
1063
  case 'paragraph': {
962
- return '<p>'
963
- + this.inline.output(this.token.text)
964
- + '</p>\n';
1064
+ return this.renderer.paragraph(this.inline.output(this.token.text));
965
1065
  }
966
1066
  case 'text': {
967
- return '<p>'
968
- + this.parseText()
969
- + '</p>\n';
1067
+ return this.renderer.paragraph(this.parseText());
970
1068
  }
971
1069
  }
972
1070
  };
@@ -984,6 +1082,19 @@ function escape(html, encode) {
984
1082
  .replace(/'/g, '&#39;');
985
1083
  }
986
1084
 
1085
+ function unescape(html) {
1086
+ return html.replace(/&([#\w]+);/g, function(_, n) {
1087
+ n = n.toLowerCase();
1088
+ if (n === 'colon') return ':';
1089
+ if (n.charAt(0) === '#') {
1090
+ return n.charAt(1) === 'x'
1091
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
1092
+ : String.fromCharCode(+n.substring(1));
1093
+ }
1094
+ return '';
1095
+ });
1096
+ }
1097
+
987
1098
  function replace(regex, opt) {
988
1099
  regex = regex.source;
989
1100
  opt = opt || '';
@@ -1016,6 +1127,7 @@ function merge(obj) {
1016
1127
  return obj;
1017
1128
  }
1018
1129
 
1130
+
1019
1131
  /**
1020
1132
  * Marked
1021
1133
  */
@@ -1027,7 +1139,7 @@ function marked(src, opt, callback) {
1027
1139
  opt = null;
1028
1140
  }
1029
1141
 
1030
- if (opt) opt = merge({}, marked.defaults, opt);
1142
+ opt = merge({}, marked.defaults, opt || {});
1031
1143
 
1032
1144
  var highlight = opt.highlight
1033
1145
  , tokens
@@ -1042,13 +1154,9 @@ function marked(src, opt, callback) {
1042
1154
 
1043
1155
  pending = tokens.length;
1044
1156
 
1045
- var done = function(hi) {
1157
+ var done = function() {
1046
1158
  var out, err;
1047
1159
 
1048
- if (hi !== true) {
1049
- delete opt.highlight;
1050
- }
1051
-
1052
1160
  try {
1053
1161
  out = Parser.parse(tokens, opt);
1054
1162
  } catch (e) {
@@ -1063,9 +1171,11 @@ function marked(src, opt, callback) {
1063
1171
  };
1064
1172
 
1065
1173
  if (!highlight || highlight.length < 3) {
1066
- return done(true);
1174
+ return done();
1067
1175
  }
1068
1176
 
1177
+ delete opt.highlight;
1178
+
1069
1179
  if (!pending) return done();
1070
1180
 
1071
1181
  for (; i < tokens.length; i++) {
@@ -1120,7 +1230,10 @@ marked.defaults = {
1120
1230
  silent: false,
1121
1231
  highlight: null,
1122
1232
  langPrefix: 'lang-',
1123
- smartypants: false
1233
+ smartypants: false,
1234
+ headerPrefix: '',
1235
+ renderer: new Renderer,
1236
+ xhtml: false
1124
1237
  };
1125
1238
 
1126
1239
  /**
@@ -1130,6 +1243,8 @@ marked.defaults = {
1130
1243
  marked.Parser = Parser;
1131
1244
  marked.parser = Parser.parse;
1132
1245
 
1246
+ marked.Renderer = Renderer;
1247
+
1133
1248
  marked.Lexer = Lexer;
1134
1249
  marked.lexer = Lexer.lex;
1135
1250