Browse Source

Various performance improvements

pull/748/head
Fabio Spampinato 4 years ago
parent
commit
c888839574
  1. 37
      benchmark/benchloop.js
  2. 4
      benchmark/profile.js
  3. 11
      lib/common/utils.js
  4. 48
      lib/renderer.js
  5. 6
      lib/rules_block/blockquote.js
  6. 4
      lib/rules_block/code.js
  7. 6
      lib/rules_block/fence.js
  8. 6
      lib/rules_block/heading.js
  9. 9
      lib/rules_block/hr.js
  10. 8
      lib/rules_block/html_block.js
  11. 6
      lib/rules_block/lheading.js
  12. 40
      lib/rules_block/list.js
  13. 6
      lib/rules_block/reference.js
  14. 14
      lib/rules_block/state_block.js
  15. 10
      lib/rules_block/table.js
  16. 4
      lib/rules_core/linkify.js
  17. 17
      lib/rules_core/normalize.js
  18. 2
      lib/rules_core/smartquotes.js
  19. 4
      lib/rules_inline/autolink.js
  20. 7
      lib/rules_inline/backticks.js
  21. 8
      lib/rules_inline/emphasis.js
  22. 4
      lib/rules_inline/entity.js
  23. 4
      lib/rules_inline/escape.js
  24. 12
      lib/rules_inline/html_inline.js
  25. 6
      lib/rules_inline/image.js
  26. 4
      lib/rules_inline/link.js
  27. 16
      lib/rules_inline/newline.js
  28. 8
      lib/rules_inline/strikethrough.js
  29. 17
      lib/rules_inline/text_collapse.js
  30. 1
      package.json

37
benchmark/benchloop.js

@ -0,0 +1,37 @@
'use strict';
/* IMPORT */
var fs = require ('fs'),
path = require ('path'),
benchmark = require ('benchloop'),
mit = require ('..');
/* HELPERS */
var SAMPLES_PATH = path.join (__dirname, 'samples');
var md = mit ('commonmark');
/* BENCHMARK */
benchmark.defaultOptions = Object.assign (benchmark.defaultOptions, {
iterations: 50,
log: 'compact'
});
fs.readdirSync (SAMPLES_PATH).forEach (function (sample) {
var samplePath = path.join (SAMPLES_PATH, sample),
content = fs.readFileSync (samplePath, 'utf-8');
benchmark ({
name: sample,
fn: function () {
md.render (content);
}
});
});
benchmark.summary ();

4
benchmark/profile.js

@ -14,6 +14,8 @@ var md = require('../')({
// var data = fs.readFileSync(path.join(__dirname, '/samples/lorem1.txt'), 'utf8'); // var data = fs.readFileSync(path.join(__dirname, '/samples/lorem1.txt'), 'utf8');
var data = fs.readFileSync(path.join(__dirname, '../test/fixtures/commonmark/spec.txt'), 'utf8'); var data = fs.readFileSync(path.join(__dirname, '../test/fixtures/commonmark/spec.txt'), 'utf8');
for (var i = 0; i < 20; i++) { console.time('profile');
for (var i = 0; i < 200; i++) {
md.render(data); md.render(data);
} }
console.timeEnd('profile');

11
lib/common/utils.js

@ -13,6 +13,14 @@ function has(object, key) {
return _hasOwnProperty.call(object, key); return _hasOwnProperty.call(object, key);
} }
var _repeat = String.prototype.repeat || function (count) {
return new Array(count + 1).join (this);
};
function repeat(str, count) {
return _repeat.call (str, count);
}
// Merge objects // Merge objects
// //
function assign(obj /*from1, from2, from3, ...*/) { function assign(obj /*from1, from2, from3, ...*/) {
@ -237,7 +245,7 @@ function isMdAsciiPunct(ch) {
} }
} }
// Hepler to unify [reference labels]. // Helper to unify [reference labels].
// //
function normalizeReference(str) { function normalizeReference(str) {
// Trim and collapse whitespace // Trim and collapse whitespace
@ -302,6 +310,7 @@ exports.lib.ucmicro = require('uc.micro');
exports.assign = assign; exports.assign = assign;
exports.isString = isString; exports.isString = isString;
exports.has = has; exports.has = has;
exports.repeat = repeat;
exports.unescapeMd = unescapeMd; exports.unescapeMd = unescapeMd;
exports.unescapeAll = unescapeAll; exports.unescapeAll = unescapeAll;
exports.isValidEntityCode = isValidEntityCode; exports.isValidEntityCode = isValidEntityCode;

48
lib/renderer.js

@ -44,9 +44,14 @@ default_rules.fence = function (tokens, idx, options, env, slf) {
highlighted, i, arr, tmpAttrs, tmpToken; highlighted, i, arr, tmpAttrs, tmpToken;
if (info) { if (info) {
arr = info.split(/(\s+)/g); if (!/\s/.test (info)) {
langName = arr[0]; langName = info;
langAttrs = arr.slice(2).join(''); langAttrs = '';
} else {
arr = info.split(/(\s+)/g);
langName = arr[0];
langAttrs = arr.slice(2).join('');
}
} }
if (options.highlight) { if (options.highlight) {
@ -55,7 +60,7 @@ default_rules.fence = function (tokens, idx, options, env, slf) {
highlighted = escapeHtml(token.content); highlighted = escapeHtml(token.content);
} }
if (highlighted.indexOf('<pre') === 0) { if (highlighted.slice(0, 4) === '<pre') {
return highlighted + '\n'; return highlighted + '\n';
} }
@ -63,12 +68,12 @@ default_rules.fence = function (tokens, idx, options, env, slf) {
// May be, one day we will add .deepClone() for token and simplify this part, but // May be, one day we will add .deepClone() for token and simplify this part, but
// now we prefer to keep things local. // now we prefer to keep things local.
if (info) { if (info) {
i = token.attrIndex('class'); i = token.attrIndex('class');
tmpAttrs = token.attrs ? token.attrs.slice() : [];
if (i < 0) { if (i < 0) {
tmpAttrs.push([ 'class', options.langPrefix + langName ]); tmpAttrs = [ [ 'class', options.langPrefix + langName ] ];
} else { } else {
tmpAttrs = token.attrs.slice();
tmpAttrs[i] = tmpAttrs[i].slice(); tmpAttrs[i] = tmpAttrs[i].slice();
tmpAttrs[i][1] += ' ' + options.langPrefix + langName; tmpAttrs[i][1] += ' ' + options.langPrefix + langName;
} }
@ -78,6 +83,12 @@ default_rules.fence = function (tokens, idx, options, env, slf) {
attrs: tmpAttrs attrs: tmpAttrs
}; };
if (i < 0) {
return '<pre><code' + slf.renderAttrs(token) + slf.renderAttrs(tmpToken) + '>'
+ highlighted
+ '</code></pre>\n';
}
return '<pre><code' + slf.renderAttrs(tmpToken) + '>' return '<pre><code' + slf.renderAttrs(tmpToken) + '>'
+ highlighted + highlighted
+ '</code></pre>\n'; + '</code></pre>\n';
@ -293,13 +304,17 @@ Renderer.prototype.renderInline = function (tokens, options, env) {
* instead of simple escaping. * instead of simple escaping.
**/ **/
Renderer.prototype.renderInlineAsText = function (tokens, options, env) { Renderer.prototype.renderInlineAsText = function (tokens, options, env) {
var result = ''; var type, token,
result = '';
for (var i = 0, len = tokens.length; i < len; i++) { for (var i = 0, len = tokens.length; i < len; i++) {
if (tokens[i].type === 'text') { token = tokens[i];
result += tokens[i].content; type = token.type;
} else if (tokens[i].type === 'image') {
result += this.renderInlineAsText(tokens[i].children, options, env); if (type === 'text') {
result += token.content;
} else if (type === 'image') {
result += this.renderInlineAsText(token.children, options, env);
} }
} }
@ -317,17 +332,18 @@ Renderer.prototype.renderInlineAsText = function (tokens, options, env) {
* this method directly. * this method directly.
**/ **/
Renderer.prototype.render = function (tokens, options, env) { Renderer.prototype.render = function (tokens, options, env) {
var i, len, type, var i, len, type, token,
result = '', result = '',
rules = this.rules; rules = this.rules;
for (i = 0, len = tokens.length; i < len; i++) { for (i = 0, len = tokens.length; i < len; i++) {
type = tokens[i].type; token = tokens[i];
type = token.type;
if (type === 'inline') { if (type === 'inline') {
result += this.renderInline(tokens[i].children, options, env); result += this.renderInline(token.children, options, env);
} else if (typeof rules[type] !== 'undefined') { } else if (typeof rules[type] !== 'undefined') {
result += rules[tokens[i].type](tokens, i, options, env, this); result += rules[type](tokens, i, options, env, this);
} else { } else {
result += this.renderToken(tokens, i, options, env); result += this.renderToken(tokens, i, options, env);
} }

6
lib/rules_block/blockquote.js

@ -6,6 +6,9 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function blockquote(state, startLine, endLine, silent) { module.exports = function blockquote(state, startLine, endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var adjustTab, var adjustTab,
ch, ch,
i, i,
@ -30,9 +33,6 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
pos = state.bMarks[startLine] + state.tShift[startLine], pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine]; max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
// check the block quote marker // check the block quote marker
if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; } if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; }

4
lib/rules_block/code.js

@ -4,10 +4,10 @@
module.exports = function code(state, startLine, endLine/*, silent*/) { module.exports = function code(state, startLine, endLine/*, silent*/) {
var nextLine, last, token;
if (state.sCount[startLine] - state.blkIndent < 4) { return false; } if (state.sCount[startLine] - state.blkIndent < 4) { return false; }
var nextLine, last, token;
last = nextLine = startLine + 1; last = nextLine = startLine + 1;
while (nextLine < endLine) { while (nextLine < endLine) {

6
lib/rules_block/fence.js

@ -4,14 +4,14 @@
module.exports = function fence(state, startLine, endLine, silent) { module.exports = function fence(state, startLine, endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var marker, len, params, nextLine, mem, token, markup, var marker, len, params, nextLine, mem, token, markup,
haveEndMarker = false, haveEndMarker = false,
pos = state.bMarks[startLine] + state.tShift[startLine], pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine]; max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
if (pos + 3 > max) { return false; } if (pos + 3 > max) { return false; }
marker = state.src.charCodeAt(pos); marker = state.src.charCodeAt(pos);

6
lib/rules_block/heading.js

@ -6,13 +6,13 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function heading(state, startLine, endLine, silent) { module.exports = function heading(state, startLine, endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var ch, level, tmp, token, var ch, level, tmp, token,
pos = state.bMarks[startLine] + state.tShift[startLine], pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine]; max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
ch = state.src.charCodeAt(pos); ch = state.src.charCodeAt(pos);
if (ch !== 0x23/* # */ || pos >= max) { return false; } if (ch !== 0x23/* # */ || pos >= max) { return false; }

9
lib/rules_block/hr.js

@ -3,16 +3,17 @@
'use strict'; 'use strict';
var isSpace = require('../common/utils').isSpace; var isSpace = require('../common/utils').isSpace;
var repeat = require('../common/utils').repeat;
module.exports = function hr(state, startLine, endLine, silent) { module.exports = function hr(state, startLine, endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var marker, cnt, ch, token, var marker, cnt, ch, token,
pos = state.bMarks[startLine] + state.tShift[startLine], pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine]; max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
marker = state.src.charCodeAt(pos++); marker = state.src.charCodeAt(pos++);
// Check hr marker // Check hr marker
@ -39,7 +40,7 @@ module.exports = function hr(state, startLine, endLine, silent) {
token = state.push('hr', 'hr', 0); token = state.push('hr', 'hr', 0);
token.map = [ startLine, state.line ]; token.map = [ startLine, state.line ];
token.markup = Array(cnt + 1).join(String.fromCharCode(marker)); token.markup = repeat (String.fromCharCode(marker), cnt);
return true; return true;
}; };

8
lib/rules_block/html_block.js

@ -21,14 +21,14 @@ var HTML_SEQUENCES = [
module.exports = function html_block(state, startLine, endLine, silent) { module.exports = function html_block(state, startLine, endLine, silent) {
var i, nextLine, token, lineText, if (!state.md.options.html) { return false; }
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block // if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; } if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
if (!state.md.options.html) { return false; } var i, nextLine, token, lineText,
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];
if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }

6
lib/rules_block/lheading.js

@ -4,13 +4,13 @@
module.exports = function lheading(state, startLine, endLine/*, silent*/) { module.exports = function lheading(state, startLine, endLine/*, silent*/) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var content, terminate, i, l, token, pos, max, level, marker, var content, terminate, i, l, token, pos, max, level, marker,
nextLine = startLine + 1, oldParentType, nextLine = startLine + 1, oldParentType,
terminatorRules = state.md.block.ruler.getRules('paragraph'); terminatorRules = state.md.block.ruler.getRules('paragraph');
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
oldParentType = state.parentType; oldParentType = state.parentType;
state.parentType = 'paragraph'; // use paragraph to match terminatorRules state.parentType = 'paragraph'; // use paragraph to match terminatorRules

40
lib/rules_block/list.js

@ -11,7 +11,6 @@ function skipBulletListMarker(state, startLine) {
var marker, pos, max, ch; var marker, pos, max, ch;
pos = state.bMarks[startLine] + state.tShift[startLine]; pos = state.bMarks[startLine] + state.tShift[startLine];
max = state.eMarks[startLine];
marker = state.src.charCodeAt(pos++); marker = state.src.charCodeAt(pos++);
// Check bullet // Check bullet
@ -21,6 +20,8 @@ function skipBulletListMarker(state, startLine) {
return -1; return -1;
} }
max = state.eMarks[startLine];
if (pos < max) { if (pos < max) {
ch = state.src.charCodeAt(pos); ch = state.src.charCodeAt(pos);
@ -84,13 +85,14 @@ function skipOrderedListMarker(state, startLine) {
} }
function markTightParagraphs(state, idx) { function markTightParagraphs(state, idx) {
var i, l, var i, l, token,
level = state.level + 2; level = state.level + 2;
for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) { for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { token = state.tokens[i];
if (token.level === level && token.type === 'paragraph_open') {
state.tokens[i + 2].hidden = true; state.tokens[i + 2].hidden = true;
state.tokens[i].hidden = true; token.hidden = true;
i += 2; i += 2;
} }
} }
@ -98,6 +100,21 @@ function markTightParagraphs(state, idx) {
module.exports = function list(state, startLine, endLine, silent) { module.exports = function list(state, startLine, endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
// Special case:
// - item 1
// - item 2
// - item 3
// - item 4
// - this one is a paragraph continuation
if (state.listIndent >= 0 &&
state.sCount[startLine] - state.listIndent >= 4 &&
state.sCount[startLine] < state.blkIndent) {
return false;
}
var ch, var ch,
contentStart, contentStart,
i, i,
@ -129,21 +146,6 @@ module.exports = function list(state, startLine, endLine, silent) {
isTerminatingParagraph = false, isTerminatingParagraph = false,
tight = true; tight = true;
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
// Special case:
// - item 1
// - item 2
// - item 3
// - item 4
// - this one is a paragraph continuation
if (state.listIndent >= 0 &&
state.sCount[startLine] - state.listIndent >= 4 &&
state.sCount[startLine] < state.blkIndent) {
return false;
}
// limit conditions when list can interrupt // limit conditions when list can interrupt
// a paragraph (validation mode only) // a paragraph (validation mode only)
if (silent && state.parentType === 'paragraph') { if (silent && state.parentType === 'paragraph') {

6
lib/rules_block/reference.js

@ -6,6 +6,9 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function reference(state, startLine, _endLine, silent) { module.exports = function reference(state, startLine, _endLine, silent) {
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
var ch, var ch,
destEndPos, destEndPos,
destEndLineNo, destEndLineNo,
@ -27,9 +30,6 @@ module.exports = function reference(state, startLine, _endLine, silent) {
max = state.eMarks[startLine], max = state.eMarks[startLine],
nextLine = startLine + 1; nextLine = startLine + 1;
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; } if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; }
// Simple check to quickly interrupt scan on [link](url) at the start of line. // Simple check to quickly interrupt scan on [link](url) at the start of line.

14
lib/rules_block/state_block.js

@ -4,6 +4,7 @@
var Token = require('../token'); var Token = require('../token');
var isSpace = require('../common/utils').isSpace; var isSpace = require('../common/utils').isSpace;
var repeat = require('../common/utils').repeat;
function StateBlock(src, md, env, tokens) { function StateBlock(src, md, env, tokens) {
@ -173,15 +174,14 @@ StateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code, min) {
// cut lines range from source. // cut lines range from source.
StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) { StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {
var i, lineIndent, ch, first, last, queue, lineStart, var i, lineIndent, ch, first, last, lineStart,
lines = '',
line = begin; line = begin;
if (begin >= end) { if (begin >= end) {
return ''; return lines;
} }
queue = new Array(end - begin);
for (i = 0; line < end; line++, i++) { for (i = 0; line < end; line++, i++) {
lineIndent = 0; lineIndent = 0;
lineStart = first = this.bMarks[line]; lineStart = first = this.bMarks[line];
@ -215,13 +215,13 @@ StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF
if (lineIndent > indent) { if (lineIndent > indent) {
// partially expanding tabs in code blocks, e.g '\t\tfoobar' // partially expanding tabs in code blocks, e.g '\t\tfoobar'
// with indent=2 becomes ' \tfoobar' // with indent=2 becomes ' \tfoobar'
queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last); lines += repeat (' ', lineIndent - indent) + this.src.slice(first, last);
} else { } else {
queue[i] = this.src.slice(first, last); lines += this.src.slice(first, last);
} }
} }
return queue.join(''); return lines;
}; };
// re-export Token class to use in block rules // re-export Token class to use in block rules

10
lib/rules_block/table.js

@ -50,20 +50,20 @@ function escapedSplit(str) {
module.exports = function table(state, startLine, endLine, silent) { module.exports = function table(state, startLine, endLine, silent) {
var ch, lineText, pos, i, l, nextLine, columns, columnCount, token,
aligns, t, tableLines, tbodyLines, oldParentType, terminate,
terminatorRules;
// should have at least two lines // should have at least two lines
if (startLine + 2 > endLine) { return false; } if (startLine + 2 > endLine) { return false; }
nextLine = startLine + 1; var nextLine = startLine + 1;
if (state.sCount[nextLine] < state.blkIndent) { return false; } if (state.sCount[nextLine] < state.blkIndent) { return false; }
// if it's indented more than 3 spaces, it should be a code block // if it's indented more than 3 spaces, it should be a code block
if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; } if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; }
var ch, lineText, pos, i, l, columns, columnCount, token,
aligns, t, tableLines, tbodyLines, oldParentType, terminate,
terminatorRules;
// first character of the second line should be '|', '-', ':', // first character of the second line should be '|', '-', ':',
// and no other characters are allowed but spaces; // and no other characters are allowed but spaces;
// basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp // basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp

4
lib/rules_core/linkify.js

@ -17,13 +17,13 @@ function isLinkClose(str) {
module.exports = function linkify(state) { module.exports = function linkify(state) {
if (!state.md.options.linkify) { return; }
var i, j, l, tokens, token, currentToken, nodes, ln, text, pos, lastPos, var i, j, l, tokens, token, currentToken, nodes, ln, text, pos, lastPos,
level, htmlLinkLevel, url, fullUrl, urlText, level, htmlLinkLevel, url, fullUrl, urlText,
blockTokens = state.tokens, blockTokens = state.tokens,
links; links;
if (!state.md.options.linkify) { return; }
for (j = 0, l = blockTokens.length; j < l; j++) { for (j = 0, l = blockTokens.length; j < l; j++) {
if (blockTokens[j].type !== 'inline' || if (blockTokens[j].type !== 'inline' ||
!state.md.linkify.pretest(blockTokens[j].content)) { !state.md.linkify.pretest(blockTokens[j].content)) {

17
lib/rules_core/normalize.js

@ -4,18 +4,21 @@
// https://spec.commonmark.org/0.29/#line-ending // https://spec.commonmark.org/0.29/#line-ending
var NEWLINES_RE = /\r\n?|\n/g; var CRLF_RE = /\r\n?/g;
var NULL_RE = /\0/g;
module.exports = function normalize(state) { module.exports = function normalize(state) {
var str; var src = state.src;
// Normalize newlines // Normalize CRLF newlines
str = state.src.replace(NEWLINES_RE, '\n'); src = src.replace(CRLF_RE, '\n');
// Replace NULL characters // Replace NULL characters
str = str.replace(NULL_RE, '\uFFFD'); for (var i = 0, l = src.length; i < l; i++) {
if (!src.charCodeAt(i)) {
src = src.slice (0, i) + '\uFFFD' + src.slice (i + 1);
}
}
state.src = str; state.src = src;
}; };

2
lib/rules_core/smartquotes.js

@ -26,7 +26,7 @@ function process_inlines(tokens, state) {
for (i = 0; i < tokens.length; i++) { for (i = 0; i < tokens.length; i++) {
token = tokens[i]; token = tokens[i];
thisLevel = tokens[i].level; thisLevel = token.level;
for (j = stack.length - 1; j >= 0; j--) { for (j = stack.length - 1; j >= 0; j--) {
if (stack[j].level <= thisLevel) { break; } if (stack[j].level <= thisLevel) { break; }

4
lib/rules_inline/autolink.js

@ -9,11 +9,11 @@ var AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/;
module.exports = function autolink(state, silent) { module.exports = function autolink(state, silent) {
if (state.src.charCodeAt(state.pos) !== 0x3C/* < */) { return false; }
var url, fullUrl, token, ch, start, max, var url, fullUrl, token, ch, start, max,
pos = state.pos; pos = state.pos;
if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }
start = state.pos; start = state.pos;
max = state.posMax; max = state.posMax;

7
lib/rules_inline/backticks.js

@ -4,12 +4,13 @@
module.exports = function backtick(state, silent) { module.exports = function backtick(state, silent) {
var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength, var ch = state.src.charCodeAt(state.pos);
pos = state.pos,
ch = state.src.charCodeAt(pos);
if (ch !== 0x60/* ` */) { return false; } if (ch !== 0x60/* ` */) { return false; }
var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength,
pos = state.pos;
start = pos; start = pos;
pos++; pos++;
max = state.posMax; max = state.posMax;

8
lib/rules_inline/emphasis.js

@ -6,14 +6,14 @@
// Insert each marker as a separate text token, and add it to delimiter list // Insert each marker as a separate text token, and add it to delimiter list
// //
module.exports.tokenize = function emphasis(state, silent) { module.exports.tokenize = function emphasis(state, silent) {
var i, scanned, token,
start = state.pos,
marker = state.src.charCodeAt(start);
if (silent) { return false; } if (silent) { return false; }
var marker = state.src.charCodeAt(state.pos);
if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; } if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; }
var i, scanned, token;
scanned = state.scanDelims(state.pos, marker === 0x2A); scanned = state.scanDelims(state.pos, marker === 0x2A);
for (i = 0; i < scanned.length; i++) { for (i = 0; i < scanned.length; i++) {

4
lib/rules_inline/entity.js

@ -13,9 +13,9 @@ var NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i;
module.exports = function entity(state, silent) { module.exports = function entity(state, silent) {
var ch, code, match, pos = state.pos, max = state.posMax; if (state.src.charCodeAt(state.pos) !== 0x26/* & */) { return false; }
if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; } var ch, code, match, pos = state.pos, max = state.posMax;
if (pos + 1 < max) { if (pos + 1 < max) {
ch = state.src.charCodeAt(pos + 1); ch = state.src.charCodeAt(pos + 1);

4
lib/rules_inline/escape.js

@ -13,9 +13,9 @@ for (var i = 0; i < 256; i++) { ESCAPED.push(0); }
module.exports = function escape(state, silent) { module.exports = function escape(state, silent) {
var ch, pos = state.pos, max = state.posMax; if (state.src.charCodeAt(state.pos) !== 0x5C/* \ */) { return false; }
if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; } var ch, pos = state.pos, max = state.posMax;
pos++; pos++;

12
lib/rules_inline/html_inline.js

@ -14,18 +14,18 @@ function isLetter(ch) {
module.exports = function html_inline(state, silent) { module.exports = function html_inline(state, silent) {
var ch, match, max, token,
pos = state.pos;
if (!state.md.options.html) { return false; } if (!state.md.options.html) { return false; }
// Check start // Check start
max = state.posMax; var max = state.posMax;
if (state.src.charCodeAt(pos) !== 0x3C/* < */ || if (state.src.charCodeAt(state.pos) !== 0x3C/* < */ ||
pos + 2 >= max) { state.pos + 2 >= max) {
return false; return false;
} }
var ch, match, token,
pos = state.pos;
// Quick fail on second char // Quick fail on second char
ch = state.src.charCodeAt(pos + 1); ch = state.src.charCodeAt(pos + 1);
if (ch !== 0x21/* ! */ && if (ch !== 0x21/* ! */ &&

6
lib/rules_inline/image.js

@ -7,6 +7,9 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function image(state, silent) { module.exports = function image(state, silent) {
if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }
if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }
var attrs, var attrs,
code, code,
content, content,
@ -24,9 +27,6 @@ module.exports = function image(state, silent) {
oldPos = state.pos, oldPos = state.pos,
max = state.posMax; max = state.posMax;
if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }
if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }
labelStart = state.pos + 2; labelStart = state.pos + 2;
labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false); labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);

4
lib/rules_inline/link.js

@ -7,6 +7,8 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function link(state, silent) { module.exports = function link(state, silent) {
if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }
var attrs, var attrs,
code, code,
label, label,
@ -23,8 +25,6 @@ module.exports = function link(state, silent) {
start = state.pos, start = state.pos,
parseReference = true; parseReference = true;
if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }
labelStart = state.pos + 1; labelStart = state.pos + 1;
labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true); labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

16
lib/rules_inline/newline.js

@ -6,11 +6,13 @@ var isSpace = require('../common/utils').isSpace;
module.exports = function newline(state, silent) { module.exports = function newline(state, silent) {
var pmax, max, pos = state.pos; if (state.src.charCodeAt(state.pos) !== 0x0A/* \n */) { return false; }
if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false; } var pmax, max,
pending = state.pending,
pos = state.pos;
pmax = state.pending.length - 1; pmax = pending.length - 1;
max = state.posMax; max = state.posMax;
// ' \n' -> hardbreak // ' \n' -> hardbreak
@ -18,12 +20,12 @@ module.exports = function newline(state, silent) {
// Pending string is stored in concat mode, indexed lookups will cause // Pending string is stored in concat mode, indexed lookups will cause
// convertion to flat mode. // convertion to flat mode.
if (!silent) { if (!silent) {
if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { if (pmax >= 0 && pending.charCodeAt(pmax) === 0x20) {
if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { if (pmax >= 1 && pending.charCodeAt(pmax - 1) === 0x20) {
state.pending = state.pending.replace(/ +$/, ''); state.pending = pending.replace(/ +$/, '');
state.push('hardbreak', 'br', 0); state.push('hardbreak', 'br', 0);
} else { } else {
state.pending = state.pending.slice(0, -1); state.pending = pending.slice(0, -1);
state.push('softbreak', 'br', 0); state.push('softbreak', 'br', 0);
} }

8
lib/rules_inline/strikethrough.js

@ -6,14 +6,14 @@
// Insert each marker as a separate text token, and add it to delimiter list // Insert each marker as a separate text token, and add it to delimiter list
// //
module.exports.tokenize = function strikethrough(state, silent) { module.exports.tokenize = function strikethrough(state, silent) {
var i, scanned, token, len, ch,
start = state.pos,
marker = state.src.charCodeAt(start);
if (silent) { return false; } if (silent) { return false; }
var marker = state.src.charCodeAt(state.pos);
if (marker !== 0x7E/* ~ */) { return false; } if (marker !== 0x7E/* ~ */) { return false; }
var i, scanned, token, len, ch;
scanned = state.scanDelims(state.pos, true); scanned = state.scanDelims(state.pos, true);
len = scanned.length; len = scanned.length;
ch = String.fromCharCode(marker); ch = String.fromCharCode(marker);

17
lib/rules_inline/text_collapse.js

@ -10,26 +10,27 @@
module.exports = function text_collapse(state) { module.exports = function text_collapse(state) {
var curr, last, var curr, last, token,
level = 0, level = 0,
tokens = state.tokens, tokens = state.tokens,
max = state.tokens.length; max = tokens.length;
for (curr = last = 0; curr < max; curr++) { for (curr = last = 0; curr < max; curr++) {
token = tokens[curr];
// re-calculate levels after emphasis/strikethrough turns some text nodes // re-calculate levels after emphasis/strikethrough turns some text nodes
// into opening/closing tags // into opening/closing tags
if (tokens[curr].nesting < 0) level--; // closing tag if (token.nesting < 0) level--; // closing tag
tokens[curr].level = level; token.level = level;
if (tokens[curr].nesting > 0) level++; // opening tag if (token.nesting > 0) level++; // opening tag
if (tokens[curr].type === 'text' && if (token.type === 'text' &&
curr + 1 < max && curr + 1 < max &&
tokens[curr + 1].type === 'text') { tokens[curr + 1].type === 'text') {
// collapse two adjacent text nodes // collapse two adjacent text nodes
tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; tokens[curr + 1].content = token.content + tokens[curr + 1].content;
} else { } else {
if (curr !== last) { tokens[last] = tokens[curr]; } if (curr !== last) { tokens[last] = token; }
last++; last++;
} }

1
package.json

@ -49,6 +49,7 @@
"@rollup/plugin-node-resolve": "^10.0.0", "@rollup/plugin-node-resolve": "^10.0.0",
"ansi": "^0.3.0", "ansi": "^0.3.0",
"autoprefixer-stylus": "^1.0.0", "autoprefixer-stylus": "^1.0.0",
"benchloop": "^1.3.2",
"benchmark": "~2.1.0", "benchmark": "~2.1.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"coveralls": "^3.0.4", "coveralls": "^3.0.4",

Loading…
Cancel
Save