Re-implement MD038 to handle multi-line spans better and rely less on RegExp.

This commit is contained in:
David Anson 2019-01-30 22:09:20 -08:00
parent 3b49414183
commit ff50da3b42
7 changed files with 235 additions and 40 deletions

View file

@ -4,49 +4,42 @@
const shared = require("./shared");
const inlineCodeSpansRe = /(?:^|[^\\])((`+)((?:[\s\S]*?[^`])|)\2(?!`))/g;
const startRe = /^\s([^`]|$)/;
const endRe = /[^`]\s$/;
module.exports = {
"names": [ "MD038", "no-space-in-code" ],
"description": "Spaces inside code span elements",
"tags": [ "whitespace", "code" ],
"function": function MD038(params, onError) {
let lastParent = null;
shared.forEachInlineChild(params, "code_inline",
function forToken(token, parent) {
if (lastParent !== parent) {
lastParent = parent;
inlineCodeSpansRe.lastIndex = 0;
}
const match = inlineCodeSpansRe.exec(parent.content);
const content = (match || [])[3];
const leftError = /^\s([^`]|$)/.test(content);
const rightError = /[^`]\s$/.test(content);
if (leftError || rightError) {
const inlineCodeSpan = match[1];
const leftContent = parent.content.substr(0,
match.index + (match[0].length - inlineCodeSpan.length));
const leftContentLines = leftContent.split(shared.newLineRe);
const inlineCodeSpanLines = inlineCodeSpan.split(shared.newLineRe);
let range = [
leftContentLines[leftContentLines.length - 1].length + 1,
inlineCodeSpanLines[0].length
];
if (leftError) {
shared.addErrorContext(onError, token.lineNumber,
inlineCodeSpan, true, false, range);
} else {
if (inlineCodeSpanLines.length > 1) {
range = [
1,
inlineCodeSpanLines[inlineCodeSpanLines.length - 1].length
];
shared.filterTokens(params, "inline", (token) => {
if (token.children.some((child) => child.type === "code_inline")) {
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
shared.forEachInlineCodeSpan(
tokenLines.join("\n"),
(code, lineIndex, columnIndex, tickCount) => {
let rangeIndex = columnIndex - tickCount;
let rangeLength = code.length + (2 * tickCount);
let rangeLineOffset = 0;
const codeLines = code.split(shared.newLineRe);
const left = startRe.test(code);
const right = !left && endRe.test(code);
if (right && (codeLines.length > 1)) {
rangeIndex = 0;
rangeLineOffset = codeLines.length - 1;
}
shared.addErrorContext(onError,
token.lineNumber + content.split(shared.newLineRe).length - 1,
inlineCodeSpan, false, true, range);
}
}
});
if (left || right) {
if (codeLines.length > 1) {
rangeLength = codeLines[rangeLineOffset].length + tickCount;
}
const context = tokenLines[lineIndex + rangeLineOffset]
.substring(rangeIndex, rangeIndex + rangeLength);
shared.addErrorContext(
onError, token.lineNumber + lineIndex + rangeLineOffset,
context, left, right, [ rangeIndex + 1, rangeLength ]);
}
});
}
});
}
};