mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-21 21:30:47 +02:00
Add MD041 with tests.
This commit is contained in:
parent
eabe2387bc
commit
7f5dd9ab6b
17 changed files with 113 additions and 18 deletions
|
@ -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
|
||||||
|
|
19
doc/Rules.md
19
doc/Rules.md
|
@ -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
|
||||||
|
```
|
||||||
|
|
23
lib/rules.js
23
lib/rules.js
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
"MD007": false,
|
"MD007": false,
|
||||||
"MD033": false,
|
"MD033": false,
|
||||||
"MD034": false,
|
"MD034": false,
|
||||||
"MD040": false
|
"MD040": false,
|
||||||
|
"MD041": false
|
||||||
}
|
}
|
||||||
|
|
4
test/break-all-the-rules.json
Normal file
4
test/break-all-the-rules.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"default": true,
|
||||||
|
"MD041": true
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
## Header 1 {MD002}
|
## Header 1 {MD002} {MD041}
|
||||||
|
|
||||||
#### Header 2 {MD001}
|
#### Header 2 {MD001}
|
||||||
|
|
||||||
|
|
4
test/first_line_top_level_header_atx.json
Normal file
4
test/first_line_top_level_header_atx.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"default": false,
|
||||||
|
"MD041": true
|
||||||
|
}
|
3
test/first_line_top_level_header_atx.md
Normal file
3
test/first_line_top_level_header_atx.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# First line is a top level header
|
||||||
|
|
||||||
|
This shouldn't trigger MD041
|
4
test/first_line_top_level_header_setext.json
Normal file
4
test/first_line_top_level_header_setext.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"default": false,
|
||||||
|
"MD041": true
|
||||||
|
}
|
4
test/first_line_top_level_header_setext.md
Normal file
4
test/first_line_top_level_header_setext.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
First line top level header
|
||||||
|
===========================
|
||||||
|
|
||||||
|
This shouldn't trigger MD041
|
3
test/markdownlint-test-default-config.json
Normal file
3
test/markdownlint-test-default-config.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"MD041": false
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
4
test/no_first_line_header.json
Normal file
4
test/no_first_line_header.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"default": true,
|
||||||
|
"MD041": true
|
||||||
|
}
|
1
test/no_first_line_header.md
Normal file
1
test/no_first_line_header.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
This is a file without a top level header {MD041}
|
5
test/no_first_line_top_level_header.json
Normal file
5
test/no_first_line_top_level_header.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"default": true,
|
||||||
|
"MD002": false,
|
||||||
|
"MD041": true
|
||||||
|
}
|
1
test/no_first_line_top_level_header.md
Normal file
1
test/no_first_line_top_level_header.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
## Second level header {MD041}
|
Loading…
Add table
Add a link
Reference in a new issue