remarkable
Advanced tools
Comparing version 1.2.0 to 1.2.1
@@ -17,2 +17,3 @@ { | ||
"bower_components", | ||
"coverage", | ||
"demo", | ||
@@ -19,0 +20,0 @@ "lib", |
@@ -1,4 +0,13 @@ | ||
1.2.0 / WIP | ||
1.2.1 / 2014-10-28 | ||
------------------ | ||
- Fixed speed degradation when linkifier enabled. | ||
- Added coverage reports. | ||
- Added debug view to demo (show internal representation) | ||
- Other minor optimizations and cleanup. | ||
1.2.0 / 2014-10-26 | ||
------------------ | ||
- Added `<ins>` rule. | ||
@@ -5,0 +14,0 @@ - Added `<mark>` rule. |
@@ -15,3 +15,2 @@ // Regexps to match html elements | ||
val = val.source || val; | ||
//val = val.replace(/(^|[^\[])\^/g, '$1'); | ||
regex = regex.replace(name, val); | ||
@@ -18,0 +17,0 @@ return self; |
@@ -8,10 +8,10 @@ // Commonmark default options | ||
options: { | ||
html: true, // Enable html tags in source | ||
html: true, // Enable HTML tags in source | ||
xhtmlOut: true, // Use '/' to close single tags (<br />) | ||
breaks: false, // Convert '\n' in paragraphs into <br> | ||
langPrefix: 'language-', // CSS language prefix for fenced blocks | ||
linkify: false, // autoconvert url-like texts to links | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Highlighter function. Should return escaped html, | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
@@ -56,3 +56,3 @@ highlight: function (/*str, , lang*/) { return ''; }, | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for russian, '„“' for deutch, empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
@@ -59,0 +59,0 @@ trademark: true, // (tm) (TM) → ™ |
@@ -8,10 +8,10 @@ // Remarkable default options | ||
options: { | ||
html: false, // Enable html tags in source | ||
html: false, // Enable HTML tags in source | ||
xhtmlOut: false, // Use '/' to close single tags (<br />) | ||
breaks: false, // Convert '\n' in paragraphs into <br> | ||
langPrefix: 'language-', // CSS language prefix for fenced blocks | ||
linkify: false, // autoconvert url-like texts to links | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Highlighter function. Should return escaped html, | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
@@ -58,3 +58,3 @@ highlight: function (/*str, , lang*/) { return ''; }, | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for russian, '„“' for deutch, empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
@@ -61,0 +61,0 @@ trademark: true, // (tm) (TM) → ™ |
@@ -8,10 +8,10 @@ // Remarkable default options | ||
options: { | ||
html: false, // Enable html tags in source | ||
html: false, // Enable HTML tags in source | ||
xhtmlOut: false, // Use '/' to close single tags (<br />) | ||
breaks: false, // Convert '\n' in paragraphs into <br> | ||
langPrefix: 'language-', // CSS language prefix for fenced blocks | ||
linkify: false, // autoconvert url-like texts to links | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Highlighter function. Should return escaped html, | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
@@ -32,3 +32,3 @@ highlight: function (/*str, , lang*/) { return ''; }, | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for russian, '„“' for deutch, empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
@@ -35,0 +35,0 @@ trademark: true, // (tm) (TM) → ™ |
@@ -10,3 +10,3 @@ // Class of link replacement rules | ||
var rules = [ | ||
var _rules = [ | ||
require('./rules_text/linkify') | ||
@@ -23,4 +23,4 @@ ]; | ||
for (var i = 0; i < rules.length; i++) { | ||
this.ruler.after(rules[i]); | ||
for (var i = 0; i < _rules.length; i++) { | ||
this.ruler.after(_rules[i]); | ||
} | ||
@@ -27,0 +27,0 @@ } |
@@ -11,15 +11,15 @@ // Block parser | ||
var rules = []; | ||
var _rules = []; | ||
// `list` should be after `hr`, but before `heading` | ||
rules.push([ require('./rules_block/code') ]); | ||
rules.push([ require('./rules_block/fences'), 'paragraph', 'blockquote', 'list' ]); | ||
rules.push([ require('./rules_block/blockquote'), 'paragraph', 'blockquote', 'list' ]); | ||
rules.push([ require('./rules_block/hr'), 'paragraph', 'blockquote', 'list' ]); | ||
rules.push([ require('./rules_block/list'), 'paragraph', 'blockquote' ]); | ||
rules.push([ require('./rules_block/heading'), 'paragraph', 'blockquote' ]); | ||
rules.push([ require('./rules_block/lheading') ]); | ||
rules.push([ require('./rules_block/htmlblock'), 'paragraph', 'blockquote' ]); | ||
rules.push([ require('./rules_block/table'), 'paragraph' ]); | ||
rules.push([ require('./rules_block/paragraph') ]); | ||
_rules.push([ require('./rules_block/code') ]); | ||
_rules.push([ require('./rules_block/fences'), 'paragraph', 'blockquote', 'list' ]); | ||
_rules.push([ require('./rules_block/blockquote'), 'paragraph', 'blockquote', 'list' ]); | ||
_rules.push([ require('./rules_block/hr'), 'paragraph', 'blockquote', 'list' ]); | ||
_rules.push([ require('./rules_block/list'), 'paragraph', 'blockquote' ]); | ||
_rules.push([ require('./rules_block/heading'), 'paragraph', 'blockquote' ]); | ||
_rules.push([ require('./rules_block/lheading') ]); | ||
_rules.push([ require('./rules_block/htmlblock'), 'paragraph', 'blockquote' ]); | ||
_rules.push([ require('./rules_block/table'), 'paragraph' ]); | ||
_rules.push([ require('./rules_block/paragraph') ]); | ||
@@ -37,4 +37,4 @@ | ||
for (var i = 0; i < rules.length; i++) { | ||
this.ruler.after(rules[i][0], rules[i].slice(1)); | ||
for (var i = 0; i < _rules.length; i++) { | ||
this.ruler.after(_rules[i][0], _rules[i].slice(1)); | ||
} | ||
@@ -41,0 +41,0 @@ } |
@@ -12,18 +12,17 @@ // Inline parser | ||
var rules = []; | ||
var _rules = []; | ||
_rules.push(require('./rules_inline/text')); | ||
_rules.push(require('./rules_inline/newline')); | ||
_rules.push(require('./rules_inline/escape')); | ||
_rules.push(require('./rules_inline/backticks')); | ||
_rules.push(require('./rules_inline/del')); | ||
_rules.push(require('./rules_inline/ins')); | ||
_rules.push(require('./rules_inline/mark')); | ||
_rules.push(require('./rules_inline/emphasis')); | ||
_rules.push(require('./rules_inline/links')); | ||
_rules.push(require('./rules_inline/autolink')); | ||
_rules.push(require('./rules_inline/htmltag')); | ||
_rules.push(require('./rules_inline/entity')); | ||
// Pure text | ||
rules.push(require('./rules_inline/text')); | ||
rules.push(require('./rules_inline/newline')); | ||
rules.push(require('./rules_inline/escape')); | ||
rules.push(require('./rules_inline/backticks')); | ||
rules.push(require('./rules_inline/del')); | ||
rules.push(require('./rules_inline/ins')); | ||
rules.push(require('./rules_inline/mark')); | ||
rules.push(require('./rules_inline/emphasis')); | ||
rules.push(require('./rules_inline/links')); | ||
rules.push(require('./rules_inline/autolink')); | ||
rules.push(require('./rules_inline/htmltag')); | ||
rules.push(require('./rules_inline/entity')); | ||
@@ -54,3 +53,3 @@ var BAD_PROTOCOLS = [ 'vbscript', 'javascript', 'file' ]; | ||
// - '{}$%@+=:' reserved for extentions | ||
this.textMatch = /^[^\n\\`*_\[\]!&<{}$%@~+=:]+/; | ||
this.textMatch = /[\n\\`*_\[\]!&<{}$%@~+=:]/; | ||
@@ -63,4 +62,4 @@ // By default CommonMark allows too much in links | ||
for (var i = 0; i < rules.length; i++) { | ||
this.ruler.after(rules[i]); | ||
for (var i = 0; i < _rules.length; i++) { | ||
this.ruler.after(_rules[i]); | ||
} | ||
@@ -80,3 +79,2 @@ } | ||
var i, cached_pos, pos = state.pos, | ||
rules = this._rules, | ||
len = this._rules.length; | ||
@@ -90,3 +88,3 @@ | ||
for (i = 0; i < len; i++) { | ||
if (rules[i](state, true)) { | ||
if (this._rules[i](state, true)) { | ||
state.cacheSet(pos, state.pos); | ||
@@ -106,3 +104,2 @@ return; | ||
var ok, i, | ||
rules = this._rules, | ||
len = this._rules.length, | ||
@@ -121,3 +118,3 @@ end = state.posMax; | ||
for (i = 0; i < len; i++) { | ||
ok = rules[i](state, false); | ||
ok = this._rules[i](state, false); | ||
if (ok) { break; } | ||
@@ -124,0 +121,0 @@ } |
@@ -285,3 +285,3 @@ 'use strict'; | ||
result = '', | ||
rules = this.rules; | ||
_rules = this.rules; | ||
@@ -292,3 +292,3 @@ for (i = 0, len = tokens.length; i < len; i++) { | ||
} else { | ||
result += rules[tokens[i].type](tokens, i, options); | ||
result += _rules[tokens[i].type](tokens, i, options); | ||
} | ||
@@ -295,0 +295,0 @@ } |
@@ -184,3 +184,3 @@ // Ruler is helper class to build responsibility chains from parse rules. | ||
if (idx < 0) { throw new Error('Rules namager: invalid rule name ' + name);} | ||
if (idx < 0) { throw new Error('Rules manager: invalid rule name ' + name); } | ||
this.rules[idx].enabled = true; | ||
@@ -205,3 +205,3 @@ | ||
if (idx < 0) { throw new Error('Rules namager: invalid rule name ' + name);} | ||
if (idx < 0) { throw new Error('Rules manager: invalid rule name ' + name); } | ||
this.rules[idx].enabled = false; | ||
@@ -208,0 +208,0 @@ |
@@ -9,7 +9,2 @@ // Parser state class | ||
// Prepare string to parse: | ||
// | ||
// - replace tabs with spaces | ||
// - remove `\r` to simplify newlines check (???) | ||
this.src = src; | ||
@@ -61,3 +56,2 @@ | ||
} else { | ||
this.tShift.push(indent); | ||
indent_found = true; | ||
@@ -67,5 +61,7 @@ } | ||
if (ch === 0x0A) { | ||
if (ch === 0x0A || pos === len - 1) { | ||
this.bMarks.push(start); | ||
this.eMarks.push(pos); | ||
this.tShift.push(indent); | ||
indent_found = false; | ||
@@ -76,7 +72,2 @@ indent = 0; | ||
} | ||
if (ch !== 0x0A) { | ||
this.bMarks.push(start); | ||
this.eMarks.push(len); | ||
if (!indent_found) { this.tShift.push(indent); } | ||
} | ||
@@ -168,12 +159,3 @@ // Push fake entry to simplify cache bounds checks | ||
// Create shadow clone of curent state with new input data | ||
StateBlock.prototype.clone = function clone(src) { | ||
return new StateBlock( | ||
src, | ||
this.parser, | ||
this.tokens, | ||
this.options | ||
); | ||
}; | ||
module.exports = StateBlock; |
// Process autolinks '<protocol:...>' | ||
'use strict'; | ||
@@ -4,0 +5,0 @@ var url_schemas = require('../common/url_schemas'); |
// Parse backticks | ||
'use strict'; | ||
module.exports = function backticks(state, silent) { | ||
@@ -4,0 +6,0 @@ var start, max, marker, matchStart, matchEnd, |
// Proceess escaped chars and hardbreaks | ||
'use strict'; | ||
var ESCAPED = []; | ||
@@ -4,0 +6,0 @@ |
// Proceess '\n' | ||
'use strict'; | ||
module.exports = function newline(state, silent) { | ||
@@ -4,0 +6,0 @@ var pmax, max, pos = state.pos; |
// Skip text characters for text token, place those to pendibg buffer | ||
// and increment current pos | ||
'use strict'; | ||
module.exports = function text(state, silent) { | ||
var match = state.src.slice(state.pos).match(state.parser.textMatch); | ||
var str = state.src.slice(state.pos), | ||
next = str.search(state.parser.textMatch); | ||
if (!match) { return false; } | ||
if (next === 0) { return false; } | ||
if (!silent) { state.pending += match[0]; } | ||
state.pos += match[0].length; | ||
if (next < 0) { next = str.length; } | ||
if (!silent) { state.pending += str.slice(0, next); } | ||
state.pos += next; | ||
return true; | ||
}; |
@@ -11,2 +11,4 @@ // Replace link-like texts with link nodes. | ||
var LINK_SCAN_RE = /www|\:\/\//; | ||
var links = []; | ||
@@ -45,6 +47,5 @@ var autolinker = new Autolinker({ | ||
i--; | ||
while (tokens[i].type !== 'link_open' && tokens[i].level !== token.level) { | ||
while (tokens[i].level !== token.level && tokens[i].type !== 'link_open') { | ||
i--; | ||
} | ||
i--; | ||
continue; | ||
@@ -64,7 +65,6 @@ } | ||
if (token.type === 'text' && | ||
(token.content.indexOf('://') || | ||
token.content.indexOf('www'))) { | ||
if (token.type === 'text' && LINK_SCAN_RE.test(token.content)) { | ||
text = token.content; | ||
links = []; | ||
links.length = 0; | ||
autolinker.link(text); | ||
@@ -71,0 +71,0 @@ |
@@ -6,2 +6,5 @@ // Simple typographyc replacements | ||
var COPY_RE = /\((c|tm|r|p)\)/i; | ||
var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/; | ||
module.exports = function replace(t, state) { | ||
@@ -17,3 +20,3 @@ var i, token, text, | ||
if (text.indexOf('(') >= 0) { | ||
if (COPY_RE.test(text)) { | ||
if (options.copyright) { | ||
@@ -33,24 +36,23 @@ text = text.replace(/\(c\)/gi, '©'); | ||
if (options.plusminus && text.indexOf('+-') >= 0) { | ||
text = text.replace(/\+-/g, '±'); | ||
if (RARE_RE.test(text)) { | ||
if (options.plusminus) { | ||
text = text.replace(/\+-/g, '±'); | ||
} | ||
if (options.ellipsis) { | ||
// .., ..., ....... -> … | ||
// but ?..... & !..... -> ?.. & !.. | ||
text = text.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..'); | ||
} | ||
if (options.dupes) { | ||
text = text.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ','); | ||
} | ||
if (options.dashes) { | ||
text = text | ||
// em-dash | ||
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2') | ||
// en-dash | ||
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2') | ||
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2'); | ||
} | ||
} | ||
if (options.ellipsis && text.indexOf('..') >= 0) { | ||
// .., ..., ....... -> … | ||
// but ?..... & !..... -> ?.. & !.. | ||
text = text.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..'); | ||
} | ||
if (options.dupes && | ||
(text.indexOf('????') >= 0 || | ||
text.indexOf('!!!!') >= 0 || | ||
text.indexOf(',,') >= 0)) { | ||
text = text.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ','); | ||
} | ||
if (options.dashes && text.indexOf('--') >= 0) { | ||
text = text | ||
// em-dash | ||
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2') | ||
// en-dash | ||
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2') | ||
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2'); | ||
} | ||
@@ -57,0 +59,0 @@ token.content = text; |
@@ -6,5 +6,6 @@ // Convert straight quotation marks to typographic ones | ||
var quoteReg = /['"]/g; | ||
var punctReg = /[-\s()\[\]]/; | ||
var apostrophe = '’'; | ||
var QUOTE_TEST_RE = /['"]/; | ||
var QUOTE_RE = /['"]/g; | ||
var PUNCT_RE = /[-\s()\[\]]/; | ||
var APOSTROPHE = '’'; | ||
@@ -15,22 +16,25 @@ // This function returns true if the character at `pos` | ||
if (pos < 0 || pos >= str.length) { return false; } | ||
return !punctReg.test(str[pos]); | ||
return !PUNCT_RE.test(str[pos]); | ||
} | ||
function addQuote(obj, tokenId, posId, str) { | ||
if (!obj[tokenId]) { obj[tokenId] = {}; } | ||
obj[tokenId][posId] = str; | ||
function replaceAt(str, index, ch) { | ||
return str.substr(0, index) + ch + str.substr(index + 1); | ||
} | ||
var stack = []; | ||
module.exports = function smartquotes(typographer, state) { | ||
/*eslint max-depth:0*/ | ||
var i, token, text, t, pos, max, thisLevel, lastSpace, nextSpace, item, canOpen, canClose, j, isSingle, fn, chars, | ||
var i, token, text, t, pos, max, thisLevel, lastSpace, nextSpace, item, canOpen, canClose, j, isSingle, chars, | ||
options = typographer.options, | ||
replace = {}, | ||
tokens = state.tokens, | ||
stack = []; | ||
tokens = state.tokens; | ||
stack.length = 0; | ||
for (i = 0; i < tokens.length; i++) { | ||
token = tokens[i]; | ||
if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; } | ||
thisLevel = tokens[i].level; | ||
@@ -43,72 +47,59 @@ | ||
if (token.type === 'text') { | ||
text = token.content; | ||
pos = 0; | ||
max = text.length; | ||
text = token.content; | ||
pos = 0; | ||
max = text.length; | ||
while (pos < max) { | ||
quoteReg.lastIndex = pos; | ||
t = quoteReg.exec(text); | ||
if (!t) { break; } | ||
/*eslint no-labels:0,block-scoped-var:0*/ | ||
OUTER: | ||
while (pos < max) { | ||
QUOTE_RE.lastIndex = pos; | ||
t = QUOTE_RE.exec(text); | ||
if (!t) { break; } | ||
lastSpace = !isLetter(text, t.index - 1); | ||
pos = t.index + t[0].length; | ||
isSingle = t[0] === "'"; | ||
nextSpace = !isLetter(text, pos); | ||
lastSpace = !isLetter(text, t.index - 1); | ||
pos = t.index + 1; | ||
isSingle = (t[0] === "'"); | ||
nextSpace = !isLetter(text, pos); | ||
if (!nextSpace && !lastSpace) { | ||
// middle word | ||
if (isSingle) { | ||
addQuote(replace, i, t.index, apostrophe); | ||
} | ||
continue; | ||
if (!nextSpace && !lastSpace) { | ||
// middle of word | ||
if (isSingle) { | ||
token.content = replaceAt(token.content, t.index, APOSTROPHE); | ||
} | ||
continue; | ||
} | ||
canOpen = !nextSpace; | ||
canClose = !lastSpace; | ||
canOpen = !nextSpace; | ||
canClose = !lastSpace; | ||
if (canClose) { | ||
// this could be a closing quote, rewind the stack to get a match | ||
for (j = stack.length - 1; j >= 0; j--) { | ||
if (canClose) { | ||
// this could be a closing quote, rewind the stack to get a match | ||
for (j = stack.length - 1; j >= 0; j--) { | ||
item = stack[j]; | ||
if (stack[j].level < thisLevel) { break; } | ||
if (item.single === isSingle && stack[j].level === thisLevel) { | ||
item = stack[j]; | ||
if (stack[j].level < thisLevel) { break; } | ||
if (item.single === isSingle && stack[j].level === thisLevel) { | ||
item = stack[j]; | ||
chars = isSingle ? options.singleQuotes : options.doubleQuotes; | ||
if (chars) { | ||
addQuote(replace, item.token, item.start, chars[0]); | ||
addQuote(replace, i, t.index, chars[1]); | ||
} | ||
stack.length = j; | ||
canOpen = false; // should be "continue OUTER;", but eslint refuses labels :( | ||
break; | ||
chars = isSingle ? options.singleQuotes : options.doubleQuotes; | ||
if (chars) { | ||
tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, chars[0]); | ||
token.content = replaceAt(token.content, t.index, chars[1]); | ||
} | ||
stack.length = j; | ||
continue OUTER; | ||
} | ||
} | ||
} | ||
if (canOpen) { | ||
stack.push({ | ||
token: i, | ||
start: t.index, | ||
end: pos, | ||
single: isSingle, | ||
level: thisLevel | ||
}); | ||
} else if (canClose && isSingle) { | ||
addQuote(replace, i, t.index, apostrophe); | ||
} | ||
if (canOpen) { | ||
stack.push({ | ||
token: i, | ||
pos: t.index, | ||
single: isSingle, | ||
level: thisLevel | ||
}); | ||
} else if (canClose && isSingle) { | ||
token.content = replaceAt(token.content, t.index, APOSTROPHE); | ||
} | ||
} | ||
} | ||
fn = function(str, pos) { | ||
if (!replace[i][pos]) { return str; } | ||
return replace[i][pos]; | ||
}; | ||
for (i = 0; i < tokens.length; i++) { | ||
if (!replace[i]) { continue; } | ||
quoteReg.lastIndex = 0; | ||
tokens[i].content = tokens[i].content.replace(quoteReg, fn); | ||
} | ||
}; |
@@ -14,3 +14,3 @@ // Class of typographic replacement rules | ||
var rules = [ | ||
var _rules = [ | ||
require('./rules_text/replace'), | ||
@@ -28,4 +28,4 @@ require('./rules_text/smartquotes') | ||
for (var i = 0; i < rules.length; i++) { | ||
this.ruler.after(rules[i]); | ||
for (var i = 0; i < _rules.length; i++) { | ||
this.ruler.after(_rules[i]); | ||
} | ||
@@ -32,0 +32,0 @@ } |
{ | ||
"name": "remarkable", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"description": "Markdown parser, done right. Commonmark support, extensions, syntax plugins, high speed - all in one.", | ||
@@ -30,4 +30,5 @@ "keywords": [ | ||
"browserify": "*", | ||
"eslint": "0.8.0", | ||
"eslint": "0.9.1", | ||
"eslint-plugin-nodeca": "^1.0.0", | ||
"istanbul": "*", | ||
"jade": "^1.6.0", | ||
@@ -34,0 +35,0 @@ "stylus": "^0.49.1", |
143
README.md
@@ -1,3 +0,2 @@ | ||
remarkable | ||
========== | ||
# remarkable | ||
@@ -7,10 +6,10 @@ [![Build Status](https://travis-ci.org/jonschlinkert/remarkable.svg?branch=master)](https://travis-ci.org/jonschlinkert/remarkable) | ||
Markdown parser done right. Fast and easy to extend. | ||
> Markdown parser done right. Fast and easy to extend. | ||
__[Live demo](http://jonschlinkert.github.io/remarkable/demo/)__ | ||
- Supports the [CommonMark](http://commonmark.org/) spec + extentions | ||
(URL autolinking, typographer). | ||
- Configurable syntax! You can add new rules and even replace existing ones. | ||
- Implements [CommonMark](http://commonmark.org/) spec + | ||
[syntax extentions](#syntax-extentions) + sugar (URL autolinking, typographer). | ||
- Very high speed. | ||
- High speed! See the [benchmarks](./benchmark). | ||
@@ -20,3 +19,3 @@ | ||
node.js: | ||
**node.js:** | ||
@@ -27,3 +26,3 @@ ```bash | ||
bower: | ||
**bower:** | ||
@@ -34,5 +33,11 @@ ```bash | ||
CDNs for browser: [jsDeliver](http://www.jsdelivr.com/#!remarkable "jsDelivr CDN") | ||
**browser:** | ||
The following CDN's host remarkable: | ||
- [jsDeliver](http://www.jsdelivr.com/#!remarkable "jsDelivr CDN") | ||
If you add remarkable to a CDN, please [let us know](https://github.com/jonschlinkert/remarkable/issues) or do PR to add it to the readme! | ||
## Usage | ||
@@ -42,14 +47,32 @@ | ||
var Remarkable = require('remarkable'); | ||
var md = new Remarkable(); | ||
// This values are default | ||
var md = new Remarkable(/* "default" */, { | ||
html: false, // Enable html tags in source | ||
console.log(md.parse('# Remarkable rulezz!')); | ||
// => <h1>Remarkable rulezz!</h1> | ||
``` | ||
### Options | ||
By default remarkable is configured to be similar to GFM, but with HTML disabled. This is easy to change | ||
if you prefer to use different settings. | ||
There are two ways to define options. | ||
#### constructor | ||
Define options in the constructor: | ||
```js | ||
// Actual default values | ||
var md = new Remarkable({ | ||
html: false, // Enable HTML tags in source | ||
xhtmlOut: false, // Use '/' to close single tags (<br />) | ||
breaks: false, // Convert '\n' in paragraphs into <br> | ||
langPrefix: 'language-', // CSS language prefix for fenced blocks | ||
linkify: false, // Autoconvert url-like texts to links | ||
linkify: false, // Autoconvert URL-like text to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Highlighter function. Should return escaped html, | ||
// or '' if input not changed | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if the source string is not changed | ||
highlight: function (/*str, , lang*/) { return ''; } | ||
@@ -62,7 +85,9 @@ }); | ||
You can define options via `set` method: | ||
#### .set | ||
Or define options via the `.set()` method: | ||
```js | ||
var Remarkable = require('remarkable'); | ||
var md = new Remarkable('full'); | ||
var md = new Remarkable(); | ||
@@ -75,9 +100,16 @@ md.set({ | ||
__Note.__ To acheive best performance, don't modify the `Remarkable` instance on | ||
the fly. If you need several configurations - create multiple instances and | ||
initialise each appropriately. | ||
**Note:** To achieve the best possible performance, don't modify a `Remarkable` instance on | ||
the fly. If you need multiple configurations it's best to create multiple instances and initialize | ||
each with a configuration that is ideal for that instance. | ||
Remarkable provides presets to quickly manage active syntax rules and options. | ||
You can reset parser to strict [CommonMark](http://commonmark.org/) mode: | ||
### Presets | ||
Remarkable offers some "presets" as a convenience to quickly enable/disable active syntax rules and options | ||
for common use cases. | ||
#### commonmark | ||
Enable strict [CommonMark](http://commonmark.org/) mode with the `commonmark` preset: | ||
```js | ||
@@ -88,4 +120,6 @@ var Remarkable = require('remarkable'); | ||
Or you can enable everything: | ||
#### full | ||
Enable everything with the `full` preset: | ||
```js | ||
@@ -96,9 +130,7 @@ var Remarkable = require('remarkable'); | ||
By default remarkable is configured to be similar to GFM, but with disabled HTML. | ||
### Syntax highlighting | ||
### Highlight fenced blocks | ||
Apply syntax highlighting to fenced code blocks with the `highlight` option: | ||
To highlight content of fenced block, assign function to `highlight` option: | ||
```js | ||
@@ -108,3 +140,3 @@ var Remarkable = require('remarkable'); | ||
// These values are default | ||
// Actual default values | ||
var md = new Remarkable({ | ||
@@ -115,3 +147,3 @@ highlight: function (str, lang) { | ||
return hljs.highlight(lang, str).value; | ||
} catch (__) {} | ||
} catch (err) {} | ||
} | ||
@@ -121,3 +153,3 @@ | ||
return hljs.highlightAuto(str).value; | ||
} catch (__) {} | ||
} catch (err) {} | ||
@@ -139,7 +171,11 @@ return ''; // use external default escaping | ||
- __\<ins>__ - `++inserted text++` | ||
- __\<mark>__ - `==marked text==` | ||
- __\<ins>__ - `++inserted text++` (experimental) | ||
- __\<mark>__ - `==marked text==` (experimental) | ||
Manage rules: | ||
__*__ Experimental extentions can be changed later for something like [Critic Markup](http://criticmarkup.com/), but you will | ||
still be able to use old-style rules via external plugins if you prefer. | ||
### Manage rules | ||
```js | ||
@@ -158,6 +194,7 @@ var md = new Remarkable(); | ||
### Typographer | ||
Though full-weight typograpic replacements are language specific, `remarkable` | ||
provides the most common and universal case coverage: | ||
Although full-weight typographical replacements are language specific, `remarkable` | ||
provides coverage for the most common and universal use cases: | ||
@@ -168,6 +205,6 @@ ```js | ||
// These values are default | ||
// Actual default values | ||
md.typographer.set({ | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for russian, '„“' for deutch, empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
@@ -184,6 +221,19 @@ trademark: true, // (tm) (TM) → ™ | ||
Of course, you can add your own rules or replace default ones with something | ||
more advanced, specific for your language. | ||
Of course, you can also add your own rules or replace the defaults with something | ||
more advanced or specific to your language. | ||
### Plugins | ||
Easily load plugins with the `.use()` method: | ||
```js | ||
var md = new Remarkable(); | ||
md.use(plugin1) | ||
.use(plugin2, opts) | ||
.use(plugin3); | ||
``` | ||
## References / Thanks | ||
@@ -195,3 +245,3 @@ | ||
Links: | ||
**Related Links:** | ||
@@ -201,3 +251,3 @@ 1. https://github.com/jgm/CommonMark - reference CommonMark implementations in C & JS, | ||
2. http://talk.commonmark.org - CommonMark forum, good place to collaborate | ||
developpers efforts. | ||
developers' efforts. | ||
@@ -209,3 +259,3 @@ | ||
reconfigure anyone as you wish. Render also can be modified and extended. See | ||
source code to understand details. Pay attention to this properties: | ||
source code to understand details. Pay attention to these properties: | ||
@@ -225,12 +275,3 @@ ```js | ||
To prettify plugins init, `Remarked` has `.use()` helper for curried calls: | ||
```js | ||
var md = new Remarkable(); | ||
md.use(plugin1) | ||
.use(plugin2, opts) | ||
.use(plugin3); | ||
``` | ||
## Authors | ||
@@ -237,0 +278,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
267
463041
11
12841