This commit is contained in:
Christopher Jeffrey 2011-08-13 17:06:08 -05:00
parent a2cccfaf1d
commit 2ab86665a5

View File

@ -22,25 +22,44 @@ var rules = {
var keys = Object.keys(rules) var keys = Object.keys(rules)
, len = keys.length; , len = keys.length;
/**
* Shared
*/
var links;
/** /**
* Lexer * Lexer
*/ */
var lex_ = function lex(str, tokens, line) { var lex = function(str) {
var i var tokens = []
, key , links = {};
, rule;
while (str.length) // normalize whitespace
for (i = 0; i < len; i++) { str = str.replace(/\r\n/g, '\n')
key = keys[i]; .replace(/\r/g, '\n');
rule = rules[key];
str = str.replace(/\t/g, ' ');
//str = str.replace(/(^|\n) +(\n|$)/g, '$1$2');
// unfortunately, this is the most
// performant method of getting link
// definitions out of the way.
str = str.replace(
/^ {0,3}\[([^\]]+)\]: *([^ ]+)(?: +"([^"]+)")?/gm,
function(_, id, href, title) {
links[id] = {
href: href,
title: title
};
return '';
});
tokens.links = links;
return lex.token(str, tokens, 0);
};
lex.token = function lex(str, tokens, line) {
while (str.length)
for (var i = 0; i < len; i++) {
var key = keys[i]
, rule = rules[key];
cap = rule.exec(str); cap = rule.exec(str);
if (!cap) continue; if (!cap) continue;
@ -109,7 +128,10 @@ var lex_ = function lex(str, tokens, line) {
type: 'list_item_start', type: 'list_item_start',
line: line line: line
}); });
// recurse
lex(item, tokens, line); lex(item, tokens, line);
tokens.push({ tokens.push({
type: 'list_item_end', type: 'list_item_end',
line: line line: line
@ -134,7 +156,10 @@ var lex_ = function lex(str, tokens, line) {
line: line line: line
}); });
cap = cap[0].replace(/^ *>/gm, ''); cap = cap[0].replace(/^ *>/gm, '');
// recurse
lex(cap, tokens, line); lex(cap, tokens, line);
tokens.push({ tokens.push({
type: 'blockquote_end', type: 'blockquote_end',
line: line line: line
@ -143,34 +168,6 @@ var lex_ = function lex(str, tokens, line) {
} }
break; break;
} }
};
var lex = function(str) {
var tokens = []
, line = 0;
// normalize whitespace
str = str.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n');
str = str.replace(/\t/g, ' ');
//str = str.replace(/(^|\n) +(\n|$)/g, '$1$2');
// unfortunately, this is the most
// performant method of getting link
// definitions out of the way.
links = {};
str = str.replace(
/^ {0,3}\[([^\]]+)\]: *([^ ]+)(?: +"([^"]+)")?/gm,
function(_, id, href, title) {
links[id] = {
href: href,
title: title
};
return '';
});
lex_(str, tokens, line);
return tokens; return tokens;
}; };
@ -207,30 +204,32 @@ var inline = function(str) {
// reference-style link. // reference-style link.
str = str.replace( str = str.replace(
/\[([^\]]+)\]\[([^\]]+)\]/g, /\[([^\]]+)\]\[([^\]]+)\]/g,
function(_, text, id) { function(__, text, id) {
var link = links[id]; var link = tokens.links[id];
return '<a href="' return '<a href="'
+ link.href + '"' + link.href + '"'
+ (link.title + (link.title
? ' title="' ? ' title="'
+ link.title + '"' + link.title + '"'
: '') : '')
+ '>' + text + '</a>'; + '>' + text + '</a>';
}); }
);
// for <http://hello.world/> links // for <http://hello.world/> links
str = str.replace( str = str.replace(
/(?:<|&lt;)([^<>:\/ ]+:(?:\/\/)?[^>\n]+?|[^<>\n]+?(@)[^<>\n]+?)(?:&gt;|>)/g, /(?:<|&lt;)([^<>:\/ ]+:(?:\/\/)?[^>\n]+?|[^<>\n]+?(@)[^<>\n]+?)(?:&gt;|>)/g,
function(_, href, at) { function(__, href, at) {
if (at) { if (at) {
// according to the markdown "spec" // according to the markdown "spec"
// we need to mangle email addresses // we need to mangle email addresses
var href = mangle(href) var href = mangle(href)
, mail = mangle('mailto:') + href; , mail = mangle('mailto:') + href;
return '<a href="' + mail + '">' + href + '</a>'; return '<a href="' + mail + '">' + href + '</a>';
}
return '<a href="' + href + '">' + href + '</a>';
} }
return '<a href="' + href + '">' + href + '</a>'; );
});
// strong // strong
str = str.replace(/__([^_]+)__/g, '<strong>$1</strong>'); str = str.replace(/__([^_]+)__/g, '<strong>$1</strong>');
@ -241,7 +240,7 @@ var inline = function(str) {
str = str.replace(/\*([^*]+)\*/g, '<em>$1</em>'); str = str.replace(/\*([^*]+)\*/g, '<em>$1</em>');
// code // code
str = str.replace(/`([^`]+)`/g, function(_, s) { str = str.replace(/`([^`]+)`/g, function(__, s) {
return '<code>' + escape(s) + '</code>'; return '<code>' + escape(s) + '</code>';
}); });
@ -255,7 +254,8 @@ var inline = function(str) {
* Parsing * Parsing
*/ */
var tokens; var tokens
, token;
var next = function() { var next = function() {
return token = tokens.pop(); return token = tokens.pop();
@ -330,7 +330,6 @@ var parse = function(src) {
tokens = null; tokens = null;
token = null; token = null;
links = null;
return out.join(' '); return out.join(' ');
}; };