markdown-it
Advanced tools
Comparing version 4.4.0 to 5.0.0
@@ -0,1 +1,15 @@ | ||
5.0.0 / 2015-10-05 | ||
------------------ | ||
- Internal API change. Due to new CM spec requirements, we had to update | ||
internals. That should not touch ordinary users, but can affect some external | ||
plugins. If you are plugin developper - see migration guide: | ||
https://github.com/markdown-it/markdown-it/blob/master/docs/5.0_migration.md. | ||
- Updated CM spec compatibility to 0.22: | ||
- Keep tabs (don't replace with spaces). | ||
- Don't wrap iframes with paragraphs. | ||
- Rewritten emphasis algorithm. | ||
- Fix closure compiler collisions (don't use reserved words), #159. | ||
4.4.0 / 2015-07-18 | ||
@@ -2,0 +16,0 @@ ------------------ |
@@ -38,2 +38,3 @@ // List of valid html blocks names, accorting to commonmark spec | ||
'html', | ||
'iframe', | ||
'legend', | ||
@@ -40,0 +41,0 @@ 'li', |
@@ -154,2 +154,11 @@ // Utilities | ||
function isSpace(code) { | ||
switch (code) { | ||
case 0x09: | ||
case 0x20: | ||
return true; | ||
} | ||
return false; | ||
} | ||
// Zs (unicode class) || [\t\f\v\r\n] | ||
@@ -181,4 +190,4 @@ function isWhiteSpace(code) { | ||
// Currently without astral characters support. | ||
function isPunctChar(char) { | ||
return UNICODE_PUNCT_RE.test(char); | ||
function isPunctChar(ch) { | ||
return UNICODE_PUNCT_RE.test(ch); | ||
} | ||
@@ -263,2 +272,3 @@ | ||
exports.arrayReplaceAt = arrayReplaceAt; | ||
exports.isSpace = isSpace; | ||
exports.isWhiteSpace = isWhiteSpace; | ||
@@ -265,0 +275,0 @@ exports.isMdAsciiPunct = isMdAsciiPunct; |
@@ -60,3 +60,3 @@ // Main perser class | ||
parsed.hostname = punycode.toASCII(parsed.hostname); | ||
} catch(er) {} | ||
} catch (er) { /**/ } | ||
} | ||
@@ -81,3 +81,3 @@ } | ||
parsed.hostname = punycode.toUnicode(parsed.hostname); | ||
} catch(er) {} | ||
} catch (er) { /**/ } | ||
} | ||
@@ -387,2 +387,5 @@ } | ||
} | ||
if (presets.components[name].rules2) { | ||
self[name].ruler2.enableOnly(presets.components[name].rules2); | ||
} | ||
}); | ||
@@ -420,2 +423,4 @@ } | ||
result = result.concat(this.inline.ruler2.enable(list, true)); | ||
var missed = list.filter(function (name) { return result.indexOf(name) < 0; }); | ||
@@ -447,2 +452,4 @@ | ||
result = result.concat(this.inline.ruler2.disable(list, true)); | ||
var missed = list.filter(function (name) { return result.indexOf(name) < 0; }); | ||
@@ -491,3 +498,3 @@ | ||
* `env` is used to pass data between "distributed" rules and return additional | ||
* metadata like reference info, needed for for renderer. It also can be used to | ||
* metadata like reference info, needed for the renderer. It also can be used to | ||
* inject data in specific cases. Usually, you will be ok to pass `{}`, | ||
@@ -494,0 +501,0 @@ * and then pass updated object to renderer. |
@@ -62,3 +62,3 @@ /** internal | ||
// Nested calls currently used for blockquotes & lists | ||
if (state.tShift[line] < state.blkIndent) { break; } | ||
if (state.sCount[line] < state.blkIndent) { break; } | ||
@@ -65,0 +65,0 @@ // If nesting level exceeded - skip tail to the end. That's not ordinary |
@@ -20,4 +20,4 @@ /** internal | ||
[ 'backticks', require('./rules_inline/backticks') ], | ||
[ 'strikethrough', require('./rules_inline/strikethrough') ], | ||
[ 'emphasis', require('./rules_inline/emphasis') ], | ||
[ 'strikethrough', require('./rules_inline/strikethrough').tokenize ], | ||
[ 'emphasis', require('./rules_inline/emphasis').tokenize ], | ||
[ 'link', require('./rules_inline/link') ], | ||
@@ -30,3 +30,10 @@ [ 'image', require('./rules_inline/image') ], | ||
var _rules2 = [ | ||
[ 'balance_pairs', require('./rules_inline/balance_pairs') ], | ||
[ 'strikethrough', require('./rules_inline/strikethrough').postProcess ], | ||
[ 'emphasis', require('./rules_inline/emphasis').postProcess ], | ||
[ 'text_collapse', require('./rules_inline/text_collapse') ] | ||
]; | ||
/** | ||
@@ -36,2 +43,4 @@ * new ParserInline() | ||
function ParserInline() { | ||
var i; | ||
/** | ||
@@ -44,5 +53,17 @@ * ParserInline#ruler -> Ruler | ||
for (var i = 0; i < _rules.length; i++) { | ||
for (i = 0; i < _rules.length; i++) { | ||
this.ruler.push(_rules[i][0], _rules[i][1]); | ||
} | ||
/** | ||
* ParserInline#ruler2 -> Ruler | ||
* | ||
* [[Ruler]] instance. Second ruler used for post-processing | ||
* (e.g. in emphasis-like rules). | ||
**/ | ||
this.ruler2 = new Ruler(); | ||
for (i = 0; i < _rules2.length; i++) { | ||
this.ruler2.push(_rules2[i][0], _rules2[i][1]); | ||
} | ||
} | ||
@@ -126,5 +147,13 @@ | ||
ParserInline.prototype.parse = function (str, md, env, outTokens) { | ||
var i, rules, len; | ||
var state = new this.State(str, md, env, outTokens); | ||
this.tokenize(state); | ||
rules = this.ruler2.getRules(''); | ||
len = rules.length; | ||
for (i = 0; i < len; i++) { | ||
rules[i](state); | ||
} | ||
}; | ||
@@ -131,0 +160,0 @@ |
@@ -22,3 +22,3 @@ // Commonmark default options | ||
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). | ||
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, | ||
quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ | ||
@@ -72,2 +72,7 @@ // Highlighter function. Should return escaped HTML, | ||
'text' | ||
], | ||
rules2: [ | ||
'balance_pairs', | ||
'emphasis', | ||
'text_collapse' | ||
] | ||
@@ -74,0 +79,0 @@ } |
@@ -22,3 +22,3 @@ // markdown-it default options | ||
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). | ||
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, | ||
quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ | ||
@@ -25,0 +25,0 @@ // Highlighter function. Should return escaped HTML, |
@@ -23,3 +23,3 @@ // "Zero" preset, with nothing enabled. Useful for manual configuring of simple | ||
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). | ||
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, | ||
quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ | ||
@@ -55,2 +55,6 @@ // Highlighter function. Should return escaped HTML, | ||
'text' | ||
], | ||
rules2: [ | ||
'balance_pairs', | ||
'text_collapse' | ||
] | ||
@@ -57,0 +61,0 @@ } |
@@ -31,3 +31,3 @@ /** | ||
default_rules.fence = function (tokens, idx, options, env, self) { | ||
default_rules.fence = function (tokens, idx, options, env, slf) { | ||
var token = tokens[idx], | ||
@@ -49,3 +49,3 @@ info = token.info ? unescapeAll(token.info).trim() : '', | ||
return '<pre><code' + self.renderAttrs(token) + '>' | ||
return '<pre><code' + slf.renderAttrs(token) + '>' | ||
+ highlighted | ||
@@ -56,3 +56,3 @@ + '</code></pre>\n'; | ||
default_rules.image = function (tokens, idx, options, env, self) { | ||
default_rules.image = function (tokens, idx, options, env, slf) { | ||
var token = tokens[idx]; | ||
@@ -66,5 +66,5 @@ | ||
token.attrs[token.attrIndex('alt')][1] = | ||
self.renderInlineAsText(token.children, options, env); | ||
slf.renderInlineAsText(token.children, options, env); | ||
return self.renderToken(tokens, idx, options); | ||
return slf.renderToken(tokens, idx, options); | ||
}; | ||
@@ -71,0 +71,0 @@ |
@@ -5,5 +5,7 @@ // Block quotes | ||
var isSpace = require('../common/utils').isSpace; | ||
module.exports = function blockquote(state, startLine, endLine, silent) { | ||
var nextLine, lastLineEmpty, oldTShift, oldBMarks, oldIndent, oldParentType, lines, | ||
var nextLine, lastLineEmpty, oldTShift, oldSCount, oldBMarks, oldIndent, oldParentType, lines, initial, offset, ch, | ||
terminatorRules, token, | ||
@@ -21,3 +23,3 @@ i, l, terminate, | ||
// skip one optional space after '>' | ||
// skip one optional space (but not tab, check cmark impl) after '>' | ||
if (state.src.charCodeAt(pos) === 0x20) { pos++; } | ||
@@ -28,9 +30,29 @@ | ||
// skip spaces after ">" and re-calculate offset | ||
initial = offset = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]); | ||
oldBMarks = [ state.bMarks[startLine] ]; | ||
state.bMarks[startLine] = pos; | ||
// check if we have an empty blockquote | ||
pos = pos < max ? state.skipSpaces(pos) : pos; | ||
while (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (isSpace(ch)) { | ||
if (ch === 0x09) { | ||
offset += 4 - offset % 4; | ||
} else { | ||
offset++; | ||
} | ||
} else { | ||
break; | ||
} | ||
pos++; | ||
} | ||
lastLineEmpty = pos >= max; | ||
oldSCount = [ state.sCount[startLine] ]; | ||
state.sCount[startLine] = offset - initial; | ||
oldTShift = [ state.tShift[startLine] ]; | ||
@@ -60,3 +82,3 @@ state.tShift[startLine] = pos - state.bMarks[startLine]; | ||
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { | ||
if (state.tShift[nextLine] < oldIndent) { break; } | ||
if (state.sCount[nextLine] < oldIndent) { break; } | ||
@@ -74,11 +96,32 @@ pos = state.bMarks[nextLine] + state.tShift[nextLine]; | ||
// skip one optional space after '>' | ||
// skip one optional space (but not tab, check cmark impl) after '>' | ||
if (state.src.charCodeAt(pos) === 0x20) { pos++; } | ||
// skip spaces after ">" and re-calculate offset | ||
initial = offset = state.sCount[nextLine] + pos - (state.bMarks[nextLine] + state.tShift[nextLine]); | ||
oldBMarks.push(state.bMarks[nextLine]); | ||
state.bMarks[nextLine] = pos; | ||
pos = pos < max ? state.skipSpaces(pos) : pos; | ||
while (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (isSpace(ch)) { | ||
if (ch === 0x09) { | ||
offset += 4 - offset % 4; | ||
} else { | ||
offset++; | ||
} | ||
} else { | ||
break; | ||
} | ||
pos++; | ||
} | ||
lastLineEmpty = pos >= max; | ||
oldSCount.push(state.sCount[nextLine]); | ||
state.sCount[nextLine] = offset - initial; | ||
oldTShift.push(state.tShift[nextLine]); | ||
@@ -104,8 +147,7 @@ state.tShift[nextLine] = pos - state.bMarks[nextLine]; | ||
oldTShift.push(state.tShift[nextLine]); | ||
oldSCount.push(state.sCount[nextLine]); | ||
// A negative number means that this is a paragraph continuation; | ||
// A negative indentation means that this is a paragraph continuation | ||
// | ||
// Any negative number will do the job here, but it's better for it | ||
// to be large enough to make any bugs obvious. | ||
state.tShift[nextLine] = -1; | ||
state.sCount[nextLine] = -1; | ||
} | ||
@@ -133,2 +175,3 @@ | ||
state.tShift[i + startLine] = oldTShift[i]; | ||
state.sCount[i + startLine] = oldSCount[i]; | ||
} | ||
@@ -135,0 +178,0 @@ state.blkIndent = oldIndent; |
@@ -9,3 +9,3 @@ // Code block (4 spaces padded) | ||
if (state.tShift[startLine] - state.blkIndent < 4) { return false; } | ||
if (state.sCount[startLine] - state.blkIndent < 4) { return false; } | ||
@@ -19,3 +19,3 @@ last = nextLine = startLine + 1; | ||
} | ||
if (state.tShift[nextLine] - state.blkIndent >= 4) { | ||
if (state.sCount[nextLine] - state.blkIndent >= 4) { | ||
nextLine++; | ||
@@ -22,0 +22,0 @@ last = nextLine; |
@@ -50,3 +50,3 @@ // fences (``` lang, ~~~ lang) | ||
if (pos < max && state.tShift[nextLine] < state.blkIndent) { | ||
if (pos < max && state.sCount[nextLine] < state.blkIndent) { | ||
// non-empty line with negative indent should stop the list: | ||
@@ -60,3 +60,3 @@ // - ``` | ||
if (state.tShift[nextLine] - state.blkIndent >= 4) { | ||
if (state.sCount[nextLine] - state.blkIndent >= 4) { | ||
// closing fence should be indented less than 4 spaces | ||
@@ -82,3 +82,3 @@ continue; | ||
// If a fence has heading spaces, they should be removed from its inner block | ||
len = state.tShift[startLine]; | ||
len = state.sCount[startLine]; | ||
@@ -85,0 +85,0 @@ state.line = nextLine + (haveEndMarker ? 1 : 0); |
@@ -5,3 +5,5 @@ // heading (#, ##, ...) | ||
var isSpace = require('../common/utils').isSpace; | ||
module.exports = function heading(state, startLine, endLine, silent) { | ||
@@ -30,5 +32,5 @@ var ch, level, tmp, token, | ||
max = state.skipCharsBack(max, 0x20, pos); // space | ||
max = state.skipSpacesBack(max, pos); | ||
tmp = state.skipCharsBack(max, 0x23, pos); // # | ||
if (tmp > pos && state.src.charCodeAt(tmp - 1) === 0x20/* space */) { | ||
if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) { | ||
max = tmp; | ||
@@ -35,0 +37,0 @@ } |
@@ -5,3 +5,5 @@ // Horizontal rule | ||
var isSpace = require('../common/utils').isSpace; | ||
module.exports = function hr(state, startLine, endLine, silent) { | ||
@@ -21,3 +23,3 @@ var marker, cnt, ch, token, | ||
// markers can be mixed with spaces, but there should be at least 3 one | ||
// markers can be mixed with spaces, but there should be at least 3 of them | ||
@@ -27,3 +29,3 @@ cnt = 1; | ||
ch = state.src.charCodeAt(pos++); | ||
if (ch !== marker && ch !== 0x20/* space */) { return false; } | ||
if (ch !== marker && !isSpace(ch)) { return false; } | ||
if (ch === marker) { cnt++; } | ||
@@ -30,0 +32,0 @@ } |
@@ -51,3 +51,3 @@ // HTML block | ||
for (; nextLine < endLine; nextLine++) { | ||
if (state.tShift[nextLine] < state.blkIndent) { break; } | ||
if (state.sCount[nextLine] < state.blkIndent) { break; } | ||
@@ -54,0 +54,0 @@ pos = state.bMarks[nextLine] + state.tShift[nextLine]; |
@@ -11,7 +11,7 @@ // lheading (---, ===) | ||
if (next >= endLine) { return false; } | ||
if (state.tShift[next] < state.blkIndent) { return false; } | ||
if (state.sCount[next] < state.blkIndent) { return false; } | ||
// Scan next line | ||
if (state.tShift[next] - state.blkIndent > 3) { return false; } | ||
if (state.sCount[next] - state.blkIndent > 3) { return false; } | ||
@@ -18,0 +18,0 @@ pos = state.bMarks[next] + state.tShift[next]; |
@@ -5,7 +5,9 @@ // Lists | ||
var isSpace = require('../common/utils').isSpace; | ||
// Search `[-+*][\n ]`, returns next pos arter marker on success | ||
// or -1 on fail. | ||
function skipBulletListMarker(state, startLine) { | ||
var marker, pos, max; | ||
var marker, pos, max, ch; | ||
@@ -23,5 +25,9 @@ pos = state.bMarks[startLine] + state.tShift[startLine]; | ||
if (pos < max && state.src.charCodeAt(pos) !== 0x20) { | ||
// " 1.test " - is not a list item | ||
return -1; | ||
if (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (!isSpace(ch)) { | ||
// " -test " - is not a list item | ||
return -1; | ||
} | ||
} | ||
@@ -71,5 +77,9 @@ | ||
if (pos < max && state.src.charCodeAt(pos) !== 0x20/* space */) { | ||
// " 1.test " - is not a list item | ||
return -1; | ||
if (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (!isSpace(ch)) { | ||
// " 1.test " - is not a list item | ||
return -1; | ||
} | ||
} | ||
@@ -95,5 +105,8 @@ return pos; | ||
var nextLine, | ||
initial, | ||
offset, | ||
indent, | ||
oldTShift, | ||
oldIndent, | ||
oldLIndent, | ||
oldTight, | ||
@@ -103,2 +116,4 @@ oldParentType, | ||
posAfterMarker, | ||
ch, | ||
pos, | ||
max, | ||
@@ -162,5 +177,25 @@ indentAfterMarker, | ||
while (nextLine < endLine) { | ||
contentStart = state.skipSpaces(posAfterMarker); | ||
pos = posAfterMarker; | ||
max = state.eMarks[nextLine]; | ||
initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[startLine] + state.tShift[startLine]); | ||
while (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (isSpace(ch)) { | ||
if (ch === 0x09) { | ||
offset += 4 - offset % 4; | ||
} else { | ||
offset++; | ||
} | ||
} else { | ||
break; | ||
} | ||
pos++; | ||
} | ||
contentStart = pos; | ||
if (contentStart >= max) { | ||
@@ -170,3 +205,3 @@ // trimming space in "- \n 3" case, indent is 1 here | ||
} else { | ||
indentAfterMarker = contentStart - posAfterMarker; | ||
indentAfterMarker = offset - initial; | ||
} | ||
@@ -180,3 +215,3 @@ | ||
// ^^^^^ - calculating total length of this thing | ||
indent = (posAfterMarker - state.bMarks[nextLine]) + indentAfterMarker; | ||
indent = initial + indentAfterMarker; | ||
@@ -191,7 +226,9 @@ // Run subparser & write tokens | ||
oldTShift = state.tShift[startLine]; | ||
oldLIndent = state.sCount[startLine]; | ||
oldParentType = state.parentType; | ||
state.tShift[startLine] = contentStart - state.bMarks[startLine]; | ||
state.blkIndent = indent; | ||
state.tight = true; | ||
state.parentType = 'list'; | ||
state.tShift[startLine] = contentStart - state.bMarks[startLine]; | ||
state.sCount[startLine] = offset; | ||
@@ -210,2 +247,3 @@ state.md.block.tokenize(state, startLine, endLine, true); | ||
state.tShift[startLine] = oldTShift; | ||
state.sCount[startLine] = oldLIndent; | ||
state.tight = oldTight; | ||
@@ -230,3 +268,3 @@ state.parentType = oldParentType; | ||
// | ||
if (state.tShift[nextLine] < state.blkIndent) { break; } | ||
if (state.sCount[nextLine] < state.blkIndent) { break; } | ||
@@ -233,0 +271,0 @@ // fail if terminating block found |
@@ -16,6 +16,6 @@ // Paragraph | ||
// it's considered a lazy continuation regardless of what's there | ||
if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } | ||
if (state.sCount[nextLine] - state.blkIndent > 3) { continue; } | ||
// quirk for blockquotes, this line should already be checked by that rule | ||
if (state.tShift[nextLine] < 0) { continue; } | ||
if (state.sCount[nextLine] < 0) { continue; } | ||
@@ -22,0 +22,0 @@ // Some tags can terminate paragraph without empty line. |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var normalizeReference = require('../common/utils').normalizeReference; | ||
var isSpace = require('../common/utils').isSpace; | ||
@@ -52,6 +53,6 @@ | ||
// it's considered a lazy continuation regardless of what's there | ||
if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } | ||
if (state.sCount[nextLine] - state.blkIndent > 3) { continue; } | ||
// quirk for blockquotes, this line should already be checked by that rule | ||
if (state.tShift[nextLine] < 0) { continue; } | ||
if (state.sCount[nextLine] < 0) { continue; } | ||
@@ -97,3 +98,3 @@ // Some tags can terminate paragraph without empty line. | ||
lines++; | ||
} else if (ch === 0x20) { | ||
} else if (isSpace(ch)) { | ||
/*eslint no-empty:0*/ | ||
@@ -127,3 +128,3 @@ } else { | ||
lines++; | ||
} else if (ch === 0x20) { | ||
} else if (isSpace(ch)) { | ||
/*eslint no-empty:0*/ | ||
@@ -149,3 +150,7 @@ } else { | ||
// skip trailing spaces until the rest of the line | ||
while (pos < max && str.charCodeAt(pos) === 0x20/* space */) { pos++; } | ||
while (pos < max) { | ||
ch = str.charCodeAt(pos); | ||
if (!isSpace(ch)) { break; } | ||
pos++; | ||
} | ||
@@ -159,3 +164,7 @@ if (pos < max && str.charCodeAt(pos) !== 0x0A) { | ||
lines = destEndLineNo; | ||
while (pos < max && str.charCodeAt(pos) === 0x20/* space */) { pos++; } | ||
while (pos < max) { | ||
ch = str.charCodeAt(pos); | ||
if (!isSpace(ch)) { break; } | ||
pos++; | ||
} | ||
} | ||
@@ -162,0 +171,0 @@ } |
@@ -6,6 +6,7 @@ // Parser state class | ||
var Token = require('../token'); | ||
var isSpace = require('../common/utils').isSpace; | ||
function StateBlock(src, md, env, tokens) { | ||
var ch, s, start, pos, len, indent, indent_found; | ||
var ch, s, start, pos, len, indent, offset, indent_found; | ||
@@ -27,3 +28,4 @@ this.src = src; | ||
this.eMarks = []; // line end offsets for fast jumps | ||
this.tShift = []; // indent for each line | ||
this.tShift = []; // offsets of the first non-space characters (tabs not expanded) | ||
this.sCount = []; // indents for each line (tabs expanded) | ||
@@ -47,11 +49,16 @@ // block parser variables | ||
s = this.src; | ||
indent = 0; | ||
indent_found = false; | ||
for (start = pos = indent = 0, len = s.length; pos < len; pos++) { | ||
for (start = pos = indent = offset = 0, len = s.length; pos < len; pos++) { | ||
ch = s.charCodeAt(pos); | ||
if (!indent_found) { | ||
if (ch === 0x20/* space */) { | ||
if (isSpace(ch)) { | ||
indent++; | ||
if (ch === 0x09) { | ||
offset += 4 - offset % 4; | ||
} else { | ||
offset++; | ||
} | ||
continue; | ||
@@ -68,5 +75,7 @@ } else { | ||
this.tShift.push(indent); | ||
this.sCount.push(offset); | ||
indent_found = false; | ||
indent = 0; | ||
offset = 0; | ||
start = pos + 1; | ||
@@ -80,2 +89,3 @@ } | ||
this.tShift.push(0); | ||
this.sCount.push(0); | ||
@@ -114,4 +124,7 @@ this.lineMax = this.bMarks.length - 1; // don't count last fake line | ||
StateBlock.prototype.skipSpaces = function skipSpaces(pos) { | ||
var ch; | ||
for (var max = this.src.length; pos < max; pos++) { | ||
if (this.src.charCodeAt(pos) !== 0x20/* space */) { break; } | ||
ch = this.src.charCodeAt(pos); | ||
if (!isSpace(ch)) { break; } | ||
} | ||
@@ -121,2 +134,12 @@ return pos; | ||
// Skip spaces from given position in reverse. | ||
StateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) { | ||
if (pos <= min) { return pos; } | ||
while (pos > min) { | ||
if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1; } | ||
} | ||
return pos; | ||
}; | ||
// Skip char codes from given position | ||
@@ -142,3 +165,3 @@ StateBlock.prototype.skipChars = function skipChars(pos, code) { | ||
StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) { | ||
var i, first, last, queue, shift, | ||
var i, lineIndent, ch, first, last, queue, lineStart, | ||
line = begin; | ||
@@ -150,18 +173,8 @@ | ||
// Opt: don't use push queue for single line; | ||
if (line + 1 === end) { | ||
first = this.bMarks[line] + Math.min(this.tShift[line], indent); | ||
last = this.eMarks[end - 1] + (keepLastLF ? 1 : 0); | ||
return this.src.slice(first, last); | ||
} | ||
queue = new Array(end - begin); | ||
for (i = 0; line < end; line++, i++) { | ||
shift = this.tShift[line]; | ||
if (shift > indent) { shift = indent; } | ||
if (shift < 0) { shift = 0; } | ||
lineIndent = 0; | ||
lineStart = first = this.bMarks[line]; | ||
first = this.bMarks[line] + shift; | ||
if (line + 1 < end || keepLastLF) { | ||
@@ -174,2 +187,21 @@ // No need for bounds check because we have fake entry on tail. | ||
while (first < last && lineIndent < indent) { | ||
ch = this.src.charCodeAt(first); | ||
if (isSpace(ch)) { | ||
if (ch === 0x09) { | ||
lineIndent += 4 - lineIndent % 4; | ||
} else { | ||
lineIndent++; | ||
} | ||
} else if (first - lineStart < this.tShift[line]) { | ||
// patched tShift masked characters to look like spaces (blockquotes, list markers) | ||
lineIndent++; | ||
} else { | ||
break; | ||
} | ||
first++; | ||
} | ||
queue[i] = this.src.slice(first, last); | ||
@@ -176,0 +208,0 @@ } |
@@ -65,3 +65,3 @@ // GFM table, non-standard | ||
if (state.tShift[nextLine] < state.blkIndent) { return false; } | ||
if (state.sCount[nextLine] < state.blkIndent) { return false; } | ||
@@ -141,3 +141,3 @@ // first character of the second line should be '|' or '-' | ||
for (nextLine = startLine + 2; nextLine < endLine; nextLine++) { | ||
if (state.tShift[nextLine] < state.blkIndent) { break; } | ||
if (state.sCount[nextLine] < state.blkIndent) { break; } | ||
@@ -144,0 +144,0 @@ lineText = getLine(state, nextLine).trim(); |
@@ -6,3 +6,2 @@ // Normalize input string | ||
var TABS_SCAN_RE = /[\n\t]/g; | ||
var NEWLINES_RE = /\r[\n\u0085]|[\u2424\u2028\u0085]/g; | ||
@@ -13,3 +12,3 @@ var NULL_RE = /\u0000/g; | ||
module.exports = function inline(state) { | ||
var str, lineStart, lastTabPos; | ||
var str; | ||
@@ -22,21 +21,3 @@ // Normalize newlines | ||
// Replace tabs with proper number of spaces (1..4) | ||
if (str.indexOf('\t') >= 0) { | ||
lineStart = 0; | ||
lastTabPos = 0; | ||
str = str.replace(TABS_SCAN_RE, function (match, offset) { | ||
var result; | ||
if (str.charCodeAt(offset) === 0x0A) { | ||
lineStart = offset + 1; | ||
lastTabPos = 0; | ||
return match; | ||
} | ||
result = ' '.slice((offset - lineStart - lastTabPos) % 4); | ||
lastTabPos = offset - lineStart + 1; | ||
return result; | ||
}); | ||
} | ||
state.src = str; | ||
}; |
@@ -6,170 +6,119 @@ // Process *this* and _that_ | ||
var isWhiteSpace = require('../common/utils').isWhiteSpace; | ||
var isPunctChar = require('../common/utils').isPunctChar; | ||
var isMdAsciiPunct = require('../common/utils').isMdAsciiPunct; | ||
// parse sequence of emphasis markers, | ||
// "start" should point at a valid marker | ||
function scanDelims(state, start) { | ||
var pos = start, lastChar, nextChar, count, can_open, can_close, | ||
isLastWhiteSpace, isLastPunctChar, | ||
isNextWhiteSpace, isNextPunctChar, | ||
left_flanking = true, | ||
right_flanking = true, | ||
max = state.posMax, | ||
// Insert each marker as a separate text token, and add it to delimiter list | ||
// | ||
module.exports.tokenize = function emphasis(state, silent) { | ||
var i, scanned, token, | ||
start = state.pos, | ||
marker = state.src.charCodeAt(start); | ||
// treat beginning of the line as a whitespace | ||
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : 0x20; | ||
if (silent) { return false; } | ||
while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } | ||
if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; } | ||
count = pos - start; | ||
scanned = state.scanDelims(state.pos, marker === 0x2A); | ||
// treat end of the line as a whitespace | ||
nextChar = pos < max ? state.src.charCodeAt(pos) : 0x20; | ||
for (i = 0; i < scanned.length; i++) { | ||
token = state.push('text', '', 0); | ||
token.content = String.fromCharCode(marker); | ||
isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); | ||
isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); | ||
state.delimiters.push({ | ||
// Char code of the starting marker (number). | ||
// | ||
marker: marker, | ||
isLastWhiteSpace = isWhiteSpace(lastChar); | ||
isNextWhiteSpace = isWhiteSpace(nextChar); | ||
// An amount of characters before this one that's equivalent to | ||
// current one. In plain English: if this delimiter does not open | ||
// an emphasis, neither do previous `jump` characters. | ||
// | ||
// Used to skip sequences like "*****" in one step, for 1st asterisk | ||
// value will be 0, for 2nd it's 1 and so on. | ||
// | ||
jump: i, | ||
if (isNextWhiteSpace) { | ||
left_flanking = false; | ||
} else if (isNextPunctChar) { | ||
if (!(isLastWhiteSpace || isLastPunctChar)) { | ||
left_flanking = false; | ||
} | ||
} | ||
// A position of the token this delimiter corresponds to. | ||
// | ||
token: state.tokens.length - 1, | ||
if (isLastWhiteSpace) { | ||
right_flanking = false; | ||
} else if (isLastPunctChar) { | ||
if (!(isNextWhiteSpace || isNextPunctChar)) { | ||
right_flanking = false; | ||
} | ||
} | ||
// Token level. | ||
// | ||
level: state.level, | ||
if (marker === 0x5F /* _ */) { | ||
// "_" inside a word can neither open nor close an emphasis | ||
can_open = left_flanking && (!right_flanking || isLastPunctChar); | ||
can_close = right_flanking && (!left_flanking || isNextPunctChar); | ||
} else { | ||
can_open = left_flanking; | ||
can_close = right_flanking; | ||
} | ||
// If this delimiter is matched as a valid opener, `end` will be | ||
// equal to its position, otherwise it's `-1`. | ||
// | ||
end: -1, | ||
return { | ||
can_open: can_open, | ||
can_close: can_close, | ||
delims: count | ||
}; | ||
} | ||
module.exports = function emphasis(state, silent) { | ||
var startCount, | ||
count, | ||
found, | ||
oldCount, | ||
newCount, | ||
stack, | ||
res, | ||
token, | ||
max = state.posMax, | ||
start = state.pos, | ||
marker = state.src.charCodeAt(start); | ||
if (marker !== 0x5F/* _ */ && marker !== 0x2A /* * */) { return false; } | ||
if (silent) { return false; } // don't run any pairs in validation mode | ||
res = scanDelims(state, start); | ||
startCount = res.delims; | ||
if (!res.can_open) { | ||
state.pos += startCount; | ||
// Earlier we checked !silent, but this implementation does not need it | ||
state.pending += state.src.slice(start, state.pos); | ||
return true; | ||
// Boolean flags that determine if this delimiter could open or close | ||
// an emphasis. | ||
// | ||
open: scanned.can_open, | ||
close: scanned.can_close | ||
}); | ||
} | ||
state.pos = start + startCount; | ||
stack = [ startCount ]; | ||
state.pos += scanned.length; | ||
while (state.pos < max) { | ||
if (state.src.charCodeAt(state.pos) === marker) { | ||
res = scanDelims(state, state.pos); | ||
count = res.delims; | ||
if (res.can_close) { | ||
oldCount = stack.pop(); | ||
newCount = count; | ||
return true; | ||
}; | ||
while (oldCount !== newCount) { | ||
if (newCount < oldCount) { | ||
stack.push(oldCount - newCount); | ||
break; | ||
} | ||
// assert(newCount > oldCount) | ||
newCount -= oldCount; | ||
// Walk through delimiter list and replace text tokens with tags | ||
// | ||
module.exports.postProcess = function emphasis(state) { | ||
var i, | ||
startDelim, | ||
endDelim, | ||
token, | ||
ch, | ||
isStrong, | ||
delimiters = state.delimiters, | ||
max = state.delimiters.length; | ||
if (stack.length === 0) { break; } | ||
state.pos += oldCount; | ||
oldCount = stack.pop(); | ||
} | ||
for (i = 0; i < max; i++) { | ||
startDelim = delimiters[i]; | ||
if (stack.length === 0) { | ||
startCount = oldCount; | ||
found = true; | ||
break; | ||
} | ||
state.pos += count; | ||
continue; | ||
} | ||
if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) { | ||
continue; | ||
} | ||
if (res.can_open) { stack.push(count); } | ||
state.pos += count; | ||
// Process only opening markers | ||
if (startDelim.end === -1) { | ||
continue; | ||
} | ||
state.md.inline.skipToken(state); | ||
} | ||
endDelim = delimiters[startDelim.end]; | ||
if (!found) { | ||
// parser failed to find ending tag, so it's not valid emphasis | ||
state.pos = start; | ||
return false; | ||
} | ||
// If the next delimiter has the same marker and is adjacent to this one, | ||
// merge those into one strong delimiter. | ||
// | ||
// `<em><em>whatever</em></em>` -> `<strong>whatever</strong>` | ||
// | ||
isStrong = i + 1 < max && | ||
delimiters[i + 1].end === startDelim.end - 1 && | ||
delimiters[i + 1].token === startDelim.token + 1 && | ||
delimiters[startDelim.end - 1].token === endDelim.token - 1 && | ||
delimiters[i + 1].marker === startDelim.marker; | ||
// found! | ||
state.posMax = state.pos; | ||
state.pos = start + startCount; | ||
ch = String.fromCharCode(startDelim.marker); | ||
// Earlier we checked !silent, but this implementation does not need it | ||
token = state.tokens[startDelim.token]; | ||
token.type = isStrong ? 'strong_open' : 'em_open'; | ||
token.tag = isStrong ? 'strong' : 'em'; | ||
token.nesting = 1; | ||
token.markup = isStrong ? ch + ch : ch; | ||
token.content = ''; | ||
// we have `startCount` starting and ending markers, | ||
// now trying to serialize them into tokens | ||
for (count = startCount; count > 1; count -= 2) { | ||
token = state.push('strong_open', 'strong', 1); | ||
token.markup = String.fromCharCode(marker) + String.fromCharCode(marker); | ||
} | ||
if (count % 2) { | ||
token = state.push('em_open', 'em', 1); | ||
token.markup = String.fromCharCode(marker); | ||
} | ||
token = state.tokens[endDelim.token]; | ||
token.type = isStrong ? 'strong_close' : 'em_close'; | ||
token.tag = isStrong ? 'strong' : 'em'; | ||
token.nesting = -1; | ||
token.markup = isStrong ? ch + ch : ch; | ||
token.content = ''; | ||
state.md.inline.tokenize(state); | ||
if (count % 2) { | ||
token = state.push('em_close', 'em', -1); | ||
token.markup = String.fromCharCode(marker); | ||
if (isStrong) { | ||
state.tokens[delimiters[i + 1].token].content = ''; | ||
state.tokens[delimiters[startDelim.end - 1].token].content = ''; | ||
i++; | ||
} | ||
} | ||
for (count = startCount; count > 1; count -= 2) { | ||
token = state.push('strong_close', 'strong', -1); | ||
token.markup = String.fromCharCode(marker) + String.fromCharCode(marker); | ||
} | ||
state.pos = state.posMax + startCount; | ||
state.posMax = max; | ||
return true; | ||
}; |
@@ -5,2 +5,4 @@ // Proceess escaped chars and hardbreaks | ||
var isSpace = require('../common/utils').isSpace; | ||
var ESCAPED = []; | ||
@@ -37,3 +39,7 @@ | ||
// skip leading whitespaces from next line | ||
while (pos < max && state.src.charCodeAt(pos) === 0x20) { pos++; } | ||
while (pos < max) { | ||
ch = state.src.charCodeAt(pos); | ||
if (!isSpace(ch)) { break; } | ||
pos++; | ||
} | ||
@@ -40,0 +46,0 @@ state.pos = pos; |
@@ -9,2 +9,3 @@ // Process ![image](<src> "title") | ||
var normalizeReference = require('../common/utils').normalizeReference; | ||
var isSpace = require('../common/utils').isSpace; | ||
@@ -49,3 +50,3 @@ | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -72,3 +73,3 @@ if (pos >= max) { return false; } | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -87,3 +88,3 @@ | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -109,3 +110,3 @@ } else { | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -143,6 +144,3 @@ | ||
if (!silent) { | ||
state.pos = labelStart; | ||
state.posMax = labelEnd; | ||
var newState = new state.md.inline.State( | ||
state.md.inline.parse( | ||
state.src.slice(labelStart, labelEnd), | ||
@@ -153,3 +151,2 @@ state.md, | ||
); | ||
newState.md.inline.tokenize(newState); | ||
@@ -156,0 +153,0 @@ token = state.push('image', 'img', 0); |
@@ -9,2 +9,3 @@ // Process [link](<to> "stuff") | ||
var normalizeReference = require('../common/utils').normalizeReference; | ||
var isSpace = require('../common/utils').isSpace; | ||
@@ -47,3 +48,3 @@ | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -70,3 +71,3 @@ if (pos >= max) { return false; } | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -85,3 +86,3 @@ | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -107,3 +108,3 @@ } else { | ||
code = state.src.charCodeAt(pos); | ||
if (code !== 0x20 && code !== 0x0A) { break; } | ||
if (!isSpace(code) && code !== 0x0A) { break; } | ||
} | ||
@@ -110,0 +111,0 @@ |
@@ -6,4 +6,8 @@ // Inline parser state | ||
var Token = require('../token'); | ||
var Token = require('../token'); | ||
var isWhiteSpace = require('../common/utils').isWhiteSpace; | ||
var isPunctChar = require('../common/utils').isPunctChar; | ||
var isMdAsciiPunct = require('../common/utils').isMdAsciiPunct; | ||
function StateInline(src, md, env, outTokens) { | ||
@@ -23,2 +27,4 @@ this.src = src; | ||
// optimization of pairs parse (emphasis, strikes). | ||
this.delimiters = []; // Emphasis-like delimiters | ||
} | ||
@@ -58,2 +64,66 @@ | ||
// Scan a sequence of emphasis-like markers, and determine whether | ||
// it can start an emphasis sequence or end an emphasis sequence. | ||
// | ||
// - start - position to scan from (it should point at a valid marker); | ||
// - canSplitWord - determine if these markers can be found inside a word | ||
// | ||
StateInline.prototype.scanDelims = function (start, canSplitWord) { | ||
var pos = start, lastChar, nextChar, count, can_open, can_close, | ||
isLastWhiteSpace, isLastPunctChar, | ||
isNextWhiteSpace, isNextPunctChar, | ||
left_flanking = true, | ||
right_flanking = true, | ||
max = this.posMax, | ||
marker = this.src.charCodeAt(start); | ||
// treat beginning of the line as a whitespace | ||
lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20; | ||
while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; } | ||
count = pos - start; | ||
// treat end of the line as a whitespace | ||
nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20; | ||
isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); | ||
isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); | ||
isLastWhiteSpace = isWhiteSpace(lastChar); | ||
isNextWhiteSpace = isWhiteSpace(nextChar); | ||
if (isNextWhiteSpace) { | ||
left_flanking = false; | ||
} else if (isNextPunctChar) { | ||
if (!(isLastWhiteSpace || isLastPunctChar)) { | ||
left_flanking = false; | ||
} | ||
} | ||
if (isLastWhiteSpace) { | ||
right_flanking = false; | ||
} else if (isLastPunctChar) { | ||
if (!(isNextWhiteSpace || isNextPunctChar)) { | ||
right_flanking = false; | ||
} | ||
} | ||
if (!canSplitWord) { | ||
can_open = left_flanking && (!right_flanking || isLastPunctChar); | ||
can_close = right_flanking && (!left_flanking || isNextPunctChar); | ||
} else { | ||
can_open = left_flanking; | ||
can_close = right_flanking; | ||
} | ||
return { | ||
can_open: can_open, | ||
can_close: can_close, | ||
length: count | ||
}; | ||
}; | ||
// re-export Token class to use in block rules | ||
@@ -60,0 +130,0 @@ StateInline.prototype.Token = Token; |
@@ -6,136 +6,113 @@ // ~~strike through~~ | ||
var isWhiteSpace = require('../common/utils').isWhiteSpace; | ||
var isPunctChar = require('../common/utils').isPunctChar; | ||
var isMdAsciiPunct = require('../common/utils').isMdAsciiPunct; | ||
// Insert each marker as a separate text token, and add it to delimiter list | ||
// | ||
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; } | ||
// parse sequence of markers, | ||
// "start" should point at a valid marker | ||
function scanDelims(state, start) { | ||
var pos = start, lastChar, nextChar, count, | ||
isLastWhiteSpace, isLastPunctChar, | ||
isNextWhiteSpace, isNextPunctChar, | ||
can_open = true, | ||
can_close = true, | ||
max = state.posMax, | ||
marker = state.src.charCodeAt(start); | ||
if (marker !== 0x7E/* ~ */) { return false; } | ||
// treat beginning of the line as a whitespace | ||
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : 0x20; | ||
scanned = state.scanDelims(state.pos, true); | ||
len = scanned.length; | ||
ch = String.fromCharCode(marker); | ||
while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } | ||
if (len < 2) { return false; } | ||
if (pos >= max) { | ||
can_open = false; | ||
if (len % 2) { | ||
token = state.push('text', '', 0); | ||
token.content = ch; | ||
len--; | ||
} | ||
count = pos - start; | ||
for (i = 0; i < len; i += 2) { | ||
token = state.push('text', '', 0); | ||
token.content = ch + ch; | ||
// treat end of the line as a whitespace | ||
nextChar = pos < max ? state.src.charCodeAt(pos) : 0x20; | ||
state.delimiters.push({ | ||
marker: marker, | ||
jump: i, | ||
token: state.tokens.length - 1, | ||
level: state.level, | ||
end: -1, | ||
open: scanned.can_open, | ||
close: scanned.can_close | ||
}); | ||
} | ||
isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); | ||
isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); | ||
state.pos += scanned.length; | ||
isLastWhiteSpace = isWhiteSpace(lastChar); | ||
isNextWhiteSpace = isWhiteSpace(nextChar); | ||
return true; | ||
}; | ||
if (isNextWhiteSpace) { | ||
can_open = false; | ||
} else if (isNextPunctChar) { | ||
if (!(isLastWhiteSpace || isLastPunctChar)) { | ||
can_open = false; | ||
// Walk through delimiter list and replace text tokens with tags | ||
// | ||
module.exports.postProcess = function strikethrough(state) { | ||
var i, j, | ||
startDelim, | ||
endDelim, | ||
token, | ||
loneMarkers = [], | ||
delimiters = state.delimiters, | ||
max = state.delimiters.length; | ||
for (i = 0; i < max; i++) { | ||
startDelim = delimiters[i]; | ||
if (startDelim.marker !== 0x7E/* ~ */) { | ||
continue; | ||
} | ||
} | ||
if (isLastWhiteSpace) { | ||
can_close = false; | ||
} else if (isLastPunctChar) { | ||
if (!(isNextWhiteSpace || isNextPunctChar)) { | ||
can_close = false; | ||
if (startDelim.end === -1) { | ||
continue; | ||
} | ||
} | ||
return { | ||
can_open: can_open, | ||
can_close: can_close, | ||
delims: count | ||
}; | ||
} | ||
endDelim = delimiters[startDelim.end]; | ||
token = state.tokens[startDelim.token]; | ||
token.type = 's_open'; | ||
token.tag = 's'; | ||
token.nesting = 1; | ||
token.markup = '~~'; | ||
token.content = ''; | ||
module.exports = function strikethrough(state, silent) { | ||
var startCount, | ||
count, | ||
tagCount, | ||
found, | ||
stack, | ||
res, | ||
token, | ||
max = state.posMax, | ||
start = state.pos, | ||
marker = state.src.charCodeAt(start); | ||
token = state.tokens[endDelim.token]; | ||
token.type = 's_close'; | ||
token.tag = 's'; | ||
token.nesting = -1; | ||
token.markup = '~~'; | ||
token.content = ''; | ||
if (marker !== 0x7E/* ~ */) { return false; } | ||
if (silent) { return false; } // don't run any pairs in validation mode | ||
if (state.tokens[endDelim.token - 1].type === 'text' && | ||
state.tokens[endDelim.token - 1].content === '~') { | ||
res = scanDelims(state, start); | ||
startCount = res.delims; | ||
if (!res.can_open) { | ||
state.pos += startCount; | ||
// Earlier we checked !silent, but this implementation does not need it | ||
state.pending += state.src.slice(start, state.pos); | ||
return true; | ||
loneMarkers.push(endDelim.token - 1); | ||
} | ||
} | ||
stack = Math.floor(startCount / 2); | ||
if (stack <= 0) { return false; } | ||
state.pos = start + startCount; | ||
// If a marker sequence has an odd number of characters, it's splitted | ||
// like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the | ||
// start of the sequence. | ||
// | ||
// So, we have to move all those markers after subsequent s_close tags. | ||
// | ||
while (loneMarkers.length) { | ||
i = loneMarkers.pop(); | ||
j = i + 1; | ||
while (state.pos < max) { | ||
if (state.src.charCodeAt(state.pos) === marker) { | ||
res = scanDelims(state, state.pos); | ||
count = res.delims; | ||
tagCount = Math.floor(count / 2); | ||
if (res.can_close) { | ||
if (tagCount >= stack) { | ||
state.pos += count - 2; | ||
found = true; | ||
break; | ||
} | ||
stack -= tagCount; | ||
state.pos += count; | ||
continue; | ||
} | ||
if (res.can_open) { stack += tagCount; } | ||
state.pos += count; | ||
continue; | ||
while (j < state.tokens.length && state.tokens[j].type === 's_close') { | ||
j++; | ||
} | ||
state.md.inline.skipToken(state); | ||
} | ||
j--; | ||
if (!found) { | ||
// parser failed to find ending tag, so it's not valid emphasis | ||
state.pos = start; | ||
return false; | ||
if (i !== j) { | ||
token = state.tokens[j]; | ||
state.tokens[j] = state.tokens[i]; | ||
state.tokens[i] = token; | ||
} | ||
} | ||
// found! | ||
state.posMax = state.pos; | ||
state.pos = start + 2; | ||
// Earlier we checked !silent, but this implementation does not need it | ||
token = state.push('s_open', 's', 1); | ||
token.markup = '~~'; | ||
state.md.inline.tokenize(state); | ||
token = state.push('s_close', 's', -1); | ||
token.markup = '~~'; | ||
state.pos = state.posMax + 2; | ||
state.posMax = max; | ||
return true; | ||
}; |
{ | ||
"name": "markdown-it", | ||
"version": "4.4.0", | ||
"version": "5.0.0", | ||
"description": "Markdown-it - modern pluggable markdown parser.", | ||
@@ -20,2 +20,8 @@ "keywords": [ | ||
}, | ||
"files": [ | ||
"index.js", | ||
"bin/", | ||
"lib/", | ||
"dist/" | ||
], | ||
"dependencies": { | ||
@@ -25,3 +31,3 @@ "argparse": "~1.0.2", | ||
"linkify-it": "~1.2.0", | ||
"mdurl": "~1.0.0", | ||
"mdurl": "~1.0.1", | ||
"uc.micro": "^1.0.0" | ||
@@ -31,9 +37,10 @@ }, | ||
"ansi": "~0.3.0", | ||
"autolinker": "^0.18.1", | ||
"autoprefixer-stylus": "~0.5.0", | ||
"benchmark": "~1.0.0", | ||
"browserify": "*", | ||
"chai": "^2.2.0", | ||
"commonmark": "~0.18.1", | ||
"chai": "^3.2.0", | ||
"commonmark": "~0.22.0", | ||
"coveralls": "~2.11.2", | ||
"eslint": "0.13.0", | ||
"eslint": "0.24.0", | ||
"eslint-plugin-nodeca": "^1.0.0", | ||
@@ -43,13 +50,13 @@ "istanbul": "*", | ||
"markdown-it-abbr": "^1.0.0", | ||
"markdown-it-container": "^1.0.0", | ||
"markdown-it-deflist": "^1.0.0", | ||
"markdown-it-container": "^2.0.0", | ||
"markdown-it-deflist": "^2.0.0", | ||
"markdown-it-emoji": "^1.0.0", | ||
"markdown-it-footnote": "^1.0.0", | ||
"markdown-it-footnote": "^2.0.0", | ||
"markdown-it-for-inline": "~0.1.0", | ||
"markdown-it-ins": "^1.0.0", | ||
"markdown-it-mark": "^1.0.0", | ||
"markdown-it-ins": "^2.0.0", | ||
"markdown-it-mark": "^2.0.0", | ||
"markdown-it-sub": "^1.0.0", | ||
"markdown-it-sup": "^1.0.0", | ||
"markdown-it-testgen": "~0.1.3", | ||
"marked": "0.3.3", | ||
"marked": "0.3.5", | ||
"stylus": "~0.50.0", | ||
@@ -56,0 +63,0 @@ "mocha": "*", |
@@ -5,3 +5,3 @@ # markdown-it | ||
[![NPM version](https://img.shields.io/npm/v/markdown-it.svg?style=flat)](https://www.npmjs.org/package/markdown-it) | ||
[![Coverage Status](https://img.shields.io/coveralls/markdown-it/markdown-it/master.svg?style=flat)](https://coveralls.io/r/markdown-it/markdown-it?branch=master) | ||
[![Coverage Status](https://coveralls.io/repos/markdown-it/markdown-it/badge.svg?branch=master&service=github)](https://coveralls.io/github/markdown-it/markdown-it?branch=master) | ||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/markdown-it/markdown-it) | ||
@@ -8,0 +8,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
514897
11387
27
Updatedmdurl@~1.0.1