markdown-it
Advanced tools
Comparing version
@@ -78,3 +78,3 @@ // Utilities | ||
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i; | ||
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i; | ||
@@ -84,3 +84,3 @@ var entities = require('./entities'); | ||
function replaceEntityPattern(match, name) { | ||
var code = 0; | ||
var code; | ||
@@ -87,0 +87,0 @@ if (has(entities, name)) { |
@@ -9,6 +9,5 @@ // Parse link destination | ||
module.exports = function parseLinkDestination(str, pos, max) { | ||
module.exports = function parseLinkDestination(str, start, max) { | ||
var code, level, | ||
lines = 0, | ||
start = pos, | ||
pos = start, | ||
result = { | ||
@@ -79,3 +78,2 @@ ok: false, | ||
result.str = unescapeAll(str.slice(start, pos)); | ||
result.lines = lines; | ||
result.pos = pos; | ||
@@ -82,0 +80,0 @@ result.ok = true; |
@@ -9,7 +9,7 @@ // Parse link title | ||
module.exports = function parseLinkTitle(str, pos, max) { | ||
module.exports = function parseLinkTitle(str, start, max) { | ||
var code, | ||
marker, | ||
lines = 0, | ||
start = pos, | ||
pos = start, | ||
result = { | ||
@@ -16,0 +16,0 @@ ok: false, |
@@ -49,3 +49,3 @@ /** internal | ||
ParserBlock.prototype.tokenize = function (state, startLine, endLine) { | ||
var ok, i, | ||
var ok, i, prevLine, | ||
rules = this.ruler.getRules(''), | ||
@@ -78,8 +78,17 @@ len = rules.length, | ||
// - return true | ||
prevLine = state.line; | ||
for (i = 0; i < len; i++) { | ||
ok = rules[i](state, line, endLine, false); | ||
if (ok) { break; } | ||
if (ok) { | ||
if (prevLine >= state.line) { | ||
throw new Error("block rule didn't increment state.line"); | ||
} | ||
break; | ||
} | ||
} | ||
// this can only happen if user disables paragraph rule | ||
if (!ok) throw new Error('none of the block rules matched'); | ||
// set state.tight if we had an empty line before current tag | ||
@@ -86,0 +95,0 @@ // i.e. latest empty line should not count |
@@ -102,3 +102,6 @@ /** internal | ||
if (ok) { break; } | ||
if (ok) { | ||
if (pos >= state.pos) { throw new Error("inline rule didn't increment state.pos"); } | ||
break; | ||
} | ||
} | ||
@@ -128,3 +131,3 @@ } else { | ||
ParserInline.prototype.tokenize = function (state) { | ||
var ok, i, | ||
var ok, i, prevPos, | ||
rules = this.ruler.getRules(''), | ||
@@ -142,2 +145,3 @@ len = rules.length, | ||
// - return true | ||
prevPos = state.pos; | ||
@@ -147,3 +151,6 @@ if (state.level < maxNesting) { | ||
ok = rules[i](state, false); | ||
if (ok) { break; } | ||
if (ok) { | ||
if (prevPos >= state.pos) { throw new Error("inline rule didn't increment state.pos"); } | ||
break; | ||
} | ||
} | ||
@@ -150,0 +157,0 @@ } |
@@ -25,3 +25,3 @@ /** | ||
return '<code' + slf.renderAttrs(token) + '>' + | ||
escapeHtml(tokens[idx].content) + | ||
escapeHtml(token.content) + | ||
'</code>'; | ||
@@ -333,3 +333,3 @@ }; | ||
} 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 { | ||
@@ -336,0 +336,0 @@ result += this.renderToken(tokens, i, options, env); |
@@ -37,3 +37,3 @@ // Block quotes | ||
// check the block quote marker | ||
if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; } | ||
if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false; } | ||
@@ -44,64 +44,7 @@ // we know that it's going to be a valid blockquote, | ||
// set offset past spaces and ">" | ||
initial = offset = state.sCount[startLine] + 1; | ||
oldBMarks = []; | ||
oldBSCount = []; | ||
oldSCount = []; | ||
oldTShift = []; | ||
// skip one optional space after '>' | ||
if (state.src.charCodeAt(pos) === 0x20 /* space */) { | ||
// ' > test ' | ||
// ^ -- position start of line here: | ||
pos++; | ||
initial++; | ||
offset++; | ||
adjustTab = false; | ||
spaceAfterMarker = true; | ||
} else if (state.src.charCodeAt(pos) === 0x09 /* tab */) { | ||
spaceAfterMarker = true; | ||
if ((state.bsCount[startLine] + offset) % 4 === 3) { | ||
// ' >\t test ' | ||
// ^ -- position start of line here (tab has width===1) | ||
pos++; | ||
initial++; | ||
offset++; | ||
adjustTab = false; | ||
} else { | ||
// ' >\t test ' | ||
// ^ -- position start of line here + shift bsCount slightly | ||
// to make extra space appear | ||
adjustTab = true; | ||
} | ||
} else { | ||
spaceAfterMarker = false; | ||
} | ||
oldBMarks = [ state.bMarks[startLine] ]; | ||
state.bMarks[startLine] = pos; | ||
while (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (isSpace(ch)) { | ||
if (ch === 0x09) { | ||
offset += 4 - (offset + state.bsCount[startLine] + (adjustTab ? 1 : 0)) % 4; | ||
} else { | ||
offset++; | ||
} | ||
} else { | ||
break; | ||
} | ||
pos++; | ||
} | ||
oldBSCount = [ state.bsCount[startLine] ]; | ||
state.bsCount[startLine] = state.sCount[startLine] + 1 + (spaceAfterMarker ? 1 : 0); | ||
lastLineEmpty = pos >= max; | ||
oldSCount = [ state.sCount[startLine] ]; | ||
state.sCount[startLine] = offset - initial; | ||
oldTShift = [ state.tShift[startLine] ]; | ||
state.tShift[startLine] = pos - state.bMarks[startLine]; | ||
terminatorRules = state.md.block.ruler.getRules('blockquote'); | ||
@@ -130,3 +73,3 @@ | ||
// ``` | ||
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { | ||
for (nextLine = startLine; nextLine < endLine; nextLine++) { | ||
// check if it's outdented, i.e. it's inside list item and indented | ||
@@ -154,3 +97,3 @@ // less than said list item: | ||
// set offset past spaces and ">" | ||
initial = offset = state.sCount[nextLine] + 1; | ||
initial = state.sCount[nextLine] + 1; | ||
@@ -163,3 +106,2 @@ // skip one optional space after '>' | ||
initial++; | ||
offset++; | ||
adjustTab = false; | ||
@@ -170,3 +112,3 @@ spaceAfterMarker = true; | ||
if ((state.bsCount[nextLine] + offset) % 4 === 3) { | ||
if ((state.bsCount[nextLine] + initial) % 4 === 3) { | ||
// ' >\t test ' | ||
@@ -176,3 +118,2 @@ // ^ -- position start of line here (tab has width===1) | ||
initial++; | ||
offset++; | ||
adjustTab = false; | ||
@@ -189,2 +130,3 @@ } else { | ||
offset = initial; | ||
oldBMarks.push(state.bMarks[nextLine]); | ||
@@ -191,0 +133,0 @@ state.bMarks[nextLine] = pos; |
@@ -115,3 +115,2 @@ // Lists | ||
max, | ||
nextLine, | ||
offset, | ||
@@ -130,2 +129,3 @@ oldListIndent, | ||
token, | ||
nextLine = startLine, | ||
isTerminatingParagraph = false, | ||
@@ -135,3 +135,3 @@ 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; } | ||
if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; } | ||
@@ -145,4 +145,4 @@ // Special case: | ||
if (state.listIndent >= 0 && | ||
state.sCount[startLine] - state.listIndent >= 4 && | ||
state.sCount[startLine] < state.blkIndent) { | ||
state.sCount[nextLine] - state.listIndent >= 4 && | ||
state.sCount[nextLine] < state.blkIndent) { | ||
return false; | ||
@@ -159,3 +159,3 @@ } | ||
// | ||
if (state.sCount[startLine] >= state.blkIndent) { | ||
if (state.sCount[nextLine] >= state.blkIndent) { | ||
isTerminatingParagraph = true; | ||
@@ -166,5 +166,5 @@ } | ||
// Detect list type and position after marker | ||
if ((posAfterMarker = skipOrderedListMarker(state, startLine)) >= 0) { | ||
if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) { | ||
isOrdered = true; | ||
start = state.bMarks[startLine] + state.tShift[startLine]; | ||
start = state.bMarks[nextLine] + state.tShift[nextLine]; | ||
markerValue = Number(state.src.slice(start, posAfterMarker - 1)); | ||
@@ -176,3 +176,3 @@ | ||
} else if ((posAfterMarker = skipBulletListMarker(state, startLine)) >= 0) { | ||
} else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) { | ||
isOrdered = false; | ||
@@ -187,11 +187,11 @@ | ||
if (isTerminatingParagraph) { | ||
if (state.skipSpaces(posAfterMarker) >= state.eMarks[startLine]) return false; | ||
if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false; | ||
} | ||
// For validation mode we can terminate immediately | ||
if (silent) { return true; } | ||
// We should terminate list on style change. Remember first one to compare. | ||
markerCharCode = state.src.charCodeAt(posAfterMarker - 1); | ||
// For validation mode we can terminate immediately | ||
if (silent) { return true; } | ||
// Start list | ||
@@ -210,3 +210,3 @@ listTokIdx = state.tokens.length; | ||
token.map = listLines = [ startLine, 0 ]; | ||
token.map = listLines = [ nextLine, 0 ]; | ||
token.markup = String.fromCharCode(markerCharCode); | ||
@@ -218,3 +218,2 @@ | ||
nextLine = startLine; | ||
prevEmptyEnd = false; | ||
@@ -230,3 +229,3 @@ terminatorRules = state.md.block.ruler.getRules('list'); | ||
initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[startLine] + state.tShift[startLine]); | ||
initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]); | ||
@@ -267,3 +266,3 @@ while (pos < max) { | ||
token.markup = String.fromCharCode(markerCharCode); | ||
token.map = itemLines = [ startLine, 0 ]; | ||
token.map = itemLines = [ nextLine, 0 ]; | ||
if (isOrdered) { | ||
@@ -275,4 +274,4 @@ token.info = state.src.slice(start, posAfterMarker - 1); | ||
oldTight = state.tight; | ||
oldTShift = state.tShift[startLine]; | ||
oldSCount = state.sCount[startLine]; | ||
oldTShift = state.tShift[nextLine]; | ||
oldSCount = state.sCount[nextLine]; | ||
@@ -288,6 +287,6 @@ // - example list | ||
state.tight = true; | ||
state.tShift[startLine] = contentStart - state.bMarks[startLine]; | ||
state.sCount[startLine] = offset; | ||
state.tShift[nextLine] = contentStart - state.bMarks[nextLine]; | ||
state.sCount[nextLine] = offset; | ||
if (contentStart >= max && state.isEmpty(startLine + 1)) { | ||
if (contentStart >= max && state.isEmpty(nextLine + 1)) { | ||
// workaround for this case | ||
@@ -302,3 +301,3 @@ // (list item is empty, list terminates before "foo"): | ||
} else { | ||
state.md.block.tokenize(state, startLine, endLine, true); | ||
state.md.block.tokenize(state, nextLine, endLine, true); | ||
} | ||
@@ -312,8 +311,8 @@ | ||
// but we should filter last element, because it means list finish | ||
prevEmptyEnd = (state.line - startLine) > 1 && state.isEmpty(state.line - 1); | ||
prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1); | ||
state.blkIndent = state.listIndent; | ||
state.listIndent = oldListIndent; | ||
state.tShift[startLine] = oldTShift; | ||
state.sCount[startLine] = oldSCount; | ||
state.tShift[nextLine] = oldTShift; | ||
state.sCount[nextLine] = oldSCount; | ||
state.tight = oldTight; | ||
@@ -324,5 +323,4 @@ | ||
nextLine = startLine = state.line; | ||
nextLine = state.line; | ||
itemLines[1] = nextLine; | ||
contentStart = state.bMarks[startLine]; | ||
@@ -337,3 +335,3 @@ if (nextLine >= endLine) { break; } | ||
// if it's indented more than 3 spaces, it should be a code block | ||
if (state.sCount[startLine] - state.blkIndent >= 4) { break; } | ||
if (state.sCount[nextLine] - state.blkIndent >= 4) { break; } | ||
@@ -340,0 +338,0 @@ // fail if terminating block found |
@@ -6,7 +6,6 @@ // Paragraph | ||
module.exports = function paragraph(state, startLine/*, endLine*/) { | ||
module.exports = function paragraph(state, startLine, endLine) { | ||
var content, terminate, i, l, token, oldParentType, | ||
nextLine = startLine + 1, | ||
terminatorRules = state.md.block.ruler.getRules('paragraph'), | ||
endLine = state.lineMax; | ||
terminatorRules = state.md.block.ruler.getRules('paragraph'); | ||
@@ -13,0 +12,0 @@ oldParentType = state.parentType; |
@@ -7,3 +7,2 @@ // Simple typographic replacements | ||
// +- → ± | ||
// (p) (P) -> § | ||
// ... → … (also ?.... → ?.., !.... → !..) | ||
@@ -10,0 +9,0 @@ // ???????? → ???, !!!!! → !!!, `,,` → `,` |
@@ -29,3 +29,3 @@ // Parse backticks | ||
matchStart = matchEnd = pos; | ||
matchEnd = pos; | ||
@@ -32,0 +32,0 @@ // Nothing found in the cache, scan until the end of the line (or until marker is found) |
@@ -6,3 +6,3 @@ // For each opening emphasis-like marker find a matching closing one | ||
function processDelimiters(state, delimiters) { | ||
function processDelimiters(delimiters) { | ||
var closerIdx, openerIdx, closer, opener, minOpenerIdx, newMinOpenerIdx, | ||
@@ -124,9 +124,9 @@ isOddMatch, lastJump, | ||
processDelimiters(state, state.delimiters); | ||
processDelimiters(state.delimiters); | ||
for (curr = 0; curr < max; curr++) { | ||
if (tokens_meta[curr] && tokens_meta[curr].delimiters) { | ||
processDelimiters(state, tokens_meta[curr].delimiters); | ||
processDelimiters(tokens_meta[curr].delimiters); | ||
} | ||
} | ||
}; |
@@ -51,3 +51,3 @@ // Process html tags | ||
token = state.push('html_inline', '', 0); | ||
token.content = state.src.slice(pos, pos + match[0].length); | ||
token.content = match[0]; | ||
@@ -54,0 +54,0 @@ if (isLinkOpen(token.content)) state.linkLevel++; |
@@ -34,2 +34,6 @@ // Process links like https://example.org/ | ||
// invalid link, but still detected by linkify somehow; | ||
// need to check to prevent infinite loop below | ||
if (url.length <= proto.length) return false; | ||
// disallow '*' at the end of the link (conflicts with emphasis) | ||
@@ -36,0 +40,0 @@ url = url.replace(/\*+$/, ''); |
{ | ||
"name": "markdown-it", | ||
"version": "13.0.1", | ||
"version": "13.0.2", | ||
"description": "Markdown-it - modern pluggable markdown parser.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -148,3 +148,3 @@ # markdown-it <!-- omit in toc --> | ||
```js | ||
var hljs = require('highlight.js'); // https://highlightjs.org/ | ||
var hljs = require('highlight.js'); // https://highlightjs.org | ||
@@ -168,3 +168,3 @@ // Actual default values | ||
```js | ||
var hljs = require('highlight.js'); // https://highlightjs.org/ | ||
var hljs = require('highlight.js'); // https://highlightjs.org | ||
@@ -201,3 +201,3 @@ // Actual default values | ||
If you are going to write plugins - take a look at | ||
If you are going to write plugins, please take a look at | ||
[Development info](https://github.com/markdown-it/markdown-it/tree/master/docs). | ||
@@ -248,6 +248,8 @@ | ||
You can find all rules in sources: | ||
[parser_core.js](lib/parser_core.js), [parser_block](lib/parser_block.js), | ||
[parser_inline](lib/parser_inline.js). | ||
- [`parser_core.js`](lib/parser_core.js) | ||
- [`parser_block.js`](lib/parser_block.js) | ||
- [`parser_inline.js`](lib/parser_inline.js) | ||
## Benchmark | ||
@@ -272,5 +274,5 @@ | ||
__Note.__ CommonMark version runs with [simplified link normalizers](https://github.com/markdown-it/markdown-it/blob/master/benchmark/implementations/current-commonmark/index.js) | ||
for more "honest" compare. Difference is ~ 1.5x. | ||
for more "honest" compare. Difference is ≈1.5×. | ||
As you can see, `markdown-it` doesn't pay with speed for it's flexibility. | ||
As you can see, `markdown-it` doesn't pay with speed for its flexibility. | ||
Slowdown of "full" version caused by additional features not available in | ||
@@ -277,0 +279,0 @@ other implementations. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
310
0.65%563110
-0.4%13919
-0.51%