From b21548a992b019ceaa52d96e3c2ca55b9122ac61 Mon Sep 17 00:00:00 2001 From: David Anson Date: Mon, 9 Mar 2015 00:31:07 -0700 Subject: [PATCH] Add passing tests, refactor to introduce forEachLine. --- .eslintrc | 2 +- lib/rules.js | 70 +++++++++++------------ test/consistent_bullet_styles_asterisk.md | 3 + test/consistent_bullet_styles_dash.md | 3 + test/consistent_bullet_styles_plus.md | 3 + test/empty_doc.md | 0 test/fenced_code_blocks.md | 21 +++++++ test/first_header_good_atx.md | 1 + test/first_header_good_setext.md | 2 + test/header_mutliple_h1_no_toplevel.md | 5 ++ 10 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 test/consistent_bullet_styles_asterisk.md create mode 100644 test/consistent_bullet_styles_dash.md create mode 100644 test/consistent_bullet_styles_plus.md create mode 100644 test/empty_doc.md create mode 100644 test/fenced_code_blocks.md create mode 100644 test/first_header_good_atx.md create mode 100644 test/first_header_good_setext.md create mode 100644 test/header_mutliple_h1_no_toplevel.md diff --git a/.eslintrc b/.eslintrc index ff4d5657..08f58162 100644 --- a/.eslintrc +++ b/.eslintrc @@ -127,7 +127,7 @@ "max-depth": [2, 4], "max-len": [2, 80, 2], "max-nested-callbacks": [2, 2], - "max-params": [2, 3], + "max-params": [2, 4], "max-statements": [0, 10], "new-cap": 2, "new-parens": 2, diff --git a/lib/rules.js b/lib/rules.js index 3928e86e..bae71b54 100644 --- a/lib/rules.js +++ b/lib/rules.js @@ -35,13 +35,23 @@ function filterTokens(tokens, tokenA, tokenB) { }); } -function padAndTrim(lines) { - return [].concat( - "", - lines.map(function mapLine(line) { - return line.trim(); - }), - ""); +function forEachLine(params, callback) { + var codeBlocks = []; + filterTokens(params.tokens, "code_block") + .forEach(function forToken(token) { + for (var i = token.lines[0]; i < token.lines[1]; i++) { + codeBlocks.push(i); + } + }); + var inFence = false; + params.lines.forEach(function forLine(line, lineIndex) { + var onFence = /^(```|~~~)/.test(line); + if (onFence) { + inFence = !inFence; + } + var codeBlock = (codeBlocks.indexOf(lineIndex) !== -1); + callback(line, lineIndex, inFence || codeBlock, onFence); + }); } module.exports = [ @@ -215,18 +225,10 @@ module.exports = [ "name": "MD012", "desc": "Multiple consecutive blank lines", "func": function MD012(params, errors) { - var exclusions = []; - filterTokens(params.tokens, "code_block", "fence") - .forEach(function forToken(token) { - for (var i = token.lines[0]; i < token.lines[1]; i++) { - exclusions.push(i); - } - }); var prevLine = "-"; - params.lines.forEach(function forLine(line, lineIndex) { + forEachLine(params, function forLine(line, lineIndex, inCode) { line = line.trim(); - if (!line.length && !prevLine.length && - (exclusions.indexOf(lineIndex) === -1)) { + if (!inCode && !line.length && !prevLine.length) { errors.push(lineIndex + 1); } prevLine = line; @@ -271,8 +273,8 @@ module.exports = [ "name": "MD018", "desc": "No space after hash on atx style header", "func": function MD018(params, errors) { - params.lines.forEach(function forLine(line, lineIndex) { - if (/^#+[^#\s]/.test(line) && !/#$/.test(line)) { + forEachLine(params, function forLine(line, lineIndex, inCode) { + if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) { errors.push(lineIndex + 1); } }); @@ -297,8 +299,8 @@ module.exports = [ "name": "MD020", "desc": "No space inside hashes on closed atx style header", "func": function MD020(params, errors) { - params.lines.forEach(function forLine(line, lineIndex) { - if (/^#+[^#]*[^\\]#+$/.test(line) && + forEachLine(params, function forLine(line, lineIndex, inCode) { + if (!inCode && /^#+[^#]*[^\\]#+$/.test(line) && (/^#+[^#\s]/.test(line) || /[^#\s]#+$/.test(line))) { errors.push(lineIndex + 1); } @@ -401,15 +403,13 @@ module.exports = [ "func": function MD031(params, errors) { // Some parsers have trouble detecting fenced code blocks without // surrounding whitespace, so examine the lines directly. - var lines = padAndTrim(params.lines); - var inCode = false; - lines.forEach(function forLine(line, lineNumber) { - if (/^(```|~~~)/.test(line)) { - inCode = !inCode; - if ((inCode && lines[lineNumber - 1].length) || - (!inCode && lines[lineNumber + 1].length)) { - errors.push(lineNumber); - } + forEachLine(params, function forLine(line, lineIndex, inCode, onFence) { + if (onFence && + ((inCode && (lineIndex - 1 >= 0) && + params.lines[lineIndex - 1].length) || + (!inCode && (lineIndex + 1 < params.lines.length) && + params.lines[lineIndex + 1].length))) { + errors.push(lineIndex + 1); } }); } @@ -422,10 +422,9 @@ module.exports = [ // Some parsers have trouble detecting lists without surrounding // whitespace, so examine the lines directly. var inList = false; - var inCode = false; var prevLine = ""; - params.lines.forEach(function forLine(line, lineIndex) { - if (!inCode) { + forEachLine(params, function forLine(line, lineIndex, inCode, onFence) { + if (!inCode || onFence) { var listMarker = /^([\*\+\-]|(\d+\.))\s/.test(line.trim()); if (listMarker && !inList && !/^($|\s)/.test(prevLine)) { errors.push(lineIndex + 1); @@ -434,10 +433,7 @@ module.exports = [ } inList = listMarker; } - if (/^(```|~~~)/.test(line.trim())) { - inCode = !inCode; - inList = false; - } + inList = inList && !onFence; prevLine = line; }); } diff --git a/test/consistent_bullet_styles_asterisk.md b/test/consistent_bullet_styles_asterisk.md new file mode 100644 index 00000000..e8ccdee3 --- /dev/null +++ b/test/consistent_bullet_styles_asterisk.md @@ -0,0 +1,3 @@ +* Item + * Item + * Item \ No newline at end of file diff --git a/test/consistent_bullet_styles_dash.md b/test/consistent_bullet_styles_dash.md new file mode 100644 index 00000000..b6c50290 --- /dev/null +++ b/test/consistent_bullet_styles_dash.md @@ -0,0 +1,3 @@ +- Item + - Item + - Item \ No newline at end of file diff --git a/test/consistent_bullet_styles_plus.md b/test/consistent_bullet_styles_plus.md new file mode 100644 index 00000000..7930238c --- /dev/null +++ b/test/consistent_bullet_styles_plus.md @@ -0,0 +1,3 @@ ++ Item + + Item + + Item \ No newline at end of file diff --git a/test/empty_doc.md b/test/empty_doc.md new file mode 100644 index 00000000..e69de29b diff --git a/test/fenced_code_blocks.md b/test/fenced_code_blocks.md new file mode 100644 index 00000000..e607018d --- /dev/null +++ b/test/fenced_code_blocks.md @@ -0,0 +1,21 @@ +This is a GFM-style fenced code block: + +``` bash +#!/bin/bash + +# Print something to stdout: +echo "Hello" +echo "World" +``` + +This is a kramdown-style fenced code block: + +~~~ bash +#!/bin/bash + +# Print something to stdout: +echo "Hello" +echo "World" +~~~ + +None of the above should trigger any heading related rules. diff --git a/test/first_header_good_atx.md b/test/first_header_good_atx.md new file mode 100644 index 00000000..7b163ace --- /dev/null +++ b/test/first_header_good_atx.md @@ -0,0 +1 @@ +# Header \ No newline at end of file diff --git a/test/first_header_good_setext.md b/test/first_header_good_setext.md new file mode 100644 index 00000000..e016d0fa --- /dev/null +++ b/test/first_header_good_setext.md @@ -0,0 +1,2 @@ +Header +====== \ No newline at end of file diff --git a/test/header_mutliple_h1_no_toplevel.md b/test/header_mutliple_h1_no_toplevel.md new file mode 100644 index 00000000..a8453007 --- /dev/null +++ b/test/header_mutliple_h1_no_toplevel.md @@ -0,0 +1,5 @@ +Some introductory text + +# Heading 1 + +# Heading 2 \ No newline at end of file