1 | var TAGS = {
|
2 | '' : ['<em>','</em>'],
|
3 | _ : ['<strong>','</strong>'],
|
4 | '\n' : ['<br />'],
|
5 | ' ' : ['<br />'],
|
6 | '-': ['<hr />']
|
7 | };
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | function outdent(str) {
|
13 | return str.replace(RegExp('^'+(str.match(/^(\t| )+/) || '')[0], 'gm'), '');
|
14 | }
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function encodeAttr(str) {
|
20 | return (str+'').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
21 | }
|
22 |
|
23 |
|
24 | function parse(md) {
|
25 | var tokenizer = /((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^```(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:\!\[([^\]]*?)\]\(([^\)]+?)\))|(\[)|(\](?:\(([^\)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(\-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,3})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( \n\n*|\n{2,}|__|\*\*|[_*])/gm,
|
26 | context = [],
|
27 | out = '',
|
28 | last = 0,
|
29 | links = {},
|
30 | chunk, prev, token, inner, t;
|
31 |
|
32 | function tag(token) {
|
33 | var desc = TAGS[token.replace(/\*/g,'_')[1] || ''],
|
34 | end = context[context.length-1]==token;
|
35 | if (!desc) { return token; }
|
36 | if (!desc[1]) { return desc[0]; }
|
37 | context[end?'pop':'push'](token);
|
38 | return desc[end|0];
|
39 | }
|
40 |
|
41 | function flush() {
|
42 | var str = '';
|
43 | while (context.length) { str += tag(context[context.length-1]); }
|
44 | return str;
|
45 | }
|
46 |
|
47 | md = md.replace(/^\[(.+?)\]:\s*(.+)$/gm, function (s, name, url) {
|
48 | links[name.toLowerCase()] = url;
|
49 | return '';
|
50 | }).replace(/^\n+|\n+$/g, '');
|
51 |
|
52 | while ( (token=tokenizer.exec(md)) ) {
|
53 | prev = md.substring(last, token.index);
|
54 | last = tokenizer.lastIndex;
|
55 | chunk = token[0];
|
56 | if (prev.match(/[^\\](\\\\)*\\$/)) {
|
57 |
|
58 | }
|
59 |
|
60 | else if (token[3] || token[4]) {
|
61 | chunk = '<pre class="code '+(token[4]?'poetry':token[2].toLowerCase())+'">'+outdent(encodeAttr(token[3] || token[4]).replace(/^\n+|\n+$/g, ''))+'</pre>';
|
62 | }
|
63 |
|
64 | else if (token[6]) {
|
65 | t = token[6];
|
66 | if (t.match(/\./)) {
|
67 | token[5] = token[5].replace(/^\d+/gm, '');
|
68 | }
|
69 | inner = parse(outdent(token[5].replace(/^\s*[>*+.-]/gm, '')));
|
70 | if (t==='>') { t = 'blockquote'; }
|
71 | else {
|
72 | t = t.match(/\./) ? 'ol' : 'ul';
|
73 | inner = inner.replace(/^(.*)(\n|$)/gm, '<li>$1</li>');
|
74 | }
|
75 | chunk = '<'+t+'>' + inner + '</'+t+'>';
|
76 | }
|
77 |
|
78 | else if (token[8]) {
|
79 | chunk = "<img src=\"" + (encodeAttr(token[8])) + "\" alt=\"" + (encodeAttr(token[7])) + "\">";
|
80 | }
|
81 |
|
82 | else if (token[10]) {
|
83 | out = out.replace('<a>', ("<a href=\"" + (encodeAttr(token[11] || links[prev.toLowerCase()])) + "\">"));
|
84 | chunk = flush() + '</a>';
|
85 | }
|
86 | else if (token[9]) {
|
87 | chunk = '<a>';
|
88 | }
|
89 |
|
90 | else if (token[12] || token[14]) {
|
91 | t = 'h' + (token[14] ? token[14].length : (token[13][0]==='='?1:2));
|
92 | chunk = '<'+t+'>' + parse(token[12] || token[15]) + '</'+t+'>';
|
93 | }
|
94 |
|
95 | else if (token[16]) {
|
96 | chunk = '<code>'+encodeAttr(token[16])+'</code>';
|
97 | }
|
98 |
|
99 | else if (token[17] || token[1]) {
|
100 | chunk = tag(token[17] || '--');
|
101 | }
|
102 | out += prev;
|
103 | out += chunk;
|
104 | }
|
105 |
|
106 | return (out + md.substring(last) + flush()).trim();
|
107 | }
|
108 |
|
109 | export default parse;
|
110 |
|