remarkable
Advanced tools
Comparing version 1.3.0 to 1.4.0
@@ -0,1 +1,14 @@ | ||
1.4.0 / WIP | ||
------------------ | ||
- Added `core` chain, to better organize code and improve pluggability. | ||
- Added `renderInline()` and `parseInline()` methods. | ||
- Added abbreviations support. | ||
- Fixed problem with tables, having single column. | ||
- Fixed rendered rules rewrite for inline tags. | ||
- Changed internal api (ruler, inline, block classes). | ||
- Removed typographer chain (rules moved to `core`). | ||
- Removed all typographer options. Quote chars defs moved to `options.quotes`. | ||
1.3.0 / 2014-10-29 | ||
@@ -2,0 +15,0 @@ ------------------ |
@@ -14,17 +14,15 @@ // Utilities | ||
var sources = Array.prototype.slice.call(arguments, 1); | ||
while (sources.length) { | ||
var source = sources.shift(); | ||
if (!source) { continue; } | ||
if (typeof(source) !== 'object') { | ||
throw new TypeError(source + 'must be non-object'); | ||
} | ||
sources.forEach(function (source) { | ||
if (!source) { return; } | ||
for (var p in source) { | ||
if (source.hasOwnProperty(p)) { | ||
obj[p] = source[p]; | ||
} | ||
if (typeof source !== 'object') { | ||
throw new TypeError(source + 'must be object'); | ||
} | ||
} | ||
Object.keys(source).forEach(function (key) { | ||
obj[key] = source[key]; | ||
}); | ||
}); | ||
return obj; | ||
@@ -70,14 +68,27 @@ } | ||
var NAMED_ENTITY_RE = /&([a-z][a-z0-9]{1,31});/gi; | ||
var NAMED_ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi; | ||
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i; | ||
var entities = require('./entities'); | ||
function replaceEntityPattern(match, name) { | ||
var code = 0; | ||
if (entities.hasOwnProperty(name)) { | ||
return entities[name]; | ||
} else if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) { | ||
code = name[1].toLowerCase() === 'x' ? | ||
parseInt(name.slice(2), 16) | ||
: | ||
parseInt(name.slice(1), 10); | ||
if (isValidEntityCode(code)) { | ||
return fromCodePoint(code); | ||
} | ||
} | ||
return match; | ||
} | ||
function replaceEntities(str) { | ||
if (str.indexOf('&') < 0) { return str; } | ||
return str.replace(NAMED_ENTITY_RE, function(match, name) { | ||
if (entities.hasOwnProperty(name)) { | ||
return entities[name]; | ||
} | ||
return match; | ||
}); | ||
return str.replace(NAMED_ENTITY_RE, replaceEntityPattern); | ||
} | ||
@@ -84,0 +95,0 @@ |
@@ -13,7 +13,16 @@ // Commonmark default options | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Enable some language-neutral replacements + quotes beautification | ||
typographer: false, | ||
// Double + single quotes replacement pairs, when typographer enabled, | ||
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. | ||
quotes: '“”‘’', | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
highlight: function (/*str, lang*/) { return ''; }, | ||
// | ||
// function (/*str, lang*/) { return ''; } | ||
// | ||
highlight: null, | ||
@@ -25,2 +34,11 @@ maxNesting: 20 // Internal protection, recursion limit | ||
core: { | ||
rules: [ | ||
'block', | ||
'inline', | ||
'references', | ||
'abbr2' | ||
] | ||
}, | ||
block: { | ||
@@ -52,19 +70,4 @@ rules: [ | ||
] | ||
}, | ||
typographer: { | ||
options: { | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
trademark: true, // (tm) (TM) → ™ | ||
registered: true, // (r) (R) → ® | ||
plusminus: true, // +- → ± | ||
paragraph: true, // (p) (P) → § | ||
ellipsis: true, // ... → … | ||
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,` | ||
dashes: true // -- → — | ||
} | ||
} | ||
} | ||
}; |
@@ -13,7 +13,16 @@ // Remarkable default options | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Enable some language-neutral replacements + quotes beautification | ||
typographer: false, | ||
// Double + single quotes replacement pairs, when typographer enabled, | ||
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. | ||
quotes: '“”‘’', | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
highlight: function (/*str, lang*/) { return ''; }, | ||
// | ||
// function (/*str, lang*/) { return ''; } | ||
// | ||
highlight: null, | ||
@@ -25,2 +34,15 @@ maxNesting: 20 // Internal protection, recursion limit | ||
core: { | ||
rules: [ | ||
'block', | ||
'inline', | ||
'references', | ||
'replacements', | ||
'linkify', | ||
'smartquotes', | ||
'references', | ||
'abbr2' | ||
] | ||
}, | ||
block: { | ||
@@ -54,19 +76,4 @@ rules: [ | ||
] | ||
}, | ||
typographer: { | ||
options: { | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
trademark: true, // (tm) (TM) → ™ | ||
registered: true, // (r) (R) → ® | ||
plusminus: true, // +- → ± | ||
paragraph: true, // (p) (P) → § | ||
ellipsis: true, // ... → … | ||
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,` | ||
dashes: true // -- → — | ||
} | ||
} | ||
} | ||
}; |
@@ -13,7 +13,16 @@ // Remarkable default options | ||
linkify: false, // autoconvert URL-like texts to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Enable some language-neutral replacements + quotes beautification | ||
typographer: false, | ||
// Double + single quotes replacement pairs, when typographer enabled, | ||
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. | ||
quotes: '“”‘’', | ||
// Highlighter function. Should return escaped HTML, | ||
// or '' if input not changed | ||
highlight: function (/*str, lang*/) { return ''; }, | ||
// | ||
// function (/*str, lang*/) { return ''; } | ||
// | ||
highlight: null, | ||
@@ -25,21 +34,7 @@ maxNesting: 20 // Internal protection, recursion limit | ||
// Don't restrict block/inline rules | ||
// Don't restrict core/block/inline rules | ||
core: {}, | ||
block: {}, | ||
inline: {}, | ||
typographer: { | ||
options: { | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
trademark: true, // (tm) (TM) → ™ | ||
registered: true, // (r) (R) → ® | ||
plusminus: true, // +- → ± | ||
paragraph: true, // (p) (P) → § | ||
ellipsis: true, // ... → … | ||
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,` | ||
dashes: true // -- → — | ||
} | ||
} | ||
inline: {} | ||
} | ||
}; |
@@ -9,8 +9,7 @@ // Main perser class | ||
var Renderer = require('./renderer'); | ||
var ParserCore = require('./parser_core'); | ||
var ParserBlock = require('./parser_block'); | ||
var ParserInline = require('./parser_inline'); | ||
var Typographer = require('./typographer'); | ||
var Linkifier = require('./linkifier'); | ||
var Ruler = require('./ruler'); | ||
var config = { | ||
@@ -23,2 +22,15 @@ 'default': require('./configs/default'), | ||
function StateCore(self, src, env) { | ||
this.src = src; | ||
this.env = env; | ||
this.options = self.options; | ||
this.tokens = []; | ||
this.inlineMode = false; | ||
this.inline = self.inline; | ||
this.block = self.block; | ||
this.renderer = self.renderer; | ||
this.typographer = self.typographer; | ||
} | ||
// Main class | ||
@@ -34,16 +46,9 @@ // | ||
this.options = {}; | ||
this.state = null; | ||
this.inline = new ParserInline(); | ||
this.block = new ParserBlock(); | ||
this.core = new ParserCore(); | ||
this.renderer = new Renderer(); | ||
this.typographer = new Typographer(); | ||
this.linkifier = new Linkifier(); | ||
this.ruler = new Ruler(); | ||
// Cross-references to simplify code (a bit dirty, but easy). | ||
this.block.inline = this.inline; | ||
this.inline.typographer = this.typographer; | ||
this.inline.linkifier = this.linkifier; | ||
this.options = {}; | ||
this.configure(config[presetName]); | ||
@@ -67,3 +72,3 @@ | ||
if (!presets) { throw new Error('Wrong config name'); } | ||
if (!presets) { throw new Error('Wrong `remarkable` preset, check name/content'); } | ||
@@ -77,5 +82,2 @@ if (presets.options) { self.set(presets.options); } | ||
} | ||
if (presets.components[name].options) { | ||
self[name].set(presets.components[name].options); | ||
} | ||
}); | ||
@@ -104,15 +106,7 @@ } | ||
Remarkable.prototype.parse = function (src, env) { | ||
var tokens, tok, i, l; | ||
// Parse blocks | ||
tokens = this.block.parse(src, this.options, env); | ||
var state = new StateCore(this, src, env); | ||
// Parse inlines | ||
for (i = 0, l = tokens.length; i < l; i++) { | ||
tok = tokens[i]; | ||
if (tok.type === 'inline') { | ||
tok.children = this.inline.parse(tok.content, this.options, env); | ||
} | ||
} | ||
this.core.process(state); | ||
return tokens; | ||
return state.tokens; | ||
}; | ||
@@ -122,4 +116,4 @@ | ||
// | ||
Remarkable.prototype.render = function (src) { | ||
var env = { references: {} }; | ||
Remarkable.prototype.render = function (src, env) { | ||
env = env || {}; | ||
@@ -130,2 +124,22 @@ return this.renderer.render(this.parse(src, env), this.options, env); | ||
// Parse content as single string | ||
// | ||
Remarkable.prototype.parseInline = function (src, env) { | ||
var state = new StateCore(this, src, env); | ||
state.inlineMode = true; | ||
this.core.process(state); | ||
return state.tokens; | ||
}; | ||
// Render single string, without wrapping it to paragraphs | ||
// | ||
Remarkable.prototype.renderInline = function (src, env) { | ||
env = env || {}; | ||
return this.renderer.render(this.parseInline(src, env), this.options, env); | ||
}; | ||
module.exports = Remarkable; |
@@ -8,3 +8,3 @@ // Block parser | ||
var Ruler = require('./ruler'); | ||
var State = require('./rules_block/state_block'); | ||
var StateBlock = require('./rules_block/state_block'); | ||
@@ -29,9 +29,4 @@ | ||
function ParserBlock() { | ||
this._rules = []; | ||
this._rulesParagraphTerm = []; | ||
this._rulesBlockquoteTerm = []; | ||
this._rulesListTerm = []; | ||
this.ruler = new Ruler(); | ||
this.ruler = new Ruler(this.rulesUpdate.bind(this)); | ||
for (var i = 0; i < _rules.length; i++) { | ||
@@ -43,10 +38,2 @@ this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() }); | ||
ParserBlock.prototype.rulesUpdate = function () { | ||
this._rules = this.ruler.getRules(); | ||
this._rulesParagraphTerm = this.ruler.getRules('paragraph'); | ||
this._rulesBlockquoteTerm = this.ruler.getRules('blockquote'); | ||
this._rulesListTerm = this.ruler.getRules('list'); | ||
}; | ||
// Generate tokens for input range | ||
@@ -56,4 +43,4 @@ // | ||
var ok, i, | ||
rules = this._rules, | ||
len = this._rules.length, | ||
rules = this.ruler.getRules(''), | ||
len = rules.length, | ||
line = startLine, | ||
@@ -82,8 +69,2 @@ hasEmptyLines = false; | ||
if (!ok) { throw new Error('No matching rules found'); } | ||
if (line === state.line) { | ||
throw new Error('None of rules updated state.line'); | ||
} | ||
// set state.tight iff we had an empty line before current tag | ||
@@ -115,3 +96,3 @@ // i.e. latest empty line should not count | ||
ParserBlock.prototype.parse = function (src, options, env) { | ||
ParserBlock.prototype.parse = function (src, options, env, outTokens) { | ||
var state, lineStart = 0, lastTabPos = 0; | ||
@@ -142,13 +123,11 @@ | ||
state = new State( | ||
state = new StateBlock( | ||
src, | ||
this, | ||
[], | ||
options, | ||
env | ||
env, | ||
outTokens | ||
); | ||
this.tokenize(state, state.line, state.lineMax); | ||
return state.tokens; | ||
}; | ||
@@ -155,0 +134,0 @@ |
@@ -33,10 +33,4 @@ // Inline parser | ||
function validateLink(url) { | ||
var str = ''; | ||
var str = decodeURI(url).trim().toLowerCase(); | ||
try { | ||
str = decodeURI(url).trim().toLowerCase(); | ||
} catch (_) {} | ||
if (!str) { return false; } | ||
if (str.indexOf(':') >= 0 && BAD_PROTOCOLS.indexOf(str.split(':')[0]) >= 0) { | ||
@@ -51,8 +45,2 @@ return false; | ||
function ParserInline() { | ||
this._rules = []; | ||
// Rule to skip pure text | ||
// - '{}$%@+=:' reserved for extentions | ||
this.textMatch = /[\n\\`*_^\[\]!&<{}$%@~+=:]/; | ||
// By default CommonMark allows too much in links | ||
@@ -62,3 +50,3 @@ // If you need to restrict it - override this with your validator. | ||
this.ruler = new Ruler(this.rulesUpdate.bind(this)); | ||
this.ruler = new Ruler(); | ||
@@ -71,7 +59,2 @@ for (var i = 0; i < _rules.length; i++) { | ||
ParserInline.prototype.rulesUpdate = function () { | ||
this._rules = this.ruler.getRules(); | ||
}; | ||
// Skip single token by running all rules in validation mode; | ||
@@ -82,3 +65,4 @@ // returns `true` if any rule reported success | ||
var i, cached_pos, pos = state.pos, | ||
len = this._rules.length; | ||
rules = this.ruler.getRules(''), | ||
len = rules.length; | ||
@@ -91,3 +75,3 @@ if ((cached_pos = state.cacheGet(pos)) > 0) { | ||
for (i = 0; i < len; i++) { | ||
if (this._rules[i](state, true)) { | ||
if (rules[i](state, true)) { | ||
state.cacheSet(pos, state.pos); | ||
@@ -107,3 +91,4 @@ return; | ||
var ok, i, | ||
len = this._rules.length, | ||
rules = this.ruler.getRules(''), | ||
len = rules.length, | ||
end = state.posMax; | ||
@@ -121,3 +106,3 @@ | ||
for (i = 0; i < len; i++) { | ||
ok = this._rules[i](state, false); | ||
ok = rules[i](state, false); | ||
if (ok) { break; } | ||
@@ -137,4 +122,2 @@ } | ||
} | ||
return state.tokens; | ||
}; | ||
@@ -145,15 +128,6 @@ | ||
// | ||
ParserInline.prototype.parse = function (str, options, env) { | ||
var state = new StateInline(str, this, options, env); | ||
ParserInline.prototype.parse = function (str, options, env, outTokens) { | ||
var state = new StateInline(str, this, options, env, outTokens); | ||
this.tokenize(state); | ||
if (options.linkify) { | ||
this.linkifier.process(state); | ||
} | ||
if (options.typographer) { | ||
this.typographer.process(state); | ||
} | ||
return state.tokens; | ||
}; | ||
@@ -160,0 +134,0 @@ |
@@ -12,15 +12,2 @@ 'use strict'; | ||
function escapeUrl(str) { | ||
try { | ||
return encodeURI(str); | ||
} catch (__) {} | ||
return ''; | ||
} | ||
function unescapeUrl(str) { | ||
try { | ||
return decodeURI(str); | ||
} catch (__) {} | ||
return ''; | ||
} | ||
var HTML_ESCAPE_TEST_RE = /[&<>"]/; | ||
@@ -46,6 +33,17 @@ var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; | ||
function nextToken(tokens, idx) { | ||
if (++idx >= tokens.length - 2) { return idx; } | ||
if ((tokens[idx].type === 'paragraph_open' && tokens[idx].tight) && | ||
(tokens[idx + 1].type === 'inline' && tokens[idx + 1].content.length === 0) && | ||
(tokens[idx + 2].type === 'paragraph_close' && tokens[idx + 2].tight)) { | ||
return nextToken(tokens, idx + 2); | ||
} | ||
return idx; | ||
} | ||
// check if we need to hide '\n' before next token | ||
function getBreak(tokens, idx) { | ||
if (++idx < tokens.length && | ||
idx = nextToken(tokens, idx); | ||
if (idx < tokens.length && | ||
tokens[idx].type === 'list_item_close') { | ||
@@ -63,6 +61,7 @@ return ''; | ||
rules.blockquote_open = function (/*tokens, idx, options*/) { | ||
rules.blockquote_open = function (/* tokens, idx, options, env */) { | ||
return '<blockquote>\n'; | ||
}; | ||
rules.blockquote_close = function (tokens, idx /*, options*/) { | ||
rules.blockquote_close = function (tokens, idx /*, options, env */) { | ||
return '</blockquote>' + getBreak(tokens, idx); | ||
@@ -72,3 +71,3 @@ }; | ||
rules.code = function (tokens, idx /*, options*/) { | ||
rules.code = function (tokens, idx /*, options, env */) { | ||
if (tokens[idx].block) { | ||
@@ -82,6 +81,6 @@ return '<pre><code>' + escapeHtml(tokens[idx].content) + '</code></pre>' + getBreak(tokens, idx); | ||
rules.fence = function (tokens, idx, options) { | ||
rules.fence = function (tokens, idx, options /*, env */) { | ||
var token = tokens[idx]; | ||
var langClass = ''; | ||
var langPrefix = options.langPrefix || ''; | ||
var langPrefix = options.langPrefix; | ||
var params, langName = ''; | ||
@@ -96,4 +95,9 @@ var highlighted; | ||
highlighted = options.highlight(token.content, langName) || escapeHtml(token.content); | ||
if (options.highlight) { | ||
highlighted = options.highlight(token.content, langName) || escapeHtml(token.content); | ||
} else { | ||
highlighted = escapeHtml(token.content); | ||
} | ||
return '<pre><code' + langClass + '>' | ||
@@ -105,6 +109,6 @@ + highlighted | ||
rules.heading_open = function (tokens, idx /*, options*/) { | ||
rules.heading_open = function (tokens, idx /*, options, env */) { | ||
return '<h' + tokens[idx].hLevel + '>'; | ||
}; | ||
rules.heading_close = function (tokens, idx /*, options*/) { | ||
rules.heading_close = function (tokens, idx /*, options, env */) { | ||
return '</h' + tokens[idx].hLevel + '>\n'; | ||
@@ -114,3 +118,3 @@ }; | ||
rules.hr = function (tokens, idx, options) { | ||
rules.hr = function (tokens, idx, options /*, env */) { | ||
return (options.xhtmlOut ? '<hr />' : '<hr>') + getBreak(tokens, idx); | ||
@@ -120,15 +124,15 @@ }; | ||
rules.bullet_list_open = function (/*tokens, idx, options*/) { | ||
rules.bullet_list_open = function (/* tokens, idx, options, env */) { | ||
return '<ul>\n'; | ||
}; | ||
rules.bullet_list_close = function (tokens, idx /*, options*/) { | ||
rules.bullet_list_close = function (tokens, idx /*, options, env */) { | ||
return '</ul>' + getBreak(tokens, idx); | ||
}; | ||
rules.list_item_open = function (/*tokens, idx, options*/) { | ||
rules.list_item_open = function (/* tokens, idx, options, env */) { | ||
return '<li>'; | ||
}; | ||
rules.list_item_close = function (/*tokens, idx, options*/) { | ||
rules.list_item_close = function (/* tokens, idx, options, env */) { | ||
return '</li>\n'; | ||
}; | ||
rules.ordered_list_open = function (tokens, idx /*, options*/) { | ||
rules.ordered_list_open = function (tokens, idx /*, options, env */) { | ||
var token = tokens[idx]; | ||
@@ -139,3 +143,3 @@ return '<ol' | ||
}; | ||
rules.ordered_list_close = function (tokens, idx /*, options*/) { | ||
rules.ordered_list_close = function (tokens, idx /*, options, env */) { | ||
return '</ol>' + getBreak(tokens, idx); | ||
@@ -145,15 +149,16 @@ }; | ||
rules.paragraph_open = function (tokens, idx/*, options*/) { | ||
rules.paragraph_open = function (tokens, idx /*, options, env */) { | ||
return tokens[idx].tight ? '' : '<p>'; | ||
}; | ||
rules.paragraph_close = function (tokens, idx /*, options*/) { | ||
return (tokens[idx].tight ? '' : '</p>') + getBreak(tokens, idx); | ||
rules.paragraph_close = function (tokens, idx /*, options, env */) { | ||
var addBreak = !(tokens[idx].tight && idx && tokens[idx - 1].type === 'inline' && !tokens[idx - 1].content); | ||
return (tokens[idx].tight ? '' : '</p>') + (addBreak ? getBreak(tokens, idx) : ''); | ||
}; | ||
rules.link_open = function (tokens, idx /*, options*/) { | ||
rules.link_open = function (tokens, idx /*, options, env */) { | ||
var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; | ||
return '<a href="' + escapeHtml(escapeUrl(unescapeUrl(replaceEntities(tokens[idx].href)))) + '"' + title + '>'; | ||
return '<a href="' + escapeHtml(encodeURI(decodeURI(replaceEntities(tokens[idx].href)))) + '"' + title + '>'; | ||
}; | ||
rules.link_close = function (/*tokens, idx, options*/) { | ||
rules.link_close = function (/* tokens, idx, options, env */) { | ||
return '</a>'; | ||
@@ -163,4 +168,4 @@ }; | ||
rules.image = function (tokens, idx, options) { | ||
var src = ' src="' + escapeHtml(escapeUrl(tokens[idx].src)) + '"'; | ||
rules.image = function (tokens, idx, options /*, env */) { | ||
var src = ' src="' + escapeHtml(encodeURI(tokens[idx].src)) + '"'; | ||
var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; | ||
@@ -173,27 +178,27 @@ var alt = ' alt="' + (tokens[idx].alt ? escapeHtml(replaceEntities(tokens[idx].alt)) : '') + '"'; | ||
rules.table_open = function (/*tokens, idx, options*/) { | ||
rules.table_open = function (/* tokens, idx, options, env */) { | ||
return '<table>\n'; | ||
}; | ||
rules.table_close = function (/*tokens, idx, options*/) { | ||
rules.table_close = function (/* tokens, idx, options, env */) { | ||
return '</table>\n'; | ||
}; | ||
rules.thead_open = function (/*tokens, idx, options*/) { | ||
rules.thead_open = function (/* tokens, idx, options, env */) { | ||
return '<thead>\n'; | ||
}; | ||
rules.thead_close = function (/*tokens, idx, options*/) { | ||
rules.thead_close = function (/* tokens, idx, options, env */) { | ||
return '</thead>\n'; | ||
}; | ||
rules.tbody_open = function (/*tokens, idx, options*/) { | ||
rules.tbody_open = function (/* tokens, idx, options, env */) { | ||
return '<tbody>\n'; | ||
}; | ||
rules.tbody_close = function (/*tokens, idx, options*/) { | ||
rules.tbody_close = function (/* tokens, idx, options, env */) { | ||
return '</tbody>\n'; | ||
}; | ||
rules.tr_open = function (/*tokens, idx, options*/) { | ||
rules.tr_open = function (/* tokens, idx, options, env */) { | ||
return '<tr>'; | ||
}; | ||
rules.tr_close = function (/*tokens, idx, options*/) { | ||
rules.tr_close = function (/* tokens, idx, options, env */) { | ||
return '</tr>\n'; | ||
}; | ||
rules.th_open = function (tokens, idx /*, options*/) { | ||
rules.th_open = function (tokens, idx /*, options, env */) { | ||
var token = tokens[idx]; | ||
@@ -204,6 +209,6 @@ return '<th' | ||
}; | ||
rules.th_close = function (/*tokens, idx, options*/) { | ||
rules.th_close = function (/* tokens, idx, options, env */) { | ||
return '</th>'; | ||
}; | ||
rules.td_open = function (tokens, idx /*, options*/) { | ||
rules.td_open = function (tokens, idx /*, options, env */) { | ||
var token = tokens[idx]; | ||
@@ -214,3 +219,3 @@ return '<td' | ||
}; | ||
rules.td_close = function (/*tokens, idx, options*/) { | ||
rules.td_close = function (/* tokens, idx, options, env */) { | ||
return '</td>'; | ||
@@ -220,12 +225,12 @@ }; | ||
rules.strong_open = function(/*tokens, idx, options*/) { | ||
rules.strong_open = function (/* tokens, idx, options, env */) { | ||
return '<strong>'; | ||
}; | ||
rules.strong_close = function(/*tokens, idx, options*/) { | ||
rules.strong_close = function (/* tokens, idx, options, env */) { | ||
return '</strong>'; | ||
}; | ||
rules.em_open = function(/*tokens, idx, options*/) { | ||
rules.em_open = function (/* tokens, idx, options, env */) { | ||
return '<em>'; | ||
}; | ||
rules.em_close = function(/*tokens, idx, options*/) { | ||
rules.em_close = function (/* tokens, idx, options, env */) { | ||
return '</em>'; | ||
@@ -235,6 +240,6 @@ }; | ||
rules.del_open = function(/*tokens, idx, options*/) { | ||
rules.del_open = function (/* tokens, idx, options, env */) { | ||
return '<del>'; | ||
}; | ||
rules.del_close = function(/*tokens, idx, options*/) { | ||
rules.del_close = function (/* tokens, idx, options, env */) { | ||
return '</del>'; | ||
@@ -244,6 +249,6 @@ }; | ||
rules.ins_open = function(/*tokens, idx, options*/) { | ||
rules.ins_open = function (/* tokens, idx, options, env */) { | ||
return '<ins>'; | ||
}; | ||
rules.ins_close = function(/*tokens, idx, options*/) { | ||
rules.ins_close = function (/* tokens, idx, options, env */) { | ||
return '</ins>'; | ||
@@ -253,6 +258,6 @@ }; | ||
rules.mark_open = function(/*tokens, idx, options*/) { | ||
rules.mark_open = function (/* tokens, idx, options, env */) { | ||
return '<mark>'; | ||
}; | ||
rules.mark_close = function(/*tokens, idx, options*/) { | ||
rules.mark_close = function (/* tokens, idx, options, env */) { | ||
return '</mark>'; | ||
@@ -262,6 +267,6 @@ }; | ||
rules.sub = function(tokens, idx/*, options*/) { | ||
rules.sub = function (tokens, idx /*, options, env */) { | ||
return '<sub>' + escapeHtml(tokens[idx].content) + '</sub>'; | ||
}; | ||
rules.sup = function(tokens, idx/*, options*/) { | ||
rules.sup = function (tokens, idx /*, options, env */) { | ||
return '<sup>' + escapeHtml(tokens[idx].content) + '</sup>'; | ||
@@ -271,6 +276,6 @@ }; | ||
rules.hardbreak = function (tokens, idx, options) { | ||
rules.hardbreak = function (tokens, idx, options /*, env */) { | ||
return options.xhtmlOut ? '<br />\n' : '<br>\n'; | ||
}; | ||
rules.softbreak = function (tokens, idx, options) { | ||
rules.softbreak = function (tokens, idx, options /*, env */) { | ||
return options.breaks ? (options.xhtmlOut ? '<br />\n' : '<br>\n') : '\n'; | ||
@@ -280,3 +285,3 @@ }; | ||
rules.text = function (tokens, idx /*, options*/) { | ||
rules.text = function (tokens, idx /*, options, env */) { | ||
return escapeHtml(tokens[idx].content); | ||
@@ -286,6 +291,6 @@ }; | ||
rules.htmlblock = function (tokens, idx /*, options*/) { | ||
rules.htmlblock = function (tokens, idx /*, options, env */) { | ||
return tokens[idx].content; | ||
}; | ||
rules.htmltag = function (tokens, idx /*, options*/) { | ||
rules.htmltag = function (tokens, idx /*, options, env */) { | ||
return tokens[idx].content; | ||
@@ -295,2 +300,10 @@ }; | ||
rules.abbr_open = function (tokens, idx /*, options, env */) { | ||
return '<abbr title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '">'; | ||
}; | ||
rules.abbr_close = function (/* tokens, idx, options, env */) { | ||
return '</abbr>'; | ||
}; | ||
// Renderer class | ||
@@ -303,7 +316,8 @@ function Renderer() { | ||
Renderer.prototype.renderInline = function (tokens, options) { | ||
var result = ''; | ||
Renderer.prototype.renderInline = function (tokens, options, env) { | ||
var result = '', | ||
_rules = this.rules; | ||
for (var i = 0, len = tokens.length; i < len; i++) { | ||
result += rules[tokens[i].type](tokens, i, options); | ||
result += _rules[tokens[i].type](tokens, i, options, env); | ||
} | ||
@@ -315,3 +329,3 @@ | ||
Renderer.prototype.render = function (tokens, options) { | ||
Renderer.prototype.render = function (tokens, options, env) { | ||
var i, len, | ||
@@ -323,5 +337,5 @@ result = '', | ||
if (tokens[i].type === 'inline') { | ||
result += this.renderInline(tokens[i].children, options); | ||
result += this.renderInline(tokens[i].children, options, env); | ||
} else { | ||
result += _rules[tokens[i].type](tokens, i, options); | ||
result += _rules[tokens[i].type](tokens, i, options, env); | ||
} | ||
@@ -328,0 +342,0 @@ } |
@@ -12,5 +12,3 @@ // Ruler is helper class to build responsibility chains from parse rules. | ||
function Ruler(compileFn) { | ||
this.compile = compileFn; // callback to call after each change | ||
function Ruler() { | ||
// List of added rules. Each element is: | ||
@@ -26,2 +24,9 @@ // | ||
this.rules = []; | ||
// Cached rule chains. | ||
// | ||
// First level - chain name, '' for default. | ||
// Second level - diginal anchor for fast filtering by charcodes. | ||
// | ||
this.cache = null; | ||
} | ||
@@ -52,3 +57,3 @@ | ||
this.rules[index].alt = opt.alt || []; | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
@@ -72,3 +77,3 @@ | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
@@ -92,3 +97,3 @@ | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
@@ -108,29 +113,6 @@ | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
// Get rules list as array of functions. By default returns main chain | ||
// | ||
Ruler.prototype.getRules = function (chainName) { | ||
var result = []; | ||
if (!chainName) { | ||
this.rules.forEach(function (rule) { | ||
if (rule.enabled) { | ||
result.push(rule.fn); | ||
} | ||
}); | ||
return result; | ||
} | ||
this.rules.forEach(function (rule) { | ||
if (rule.alt.indexOf(chainName) >= 0 && rule.enabled) { | ||
result.push(rule.fn); | ||
} | ||
}); | ||
return result; | ||
}; | ||
// Enable list of rules by names. If `strict` is true, then all non listed | ||
@@ -160,3 +142,3 @@ // rules will be disabled. | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
@@ -181,6 +163,48 @@ | ||
this.compile(); | ||
this.cache = null; | ||
}; | ||
// Build rules lookup cache | ||
// | ||
Ruler.prototype.compile = function () { | ||
var self = this; | ||
var chains = [ '' ]; | ||
// collect unique names | ||
self.rules.forEach(function (rule) { | ||
if (!rule.enabled) { return; } | ||
rule.alt.forEach(function (altName) { | ||
if (chains.indexOf(altName) < 0) { | ||
chains.push(altName); | ||
} | ||
}); | ||
}); | ||
self.cache = {}; | ||
chains.forEach(function (chain) { | ||
self.cache[chain] = []; | ||
self.rules.forEach(function (rule) { | ||
if (!rule.enabled) { return; } | ||
if (chain && rule.alt.indexOf(chain) < 0) { return; } | ||
self.cache[chain].push(rule.fn); | ||
}); | ||
}); | ||
}; | ||
// Get rules list as array of functions. | ||
// | ||
Ruler.prototype.getRules = function (chainName) { | ||
if (this.cache === null) { | ||
this.compile(); | ||
} | ||
return this.cache[chainName]; | ||
}; | ||
module.exports = Ruler; |
@@ -8,3 +8,4 @@ // Block quotes | ||
var nextLine, lastLineEmpty, oldTShift, oldBMarks, oldIndent, oldParentType, lines, | ||
terminatorRules = state.parser._rulesBlockquoteTerm, i, l, terminate, | ||
terminatorRules, | ||
i, l, terminate, | ||
pos = state.bMarks[startLine] + state.tShift[startLine], | ||
@@ -40,2 +41,4 @@ max = state.eMarks[startLine]; | ||
terminatorRules = state.parser.ruler.getRules('blockquote'); | ||
// Search the end of the block | ||
@@ -42,0 +45,0 @@ // |
@@ -6,3 +6,3 @@ // Code block (4 spaces padded) | ||
module.exports = function code(state, startLine, endLine, silent) { | ||
module.exports = function code(state, startLine, endLine/*, silent*/) { | ||
var nextLine, last; | ||
@@ -27,4 +27,2 @@ | ||
if (silent) { return true; } | ||
state.line = nextLine; | ||
@@ -31,0 +29,0 @@ state.tokens.push({ |
@@ -6,3 +6,3 @@ // lheading (---, ===) | ||
module.exports = function lheading(state, startLine, endLine, silent) { | ||
module.exports = function lheading(state, startLine, endLine/*, silent*/) { | ||
var marker, pos, max, | ||
@@ -33,4 +33,2 @@ next = startLine + 1; | ||
if (silent) { return true; } | ||
pos = state.bMarks[startLine] + state.tShift[startLine]; | ||
@@ -37,0 +35,0 @@ |
@@ -105,3 +105,3 @@ // Lists | ||
tight = true, | ||
terminatorRules = state.parser._rulesListTerm, | ||
terminatorRules, | ||
i, l, terminate; | ||
@@ -154,2 +154,3 @@ | ||
prevEmptyEnd = false; | ||
terminatorRules = state.parser.ruler.getRules('list'); | ||
@@ -156,0 +157,0 @@ while (nextLine < endLine) { |
@@ -6,9 +6,6 @@ // Paragraph | ||
var parseRef = require('../parser_ref'); | ||
module.exports = function paragraph(state, startLine/*, endLine*/) { | ||
var endLine, content, pos, terminate, i, l, | ||
var endLine, content, terminate, i, l, | ||
nextLine = startLine + 1, | ||
terminatorRules = state.parser._rulesParagraphTerm; | ||
terminatorRules; | ||
@@ -18,16 +15,20 @@ endLine = state.lineMax; | ||
// jump line-by-line until empty one or EOF | ||
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { | ||
// this would be a code block normally, but after paragraph | ||
// it's considered a lazy continuation regardless of what's there | ||
if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } | ||
if (nextLine < endLine && !state.isEmpty(nextLine)) { | ||
terminatorRules = state.parser.ruler.getRules('paragraph'); | ||
// Some tags can terminate paragraph without empty line. | ||
terminate = false; | ||
for (i = 0, l = terminatorRules.length; i < l; i++) { | ||
if (terminatorRules[i](state, nextLine, endLine, true)) { | ||
terminate = true; | ||
break; | ||
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { | ||
// this would be a code block normally, but after paragraph | ||
// it's considered a lazy continuation regardless of what's there | ||
if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } | ||
// Some tags can terminate paragraph without empty line. | ||
terminate = false; | ||
for (i = 0, l = terminatorRules.length; i < l; i++) { | ||
if (terminatorRules[i](state, nextLine, endLine, true)) { | ||
terminate = true; | ||
break; | ||
} | ||
} | ||
if (terminate) { break; } | ||
} | ||
if (terminate) { break; } | ||
} | ||
@@ -37,8 +38,2 @@ | ||
while (content.length) { | ||
pos = parseRef(content, state.parser.inline, state.options, state.env); | ||
if (pos < 0) { break; } | ||
content = content.slice(pos).trim(); | ||
} | ||
state.line = nextLine; | ||
@@ -45,0 +40,0 @@ if (content.length) { |
@@ -6,3 +6,3 @@ // Parser state class | ||
function StateBlock(src, parser, tokens, options, env) { | ||
function StateBlock(src, parser, options, env, tokens) { | ||
var ch, s, start, pos, len, indent, indent_found; | ||
@@ -9,0 +9,0 @@ |
@@ -6,7 +6,7 @@ // GFM table, non-standard | ||
function lineMatch(state, line, reg) { | ||
function getLine(state, line) { | ||
var pos = state.bMarks[line] + state.blkIndent, | ||
max = state.eMarks[line]; | ||
return state.src.substr(pos, max - pos).match(reg); | ||
return state.src.substr(pos, max - pos); | ||
} | ||
@@ -16,3 +16,3 @@ | ||
module.exports = function table(state, startLine, endLine, silent) { | ||
var ch, firstLineMatch, secondLineMatch, pos, i, nextLine, m, rows, | ||
var ch, lineText, pos, i, nextLine, rows, | ||
aligns, t, tableLines, tbodyLines; | ||
@@ -35,23 +35,33 @@ | ||
secondLineMatch = lineMatch(state, startLine + 1, | ||
/^ *\|?(( *[:-]-+[:-] *\|)+( *[:-]-+[:-] *))\|? *$/); | ||
if (!secondLineMatch) { return false; } | ||
lineText = getLine(state, startLine + 1); | ||
if (!/^[-:| ]+$/.test(lineText)) { return false; } | ||
rows = secondLineMatch[1].split('|'); | ||
rows = lineText.split('|'); | ||
if (rows <= 2) { return false; } | ||
aligns = []; | ||
for (i = 0; i < rows.length; i++) { | ||
t = rows[i].trim(); | ||
if (!t) { | ||
// allow empty columns before and after table, but not in between columns; | ||
// e.g. allow ` |---| `, disallow ` ---||--- ` | ||
if (i === 0 || i === rows.length - 1) { | ||
continue; | ||
} else { | ||
return false; | ||
} | ||
} | ||
if (!/^:?-+:?$/.test(t)) { return false; } | ||
if (t.charCodeAt(t.length - 1) === 0x3A/* : */) { | ||
aligns[i] = t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right'; | ||
aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right'); | ||
} else if (t.charCodeAt(0) === 0x3A/* : */) { | ||
aligns[i] = 'left'; | ||
aligns.push('left'); | ||
} else { | ||
aligns[i] = ''; | ||
aligns.push(''); | ||
} | ||
} | ||
firstLineMatch = lineMatch(state, startLine, /^ *\|?(.*?\|.*?)\|? *$/); | ||
if (!firstLineMatch) { return false; } | ||
rows = firstLineMatch[1].split('|'); | ||
lineText = getLine(state, startLine).trim(); | ||
if (lineText.indexOf('|') === -1) { return false; } | ||
rows = lineText.replace(/^\||\|$/g, '').split('|'); | ||
if (aligns.length !== rows.length) { return false; } | ||
@@ -104,5 +114,5 @@ if (silent) { return true; } | ||
m = lineMatch(state, nextLine, /^ *\|?(.*?\|.*?)\|? *$/); | ||
if (!m) { break; } | ||
rows = m[1].split('|'); | ||
lineText = getLine(state, nextLine).trim(); | ||
if (lineText.indexOf('|') === -1) { break; } | ||
rows = lineText.replace(/^\||\|$/g, '').split('|'); | ||
@@ -109,0 +119,0 @@ state.tokens.push({ type: 'tr_open', level: state.level++ }); |
@@ -5,6 +5,6 @@ // Process [links](<to> "stuff") | ||
var parseLinkLabel = require('../links').parseLinkLabel; | ||
var parseLinkDestination = require('../links').parseLinkDestination; | ||
var parseLinkTitle = require('../links').parseLinkTitle; | ||
var normalizeReference = require('../links').normalizeReference; | ||
var parseLinkLabel = require('../helpers/parse_link_label'); | ||
var parseLinkDestination = require('../helpers/parse_link_destination'); | ||
var parseLinkTitle = require('../helpers/parse_link_title'); | ||
var normalizeReference = require('../helpers/normalize_reference'); | ||
@@ -11,0 +11,0 @@ |
@@ -6,8 +6,8 @@ // Inline parser state | ||
function StateInline(src, parser, options, env) { | ||
function StateInline(src, parserInline, options, env, outTokens) { | ||
this.src = src; | ||
this.env = env; | ||
this.options = options; | ||
this.parser = parser; | ||
this.tokens = []; | ||
this.parser = parserInline; | ||
this.tokens = outTokens; | ||
this.pos = 0; | ||
@@ -14,0 +14,0 @@ this.posMax = this.src.length; |
@@ -6,14 +6,49 @@ // Skip text characters for text token, place those to pending buffer | ||
// Rule to skip pure text | ||
// '{}$%@~+=:' reserved for extentions | ||
function isTerminatorChar(ch) { | ||
switch (ch) { | ||
case 0x0A/* \n */: | ||
case 0x5C/* \ */: | ||
case 0x60/* ` */: | ||
case 0x2A/* * */: | ||
case 0x5F/* _ */: | ||
case 0x5E/* ^ */: | ||
case 0x5B/* [ */: | ||
case 0x5D/* ] */: | ||
case 0x21/* ! */: | ||
case 0x26/* & */: | ||
case 0x3C/* < */: | ||
case 0x3E/* > */: | ||
case 0x7B/* { */: | ||
case 0x7D/* } */: | ||
case 0x24/* $ */: | ||
case 0x25/* % */: | ||
case 0x40/* @ */: | ||
case 0x7E/* ~ */: | ||
case 0x2B/* + */: | ||
case 0x3D/* = */: | ||
case 0x3A/* : */: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
module.exports = function text(state, silent) { | ||
var str = state.src.slice(state.pos), | ||
next = str.search(state.parser.textMatch); | ||
var pos = state.pos; | ||
if (next === 0) { return false; } | ||
while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) { | ||
pos++; | ||
} | ||
if (next < 0) { next = str.length; } | ||
if (pos === state.pos) { return false; } | ||
if (!silent) { state.pending += str.slice(0, next); } | ||
state.pos += next; | ||
if (!silent) { state.pending += state.src.slice(state.pos, pos); } | ||
state.pos = pos; | ||
return true; | ||
}; |
{ | ||
"name": "remarkable", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "Markdown parser, done right. Commonmark support, extensions, syntax plugins, high speed - all in one.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -11,6 +11,6 @@ # remarkable | ||
- Supports the [CommonMark](http://commonmark.org/) spec + extentions | ||
(URL autolinking, typographer). | ||
- Supports the [CommonMark](http://commonmark.org/) spec + | ||
[syntax extensions](#syntax-extensions) + sugar (URL autolinking, typographer). | ||
- Configurable syntax! You can add new rules and even replace existing ones. | ||
- High speed! See the [benchmarks](./benchmark). | ||
- [High speed](#benchmark)! | ||
@@ -67,4 +67,10 @@ | ||
linkify: false, // Autoconvert URL-like text to links | ||
typographer: false, // Enable smartypants and other sweet transforms | ||
// Enable some language-neutral replacement + quotes beautification | ||
typographer: false, | ||
// Double + single quotes replacement pairs, when typographer enabled, | ||
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. | ||
quotes: '“”‘’', | ||
// Highlighter function. Should return escaped HTML, | ||
@@ -157,3 +163,3 @@ // or '' if the source string is not changed | ||
### Syntax extentions | ||
### Syntax extensions | ||
@@ -168,8 +174,9 @@ Enabled by default: | ||
- [\<sup](http://johnmacfarlane.net/pandoc/README.html#superscripts-and-subscripts) - `19^th^` | ||
- [\<sup>](http://johnmacfarlane.net/pandoc/README.html#superscripts-and-subscripts) - `19^th^` | ||
- [\<sub>](http://johnmacfarlane.net/pandoc/README.html#superscripts-and-subscripts) - `H~2~0` | ||
- [abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr) | ||
- __\<ins>__ - `++inserted text++` (experimental) | ||
- __\<mark>__ - `==marked text==` (experimental) | ||
__*__ Experimental extentions can be changed later for something like | ||
__*__ Experimental extensions can be changed later for something like | ||
[Critic Markup](http://criticmarkup.com/), but you will still be able to use | ||
@@ -202,17 +209,23 @@ old-style rules via external plugins if you prefer. | ||
var Remarkable = require('remarkable'); | ||
var md = new Remarkable({ typographer: true }); | ||
var md = new Remarkable({ | ||
typographer: true, | ||
quotes: '“”‘’' | ||
}); | ||
// Actual default values | ||
md.typographer.set({ | ||
singleQuotes: '‘’', // set empty to disable | ||
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable | ||
copyright: true, // (c) (C) → © | ||
trademark: true, // (tm) (TM) → ™ | ||
registered: true, // (r) (R) → ® | ||
plusminus: true, // +- → ± | ||
paragraph: true, // (p) (P) -> § | ||
ellipsis: true, // ... → … (also ?.... → ?.., !.... → !..) | ||
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,` | ||
dashes: true // -- → –, --- → — | ||
}) | ||
// Disable rules at all: | ||
md.core.ruler.disable([ 'replacements', 'smartquotes' ]); | ||
// Actual default replacements: | ||
// | ||
// '' → ‘’ | ||
// "" → “”. Set '«»' for Russian, '„“' for German, empty to disable | ||
// (c) (C) → © | ||
// (tm) (TM) → ™ | ||
// (r) (R) → ® | ||
// +- → ± | ||
// (p) (P) -> § | ||
// ... → … (also ?.... → ?.., !.... → !..) | ||
// ???????? → ???, !!!!! → !!!, `,,` → `,` | ||
// -- → –, --- → — | ||
// | ||
``` | ||
@@ -258,2 +271,4 @@ | ||
```js | ||
Remarkable.core | ||
Remarkable.core.ruler | ||
Remarkable.block | ||
@@ -263,6 +278,2 @@ Remarkable.block.ruler | ||
Remarkable.inline.ruler | ||
Remarkable.typographer | ||
Remarkable.typographer.ruler | ||
Remarkable.linkifier | ||
Remarkable.linkifier.ruler | ||
Remarkable.renderer | ||
@@ -272,3 +283,22 @@ Remarkable.renderer.rules | ||
## Benchmark | ||
Here is result of CommonMark spec parse at Core i5 2.4 GHz (i5-4258U): | ||
```bash | ||
$ benchmark/benchmark.js spec | ||
Selected samples: (1 of 27) | ||
> spec | ||
Sample: spec.txt (110610 bytes) | ||
> commonmark-reference x 40.42 ops/sec ±4.07% (51 runs sampled) | ||
> current x 74.99 ops/sec ±4.69% (67 runs sampled) | ||
> current-commonmark x 93.76 ops/sec ±1.23% (79 runs sampled) | ||
> marked-0.3.2 x 22.92 ops/sec ±0.79% (41 runs sampled) | ||
``` | ||
As you can see, `remarkabe` doesn't pay with speed for it's flexibility. Because | ||
it's written in monomorphyc style and use JIT inline caches effectively. | ||
## Authors | ||
@@ -275,0 +305,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
491710
62
13471
306