mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 22:10:13 +01:00
Reimplement MD037/no-space-in-emphasis using micromark tokens, report start/end separately for smaller edit spans, remove markdown-it-texmath (fixes #533, fixes #597).
This commit is contained in:
parent
e86fb7699d
commit
73b9704159
20 changed files with 1784 additions and 2502 deletions
|
|
@ -60,7 +60,11 @@
|
||||||
micromarkHtml.mathHtml()
|
micromarkHtml.mathHtml()
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
return micromarkHtml.compile(compileOptions)(events);
|
try {
|
||||||
|
return micromarkHtml.compile(compileOptions)(events);
|
||||||
|
} catch (error) {
|
||||||
|
return `[Exception: "${error}"]`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return `[Unsupported renderer "${renderer}"]`;
|
return `[Unsupported renderer "${renderer}"]`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,6 @@ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" =
|
||||||
var micromark = __webpack_require__(/*! ./micromark.cjs */ "../helpers/micromark.cjs");
|
var micromark = __webpack_require__(/*! ./micromark.cjs */ "../helpers/micromark.cjs");
|
||||||
var _require = __webpack_require__(/*! ./shared.js */ "../helpers/shared.js"),
|
var _require = __webpack_require__(/*! ./shared.js */ "../helpers/shared.js"),
|
||||||
newLineRe = _require.newLineRe;
|
newLineRe = _require.newLineRe;
|
||||||
|
|
||||||
// Regular expression for matching common newline characters
|
|
||||||
// See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js
|
|
||||||
module.exports.newLineRe = newLineRe;
|
module.exports.newLineRe = newLineRe;
|
||||||
|
|
||||||
// Regular expression for matching common front matter (YAML and TOML)
|
// Regular expression for matching common front matter (YAML and TOML)
|
||||||
|
|
@ -71,9 +68,6 @@ module.exports.htmlElementRe = htmlElementRe;
|
||||||
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
||||||
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
||||||
|
|
||||||
// Regular expression for all instances of emphasis markers
|
|
||||||
var emphasisMarkersRe = /[_*]/g;
|
|
||||||
|
|
||||||
// Regular expression for blockquote prefixes
|
// Regular expression for blockquote prefixes
|
||||||
var blockquotePrefixRe = /^[>\s]*/;
|
var blockquotePrefixRe = /^[>\s]*/;
|
||||||
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
||||||
|
|
@ -383,21 +377,10 @@ function filterTokens(params, type, handler) {
|
||||||
}
|
}
|
||||||
module.exports.filterTokens = filterTokens;
|
module.exports.filterTokens = filterTokens;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a token is a math block (created by markdown-it-texmath).
|
|
||||||
*
|
|
||||||
* @param {Object} token MarkdownItToken instance.
|
|
||||||
* @returns {boolean} True iff token is a math block.
|
|
||||||
*/
|
|
||||||
function isMathBlock(token) {
|
|
||||||
return (token.tag === "$$" || token.tag === "math") && token.type.startsWith("math_block") && !token.type.endsWith("_end");
|
|
||||||
}
|
|
||||||
module.exports.isMathBlock = isMathBlock;
|
|
||||||
|
|
||||||
// Get line metadata array
|
// Get line metadata array
|
||||||
module.exports.getLineMetadata = function getLineMetadata(params) {
|
module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
var lineMetadata = params.lines.map(function (line, index) {
|
var lineMetadata = params.lines.map(function (line, index) {
|
||||||
return [line, index, false, 0, false, false, false, false];
|
return [line, index, false, 0, false, false, false];
|
||||||
});
|
});
|
||||||
filterTokens(params, "fence", function (token) {
|
filterTokens(params, "fence", function (token) {
|
||||||
lineMetadata[token.map[0]][3] = 1;
|
lineMetadata[token.map[0]][3] = 1;
|
||||||
|
|
@ -426,20 +409,6 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
filterTokens(params, "hr", function (token) {
|
filterTokens(params, "hr", function (token) {
|
||||||
lineMetadata[token.map[0]][6] = true;
|
lineMetadata[token.map[0]][6] = true;
|
||||||
});
|
});
|
||||||
var _iterator2 = _createForOfIteratorHelper(params.parsers.markdownit.tokens.filter(isMathBlock)),
|
|
||||||
_step2;
|
|
||||||
try {
|
|
||||||
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
||||||
var token = _step2.value;
|
|
||||||
for (var i = token.map[0]; i < token.map[1]; i++) {
|
|
||||||
lineMetadata[i][7] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
_iterator2.e(err);
|
|
||||||
} finally {
|
|
||||||
_iterator2.f();
|
|
||||||
}
|
|
||||||
return lineMetadata;
|
return lineMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -448,21 +417,21 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
*
|
*
|
||||||
* @param {Object} lineMetadata Line metadata object.
|
* @param {Object} lineMetadata Line metadata object.
|
||||||
* @param {Function} handler Function taking (line, lineIndex, inCode, onFence,
|
* @param {Function} handler Function taking (line, lineIndex, inCode, onFence,
|
||||||
* inTable, inItem, inBreak, inMath).
|
* inTable, inItem, inBreak).
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachLine(lineMetadata, handler) {
|
function forEachLine(lineMetadata, handler) {
|
||||||
var _iterator3 = _createForOfIteratorHelper(lineMetadata),
|
var _iterator2 = _createForOfIteratorHelper(lineMetadata),
|
||||||
_step3;
|
_step2;
|
||||||
try {
|
try {
|
||||||
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
||||||
var metadata = _step3.value;
|
var metadata = _step2.value;
|
||||||
handler.apply(void 0, _toConsumableArray(metadata));
|
handler.apply(void 0, _toConsumableArray(metadata));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator3.e(err);
|
_iterator2.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator3.f();
|
_iterator2.f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports.forEachLine = forEachLine;
|
module.exports.forEachLine = forEachLine;
|
||||||
|
|
@ -477,11 +446,11 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
var lastWithMap = {
|
var lastWithMap = {
|
||||||
"map": [0, 1]
|
"map": [0, 1]
|
||||||
};
|
};
|
||||||
var _iterator4 = _createForOfIteratorHelper(tokens),
|
var _iterator3 = _createForOfIteratorHelper(tokens),
|
||||||
_step4;
|
_step3;
|
||||||
try {
|
try {
|
||||||
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
||||||
var token = _step4.value;
|
var token = _step3.value;
|
||||||
if (token.type === "bullet_list_open" || token.type === "ordered_list_open") {
|
if (token.type === "bullet_list_open" || token.type === "ordered_list_open") {
|
||||||
// Save current context and start a new one
|
// Save current context and start a new one
|
||||||
stack.push(current);
|
stack.push(current);
|
||||||
|
|
@ -519,9 +488,9 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator4.e(err);
|
_iterator3.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator4.f();
|
_iterator3.f();
|
||||||
}
|
}
|
||||||
return flattenedLists;
|
return flattenedLists;
|
||||||
};
|
};
|
||||||
|
|
@ -536,19 +505,19 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
*/
|
*/
|
||||||
function forEachInlineChild(params, type, handler) {
|
function forEachInlineChild(params, type, handler) {
|
||||||
filterTokens(params, "inline", function (token) {
|
filterTokens(params, "inline", function (token) {
|
||||||
var _iterator5 = _createForOfIteratorHelper(token.children.filter(function (c) {
|
var _iterator4 = _createForOfIteratorHelper(token.children.filter(function (c) {
|
||||||
return c.type === type;
|
return c.type === type;
|
||||||
})),
|
})),
|
||||||
_step5;
|
_step4;
|
||||||
try {
|
try {
|
||||||
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
||||||
var child = _step5.value;
|
var child = _step4.value;
|
||||||
handler(child, token);
|
handler(child, token);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator5.e(err);
|
_iterator4.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator5.f();
|
_iterator4.f();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -557,11 +526,11 @@ module.exports.forEachInlineChild = forEachInlineChild;
|
||||||
// Calls the provided function for each heading's content
|
// Calls the provided function for each heading's content
|
||||||
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
var heading = null;
|
var heading = null;
|
||||||
var _iterator6 = _createForOfIteratorHelper(params.parsers.markdownit.tokens),
|
var _iterator5 = _createForOfIteratorHelper(params.parsers.markdownit.tokens),
|
||||||
_step6;
|
_step5;
|
||||||
try {
|
try {
|
||||||
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
||||||
var token = _step6.value;
|
var token = _step5.value;
|
||||||
if (token.type === "heading_open") {
|
if (token.type === "heading_open") {
|
||||||
heading = token;
|
heading = token;
|
||||||
} else if (token.type === "heading_close") {
|
} else if (token.type === "heading_close") {
|
||||||
|
|
@ -571,9 +540,9 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator6.e(err);
|
_iterator5.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator6.f();
|
_iterator5.f();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -708,19 +677,19 @@ module.exports.codeBlockAndSpanRanges = function (params, lineMetadata) {
|
||||||
var tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
var tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
||||||
forEachInlineCodeSpan(tokenLines.join("\n"), function (code, lineIndex, columnIndex) {
|
forEachInlineCodeSpan(tokenLines.join("\n"), function (code, lineIndex, columnIndex) {
|
||||||
var codeLines = code.split(newLineRe);
|
var codeLines = code.split(newLineRe);
|
||||||
var _iterator7 = _createForOfIteratorHelper(codeLines.entries()),
|
var _iterator6 = _createForOfIteratorHelper(codeLines.entries()),
|
||||||
_step7;
|
_step6;
|
||||||
try {
|
try {
|
||||||
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
||||||
var _step7$value = _slicedToArray(_step7.value, 2),
|
var _step6$value = _slicedToArray(_step6.value, 2),
|
||||||
i = _step7$value[0],
|
i = _step6$value[0],
|
||||||
line = _step7$value[1];
|
line = _step6$value[1];
|
||||||
exclusions.push([token.lineNumber - 1 + lineIndex + i, i ? 0 : columnIndex, line.length]);
|
exclusions.push([token.lineNumber - 1 + lineIndex + i, i ? 0 : columnIndex, line.length]);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator7.e(err);
|
_iterator6.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator7.f();
|
_iterator6.f();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -728,51 +697,6 @@ module.exports.codeBlockAndSpanRanges = function (params, lineMetadata) {
|
||||||
return exclusions;
|
return exclusions;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of HTML element ranges.
|
|
||||||
*
|
|
||||||
* @param {Object} params RuleParams instance.
|
|
||||||
* @param {Object} lineMetadata Line metadata object.
|
|
||||||
* @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
|
|
||||||
*/
|
|
||||||
module.exports.htmlElementRanges = function (params, lineMetadata) {
|
|
||||||
var exclusions = [];
|
|
||||||
// Match with htmlElementRe
|
|
||||||
forEachLine(lineMetadata, function (line, lineIndex, inCode) {
|
|
||||||
var match = null;
|
|
||||||
// eslint-disable-next-line no-unmodified-loop-condition
|
|
||||||
while (!inCode && (match = htmlElementRe.exec(line)) !== null) {
|
|
||||||
exclusions.push([lineIndex, match.index, match[0].length]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Match with html_inline
|
|
||||||
forEachInlineChild(params, "html_inline", function (token, parent) {
|
|
||||||
var parentContent = parent.content;
|
|
||||||
var tokenContent = token.content;
|
|
||||||
var parentIndex = parentContent.indexOf(tokenContent);
|
|
||||||
var deltaLines = 0;
|
|
||||||
var indent = 0;
|
|
||||||
for (var i = parentIndex - 1; i >= 0; i--) {
|
|
||||||
if (parentContent[i] === "\n") {
|
|
||||||
deltaLines++;
|
|
||||||
} else if (deltaLines === 0) {
|
|
||||||
indent++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var lineIndex = token.lineNumber - 1 + deltaLines;
|
|
||||||
do {
|
|
||||||
var index = tokenContent.indexOf("\n");
|
|
||||||
var length = index === -1 ? tokenContent.length : index;
|
|
||||||
exclusions.push([lineIndex, indent, length]);
|
|
||||||
tokenContent = tokenContent.slice(length + 1);
|
|
||||||
lineIndex++;
|
|
||||||
indent = 0;
|
|
||||||
} while (tokenContent.length > 0);
|
|
||||||
});
|
|
||||||
// Return results
|
|
||||||
return exclusions;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the specified range is within another range.
|
* Determines whether the specified range is within another range.
|
||||||
*
|
*
|
||||||
|
|
@ -810,155 +734,6 @@ module.exports.frontMatterHasTitle = function frontMatterHasTitle(frontMatterLin
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the provided function for each link.
|
|
||||||
*
|
|
||||||
* @param {string} line Line of Markdown input.
|
|
||||||
* @param {Function} handler Function taking (index, link, text, destination).
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function forEachLink(line, handler) {
|
|
||||||
// Helper to find matching close symbol for link text/destination
|
|
||||||
var findClosingSymbol = function findClosingSymbol(index) {
|
|
||||||
var begin = line[index];
|
|
||||||
var end = begin === "[" ? "]" : ")";
|
|
||||||
var nesting = 0;
|
|
||||||
var escaping = false;
|
|
||||||
var pointy = false;
|
|
||||||
for (var i = index + 1; i < line.length; i++) {
|
|
||||||
var current = line[i];
|
|
||||||
if (current === "\\") {
|
|
||||||
escaping = !escaping;
|
|
||||||
} else if (!escaping && current === begin) {
|
|
||||||
nesting++;
|
|
||||||
} else if (!escaping && current === end) {
|
|
||||||
if (nesting > 0) {
|
|
||||||
nesting--;
|
|
||||||
} else if (!pointy) {
|
|
||||||
// Return index after matching close symbol
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
} else if (i === index + 1 && begin === "(" && current === "<") {
|
|
||||||
pointy = true;
|
|
||||||
} else if (!escaping && pointy && current === ">") {
|
|
||||||
pointy = false;
|
|
||||||
nesting = 0;
|
|
||||||
} else {
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No match found
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
// Scan line for unescaped "[" character
|
|
||||||
var escaping = false;
|
|
||||||
for (var i = 0; i < line.length; i++) {
|
|
||||||
var current = line[i];
|
|
||||||
if (current === "\\") {
|
|
||||||
escaping = !escaping;
|
|
||||||
} else if (!escaping && current === "[") {
|
|
||||||
// Scan for matching close "]" of link text
|
|
||||||
var textEnd = findClosingSymbol(i);
|
|
||||||
if (textEnd !== -1) {
|
|
||||||
if (line[textEnd] === "(" || line[textEnd] === "[") {
|
|
||||||
// Scan for matching close ")" or "]" of link destination
|
|
||||||
var destEnd = findClosingSymbol(textEnd);
|
|
||||||
if (destEnd !== -1) {
|
|
||||||
// Call handler with link text and destination
|
|
||||||
var link = line.slice(i, destEnd);
|
|
||||||
var text = line.slice(i, textEnd);
|
|
||||||
var dest = line.slice(textEnd, destEnd);
|
|
||||||
handler(i, link, text, dest);
|
|
||||||
i = destEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i < textEnd) {
|
|
||||||
// Call handler with link text only
|
|
||||||
var _text = line.slice(i, textEnd);
|
|
||||||
handler(i, _text, _text);
|
|
||||||
i = textEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports.forEachLink = forEachLink;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of emphasis markers in code spans and links.
|
|
||||||
*
|
|
||||||
* @param {Object} params RuleParams instance.
|
|
||||||
* @returns {number[][]} List of markers.
|
|
||||||
*/
|
|
||||||
function emphasisMarkersInContent(params) {
|
|
||||||
var lines = params.lines;
|
|
||||||
var byLine = new Array(lines.length);
|
|
||||||
// Search links
|
|
||||||
var _iterator8 = _createForOfIteratorHelper(lines.entries()),
|
|
||||||
_step8;
|
|
||||||
try {
|
|
||||||
var _loop = function _loop() {
|
|
||||||
var _step8$value = _slicedToArray(_step8.value, 2),
|
|
||||||
tokenLineIndex = _step8$value[0],
|
|
||||||
tokenLine = _step8$value[1];
|
|
||||||
var inLine = [];
|
|
||||||
forEachLink(tokenLine, function (index, match) {
|
|
||||||
var markerMatch = null;
|
|
||||||
while (markerMatch = emphasisMarkersRe.exec(match)) {
|
|
||||||
inLine.push(index + markerMatch.index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
byLine[tokenLineIndex] = inLine;
|
|
||||||
};
|
|
||||||
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
||||||
_loop();
|
|
||||||
}
|
|
||||||
// Search code spans
|
|
||||||
} catch (err) {
|
|
||||||
_iterator8.e(err);
|
|
||||||
} finally {
|
|
||||||
_iterator8.f();
|
|
||||||
}
|
|
||||||
filterTokens(params, "inline", function (token) {
|
|
||||||
var children = token.children,
|
|
||||||
lineNumber = token.lineNumber,
|
|
||||||
map = token.map;
|
|
||||||
if (children.some(function (child) {
|
|
||||||
return child.type === "code_inline";
|
|
||||||
})) {
|
|
||||||
var tokenLines = lines.slice(map[0], map[1]);
|
|
||||||
forEachInlineCodeSpan(tokenLines.join("\n"), function (code, lineIndex, column, tickCount) {
|
|
||||||
var codeLines = code.split(newLineRe);
|
|
||||||
var _iterator9 = _createForOfIteratorHelper(codeLines.entries()),
|
|
||||||
_step9;
|
|
||||||
try {
|
|
||||||
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
|
||||||
var _step9$value = _slicedToArray(_step9.value, 2),
|
|
||||||
codeLineIndex = _step9$value[0],
|
|
||||||
codeLine = _step9$value[1];
|
|
||||||
var byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
|
||||||
var inLine = byLine[byLineIndex];
|
|
||||||
var codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
|
||||||
var match = null;
|
|
||||||
while (match = emphasisMarkersRe.exec(codeLine)) {
|
|
||||||
inLine.push(codeLineOffset + match.index);
|
|
||||||
}
|
|
||||||
byLine[byLineIndex] = inLine;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
_iterator9.e(err);
|
|
||||||
} finally {
|
|
||||||
_iterator9.f();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return byLine;
|
|
||||||
}
|
|
||||||
module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object with information about reference links and images.
|
* Returns an object with information about reference links and images.
|
||||||
*
|
*
|
||||||
|
|
@ -981,11 +756,11 @@ function getReferenceLinkImageData(params) {
|
||||||
"definitionLabelString", "gfmFootnoteDefinitionLabelString",
|
"definitionLabelString", "gfmFootnoteDefinitionLabelString",
|
||||||
// references and shortcuts
|
// references and shortcuts
|
||||||
"gfmFootnoteCall", "image", "link"]);
|
"gfmFootnoteCall", "image", "link"]);
|
||||||
var _iterator10 = _createForOfIteratorHelper(filteredTokens),
|
var _iterator7 = _createForOfIteratorHelper(filteredTokens),
|
||||||
_step10;
|
_step7;
|
||||||
try {
|
try {
|
||||||
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
||||||
var token = _step10.value;
|
var token = _step7.value;
|
||||||
var labelPrefix = "";
|
var labelPrefix = "";
|
||||||
// eslint-disable-next-line default-case
|
// eslint-disable-next-line default-case
|
||||||
switch (token.type) {
|
switch (token.type) {
|
||||||
|
|
@ -1052,9 +827,9 @@ function getReferenceLinkImageData(params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator10.e(err);
|
_iterator7.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator10.f();
|
_iterator7.f();
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
references: references,
|
references: references,
|
||||||
|
|
@ -1078,11 +853,11 @@ function getPreferredLineEnding(input, os) {
|
||||||
var lf = 0;
|
var lf = 0;
|
||||||
var crlf = 0;
|
var crlf = 0;
|
||||||
var endings = input.match(newLineRe) || [];
|
var endings = input.match(newLineRe) || [];
|
||||||
var _iterator11 = _createForOfIteratorHelper(endings),
|
var _iterator8 = _createForOfIteratorHelper(endings),
|
||||||
_step11;
|
_step8;
|
||||||
try {
|
try {
|
||||||
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
|
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
||||||
var ending = _step11.value;
|
var ending = _step8.value;
|
||||||
// eslint-disable-next-line default-case
|
// eslint-disable-next-line default-case
|
||||||
switch (ending) {
|
switch (ending) {
|
||||||
case "\r":
|
case "\r":
|
||||||
|
|
@ -1097,9 +872,9 @@ function getPreferredLineEnding(input, os) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator11.e(err);
|
_iterator8.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator11.f();
|
_iterator8.f();
|
||||||
}
|
}
|
||||||
var preferredLineEnding = null;
|
var preferredLineEnding = null;
|
||||||
if (!cr && !lf && !crlf) {
|
if (!cr && !lf && !crlf) {
|
||||||
|
|
@ -1182,11 +957,11 @@ function applyFixes(input, errors) {
|
||||||
lastFixInfo = {
|
lastFixInfo = {
|
||||||
"lineNumber": -1
|
"lineNumber": -1
|
||||||
};
|
};
|
||||||
var _iterator12 = _createForOfIteratorHelper(fixInfos),
|
var _iterator9 = _createForOfIteratorHelper(fixInfos),
|
||||||
_step12;
|
_step9;
|
||||||
try {
|
try {
|
||||||
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
|
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
||||||
var fixInfo = _step12.value;
|
var fixInfo = _step9.value;
|
||||||
if (fixInfo.lineNumber === lastFixInfo.lineNumber && fixInfo.editColumn === lastFixInfo.editColumn && !fixInfo.insertText && fixInfo.deleteCount > 0 && lastFixInfo.insertText && !lastFixInfo.deleteCount) {
|
if (fixInfo.lineNumber === lastFixInfo.lineNumber && fixInfo.editColumn === lastFixInfo.editColumn && !fixInfo.insertText && fixInfo.deleteCount > 0 && lastFixInfo.insertText && !lastFixInfo.deleteCount) {
|
||||||
fixInfo.insertText = lastFixInfo.insertText;
|
fixInfo.insertText = lastFixInfo.insertText;
|
||||||
lastFixInfo.lineNumber = 0;
|
lastFixInfo.lineNumber = 0;
|
||||||
|
|
@ -1194,9 +969,9 @@ function applyFixes(input, errors) {
|
||||||
lastFixInfo = fixInfo;
|
lastFixInfo = fixInfo;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator12.e(err);
|
_iterator9.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator12.f();
|
_iterator9.f();
|
||||||
}
|
}
|
||||||
fixInfos = fixInfos.filter(function (fixInfo) {
|
fixInfos = fixInfos.filter(function (fixInfo) {
|
||||||
return fixInfo.lineNumber;
|
return fixInfo.lineNumber;
|
||||||
|
|
@ -1204,11 +979,11 @@ function applyFixes(input, errors) {
|
||||||
// Apply all (remaining/updated) fixes
|
// Apply all (remaining/updated) fixes
|
||||||
var lastLineIndex = -1;
|
var lastLineIndex = -1;
|
||||||
var lastEditIndex = -1;
|
var lastEditIndex = -1;
|
||||||
var _iterator13 = _createForOfIteratorHelper(fixInfos),
|
var _iterator10 = _createForOfIteratorHelper(fixInfos),
|
||||||
_step13;
|
_step10;
|
||||||
try {
|
try {
|
||||||
for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
|
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
||||||
var _fixInfo = _step13.value;
|
var _fixInfo = _step10.value;
|
||||||
var lineNumber = _fixInfo.lineNumber,
|
var lineNumber = _fixInfo.lineNumber,
|
||||||
editColumn = _fixInfo.editColumn,
|
editColumn = _fixInfo.editColumn,
|
||||||
deleteCount = _fixInfo.deleteCount;
|
deleteCount = _fixInfo.deleteCount;
|
||||||
|
|
@ -1223,9 +998,9 @@ function applyFixes(input, errors) {
|
||||||
}
|
}
|
||||||
// Return corrected input
|
// Return corrected input
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_iterator13.e(err);
|
_iterator10.e(err);
|
||||||
} finally {
|
} finally {
|
||||||
_iterator13.f();
|
_iterator10.f();
|
||||||
}
|
}
|
||||||
return lines.filter(function (line) {
|
return lines.filter(function (line) {
|
||||||
return line !== null;
|
return line !== null;
|
||||||
|
|
@ -1710,9 +1485,6 @@ module.exports.codeBlockAndSpanRanges = function () {
|
||||||
module.exports.flattenedLists = function () {
|
module.exports.flattenedLists = function () {
|
||||||
return map.get("flattenedLists");
|
return map.get("flattenedLists");
|
||||||
};
|
};
|
||||||
module.exports.htmlElementRanges = function () {
|
|
||||||
return map.get("htmlElementRanges");
|
|
||||||
};
|
|
||||||
module.exports.lineMetadata = function () {
|
module.exports.lineMetadata = function () {
|
||||||
return map.get("lineMetadata");
|
return map.get("lineMetadata");
|
||||||
};
|
};
|
||||||
|
|
@ -2477,12 +2249,10 @@ function lintContent(ruleList, aliasToRuleNames, name, content, md, config, conf
|
||||||
var lineMetadata = helpers.getLineMetadata(paramsBase);
|
var lineMetadata = helpers.getLineMetadata(paramsBase);
|
||||||
var codeBlockAndSpanRanges = helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
var codeBlockAndSpanRanges = helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
||||||
var flattenedLists = helpers.flattenLists(paramsBase.parsers.markdownit.tokens);
|
var flattenedLists = helpers.flattenLists(paramsBase.parsers.markdownit.tokens);
|
||||||
var htmlElementRanges = helpers.htmlElementRanges(paramsBase, lineMetadata);
|
|
||||||
var referenceLinkImageData = helpers.getReferenceLinkImageData(paramsBase);
|
var referenceLinkImageData = helpers.getReferenceLinkImageData(paramsBase);
|
||||||
cache.set({
|
cache.set({
|
||||||
codeBlockAndSpanRanges: codeBlockAndSpanRanges,
|
codeBlockAndSpanRanges: codeBlockAndSpanRanges,
|
||||||
flattenedLists: flattenedLists,
|
flattenedLists: flattenedLists,
|
||||||
htmlElementRanges: htmlElementRanges,
|
|
||||||
lineMetadata: lineMetadata,
|
lineMetadata: lineMetadata,
|
||||||
referenceLinkImageData: referenceLinkImageData
|
referenceLinkImageData: referenceLinkImageData
|
||||||
});
|
});
|
||||||
|
|
@ -5346,6 +5116,11 @@ module.exports = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
||||||
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||||
|
function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
|
||||||
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||||||
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
||||||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
||||||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||||||
|
|
@ -5353,154 +5128,113 @@ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symb
|
||||||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
||||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||||||
var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
|
var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
|
||||||
addErrorContext = _require.addErrorContext,
|
addError = _require.addError;
|
||||||
emphasisMarkersInContent = _require.emphasisMarkersInContent,
|
var emphasisStartTextRe = /^(\S{1,3})(\s+)\S/;
|
||||||
forEachLine = _require.forEachLine,
|
var emphasisEndTextRe = /\S(\s+)(\S{1,3})$/;
|
||||||
isBlankLine = _require.isBlankLine,
|
|
||||||
withinAnyRange = _require.withinAnyRange;
|
|
||||||
var _require2 = __webpack_require__(/*! ./cache */ "../lib/cache.js"),
|
|
||||||
htmlElementRanges = _require2.htmlElementRanges,
|
|
||||||
lineMetadata = _require2.lineMetadata;
|
|
||||||
var emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
|
|
||||||
var embeddedUnderscoreRe = /([A-Za-z\d])(_([A-Za-z\d]))+/g;
|
|
||||||
var asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
||||||
var leftSpaceRe = /^\s+/;
|
|
||||||
var rightSpaceRe = /\s+$/;
|
|
||||||
var tablePipeRe = /\|/;
|
|
||||||
var allUnderscoresRe = /_/g;
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": ["MD037", "no-space-in-emphasis"],
|
"names": ["MD037", "no-space-in-emphasis"],
|
||||||
"description": "Spaces inside emphasis markers",
|
"description": "Spaces inside emphasis markers",
|
||||||
"tags": ["whitespace", "emphasis"],
|
"tags": ["whitespace", "emphasis"],
|
||||||
"function": function MD037(params, onError) {
|
"function": function MD037(params, onError) {
|
||||||
var exclusions = htmlElementRanges();
|
// Initialize variables
|
||||||
// eslint-disable-next-line init-declarations
|
var lines = params.lines,
|
||||||
var effectiveEmphasisLength,
|
parsers = params.parsers;
|
||||||
emphasisIndex,
|
var emphasisTokensByMarker = new Map();
|
||||||
emphasisKind,
|
for (var _i = 0, _arr = ["_", "__", "___", "*", "**", "***"]; _i < _arr.length; _i++) {
|
||||||
emphasisLength,
|
var marker = _arr[_i];
|
||||||
pendingError = null;
|
emphasisTokensByMarker.set(marker, []);
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
||||||
function resetRunTracking() {
|
|
||||||
emphasisIndex = -1;
|
|
||||||
emphasisLength = 0;
|
|
||||||
emphasisKind = "";
|
|
||||||
effectiveEmphasisLength = 0;
|
|
||||||
pendingError = null;
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
var pending = _toConsumableArray(parsers.micromark.tokens);
|
||||||
function handleRunEnd(line, lineIndex, contextLength, match, matchIndex, inTable) {
|
var token = null;
|
||||||
// Close current run
|
while (token = pending.shift()) {
|
||||||
var content = line.substring(emphasisIndex, matchIndex);
|
// Use reparsed children of htmlFlow tokens
|
||||||
if (!emphasisLength) {
|
if (token.type === "htmlFlow") {
|
||||||
content = content.trimStart();
|
pending.unshift.apply(pending, _toConsumableArray(token.htmlFlowChildren));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!match) {
|
pending.push.apply(pending, _toConsumableArray(token.children));
|
||||||
content = content.trimEnd();
|
|
||||||
}
|
// Build lists of bare tokens for each emphasis marker type
|
||||||
var leftSpace = leftSpaceRe.test(content);
|
var _iterator = _createForOfIteratorHelper(emphasisTokensByMarker.values()),
|
||||||
var rightSpace = rightSpaceRe.test(content);
|
_step;
|
||||||
if ((leftSpace || rightSpace) && (!inTable || !tablePipeRe.test(content))) {
|
try {
|
||||||
// Report the violation
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
||||||
var contextStart = emphasisIndex - emphasisLength;
|
var emphasisTokens = _step.value;
|
||||||
var contextEnd = matchIndex + contextLength;
|
emphasisTokens.length = 0;
|
||||||
var column = contextStart + 1;
|
|
||||||
var length = contextEnd - contextStart;
|
|
||||||
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
|
|
||||||
var context = line.substring(contextStart, contextEnd);
|
|
||||||
var leftMarker = line.substring(contextStart, emphasisIndex);
|
|
||||||
var rightMarker = match ? match[2] || match[3] : "";
|
|
||||||
var fixedText = "".concat(leftMarker).concat(content.trim()).concat(rightMarker);
|
|
||||||
return [onError, lineIndex + 1, context, leftSpace, rightSpace, [column, length], {
|
|
||||||
"editColumn": column,
|
|
||||||
"deleteCount": length,
|
|
||||||
"insertText": fixedText
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_iterator.e(err);
|
||||||
|
} finally {
|
||||||
|
_iterator.f();
|
||||||
|
}
|
||||||
|
var _iterator2 = _createForOfIteratorHelper(token.children),
|
||||||
|
_step2;
|
||||||
|
try {
|
||||||
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
||||||
|
var child = _step2.value;
|
||||||
|
var text = child.text,
|
||||||
|
type = child.type;
|
||||||
|
if (type === "data" && text.length <= 3) {
|
||||||
|
var _emphasisTokens = emphasisTokensByMarker.get(text);
|
||||||
|
if (_emphasisTokens) {
|
||||||
|
_emphasisTokens.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process bare tokens for each emphasis marker type
|
||||||
|
} catch (err) {
|
||||||
|
_iterator2.e(err);
|
||||||
|
} finally {
|
||||||
|
_iterator2.f();
|
||||||
|
}
|
||||||
|
var _iterator3 = _createForOfIteratorHelper(emphasisTokensByMarker.values()),
|
||||||
|
_step3;
|
||||||
|
try {
|
||||||
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
||||||
|
var _emphasisTokens2 = _step3.value;
|
||||||
|
for (var i = 0; i + 1 < _emphasisTokens2.length; i += 2) {
|
||||||
|
// Process start token of start/end pair
|
||||||
|
var startToken = _emphasisTokens2[i];
|
||||||
|
var startText = lines[startToken.startLine - 1].slice(startToken.startColumn - 1);
|
||||||
|
var startMatch = startText.match(emphasisStartTextRe);
|
||||||
|
if (startMatch) {
|
||||||
|
var _startMatch = _slicedToArray(startMatch, 3),
|
||||||
|
startContext = _startMatch[0],
|
||||||
|
startMarker = _startMatch[1],
|
||||||
|
startSpaces = _startMatch[2];
|
||||||
|
if (startMarker === startToken.text && startSpaces.length > 0) {
|
||||||
|
addError(onError, startToken.startLine, undefined, startContext, [startToken.startColumn, startContext.length], {
|
||||||
|
"editColumn": startToken.endColumn,
|
||||||
|
"deleteCount": startSpaces.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process end token of start/end pair
|
||||||
|
var endToken = _emphasisTokens2[i + 1];
|
||||||
|
var endText = lines[endToken.startLine - 1].slice(0, endToken.endColumn - 1);
|
||||||
|
var endMatch = endText.match(emphasisEndTextRe);
|
||||||
|
if (endMatch) {
|
||||||
|
var _endMatch = _slicedToArray(endMatch, 3),
|
||||||
|
endContext = _endMatch[0],
|
||||||
|
endSpace = _endMatch[1],
|
||||||
|
endMarker = _endMatch[2];
|
||||||
|
if (endMarker === endToken.text && endSpace.length > 0) {
|
||||||
|
addError(onError, endToken.startLine, undefined, endContext, [endToken.endColumn - endContext.length, endContext.length], {
|
||||||
|
"editColumn": endToken.startColumn - endSpace.length,
|
||||||
|
"deleteCount": endSpace.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_iterator3.e(err);
|
||||||
|
} finally {
|
||||||
|
_iterator3.f();
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
// Initialize
|
|
||||||
var ignoreMarkersByLine = emphasisMarkersInContent(params);
|
|
||||||
resetRunTracking();
|
|
||||||
forEachLine(lineMetadata(), function (line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) {
|
|
||||||
var onItemStart = inItem === 1;
|
|
||||||
if (inCode || onFence || inTable || onBreak || onItemStart || isBlankLine(line)) {
|
|
||||||
// Emphasis resets when leaving a block
|
|
||||||
resetRunTracking();
|
|
||||||
}
|
|
||||||
if (inCode || onFence || onBreak || inMath) {
|
|
||||||
// Emphasis has no meaning here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var patchedLine = line.replace(embeddedUnderscoreRe, function (match) {
|
|
||||||
return match.replace(allUnderscoresRe, " ");
|
|
||||||
});
|
|
||||||
if (onItemStart) {
|
|
||||||
// Trim overlapping '*' list item marker
|
|
||||||
patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
||||||
}
|
|
||||||
var match = null;
|
|
||||||
// Match all emphasis-looking runs in the line...
|
|
||||||
while (match = emphasisRe.exec(patchedLine)) {
|
|
||||||
var ignoreMarkersForLine = ignoreMarkersByLine[lineIndex];
|
|
||||||
var matchIndex = match.index + match[1].length;
|
|
||||||
if (ignoreMarkersForLine.includes(matchIndex)) {
|
|
||||||
// Ignore emphasis markers inside code spans and links
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var matchLength = match[0].length - match[1].length;
|
|
||||||
var matchKind = (match[2] || match[3])[0];
|
|
||||||
if (emphasisIndex === -1) {
|
|
||||||
// New run
|
|
||||||
emphasisIndex = matchIndex + matchLength;
|
|
||||||
emphasisLength = matchLength;
|
|
||||||
emphasisKind = matchKind;
|
|
||||||
effectiveEmphasisLength = matchLength;
|
|
||||||
} else if (matchKind === emphasisKind) {
|
|
||||||
// Matching emphasis markers
|
|
||||||
if (matchLength === effectiveEmphasisLength) {
|
|
||||||
// Ending an existing run, report any pending error
|
|
||||||
if (pendingError) {
|
|
||||||
// @ts-ignore
|
|
||||||
addErrorContext.apply(void 0, _toConsumableArray(pendingError));
|
|
||||||
pendingError = null;
|
|
||||||
}
|
|
||||||
var error = handleRunEnd(line, lineIndex, effectiveEmphasisLength, match, matchIndex, inTable);
|
|
||||||
if (error) {
|
|
||||||
// @ts-ignore
|
|
||||||
addErrorContext.apply(void 0, _toConsumableArray(error));
|
|
||||||
}
|
|
||||||
// Reset
|
|
||||||
resetRunTracking();
|
|
||||||
} else if (matchLength === 3) {
|
|
||||||
// Swap internal run length (1->2 or 2->1)
|
|
||||||
effectiveEmphasisLength = matchLength - effectiveEmphasisLength;
|
|
||||||
} else if (effectiveEmphasisLength === 3) {
|
|
||||||
// Downgrade internal run (3->1 or 3->2)
|
|
||||||
effectiveEmphasisLength -= matchLength;
|
|
||||||
} else {
|
|
||||||
// Upgrade to internal run (1->3 or 2->3)
|
|
||||||
effectiveEmphasisLength += matchLength;
|
|
||||||
}
|
|
||||||
// Back up one character so RegExp has a chance to match the
|
|
||||||
// next marker (ex: "**star**_underscore_")
|
|
||||||
if (emphasisRe.lastIndex > 1) {
|
|
||||||
emphasisRe.lastIndex--;
|
|
||||||
}
|
|
||||||
} else if (emphasisRe.lastIndex > 1) {
|
|
||||||
// Back up one character so RegExp has a chance to match the
|
|
||||||
// mis-matched marker (ex: "*text_*")
|
|
||||||
emphasisRe.lastIndex--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (emphasisIndex !== -1) {
|
|
||||||
pendingError = pendingError || handleRunEnd(line, lineIndex, 0, null, line.length, inTable);
|
|
||||||
// Adjust for pending run on new line
|
|
||||||
emphasisIndex = 0;
|
|
||||||
emphasisLength = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const micromark = require("./micromark.cjs");
|
const micromark = require("./micromark.cjs");
|
||||||
const { newLineRe } = require("./shared.js");
|
|
||||||
|
|
||||||
// Regular expression for matching common newline characters
|
const { newLineRe } = require("./shared.js");
|
||||||
// See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js
|
|
||||||
module.exports.newLineRe = newLineRe;
|
module.exports.newLineRe = newLineRe;
|
||||||
|
|
||||||
// Regular expression for matching common front matter (YAML and TOML)
|
// Regular expression for matching common front matter (YAML and TOML)
|
||||||
|
|
@ -28,9 +26,6 @@ module.exports.htmlElementRe = htmlElementRe;
|
||||||
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
||||||
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
||||||
|
|
||||||
// Regular expression for all instances of emphasis markers
|
|
||||||
const emphasisMarkersRe = /[_*]/g;
|
|
||||||
|
|
||||||
// Regular expression for blockquote prefixes
|
// Regular expression for blockquote prefixes
|
||||||
const blockquotePrefixRe = /^[>\s]*/;
|
const blockquotePrefixRe = /^[>\s]*/;
|
||||||
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
||||||
|
|
@ -348,25 +343,10 @@ function filterTokens(params, type, handler) {
|
||||||
}
|
}
|
||||||
module.exports.filterTokens = filterTokens;
|
module.exports.filterTokens = filterTokens;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a token is a math block (created by markdown-it-texmath).
|
|
||||||
*
|
|
||||||
* @param {Object} token MarkdownItToken instance.
|
|
||||||
* @returns {boolean} True iff token is a math block.
|
|
||||||
*/
|
|
||||||
function isMathBlock(token) {
|
|
||||||
return (
|
|
||||||
((token.tag === "$$") || (token.tag === "math")) &&
|
|
||||||
token.type.startsWith("math_block") &&
|
|
||||||
!token.type.endsWith("_end")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
module.exports.isMathBlock = isMathBlock;
|
|
||||||
|
|
||||||
// Get line metadata array
|
// Get line metadata array
|
||||||
module.exports.getLineMetadata = function getLineMetadata(params) {
|
module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
const lineMetadata = params.lines.map(
|
const lineMetadata = params.lines.map(
|
||||||
(line, index) => [ line, index, false, 0, false, false, false, false ]
|
(line, index) => [ line, index, false, 0, false, false, false ]
|
||||||
);
|
);
|
||||||
filterTokens(params, "fence", (token) => {
|
filterTokens(params, "fence", (token) => {
|
||||||
lineMetadata[token.map[0]][3] = 1;
|
lineMetadata[token.map[0]][3] = 1;
|
||||||
|
|
@ -395,11 +375,6 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
filterTokens(params, "hr", (token) => {
|
filterTokens(params, "hr", (token) => {
|
||||||
lineMetadata[token.map[0]][6] = true;
|
lineMetadata[token.map[0]][6] = true;
|
||||||
});
|
});
|
||||||
for (const token of params.parsers.markdownit.tokens.filter(isMathBlock)) {
|
|
||||||
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
||||||
lineMetadata[i][7] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lineMetadata;
|
return lineMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -408,7 +383,7 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
*
|
*
|
||||||
* @param {Object} lineMetadata Line metadata object.
|
* @param {Object} lineMetadata Line metadata object.
|
||||||
* @param {Function} handler Function taking (line, lineIndex, inCode, onFence,
|
* @param {Function} handler Function taking (line, lineIndex, inCode, onFence,
|
||||||
* inTable, inItem, inBreak, inMath).
|
* inTable, inItem, inBreak).
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachLine(lineMetadata, handler) {
|
function forEachLine(lineMetadata, handler) {
|
||||||
|
|
@ -655,51 +630,6 @@ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
|
||||||
return exclusions;
|
return exclusions;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of HTML element ranges.
|
|
||||||
*
|
|
||||||
* @param {Object} params RuleParams instance.
|
|
||||||
* @param {Object} lineMetadata Line metadata object.
|
|
||||||
* @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
|
|
||||||
*/
|
|
||||||
module.exports.htmlElementRanges = (params, lineMetadata) => {
|
|
||||||
const exclusions = [];
|
|
||||||
// Match with htmlElementRe
|
|
||||||
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
||||||
let match = null;
|
|
||||||
// eslint-disable-next-line no-unmodified-loop-condition
|
|
||||||
while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) {
|
|
||||||
exclusions.push([ lineIndex, match.index, match[0].length ]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Match with html_inline
|
|
||||||
forEachInlineChild(params, "html_inline", (token, parent) => {
|
|
||||||
const parentContent = parent.content;
|
|
||||||
let tokenContent = token.content;
|
|
||||||
const parentIndex = parentContent.indexOf(tokenContent);
|
|
||||||
let deltaLines = 0;
|
|
||||||
let indent = 0;
|
|
||||||
for (let i = parentIndex - 1; i >= 0; i--) {
|
|
||||||
if (parentContent[i] === "\n") {
|
|
||||||
deltaLines++;
|
|
||||||
} else if (deltaLines === 0) {
|
|
||||||
indent++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let lineIndex = token.lineNumber - 1 + deltaLines;
|
|
||||||
do {
|
|
||||||
const index = tokenContent.indexOf("\n");
|
|
||||||
const length = (index === -1) ? tokenContent.length : index;
|
|
||||||
exclusions.push([ lineIndex, indent, length ]);
|
|
||||||
tokenContent = tokenContent.slice(length + 1);
|
|
||||||
lineIndex++;
|
|
||||||
indent = 0;
|
|
||||||
} while (tokenContent.length > 0);
|
|
||||||
});
|
|
||||||
// Return results
|
|
||||||
return exclusions;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the specified range is within another range.
|
* Determines whether the specified range is within another range.
|
||||||
*
|
*
|
||||||
|
|
@ -744,129 +674,6 @@ module.exports.frontMatterHasTitle =
|
||||||
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the provided function for each link.
|
|
||||||
*
|
|
||||||
* @param {string} line Line of Markdown input.
|
|
||||||
* @param {Function} handler Function taking (index, link, text, destination).
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function forEachLink(line, handler) {
|
|
||||||
// Helper to find matching close symbol for link text/destination
|
|
||||||
const findClosingSymbol = (index) => {
|
|
||||||
const begin = line[index];
|
|
||||||
const end = (begin === "[") ? "]" : ")";
|
|
||||||
let nesting = 0;
|
|
||||||
let escaping = false;
|
|
||||||
let pointy = false;
|
|
||||||
for (let i = index + 1; i < line.length; i++) {
|
|
||||||
const current = line[i];
|
|
||||||
if (current === "\\") {
|
|
||||||
escaping = !escaping;
|
|
||||||
} else if (!escaping && (current === begin)) {
|
|
||||||
nesting++;
|
|
||||||
} else if (!escaping && (current === end)) {
|
|
||||||
if (nesting > 0) {
|
|
||||||
nesting--;
|
|
||||||
} else if (!pointy) {
|
|
||||||
// Return index after matching close symbol
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
} else if ((i === index + 1) && (begin === "(") && (current === "<")) {
|
|
||||||
pointy = true;
|
|
||||||
} else if (!escaping && pointy && current === ">") {
|
|
||||||
pointy = false;
|
|
||||||
nesting = 0;
|
|
||||||
} else {
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No match found
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
// Scan line for unescaped "[" character
|
|
||||||
let escaping = false;
|
|
||||||
for (let i = 0; i < line.length; i++) {
|
|
||||||
const current = line[i];
|
|
||||||
if (current === "\\") {
|
|
||||||
escaping = !escaping;
|
|
||||||
} else if (!escaping && (current === "[")) {
|
|
||||||
// Scan for matching close "]" of link text
|
|
||||||
const textEnd = findClosingSymbol(i);
|
|
||||||
if (textEnd !== -1) {
|
|
||||||
if ((line[textEnd] === "(") || (line[textEnd] === "[")) {
|
|
||||||
// Scan for matching close ")" or "]" of link destination
|
|
||||||
const destEnd = findClosingSymbol(textEnd);
|
|
||||||
if (destEnd !== -1) {
|
|
||||||
// Call handler with link text and destination
|
|
||||||
const link = line.slice(i, destEnd);
|
|
||||||
const text = line.slice(i, textEnd);
|
|
||||||
const dest = line.slice(textEnd, destEnd);
|
|
||||||
handler(i, link, text, dest);
|
|
||||||
i = destEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i < textEnd) {
|
|
||||||
// Call handler with link text only
|
|
||||||
const text = line.slice(i, textEnd);
|
|
||||||
handler(i, text, text);
|
|
||||||
i = textEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports.forEachLink = forEachLink;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of emphasis markers in code spans and links.
|
|
||||||
*
|
|
||||||
* @param {Object} params RuleParams instance.
|
|
||||||
* @returns {number[][]} List of markers.
|
|
||||||
*/
|
|
||||||
function emphasisMarkersInContent(params) {
|
|
||||||
const { lines } = params;
|
|
||||||
const byLine = new Array(lines.length);
|
|
||||||
// Search links
|
|
||||||
for (const [ tokenLineIndex, tokenLine ] of lines.entries()) {
|
|
||||||
const inLine = [];
|
|
||||||
forEachLink(tokenLine, (index, match) => {
|
|
||||||
let markerMatch = null;
|
|
||||||
while ((markerMatch = emphasisMarkersRe.exec(match))) {
|
|
||||||
inLine.push(index + markerMatch.index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
byLine[tokenLineIndex] = inLine;
|
|
||||||
}
|
|
||||||
// Search code spans
|
|
||||||
filterTokens(params, "inline", (token) => {
|
|
||||||
const { children, lineNumber, map } = token;
|
|
||||||
if (children.some((child) => child.type === "code_inline")) {
|
|
||||||
const tokenLines = lines.slice(map[0], map[1]);
|
|
||||||
forEachInlineCodeSpan(
|
|
||||||
tokenLines.join("\n"),
|
|
||||||
(code, lineIndex, column, tickCount) => {
|
|
||||||
const codeLines = code.split(newLineRe);
|
|
||||||
for (const [ codeLineIndex, codeLine ] of codeLines.entries()) {
|
|
||||||
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
|
||||||
const inLine = byLine[byLineIndex];
|
|
||||||
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
|
||||||
let match = null;
|
|
||||||
while ((match = emphasisMarkersRe.exec(codeLine))) {
|
|
||||||
inLine.push(codeLineOffset + match.index);
|
|
||||||
}
|
|
||||||
byLine[byLineIndex] = inLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return byLine;
|
|
||||||
}
|
|
||||||
module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object with information about reference links and images.
|
* Returns an object with information about reference links and images.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ module.exports.codeBlockAndSpanRanges =
|
||||||
() => map.get("codeBlockAndSpanRanges");
|
() => map.get("codeBlockAndSpanRanges");
|
||||||
module.exports.flattenedLists =
|
module.exports.flattenedLists =
|
||||||
() => map.get("flattenedLists");
|
() => map.get("flattenedLists");
|
||||||
module.exports.htmlElementRanges =
|
|
||||||
() => map.get("htmlElementRanges");
|
|
||||||
module.exports.lineMetadata =
|
module.exports.lineMetadata =
|
||||||
() => map.get("lineMetadata");
|
() => map.get("lineMetadata");
|
||||||
module.exports.referenceLinkImageData =
|
module.exports.referenceLinkImageData =
|
||||||
|
|
|
||||||
|
|
@ -583,14 +583,11 @@ function lintContent(
|
||||||
helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
||||||
const flattenedLists =
|
const flattenedLists =
|
||||||
helpers.flattenLists(paramsBase.parsers.markdownit.tokens);
|
helpers.flattenLists(paramsBase.parsers.markdownit.tokens);
|
||||||
const htmlElementRanges =
|
|
||||||
helpers.htmlElementRanges(paramsBase, lineMetadata);
|
|
||||||
const referenceLinkImageData =
|
const referenceLinkImageData =
|
||||||
helpers.getReferenceLinkImageData(paramsBase);
|
helpers.getReferenceLinkImageData(paramsBase);
|
||||||
cache.set({
|
cache.set({
|
||||||
codeBlockAndSpanRanges,
|
codeBlockAndSpanRanges,
|
||||||
flattenedLists,
|
flattenedLists,
|
||||||
htmlElementRanges,
|
|
||||||
lineMetadata,
|
lineMetadata,
|
||||||
referenceLinkImageData
|
referenceLinkImageData
|
||||||
});
|
});
|
||||||
|
|
|
||||||
237
lib/md037.js
237
lib/md037.js
|
|
@ -2,184 +2,97 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine,
|
const { addError } = require("../helpers");
|
||||||
withinAnyRange } = require("../helpers");
|
|
||||||
const { htmlElementRanges, lineMetadata } = require("./cache");
|
|
||||||
|
|
||||||
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
|
const emphasisStartTextRe = /^(\S{1,3})(\s+)\S/;
|
||||||
const embeddedUnderscoreRe = /([A-Za-z\d])(_([A-Za-z\d]))+/g;
|
const emphasisEndTextRe = /\S(\s+)(\S{1,3})$/;
|
||||||
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
||||||
const leftSpaceRe = /^\s+/;
|
|
||||||
const rightSpaceRe = /\s+$/;
|
|
||||||
const tablePipeRe = /\|/;
|
|
||||||
const allUnderscoresRe = /_/g;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD037", "no-space-in-emphasis" ],
|
"names": [ "MD037", "no-space-in-emphasis" ],
|
||||||
"description": "Spaces inside emphasis markers",
|
"description": "Spaces inside emphasis markers",
|
||||||
"tags": [ "whitespace", "emphasis" ],
|
"tags": [ "whitespace", "emphasis" ],
|
||||||
"function": function MD037(params, onError) {
|
"function": function MD037(params, onError) {
|
||||||
const exclusions = htmlElementRanges();
|
|
||||||
// eslint-disable-next-line init-declarations
|
// Initialize variables
|
||||||
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
|
const { lines, parsers } = params;
|
||||||
pendingError = null;
|
const emphasisTokensByMarker = new Map();
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
for (const marker of [ "_", "__", "___", "*", "**", "***" ]) {
|
||||||
function resetRunTracking() {
|
emphasisTokensByMarker.set(marker, []);
|
||||||
emphasisIndex = -1;
|
|
||||||
emphasisLength = 0;
|
|
||||||
emphasisKind = "";
|
|
||||||
effectiveEmphasisLength = 0;
|
|
||||||
pendingError = null;
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
const pending = [ ...parsers.micromark.tokens ];
|
||||||
function handleRunEnd(
|
let token = null;
|
||||||
line, lineIndex, contextLength, match, matchIndex, inTable
|
while ((token = pending.shift())) {
|
||||||
) {
|
|
||||||
// Close current run
|
// Use reparsed children of htmlFlow tokens
|
||||||
let content = line.substring(emphasisIndex, matchIndex);
|
if (token.type === "htmlFlow") {
|
||||||
if (!emphasisLength) {
|
pending.unshift(...token.htmlFlowChildren);
|
||||||
content = content.trimStart();
|
continue;
|
||||||
}
|
}
|
||||||
if (!match) {
|
pending.push(...token.children);
|
||||||
content = content.trimEnd();
|
|
||||||
|
// Build lists of bare tokens for each emphasis marker type
|
||||||
|
for (const emphasisTokens of emphasisTokensByMarker.values()) {
|
||||||
|
emphasisTokens.length = 0;
|
||||||
}
|
}
|
||||||
const leftSpace = leftSpaceRe.test(content);
|
for (const child of token.children) {
|
||||||
const rightSpace = rightSpaceRe.test(content);
|
const { text, type } = child;
|
||||||
if (
|
if ((type === "data") && (text.length <= 3)) {
|
||||||
(leftSpace || rightSpace) &&
|
const emphasisTokens = emphasisTokensByMarker.get(text);
|
||||||
(!inTable || !tablePipeRe.test(content))
|
if (emphasisTokens) {
|
||||||
) {
|
emphasisTokens.push(child);
|
||||||
// Report the violation
|
|
||||||
const contextStart = emphasisIndex - emphasisLength;
|
|
||||||
const contextEnd = matchIndex + contextLength;
|
|
||||||
const column = contextStart + 1;
|
|
||||||
const length = contextEnd - contextStart;
|
|
||||||
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
|
|
||||||
const context = line.substring(contextStart, contextEnd);
|
|
||||||
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
||||||
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
||||||
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
||||||
return [
|
|
||||||
onError,
|
|
||||||
lineIndex + 1,
|
|
||||||
context,
|
|
||||||
leftSpace,
|
|
||||||
rightSpace,
|
|
||||||
[ column, length ],
|
|
||||||
{
|
|
||||||
"editColumn": column,
|
|
||||||
"deleteCount": length,
|
|
||||||
"insertText": fixedText
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Initialize
|
|
||||||
const ignoreMarkersByLine = emphasisMarkersInContent(params);
|
|
||||||
resetRunTracking();
|
|
||||||
forEachLine(
|
|
||||||
lineMetadata(),
|
|
||||||
(line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) => {
|
|
||||||
const onItemStart = (inItem === 1);
|
|
||||||
if (
|
|
||||||
inCode ||
|
|
||||||
onFence ||
|
|
||||||
inTable ||
|
|
||||||
onBreak ||
|
|
||||||
onItemStart ||
|
|
||||||
isBlankLine(line)
|
|
||||||
) {
|
|
||||||
// Emphasis resets when leaving a block
|
|
||||||
resetRunTracking();
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
inCode ||
|
|
||||||
onFence ||
|
|
||||||
onBreak ||
|
|
||||||
inMath
|
|
||||||
) {
|
|
||||||
// Emphasis has no meaning here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let patchedLine = line.replace(
|
|
||||||
embeddedUnderscoreRe,
|
|
||||||
(match) => match.replace(allUnderscoresRe, " ")
|
|
||||||
);
|
|
||||||
if (onItemStart) {
|
|
||||||
// Trim overlapping '*' list item marker
|
|
||||||
patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
||||||
}
|
|
||||||
let match = null;
|
|
||||||
// Match all emphasis-looking runs in the line...
|
|
||||||
while ((match = emphasisRe.exec(patchedLine))) {
|
|
||||||
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex];
|
|
||||||
const matchIndex = match.index + match[1].length;
|
|
||||||
if (ignoreMarkersForLine.includes(matchIndex)) {
|
|
||||||
// Ignore emphasis markers inside code spans and links
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const matchLength = match[0].length - match[1].length;
|
}
|
||||||
const matchKind = (match[2] || match[3])[0];
|
}
|
||||||
if (emphasisIndex === -1) {
|
|
||||||
// New run
|
// Process bare tokens for each emphasis marker type
|
||||||
emphasisIndex = matchIndex + matchLength;
|
for (const emphasisTokens of emphasisTokensByMarker.values()) {
|
||||||
emphasisLength = matchLength;
|
for (let i = 0; i + 1 < emphasisTokens.length; i += 2) {
|
||||||
emphasisKind = matchKind;
|
|
||||||
effectiveEmphasisLength = matchLength;
|
// Process start token of start/end pair
|
||||||
} else if (matchKind === emphasisKind) {
|
const startToken = emphasisTokens[i];
|
||||||
// Matching emphasis markers
|
const startText =
|
||||||
if (matchLength === effectiveEmphasisLength) {
|
lines[startToken.startLine - 1].slice(startToken.startColumn - 1);
|
||||||
// Ending an existing run, report any pending error
|
const startMatch = startText.match(emphasisStartTextRe);
|
||||||
if (pendingError) {
|
if (startMatch) {
|
||||||
// @ts-ignore
|
const [ startContext, startMarker, startSpaces ] = startMatch;
|
||||||
addErrorContext(...pendingError);
|
if ((startMarker === startToken.text) && (startSpaces.length > 0)) {
|
||||||
pendingError = null;
|
addError(
|
||||||
}
|
onError,
|
||||||
const error = handleRunEnd(
|
startToken.startLine,
|
||||||
line,
|
undefined,
|
||||||
lineIndex,
|
startContext,
|
||||||
effectiveEmphasisLength,
|
[ startToken.startColumn, startContext.length ],
|
||||||
match,
|
{
|
||||||
matchIndex,
|
"editColumn": startToken.endColumn,
|
||||||
inTable
|
"deleteCount": startSpaces.length
|
||||||
|
}
|
||||||
);
|
);
|
||||||
if (error) {
|
|
||||||
// @ts-ignore
|
|
||||||
addErrorContext(...error);
|
|
||||||
}
|
|
||||||
// Reset
|
|
||||||
resetRunTracking();
|
|
||||||
} else if (matchLength === 3) {
|
|
||||||
// Swap internal run length (1->2 or 2->1)
|
|
||||||
effectiveEmphasisLength = matchLength - effectiveEmphasisLength;
|
|
||||||
} else if (effectiveEmphasisLength === 3) {
|
|
||||||
// Downgrade internal run (3->1 or 3->2)
|
|
||||||
effectiveEmphasisLength -= matchLength;
|
|
||||||
} else {
|
|
||||||
// Upgrade to internal run (1->3 or 2->3)
|
|
||||||
effectiveEmphasisLength += matchLength;
|
|
||||||
}
|
}
|
||||||
// Back up one character so RegExp has a chance to match the
|
}
|
||||||
// next marker (ex: "**star**_underscore_")
|
|
||||||
if (emphasisRe.lastIndex > 1) {
|
// Process end token of start/end pair
|
||||||
emphasisRe.lastIndex--;
|
const endToken = emphasisTokens[i + 1];
|
||||||
|
const endText =
|
||||||
|
lines[endToken.startLine - 1].slice(0, endToken.endColumn - 1);
|
||||||
|
const endMatch = endText.match(emphasisEndTextRe);
|
||||||
|
if (endMatch) {
|
||||||
|
const [ endContext, endSpace, endMarker ] = endMatch;
|
||||||
|
if ((endMarker === endToken.text) && (endSpace.length > 0)) {
|
||||||
|
addError(
|
||||||
|
onError,
|
||||||
|
endToken.startLine,
|
||||||
|
undefined,
|
||||||
|
endContext,
|
||||||
|
[ endToken.endColumn - endContext.length, endContext.length ],
|
||||||
|
{
|
||||||
|
"editColumn": endToken.startColumn - endSpace.length,
|
||||||
|
"deleteCount": endSpace.length
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (emphasisRe.lastIndex > 1) {
|
|
||||||
// Back up one character so RegExp has a chance to match the
|
|
||||||
// mis-matched marker (ex: "*text_*")
|
|
||||||
emphasisRe.lastIndex--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (emphasisIndex !== -1) {
|
|
||||||
pendingError = pendingError ||
|
|
||||||
handleRunEnd(line, lineIndex, 0, null, line.length, inTable);
|
|
||||||
// Adjust for pending run on new line
|
|
||||||
emphasisIndex = 0;
|
|
||||||
emphasisLength = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@
|
||||||
"markdown-it-for-inline": "0.1.1",
|
"markdown-it-for-inline": "0.1.1",
|
||||||
"markdown-it-sub": "1.0.0",
|
"markdown-it-sub": "1.0.0",
|
||||||
"markdown-it-sup": "1.0.0",
|
"markdown-it-sup": "1.0.0",
|
||||||
"markdown-it-texmath": "1.0.0",
|
|
||||||
"markdownlint-rule-helpers": "0.20.0",
|
"markdownlint-rule-helpers": "0.20.0",
|
||||||
"npm-run-all": "4.1.5",
|
"npm-run-all": "4.1.5",
|
||||||
"strip-json-comments": "5.0.1",
|
"strip-json-comments": "5.0.1",
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,8 @@ t<!--> *{MD037} * -->
|
||||||
|
|
||||||
t<!---> *{MD037} * -->
|
t<!---> *{MD037} * -->
|
||||||
|
|
||||||
t<!-- *{MD037} * --->
|
t<!-- *comment * --->
|
||||||
|
|
||||||
t<!-- -- *{MD037} * -->
|
t<!-- -- *comment * -->
|
||||||
|
|
||||||
t<!-- *{MD037} * -- -->
|
t<!-- *comment * -- -->
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
It's important that the rule used above is one that calls
|
|
||||||
`helpers.forEachLine` so `markdown-it` doesn't ignore any
|
|
||||||
incorrectly-remaining comment blocks.
|
|
||||||
|
|
|
||||||
|
|
@ -895,333 +895,6 @@ test("applyFixes", (t) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("forEachLink", (t) => {
|
|
||||||
t.plan(291);
|
|
||||||
const testCases = [
|
|
||||||
[
|
|
||||||
"",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [text] (text) text",
|
|
||||||
[ [ 5, "[text]", "[text]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [text] text (text) text",
|
|
||||||
[ [ 5, "[text]", "[text]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [text] [text] text",
|
|
||||||
[
|
|
||||||
[ 5, "[text]", "[text]", undefined ],
|
|
||||||
[ 12, "[text]", "[text]", undefined ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [text] text [text] text",
|
|
||||||
[
|
|
||||||
[ 5, "[text]", "[text]", undefined ],
|
|
||||||
[ 17, "[text]", "[text]", undefined ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](destination) text",
|
|
||||||
[ [ 5, "[link](destination)", "[link]", "(destination)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link0](destination0) text [link1](destination1) text",
|
|
||||||
[
|
|
||||||
[ 5, "[link0](destination0)", "[link0]", "(destination0)" ],
|
|
||||||
[ 32, "[link1](destination1)", "[link1]", "(destination1)" ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link0] text [link1](destination1) text [link2] text",
|
|
||||||
[
|
|
||||||
[ 5, "[link0]", "[link0]", undefined ],
|
|
||||||
[ 18, "[link1](destination1)", "[link1]", "(destination1)" ],
|
|
||||||
[ 45, "[link2]", "[link2]", undefined ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link0](destination0) text [link1] text [link2](destination2) text",
|
|
||||||
[
|
|
||||||
[ 5, "[link0](destination0)", "[link0]", "(destination0)" ],
|
|
||||||
[ 32, "[link1]", "[link1]", undefined ],
|
|
||||||
[ 45, "[link2](destination2)", "[link2]", "(destination2)" ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link0][destination0] text [link1] text [link2](destination2) text",
|
|
||||||
[
|
|
||||||
[ 5, "[link0][destination0]", "[link0]", "[destination0]" ],
|
|
||||||
[ 32, "[link1]", "[link1]", undefined ],
|
|
||||||
[ 45, "[link2](destination2)", "[link2]", "(destination2)" ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link0](destination0) text [link1] text [link2][destination2] text",
|
|
||||||
[
|
|
||||||
[ 5, "[link0](destination0)", "[link0]", "(destination0)" ],
|
|
||||||
[ 32, "[link1]", "[link1]", undefined ],
|
|
||||||
[ 45, "[link2][destination2]", "[link2]", "[destination2]" ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](destination \"title\") text",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"[link](destination \"title\")",
|
|
||||||
"[link]",
|
|
||||||
"(destination \"title\")"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<destination> \"title\") text",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"[link](<destination> \"title\")",
|
|
||||||
"[link]",
|
|
||||||
"(<destination> \"title\")"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](destination \"ti\\\"tle\") text",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"[link](destination \"ti\\\"tle\")",
|
|
||||||
"[link]",
|
|
||||||
"(destination \"ti\\\"tle\")"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](destination 'title') text",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"[link](destination 'title')",
|
|
||||||
"[link]",
|
|
||||||
"(destination 'title')"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](destination (title)) text",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"[link](destination (title))",
|
|
||||||
"[link]",
|
|
||||||
"(destination (title))"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](\"title\") text",
|
|
||||||
[ [ 5, "[link](\"title\")", "[link]", "(\"title\")" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"[]()",
|
|
||||||
[ [ 0, "[]()", "[]", "()" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"[l](d)",
|
|
||||||
[ [ 0, "[l](d)", "[l]", "(d)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li[nk](dest) text",
|
|
||||||
[ [ 8, "[nk](dest)", "[nk]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li\\[nk](dest) text",
|
|
||||||
[ [ 5, "[li\\[nk](dest)", "[li\\[nk]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li]nk](dest) text",
|
|
||||||
[ [ 5, "[li]", "[li]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li\\]nk](dest) text",
|
|
||||||
[ [ 5, "[li\\]nk](dest)", "[li\\]nk]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [l[in]k](dest) text",
|
|
||||||
[ [ 5, "[l[in]k](dest)", "[l[in]k]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li(nk](dest) text",
|
|
||||||
[ [ 5, "[li(nk](dest)", "[li(nk]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [li)nk](dest) text",
|
|
||||||
[ [ 5, "[li)nk](dest)", "[li)nk]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [l(in)k](dest) text",
|
|
||||||
[ [ 5, "[l(in)k](dest)", "[l(in)k]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](de(st) text",
|
|
||||||
[ [ 5, "[link]", "[link]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](de\\(st) text",
|
|
||||||
[ [ 5, "[link](de\\(st)", "[link]", "(de\\(st)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](de)st) text",
|
|
||||||
[ [ 5, "[link](de)", "[link]", "(de)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](de\\)st) text",
|
|
||||||
[ [ 5, "[link](de\\)st)", "[link]", "(de\\)st)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](d(es)t) text",
|
|
||||||
[ [ 5, "[link](d(es)t)", "[link]", "(d(es)t)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link]() text",
|
|
||||||
[ [ 5, "[link]()", "[link]", "()" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](#) text",
|
|
||||||
[ [ 5, "[link](#)", "[link]", "(#)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<de) text",
|
|
||||||
[ [ 5, "[link]", "[link]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<de)st> text",
|
|
||||||
[ [ 5, "[link]", "[link]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<>) text",
|
|
||||||
[ [ 5, "[link](<>)", "[link]", "(<>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<dest>) text",
|
|
||||||
[ [ 5, "[link](<dest>)", "[link]", "(<dest>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<de st>) text",
|
|
||||||
[ [ 5, "[link](<de st>)", "[link]", "(<de st>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<de)st>) text",
|
|
||||||
[ [ 5, "[link](<de)st>)", "[link]", "(<de)st>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [<link](dest) text",
|
|
||||||
[ [ 5, "[<link](dest)", "[<link]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [<link>](dest) text",
|
|
||||||
[ [ 5, "[<link>](dest)", "[<link>]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [<link>](<dest) text",
|
|
||||||
[ [ 5, "[<link>]", "[<link>]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [<link>](<dest>) text",
|
|
||||||
[ [ 5, "[<link>](<dest>)", "[<link>]", "(<dest>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [[[[l[i]n[k]](dest) text",
|
|
||||||
[ [ 8, "[l[i]n[k]](dest)", "[l[i]n[k]]", "(dest)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](d(e(st))) text",
|
|
||||||
[ [ 5, "[link](d(e(st)))", "[link]", "(d(e(st)))" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](d(e(st)) text",
|
|
||||||
[ [ 5, "[link]", "[link]", undefined ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link](<d(e(st)>) text",
|
|
||||||
[ [ 5, "[link](<d(e(st)>)", "[link]", "(<d(e(st)>)" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link][reference] text",
|
|
||||||
[ [ 5, "[link][reference]", "[link]", "[reference]" ] ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Text [link][refer]ence] text",
|
|
||||||
[ [ 5, "[link][refer]", "[link]", "[refer]" ] ]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
for (const testCase of testCases) {
|
|
||||||
const [ markdown, matches ] = testCase;
|
|
||||||
helpers.forEachLink(String(markdown), (idx, lnk, txt, des) => {
|
|
||||||
// @ts-ignore
|
|
||||||
const match = matches.shift();
|
|
||||||
const [ index, link, text, destination ] = match;
|
|
||||||
t.is(idx, index, String(markdown));
|
|
||||||
t.is(lnk, link, String(markdown));
|
|
||||||
t.is(txt, text, String(markdown));
|
|
||||||
t.is(des, destination, String(markdown));
|
|
||||||
});
|
|
||||||
t.is(matches.length, 0, "Missing match");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("htmlElementRanges", (t) => {
|
|
||||||
t.plan(1);
|
|
||||||
const params = {
|
|
||||||
"lines": [
|
|
||||||
"# Heading",
|
|
||||||
"",
|
|
||||||
"Text text text",
|
|
||||||
"text <a id='id'/> text",
|
|
||||||
"text text text",
|
|
||||||
"",
|
|
||||||
"<p>",
|
|
||||||
"Text <em>text</em> text",
|
|
||||||
"</p>",
|
|
||||||
"",
|
|
||||||
"```",
|
|
||||||
"<br/>",
|
|
||||||
"```",
|
|
||||||
"",
|
|
||||||
"Text `<br/>` text",
|
|
||||||
"text <br/> text"
|
|
||||||
],
|
|
||||||
"parsers": {
|
|
||||||
"markdownit": {
|
|
||||||
"tokens": [
|
|
||||||
{
|
|
||||||
"type": "code_block",
|
|
||||||
"map": [ 10, 12 ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const expected = [
|
|
||||||
[ 3, 5, 12 ],
|
|
||||||
[ 6, 0, 3 ],
|
|
||||||
[ 7, 5, 4 ],
|
|
||||||
[ 14, 6, 5 ],
|
|
||||||
[ 15, 5, 5 ]
|
|
||||||
];
|
|
||||||
const lineMetadata = helpers.getLineMetadata(params);
|
|
||||||
const actual = helpers.htmlElementRanges(params, lineMetadata);
|
|
||||||
t.deepEqual(actual, expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("expandTildePath", (t) => {
|
test("expandTildePath", (t) => {
|
||||||
t.plan(17);
|
t.plan(17);
|
||||||
const homedir = os.homedir();
|
const homedir = os.homedir();
|
||||||
|
|
|
||||||
|
|
@ -406,12 +406,24 @@ test("resultFormattingV3", (t) => new Promise((resolve) => {
|
||||||
"ruleDescription": "Spaces inside emphasis markers",
|
"ruleDescription": "Spaces inside emphasis markers",
|
||||||
"ruleInformation": `${homepage}/blob/v${version}/doc/md037.md`,
|
"ruleInformation": `${homepage}/blob/v${version}/doc/md037.md`,
|
||||||
"errorDetail": null,
|
"errorDetail": null,
|
||||||
"errorContext": "* emphasis *",
|
"errorContext": "* e",
|
||||||
"errorRange": [ 6, 12 ],
|
"errorRange": [ 6, 3 ],
|
||||||
"fixInfo": {
|
"fixInfo": {
|
||||||
"editColumn": 6,
|
"editColumn": 7,
|
||||||
"deleteCount": 12,
|
"deleteCount": 1
|
||||||
"insertText": "*emphasis*"
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineNumber": 4,
|
||||||
|
"ruleNames": [ "MD037", "no-space-in-emphasis" ],
|
||||||
|
"ruleDescription": "Spaces inside emphasis markers",
|
||||||
|
"ruleInformation": `${homepage}/blob/v${version}/doc/md037.md`,
|
||||||
|
"errorDetail": null,
|
||||||
|
"errorContext": "s *",
|
||||||
|
"errorRange": [ 15, 3 ],
|
||||||
|
"fixInfo": {
|
||||||
|
"editColumn": 16,
|
||||||
|
"deleteCount": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -439,7 +451,9 @@ test("resultFormattingV3", (t) => new Promise((resolve) => {
|
||||||
"input: 3: MD010/no-hard-tabs" +
|
"input: 3: MD010/no-hard-tabs" +
|
||||||
" Hard tabs [Column: 10]\n" +
|
" Hard tabs [Column: 10]\n" +
|
||||||
"input: 4: MD037/no-space-in-emphasis" +
|
"input: 4: MD037/no-space-in-emphasis" +
|
||||||
" Spaces inside emphasis markers [Context: \"* emphasis *\"]\n" +
|
" Spaces inside emphasis markers [Context: \"* e\"]\n" +
|
||||||
|
"input: 4: MD037/no-space-in-emphasis" +
|
||||||
|
" Spaces inside emphasis markers [Context: \"s *\"]\n" +
|
||||||
"input: 4: MD047/single-trailing-newline" +
|
"input: 4: MD047/single-trailing-newline" +
|
||||||
" Files should end with a single newline character";
|
" Files should end with a single newline character";
|
||||||
t.is(actualMessage, expectedMessage, "Incorrect message.");
|
t.is(actualMessage, expectedMessage, "Incorrect message.");
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ const md = require("markdown-it")();
|
||||||
const pluginInline = require("markdown-it-for-inline");
|
const pluginInline = require("markdown-it-for-inline");
|
||||||
const pluginSub = require("markdown-it-sub");
|
const pluginSub = require("markdown-it-sub");
|
||||||
const pluginSup = require("markdown-it-sup");
|
const pluginSup = require("markdown-it-sup");
|
||||||
const pluginTexMath = require("markdown-it-texmath");
|
|
||||||
const test = require("ava").default;
|
const test = require("ava").default;
|
||||||
const tv4 = require("tv4");
|
const tv4 = require("tv4");
|
||||||
const { "exports": packageExports, homepage, version } =
|
const { "exports": packageExports, homepage, version } =
|
||||||
|
|
@ -20,11 +19,6 @@ const rules = require("../lib/rules");
|
||||||
const customRules = require("./rules/rules.js");
|
const customRules = require("./rules/rules.js");
|
||||||
const configSchema = require("../schema/markdownlint-config-schema.json");
|
const configSchema = require("../schema/markdownlint-config-schema.json");
|
||||||
|
|
||||||
const pluginTexMathOptions = {
|
|
||||||
"engine": {
|
|
||||||
"renderToString": () => ""
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const deprecatedRuleNames = new Set(constants.deprecatedRuleNames);
|
const deprecatedRuleNames = new Set(constants.deprecatedRuleNames);
|
||||||
const configSchemaStrict = {
|
const configSchemaStrict = {
|
||||||
...configSchema,
|
...configSchema,
|
||||||
|
|
@ -1104,77 +1098,6 @@ test("markdownItPluginsMultiple", (t) => new Promise((resolve) => {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test("markdownItPluginsMathjax", (t) => new Promise((resolve) => {
|
|
||||||
t.plan(2);
|
|
||||||
markdownlint({
|
|
||||||
"strings": {
|
|
||||||
"string":
|
|
||||||
"# Heading\n" +
|
|
||||||
"\n" +
|
|
||||||
"$1 *2* 3$\n" +
|
|
||||||
"\n" +
|
|
||||||
"$$1 *2* 3$$\n" +
|
|
||||||
"\n" +
|
|
||||||
"$$1\n" +
|
|
||||||
"+ 2\n" +
|
|
||||||
"+ 3$$\n"
|
|
||||||
},
|
|
||||||
"markdownItPlugins": [ [ pluginTexMath, pluginTexMathOptions ] ]
|
|
||||||
}, function callback(err, actual) {
|
|
||||||
t.falsy(err);
|
|
||||||
const expected = { "string": [] };
|
|
||||||
t.deepEqual(actual, expected, "Unexpected issues.");
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
test("markdownItPluginsMathjaxIssue166", (t) => new Promise((resolve) => {
|
|
||||||
t.plan(2);
|
|
||||||
markdownlint({
|
|
||||||
"strings": {
|
|
||||||
"string":
|
|
||||||
`## Heading
|
|
||||||
|
|
||||||
$$
|
|
||||||
1
|
|
||||||
$$$$
|
|
||||||
2
|
|
||||||
$$\n`
|
|
||||||
},
|
|
||||||
"markdownItPlugins": [ [ pluginTexMath, pluginTexMathOptions ] ],
|
|
||||||
"resultVersion": 0
|
|
||||||
}, function callback(err, actual) {
|
|
||||||
t.falsy(err);
|
|
||||||
const expected = {
|
|
||||||
"string": {
|
|
||||||
"MD041": [ 1 ]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// @ts-ignore
|
|
||||||
t.deepEqual(actual, expected, "Unexpected issues.");
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
test("texmath test files with texmath plugin", (t) => new Promise((resolve) => {
|
|
||||||
t.plan(2);
|
|
||||||
markdownlint({
|
|
||||||
"files": [
|
|
||||||
"./test/texmath-content-in-lists.md",
|
|
||||||
"./test/texmath-content-violating-md037.md"
|
|
||||||
],
|
|
||||||
"markdownItPlugins": [ [ pluginTexMath, pluginTexMathOptions ] ]
|
|
||||||
}, function callback(err, actual) {
|
|
||||||
t.falsy(err);
|
|
||||||
const expected = {
|
|
||||||
"./test/texmath-content-in-lists.md": [],
|
|
||||||
"./test/texmath-content-violating-md037.md": []
|
|
||||||
};
|
|
||||||
t.deepEqual(actual, expected, "Unexpected issues.");
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
test("Pandoc footnote", (t) => new Promise((resolve) => {
|
test("Pandoc footnote", (t) => new Promise((resolve) => {
|
||||||
t.plan(2);
|
t.plan(2);
|
||||||
markdownlint({
|
markdownlint({
|
||||||
|
|
|
||||||
15
test/mathjax-scenarios.md
Normal file
15
test/mathjax-scenarios.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Mathjax Scenarios
|
||||||
|
|
||||||
|
$1 * 2 * 3$
|
||||||
|
|
||||||
|
$$1 * 2 * 3$$
|
||||||
|
|
||||||
|
$$1
|
||||||
|
+ 2
|
||||||
|
+ 3$$
|
||||||
|
|
||||||
|
$$
|
||||||
|
1
|
||||||
|
$$$$
|
||||||
|
2
|
||||||
|
$$
|
||||||
|
|
@ -17,7 +17,9 @@ Generated by [AVA](https://avajs.dev).
|
||||||
`test-repos/dotnet-docs/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
`test-repos/dotnet-docs/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
||||||
test-repos/dotnet-docs/docs/azure/sdk/includes/assign-managed-identity-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
test-repos/dotnet-docs/docs/azure/sdk/includes/assign-managed-identity-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
||||||
test-repos/dotnet-docs/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
test-repos/dotnet-docs/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-4.md: 5: MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "<br>"]␊
|
||||||
test-repos/dotnet-docs/docs/core/compatibility/core-libraries/5.0/code-access-security-apis-obsolete.md: 431: MD033/no-inline-html Inline HTML [Element: StrongName]`
|
test-repos/dotnet-docs/docs/core/compatibility/core-libraries/5.0/code-access-security-apis-obsolete.md: 431: MD033/no-inline-html Inline HTML [Element: StrongName]␊
|
||||||
|
test-repos/dotnet-docs/docs/core/extensions/windows-service.md: 177: MD037/no-space-in-emphasis Spaces inside emphasis markers [Context: "n *"]␊
|
||||||
|
test-repos/dotnet-docs/docs/devops/github-actions-overview.md: 32: MD037/no-space-in-emphasis Spaces inside emphasis markers [Context: "r *"]`
|
||||||
|
|
||||||
## https://github.com/electron/electron
|
## https://github.com/electron/electron
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -42,8 +42,8 @@ emphasis * text {MD037}
|
||||||
Text * emphasis {MD037}
|
Text * emphasis {MD037}
|
||||||
emphasis * text {MD037}
|
emphasis * text {MD037}
|
||||||
|
|
||||||
Text *emphasis * *emphasis {MD037}
|
Text *emphasis * *emphasis
|
||||||
emphasis* * emphasis* text {MD037}
|
emphasis* * emphasis* text
|
||||||
|
|
||||||
Text *emphasis* * emphasis {MD037}
|
Text *emphasis* * emphasis {MD037}
|
||||||
emphasis * *emphasis* text {MD037}
|
emphasis * *emphasis* text {MD037}
|
||||||
|
|
|
||||||
|
|
@ -125,32 +125,51 @@ Uncommon scenarios from the CommonMark specification (and some variations):
|
||||||
*in emph **strong***
|
*in emph **strong***
|
||||||
|
|
||||||
*** strong emph*** {MD037}
|
*** strong emph*** {MD037}
|
||||||
*** strong** in emph* {MD037}
|
|
||||||
*** emph* in strong** {MD037}
|
*** strong** in emph* {possible MD037}
|
||||||
|
|
||||||
|
*** emph* in strong** {possible MD037}
|
||||||
|
|
||||||
** in strong *emph*** {MD037}
|
** in strong *emph*** {MD037}
|
||||||
|
|
||||||
***strong emph *** {MD037}
|
***strong emph *** {MD037}
|
||||||
|
|
||||||
***strong** in emph * {MD037}
|
***strong** in emph * {MD037}
|
||||||
|
|
||||||
***emph* in strong ** {MD037}
|
***emph* in strong ** {MD037}
|
||||||
**in strong *emph *** {MD037}
|
|
||||||
*in emph **strong *** {MD037}
|
**in strong *emph *** {possible MD037}
|
||||||
|
|
||||||
|
*in emph **strong *** {possible MD037}
|
||||||
|
|
||||||
** *strong emph*** {MD037}
|
** *strong emph*** {MD037}
|
||||||
|
|
||||||
** *strong** in emph* {MD037}
|
** *strong** in emph* {MD037}
|
||||||
|
|
||||||
** *emph* in strong** {MD037}
|
** *emph* in strong** {MD037}
|
||||||
|
|
||||||
**in strong * emph*** (internal spaces are not detected)
|
**in strong * emph*** (internal spaces are not detected)
|
||||||
|
|
||||||
*in emph ** strong*** (internal spaces are not detected)
|
*in emph ** strong*** (internal spaces are not detected)
|
||||||
|
|
||||||
***strong emph* ** {MD037}
|
***strong emph* ** {MD037}
|
||||||
|
|
||||||
***strong ** in emph* (internal spaces are not detected)
|
***strong ** in emph* (internal spaces are not detected)
|
||||||
|
|
||||||
***emph * in strong** (internal spaces are not detected)
|
***emph * in strong** (internal spaces are not detected)
|
||||||
|
|
||||||
**in strong *emph* ** {MD037}
|
**in strong *emph* ** {MD037}
|
||||||
|
|
||||||
*in emph **strong* ** {MD037}
|
*in emph **strong* ** {MD037}
|
||||||
|
|
||||||
Text *emph***strong** text
|
Text *emph***strong** text
|
||||||
|
|
||||||
Text * emph***strong** text {MD037}
|
Text * emph***strong** text {MD037}
|
||||||
Text *emph ***strong** text (internal spaces are not detected)
|
|
||||||
Text *emph*** strong** text (internal spaces are not detected)
|
Text *emph ***strong** text {MD037}
|
||||||
|
|
||||||
|
Text *emph*** strong** text {MD037}
|
||||||
|
|
||||||
Text *emph***strong ** text {MD037}
|
Text *emph***strong ** text {MD037}
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# texmath-content-violating-md037
|
|
||||||
|
|
||||||
## Inline (not handled)
|
|
||||||
|
|
||||||
text `$ x * y * z $` text
|
|
||||||
|
|
||||||
text `$$ x * y * z $$` text
|
|
||||||
|
|
||||||
## Block (handled when used with markdown-it-texmath)
|
|
||||||
|
|
||||||
$$
|
|
||||||
x * y * z {MD037}
|
|
||||||
$$
|
|
||||||
|
|
||||||
text
|
|
||||||
|
|
||||||
$$
|
|
||||||
x * y = x * y {MD037}
|
|
||||||
$$
|
|
||||||
19
test/texmath-content.md
Normal file
19
test/texmath-content.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# texmath-content
|
||||||
|
|
||||||
|
## Inline
|
||||||
|
|
||||||
|
text $ x * y * z $ text
|
||||||
|
|
||||||
|
text $$ x * y * z $$ text
|
||||||
|
|
||||||
|
## Block
|
||||||
|
|
||||||
|
$$
|
||||||
|
x * y * z
|
||||||
|
$$
|
||||||
|
|
||||||
|
text
|
||||||
|
|
||||||
|
$$
|
||||||
|
x * y = x * y
|
||||||
|
$$
|
||||||
Loading…
Add table
Add a link
Reference in a new issue