remarkable
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -0,1 +1,10 @@ | ||
1.1.1 / 2014-10-22 | ||
------------------ | ||
- Fixed `Ruler.after()` method. | ||
- Fixed linkification | ||
- Simplified loose/tight rendering. | ||
- Refactored inline parser. No close coupled code in rules anymore. | ||
1.1.0 / 2014-10-20 | ||
@@ -2,0 +11,0 @@ ------------------ |
@@ -14,10 +14,8 @@ | ||
oldPos = state.pos, | ||
oldLength = state.tokens.length, | ||
oldPending = state.pending, | ||
oldFlag = state.validateInsideLink; | ||
oldFlag = state.isInLabel; | ||
if (state.validateInsideLink) { return -1; } | ||
if (state.isInLabel) { return -1; } | ||
if (state.label_nest_level) { | ||
state.label_nest_level--; | ||
if (state.labelUnmatchedScopes) { | ||
state.labelUnmatchedScopes--; | ||
return -1; | ||
@@ -27,3 +25,3 @@ } | ||
state.pos = start + 1; | ||
state.validateInsideLink = true; | ||
state.isInLabel = true; | ||
level = 1; | ||
@@ -43,5 +41,5 @@ | ||
ok = state.parser.tokenizeSingle(state); | ||
ok = state.parser.skipToken(state); | ||
if (!ok) { state.pending += state.src[state.pos++]; } | ||
if (!ok) { state.pos++; } | ||
} | ||
@@ -51,5 +49,5 @@ | ||
labelEnd = state.pos; | ||
state.label_nest_level = 0; | ||
state.labelUnmatchedScopes = 0; | ||
} else { | ||
state.label_nest_level = level - 1; | ||
state.labelUnmatchedScopes = level - 1; | ||
} | ||
@@ -59,5 +57,3 @@ | ||
state.pos = oldPos; | ||
state.tokens.length = oldLength; | ||
state.pending = oldPending; | ||
state.validateInsideLink = oldFlag; | ||
state.isInLabel = oldFlag; | ||
@@ -84,3 +80,3 @@ return labelEnd; | ||
state.pos = pos + 1; | ||
state.link_content = href; | ||
state.linkContent = href; | ||
return true; | ||
@@ -136,3 +132,3 @@ } | ||
state.pos = pos; | ||
state.link_content = href; | ||
state.linkContent = href; | ||
return true; | ||
@@ -163,3 +159,3 @@ } | ||
state.pos = pos + 1; | ||
state.link_content = title; | ||
state.linkContent = title; | ||
return true; | ||
@@ -166,0 +162,0 @@ } |
@@ -60,16 +60,23 @@ // Inline parser | ||
// Generate single token; | ||
// Skip single token by running all rules in validation mode; | ||
// returns `true` if any rule reported success | ||
// | ||
ParserInline.prototype.tokenizeSingle = function (state) { | ||
var ok, i, | ||
ParserInline.prototype.skipToken = function (state) { | ||
var i, pos = state.pos, | ||
rules = this._rules, | ||
len = this._rules.length; | ||
if (state.cache[pos] !== undefined) { | ||
state.pos = state.cache[pos]; | ||
return true; | ||
} | ||
for (i = 0; i < len; i++) { | ||
ok = rules[i](state); | ||
if (ok) { break; } | ||
if (rules[i](state, true)) { | ||
state.cache[pos] = state.pos; | ||
return true; | ||
} | ||
} | ||
return ok; | ||
return false; | ||
}; | ||
@@ -96,3 +103,3 @@ | ||
for (i = 0; i < len; i++) { | ||
ok = rules[i](state); | ||
ok = rules[i](state, false); | ||
if (ok) { break; } | ||
@@ -99,0 +106,0 @@ } |
@@ -38,3 +38,3 @@ | ||
if (!parseLinkDestination(state, pos)) { return -1; } | ||
href = state.link_content; | ||
href = state.linkContent; | ||
pos = state.pos; | ||
@@ -53,3 +53,3 @@ | ||
if (pos < max && start !== pos && parseLinkTitle(state, pos)) { | ||
title = state.link_content; | ||
title = state.linkContent; | ||
pos = state.pos; | ||
@@ -56,0 +56,0 @@ } else { |
@@ -111,7 +111,7 @@ 'use strict'; | ||
rules.paragraph_open = function (/*tokens, idx, options*/) { | ||
return '<p>'; | ||
rules.paragraph_open = function (tokens, idx/*, options*/) { | ||
return tokens[idx].tight ? '' : '<p>'; | ||
}; | ||
rules.paragraph_close = function (tokens, idx /*, options*/) { | ||
return '</p>' + getBreak(tokens, idx); | ||
return (tokens[idx].tight ? '' : '</p>') + getBreak(tokens, idx); | ||
}; | ||
@@ -244,48 +244,11 @@ | ||
Renderer.prototype.render = function (tokens, options) { | ||
var i, len, name, | ||
var i, len, | ||
result = '', | ||
rules = this.rules, | ||
tightStack = []; | ||
rules = this.rules; | ||
// wrap paragraphs on top level by default | ||
var tight = false; | ||
for (i = 0, len = tokens.length; i < len; i++) { | ||
name = tokens[i].type; | ||
// Dirty stack machine to track lists style (loose/tight) | ||
if (name === 'ordered_list_open' || name === 'bullet_list_open') { | ||
tightStack.push(tight); | ||
tight = tokens[i].tight; | ||
} | ||
if (name === 'ordered_list_close' || name === 'bullet_list_close') { | ||
tight = tightStack.pop(); | ||
} | ||
if (name === 'blockquote_open') { | ||
tightStack.push(tight); | ||
tight = false; | ||
} | ||
if (name === 'blockquote_close') { | ||
tight = tightStack.pop(); | ||
} | ||
// in tight mode just ignore paragraphs for lists | ||
// TODO - track right nesting to blockquotes | ||
if (name === 'paragraph_open' && tight) { | ||
continue; | ||
} | ||
if (name === 'paragraph_close' && tight) { | ||
// Quick hack - texts should have LF if followed by blocks | ||
if (tokens[i + 1].type !== 'list_item_close') { | ||
result += '\n'; | ||
} | ||
continue; | ||
} | ||
if (tokens[i].type === 'inline') { | ||
result += this.renderInline(tokens[i].children, options); | ||
} else { | ||
result += rules[name](tokens, i, options); | ||
result += rules[tokens[i].type](tokens, i, options); | ||
} | ||
@@ -292,0 +255,0 @@ } |
@@ -135,3 +135,3 @@ // Ruler is helper class to build responsibility chains from parse rules. | ||
} | ||
this.rules.splice(index + 1, 0, fn); | ||
this.rules.splice(index + 1, 0, rule); | ||
} | ||
@@ -138,0 +138,0 @@ |
@@ -91,3 +91,5 @@ // Lists | ||
itemLines, | ||
terminatorRules = state.parser._rulesListTerm, i, l, terminate; | ||
tight = true, | ||
terminatorRules = state.parser._rulesListTerm, | ||
i, l, terminate, level, tokens; | ||
@@ -121,3 +123,2 @@ // Detect list type and position after marker | ||
order: markerValue, | ||
tight: true, | ||
lines: listLines = [ startLine, 0 ], | ||
@@ -130,3 +131,2 @@ level: state.level++ | ||
type: 'bullet_list_open', | ||
tight: true, | ||
lines: listLines = [ startLine, 0 ], | ||
@@ -189,3 +189,3 @@ level: state.level++ | ||
if (!state.tight || prevEmptyEnd) { | ||
state.tokens[listTokIdx].tight = false; | ||
tight = false; | ||
} | ||
@@ -201,3 +201,6 @@ // Item become loose if finish with empty line, | ||
state.tokens.push({ type: 'list_item_close', level: --state.level }); | ||
state.tokens.push({ | ||
type: 'list_item_close', | ||
level: --state.level | ||
}); | ||
@@ -242,11 +245,25 @@ nextLine = startLine = state.line; | ||
// Finilize list | ||
if (isOrdered) { | ||
state.tokens.push({ type: 'ordered_list_close', level: --state.level }); | ||
} else { | ||
state.tokens.push({ type: 'bullet_list_close', level: --state.level }); | ||
} | ||
state.tokens.push({ | ||
type: isOrdered ? 'ordered_list_close' : 'bullet_list_close', | ||
level: --state.level | ||
}); | ||
listLines[1] = nextLine; | ||
state.line = nextLine; | ||
// mark paragraphs tight if needed | ||
if (tight) { | ||
level = state.level + 2; | ||
tokens = state.tokens; | ||
for (i = listTokIdx + 2, l = tokens.length - 2; i < l; i++) { | ||
if (tokens[i].level === level && tokens[i].type === 'paragraph_open') { | ||
tokens[i].tight = true; | ||
i += 2; | ||
tokens[i].tight = true; | ||
} | ||
} | ||
} | ||
return true; | ||
}; |
@@ -45,2 +45,3 @@ // Paragraph | ||
type: 'paragraph_open', | ||
tight: false, | ||
lines: [ startLine, state.line ], | ||
@@ -58,2 +59,3 @@ level: state.level | ||
type: 'paragraph_close', | ||
tight: false, | ||
level: state.level | ||
@@ -60,0 +62,0 @@ }); |
@@ -13,3 +13,3 @@ // Process autolinks '<protocol:...>' | ||
module.exports = function autolink(state) { | ||
module.exports = function autolink(state, silent) { | ||
var tail, linkMatch, emailMatch, url, pos = state.pos; | ||
@@ -32,13 +32,15 @@ | ||
state.push({ | ||
type: 'link_open', | ||
href: url, | ||
level: state.level | ||
}); | ||
state.push({ | ||
type: 'text', | ||
content: escapeHtml(url), | ||
level: state.level + 1 | ||
}); | ||
state.push({ type: 'link_close', level: state.level }); | ||
if (!silent) { | ||
state.push({ | ||
type: 'link_open', | ||
href: url, | ||
level: state.level | ||
}); | ||
state.push({ | ||
type: 'text', | ||
content: escapeHtml(url), | ||
level: state.level + 1 | ||
}); | ||
state.push({ type: 'link_close', level: state.level }); | ||
} | ||
@@ -57,13 +59,15 @@ state.pos += linkMatch[0].length; | ||
state.push({ | ||
type: 'link_open', | ||
href: 'mailto:' + url, | ||
level: state.level | ||
}); | ||
state.push({ | ||
type: 'text', | ||
content: escapeHtml(url), | ||
level: state.level + 1 | ||
}); | ||
state.push({ type: 'link_close', level: state.level }); | ||
if (!silent) { | ||
state.push({ | ||
type: 'link_open', | ||
href: 'mailto:' + url, | ||
level: state.level | ||
}); | ||
state.push({ | ||
type: 'text', | ||
content: escapeHtml(url), | ||
level: state.level + 1 | ||
}); | ||
state.push({ type: 'link_close', level: state.level }); | ||
} | ||
@@ -70,0 +74,0 @@ state.pos += emailMatch[0].length; |
// Parse backticks | ||
module.exports = function backticks(state) { | ||
module.exports = function backticks(state, silent) { | ||
var start, max, marker, matchStart, matchEnd, | ||
@@ -26,10 +26,12 @@ pos = state.pos, | ||
if (matchEnd - matchStart === marker.length) { | ||
state.push({ | ||
type: 'code', | ||
content: state.src.slice(pos, matchStart) | ||
.replace(/[ \n]+/g,' ') | ||
.trim(), | ||
block: false, | ||
level: state.level | ||
}); | ||
if (!silent) { | ||
state.push({ | ||
type: 'code', | ||
content: state.src.slice(pos, matchStart) | ||
.replace(/[ \n]+/g,' ') | ||
.trim(), | ||
block: false, | ||
level: state.level | ||
}); | ||
} | ||
state.pos = matchEnd; | ||
@@ -40,5 +42,5 @@ return true; | ||
state.pending += marker; | ||
if (!silent) { state.pending += marker; } | ||
state.pos += marker.length; | ||
return true; | ||
}; |
@@ -12,9 +12,8 @@ // Process *this* and _that_ | ||
// returns the amount of markers (1, 2, 3, 4+), or -1 on failure; | ||
// parse sequence of emphasis markers, | ||
// "start" should point at a valid marker | ||
// | ||
// note: in case if 4+ markers it is still not a valid emphasis, | ||
// should be treated as a special case | ||
function parseStart(state, start) { | ||
function scanDelims(state, start) { | ||
var pos = start, lastChar, nextChar, count, | ||
can_open = true, | ||
can_close = true, | ||
max = state.posMax, | ||
@@ -26,85 +25,39 @@ marker = state.src.charCodeAt(start); | ||
while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } | ||
if (pos >= max) { return -1; } | ||
if (pos >= max) { can_open = false; } | ||
count = pos - start; | ||
// Quoting spec: | ||
// | ||
// Character can open emphasis iff | ||
// 1. it is not part of a sequence of four or more unescaped markers, | ||
// 2. it is not followed by whitespace, | ||
// 3. it is "_" and it is not preceded by an ASCII alphanumeric character, and | ||
// 4. either it is not followed by a marker or it is followed immediately by strong emphasis. | ||
if (count >= 4) { | ||
// check condition 1 | ||
// sequence of four or more unescaped markers can't start an emphasis | ||
return count; | ||
} | ||
// sequence of four or more unescaped markers can't start/end an emphasis | ||
can_open = can_close = false; | ||
} else { | ||
nextChar = pos < max ? state.src.charCodeAt(pos) : -1; | ||
// check condition 2, marker followed by whitespace | ||
nextChar = state.src.charCodeAt(pos); | ||
if (nextChar === 0x20 || nextChar === 0x0A) { return -1; } | ||
// check whitespace conditions | ||
if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; } | ||
if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; } | ||
if (marker === 0x5F /* _ */) { | ||
// check condition 3, if it's the beginning of the word | ||
// we need to look back for this | ||
if (isAlphaNum(lastChar)) { return -1; } | ||
if (marker === 0x5F /* _ */) { | ||
// check if we aren't inside the word | ||
if (isAlphaNum(lastChar)) { can_open = false; } | ||
if (isAlphaNum(nextChar)) { can_close = false; } | ||
} | ||
} | ||
return count; | ||
return { | ||
can_open: can_open, | ||
can_close: can_close, | ||
delims: count | ||
}; | ||
} | ||
// returns the amount of markers (1, 2, 3, 4+), or -1 on failure; | ||
// "start" should point at a valid marker | ||
// | ||
// note: in case if 4+ markers it is still not a valid emphasis, | ||
// should be treated as a special case | ||
function parseEnd(state, start) { | ||
var pos = start, lastChar, count, | ||
max = state.posMax, | ||
marker = state.src.charCodeAt(start); | ||
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1; | ||
while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } | ||
count = pos - start; | ||
// Quoting spec: | ||
// | ||
// Character can close emphasis iff | ||
// 1. it is not part of a sequence of four or more unescaped markers, | ||
// 2. it is not preceded by whitespace, | ||
// 3. it is not "_" or it is not followed by an ASCII alphanumeric character | ||
if (count >= 4) { | ||
// check condition 1 | ||
// sequence of four or more unescaped markers can't start an emphasis | ||
return count; | ||
} | ||
// check condition 2, marker preceded by whitespace | ||
if (lastChar === 0x20 || lastChar === 0x0A) { return -1; } | ||
if (marker === 0x5F) { | ||
// check condition 3, if it's the end of the word | ||
if (pos < max && isAlphaNum(state.src.charCodeAt(pos))) { return -1; } | ||
} | ||
return count; | ||
} | ||
module.exports = function emphasis(state/*, silent*/) { | ||
module.exports = function emphasis(state, silent) { | ||
var startCount, | ||
count, | ||
oldLength, | ||
oldPending, | ||
oldFlag, | ||
found, | ||
ok, | ||
oldCount, | ||
newCount, | ||
stack, | ||
res, | ||
max = state.posMax, | ||
start = state.pos, | ||
haveLiteralAsterisk, | ||
marker = state.src.charCodeAt(start); | ||
@@ -117,9 +70,9 @@ | ||
// [foo `bar]()` | ||
if (state.validateInsideEm || state.validateInsideLink) { return false; } | ||
if (silent && state.isInLabel) { return false; } | ||
startCount = parseStart(state, start); | ||
if (startCount < 0) { return false; } | ||
if (startCount >= 4) { | ||
res = scanDelims(state, start); | ||
startCount = res.delims; | ||
if (!res.can_open) { | ||
state.pos += startCount; | ||
state.pending += state.src.slice(start, startCount); | ||
if (!silent) { state.pending += state.src.slice(start, state.pos); } | ||
return true; | ||
@@ -130,14 +83,10 @@ } | ||
oldLength = state.tokens.length; | ||
oldPending = state.pending; | ||
oldFlag = state.validateInsideEm; | ||
state.pos = start + startCount; | ||
stack = [ startCount ]; | ||
state.validateInsideEm = true; | ||
while (state.pos < max) { | ||
if (state.src.charCodeAt(state.pos) === marker && !haveLiteralAsterisk) { | ||
count = parseEnd(state, state.pos); | ||
if (count >= 1 && count < 4) { | ||
if (state.src.charCodeAt(state.pos) === marker) { | ||
res = scanDelims(state, state.pos); | ||
count = res.delims; | ||
if (res.can_close) { | ||
oldCount = stack.pop(); | ||
@@ -168,27 +117,7 @@ newCount = count; | ||
} | ||
count = parseStart(state, state.pos); | ||
if (count >= 1 && count < 4) { | ||
stack.push(count); | ||
state.pos += count; | ||
continue; | ||
} | ||
} | ||
ok = state.parser.tokenizeSingle(state); | ||
if (ok) { | ||
haveLiteralAsterisk = false; | ||
} else { | ||
haveLiteralAsterisk = state.src.charCodeAt(state.pos) === marker; | ||
state.pending += state.src[state.pos]; | ||
state.pos++; | ||
} | ||
if (!state.parser.skipToken(state)) { state.pos++; } | ||
} | ||
// restore old state | ||
state.tokens.length = oldLength; | ||
state.pending = oldPending; | ||
state.validateInsideEm = oldFlag; | ||
if (!found) { | ||
@@ -204,17 +133,19 @@ // parser failed to find ending tag, so it's not valid emphasis | ||
if (startCount === 2 || startCount === 3) { | ||
state.push({ type: 'strong_open', level: state.level++ }); | ||
} | ||
if (startCount === 1 || startCount === 3) { | ||
state.push({ type: 'em_open', level: state.level++ }); | ||
} | ||
if (!silent) { | ||
if (startCount === 2 || startCount === 3) { | ||
state.push({ type: 'strong_open', level: state.level++ }); | ||
} | ||
if (startCount === 1 || startCount === 3) { | ||
state.push({ type: 'em_open', level: state.level++ }); | ||
} | ||
state.parser.tokenize(state); | ||
state.parser.tokenize(state); | ||
if (startCount === 1 || startCount === 3) { | ||
state.push({ type: 'em_close', level: --state.level }); | ||
if (startCount === 1 || startCount === 3) { | ||
state.push({ type: 'em_close', level: --state.level }); | ||
} | ||
if (startCount === 2 || startCount === 3) { | ||
state.push({ type: 'strong_close', level: --state.level }); | ||
} | ||
} | ||
if (startCount === 2 || startCount === 3) { | ||
state.push({ type: 'strong_close', level: --state.level }); | ||
} | ||
@@ -221,0 +152,0 @@ state.pos = state.posMax + startCount; |
@@ -15,3 +15,3 @@ // Proceess html entity - {, ¯, ", ... | ||
module.exports = function entity(state) { | ||
module.exports = function entity(state, silent) { | ||
var ch, code, match, pos = state.pos, max = state.posMax; | ||
@@ -27,4 +27,6 @@ | ||
if (match) { | ||
code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); | ||
state.pending += isValidEntityCode(code) ? escapeHtml(fromCodePoint(code)) : fromCodePoint(0xFFFD); | ||
if (!silent) { | ||
code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); | ||
state.pending += isValidEntityCode(code) ? escapeHtml(fromCodePoint(code)) : fromCodePoint(0xFFFD); | ||
} | ||
state.pos += match[0].length; | ||
@@ -37,3 +39,3 @@ return true; | ||
if (entities.hasOwnProperty(match[1])) { | ||
state.pending += escapeHtml(entities[match[1]]); | ||
if (!silent) { state.pending += escapeHtml(entities[match[1]]); } | ||
state.pos += match[0].length; | ||
@@ -46,5 +48,5 @@ return true; | ||
state.pending += '&'; | ||
if (!silent) { state.pending += '&'; } | ||
state.pos++; | ||
return true; | ||
}; |
// Process < > " (& was processed in markdown escape) | ||
module.exports = function escape_html_char(state) { | ||
var ch = state.src.charCodeAt(state.pos); | ||
module.exports = function escape_html_char(state, silent) { | ||
var ch = state.src.charCodeAt(state.pos), | ||
str; | ||
if (ch === 0x3C/* < */) { | ||
state.pending += '<'; | ||
str = '<'; | ||
} else if (ch === 0x3E/* > */) { | ||
state.pending += '>'; | ||
str = '>'; | ||
} else if (ch === 0x22/* " */) { | ||
state.pending += '"'; | ||
str = '"'; | ||
} else { | ||
@@ -16,4 +17,5 @@ return false; | ||
if (!silent) { state.pending += str; } | ||
state.pos++; | ||
return true; | ||
}; |
@@ -8,4 +8,4 @@ // Proceess escaped chars and hardbreaks | ||
module.exports = function escape(state) { | ||
var ch, pos = state.pos, max = state.posMax; | ||
module.exports = function escape(state, silent) { | ||
var ch, str, pos = state.pos, max = state.posMax; | ||
@@ -22,12 +22,13 @@ if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; } | ||
if (ch === 0x26/* & */) { | ||
state.pending += '&'; | ||
str = '&'; | ||
} else if (ch === 0x3C/* < */) { | ||
state.pending += '<'; | ||
str = '<'; | ||
} else if (ch === 0x3E/* > */) { | ||
state.pending += '>'; | ||
str = '>'; | ||
} else if (ch === 0x22/* " */) { | ||
state.pending += '"'; | ||
str = '"'; | ||
} else { | ||
state.pending += state.src[pos]; | ||
str = state.src[pos]; | ||
} | ||
if (!silent) { state.pending += str; } | ||
state.pos += 2; | ||
@@ -38,6 +39,8 @@ return true; | ||
if (ch === 0x0A) { | ||
state.push({ | ||
type: 'hardbreak', | ||
level: state.level | ||
}); | ||
if (!silent) { | ||
state.push({ | ||
type: 'hardbreak', | ||
level: state.level | ||
}); | ||
} | ||
@@ -53,5 +56,5 @@ pos++; | ||
state.pending += '\\'; | ||
if (!silent) { state.pending += '\\'; } | ||
state.pos++; | ||
return true; | ||
}; |
@@ -16,3 +16,3 @@ // Process html tags | ||
module.exports = function htmltag(state) { | ||
module.exports = function htmltag(state, silent) { | ||
var ch, match, max, pos = state.pos; | ||
@@ -41,10 +41,11 @@ | ||
state.push({ | ||
type: 'htmltag', | ||
content: state.src.slice(pos, pos + match[0].length), | ||
level: state.level | ||
}); | ||
//console.log(state.tokens) | ||
if (!silent) { | ||
state.push({ | ||
type: 'htmltag', | ||
content: state.src.slice(pos, pos + match[0].length), | ||
level: state.level | ||
}); | ||
} | ||
state.pos += match[0].length; | ||
return true; | ||
}; |
@@ -11,3 +11,3 @@ // Process [links](<to> "stuff") | ||
function links(state) { | ||
module.exports = function links(state, silent) { | ||
var labelStart, | ||
@@ -59,3 +59,3 @@ labelEnd, | ||
if (parseLinkDestination(state, pos)) { | ||
href = state.link_content; | ||
href = state.linkContent; | ||
pos = state.pos; | ||
@@ -77,3 +77,3 @@ } else { | ||
if (pos < max && start !== pos && parseLinkTitle(state, pos)) { | ||
title = state.link_content; | ||
title = state.linkContent; | ||
pos = state.pos; | ||
@@ -138,24 +138,26 @@ | ||
// | ||
state.pos = labelStart; | ||
state.posMax = labelEnd; | ||
if (!silent) { | ||
state.pos = labelStart; | ||
state.posMax = labelEnd; | ||
if (isImage) { | ||
state.push({ | ||
type: 'image', | ||
src: href, | ||
title: title, | ||
alt: state.src.substr(labelStart, labelEnd - labelStart), | ||
level: state.level | ||
}); | ||
} else { | ||
state.push({ | ||
type: 'link_open', | ||
href: href, | ||
title: title, | ||
level: state.level++ | ||
}); | ||
state.linkLevel++; | ||
state.parser.tokenize(state); | ||
state.linkLevel--; | ||
state.push({ type: 'link_close', level: --state.level }); | ||
if (isImage) { | ||
state.push({ | ||
type: 'image', | ||
src: href, | ||
title: title, | ||
alt: state.src.substr(labelStart, labelEnd - labelStart), | ||
level: state.level | ||
}); | ||
} else { | ||
state.push({ | ||
type: 'link_open', | ||
href: href, | ||
title: title, | ||
level: state.level++ | ||
}); | ||
state.linkLevel++; | ||
state.parser.tokenize(state); | ||
state.linkLevel--; | ||
state.push({ type: 'link_close', level: --state.level }); | ||
} | ||
} | ||
@@ -166,4 +168,2 @@ | ||
return true; | ||
} | ||
module.exports = links; | ||
}; |
// Proceess '\n' | ||
module.exports = function newline(state) { | ||
module.exports = function newline(state, silent) { | ||
var pmax, max, pos = state.pos; | ||
@@ -15,11 +15,19 @@ | ||
// convertion to flat mode. | ||
if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { | ||
if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { | ||
state.pending = state.pending.replace(/ +$/, ''); | ||
state.push({ | ||
type: 'hardbreak', | ||
level: state.level | ||
}); | ||
if (!silent) { | ||
if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { | ||
if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { | ||
state.pending = state.pending.replace(/ +$/, ''); | ||
state.push({ | ||
type: 'hardbreak', | ||
level: state.level | ||
}); | ||
} else { | ||
state.pending = state.pending.slice(0, -1); | ||
state.push({ | ||
type: 'softbreak', | ||
level: state.level | ||
}); | ||
} | ||
} else { | ||
state.pending = state.pending.slice(0, -1); | ||
state.push({ | ||
@@ -30,8 +38,2 @@ type: 'softbreak', | ||
} | ||
} else { | ||
state.push({ | ||
type: 'softbreak', | ||
level: state.level | ||
}); | ||
} | ||
@@ -38,0 +40,0 @@ |
@@ -18,7 +18,18 @@ // Inline parser state | ||
this.validateInsideEm = false; | ||
this.validateInsideLink = false; | ||
this.linkLevel = 0; | ||
this.link_content = ''; | ||
this.label_nest_level = 0; // for stmd-like backtrack optimization | ||
this.cache = {}; // Stores { start: end } pairs. Useful for backtrack | ||
// optimization of pairs parse (emphasis, strikes). | ||
// Link parser state vars | ||
this.isInLabel = false; // Set true when seek link label - we should disable | ||
// "paired" rules (emphasis, strikes) to not skip | ||
// tailing `]` | ||
this.linkLevel = 0; // Increment for each nesting link. Used to prevent | ||
// nesting in definitions | ||
this.linkContent = ''; // Temporary storage for link url | ||
this.labelUnmatchedScopes = 0; // Track unpaired `[` for link labels | ||
// (backtrack optimization) | ||
} | ||
@@ -25,0 +36,0 @@ |
@@ -5,10 +5,5 @@ // Process ~~strike through~~ | ||
module.exports = function strikethrough(state) { | ||
var oldLength, | ||
oldPending, | ||
oldFlag, | ||
found, | ||
ok, | ||
module.exports = function strikethrough(state, silent) { | ||
var found, | ||
pos, | ||
stack, | ||
max = state.posMax, | ||
@@ -25,3 +20,3 @@ start = state.pos, | ||
// this code also prevents recursion | ||
if (state.validateInsideEm || state.validateInsideLink) { return false; } | ||
if (silent && state.isInLabel) { return false; } | ||
@@ -42,13 +37,7 @@ if (state.level >= state.options.maxNesting) { return false; } | ||
state.pos += pos - start; | ||
state.pending += state.src.slice(start, pos); | ||
if (!silent) { state.pending += state.src.slice(start, pos); } | ||
return true; | ||
} | ||
oldLength = state.tokens.length; | ||
oldPending = state.pending; | ||
oldFlag = state.validateInsideEm; | ||
state.pos = start + 2; | ||
state.validateInsideEm = true; | ||
stack = 1; | ||
@@ -63,10 +52,2 @@ while (state.pos + 1 < max) { | ||
// closing '~~' | ||
stack--; | ||
} else if (nextChar !== 0x20 && nextChar !== 0x0A) { | ||
// opening '~~' | ||
stack++; | ||
} // else { | ||
// // standalone ' ~~ ' indented with spaces | ||
//} | ||
if (stack <= 0) { | ||
found = true; | ||
@@ -79,15 +60,5 @@ break; | ||
ok = state.parser.tokenizeSingle(state); | ||
if (!ok) { | ||
state.pending += state.src[state.pos]; | ||
state.pos++; | ||
} | ||
if (!state.parser.skipToken(state)) { state.pos++; } | ||
} | ||
// restore old state | ||
state.tokens.length = oldLength; | ||
state.pending = oldPending; | ||
state.validateInsideEm = oldFlag; | ||
if (!found) { | ||
@@ -103,5 +74,7 @@ // parser failed to find ending tag, so it's not valid emphasis | ||
state.push({ type: 'del_open', level: state.level++ }); | ||
state.parser.tokenize(state); | ||
state.push({ type: 'del_close', level: --state.level }); | ||
if (!silent) { | ||
state.push({ type: 'del_open', level: state.level++ }); | ||
state.parser.tokenize(state); | ||
state.push({ type: 'del_close', level: --state.level }); | ||
} | ||
@@ -108,0 +81,0 @@ state.pos = state.posMax + 2; |
// Skip text characters for text token, place those to pendibg buffer | ||
// and increment current pos | ||
module.exports = function text(state) { | ||
module.exports = function text(state, silent) { | ||
var match = state.src.slice(state.pos).match(state.parser.textMatch); | ||
@@ -9,3 +9,3 @@ | ||
state.pending += match[0]; | ||
if (!silent) { state.pending += match[0]; } | ||
state.pos += match[0].length; | ||
@@ -12,0 +12,0 @@ |
@@ -18,3 +18,3 @@ // Replace link-like texts with link nodes. | ||
if (match.getType() === 'url') { | ||
links.push(match.getUrl()); | ||
links.push({ text: match.matchedText, url: match.getUrl() }); | ||
} | ||
@@ -79,5 +79,8 @@ return false; | ||
if (!state.parser.validateLink(links[ln])) { continue; } | ||
if (!state.parser.validateLink(links[ln].url)) { continue; } | ||
pos = text.indexOf(links[ln]); | ||
pos = text.indexOf(links[ln].text); | ||
if (pos === -1) { continue; } | ||
if (pos) { | ||
@@ -93,3 +96,3 @@ level = level; | ||
type: 'link_open', | ||
href: links[ln], | ||
href: links[ln].url, | ||
title: '', | ||
@@ -100,3 +103,3 @@ level: level++ | ||
type: 'text', | ||
content: escapeHtml(links[ln]), | ||
content: escapeHtml(links[ln].text), | ||
level: level | ||
@@ -108,3 +111,3 @@ }); | ||
}); | ||
text = text.slice(pos + links[ln].length); | ||
text = text.slice(pos + links[ln].text.length); | ||
} | ||
@@ -111,0 +114,0 @@ if (text.length) { |
{ | ||
"name": "remarkable", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Markdown parser, done right. Commonmark support, extensions, syntax plugins, high speed - all in one.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
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
441569
12311