Comparing version 0.0.1 to 0.0.2
@@ -6,7 +6,76 @@ /** | ||
;(function() { | ||
/** | ||
* Client-Side Shim | ||
*/ | ||
if (typeof module === 'undefined') { | ||
var keys = Object.keys | ||
, hop = Object.prototype.hasOwnProperty | ||
, first = true | ||
, a = Array.prototype; | ||
Object.keys = function(obj) { | ||
if (obj === inline) { | ||
if (!first) { | ||
return [ | ||
'autolink', | ||
'tag', | ||
'img', | ||
'link', | ||
'reflink', | ||
'strong', | ||
'em', | ||
'escape', | ||
'text' | ||
]; | ||
} | ||
first = false; | ||
} else if (obj === block) { | ||
return [ | ||
'newline', | ||
'block', | ||
'heading', | ||
'lheading', | ||
'hr', | ||
'blockquote', | ||
'list', | ||
'html', | ||
'text' | ||
]; | ||
} | ||
if (keys) { | ||
return keys.call(Object, obj); | ||
} | ||
var out = [] | ||
, key; | ||
for (key in obj) if (hop.call(obj, key)) { | ||
out.push(key); | ||
} | ||
return out; | ||
}; | ||
if (!a.forEach) a.forEach = function(func, context) { | ||
var i = 0 | ||
, l = this.length; | ||
for (; i < l; i++) { | ||
func.call(context, this[i], i, this); | ||
} | ||
}; | ||
if (!a.map) a.map = function(func, context) { | ||
var out = []; | ||
a.forEach.call(this, function(val, i, obj) { | ||
out.push(func.call(context, val, i, obj)); | ||
}); | ||
return out; | ||
}; | ||
} | ||
/** | ||
* Block-Level Grammar | ||
*/ | ||
var rules = { | ||
var block = { | ||
newline: /^\n/, | ||
@@ -23,42 +92,25 @@ block: /^[ ]{4,}[^\n]*(?:\n[ ]{4,}[^\n]*)*/, | ||
var keys = Object.keys(rules) | ||
, len = keys.length; | ||
block.keys = Object.keys(block); | ||
/** | ||
* Shared | ||
* Lexer | ||
*/ | ||
var line | ||
, links | ||
, token | ||
, tokens; | ||
block.lexer = function(str) { | ||
var tokens = [] | ||
, links = {}; | ||
/** | ||
* Lexer | ||
*/ | ||
// normalize whitespace | ||
str = str.replace(/\r\n/g, '\n') | ||
.replace(/\r/g, '\n'); | ||
var lex = function(str, tokens) { | ||
if (!tokens) { | ||
tokens = []; | ||
line = 0; | ||
str = str.replace(/\t/g, ' '); | ||
// normalize whitespace | ||
str = str.replace(/\r\n/g, '\n') | ||
.replace(/\r/g, '\n'); | ||
// experimental | ||
//str = str.replace(/(^|\n) +(\n|$)/g, '$1$2'); | ||
str = str.replace(/\t/g, ' '); | ||
//str = str.replace(/(^|\n) +(\n|$)/g, '$1$2'); | ||
// get the link definitions out of | ||
// the way as they dont compile to | ||
// anything, this results in a boost | ||
// to performance. we could put this | ||
// in the "inline" function instead | ||
// but it confuses things because | ||
// it doesn't actually output anything | ||
// and it causes a performance hit. | ||
links = {}; | ||
str = str.replace( | ||
/^ {0,3}\[([^\]]+)\]: *([^ ]+)(?: +"([^"]+)")?/gm, | ||
function(_, id, href, title) { | ||
// grab link definitons | ||
str = str.replace( | ||
/^ {0,3}\[([^\]]+)\]: *([^ ]+)(?: +"([^"]+)")?[ \t]*(?:\n|$)/gm, | ||
function(_, id, href, title) { | ||
links[id] = { | ||
@@ -69,13 +121,23 @@ href: href, | ||
return ''; | ||
}); | ||
} | ||
} | ||
); | ||
tokens.links = links; | ||
return block.token(str, tokens, 0); | ||
}; | ||
block.token = function lex(str, tokens, line) { | ||
var keys = block.keys | ||
, len = keys.length; | ||
var i | ||
, key | ||
, rule; | ||
, rule | ||
, cap; | ||
while (str.length) | ||
while (str.length) | ||
for (i = 0; i < len; i++) { | ||
key = keys[i]; | ||
rule = rules[key]; | ||
rule = block[key]; | ||
@@ -113,3 +175,3 @@ cap = rule.exec(str); | ||
case 'block': | ||
cap = cap[0].replace(/^ +/gm, ''); | ||
cap = cap[0].replace(/^ {4}/gm, ''); | ||
tokens.push({ | ||
@@ -150,3 +212,6 @@ type: 'block', | ||
}); | ||
lex(item, tokens); | ||
// recurse | ||
lex(item, tokens, line); | ||
tokens.push({ | ||
@@ -176,3 +241,6 @@ type: 'list_item_end', | ||
cap = cap[0].replace(/^ *>/gm, ''); | ||
lex(cap, tokens); | ||
// recurse | ||
lex(cap, tokens, line); | ||
tokens.push({ | ||
@@ -194,72 +262,121 @@ type: 'blockquote_end', | ||
// this is really bad. i should define | ||
// some lexemes for all of the inline stuff, | ||
// but this was just easier for the time being. | ||
var inline = { | ||
autolink: /^<([^ >]*(:|@)[^ >]*)>/, | ||
tag: /^<[^\n>]+>/, | ||
img: /^!\[([^\]]+)\]\(([^\s\)]+)\s*([^\)]*)\)/, | ||
link: /^\[([^\]]+)\]\(([^\)]+)\)/, | ||
reflink: /^\[([^\]]+)\]\[([^\]]+)\]/, | ||
strong: /^__([\s\S]+?)__|^\*\*([\s\S]+?)\*\*/, | ||
em: /^_([^_]+)_|^\*([^*]+)\*/, | ||
escape: /^`([^`]+)`|^``([\s\S]+?)``/ | ||
}; | ||
var inline = function(str) { | ||
// img | ||
str = str.replace( | ||
/!\[([^\]]+)\]\(([^\s\)]+)\s*([^\)]*)\)/g, | ||
function(_, alt, src, title) { | ||
return '<img src="' | ||
+ src + '" alt="' | ||
+ alt + '"' | ||
+ (title | ||
? ' title="' + title + '"' | ||
: '') | ||
+ '>'; | ||
}); | ||
// super hack for performance | ||
inline.text = new RegExp( | ||
'^([\\s\\S]+?)(?=' | ||
+ Object.keys(inline).map(function(key) { | ||
return inline[key].source.replace(/(^|[^\[])\^/g, '$1'); | ||
}).join('|') | ||
+ '|$)' | ||
); | ||
// links | ||
str = str.replace( | ||
/\[([^\]]+)\]\(([^\)]+)\)/g, | ||
'<a href="$2">$1</a>' | ||
); | ||
inline.keys = Object.keys(inline); | ||
// This is [an example][id] | ||
// reference-style link. | ||
str = str.replace( | ||
/\[([^\]]+)\]\[([^\]]+)\]/g, | ||
function(_, text, id) { | ||
var link = links[id]; | ||
return '<a href="' | ||
+ link.href + '"' | ||
+ (link.title | ||
? ' title="' | ||
+ link.title + '"' | ||
: '') | ||
+ '>' + text + '</a>'; | ||
}); | ||
/** | ||
* Inline Lexer | ||
*/ | ||
// for <http://hello.world/> links | ||
str = str.replace( | ||
/(?:<|<)([^<>:\/ ]+:(?:\/\/)?[^>\n]+?|[^<>\n]+?(@)[^<>\n]+?)(?:>|>)/g, | ||
function(_, href, at) { | ||
if (at) { | ||
// according to the markdown "spec" | ||
// we need to mangle email addresses | ||
var href = mangle(href) | ||
, mail = mangle('mailto:') + href; | ||
return '<a href="' + mail + '">' + href + '</a>'; | ||
} | ||
return '<a href="' + href + '">' + href + '</a>'; | ||
}); | ||
inline.lexer = function(str) { | ||
var rules = inline | ||
, keys = inline.keys | ||
, len = keys.length | ||
, out = '' | ||
, links = tokens.links; | ||
// strong | ||
str = str.replace(/__([^_]+)__/g, '<strong>$1</strong>'); | ||
str = str.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>'); | ||
var i | ||
, key | ||
, rule | ||
, cap | ||
, link | ||
, text | ||
, href; | ||
// em | ||
str = str.replace(/_([^_]+)_/g, '<em>$1</em>'); | ||
str = str.replace(/\*([^*]+)\*/g, '<em>$1</em>'); | ||
while (str.length) { | ||
for (i = 0; i < len; i++) { | ||
key = keys[i]; | ||
rule = rules[key]; | ||
// code | ||
str = str.replace(/`([^`]+)`/g, function(_, s) { | ||
return '<code>' + escape(s) + '</code>'; | ||
}); | ||
cap = rule.exec(str); | ||
if (!cap) continue; | ||
str = str.substring(cap[0].length); | ||
// br | ||
str = str.replace(/ $/gm, '<br>'); | ||
switch (key) { | ||
case 'tag': | ||
out += cap[0]; | ||
break; | ||
case 'img': | ||
out += '<img src="' | ||
+ escape(cap[2]) | ||
+ '" alt="' + escape(cap[1]) | ||
+ '"' | ||
+ (cap[3] | ||
? ' title="' | ||
+ escape(cap[3]) | ||
+ '"' | ||
: '') | ||
+ '>'; | ||
break; | ||
case 'link': | ||
case 'reflink': | ||
link = links[cap[2]] || ''; | ||
out += '<a href="' | ||
+ escape(link.href || cap[2]) | ||
+ '"' | ||
+ (link.title | ||
? ' title="' | ||
+ escape(link.title) | ||
+ '"' | ||
: '') | ||
+ '>' | ||
+ inline.lexer(cap[1]) | ||
+ '</a>'; | ||
break; | ||
case 'autolink': | ||
if (cap[2] === '@') { | ||
text = mangle(cap[1]); | ||
href = mangle('mailto:') + text; | ||
} else { | ||
text = escape(cap[1]); | ||
href = text; | ||
} | ||
out += '<a href="' + href + '">' | ||
+ text | ||
+ '</a>'; | ||
break; | ||
case 'strong': | ||
out += '<strong>' | ||
+ inline.lexer(cap[2] || cap[1]) | ||
+ '</strong>'; | ||
break; | ||
case 'em': | ||
out += '<em>' | ||
+ inline.lexer(cap[2] || cap[1]) | ||
+ '</em>'; | ||
break; | ||
case 'escape': | ||
out += '<code>' | ||
+ escape(cap[2] || cap[1]) | ||
+ '</code>'; | ||
break; | ||
case 'text': | ||
out += escape(cap[1]); | ||
break; | ||
default: | ||
break; | ||
} | ||
break; | ||
} | ||
} | ||
return str; | ||
return out; | ||
}; | ||
@@ -271,2 +388,5 @@ | ||
var tokens | ||
, token; | ||
var next = function() { | ||
@@ -282,3 +402,3 @@ return token = tokens.pop(); | ||
return '<h' + token.depth + '>' | ||
+ inline(token.text) | ||
+ inline.lexer(token.text) | ||
+ '</h' + token.depth + '>'; | ||
@@ -309,4 +429,6 @@ case 'block': | ||
while (next().type !== 'list_item_end') { | ||
// TODO incorporate paragraph | ||
// list items here | ||
if (token.type === 'text') { | ||
body.push(inline(token.text)); | ||
body.push(inline.lexer(token.text)); | ||
} else { | ||
@@ -320,3 +442,3 @@ body.push(tok()); | ||
case 'html': | ||
return inline(token.text); | ||
return inline.lexer(token.text); | ||
case 'text': | ||
@@ -333,3 +455,3 @@ var body = [] | ||
return '<p>' | ||
+ inline(body.join(' ')) | ||
+ inline.lexer(body.join(' ')) | ||
+ '</p>'; | ||
@@ -349,6 +471,4 @@ } | ||
token = null; | ||
links = null; | ||
line = null; | ||
return out.join('\n'); | ||
return out.join(' '); | ||
}; | ||
@@ -360,5 +480,5 @@ | ||
var escape = function(html, d) { | ||
var escape = function(html) { | ||
return html | ||
.replace(d ? /&(?![^;\n]+;)/ : /&/g, '&') | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
@@ -377,4 +497,4 @@ .replace(/>/g, '>') | ||
for (; i < l; i++) { | ||
ch = str[i].charCodeAt(0); | ||
if (Math.random() > .5) { | ||
ch = str.charCodeAt(i); | ||
if (Math.random() > 0.5) { | ||
ch = 'x' + ch.toString(16); | ||
@@ -392,9 +512,15 @@ } | ||
exports = function(str) { | ||
return parse(lex(str)); | ||
var marked = function(str) { | ||
return parse(block.lexer(str)); | ||
}; | ||
exports.parser = parse; | ||
exports.lexer = lex; | ||
marked.parser = parse; | ||
marked.lexer = block.lexer; | ||
module.exports = exports; | ||
if (typeof module !== 'undefined') { | ||
module.exports = marked; | ||
} else { | ||
this.marked = marked; | ||
} | ||
}).call(this); |
@@ -5,6 +5,7 @@ { | ||
"author": "Christopher Jeffrey", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"main": "./lib/marked.js", | ||
"bin": { "marked": "./bin/marked" }, | ||
"repository": "git://github.com/chjj/marked.git", | ||
"keywords": [ "markdown", "markup" ] | ||
} | ||
} |
@@ -8,6 +8,8 @@ # marked | ||
$ node test/bench | ||
marked: 6260ms | ||
showdown: 21665ms | ||
markdownjs: 69168ms | ||
``` bash | ||
$ node test/bench | ||
marked: 6260ms | ||
showdown: 21665ms | ||
markdownjs: 69168ms | ||
``` | ||
@@ -22,13 +24,19 @@ The point of marked was to create a markdown compiler where it was possible to | ||
$ npm install marked | ||
``` bash | ||
$ npm install marked | ||
``` | ||
## Usage | ||
var marked = require('marked'); | ||
console.log(marked('i am using __markdown__.')); | ||
``` js | ||
var marked = require('marked'); | ||
console.log(marked('i am using __markdown__.')); | ||
``` | ||
You also have direct access to the lexer and parser if you so desire. | ||
var tokens = md.lexer(str); | ||
console.log(md.parser(tokens)); | ||
``` js | ||
var tokens = marked.lexer(str); | ||
console.log(marked.parser(tokens)); | ||
``` | ||
@@ -44,4 +52,2 @@ ## Todo (& notes to self) | ||
be possible. | ||
- Write actual rules for inline markup (links, em, strong, etc). Currently, | ||
only blocks are tokenized. | ||
- Possibly add some | ||
@@ -56,5 +62,3 @@ [ReMarkable](http://camendesign.com/code/remarkable/documentation.html) | ||
- Add an explicit pretty printing and minification feature. | ||
- Handle escaping of HTML entities better. | ||
- Client-side compatibility. | ||
I've still just begun to write this. I expect I will be updating it frequently. | ||
I've still just begun to write this. I expect I will be updating it frequently. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17413
12
491
61
4