Ignore the content of (valid) HTML comments when linting (fixes #64).

This commit is contained in:
David Anson 2017-07-16 23:08:47 -07:00
parent 8c34383f80
commit 0a678d25c1
6 changed files with 240 additions and 2 deletions

View file

@ -57,7 +57,7 @@
"max-lines": "off",
"max-nested-callbacks": "error",
"max-params": ["error", 7],
"max-statements": ["error", 30],
"max-statements": ["error", 32],
"max-statements-per-line": "error",
"multiline-ternary": "off",
"new-cap": "error",

View file

@ -115,6 +115,12 @@ See [Rules.md](doc/Rules.md) for more details.
## Configuration
Text passed to `markdownlint` is parsed as Markdown, analyzed, and any issues reported.
Two kinds of text are ignored:
* [HTML comments](https://www.w3.org/TR/html5/syntax.html#comments)
* [Front matter](https://jekyllrb.com/docs/frontmatter/) (see `options.frontMatter` below)
Rules can be enabled, disabled, and configured via `options.config` (described
below) to define the expected behavior for a set of inputs. To enable or disable
rules within a file, add one of these markers to the appropriate place (HTML

View file

@ -104,6 +104,8 @@ function lintContent(
}
}
}
// Ignore the content of HTML comments
content = shared.clearHtmlCommentText(content);
// Parse content into tokens and lines
var tokens = md.parse(content, {});
var lines = content.split(shared.newLineRe);

View file

@ -7,8 +7,9 @@ module.exports.newLineRe = /\r\n|\r|\n/;
module.exports.frontMatterRe = /^(---|\+\+\+)$[^]*?^\1$(\r\n|\r|\n)/m;
// Regular expression for matching inline disable/enable comments
module.exports.inlineCommentRe =
var inlineCommentRe =
/<!--\s*markdownlint-(dis|en)able((?:\s+[a-z0-9_-]+)*)\s*-->/ig;
module.exports.inlineCommentRe = inlineCommentRe;
// readFile options for reading with the UTF-8 encoding
module.exports.utf8Encoding = { "encoding": "utf8" };
@ -26,3 +27,36 @@ module.exports.assign = assign;
module.exports.clone = function clone(obj) {
return assign({}, obj);
};
// Replaces the text of all properly-formatted HTML comments with whitespace
// This preserves the line/column information for the rest of the document
// Trailing whitespace is avoided with a '\' character in the last column
// See https://www.w3.org/TR/html5/syntax.html#comments for details
var htmlCommentBegin = "<!--";
var htmlCommentEnd = "-->";
function clearHtmlCommentText(text) {
var i = 0;
while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
var j = text.indexOf(htmlCommentEnd, i);
if (j === -1) {
j = text.length;
text += "\\";
}
var comment = text.slice(i + htmlCommentBegin.length, j);
if ((comment.length > 0) &&
(comment[0] !== ">") &&
(comment[comment.length - 1] !== "-") &&
(comment.indexOf("--") === -1) &&
(text.slice(i, j + htmlCommentEnd.length)
.search(inlineCommentRe) === -1)) {
var blanks = comment
.replace(/[^\r\n]/g, " ")
.replace(/ ([\r\n])/g, "\\$1");
text = text.slice(0, i + htmlCommentBegin.length) +
blanks + text.slice(j);
}
i = j + htmlCommentEnd.length;
}
return text;
}
module.exports.clearHtmlCommentText = clearHtmlCommentText;

44
test/ignore-comments.md Normal file
View file

@ -0,0 +1,44 @@
# ignore-comments.md
Hard tab {MD010}
<!-- Hard tab -->
<!--Hard tab-->
<!--
Hard tab
-->
<!--
Hard tab
Hard tab
-->
<!--
Hard tab {MD010}
Invalid--comment
Hard tab {MD010}
-->
Te<!-- Hard tab -->xt
Te<!-- Hard tab -->xt {MD009}
T<!-- Hard tab -->ex<!-- Hard tab -->t
Te<!--
Hard tab
-->xt
Te<!--
Hard tab
-->xt {MD009}
Te<!-- Trailing space
-->xt
<!-- markdownlint-disable MD010 -->
Hard tab

View file

@ -1142,6 +1142,158 @@ module.exports.validateConfigSchema = function validateConfigSchema(test) {
test.done();
};
module.exports.clearHtmlCommentTextValid =
function clearHtmlCommentTextValid(test) {
test.expect(1);
var validComments = [
"<!-- text -->",
"<!--text-->",
"<!-- -->",
"<!---->",
"<!---text-->",
"<!--text-text-->",
"<!--- -->",
"<!--",
"-->",
"<!--",
"",
"-->",
"<!--",
"",
"",
"-->",
"<!--",
"",
" text ",
"",
"-->",
"<!--text",
"",
"text-->",
"text<!--text-->text",
"text<!--",
"-->text",
"text<!--",
"text",
"-->text",
"<!--text--><!--text-->",
"text<!--text-->text<!--text-->text",
"<!--",
"text"
];
var validResult = [
"<!-- -->",
"<!-- -->",
"<!-- -->",
"<!---->",
"<!-- -->",
"<!-- -->",
"<!-- -->",
"<!--",
"-->",
"<!--",
"",
"-->",
"<!--",
"",
"",
"-->",
"<!--",
"",
" \\",
"",
"-->",
"<!-- \\",
"",
" -->",
"text<!-- -->text",
"text<!--",
"-->text",
"text<!--",
" \\",
"-->text",
"<!-- --><!-- -->",
"text<!-- -->text<!-- -->text",
"<!--",
" \\"
];
var actual = shared.clearHtmlCommentText(validComments.join("\n"));
var expected = validResult.join("\n");
test.equal(actual, expected);
test.done();
};
module.exports.clearHtmlCommentTextInvalid =
function clearHtmlCommentTextInvalid(test) {
test.expect(1);
var invalidComments = [
"<!>",
"<!->",
"<!-->",
"<!--->",
"<!-->-->",
"<!--->-->",
"<!----->",
"<!------>",
"<!-- -- -->",
"<!-->-->",
"<!--> -->",
"<!--->-->",
"<!-->text-->",
"<!--->text-->",
"<!--text--->",
"<!--te--xt-->"
];
var actual = shared.clearHtmlCommentText(invalidComments.join("\n"));
var expected = invalidComments.join("\n");
test.equal(actual, expected);
test.done();
};
module.exports.clearHtmlCommentTextNonGreedy =
function clearHtmlCommentTextNonGreedy(test) {
test.expect(1);
var nonGreedyComments = [
"<!-- text --> -->",
"<!---text --> -->",
"<!--t--> -->",
"<!----> -->"
];
var nonGreedyResult = [
"<!-- --> -->",
"<!-- --> -->",
"<!-- --> -->",
"<!----> -->"
];
var actual = shared.clearHtmlCommentText(nonGreedyComments.join("\n"));
var expected = nonGreedyResult.join("\n");
test.equal(actual, expected);
test.done();
};
module.exports.clearHtmlCommentTextEmbedded =
function clearHtmlCommentTextEmbedded(test) {
test.expect(1);
var embeddedComments = [
"text<!--text-->text",
"<!-- markdownlint-disable MD010 -->",
"text<!--text-->text",
"text<!-- markdownlint-disable MD010 -->text",
"text<!--text-->text"
];
var embeddedResult = [
"text<!-- -->text",
"<!-- markdownlint-disable MD010 -->",
"text<!-- -->text",
"text<!-- markdownlint-disable MD010 -->text",
"text<!-- -->text"
];
var actual = shared.clearHtmlCommentText(embeddedComments.join("\n"));
var expected = embeddedResult.join("\n");
test.equal(actual, expected);
test.done();
};
module.exports.trimPolyfills = function trimPolyfills(test) {
var inputs = [
"text text",