/** * marked - A markdown parser (https://github.com/chjj/marked) * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) */ ;(function() { /** * Block-Level Grammar */ var block = { newline: /^\n+/, code: /^ {4,}[^\n]*(?:\n {4,}[^\n]*|\n)*(?:\n+|$)/, gfm_code: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/, hr: /^( *[\-*_]){3,} *(?:\n+|$)/, heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )|\s*$)(?!\1bullet)\n*/, html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, paragraph: /^([^\n]+\n?(?!body))+\n*/, text: /^[^\n]+/ }; block.list = (function() { var list = block.list.source; list = list .replace('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/.source); return new RegExp(list); })(); block.html = (function() { var html = block.html.source; html = html .replace('comment', //.source) .replace('closed', /<(tag)[^\0]+?<\/\1>/.source) .replace('closing', /])*?>/.source) .replace(/tag/g, tag()); return new RegExp(html); })(); block.paragraph = (function() { var paragraph = block.paragraph.source , body = []; (function push(rule) { rule = block[rule] ? block[rule].source : rule; body.push(rule.replace(/(^|[^\[])\^/g, '$1')); return push; }) ('gfm_code') ('hr') ('heading') ('lheading') ('blockquote') ('<' + tag()) ('def'); return new RegExp(paragraph.replace('body', body.join('|'))); })(); /** * Block Lexer */ block.lexer = function(src) { var tokens = []; tokens.links = {}; src = src .replace(/\r\n|\r/g, '\n') .replace(/\t/g, ' '); return block.token(src, tokens, true); }; block.token = function(src, tokens, top) { var src = src.replace(/^ +$/gm, '') , next , loose , cap , item , space , i , l; while (src) { // newline if (cap = block.newline.exec(src)) { src = src.substring(cap[0].length); if (cap[0].length > 1) { tokens.push({ type: 'space' }); } } // code if (cap = block.code.exec(src)) { src = src.substring(cap[0].length); cap = cap[0].replace(/^ {4}/gm, ''); tokens.push({ type: 'code', text: cap.replace(/\n+$/, '') }); continue; } // gfm_code if (cap = block.gfm_code.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'code', lang: cap[1], text: cap[2] }); continue; } // heading if (cap = block.heading.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'heading', depth: cap[1].length, text: cap[2] }); continue; } // lheading if (cap = block.lheading.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'heading', depth: cap[2] === '=' ? 1 : 2, text: cap[1] }); continue; } // hr if (cap = block.hr.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'hr' }); continue; } // blockquote if (cap = block.blockquote.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'blockquote_start' }); 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); tokens.push({ type: 'blockquote_end' }); continue; } // list if (cap = block.list.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'list_start', ordered: isFinite(cap[2]) }); // Get each top-level item. cap = cap[0].match( /^( *)([*+-]|\d+\.)[^\n]*(?:\n(?!\1(?:[*+-]|\d+\.))[^\n]*)*/gm ); next = false; l = cap.length; i = 0; for (; i < l; i++) { item = cap[i]; // Remove the list item's bullet // so it is seen as the next token. space = item.length; item = item.replace(/^ *([*+-]|\d+\.) */, ''); // Outdent whatever the // list item contains. Hacky. if (~item.indexOf('\n ')) { space -= item.length; item = item.replace(new RegExp('^ {1,' + space + '}', 'gm'), ''); } // 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; } tokens.push({ type: loose ? 'loose_item_start' : 'list_item_start' }); // Recurse. block.token(item, tokens); tokens.push({ type: 'list_item_end' }); } tokens.push({ type: 'list_end' }); continue; } // html if (cap = block.html.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'html', 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); tokens.push({ type: 'paragraph', text: cap[0] }); continue; } // text if (cap = block.text.exec(src)) { // Top-level should never reach here. src = src.substring(cap[0].length); tokens.push({ type: 'text', text: cap[0] }); continue; } } return tokens; }; /** * Inline Processing */ var inline = { escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, gfm_autolink: /^(\w+:\/\/[^\s]+[^.,:;"')\]\s])/, tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, link: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\(([^\)]*)\)/, reflink: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\s*\[([^\]]*)\]/, nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, em: /^\b_([^\0]+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/, code: /^(`+)([^\0]*?[^`])\1(?!`)/, br: /^ {2,}\n(?!\s*$)/, text: /^[^\0]+?(?=[\\' + text + ''; continue; } // gfm_autolink if (cap = inline.gfm_autolink.exec(src)) { src = src.substring(cap[0].length); text = escape(cap[1]); href = text; out += '' + text + ''; continue; } // tag if (cap = inline.tag.exec(src)) { src = src.substring(cap[0].length); out += cap[0]; continue; } // link if (cap = inline.link.exec(src)) { src = src.substring(cap[0].length); text = /^\s*?(?:\s+"([^\n]+)")?\s*$/.exec(cap[2]); if (!text) { out += cap[0][0]; src = cap[0].substring(1) + src; continue; } out += outputLink(cap, { href: text[1], title: text[2] }); continue; } // reflink, nolink if ((cap = inline.reflink.exec(src)) || (cap = inline.nolink.exec(src))) { src = src.substring(cap[0].length); link = (cap[2] || cap[1]).replace(/\s+/g, ' '); link = links[link.toLowerCase()]; if (!link || !link.href) { out += cap[0][0]; src = cap[0].substring(1) + src; continue; } out += outputLink(cap, link); continue; } // strong if (cap = inline.strong.exec(src)) { src = src.substring(cap[0].length); out += '' + inline.lexer(cap[2] || cap[1]) + ''; continue; } // em if (cap = inline.em.exec(src)) { src = src.substring(cap[0].length); out += '' + inline.lexer(cap[2] || cap[1]) + ''; continue; } // code if (cap = inline.code.exec(src)) { src = src.substring(cap[0].length); out += '' + escape(cap[2], true) + ''; continue; } // br if (cap = inline.br.exec(src)) { src = src.substring(cap[0].length); out += '
'; continue; } // text if (cap = inline.text.exec(src)) { src = src.substring(cap[0].length); out += escape(cap[0]); continue; } } return out; }; var outputLink = function(cap, link) { if (cap[0][0] !== '!') { return '' + inline.lexer(cap[1]) + ''; } else { return ''
      + escape(cap[1])
      + ''; } }; /** * Parsing */ var tokens , token; var next = function() { return token = tokens.pop(); }; var tok = function() { switch (token.type) { case 'space': { return ''; } case 'hr': { return '
\n'; } case 'heading': { return '' + inline.lexer(token.text) + '\n'; } case 'code': { return '
'
        + (token.escaped
        ? token.text
        : escape(token.text, true))
        + '
\n'; } case 'blockquote_start': { var body = ''; while (next().type !== 'blockquote_end') { body += tok(); } return '
\n' + body + '
\n'; } case 'list_start': { var type = token.ordered ? 'ol' : 'ul' , body = ''; while (next().type !== 'list_end') { body += tok(); } return '<' + type + '>\n' + body + '\n'; } case 'list_item_start': { var body = ''; while (next().type !== 'list_item_end') { body += token.type === 'text' ? parseText() : tok(); } return '
  • ' + body + '
  • \n'; } case 'loose_item_start': { var body = ''; while (next().type !== 'list_item_end') { body += tok(); } return '
  • ' + body + '
  • \n'; } case 'html': { return inline.lexer(token.text); } case 'paragraph': { return '

    ' + inline.lexer(token.text) + '

    \n'; } case 'text': { return '

    ' + parseText() + '

    \n'; } } }; var parseText = function() { var body = token.text , top; while ((top = tokens[tokens.length-1]) && top.type === 'text') { body += '\n' + next().text; } return inline.lexer(body); }; var parse = function(src) { tokens = src.reverse(); var out = ''; while (next()) { out += tok(); } tokens = null; token = null; return out; }; /** * Helpers */ var escape = function(html, encode) { return html .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }; var mangle = function(text) { var out = '' , l = text.length , i = 0 , ch; for (; i < l; i++) { ch = text.charCodeAt(i); if (Math.random() > 0.5) { ch = 'x' + ch.toString(16); } out += '&#' + ch + ';'; } return out; }; 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+'; return tag; } /** * Expose */ var marked = function(src) { return parse(block.lexer(src)); }; marked.parser = parse; marked.lexer = block.lexer; marked.parse = marked; if (typeof module !== 'undefined') { module.exports = marked; } else { this.marked = marked; } }).call(this);