From 1db87ef0c6b9eee11c8358ea8bfd0d0d6e729b98 Mon Sep 17 00:00:00 2001 From: David Anson Date: Wed, 20 Mar 2019 21:48:18 -0700 Subject: [PATCH] Update MD031/blanks-around-fences and MD032/blanks-around-lists to ignore comments and blockquotes (fixes #171, fixes #172). --- lib/md031.js | 12 ++++---- lib/md032.js | 20 ++++++------- lib/shared.js | 7 +++++ test/blanks-around.md | 61 +++++++++++++++++++++++++++++++++++++++ test/markdownlint-test.js | 36 +++++++++++++++++++++++ 5 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 test/blanks-around.md diff --git a/lib/md031.js b/lib/md031.js index 562ca601..eab64c6c 100644 --- a/lib/md031.js +++ b/lib/md031.js @@ -3,17 +3,19 @@ "use strict"; const shared = require("./shared"); +const { addErrorContext, forEachLine, isBlankLine } = shared; module.exports = { "names": [ "MD031", "blanks-around-fences" ], "description": "Fenced code blocks should be surrounded by blank lines", "tags": [ "code", "blank_lines" ], "function": function MD031(params, onError) { - const lines = params.lines; - shared.forEachLine(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)) { - shared.addErrorContext(onError, i + 1, lines[i].trim()); + const { lines } = params; + const { length } = lines; + forEachLine(function forLine(line, i, inCode, onFence) { + if (((onFence > 0) && (i - 1 >= 0) && !isBlankLine(lines[i - 1])) || + ((onFence < 0) && (i + 1 < length) && !isBlankLine(lines[i + 1]))) { + addErrorContext(onError, i + 1, lines[i].trim()); } }); } diff --git a/lib/md032.js b/lib/md032.js index 30140573..cb84f01a 100644 --- a/lib/md032.js +++ b/lib/md032.js @@ -3,24 +3,22 @@ "use strict"; const shared = require("./shared"); - -const blankLineRe = /^[\s>]*$/; +const { addErrorContext, flattenLists, isBlankLine } = shared; module.exports = { "names": [ "MD032", "blanks-around-lists" ], "description": "Lists should be surrounded by blank lines", "tags": [ "bullet", "ul", "ol", "blank_lines" ], "function": function MD032(params, onError) { - shared.flattenLists().filter((list) => !list.nesting).forEach((list) => { - const firstLineIndex = list.open.map[0]; - if (!blankLineRe.test(params.lines[firstLineIndex - 1] || "")) { - shared.addErrorContext( - onError, firstLineIndex + 1, params.lines[firstLineIndex].trim()); + const { lines } = params; + flattenLists().filter((list) => !list.nesting).forEach((list) => { + const firstIndex = list.open.map[0]; + if (!isBlankLine(lines[firstIndex - 1])) { + addErrorContext(onError, firstIndex + 1, lines[firstIndex].trim()); } - const bottomLineIndex = list.lastLineIndex - 1; - if (!blankLineRe.test(params.lines[bottomLineIndex + 1] || "")) { - shared.addErrorContext( - onError, bottomLineIndex + 1, params.lines[bottomLineIndex].trim()); + const lastIndex = list.lastLineIndex - 1; + if (!isBlankLine(lines[lastIndex + 1])) { + addErrorContext(onError, lastIndex + 1, lines[lastIndex].trim()); } }); } diff --git a/lib/shared.js b/lib/shared.js index e6f516cb..82a96d3d 100644 --- a/lib/shared.js +++ b/lib/shared.js @@ -64,6 +64,13 @@ module.exports.isEmptyString = function isEmptyString(str) { return str.length === 0; }; +// Returns true iff the input line is blank (no content) +// Example: Contains nothing, whitespace, or comments +const blankLineRe = />|(?:)/g; +module.exports.isBlankLine = function isBlankLine(line) { + return !line || !line.trim() || !line.replace(blankLineRe, "").trim(); +}; + // 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 diff --git a/test/blanks-around.md b/test/blanks-around.md new file mode 100644 index 00000000..33570102 --- /dev/null +++ b/test/blanks-around.md @@ -0,0 +1,61 @@ +# Blanks Around + +--- + +## MD022/blanks-around-headings + +> +### Alpha {MD022} +> > + + +### Beta {MD022} + + +> Text +> +> ### Gamma +> > +> > Text + +--- + +## MD031/blanks-around-fences + +> > +```js +console.log(); +``` +> + + +```js +console.log(); +``` + + +> Text +> +> ```js +> console.log(); +> ``` +> > +> >Text + +--- + +## MD032/blanks-around-lists + +> +- List item +>> + + +- List item + + +> Text +> +> - List item +>> +>> Text diff --git a/test/markdownlint-test.js b/test/markdownlint-test.js index 6f8d57b2..da0b2788 100644 --- a/test/markdownlint-test.js +++ b/test/markdownlint-test.js @@ -1396,6 +1396,42 @@ function clearHtmlCommentTextEmbedded(test) { test.done(); }; +module.exports.isBlankLine = function isBlankLine(test) { + test.expect(25); + const blankLines = [ + null, + "", + " ", + " ", + "\t\t\t", + "\r", + "\n", + "\t\r\n", + " ", + "", + "", + "\t", + ">", + "> ", + "> > > \t", + "> ", + ">>" + ]; + blankLines.forEach((line) => test.ok(shared.isBlankLine(line), line)); + const nonBlankLines = [ + "text", + " text ", + ".", + "> .", + " text", + "", + "" + ]; + nonBlankLines.forEach((line) => test.ok(!shared.isBlankLine(line), line)); + test.done(); +}; + module.exports.trimLeftRight = function trimLeftRight(test) { const inputs = [ "text text",