Add passing tests, refactor to introduce forEachLine.

This commit is contained in:
David Anson 2015-03-09 00:31:07 -07:00
parent 9bedd25234
commit b21548a992
10 changed files with 72 additions and 38 deletions

View file

@ -127,7 +127,7 @@
"max-depth": [2, 4], "max-depth": [2, 4],
"max-len": [2, 80, 2], "max-len": [2, 80, 2],
"max-nested-callbacks": [2, 2], "max-nested-callbacks": [2, 2],
"max-params": [2, 3], "max-params": [2, 4],
"max-statements": [0, 10], "max-statements": [0, 10],
"new-cap": 2, "new-cap": 2,
"new-parens": 2, "new-parens": 2,

View file

@ -35,13 +35,23 @@ function filterTokens(tokens, tokenA, tokenB) {
}); });
} }
function padAndTrim(lines) { function forEachLine(params, callback) {
return [].concat( var codeBlocks = [];
"", filterTokens(params.tokens, "code_block")
lines.map(function mapLine(line) { .forEach(function forToken(token) {
return line.trim(); 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 = [ module.exports = [
@ -215,18 +225,10 @@ module.exports = [
"name": "MD012", "name": "MD012",
"desc": "Multiple consecutive blank lines", "desc": "Multiple consecutive blank lines",
"func": function MD012(params, errors) { "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 = "-"; var prevLine = "-";
params.lines.forEach(function forLine(line, lineIndex) { forEachLine(params, function forLine(line, lineIndex, inCode) {
line = line.trim(); line = line.trim();
if (!line.length && !prevLine.length && if (!inCode && !line.length && !prevLine.length) {
(exclusions.indexOf(lineIndex) === -1)) {
errors.push(lineIndex + 1); errors.push(lineIndex + 1);
} }
prevLine = line; prevLine = line;
@ -271,8 +273,8 @@ module.exports = [
"name": "MD018", "name": "MD018",
"desc": "No space after hash on atx style header", "desc": "No space after hash on atx style header",
"func": function MD018(params, errors) { "func": function MD018(params, errors) {
params.lines.forEach(function forLine(line, lineIndex) { forEachLine(params, function forLine(line, lineIndex, inCode) {
if (/^#+[^#\s]/.test(line) && !/#$/.test(line)) { if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) {
errors.push(lineIndex + 1); errors.push(lineIndex + 1);
} }
}); });
@ -297,8 +299,8 @@ module.exports = [
"name": "MD020", "name": "MD020",
"desc": "No space inside hashes on closed atx style header", "desc": "No space inside hashes on closed atx style header",
"func": function MD020(params, errors) { "func": function MD020(params, errors) {
params.lines.forEach(function forLine(line, lineIndex) { forEachLine(params, function forLine(line, lineIndex, inCode) {
if (/^#+[^#]*[^\\]#+$/.test(line) && if (!inCode && /^#+[^#]*[^\\]#+$/.test(line) &&
(/^#+[^#\s]/.test(line) || /[^#\s]#+$/.test(line))) { (/^#+[^#\s]/.test(line) || /[^#\s]#+$/.test(line))) {
errors.push(lineIndex + 1); errors.push(lineIndex + 1);
} }
@ -401,15 +403,13 @@ module.exports = [
"func": function MD031(params, errors) { "func": function MD031(params, errors) {
// Some parsers have trouble detecting fenced code blocks without // Some parsers have trouble detecting fenced code blocks without
// surrounding whitespace, so examine the lines directly. // surrounding whitespace, so examine the lines directly.
var lines = padAndTrim(params.lines); forEachLine(params, function forLine(line, lineIndex, inCode, onFence) {
var inCode = false; if (onFence &&
lines.forEach(function forLine(line, lineNumber) { ((inCode && (lineIndex - 1 >= 0) &&
if (/^(```|~~~)/.test(line)) { params.lines[lineIndex - 1].length) ||
inCode = !inCode; (!inCode && (lineIndex + 1 < params.lines.length) &&
if ((inCode && lines[lineNumber - 1].length) || params.lines[lineIndex + 1].length))) {
(!inCode && lines[lineNumber + 1].length)) { errors.push(lineIndex + 1);
errors.push(lineNumber);
}
} }
}); });
} }
@ -422,10 +422,9 @@ module.exports = [
// Some parsers have trouble detecting lists without surrounding // Some parsers have trouble detecting lists without surrounding
// whitespace, so examine the lines directly. // whitespace, so examine the lines directly.
var inList = false; var inList = false;
var inCode = false;
var prevLine = ""; var prevLine = "";
params.lines.forEach(function forLine(line, lineIndex) { forEachLine(params, function forLine(line, lineIndex, inCode, onFence) {
if (!inCode) { if (!inCode || onFence) {
var listMarker = /^([\*\+\-]|(\d+\.))\s/.test(line.trim()); var listMarker = /^([\*\+\-]|(\d+\.))\s/.test(line.trim());
if (listMarker && !inList && !/^($|\s)/.test(prevLine)) { if (listMarker && !inList && !/^($|\s)/.test(prevLine)) {
errors.push(lineIndex + 1); errors.push(lineIndex + 1);
@ -434,10 +433,7 @@ module.exports = [
} }
inList = listMarker; inList = listMarker;
} }
if (/^(```|~~~)/.test(line.trim())) { inList = inList && !onFence;
inCode = !inCode;
inList = false;
}
prevLine = line; prevLine = line;
}); });
} }

View file

@ -0,0 +1,3 @@
* Item
* Item
* Item

View file

@ -0,0 +1,3 @@
- Item
- Item
- Item

View file

@ -0,0 +1,3 @@
+ Item
+ Item
+ Item

0
test/empty_doc.md Normal file
View file

View file

@ -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.

View file

@ -0,0 +1 @@
# Header

View file

@ -0,0 +1,2 @@
Header
======

View file

@ -0,0 +1,5 @@
Some introductory text
# Heading 1
# Heading 2