Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Testing this out using marked.js instead of showdown.js

  • Loading branch information...
commit 79333edb26d67ae565b89019595df96d91b07ea8 1 parent d57dd7d
@niftylettuce authored
Showing with 773 additions and 2 deletions.
  1. +2 −2 package.json
  2. +771 −0 scripts/marked.js
View
4 package.json
@@ -1,8 +1,8 @@
{
"name": "github-flavored-markdown",
- "version": "1.0.1",
+ "version": "1.0.2",
"description": "The port of Showdown used on github.com",
"author": "tekkup (http://tekkub.net/) <git@tekkub.net>",
- "main": "./scripts/showdown.js",
+ "main": "./scripts/marked.js",
"repository": "http://github.com/isaacs/github-flavored-markdown"
}
View
771 scripts/marked.js
@@ -0,0 +1,771 @@
+/**
+ * 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*)+/,
+ fences: noop,
+ hr: /^( *[\-*_]){3,} *(?:\n+|$)/,
+ heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
+ lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
+ blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
+ list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )(?!\1bullet)\n*|\s*$)/,
+ html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
+ def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
+ paragraph: /^([^\n]+\n?(?!body))+\n*/,
+ text: /^[^\n]+/
+};
+
+block.list = replace(block.list)
+ ('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/)
+ ();
+
+block.html = replace(block.html)
+ ('comment', /<!--[^\0]*?-->/)
+ ('closed', /<(tag)[^\0]+?<\/\1>/)
+ ('closing', /<tag(?!:\/|@)\b(?:"[^"]*"|'[^']*'|[^'">])*?>/)
+ (/tag/g, tag())
+ ();
+
+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;
+ })
+ ('hr')
+ ('heading')
+ ('lheading')
+ ('blockquote')
+ ('<' + tag())
+ ('def');
+
+ return new
+ RegExp(paragraph.replace('body', body.join('|')));
+})();
+
+block.normal = {
+ fences: block.fences,
+ paragraph: block.paragraph
+};
+
+block.gfm = {
+ fences: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/,
+ paragraph: /^/
+};
+
+block.gfm.paragraph = replace(block.paragraph)
+ ('(?!', '(?!' + block.gfm.fences.source.replace(/(^|[^\[])\^/g, '$1') + '|')
+ ();
+
+/**
+ * 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: !options.pedantic
+ ? cap.replace(/\n+$/, '')
+ : cap
+ });
+ continue;
+ }
+
+ // fences (gfm)
+ if (cap = block.fences.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 = !options.pedantic
+ ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
+ : item.replace(/^ {1,4}/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',
+ pre: cap[1] === 'pre',
+ 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: /^<([^ >]+(@|:\/)[^ >]+)>/,
+ url: noop,
+ tag: /^<!--[^\0]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
+ link: /^!?\[(inside)\]\(href\)/,
+ reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
+ nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
+ strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/,
+ em: /^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/,
+ code: /^(`+)([^\0]*?[^`])\1(?!`)/,
+ br: /^ {2,}\n(?!\s*$)/,
+ text: /^[^\0]+?(?=[\\<!\[_*`]| {2,}\n|$)/
+};
+
+inline._linkInside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
+inline._linkHref = /\s*<?([^\s]*?)>?(?:\s+['"]([^\0]*?)['"])?\s*/;
+
+inline.link = replace(inline.link)
+ ('inside', inline._linkInside)
+ ('href', inline._linkHref)
+ ();
+
+inline.reflink = replace(inline.reflink)
+ ('inside', inline._linkInside)
+ ();
+
+inline.normal = {
+ url: inline.url,
+ strong: inline.strong,
+ em: inline.em,
+ text: inline.text
+};
+
+inline.pedantic = {
+ strong: /^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/,
+ em: /^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/
+};
+
+inline.gfm = {
+ url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,
+ text: /^[^\0]+?(?=[\\<!\[_*`]|https?:\/\/| {2,}\n|$)/
+};
+
+/**
+ * Inline Lexer
+ */
+
+inline.lexer = function(src) {
+ var out = ''
+ , links = tokens.links
+ , link
+ , text
+ , href
+ , cap;
+
+ while (src) {
+ // escape
+ if (cap = inline.escape.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += cap[1];
+ continue;
+ }
+
+ // autolink
+ if (cap = inline.autolink.exec(src)) {
+ src = src.substring(cap[0].length);
+ 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;
+ }
+ out += '<a href="'
+ + href
+ + '">'
+ + text
+ + '</a>';
+ continue;
+ }
+
+ // 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;
+ }
+
+ // tag
+ if (cap = inline.tag.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += options.sanitize
+ ? escape(cap[0])
+ : cap[0];
+ continue;
+ }
+
+ // link
+ if (cap = inline.link.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += outputLink(cap, {
+ href: cap[2],
+ title: cap[3]
+ });
+ 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 += '<strong>'
+ + inline.lexer(cap[2] || cap[1])
+ + '</strong>';
+ continue;
+ }
+
+ // em
+ if (cap = inline.em.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += '<em>'
+ + inline.lexer(cap[2] || cap[1])
+ + '</em>';
+ continue;
+ }
+
+ // code
+ if (cap = inline.code.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += '<code>'
+ + escape(cap[2], true)
+ + '</code>';
+ continue;
+ }
+
+ // br
+ if (cap = inline.br.exec(src)) {
+ src = src.substring(cap[0].length);
+ out += '<br>';
+ 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 '<a href="'
+ + escape(link.href)
+ + '"'
+ + (link.title
+ ? ' title="'
+ + escape(link.title)
+ + '"'
+ : '')
+ + '>'
+ + inline.lexer(cap[1])
+ + '</a>';
+ } else {
+ return '<img src="'
+ + escape(link.href)
+ + '" alt="'
+ + escape(cap[1])
+ + '"'
+ + (link.title
+ ? ' title="'
+ + escape(link.title)
+ + '"'
+ : '')
+ + '>';
+ }
+};
+
+/**
+ * Parsing
+ */
+
+var tokens
+ , token;
+
+var next = function() {
+ return token = tokens.pop();
+};
+
+var tok = function() {
+ switch (token.type) {
+ case 'space': {
+ return '';
+ }
+ case 'hr': {
+ return '<hr>\n';
+ }
+ case 'heading': {
+ return '<h'
+ + token.depth
+ + '>'
+ + inline.lexer(token.text)
+ + '</h'
+ + token.depth
+ + '>\n';
+ }
+ case 'code': {
+ return '<pre><code'
+ + (token.lang
+ ? ' class="'
+ + token.lang
+ + '"'
+ : '')
+ + '>'
+ + (token.escaped
+ ? token.text
+ : escape(token.text, true))
+ + '</code></pre>\n';
+ }
+ case 'blockquote_start': {
+ var body = '';
+
+ while (next().type !== 'blockquote_end') {
+ body += tok();
+ }
+
+ return '<blockquote>\n'
+ + body
+ + '</blockquote>\n';
+ }
+ case 'list_start': {
+ var type = token.ordered ? 'ol' : 'ul'
+ , body = '';
+
+ while (next().type !== 'list_end') {
+ body += tok();
+ }
+
+ return '<'
+ + type
+ + '>\n'
+ + body
+ + '</'
+ + type
+ + '>\n';
+ }
+ case 'list_item_start': {
+ var body = '';
+
+ while (next().type !== 'list_item_end') {
+ body += token.type === 'text'
+ ? parseText()
+ : tok();
+ }
+
+ return '<li>'
+ + body
+ + '</li>\n';
+ }
+ case 'loose_item_start': {
+ var body = '';
+
+ while (next().type !== 'list_item_end') {
+ body += tok();
+ }
+
+ return '<li>'
+ + body
+ + '</li>\n';
+ }
+ case 'html': {
+ if (options.sanitize) {
+ return inline.lexer(token.text);
+ }
+ return !token.pre && !options.pedantic
+ ? inline.lexer(token.text)
+ : token.text;
+ }
+ case 'paragraph': {
+ return '<p>'
+ + inline.lexer(token.text)
+ + '</p>\n';
+ }
+ case 'text': {
+ return '<p>'
+ + parseText()
+ + '</p>\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, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;')
+ .replace(/'/g, '&#39;');
+};
+
+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;
+}
+
+function replace(regex) {
+ regex = regex.source;
+ return function self(name, val) {
+ if (!name) return new RegExp(regex);
+ regex = regex.replace(name, val.source || val);
+ return self;
+ };
+}
+
+function noop() {}
+noop.exec = noop;
+
+/**
+ * Marked
+ */
+
+var marked = function(src, opt) {
+ setOptions(opt);
+ return parse(block.lexer(src));
+};
+
+/**
+ * Options
+ */
+
+var options
+ , defaults;
+
+var setOptions = function(opt) {
+ if (!opt) opt = defaults;
+ if (options === opt) return;
+ options = opt;
+
+ if (options.gfm) {
+ block.fences = block.gfm.fences;
+ block.paragraph = block.gfm.paragraph;
+ inline.text = inline.gfm.text;
+ inline.url = inline.gfm.url;
+ } else {
+ block.fences = block.normal.fences;
+ block.paragraph = block.normal.paragraph;
+ 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;
+ }
+};
+
+marked.options =
+marked.setOptions = function(opt) {
+ defaults = opt;
+ setOptions(opt);
+};
+
+marked.options({
+ gfm: true,
+ pedantic: false,
+ sanitize: false
+});
+
+/**
+ * Expose
+ */
+
+marked.parser = function(src, opt) {
+ setOptions(opt);
+ return parse(src);
+};
+
+marked.lexer = function(src, opt) {
+ setOptions(opt);
+ return block.lexer(src);
+};
+
+marked.parse = marked;
+
+if (typeof module !== 'undefined') {
+ module.exports = marked;
+} else {
+ this.marked = marked;
+}
+
+}).call(this);
Please sign in to comment.
Something went wrong with that request. Please try again.