marked/lib/marked.js

904 lines
19 KiB
JavaScript
Raw Normal View History

2011-07-24 08:15:35 -05:00
/**
* marked - A markdown parser (https://github.com/chjj/marked)
2012-01-03 00:35:47 -06:00
* Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed)
2011-07-24 08:15:35 -05:00
*/
2011-08-13 23:19:46 -05:00
;(function() {
2011-07-24 08:15:35 -05:00
/**
* Block-Level Grammar
*/
2011-08-13 23:19:46 -05:00
var block = {
2011-08-18 18:59:42 -05:00
newline: /^\n+/,
2012-03-05 21:32:48 -06:00
code: /^( {4}[^\n]+\n*)+/,
2012-02-19 20:29:35 -06:00
fences: noop,
table: noop,
nptable: noop,
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
2012-01-20 06:07:41 -06:00
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
2012-01-28 06:01:21 -06:00
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
2012-11-23 10:54:18 +00:00
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
2012-01-06 14:41:27 -06:00
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
2012-09-05 13:20:06 -05:00
paragraph: /^([^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+\n*/,
2012-01-06 14:41:27 -06:00
text: /^[^\n]+/
2011-07-24 08:15:35 -05:00
};
2012-04-22 17:19:08 -05:00
block.bullet = /(?:[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
2012-04-21 18:03:57 -05:00
block.item = replace(block.item, 'gm')
2012-04-22 17:19:08 -05:00
(/bull/g, block.bullet)
2012-04-21 18:03:57 -05:00
();
2012-03-05 15:44:55 -06:00
block.list = replace(block.list)
2012-04-22 17:19:08 -05:00
(/bull/g, block.bullet)
2012-04-26 09:18:41 -05:00
('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
2012-03-05 15:44:55 -06:00
();
2012-01-10 14:13:57 -06:00
2012-03-05 15:44:55 -06:00
block.html = replace(block.html)
2012-11-23 10:54:18 +00:00
('comment', /<!--[\s\S]*?-->/)
('closed', /<(tag)[\s\S]+?<\/\1>/)
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
2012-03-05 15:44:55 -06:00
(/tag/g, tag())
();
2012-09-05 13:20:06 -05:00
block.paragraph = replace(block.paragraph)
('hr', block.hr)
('heading', block.heading)
('lheading', block.lheading)
('blockquote', block.blockquote)
('tag', '<' + tag())
('def', block.def)
();
2012-02-19 20:29:35 -06:00
block.normal = {
fences: block.fences,
paragraph: block.paragraph,
table: block.table,
nptable: block.nptable
2012-02-19 20:29:35 -06:00
};
block.gfm = {
fences: /^ *(`{3,}|~{3,}) *(\w+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
paragraph: /^/,
2013-01-02 14:34:19 -06:00
table: /^ {0,3}\|(.+)\n {0,3}\|( *[-:]+[-| :]*)\n((?: *\|.*\n)*)\n*/,
nptable: /^ {0,3}(\S.*\|.*)\n {0,3}([-:]+ *\|[-| :]*)\n((?:.*\|.*\n)*)\n*/
2012-02-19 20:29:35 -06:00
};
2012-03-05 15:44:55 -06:00
block.gfm.paragraph = replace(block.paragraph)
2012-09-05 13:20:06 -05:00
('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
2012-03-05 15:44:55 -06:00
();
2012-02-19 20:29:35 -06:00
2011-07-24 08:15:35 -05:00
/**
2011-10-22 23:39:04 -05:00
* Block Lexer
2011-07-24 08:15:35 -05:00
*/
block.lexer = function(src) {
var tokens = [];
2011-08-13 17:06:08 -05:00
tokens.links = {};
src = src
.replace(/\r\n|\r/g, '\n')
.replace(/\t/g, ' ');
2011-07-24 08:15:35 -05:00
return block.token(src, tokens, true);
2011-08-13 17:06:08 -05:00
};
2011-08-13 16:53:15 -05:00
block.token = function(src, tokens, top) {
var src = src.replace(/^ +$/gm, '')
2012-01-28 22:33:42 -06:00
, next
2011-10-22 06:09:28 -05:00
, loose
2011-10-22 07:49:11 -05:00
, cap
, item
, space
, i
, l;
2011-10-22 06:09:28 -05:00
while (src) {
2011-10-22 23:39:04 -05:00
// newline
if (cap = block.newline.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
if (cap[0].length > 1) {
tokens.push({
type: 'space'
});
2011-08-14 01:02:14 -05:00
}
2011-10-22 06:09:28 -05:00
}
2011-10-22 23:39:04 -05:00
// code
if (cap = block.code.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
cap = cap[0].replace(/^ {4}/gm, '');
tokens.push({
2011-10-22 08:05:31 -05:00
type: 'code',
2012-02-19 03:00:03 -06:00
text: !options.pedantic
? cap.replace(/\n+$/, '')
: cap
2011-10-22 06:09:28 -05:00
});
continue;
}
2012-02-19 20:29:35 -06:00
// fences (gfm)
if (cap = block.fences.exec(src)) {
src = src.substring(cap[0].length);
2012-01-02 04:10:23 -06:00
tokens.push({
type: 'code',
2012-08-17 10:24:12 -07:00
lang: cap[2],
text: cap[3]
2012-01-02 04:10:23 -06:00
});
continue;
}
// table (gfm)
2012-08-24 07:26:12 +01:00
if (cap = block.table.exec(src)) {
src = src.substring(cap[0].length);
tokens.push({
type: 'table',
2013-01-02 14:34:19 -06:00
header: cap[1].replace(/(^ *| *\| *$)/g, '').split(/ *\| */),
align: cap[2].replace(/(^ *|\| *$)/g, '').split(/ *\| */).map(function(row) {
return /^ *-+: *$/.test(row)
? 'right'
: /^ *:-+: *$/.test(row)
? 'center'
: /^ *:-+ *$/.test(row)
? 'left'
: false;
2012-08-24 07:26:12 +01:00
}),
2013-01-02 14:34:19 -06:00
cells: cap[3].replace(/( *\| *)?\n$/, '').split('\n').map(function(row) {
return row.replace(/(^ *\| *| *\| *$)/g, '').split(/ *\| */);
2012-08-24 07:26:12 +01:00
})
});
continue;
}
// table no leading pipe (gfm)
2012-08-24 07:26:12 +01:00
if (cap = block.nptable.exec(src)) {
src = src.substring(cap[0].length);
tokens.push({
type: 'table',
2013-01-02 14:34:19 -06:00
header: cap[1].replace(/(^ *| *\| *$)/g, '').split(/ *\| */),
align: cap[2].replace(/(^ *|\| *$)/g, '').split(/ *\| */).map(function(row) {
return /^ *-+: *$/.test(row)
? 'right'
: /^ *:-+: *$/.test(row)
? 'center'
: /^ *:-+ *$/.test(row)
? 'left'
: false;
2012-08-24 07:26:12 +01:00
}),
2013-01-02 14:34:19 -06:00
cells: cap[3].replace(/\n$/, '').split('\n').map(function(row) {
return row.split(/ *\| */);
2012-08-24 07:26:12 +01:00
})
});
continue;
}
2011-10-22 23:39:04 -05:00
// heading
if (cap = block.heading.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'heading',
depth: cap[1].length,
text: cap[2]
});
continue;
}
2011-10-22 23:39:04 -05:00
// lheading
if (cap = block.lheading.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'heading',
depth: cap[2] === '=' ? 1 : 2,
text: cap[1]
});
continue;
}
2011-10-22 23:39:04 -05:00
// hr
if (cap = block.hr.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'hr'
});
continue;
}
2011-10-22 23:39:04 -05:00
// blockquote
if (cap = block.blockquote.exec(src)) {
src = src.substring(cap[0].length);
2012-02-19 03:00:03 -06:00
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'blockquote_start'
});
2012-01-06 16:44:48 -06:00
2012-01-20 22:51:25 -06:00
cap = cap[0].replace(/^ *> ?/gm, '');
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
block.token(cap, tokens, top);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'blockquote_end'
});
2012-02-19 03:00:03 -06:00
2011-10-22 06:09:28 -05:00
continue;
2011-08-14 01:02:14 -05:00
}
2011-10-22 06:09:28 -05:00
2011-10-22 23:39:04 -05:00
// list
if (cap = block.list.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'list_start',
ordered: isFinite(cap[2])
});
// Get each top-level item.
2012-04-21 18:03:57 -05:00
cap = cap[0].match(block.item);
2011-10-22 06:09:28 -05:00
2012-01-28 22:33:42 -06:00
next = false;
2011-10-22 23:39:04 -05:00
l = cap.length;
2012-01-28 22:33:42 -06:00
i = 0;
2011-10-22 07:49:11 -05:00
for (; i < l; i++) {
item = cap[i];
// Remove the list item's bullet
// so it is seen as the next token.
space = item.length;
2012-03-05 21:32:48 -06:00
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
// Outdent whatever the
// list item contains. Hacky.
if (~item.indexOf('\n ')) {
space -= item.length;
2012-02-19 03:00:03 -06:00
item = !options.pedantic
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
: item.replace(/^ {1,4}/gm, '');
2011-08-18 18:59:42 -05:00
}
2012-01-28 22:33:42 -06:00
// Determine whether item is loose or not.
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
// for discount behavior.
loose = next || /\n\n(?!\s*$)/.test(item);
if (i !== l - 1) {
next = item[item.length-1] === '\n';
if (!loose) loose = next;
}
2011-08-14 01:04:35 -05:00
tokens.push({
2011-10-22 06:09:28 -05:00
type: loose
? 'loose_item_start'
: 'list_item_start'
2011-08-14 01:04:35 -05:00
});
// Recurse.
2011-10-22 06:09:28 -05:00
block.token(item, tokens);
2011-08-14 01:04:35 -05:00
tokens.push({
2011-10-22 06:09:28 -05:00
type: 'list_item_end'
2011-08-14 01:04:35 -05:00
});
2011-10-22 07:49:11 -05:00
}
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'list_end'
});
continue;
}
2011-10-22 23:39:04 -05:00
// html
if (cap = block.html.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: options.sanitize
? 'paragraph'
: 'html',
pre: cap[1] === 'pre',
2011-10-22 06:09:28 -05:00
text: cap[0]
});
continue;
}
// def
if (top && (cap = block.def.exec(src))) {
src = src.substring(cap[0].length);
tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
title: cap[3]
};
continue;
}
// top-level paragraph
if (top && (cap = block.paragraph.exec(src))) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
tokens.push({
type: 'paragraph',
2011-10-22 06:09:28 -05:00
text: cap[0]
});
continue;
2011-08-14 01:04:35 -05:00
}
2012-01-03 02:25:47 -06:00
// text
if (cap = block.text.exec(src)) {
// Top-level should never reach here.
src = src.substring(cap[0].length);
2012-01-03 02:25:47 -06:00
tokens.push({
type: 'text',
text: cap[0]
});
continue;
}
2012-11-23 10:33:47 -06:00
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
2011-08-13 16:53:15 -05:00
}
2011-07-24 08:15:35 -05:00
return tokens;
};
/**
* Inline Processing
*/
2011-08-13 23:19:46 -05:00
var inline = {
2012-08-24 07:55:49 +01:00
escape: /^\\([\\`*{}\[\]()#+\-.!_>|])/,
2011-08-18 19:31:53 -05:00
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
2012-02-19 20:29:35 -06:00
url: noop,
2012-11-23 10:54:18 +00:00
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
2012-03-05 21:32:48 -06:00
link: /^!?\[(inside)\]\(href\)/,
2012-03-05 15:44:55 -06:00
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
2011-08-22 11:02:21 -05:00
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
2012-11-23 10:54:18 +00:00
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
code: /^(`+)([\s\S]*?[^`])\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
2012-11-23 10:54:18 +00:00
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
2012-02-19 20:29:35 -06:00
};
2012-03-05 21:32:48 -06:00
inline._linkInside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
2012-11-23 10:54:18 +00:00
inline._linkHref = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
2012-03-05 15:44:55 -06:00
inline.link = replace(inline.link)
2012-03-05 21:32:48 -06:00
('inside', inline._linkInside)
('href', inline._linkHref)
2012-03-05 15:44:55 -06:00
();
inline.reflink = replace(inline.reflink)
2012-03-05 21:32:48 -06:00
('inside', inline._linkInside)
2012-03-05 15:44:55 -06:00
();
2012-02-19 20:29:35 -06:00
inline.normal = {
url: inline.url,
strong: inline.strong,
em: inline.em,
text: inline.text
};
inline.pedantic = {
2012-11-23 10:54:18 +00:00
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
2012-02-19 20:29:35 -06:00
};
inline.gfm = {
2012-02-29 22:29:36 -06:00
url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,
2012-11-23 10:54:18 +00:00
text: /^[\s\S]+?(?=[\\<!\[_*`]|https?:\/\/| {2,}\n|$)/
2011-08-13 23:19:46 -05:00
};
2011-08-13 21:04:18 -05:00
2011-08-13 23:19:46 -05:00
/**
* Inline Lexer
*/
inline.lexer = function(src) {
2011-08-14 01:02:14 -05:00
var out = ''
, links = tokens.links
2011-08-18 19:26:23 -05:00
, link
2011-08-14 01:02:14 -05:00
, text
2011-10-22 06:09:28 -05:00
, href
2011-08-14 01:02:14 -05:00
, cap;
2011-08-13 23:36:44 -05:00
while (src) {
2011-10-22 23:39:04 -05:00
// escape
if (cap = inline.escape.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += cap[1];
continue;
}
2011-10-22 23:39:04 -05:00
// autolink
if (cap = inline.autolink.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
if (cap[2] === '@') {
text = cap[1][6] === ':'
? mangle(cap[1].substring(7))
: mangle(cap[1]);
href = mangle('mailto:') + text;
} else {
text = escape(cap[1]);
href = text;
2011-08-13 21:04:18 -05:00
}
2011-10-22 08:05:31 -05:00
out += '<a href="'
+ href
+ '">'
2011-10-22 06:09:28 -05:00
+ text
+ '</a>';
continue;
2011-08-13 21:04:18 -05:00
}
2011-10-22 06:09:28 -05:00
2012-02-19 20:29:35 -06:00
// url (gfm)
if (cap = inline.url.exec(src)) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
out += '<a href="'
+ href
+ '">'
+ text
+ '</a>';
continue;
}
2011-10-22 23:39:04 -05:00
// tag
if (cap = inline.tag.exec(src)) {
src = src.substring(cap[0].length);
2012-02-19 03:00:03 -06:00
out += options.sanitize
? escape(cap[0])
: cap[0];
2011-10-22 06:09:28 -05:00
continue;
}
2011-10-22 23:39:04 -05:00
// link
if (cap = inline.link.exec(src)) {
src = src.substring(cap[0].length);
2012-01-21 09:28:53 -06:00
out += outputLink(cap, {
2012-03-05 15:44:55 -06:00
href: cap[2],
2012-03-10 16:47:38 -06:00
title: cap[3]
2012-01-21 09:28:53 -06:00
});
2011-10-22 06:09:28 -05:00
continue;
}
2011-10-22 23:39:04 -05:00
// reflink, nolink
if ((cap = inline.reflink.exec(src))
|| (cap = inline.nolink.exec(src))) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
link = links[link.toLowerCase()];
2012-01-14 03:33:28 -06:00
if (!link || !link.href) {
2011-10-22 06:09:28 -05:00
out += cap[0][0];
src = cap[0].substring(1) + src;
2011-10-22 06:09:28 -05:00
continue;
}
2012-01-21 09:28:53 -06:00
out += outputLink(cap, link);
2011-10-22 06:09:28 -05:00
continue;
}
2011-10-22 23:39:04 -05:00
// strong
if (cap = inline.strong.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += '<strong>'
+ inline.lexer(cap[2] || cap[1])
+ '</strong>';
continue;
}
2011-10-22 23:39:04 -05:00
// em
if (cap = inline.em.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += '<em>'
+ inline.lexer(cap[2] || cap[1])
+ '</em>';
continue;
}
2011-10-22 23:39:04 -05:00
// code
if (cap = inline.code.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += '<code>'
+ escape(cap[2], true)
2011-10-22 06:09:28 -05:00
+ '</code>';
continue;
}
2011-10-22 23:39:04 -05:00
// br
if (cap = inline.br.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += '<br>';
continue;
}
2011-10-22 23:39:04 -05:00
// text
if (cap = inline.text.exec(src)) {
src = src.substring(cap[0].length);
2011-10-22 06:09:28 -05:00
out += escape(cap[0]);
continue;
2011-08-14 01:04:35 -05:00
}
2012-11-23 10:33:47 -06:00
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
2011-08-13 23:19:46 -05:00
}
2011-08-13 21:04:18 -05:00
2011-08-13 23:19:46 -05:00
return out;
};
2011-08-13 21:04:18 -05:00
function outputLink(cap, link) {
2011-10-22 06:09:28 -05:00
if (cap[0][0] !== '!') {
return '<a href="'
+ escape(link.href)
+ '"'
+ (link.title
2012-01-14 03:27:06 -06:00
? ' title="'
+ escape(link.title)
+ '"'
: '')
2011-10-22 06:09:28 -05:00
+ '>'
+ inline.lexer(cap[1])
+ '</a>';
} else {
return '<img src="'
+ escape(link.href)
+ '" alt="'
+ escape(cap[1])
+ '"'
+ (link.title
2012-01-14 03:27:06 -06:00
? ' title="'
+ escape(link.title)
+ '"'
: '')
2011-10-22 06:09:28 -05:00
+ '>';
}
}
2011-10-22 06:09:28 -05:00
2011-07-24 08:15:35 -05:00
/**
* Parsing
*/
2011-08-13 17:06:08 -05:00
var tokens
, token;
2011-08-13 16:38:46 -05:00
function next() {
2011-07-24 08:15:35 -05:00
return token = tokens.pop();
}
2011-07-24 08:15:35 -05:00
function tok() {
2011-07-24 08:15:35 -05:00
switch (token.type) {
2011-10-22 06:18:15 -05:00
case 'space': {
2011-08-18 18:59:42 -05:00
return '';
2011-10-22 06:18:15 -05:00
}
case 'hr': {
return '<hr>\n';
2011-10-22 06:18:15 -05:00
}
case 'heading': {
return '<h'
+ token.depth
+ '>'
2011-08-13 23:19:46 -05:00
+ inline.lexer(token.text)
2011-10-22 06:18:15 -05:00
+ '</h'
+ token.depth
+ '>\n';
2011-10-22 06:18:15 -05:00
}
2011-10-22 08:05:31 -05:00
case 'code': {
if (options.highlight) {
token.code = options.highlight(token.text, token.lang);
if (token.code != null && token.code !== token.text) {
token.escaped = true;
token.text = token.code;
}
}
if (!token.escaped) {
token.text = escape(token.text, true);
}
return '<pre><code'
+ (token.lang
? ' class="lang-'
2012-01-14 03:27:06 -06:00
+ token.lang
+ '"'
: '')
+ '>'
+ token.text
+ '</code></pre>\n';
2011-10-22 06:18:15 -05:00
}
2012-08-24 07:26:12 +01:00
case 'table': {
var thead = '\t<thead>\n\t\t<tr>';
2013-01-02 14:34:19 -06:00
token.header.forEach(function(heading, i) {
2012-08-24 07:26:12 +01:00
heading = inline.lexer(heading);
2013-01-02 14:34:19 -06:00
var align = i < token.align.length
? token.align[i]
: false;
switch (align) {
case 'left':
case 'right':
case 'center':
2012-08-24 07:26:12 +01:00
thead += '<th align="' + align + '">' + heading + '</td>';
break;
default:
thead += '<th>' + heading + '</th>';
}
});
thead += '</tr>\n\t</thead>\n';
var tbody = '\t<tbody>\n';
2013-01-02 14:34:19 -06:00
token.cells.forEach(function(row) {
2012-08-24 07:26:12 +01:00
tbody += '\t\t<tr>';
2013-01-02 14:34:19 -06:00
row.forEach(function(cell, i) {
2012-08-24 07:26:12 +01:00
cell = inline.lexer(cell);
2013-01-02 14:34:19 -06:00
var align = i < token.align.length
? token.align[i]
: false;
switch (align) {
case 'left':
case 'right':
case 'center':
2012-08-24 07:26:12 +01:00
tbody += '<td align="' + align + '">' + cell + '</td>';
break;
default:
tbody += '<td>' + cell + '</td>';
}
});
tbody += '</tr>\n';
});
tbody += '\t</tbody>\n';
return '<table>\n'
+ thead
+ tbody
+ '</table>\n'
}
2011-10-22 06:18:15 -05:00
case 'blockquote_start': {
var body = '';
2011-10-22 06:18:15 -05:00
2011-07-24 08:15:35 -05:00
while (next().type !== 'blockquote_end') {
body += tok();
2011-07-24 08:15:35 -05:00
}
2011-10-22 06:18:15 -05:00
return '<blockquote>\n'
+ body
+ '</blockquote>\n';
2011-10-22 06:18:15 -05:00
}
case 'list_start': {
2011-10-04 17:32:59 -05:00
var type = token.ordered ? 'ol' : 'ul'
, body = '';
2011-10-22 06:18:15 -05:00
2011-07-24 08:15:35 -05:00
while (next().type !== 'list_end') {
body += tok();
2011-07-24 08:15:35 -05:00
}
2011-10-22 06:18:15 -05:00
return '<'
+ type
+ '>\n'
+ body
2011-10-22 06:18:15 -05:00
+ '</'
+ type
+ '>\n';
2011-10-22 06:18:15 -05:00
}
case 'list_item_start': {
var body = '';
2011-10-22 06:18:15 -05:00
2011-07-24 08:15:35 -05:00
while (next().type !== 'list_item_end') {
body += token.type === 'text'
2012-01-21 09:28:53 -06:00
? parseText()
: tok();
2011-07-24 08:15:35 -05:00
}
2011-10-22 06:18:15 -05:00
2011-10-04 17:32:59 -05:00
return '<li>'
+ body
+ '</li>\n';
2011-10-22 06:18:15 -05:00
}
case 'loose_item_start': {
var body = '';
2011-10-22 06:18:15 -05:00
2011-08-20 08:59:47 -05:00
while (next().type !== 'list_item_end') {
body += tok();
2011-08-20 08:59:47 -05:00
}
2011-10-22 06:18:15 -05:00
2011-10-04 17:32:59 -05:00
return '<li>'
+ body
+ '</li>\n';
2011-10-22 06:18:15 -05:00
}
case 'html': {
2012-02-19 03:00:03 -06:00
return !token.pre && !options.pedantic
? inline.lexer(token.text)
: token.text;
2011-10-22 06:18:15 -05:00
}
case 'paragraph': {
return '<p>'
+ inline.lexer(token.text)
+ '</p>\n';
}
2011-10-22 06:18:15 -05:00
case 'text': {
2011-10-22 06:09:28 -05:00
return '<p>'
2012-01-21 09:28:53 -06:00
+ parseText()
+ '</p>\n';
2011-10-22 06:18:15 -05:00
}
}
}
2011-10-04 17:32:59 -05:00
function parseText() {
var body = token.text
, top;
2011-10-04 17:32:59 -05:00
while ((top = tokens[tokens.length-1])
&& top.type === 'text') {
body += '\n' + next().text;
2011-07-24 08:15:35 -05:00
}
2011-10-04 17:32:59 -05:00
return inline.lexer(body);
}
2011-07-24 08:15:35 -05:00
function parse(src) {
2011-07-24 08:15:35 -05:00
tokens = src.reverse();
var out = '';
2011-07-24 08:15:35 -05:00
while (next()) {
out += tok();
2011-07-24 08:15:35 -05:00
}
tokens = null;
token = null;
return out;
}
2011-07-24 08:15:35 -05:00
/**
* Helpers
*/
function escape(html, encode) {
2011-07-24 08:15:35 -05:00
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
2011-07-24 08:15:35 -05:00
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
2011-07-24 08:15:35 -05:00
function mangle(text) {
2011-08-14 02:47:56 -05:00
var out = ''
, l = text.length
2011-07-24 08:15:35 -05:00
, i = 0
, ch;
2011-07-24 08:15:35 -05:00
for (; i < l; i++) {
ch = text.charCodeAt(i);
2011-08-13 23:19:46 -05:00
if (Math.random() > 0.5) {
2011-07-24 08:15:35 -05:00
ch = 'x' + ch.toString(16);
}
out += '&#' + ch + ';';
}
return out;
}
2011-07-24 08:15:35 -05:00
function tag() {
var tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
return tag;
}
2012-04-21 18:03:57 -05:00
function replace(regex, opt) {
2012-03-05 15:44:55 -06:00
regex = regex.source;
2012-04-21 18:03:57 -05:00
opt = opt || '';
2012-03-05 15:44:55 -06:00
return function self(name, val) {
2012-04-21 18:03:57 -05:00
if (!name) return new RegExp(regex, opt);
2012-09-05 13:20:06 -05:00
val = val.source || val;
val = val.replace(/(^|[^\[])\^/g, '$1');
regex = regex.replace(name, val);
2012-03-05 15:44:55 -06:00
return self;
};
}
2012-02-19 20:29:35 -06:00
function noop() {}
noop.exec = noop;
2011-07-24 08:15:35 -05:00
/**
2012-02-19 03:00:03 -06:00
* Marked
2011-07-24 08:15:35 -05:00
*/
function marked(src, opt) {
2012-02-19 22:28:55 -06:00
setOptions(opt);
2012-11-23 10:33:47 -06:00
try {
return parse(block.lexer(src));
} catch (e) {
e.message += '\nPlease report this to https://github.com/chjj/marked.';
if (marked.options.silent) {
return 'An error occured: ' + e.message;
}
throw e;
}
}
2011-07-24 08:15:35 -05:00
2012-02-19 20:29:35 -06:00
/**
* Options
*/
var options
, defaults;
2012-02-19 20:29:35 -06:00
function setOptions(opt) {
if (!opt) opt = defaults;
2012-02-19 22:28:55 -06:00
if (options === opt) return;
options = opt;
2012-02-19 20:29:35 -06:00
if (options.gfm) {
block.fences = block.gfm.fences;
block.paragraph = block.gfm.paragraph;
block.table = block.gfm.table;
block.nptable = block.gfm.nptable;
2012-02-19 20:29:35 -06:00
inline.text = inline.gfm.text;
inline.url = inline.gfm.url;
} else {
block.fences = block.normal.fences;
block.paragraph = block.normal.paragraph;
block.table = block.normal.table;
block.nptable = block.normal.table;
2012-02-19 20:29:35 -06:00
inline.text = inline.normal.text;
inline.url = inline.normal.url;
}
if (options.pedantic) {
inline.em = inline.pedantic.em;
inline.strong = inline.pedantic.strong;
} else {
inline.em = inline.normal.em;
inline.strong = inline.normal.strong;
}
}
2012-02-19 20:29:35 -06:00
marked.options =
marked.setOptions = function(opt) {
defaults = opt;
2012-02-19 20:29:35 -06:00
setOptions(opt);
return marked;
2012-02-19 20:29:35 -06:00
};
marked.setOptions({
2012-02-19 03:00:03 -06:00
gfm: true,
pedantic: false,
sanitize: false,
highlight: null
2012-02-19 20:29:35 -06:00
});
2012-02-19 03:00:03 -06:00
/**
* Expose
*/
2012-02-19 20:29:35 -06:00
marked.parser = function(src, opt) {
2012-02-19 22:28:55 -06:00
setOptions(opt);
2012-02-19 20:29:35 -06:00
return parse(src);
};
marked.lexer = function(src, opt) {
2012-02-19 22:28:55 -06:00
setOptions(opt);
2012-02-19 20:29:35 -06:00
return block.lexer(src);
};
2011-08-13 23:19:46 -05:00
2011-11-26 22:12:02 -06:00
marked.parse = marked;
2011-08-13 23:19:46 -05:00
if (typeof module !== 'undefined') {
module.exports = marked;
} else {
this.marked = marked;
}
2011-07-24 08:15:35 -05:00
2012-04-12 02:27:41 -05:00
}).call(function() {
return this || (typeof window !== 'undefined' ? window : global);
}());