Add MD041 with tests.

This commit is contained in:
David Anson 2015-07-20 22:06:48 -07:00
parent eabe2387bc
commit 7f5dd9ab6b
17 changed files with 113 additions and 18 deletions

View file

@ -76,6 +76,7 @@ playground for learning and exploring.
* **MD038** - Spaces inside code span elements * **MD038** - Spaces inside code span elements
* **MD039** - Spaces inside link text * **MD039** - Spaces inside link text
* **MD040** - Fenced code blocks should have a language specified * **MD040** - Fenced code blocks should have a language specified
* **MD041** - First line in file should be a top level header
See [Rules.md](doc/Rules.md) for more details. See [Rules.md](doc/Rules.md) for more details.
@ -90,7 +91,7 @@ See [Rules.md](doc/Rules.md) for more details.
* **emphasis** - MD036, MD037 * **emphasis** - MD036, MD037
* **hard_tab** - MD010 * **hard_tab** - MD010
* **headers** - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, * **headers** - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023,
MD024, MD025, MD026, MD036 MD024, MD025, MD026, MD036, MD041
* **hr** - MD035 * **hr** - MD035
* **html** - MD033 * **html** - MD033
* **indentation** - MD005, MD006, MD007, MD027 * **indentation** - MD005, MD006, MD007, MD027

View file

@ -872,3 +872,22 @@ To fix this, add a language specifier to the code block:
#!/bin/bash #!/bin/bash
echo Hello world echo Hello world
``` ```
## MD041 - First line in file should be a top level header
Tags: headers
This rule is triggered when the first line in the file isn't a top level (h1)
header:
```
This is a file without a header
```
To fix this, add a header to the top of your file:
```
# File with header
This is a file with a top level header
```

View file

@ -779,5 +779,28 @@ module.exports = [
} }
}); });
} }
},
{
"name": "MD041",
"desc": "First line in file should be a top level header",
"tags": [ "headers" ],
"func": function MD041(params, errors) {
var firstHeader = null;
params.tokens.every(function forToken(token) {
if (token.type === "heading_open") {
firstHeader = token;
return false;
} else if (token.lineNumber > 1) {
return false;
}
return true;
});
if (!firstHeader ||
(firstHeader.lineNumber !== 1) ||
(firstHeader.tag !== "h1")) {
errors.push(1);
}
}
} }
]; ];

View file

@ -27,6 +27,8 @@
"cpy": "^3.3.0", "cpy": "^3.3.0",
"eslint": "^0.23.0", "eslint": "^0.23.0",
"istanbul": "^0.3.15", "istanbul": "^0.3.15",
"lodash.assign": "^3.2.0",
"lodash.clone": "^3.0.2",
"nodeunit": "^0.9.1", "nodeunit": "^0.9.1",
"q": "^1.4.0", "q": "^1.4.0",
"rimraf": "^2.4.0", "rimraf": "^2.4.0",

View file

@ -8,5 +8,6 @@
"MD007": false, "MD007": false,
"MD033": false, "MD033": false,
"MD034": false, "MD034": false,
"MD040": false "MD040": false,
"MD041": false
} }

View file

@ -0,0 +1,4 @@
{
"default": true,
"MD041": true
}

View file

@ -1,4 +1,4 @@
## Header 1 {MD002} ## Header 1 {MD002} {MD041}
#### Header 2 {MD001} #### Header 2 {MD001}

View file

@ -0,0 +1,4 @@
{
"default": false,
"MD041": true
}

View file

@ -0,0 +1,3 @@
# First line is a top level header
This shouldn't trigger MD041

View file

@ -0,0 +1,4 @@
{
"default": false,
"MD041": true
}

View file

@ -0,0 +1,4 @@
First line top level header
===========================
This shouldn't trigger MD041

View file

@ -0,0 +1,3 @@
{
"MD041": false
}

View file

@ -3,11 +3,14 @@
var fs = require("fs"); var fs = require("fs");
var path = require("path"); var path = require("path");
var md = require("markdown-it")(); var md = require("markdown-it")();
var assign = require("lodash.assign");
var clone = require("lodash.clone");
var Q = require("q"); var Q = require("q");
var markdownlint = require("../lib/markdownlint"); var markdownlint = require("../lib/markdownlint");
var shared = require("../lib/shared"); var shared = require("../lib/shared");
var rules = require("../lib/rules"); var rules = require("../lib/rules");
var polyfills = require("../demo/browser-polyfills"); var polyfills = require("../demo/browser-polyfills");
var defaultConfig = require("./markdownlint-test-default-config.json");
function createTestForFile(file) { function createTestForFile(file) {
return function testForFile(test) { return function testForFile(test) {
@ -27,9 +30,10 @@ function createTestForFile(file) {
}) })
.then( .then(
function lintWithConfig(config) { function lintWithConfig(config) {
var mergedConfig = assign(clone(defaultConfig), config);
return Q.nfcall(markdownlint, { return Q.nfcall(markdownlint, {
"files": [ file ], "files": [ file ],
"config": config "config": mergedConfig
}); });
}); });
var expectedPromise = Q.nfcall(fs.readFile, file, shared.utf8Encoding) var expectedPromise = Q.nfcall(fs.readFile, file, shared.utf8Encoding)
@ -91,7 +95,8 @@ module.exports.resultFormatting = function resultFormatting(test) {
"files": [ "files": [
"./test/atx_header_spacing.md", "./test/atx_header_spacing.md",
"./test/first_header_bad_atx.md" "./test/first_header_bad_atx.md"
] ],
"config": defaultConfig
}; };
markdownlint(options, function callback(err, actualResult) { markdownlint(options, function callback(err, actualResult) {
test.ifError(err); test.ifError(err);
@ -129,7 +134,8 @@ module.exports.resultFormattingSync = function resultFormattingSync(test) {
"files": [ "files": [
"./test/atx_header_spacing.md", "./test/atx_header_spacing.md",
"./test/first_header_bad_atx.md" "./test/first_header_bad_atx.md"
] ],
"config": defaultConfig
}; };
var actualResult = markdownlint.sync(options); var actualResult = markdownlint.sync(options);
var expectedResult = { var expectedResult = {
@ -167,7 +173,8 @@ module.exports.stringInputLineEndings = function stringInputLineEndings(test) {
"lf": "One\nTwo\n#Three", "lf": "One\nTwo\n#Three",
"crlf": "One\r\nTwo\r\n#Three", "crlf": "One\r\nTwo\r\n#Three",
"mixed": "One\rTwo\n#Three" "mixed": "One\rTwo\n#Three"
} },
"config": defaultConfig
}; };
markdownlint(options, function callback(err, actualResult) { markdownlint(options, function callback(err, actualResult) {
test.ifError(err); test.ifError(err);
@ -199,10 +206,12 @@ module.exports.defaultTrue = function defaultTrue(test) {
"./test/atx_header_spacing.md": { "./test/atx_header_spacing.md": {
"MD002": [ 3 ], "MD002": [ 3 ],
"MD018": [ 1 ], "MD018": [ 1 ],
"MD019": [ 3, 5 ] "MD019": [ 3, 5 ],
"MD041": [ 1 ]
}, },
"./test/first_header_bad_atx.md": { "./test/first_header_bad_atx.md": {
"MD002": [ 1 ] "MD002": [ 1 ],
"MD041": [ 1 ]
} }
}; };
test.deepEqual(actualResult, expectedResult, "Undetected issues."); test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -247,10 +256,12 @@ module.exports.defaultUndefined = function defaultUndefined(test) {
"./test/atx_header_spacing.md": { "./test/atx_header_spacing.md": {
"MD002": [ 3 ], "MD002": [ 3 ],
"MD018": [ 1 ], "MD018": [ 1 ],
"MD019": [ 3, 5 ] "MD019": [ 3, 5 ],
"MD041": [ 1 ]
}, },
"./test/first_header_bad_atx.md": { "./test/first_header_bad_atx.md": {
"MD002": [ 1 ] "MD002": [ 1 ],
"MD041": [ 1 ]
} }
}; };
test.deepEqual(actualResult, expectedResult, "Undetected issues."); test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -268,7 +279,8 @@ module.exports.disableRules = function disableRules(test) {
"config": { "config": {
"MD002": false, "MD002": false,
"default": true, "default": true,
"MD019": false "MD019": false,
"MD041": false
} }
}; };
markdownlint(options, function callback(err, actualResult) { markdownlint(options, function callback(err, actualResult) {
@ -329,10 +341,12 @@ module.exports.disableTag = function disableTag(test) {
test.ifError(err); test.ifError(err);
var expectedResult = { var expectedResult = {
"./test/atx_header_spacing.md": { "./test/atx_header_spacing.md": {
"MD002": [ 3 ] "MD002": [ 3 ],
"MD041": [ 1 ]
}, },
"./test/first_header_bad_atx.md": { "./test/first_header_bad_atx.md": {
"MD002": [ 1 ] "MD002": [ 1 ],
"MD041": [ 1 ]
} }
}; };
test.deepEqual(actualResult, expectedResult, "Undetected issues."); test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -421,7 +435,8 @@ module.exports.styleAll = function styleAll(test) {
"MD037": [ 67 ], "MD037": [ 67 ],
"MD038": [ 69 ], "MD038": [ 69 ],
"MD039": [ 71 ], "MD039": [ 71 ],
"MD040": [ 73 ] "MD040": [ 73 ],
"MD041": [ 1 ]
} }
}; };
test.deepEqual(actualResult, expectedResult, "Undetected issues."); test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -539,7 +554,8 @@ module.exports.missingStringValue = function missingStringValue(test) {
"undefined": undefined, "undefined": undefined,
"null": null, "null": null,
"empty": "" "empty": ""
} },
"config": defaultConfig
}, function callback(err, result) { }, function callback(err, result) {
test.ifError(err); test.ifError(err);
var expectedResult = { var expectedResult = {
@ -553,7 +569,7 @@ module.exports.missingStringValue = function missingStringValue(test) {
}; };
module.exports.readme = function readme(test) { module.exports.readme = function readme(test) {
test.expect(95); test.expect(97);
var tagToRules = {}; var tagToRules = {};
rules.forEach(function forRule(rule) { rules.forEach(function forRule(rule) {
rule.tags.forEach(function forTag(tag) { rule.tags.forEach(function forTag(tag) {
@ -610,7 +626,7 @@ module.exports.readme = function readme(test) {
}; };
module.exports.doc = function doc(test) { module.exports.doc = function doc(test) {
test.expect(147); test.expect(151);
fs.readFile("doc/Rules.md", shared.utf8Encoding, fs.readFile("doc/Rules.md", shared.utf8Encoding,
function readFile(err, contents) { function readFile(err, contents) {
test.ifError(err); test.ifError(err);

View file

@ -0,0 +1,4 @@
{
"default": true,
"MD041": true
}

View file

@ -0,0 +1 @@
This is a file without a top level header {MD041}

View file

@ -0,0 +1,5 @@
{
"default": true,
"MD002": false,
"MD041": true
}

View file

@ -0,0 +1 @@
## Second level header {MD041}