mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-17 06:20:12 +01:00
Add options.resultVersion for more detailed error reporting (fixes #23).
This commit is contained in:
parent
3a356467cd
commit
0ca8bc7bb6
11 changed files with 454 additions and 160 deletions
238
lib/rules.js
238
lib/rules.js
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
var shared = require("./shared");
|
||||
|
||||
// Escapes a string for use in a RegExp
|
||||
function escapeForRegExp(str) {
|
||||
return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
}
|
||||
|
||||
// Returns the indent for a token
|
||||
function indentFor(token) {
|
||||
var line = token.line.replace(/^[\s>]*(> |>)/, "");
|
||||
|
|
@ -161,8 +166,9 @@ module.exports = [
|
|||
var prevLevel = 0;
|
||||
filterTokens(params, "heading_open", function forToken(token) {
|
||||
var level = parseInt(token.tag.slice(1), 10);
|
||||
if (prevLevel && (level > prevLevel + 1)) {
|
||||
errors.push(token.lineNumber);
|
||||
if (prevLevel && (level > prevLevel)) {
|
||||
errors.addDetailIf(token.lineNumber,
|
||||
"h" + (prevLevel + 1), "h" + level);
|
||||
}
|
||||
prevLevel = level;
|
||||
});
|
||||
|
|
@ -179,9 +185,7 @@ module.exports = [
|
|||
var tag = "h" + level;
|
||||
params.tokens.every(function forToken(token) {
|
||||
if (token.type === "heading_open") {
|
||||
if (token.tag !== tag) {
|
||||
errors.push(token.lineNumber);
|
||||
}
|
||||
errors.addDetailIf(token.lineNumber, tag, token.tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -203,17 +207,22 @@ module.exports = [
|
|||
}
|
||||
if (styleForToken !== style) {
|
||||
var h12 = /h[12]/.test(token.tag);
|
||||
var hOther = /h[^12]/.test(token.tag);
|
||||
var setextWithAtx =
|
||||
(style === "setext_with_atx") &&
|
||||
((h12 && (styleForToken === "setext")) ||
|
||||
(hOther && (styleForToken === "atx")));
|
||||
(!h12 && (styleForToken === "atx")));
|
||||
var setextWithAtxClosed =
|
||||
(style === "setext_with_atx_closed") &&
|
||||
((h12 && (styleForToken === "setext")) ||
|
||||
(hOther && (styleForToken === "atx_closed")));
|
||||
(!h12 && (styleForToken === "atx_closed")));
|
||||
if (!setextWithAtx && !setextWithAtxClosed) {
|
||||
errors.push(token.lineNumber);
|
||||
var expected = style;
|
||||
if (style === "setext_with_atx") {
|
||||
expected = h12 ? "setext" : "atx";
|
||||
} else if (style === "setext_with_atx_closed") {
|
||||
expected = h12 ? "setext" : "atx_closed";
|
||||
}
|
||||
errors.addDetailIf(token.lineNumber, expected, styleForToken);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -241,11 +250,12 @@ module.exports = [
|
|||
if (!nestingStyles[nesting] &&
|
||||
(itemStyle !== nestingStyles[nesting - 1])) {
|
||||
nestingStyles[nesting] = itemStyle;
|
||||
} else if (itemStyle !== nestingStyles[nesting]) {
|
||||
errors.push(item.lineNumber);
|
||||
} else {
|
||||
errors.addDetailIf(item.lineNumber,
|
||||
nestingStyles[nesting], itemStyle);
|
||||
}
|
||||
} else if (itemStyle !== expectedStyle) {
|
||||
errors.push(item.lineNumber);
|
||||
} else {
|
||||
errors.addDetailIf(item.lineNumber, expectedStyle, itemStyle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -262,9 +272,7 @@ module.exports = [
|
|||
flattenLists(params).forEach(function forList(list) {
|
||||
var indent = indentFor(list.items[0]);
|
||||
list.items.forEach(function forItem(item) {
|
||||
if (indentFor(item) !== indent) {
|
||||
errors.push(item.lineNumber);
|
||||
}
|
||||
errors.addDetailIf(item.lineNumber, indent, indentFor(item));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -277,8 +285,8 @@ module.exports = [
|
|||
"aliases": [ "ul-start-left" ],
|
||||
"func": function MD006(params, errors) {
|
||||
flattenLists(params).forEach(function forList(list) {
|
||||
if (list.unordered && !list.nesting && indentFor(list.open)) {
|
||||
errors.push(list.open.lineNumber);
|
||||
if (list.unordered && !list.nesting) {
|
||||
errors.addDetailIf(list.open.lineNumber, 0, indentFor(list.open));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -295,9 +303,9 @@ module.exports = [
|
|||
flattenLists(params).forEach(function forList(list) {
|
||||
if (list.unordered && list.parentsUnordered) {
|
||||
var indent = indentFor(list.open);
|
||||
if ((indent > prevIndent) &&
|
||||
((indent - prevIndent) !== optionsIndent)) {
|
||||
errors.push(list.open.lineNumber);
|
||||
if (indent > prevIndent) {
|
||||
errors.addDetailIf(list.open.lineNumber,
|
||||
prevIndent + optionsIndent, indent);
|
||||
}
|
||||
prevIndent = indent;
|
||||
}
|
||||
|
|
@ -313,10 +321,10 @@ module.exports = [
|
|||
"func": function MD009(params, errors) {
|
||||
var brSpaces = params.options.br_spaces || 0;
|
||||
params.lines.forEach(function forLine(line, lineIndex) {
|
||||
if (/\s$/.test(line) &&
|
||||
((brSpaces < 2) ||
|
||||
(line.length - line.trimRight().length !== brSpaces))) {
|
||||
errors.push(lineIndex + 1);
|
||||
if (/\s$/.test(line)) {
|
||||
var expected = (brSpaces < 2) ? 0 : brSpaces;
|
||||
errors.addDetailIf(lineIndex + 1,
|
||||
expected, line.length - line.trimRight().length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -332,7 +340,8 @@ module.exports = [
|
|||
var includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
||||
forEachLine(params, function forLine(line, lineIndex, inCode) {
|
||||
if (/\t/.test(line) && (!inCode || includeCodeBlocks)) {
|
||||
errors.push(lineIndex + 1);
|
||||
errors.addDetail(lineIndex + 1,
|
||||
"Column: " + (line.indexOf("\t") + 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -345,8 +354,9 @@ module.exports = [
|
|||
"aliases": [ "no-reversed-links" ],
|
||||
"func": function MD011(params, errors) {
|
||||
forEachInlineChild(params, "text", function forToken(token) {
|
||||
if (/\([^)]+\)\[[^\]^][^\]]*\]/.test(token.content)) {
|
||||
errors.push(token.lineNumber);
|
||||
var match = /\([^)]+\)\[[^\]^][^\]]*\]/.exec(token.content);
|
||||
if (match) {
|
||||
errors.addDetail(token.lineNumber, match[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -363,7 +373,7 @@ module.exports = [
|
|||
forEachLine(params, function forLine(line, lineIndex, inCode) {
|
||||
count = (inCode || line.trim().length) ? 0 : count + 1;
|
||||
if (maximum < count) {
|
||||
errors.push(lineIndex + 1);
|
||||
errors.addDetailIf(lineIndex + 1, maximum, count);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -386,7 +396,7 @@ module.exports = [
|
|||
if ((includeCodeBlocks || !inCode) &&
|
||||
(includeTables || !inTable) &&
|
||||
re.test(line)) {
|
||||
errors.push(lineIndex + 1);
|
||||
errors.addDetailIf(lineIndex + 1, lineLength, line.length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -405,7 +415,8 @@ module.exports = [
|
|||
.every(function forLine(line) {
|
||||
return !line || (allBlank = false) || /^\$\s/.test(line);
|
||||
}) && !allBlank) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber,
|
||||
token.content.split(shared.newLineRe)[0].trim());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -420,7 +431,7 @@ module.exports = [
|
|||
"func": function MD018(params, errors) {
|
||||
forEachLine(params, function forLine(line, lineIndex, inCode) {
|
||||
if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) {
|
||||
errors.push(lineIndex + 1);
|
||||
errors.addContext(lineIndex + 1, line.trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -435,7 +446,7 @@ module.exports = [
|
|||
filterTokens(params, "heading_open", function forToken(token) {
|
||||
if ((headingStyleFor(token) === "atx") &&
|
||||
/^#+\s\s/.test(token.line)) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber, token.line.trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -448,9 +459,12 @@ module.exports = [
|
|||
"aliases": [ "no-missing-space-closed-atx" ],
|
||||
"func": function MD020(params, errors) {
|
||||
forEachLine(params, function forLine(line, lineIndex, inCode) {
|
||||
if (!inCode && /^#+[^#]*[^\\]#+$/.test(line) &&
|
||||
(/^#+[^#\s]/.test(line) || /[^#\s]#+$/.test(line))) {
|
||||
errors.push(lineIndex + 1);
|
||||
if (!inCode && /^#+[^#]*[^\\]#+$/.test(line)) {
|
||||
var left = /^#+[^#\s]/.test(line);
|
||||
var right = /[^#\s]#+$/.test(line);
|
||||
if (left || right) {
|
||||
errors.addContext(lineIndex + 1, line.trim(), left, right);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -463,9 +477,12 @@ module.exports = [
|
|||
"aliases": [ "no-multiple-space-closed-atx" ],
|
||||
"func": function MD021(params, errors) {
|
||||
filterTokens(params, "heading_open", function forToken(token) {
|
||||
if ((headingStyleFor(token) === "atx_closed") &&
|
||||
(/^#+\s\s/.test(token.line) || /\s\s#+$/.test(token.line))) {
|
||||
errors.push(token.lineNumber);
|
||||
if (headingStyleFor(token) === "atx_closed") {
|
||||
var left = /^#+\s\s/.test(token.line);
|
||||
var right = /\s\s#+$/.test(token.line);
|
||||
if (left || right) {
|
||||
errors.addContext(token.lineNumber, token.line.trim(), left, right);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -483,7 +500,7 @@ module.exports = [
|
|||
params.tokens.forEach(function forToken(token) {
|
||||
if (token.type === "heading_open") {
|
||||
if ((token.map[0] - prevMaxLineIndex) === 0) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber, token.line.trim());
|
||||
}
|
||||
} else if (token.type === "heading_close") {
|
||||
needBlankLine = true;
|
||||
|
|
@ -491,7 +508,8 @@ module.exports = [
|
|||
if (token.map) {
|
||||
if (needBlankLine) {
|
||||
if ((token.map[0] - prevMaxLineIndex) === 0) {
|
||||
errors.push(prevHeadingLineNumber);
|
||||
errors.addContext(prevHeadingLineNumber,
|
||||
params.lines[prevHeadingLineNumber - 1].trim());
|
||||
}
|
||||
needBlankLine = false;
|
||||
}
|
||||
|
|
@ -512,7 +530,7 @@ module.exports = [
|
|||
"func": function MD023(params, errors) {
|
||||
filterTokens(params, "heading_open", function forToken(token) {
|
||||
if (/^\s/.test(token.line)) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber, token.line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -529,7 +547,7 @@ module.exports = [
|
|||
if (knownContent.indexOf(content) === -1) {
|
||||
knownContent.push(content);
|
||||
} else {
|
||||
errors.push(heading.lineNumber);
|
||||
errors.addContext(heading.lineNumber, heading.line.trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -547,7 +565,7 @@ module.exports = [
|
|||
filterTokens(params, "heading_open", function forToken(token) {
|
||||
if (token.tag === tag) {
|
||||
if (hasTopLevelHeading) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber, token.line.trim());
|
||||
} else if (token.lineNumber === 1) {
|
||||
hasTopLevelHeading = true;
|
||||
}
|
||||
|
|
@ -565,8 +583,10 @@ module.exports = [
|
|||
var punctuation = params.options.punctuation || ".,;:!?";
|
||||
var re = new RegExp("[" + punctuation + "]$");
|
||||
forEachHeading(params, function forHeading(heading, content) {
|
||||
if (re.test(content)) {
|
||||
errors.push(heading.lineNumber);
|
||||
var match = re.exec(content);
|
||||
if (match) {
|
||||
errors.addDetail(heading.lineNumber,
|
||||
"Punctuation: '" + match[0] + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -585,11 +605,13 @@ module.exports = [
|
|||
} else if (token.type === "blockquote_close") {
|
||||
blockquoteNesting--;
|
||||
} else if ((token.type === "inline") && (blockquoteNesting > 0)) {
|
||||
if (/^(\s*>)+\s\s/.test(token.line)) {
|
||||
errors.addContext(token.lineNumber, token.line);
|
||||
}
|
||||
token.content.split(shared.newLineRe)
|
||||
.forEach(function forLine(line, offset) {
|
||||
if (/^\s/.test(line) ||
|
||||
(!offset && /^(\s*>)+\s\s/.test(token.line))) {
|
||||
errors.push(token.lineNumber + offset);
|
||||
if (/^\s/.test(line)) {
|
||||
errors.addContext(token.lineNumber + offset, "> " + line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -607,7 +629,7 @@ module.exports = [
|
|||
params.tokens.forEach(function forToken(token) {
|
||||
if ((token.type === "blockquote_open") &&
|
||||
(prevToken.type === "blockquote_close")) {
|
||||
errors.push(token.lineNumber - 1);
|
||||
errors.add(token.lineNumber - 1);
|
||||
}
|
||||
prevToken = token;
|
||||
});
|
||||
|
|
@ -625,10 +647,9 @@ module.exports = [
|
|||
if (!list.unordered) {
|
||||
var number = 1;
|
||||
list.items.forEach(function forItem(item) {
|
||||
var re = new RegExp("^[\\s>]*" + String(number) + "[\\.)]");
|
||||
if (!re.test(item.line)) {
|
||||
errors.push(item.lineNumber);
|
||||
}
|
||||
var match = /^[\s>]*([^\.)]*)[\.)]/.exec(item.line);
|
||||
errors.addDetailIf(item.lineNumber,
|
||||
String(number), !match || match[1]);
|
||||
if (style === "ordered") {
|
||||
number++;
|
||||
}
|
||||
|
|
@ -656,9 +677,8 @@ module.exports = [
|
|||
(allSingle ? olSingle : olMulti);
|
||||
list.items.forEach(function forItem(item) {
|
||||
var match = /^[\s>]*\S+(\s+)/.exec(item.line);
|
||||
if (!match || (match[1].length !== expectedSpaces)) {
|
||||
errors.push(item.lineNumber);
|
||||
}
|
||||
errors.addDetailIf(item.lineNumber,
|
||||
expectedSpaces, !match || match[1].length);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -674,7 +694,7 @@ module.exports = [
|
|||
forEachLine(params, function forLine(line, i, inCode, onFence) {
|
||||
if (((onFence > 0) && (i - 1 >= 0) && lines[i - 1].length) ||
|
||||
((onFence < 0) && (i + 1 < lines.length) && lines[i + 1].length)) {
|
||||
errors.push(i + 1);
|
||||
errors.addContext(i + 1, lines[i].trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -690,11 +710,12 @@ module.exports = [
|
|||
var prevLine = "";
|
||||
forEachLine(params, function forLine(line, lineIndex, inCode, onFence) {
|
||||
if (!inCode || onFence) {
|
||||
var listMarker = /^([\*\+\-]|(\d+\.))\s/.test(line.trim());
|
||||
var lineTrim = line.trim();
|
||||
var listMarker = /^([\*\+\-]|(\d+\.))\s/.test(lineTrim);
|
||||
if (listMarker && !inList && !/^($|\s)/.test(prevLine)) {
|
||||
errors.push(lineIndex + 1);
|
||||
errors.addContext(lineIndex + 1, lineTrim);
|
||||
} else if (!listMarker && inList && !/^($|\s)/.test(line)) {
|
||||
errors.push(lineIndex);
|
||||
errors.addContext(lineIndex, lineTrim);
|
||||
}
|
||||
inList = listMarker;
|
||||
}
|
||||
|
|
@ -723,11 +744,12 @@ module.exports = [
|
|||
.map(function forElement(element) {
|
||||
return element.slice(1).toLowerCase();
|
||||
})
|
||||
.every(function forElement(element) {
|
||||
return allowedElements.indexOf(element) !== -1;
|
||||
.filter(function forElement(element) {
|
||||
return allowedElements.indexOf(element) === -1;
|
||||
});
|
||||
if (!allowed) {
|
||||
errors.push(token.lineNumber + offset);
|
||||
if (allowed.length) {
|
||||
errors.addDetail(token.lineNumber + offset,
|
||||
"Element: " + allowed[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -745,14 +767,15 @@ module.exports = [
|
|||
filterTokens(params, "inline", function forToken(token) {
|
||||
var inLink = false;
|
||||
token.children.forEach(function forChild(child) {
|
||||
var match = null;
|
||||
if (child.type === "link_open") {
|
||||
inLink = true;
|
||||
} else if (child.type === "link_close") {
|
||||
inLink = false;
|
||||
} else if ((child.type === "text") &&
|
||||
!inLink &&
|
||||
/https?:\/\//.test(child.content)) {
|
||||
errors.push(child.lineNumber);
|
||||
(match = /(http|ftp)s?:\/\/[^\s]*/.exec(child.content))) {
|
||||
errors.addContext(child.lineNumber, match[0]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -767,12 +790,11 @@ module.exports = [
|
|||
"func": function MD035(params, errors) {
|
||||
var style = params.options.style || "consistent";
|
||||
filterTokens(params, "hr", function forToken(token) {
|
||||
var lineTrim = token.line.trim();
|
||||
if (style === "consistent") {
|
||||
style = token.line;
|
||||
}
|
||||
if (token.line !== style) {
|
||||
errors.push(token.lineNumber);
|
||||
style = lineTrim;
|
||||
}
|
||||
errors.addDetailIf(token.lineNumber, style, lineTrim);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
@ -794,7 +816,7 @@ module.exports = [
|
|||
(t.children[0].type === "em_open")) &&
|
||||
(t.children[1].type === "text") &&
|
||||
!re.test(t.children[1].content)) {
|
||||
errors.push(t.lineNumber);
|
||||
errors.addContext(t.lineNumber, t.children[1].content);
|
||||
}
|
||||
};
|
||||
} else if (token.type === "blockquote_open") {
|
||||
|
|
@ -825,9 +847,12 @@ module.exports = [
|
|||
"aliases": [ "no-space-in-emphasis" ],
|
||||
"func": function MD037(params, errors) {
|
||||
forEachInlineChild(params, "text", function forToken(token) {
|
||||
if (/\s(\*\*?|__?)\s.+\1/.test(token.content) ||
|
||||
/(\*\*?|__?).+\s\1\s/.test(token.content)) {
|
||||
errors.push(token.lineNumber);
|
||||
var left = /\s(\*\*?|__?)\s.+\1/.exec(token.content);
|
||||
var right = /(\*\*?|__?).+\s\1\s/.exec(token.content);
|
||||
if (left) {
|
||||
errors.addContext(token.lineNumber, left[0].trim());
|
||||
} else if (right) {
|
||||
errors.addContext(token.lineNumber, right[0].trim(), false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -841,8 +866,15 @@ module.exports = [
|
|||
"func": function MD038(params, errors) {
|
||||
forEachInlineChild(params, "code_inline",
|
||||
function forToken(token, inline) {
|
||||
if (inline.content.indexOf("`" + token.content + "`") === -1) {
|
||||
errors.push(token.lineNumber);
|
||||
var escapedContent = escapeForRegExp(token.content);
|
||||
var left = (new RegExp("`\\s+" + escapedContent + "\\s*`"))
|
||||
.exec(inline.content);
|
||||
var right = (new RegExp("`\\s*" + escapedContent + "\\s+`"))
|
||||
.exec(inline.content);
|
||||
if (left) {
|
||||
errors.addContext(token.lineNumber, left[0]);
|
||||
} else if (right) {
|
||||
errors.addContext(token.lineNumber, right[0], false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -856,26 +888,20 @@ module.exports = [
|
|||
"func": function MD039(params, errors) {
|
||||
filterTokens(params, "inline", function forToken(token) {
|
||||
var inLink = false;
|
||||
var index = 0;
|
||||
var lastChildRightSpaceLineNumber = 0;
|
||||
var linkText = "";
|
||||
token.children.forEach(function forChild(child) {
|
||||
if (child.type === "link_open") {
|
||||
inLink = true;
|
||||
index = 0;
|
||||
linkText = "";
|
||||
} else if (child.type === "link_close") {
|
||||
inLink = false;
|
||||
if (lastChildRightSpaceLineNumber) {
|
||||
errors.push(lastChildRightSpaceLineNumber);
|
||||
var left = linkText.trimLeft().length !== linkText.length;
|
||||
var right = linkText.trimRight().length !== linkText.length;
|
||||
if (left || right) {
|
||||
errors.addContext(token.lineNumber, linkText, left, right);
|
||||
}
|
||||
} else if (inLink) {
|
||||
if ((index === 0) &&
|
||||
(child.content.trimLeft().length !== child.content.length)) {
|
||||
errors.push(child.lineNumber);
|
||||
}
|
||||
lastChildRightSpaceLineNumber =
|
||||
(child.content.trimRight().length === child.content.length) ?
|
||||
0 : child.lineNumber;
|
||||
index++;
|
||||
linkText += child.content;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -890,7 +916,7 @@ module.exports = [
|
|||
"func": function MD040(params, errors) {
|
||||
filterTokens(params, "fence", function forToken(token) {
|
||||
if (!token.info.trim()) {
|
||||
errors.push(token.lineNumber);
|
||||
errors.addContext(token.lineNumber, token.line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -917,7 +943,7 @@ module.exports = [
|
|||
if (!firstHeader ||
|
||||
(firstHeader.lineNumber !== 1) ||
|
||||
(firstHeader.tag !== tag)) {
|
||||
errors.push(1);
|
||||
errors.addContext(1, params.lines[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -928,10 +954,26 @@ module.exports = [
|
|||
"tags": [ "links" ],
|
||||
"aliases": [ "no-empty-links" ],
|
||||
"func": function MD042(params, errors) {
|
||||
forEachInlineChild(params, "link_open", function forToken(token) {
|
||||
token.attrs.forEach(function forAttr(attr) {
|
||||
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
||||
errors.push(token.lineNumber);
|
||||
filterTokens(params, "inline", function forToken(token) {
|
||||
var inLink = false;
|
||||
var linkText = "";
|
||||
var emptyLink = false;
|
||||
token.children.forEach(function forChild(child) {
|
||||
if (child.type === "link_open") {
|
||||
inLink = true;
|
||||
linkText = "";
|
||||
child.attrs.forEach(function forAttr(attr) {
|
||||
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
||||
emptyLink = true;
|
||||
}
|
||||
});
|
||||
} else if (child.type === "link_close") {
|
||||
inLink = false;
|
||||
if (emptyLink) {
|
||||
errors.addContext(child.lineNumber, "[" + linkText + "]");
|
||||
}
|
||||
} else if (inLink) {
|
||||
linkText += child.content;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -963,12 +1005,12 @@ module.exports = [
|
|||
} else if (optional) {
|
||||
i--;
|
||||
} else {
|
||||
errors.push(heading.lineNumber);
|
||||
errors.addDetailIf(heading.lineNumber, expected, actual);
|
||||
}
|
||||
}
|
||||
});
|
||||
if ((i < requiredHeaders.length) && !errors.length) {
|
||||
errors.push(params.lines.length);
|
||||
errors.addContext(params.lines.length, requiredHeaders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue