Comparing version 7.0.0 to 7.1.0
@@ -1,4 +0,6 @@ | ||
var TurndownService = (function () { | ||
var TurndownService = (function (domino) { | ||
'use strict'; | ||
domino = domino && Object.prototype.hasOwnProperty.call(domino, 'default') ? domino['default'] : domino; | ||
function extend (destination) { | ||
@@ -18,2 +20,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -304,15 +317,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -461,3 +470,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -472,3 +481,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -493,7 +502,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -614,3 +626,3 @@ } else { | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -632,3 +644,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -645,7 +658,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -664,24 +681,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -702,2 +730,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -711,4 +741,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -745,2 +773,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -778,3 +807,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -868,3 +897,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -922,27 +951,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -971,2 +990,2 @@ | ||
}()); | ||
}(domino)); |
'use strict'; | ||
require('domino'); | ||
function extend (destination) { | ||
@@ -17,2 +19,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -303,15 +316,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -460,3 +469,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -471,3 +480,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -492,7 +501,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -613,3 +625,3 @@ } else { | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -631,3 +643,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -644,7 +657,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -663,24 +680,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -701,2 +729,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -710,4 +740,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -744,2 +772,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -777,3 +806,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -867,3 +896,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -921,27 +950,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -948,0 +967,0 @@ |
@@ -0,1 +1,3 @@ | ||
import 'domino'; | ||
function extend (destination) { | ||
@@ -15,2 +17,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -301,15 +314,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -458,3 +467,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -469,3 +478,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -490,7 +499,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -611,3 +623,3 @@ } else { | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -629,3 +641,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -642,7 +655,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -661,24 +678,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -699,2 +727,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -708,4 +738,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -742,2 +770,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -775,3 +804,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -865,3 +894,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -919,27 +948,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -946,0 +965,0 @@ |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global.TurndownService = factory()); | ||
}(this, (function () { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('domino')) : | ||
typeof define === 'function' && define.amd ? define(['domino'], factory) : | ||
(global = global || self, global.TurndownService = factory(global.domino)); | ||
}(this, (function (domino) { 'use strict'; | ||
domino = domino && Object.prototype.hasOwnProperty.call(domino, 'default') ? domino['default'] : domino; | ||
function extend (destination) { | ||
@@ -21,2 +23,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -307,15 +320,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -464,3 +473,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -475,3 +484,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -496,7 +505,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -617,3 +629,3 @@ } else { | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -635,3 +647,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -648,7 +661,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -667,24 +684,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -705,2 +733,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -714,4 +744,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -748,2 +776,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -781,3 +810,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -871,3 +900,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -925,27 +954,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -952,0 +971,0 @@ |
'use strict'; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var domino = _interopDefault(require('domino')); | ||
function extend (destination) { | ||
@@ -17,2 +21,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -303,15 +318,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -460,3 +471,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -471,3 +482,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -492,7 +503,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -579,5 +593,5 @@ } else { | ||
{ | ||
var domino = require('domino'); | ||
var domino$1 = domino; | ||
Parser.prototype.parseFromString = function (string) { | ||
return domino.createDocument(string) | ||
return domino$1.createDocument(string) | ||
}; | ||
@@ -590,3 +604,3 @@ } | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -608,3 +622,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -621,7 +636,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -640,24 +659,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -678,2 +708,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -687,4 +719,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -721,2 +751,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -754,3 +785,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -844,3 +875,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -898,27 +929,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -925,0 +946,0 @@ |
@@ -0,1 +1,3 @@ | ||
import domino from 'domino'; | ||
function extend (destination) { | ||
@@ -15,2 +17,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -301,15 +314,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -458,3 +467,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -469,3 +478,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -490,7 +499,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -577,5 +589,5 @@ } else { | ||
{ | ||
var domino = require('domino'); | ||
var domino$1 = domino; | ||
Parser.prototype.parseFromString = function (string) { | ||
return domino.createDocument(string) | ||
return domino$1.createDocument(string) | ||
}; | ||
@@ -588,3 +600,3 @@ } | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -606,3 +618,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -619,7 +632,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -638,24 +655,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -676,2 +704,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -685,4 +715,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -719,2 +747,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -752,3 +781,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -842,3 +871,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -896,27 +925,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -923,0 +942,0 @@ |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global.TurndownService = factory()); | ||
}(this, (function () { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('domino')) : | ||
typeof define === 'function' && define.amd ? define(['domino'], factory) : | ||
(global = global || self, global.TurndownService = factory(global.domino)); | ||
}(this, (function (domino) { 'use strict'; | ||
domino = domino && Object.prototype.hasOwnProperty.call(domino, 'default') ? domino['default'] : domino; | ||
function extend (destination) { | ||
@@ -21,2 +23,13 @@ for (var i = 1; i < arguments.length; i++) { | ||
function trimLeadingNewlines (string) { | ||
return string.replace(/^\n*/, '') | ||
} | ||
function trimTrailingNewlines (string) { | ||
// avoid match-at-end regexp bottleneck, see #370 | ||
var indexEnd = string.length; | ||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; | ||
return string.substring(0, indexEnd) | ||
} | ||
var blockElements = [ | ||
@@ -307,15 +320,11 @@ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', | ||
replacement: function (content) { | ||
if (!content.trim()) return '' | ||
if (!content) return '' | ||
content = content.replace(/\r?\n|\r/g, ' '); | ||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; | ||
var delimiter = '`'; | ||
var leadingSpace = ''; | ||
var trailingSpace = ''; | ||
var matches = content.match(/`+/gm); | ||
if (matches) { | ||
if (/^`/.test(content)) leadingSpace = ' '; | ||
if (/`$/.test(content)) trailingSpace = ' '; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
} | ||
var matches = content.match(/`+/gm) || []; | ||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; | ||
return delimiter + leadingSpace + content + trailingSpace + delimiter | ||
return delimiter + extraSpace + content + extraSpace + delimiter | ||
} | ||
@@ -464,3 +473,3 @@ }; | ||
var prevText = null; | ||
var prevVoid = false; | ||
var keepLeadingWs = false; | ||
@@ -475,3 +484,3 @@ var prev = null; | ||
if ((!prevText || / $/.test(prevText.data)) && | ||
!prevVoid && text[0] === ' ') { | ||
!keepLeadingWs && text[0] === ' ') { | ||
text = text.substr(1); | ||
@@ -496,7 +505,10 @@ } | ||
prevText = null; | ||
prevVoid = false; | ||
} else if (isVoid(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements. | ||
keepLeadingWs = false; | ||
} else if (isVoid(node) || isPre(node)) { | ||
// Avoid trimming space around non-block, non-BR void elements and inline PRE. | ||
prevText = null; | ||
prevVoid = true; | ||
keepLeadingWs = true; | ||
} else if (prevText) { | ||
// Drop protection if set previously. | ||
keepLeadingWs = false; | ||
} | ||
@@ -583,5 +595,5 @@ } else { | ||
{ | ||
var domino = require('domino'); | ||
var domino$1 = domino; | ||
Parser.prototype.parseFromString = function (string) { | ||
return domino.createDocument(string) | ||
return domino$1.createDocument(string) | ||
}; | ||
@@ -594,3 +606,3 @@ } | ||
function RootNode (input) { | ||
function RootNode (input, options) { | ||
var root; | ||
@@ -612,3 +624,4 @@ if (typeof input === 'string') { | ||
isBlock: isBlock, | ||
isVoid: isVoid | ||
isVoid: isVoid, | ||
isPre: options.preformattedCode ? isPreOrCode : null | ||
}); | ||
@@ -625,7 +638,11 @@ | ||
function Node (node) { | ||
function isPreOrCode (node) { | ||
return node.nodeName === 'PRE' || node.nodeName === 'CODE' | ||
} | ||
function Node (node, options) { | ||
node.isBlock = isBlock(node); | ||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; | ||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; | ||
node.isBlank = isBlank(node); | ||
node.flankingWhitespace = flankingWhitespace(node); | ||
node.flankingWhitespace = flankingWhitespace(node, options); | ||
return node | ||
@@ -644,24 +661,35 @@ } | ||
function flankingWhitespace (node) { | ||
var leading = ''; | ||
var trailing = ''; | ||
function flankingWhitespace (node, options) { | ||
if (node.isBlock || (options.preformattedCode && node.isCode)) { | ||
return { leading: '', trailing: '' } | ||
} | ||
if (!node.isBlock) { | ||
var hasLeading = /^\s/.test(node.textContent); | ||
var hasTrailing = /\s$/.test(node.textContent); | ||
var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; | ||
var edges = edgeWhitespace(node.textContent); | ||
if (hasLeading && !isFlankedByWhitespace('left', node)) { | ||
leading = ' '; | ||
} | ||
// abandon leading ASCII WS if left-flanked by ASCII WS | ||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { | ||
edges.leading = edges.leadingNonAscii; | ||
} | ||
if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { | ||
trailing = ' '; | ||
} | ||
// abandon trailing ASCII WS if right-flanked by ASCII WS | ||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { | ||
edges.trailing = edges.trailingNonAscii; | ||
} | ||
return { leading: leading, trailing: trailing } | ||
return { leading: edges.leading, trailing: edges.trailing } | ||
} | ||
function isFlankedByWhitespace (side, node) { | ||
function edgeWhitespace (string) { | ||
var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); | ||
return { | ||
leading: m[1], // whole string for whitespace-only strings | ||
leadingAscii: m[2], | ||
leadingNonAscii: m[3], | ||
trailing: m[4], // empty for whitespace-only strings | ||
trailingNonAscii: m[5], | ||
trailingAscii: m[6] | ||
} | ||
} | ||
function isFlankedByWhitespace (side, node, options) { | ||
var sibling; | ||
@@ -682,2 +710,4 @@ var regExp; | ||
isFlanked = regExp.test(sibling.nodeValue); | ||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') { | ||
isFlanked = false; | ||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) { | ||
@@ -691,4 +721,2 @@ isFlanked = regExp.test(sibling.textContent); | ||
var reduce = Array.prototype.reduce; | ||
var leadingNewLinesRegExp = /^\n*/; | ||
var trailingNewLinesRegExp = /\n*$/; | ||
var escapes = [ | ||
@@ -725,2 +753,3 @@ [/\\/g, '\\\\'], | ||
br: ' ', | ||
preformattedCode: false, | ||
blankReplacement: function (content, node) { | ||
@@ -758,3 +787,3 @@ return node.isBlock ? '\n\n' : '' | ||
var output = process.call(this, new RootNode(input)); | ||
var output = process.call(this, new RootNode(input, this.options)); | ||
return postProcess.call(this, output) | ||
@@ -848,3 +877,3 @@ }, | ||
return reduce.call(parentNode.childNodes, function (output, node) { | ||
node = new Node(node); | ||
node = new Node(node, self.options); | ||
@@ -902,27 +931,17 @@ var replacement = ''; | ||
/** | ||
* Determines the new lines between the current output and the replacement | ||
* Joins replacement to the current output with appropriate number of new lines | ||
* @private | ||
* @param {String} output The current conversion output | ||
* @param {String} replacement The string to append to the output | ||
* @returns The whitespace to separate the current output and the replacement | ||
* @returns Joined output | ||
* @type String | ||
*/ | ||
function separatingNewlines (output, replacement) { | ||
var newlines = [ | ||
output.match(trailingNewLinesRegExp)[0], | ||
replacement.match(leadingNewLinesRegExp)[0] | ||
].sort(); | ||
var maxNewlines = newlines[newlines.length - 1]; | ||
return maxNewlines.length < 2 ? maxNewlines : '\n\n' | ||
} | ||
function join (output, replacement) { | ||
var s1 = trimTrailingNewlines(output); | ||
var s2 = trimLeadingNewlines(replacement); | ||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length); | ||
var separator = '\n\n'.substring(0, nls); | ||
function join (string1, string2) { | ||
var separator = separatingNewlines(string1, string2); | ||
// Remove trailing/leading newlines and replace with separator | ||
string1 = string1.replace(trailingNewLinesRegExp, ''); | ||
string2 = string2.replace(leadingNewLinesRegExp, ''); | ||
return string1 + separator + string2 | ||
return s1 + separator + s2 | ||
} | ||
@@ -929,0 +948,0 @@ |
{ | ||
"name": "turndown", | ||
"description": "A library that converts HTML to Markdown", | ||
"version": "7.0.0", | ||
"version": "7.1.0", | ||
"author": "Dom Christie", | ||
@@ -10,3 +10,6 @@ "main": "lib/turndown.cjs.js", | ||
"browser": { | ||
"domino": false | ||
"domino": false, | ||
"./lib/turndown.cjs.js": "./lib/turndown.browser.cjs.js", | ||
"./lib/turndown.es.js": "./lib/turndown.browser.es.js", | ||
"./lib/turndown.umd.js": "./lib/turndown.browser.umd.js" | ||
}, | ||
@@ -46,5 +49,5 @@ "dependencies": { | ||
"build-test": "browserify test/turndown-test.js --outfile test/turndown-test.browser.js", | ||
"prepublish": "npm run build", | ||
"prepare": "npm run build", | ||
"test": "npm run build && npm run build-test && standard ./src/**/*.js && node test/turndown-test.js" | ||
} | ||
} |
@@ -7,3 +7,5 @@ # Turndown | ||
### to-markdown has been renamed to Turndown. See the [migration guide](https://github.com/domchristie/to-markdown/wiki/Migrating-from-to-markdown-to-Turndown) for details. | ||
## Project Updates | ||
* `to-markdown` has been renamed to Turndown. See the [migration guide](https://github.com/domchristie/to-markdown/wiki/Migrating-from-to-markdown-to-Turndown) for details. | ||
* Turndown repository has changed its URL to https://github.com/mixmark-io/turndown. | ||
@@ -61,2 +63,3 @@ ## Installation | ||
| `linkReferenceStyle` | `full`, `collapsed`, or `shortcut` | `full` | | ||
| `preformattedCode` | `false` or [`true`](https://github.com/lucthev/collapse-whitespace/issues/16) | `false` | | ||
@@ -63,0 +66,0 @@ ### Advanced Options |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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
233
191410
10
5703
1