Comparing version 0.1.4 to 0.1.5
/** | ||
* marked - A markdown parser | ||
* Copyright (c) 2011, Christopher Jeffrey. (MIT Licensed) | ||
* marked - A markdown parser (https://github.com/chjj/marked) | ||
* Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) | ||
*/ | ||
@@ -15,2 +15,3 @@ | ||
code: /^ {4,}[^\n]*(?:\n {4,}[^\n]*|\n)*(?=\n| *$)/, | ||
gfm_code: /^ *``` *(\w+)? *\n([^\0]+?)\s*```(?= *\n| *$)/, | ||
hr: /^( *[\-*_]){3,} *\n/, | ||
@@ -22,5 +23,41 @@ heading: /^ *(#{1,6}) *([^\0]+?) *#* *\n+/, | ||
html: /^ *(?:<!--[^\0]*?-->|<(\w+)[^\0]+?<\/\1>|<\w+[^>]*>) *(?:\n{2,}|\s*$)/, | ||
text: /^[^\n]+/ | ||
text: /^[^\n]+/, | ||
paragraph: /^/ | ||
}; | ||
block.paragraph = (function() { | ||
var body = []; | ||
// this rule determines which tokens are able to | ||
// immediately follow a line of text on the top level. | ||
// everything below conforms to markdown.pl. | ||
(function push(rule) { | ||
rule = rule.source || block[rule].source; | ||
body.push(rule.replace(/(^|[^\[])\^/g, '$1')); | ||
return push; | ||
}) | ||
// no code | ||
('gfm_code') | ||
('hr') | ||
('heading') | ||
('lheading') | ||
('blockquote') | ||
// no list | ||
// html - stop before block-level elements only | ||
// from: github.com/Kroc/ReMarkable | ||
// (possibly stray from conformance and remove this altogether) | ||
(new RegExp('<' | ||
+ '(?:article|aside|audio|blockquote|canvas|caption|col|colgroup|dialog|div' | ||
+ '|d[ltd]|embed|fieldset|figure|figcaption|footer|form|h[1-6r]|header' | ||
+ '|hgroup|input|label|legend|li|nav|noscript|object|[ou]l|optgroup|option' | ||
+ '|p|param|pre|script|section|select|source|table|t(?:body|foot|head)' | ||
+ '|t[dhr]|textarea|video)')); | ||
body = body.join('|'); | ||
return new | ||
RegExp('^([^\\n]+\\n?(?!' + body + '))+\\n*'); | ||
})(); | ||
/** | ||
@@ -50,6 +87,6 @@ * Block Lexer | ||
return block.token(str, tokens); | ||
return block.token(str, tokens, true); | ||
}; | ||
block.token = function(str, tokens) { | ||
block.token = function(str, tokens, top) { | ||
var str = str.replace(/^ +$/gm, '') | ||
@@ -72,3 +109,2 @@ , loose | ||
} | ||
continue; | ||
} | ||
@@ -82,3 +118,5 @@ | ||
type: 'code', | ||
text: cap | ||
text: cap[cap.length-1] === '\n' | ||
? cap.slice(0, -1) | ||
: cap | ||
}); | ||
@@ -88,2 +126,13 @@ continue; | ||
// gfm_code | ||
if (cap = block.gfm_code.exec(str)) { | ||
str = str.substring(cap[0].length); | ||
tokens.push({ | ||
type: 'code', | ||
lang: cap[1], | ||
text: cap[2] | ||
}); | ||
continue; | ||
} | ||
// heading | ||
@@ -127,3 +176,6 @@ if (cap = block.heading.exec(str)) { | ||
cap = cap[0].replace(/^ *>/gm, ''); | ||
block.token(cap, tokens); | ||
// pass `top` to keep the current | ||
// "toplevel" state. this is exactly | ||
// how markdown.pl works. | ||
block.token(cap, tokens, top); | ||
tokens.push({ | ||
@@ -148,3 +200,3 @@ type: 'blockquote_end' | ||
cap = cap[0].match( | ||
/^( *)([*+-]|\d+\.)[^\n]*(?:\n(?!\1(?:\2|\d+\.))[^\n]*)*/gm | ||
/^( *)([*+-]|\d+\.)[^\n]*(?:\n(?!\1\2|\1\d+\.)[^\n]*)*/gm | ||
); | ||
@@ -156,4 +208,4 @@ | ||
for (; i < l; i++) { | ||
// remove the list items sigil | ||
// so its seen as the next token | ||
// remove the list item's bullet | ||
// so it is seen as the next token | ||
item = cap[i].replace(/^ *([*+-]|\d+\.) */, ''); | ||
@@ -195,3 +247,14 @@ // outdent whatever the | ||
// text | ||
// optimization for top-level paragraphs. | ||
// ignores list-item-looking lines. | ||
if (top && (cap = block.paragraph.exec(str))) { | ||
str = str.substring(cap[0].length); | ||
tokens.push({ | ||
type: 'paragraph', | ||
text: cap[0] | ||
}); | ||
continue; | ||
} | ||
// text (top-level should never reach here) | ||
if (cap = block.text.exec(str)) { | ||
@@ -217,2 +280,3 @@ str = str.substring(cap[0].length); | ||
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, | ||
gfm_autolink: /^(\w+:\/\/[^\s]+[^.,:;"')\]\s])/, | ||
tag: /^<!--[^\0]*?-->|^<\/?\w+[^>]*>/, | ||
@@ -222,4 +286,4 @@ link: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]\(([^\)]*)\)/, | ||
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, | ||
strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, | ||
em: /^_([^_]+)_|^\*([^*]+)\*/, | ||
strong: /^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/, | ||
em: /^\b_(?=\S)([^\0]*?\S)_\b|^\*(?=\S)([^\0]*?\S)\*/, | ||
code: /^`([^`]+)`|^``([^\0]+?)``/, | ||
@@ -230,3 +294,2 @@ br: /^ {2,}\n(?!\s*$)/, | ||
// hacky, but performant | ||
inline.text = (function() { | ||
@@ -241,2 +304,3 @@ var body = []; | ||
('escape') | ||
('gfm_autolink') | ||
('tag') | ||
@@ -293,2 +357,15 @@ ('nolink') | ||
// gfm_autolink | ||
if (cap = inline.gfm_autolink.exec(str)) { | ||
str = str.substring(cap[0].length); | ||
text = escape(cap[1]); | ||
href = text; | ||
out += '<a href="' | ||
+ href | ||
+ '">' | ||
+ text | ||
+ '</a>'; | ||
continue; | ||
} | ||
// tag | ||
@@ -379,6 +456,6 @@ if (cap = inline.tag.exec(str)) { | ||
+ (link.title | ||
? ' title="' | ||
+ escape(link.title) | ||
+ '"' | ||
: '') | ||
? ' title="' | ||
+ escape(link.title) | ||
+ '"' | ||
: '') | ||
+ '>' | ||
@@ -394,6 +471,6 @@ + inline.lexer(cap[1]) | ||
+ (link.title | ||
? ' title="' | ||
+ escape(link.title) | ||
+ '"' | ||
: '') | ||
? ' title="' | ||
+ escape(link.title) | ||
+ '"' | ||
: '') | ||
+ '>'; | ||
@@ -432,7 +509,12 @@ } | ||
case 'code': { | ||
if (token.text[token.text.length-1] === '\n') { | ||
token.text = token.text.slice(0, -1); | ||
} | ||
return '<pre><code>' | ||
+ escape(token.text, true) | ||
return '<pre><code' | ||
+ (token.lang | ||
? ' class="' | ||
+ token.lang | ||
+ '"' | ||
: '') | ||
+ '>' | ||
+ (token.escaped | ||
? token.text | ||
: escape(token.text, true)) | ||
+ '</code></pre>'; | ||
@@ -494,2 +576,7 @@ } | ||
} | ||
case 'paragraph': { | ||
return '<p>' | ||
+ inline.lexer(token.text) | ||
+ '</p>'; | ||
} | ||
case 'text': { | ||
@@ -526,3 +613,3 @@ return '<p>' | ||
return out.join(' '); | ||
return out.join('\n'); | ||
}; | ||
@@ -529,0 +616,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"author": "Christopher Jeffrey", | ||
"version": "0.1.4", | ||
"version": "0.1.5", | ||
"main": "./lib/marked.js", | ||
@@ -8,0 +8,0 @@ "bin": { "marked": "./bin/marked" }, |
# marked | ||
A full-featured markdown parser and compiler implemented in ~430 lines of JS. | ||
A full-featured markdown parser and compiler. | ||
Built for speed. | ||
@@ -8,2 +8,4 @@ | ||
node v0.4.x | ||
``` bash | ||
@@ -17,2 +19,22 @@ $ node test --bench | ||
node v0.6.x | ||
``` bash | ||
$ node test --bench | ||
marked completed in 7904ms. | ||
marked (with gfm) completed in 8947ms. | ||
discount completed in 7171ms. | ||
showdown (reuse converter) completed in 15729ms. | ||
showdown (new converter) completed in 18149ms. | ||
markdown-js completed in 24521ms. | ||
``` | ||
__Marked is now only ~700ms behind Discount (which is written in C).__ | ||
For those feeling skeptical: These benchmarks run the entire markdown test suite | ||
1000 times. The test suite tests every feature. It doesn't cater to specific | ||
aspects. | ||
Benchmarks for other engines to come (?). | ||
## Install | ||
@@ -24,3 +46,3 @@ | ||
# Another javascript markdown parser | ||
## Another javascript markdown parser | ||
@@ -31,4 +53,4 @@ The point of marked was to create a markdown compiler where it was possible to | ||
marked lingers around 430 (may vary) lines long and still implements all | ||
markdown features. It is also now fully compatible with the client-side. | ||
marked is very concise and still implements all markdown features. It is also | ||
now fully compatible with the client-side. | ||
@@ -43,2 +65,5 @@ marked more or less passes the official markdown test suite in its | ||
Along with implementing every markdown feature, marked also implements | ||
[GFM features](http://github.github.com/github-flavored-markdown/). | ||
## Usage | ||
@@ -67,9 +92,50 @@ | ||
## Todo (& notes to self) | ||
## CLI | ||
- Implement GFM features. | ||
- Possibly add some | ||
[ReMarkable](http://camendesign.com/code/remarkable/documentation.html) | ||
features while remaining backwardly compatible with all markdown syntax. | ||
- Optimize the lexer to return an iterator instead of a collection of tokens. | ||
- Add an explicit pretty printing and minification feature. | ||
``` bash | ||
$ marked -o hello.html | ||
hello world | ||
^D | ||
$ cat hello.html | ||
<p>hello world</p> | ||
``` | ||
## Syntax Highlighting | ||
Marked has an interface that allows for a syntax highlighter to highlight code | ||
blocks before they're output. | ||
Example implementation: | ||
``` js | ||
var highlight = require('my-syntax-highlighter') | ||
, marked_ = require('marked'); | ||
var marked = function(text) { | ||
var tokens = marked_.lexer(text) | ||
, l = tokens.length | ||
, i = 0 | ||
, token; | ||
for (; i < l; i++) { | ||
token = tokens[i]; | ||
if (token.type === 'code') { | ||
token.text = highlight(token.text, token.lang); | ||
// marked should not escape this | ||
token.escaped = true; | ||
} | ||
} | ||
text = marked_.parser(tokens); | ||
return text; | ||
}; | ||
module.exports = marked; | ||
``` | ||
## License | ||
Copyright (c) 2011-2012, Christopher Jeffrey. (MIT License) | ||
See LICENSE for more info. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
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
136
1
21022
8
565