markdownlint 0.12.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +52 -275
- package/.travis.yml +2 -2
- package/LICENSE +1 -1
- package/README.md +54 -27
- package/doc/CustomRules.md +7 -2
- package/doc/Rules.md +120 -33
- package/example/standalone.js +2 -2
- package/helpers/LICENSE +21 -0
- package/helpers/README.md +50 -0
- package/{lib/shared.js → helpers/helpers.js} +91 -82
- package/helpers/package.json +18 -0
- package/lib/cache.js +24 -0
- package/lib/markdownlint.js +78 -45
- package/lib/md001.js +3 -3
- package/lib/md002.js +2 -2
- package/lib/md003.js +5 -4
- package/lib/md004.js +11 -9
- package/lib/md005.js +12 -10
- package/lib/md006.js +7 -5
- package/lib/md007.js +7 -5
- package/lib/md009.js +10 -8
- package/lib/md010.js +5 -5
- package/lib/md011.js +4 -4
- package/lib/md012.js +4 -3
- package/lib/md013.js +41 -32
- package/lib/md014.js +7 -6
- package/lib/md018.js +6 -4
- package/lib/md019.js +6 -5
- package/lib/md020.js +5 -4
- package/lib/md021.js +6 -5
- package/lib/md022.js +22 -22
- package/lib/md023.js +5 -4
- package/lib/md024.js +6 -6
- package/lib/md025.js +11 -5
- package/lib/md026.js +4 -4
- package/lib/md027.js +6 -6
- package/lib/md028.js +2 -2
- package/lib/md029.js +17 -9
- package/lib/md030.js +8 -6
- package/lib/md031.js +7 -6
- package/lib/md032.js +10 -12
- package/lib/md033.js +27 -26
- package/lib/md034.js +15 -10
- package/lib/md035.js +3 -3
- package/lib/md036.js +2 -2
- package/lib/md037.js +12 -9
- package/lib/md038.js +6 -5
- package/lib/md039.js +7 -6
- package/lib/md040.js +3 -3
- package/lib/md041.js +17 -19
- package/lib/md042.js +5 -4
- package/lib/md043.js +5 -4
- package/lib/md044.js +14 -13
- package/lib/md045.js +3 -3
- package/lib/md046.js +32 -0
- package/lib/md047.js +18 -0
- package/lib/rules.js +3 -1
- package/package.json +12 -11
- package/schema/build-config-schema.js +36 -2
- package/schema/markdownlint-config-schema.json +178 -14
- package/style/cirosantilli.json +1 -1
package/lib/md001.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, filterTokens } = require("../helpers");
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
"names": [ "MD001", "heading-increment", "header-increment" ],
|
|
@@ -10,10 +10,10 @@ module.exports = {
|
|
|
10
10
|
"tags": [ "headings", "headers" ],
|
|
11
11
|
"function": function MD001(params, onError) {
|
|
12
12
|
let prevLevel = 0;
|
|
13
|
-
|
|
13
|
+
filterTokens(params, "heading_open", function forToken(token) {
|
|
14
14
|
const level = parseInt(token.tag.slice(1), 10);
|
|
15
15
|
if (prevLevel && (level > prevLevel)) {
|
|
16
|
-
|
|
16
|
+
addErrorDetailIf(onError, token.lineNumber,
|
|
17
17
|
"h" + (prevLevel + 1), "h" + level);
|
|
18
18
|
}
|
|
19
19
|
prevLevel = level;
|
package/lib/md002.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf } = require("../helpers");
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
"names": [ "MD002", "first-heading-h1", "first-header-h1" ],
|
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
|
13
13
|
const tag = "h" + level;
|
|
14
14
|
params.tokens.every(function forToken(token) {
|
|
15
15
|
if (token.type === "heading_open") {
|
|
16
|
-
|
|
16
|
+
addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
19
|
return true;
|
package/lib/md003.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, filterTokens, headingStyleFor } =
|
|
6
|
+
require("../helpers");
|
|
6
7
|
|
|
7
8
|
module.exports = {
|
|
8
9
|
"names": [ "MD003", "heading-style", "header-style" ],
|
|
@@ -10,8 +11,8 @@ module.exports = {
|
|
|
10
11
|
"tags": [ "headings", "headers" ],
|
|
11
12
|
"function": function MD003(params, onError) {
|
|
12
13
|
let style = params.config.style || "consistent";
|
|
13
|
-
|
|
14
|
-
const styleForToken =
|
|
14
|
+
filterTokens(params, "heading_open", function forToken(token) {
|
|
15
|
+
const styleForToken = headingStyleFor(token);
|
|
15
16
|
if (style === "consistent") {
|
|
16
17
|
style = styleForToken;
|
|
17
18
|
}
|
|
@@ -32,7 +33,7 @@ module.exports = {
|
|
|
32
33
|
} else if (style === "setext_with_atx_closed") {
|
|
33
34
|
expected = h12 ? "setext" : "atx_closed";
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
addErrorDetailIf(onError, token.lineNumber,
|
|
36
37
|
expected, styleForToken);
|
|
37
38
|
}
|
|
38
39
|
}
|
package/lib/md004.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, listItemMarkerRe,
|
|
6
|
+
rangeFromRegExp } = require("../helpers");
|
|
7
|
+
const { flattenedLists } = require("./cache");
|
|
6
8
|
|
|
7
9
|
// Returns the unordered list style for a list item token
|
|
8
10
|
function unorderedListStyleFor(token) {
|
|
@@ -25,12 +27,12 @@ module.exports = {
|
|
|
25
27
|
const style = params.config.style || "consistent";
|
|
26
28
|
let expectedStyle = style;
|
|
27
29
|
const nestingStyles = [];
|
|
28
|
-
|
|
30
|
+
flattenedLists().forEach((list) => {
|
|
29
31
|
if (list.unordered) {
|
|
30
32
|
if (expectedStyle === "consistent") {
|
|
31
33
|
expectedStyle = unorderedListStyleFor(list.items[0]);
|
|
32
34
|
}
|
|
33
|
-
list.items.forEach(
|
|
35
|
+
list.items.forEach((item) => {
|
|
34
36
|
const itemStyle = unorderedListStyleFor(item);
|
|
35
37
|
if (style === "sublist") {
|
|
36
38
|
const nesting = list.nesting;
|
|
@@ -38,14 +40,14 @@ module.exports = {
|
|
|
38
40
|
(itemStyle !== nestingStyles[nesting - 1])) {
|
|
39
41
|
nestingStyles[nesting] = itemStyle;
|
|
40
42
|
} else {
|
|
41
|
-
|
|
42
|
-
nestingStyles[nesting], itemStyle, null,
|
|
43
|
-
|
|
43
|
+
addErrorDetailIf(onError, item.lineNumber,
|
|
44
|
+
nestingStyles[nesting], itemStyle, null, null,
|
|
45
|
+
rangeFromRegExp(item.line, listItemMarkerRe));
|
|
44
46
|
}
|
|
45
47
|
} else {
|
|
46
|
-
|
|
47
|
-
expectedStyle, itemStyle, null,
|
|
48
|
-
|
|
48
|
+
addErrorDetailIf(onError, item.lineNumber,
|
|
49
|
+
expectedStyle, itemStyle, null, null,
|
|
50
|
+
rangeFromRegExp(item.line, listItemMarkerRe));
|
|
49
51
|
}
|
|
50
52
|
});
|
|
51
53
|
}
|
package/lib/md005.js
CHANGED
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addError, addErrorDetailIf, indentFor, listItemMarkerRe,
|
|
6
|
+
orderedListItemMarkerRe, rangeFromRegExp } = require("../helpers");
|
|
7
|
+
const { flattenedLists } = require("./cache");
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
"names": [ "MD005", "list-indent" ],
|
|
9
11
|
"description": "Inconsistent indentation for list items at the same level",
|
|
10
12
|
"tags": [ "bullet", "ul", "indentation" ],
|
|
11
13
|
"function": function MD005(params, onError) {
|
|
12
|
-
|
|
14
|
+
flattenedLists().forEach((list) => {
|
|
13
15
|
const expectedIndent = list.indent;
|
|
14
16
|
let expectedEnd = 0;
|
|
15
17
|
let actualEnd = -1;
|
|
16
18
|
let endMatching = false;
|
|
17
|
-
list.items.forEach(
|
|
18
|
-
const actualIndent =
|
|
19
|
+
list.items.forEach((item) => {
|
|
20
|
+
const actualIndent = indentFor(item);
|
|
19
21
|
if (list.unordered) {
|
|
20
|
-
|
|
21
|
-
expectedIndent, actualIndent, null,
|
|
22
|
-
|
|
22
|
+
addErrorDetailIf(onError, item.lineNumber,
|
|
23
|
+
expectedIndent, actualIndent, null, null,
|
|
24
|
+
rangeFromRegExp(item.line, listItemMarkerRe));
|
|
23
25
|
} else {
|
|
24
|
-
const match =
|
|
26
|
+
const match = orderedListItemMarkerRe.exec(item.line);
|
|
25
27
|
actualEnd = match && match[0].length;
|
|
26
28
|
expectedEnd = expectedEnd || actualEnd;
|
|
27
29
|
if ((expectedIndent !== actualIndent) || endMatching) {
|
|
@@ -31,8 +33,8 @@ module.exports = {
|
|
|
31
33
|
const detail = endMatching ?
|
|
32
34
|
`Expected: (${expectedEnd}); Actual: (${actualEnd})` :
|
|
33
35
|
`Expected: ${expectedIndent}; Actual: ${actualIndent}`;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
addError(onError, item.lineNumber, detail, null,
|
|
37
|
+
rangeFromRegExp(item.line, listItemMarkerRe));
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
}
|
package/lib/md006.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
const { flattenedLists } = require("./cache");
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
"names": [ "MD006", "ul-start-left" ],
|
|
@@ -10,11 +12,11 @@ module.exports = {
|
|
|
10
12
|
"Consider starting bulleted lists at the beginning of the line",
|
|
11
13
|
"tags": [ "bullet", "ul", "indentation" ],
|
|
12
14
|
"function": function MD006(params, onError) {
|
|
13
|
-
|
|
15
|
+
flattenedLists().forEach((list) => {
|
|
14
16
|
if (list.unordered && !list.nesting) {
|
|
15
|
-
|
|
16
|
-
0, list.indent, null,
|
|
17
|
-
|
|
17
|
+
addErrorDetailIf(onError, list.open.lineNumber,
|
|
18
|
+
0, list.indent, null, null,
|
|
19
|
+
rangeFromRegExp(list.open.line, listItemMarkerRe));
|
|
18
20
|
}
|
|
19
21
|
});
|
|
20
22
|
}
|
package/lib/md007.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
const { flattenedLists } = require("./cache");
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
"names": [ "MD007", "ul-indent" ],
|
|
@@ -10,11 +12,11 @@ module.exports = {
|
|
|
10
12
|
"tags": [ "bullet", "ul", "indentation" ],
|
|
11
13
|
"function": function MD007(params, onError) {
|
|
12
14
|
const optionsIndent = params.config.indent || 2;
|
|
13
|
-
|
|
15
|
+
flattenedLists().forEach((list) => {
|
|
14
16
|
if (list.unordered && list.parentsUnordered && list.indent) {
|
|
15
|
-
|
|
16
|
-
list.parentIndent + optionsIndent, list.indent, null,
|
|
17
|
-
|
|
17
|
+
addErrorDetailIf(onError, list.open.lineNumber,
|
|
18
|
+
list.parentIndent + optionsIndent, list.indent, null, null,
|
|
19
|
+
rangeFromRegExp(list.open.line, listItemMarkerRe));
|
|
18
20
|
}
|
|
19
21
|
});
|
|
20
22
|
}
|
package/lib/md009.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addError, filterTokens, forEachLine, includesSorted, rangeFromRegExp } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
const { lineMetadata } = require("./cache");
|
|
6
8
|
|
|
7
9
|
const trailingSpaceRe = /\s+$/;
|
|
8
10
|
|
|
@@ -20,24 +22,24 @@ module.exports = {
|
|
|
20
22
|
(listItemEmptyLines === undefined) ? false : !!listItemEmptyLines;
|
|
21
23
|
const listItemLineNumbers = [];
|
|
22
24
|
if (allowListItemEmptyLines) {
|
|
23
|
-
|
|
25
|
+
filterTokens(params, "list_item_open", (token) => {
|
|
24
26
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
25
27
|
listItemLineNumbers.push(i + 1);
|
|
26
28
|
}
|
|
27
29
|
});
|
|
30
|
+
listItemLineNumbers.sort((a, b) => a - b);
|
|
28
31
|
}
|
|
29
32
|
const expected = (brSpaces < 2) ? 0 : brSpaces;
|
|
30
|
-
|
|
33
|
+
forEachLine(lineMetadata(), (line, lineIndex) => {
|
|
31
34
|
const lineNumber = lineIndex + 1;
|
|
32
35
|
if (trailingSpaceRe.test(line) &&
|
|
33
|
-
(listItemLineNumbers
|
|
34
|
-
const actual = line.length -
|
|
36
|
+
!includesSorted(listItemLineNumbers, lineNumber)) {
|
|
37
|
+
const actual = line.length - line.trimRight().length;
|
|
35
38
|
if (expected !== actual) {
|
|
36
|
-
|
|
39
|
+
addError(onError, lineNumber,
|
|
37
40
|
"Expected: " + (expected === 0 ? "" : "0 or ") +
|
|
38
41
|
expected + "; Actual: " + actual,
|
|
39
|
-
null,
|
|
40
|
-
shared.rangeFromRegExp(line, trailingSpaceRe));
|
|
42
|
+
null, rangeFromRegExp(line, trailingSpaceRe));
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
});
|
package/lib/md010.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addError, forEachLine, rangeFromRegExp } = require("../helpers");
|
|
6
|
+
const { lineMetadata } = require("./cache");
|
|
6
7
|
|
|
7
8
|
const tabRe = /\t+/;
|
|
8
9
|
|
|
@@ -13,11 +14,10 @@ module.exports = {
|
|
|
13
14
|
"function": function MD010(params, onError) {
|
|
14
15
|
const codeBlocks = params.config.code_blocks;
|
|
15
16
|
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
16
|
-
|
|
17
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
17
18
|
if (tabRe.test(line) && (!inCode || includeCodeBlocks)) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
shared.rangeFromRegExp(line, tabRe));
|
|
19
|
+
addError(onError, lineIndex + 1, "Column: " + (line.indexOf("\t") + 1),
|
|
20
|
+
null, rangeFromRegExp(line, tabRe));
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
}
|
package/lib/md011.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addError, forEachInlineChild, rangeFromRegExp } = require("../helpers");
|
|
6
6
|
|
|
7
7
|
const reversedLinkRe = /\([^)]+\)\[[^\]^][^\]]*]/;
|
|
8
8
|
|
|
@@ -11,11 +11,11 @@ module.exports = {
|
|
|
11
11
|
"description": "Reversed link syntax",
|
|
12
12
|
"tags": [ "links" ],
|
|
13
13
|
"function": function MD011(params, onError) {
|
|
14
|
-
|
|
14
|
+
forEachInlineChild(params, "text", function forToken(token) {
|
|
15
15
|
const match = reversedLinkRe.exec(token.content);
|
|
16
16
|
if (match) {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
addError(onError, token.lineNumber, match[0], null,
|
|
18
|
+
rangeFromRegExp(token.line, reversedLinkRe));
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
}
|
package/lib/md012.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, forEachLine } = require("../helpers");
|
|
6
|
+
const { lineMetadata } = require("./cache");
|
|
6
7
|
|
|
7
8
|
module.exports = {
|
|
8
9
|
"names": [ "MD012", "no-multiple-blanks" ],
|
|
@@ -11,10 +12,10 @@ module.exports = {
|
|
|
11
12
|
"function": function MD012(params, onError) {
|
|
12
13
|
const maximum = params.config.maximum || 1;
|
|
13
14
|
let count = 0;
|
|
14
|
-
|
|
15
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
15
16
|
count = (inCode || line.trim().length) ? 0 : count + 1;
|
|
16
17
|
if (maximum < count) {
|
|
17
|
-
|
|
18
|
+
addErrorDetailIf(onError, lineIndex + 1, maximum, count);
|
|
18
19
|
}
|
|
19
20
|
});
|
|
20
21
|
}
|
package/lib/md013.js
CHANGED
|
@@ -2,9 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
|
|
6
|
+
includesSorted, rangeFromRegExp } = require("../helpers");
|
|
7
|
+
const { lineMetadata } = require("./cache");
|
|
6
8
|
|
|
9
|
+
const longLineRePrefix = "^(.{";
|
|
10
|
+
const longLineRePostfix = "})(.*\\s.*)$";
|
|
7
11
|
const labelRe = /^\s*\[.*[^\\]]:/;
|
|
12
|
+
const linkOnlyLineRe = /^[es]*lT?L[ES]*$/;
|
|
13
|
+
const tokenTypeMap = {
|
|
14
|
+
"em_open": "e",
|
|
15
|
+
"em_close": "E",
|
|
16
|
+
"link_open": "l",
|
|
17
|
+
"link_close": "L",
|
|
18
|
+
"strong_open": "s",
|
|
19
|
+
"strong_close": "S",
|
|
20
|
+
"text": "T"
|
|
21
|
+
};
|
|
8
22
|
|
|
9
23
|
module.exports = {
|
|
10
24
|
"names": [ "MD013", "line-length" ],
|
|
@@ -12,6 +26,11 @@ module.exports = {
|
|
|
12
26
|
"tags": [ "line_length" ],
|
|
13
27
|
"function": function MD013(params, onError) {
|
|
14
28
|
const lineLength = params.config.line_length || 80;
|
|
29
|
+
const headingLineLength = params.config.heading_line_length || lineLength;
|
|
30
|
+
const longLineRe =
|
|
31
|
+
new RegExp(longLineRePrefix + lineLength + longLineRePostfix);
|
|
32
|
+
const longHeadingLineRe =
|
|
33
|
+
new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix);
|
|
15
34
|
const codeBlocks = params.config.code_blocks;
|
|
16
35
|
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
17
36
|
const tables = params.config.tables;
|
|
@@ -22,45 +41,35 @@ module.exports = {
|
|
|
22
41
|
}
|
|
23
42
|
const includeHeadings = (headings === undefined) ? true : !!headings;
|
|
24
43
|
const headingLineNumbers = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
const tokenTypeMap = {
|
|
31
|
-
"em_open": "e",
|
|
32
|
-
"em_close": "E",
|
|
33
|
-
"link_open": "l",
|
|
34
|
-
"link_close": "L",
|
|
35
|
-
"strong_open": "s",
|
|
36
|
-
"strong_close": "S",
|
|
37
|
-
"text": "T"
|
|
38
|
-
};
|
|
44
|
+
forEachHeading(params, (heading) => {
|
|
45
|
+
headingLineNumbers.push(heading.lineNumber);
|
|
46
|
+
});
|
|
39
47
|
const linkOnlyLineNumbers = [];
|
|
40
|
-
|
|
48
|
+
filterTokens(params, "inline", (token) => {
|
|
41
49
|
let childTokenTypes = "";
|
|
42
|
-
token.children.forEach(
|
|
50
|
+
token.children.forEach((child) => {
|
|
43
51
|
if (child.type !== "text" || child.content !== "") {
|
|
44
52
|
childTokenTypes += tokenTypeMap[child.type] || "x";
|
|
45
53
|
}
|
|
46
54
|
});
|
|
47
|
-
if (
|
|
55
|
+
if (linkOnlyLineRe.test(childTokenTypes)) {
|
|
48
56
|
linkOnlyLineNumbers.push(token.lineNumber);
|
|
49
57
|
}
|
|
50
58
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
59
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
|
|
60
|
+
const lineNumber = lineIndex + 1;
|
|
61
|
+
const isHeading = includesSorted(headingLineNumbers, lineNumber);
|
|
62
|
+
const length = isHeading ? headingLineLength : lineLength;
|
|
63
|
+
const lengthRe = isHeading ? longHeadingLineRe : longLineRe;
|
|
64
|
+
if ((includeCodeBlocks || !inCode) &&
|
|
65
|
+
(includeTables || !inTable) &&
|
|
66
|
+
(includeHeadings || !isHeading) &&
|
|
67
|
+
!includesSorted(linkOnlyLineNumbers, lineNumber) &&
|
|
68
|
+
lengthRe.test(line) &&
|
|
69
|
+
!labelRe.test(line)) {
|
|
70
|
+
addErrorDetailIf(onError, lineNumber, length, line.length,
|
|
71
|
+
null, null, rangeFromRegExp(line, lengthRe));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
65
74
|
}
|
|
66
75
|
};
|
package/lib/md014.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorContext, filterTokens, newLineRe, rangeFromRegExp } =
|
|
6
|
+
require("../helpers");
|
|
6
7
|
|
|
7
8
|
const dollarCommandRe = /^(\s*)(\$\s)/;
|
|
8
9
|
|
|
@@ -12,15 +13,15 @@ module.exports = {
|
|
|
12
13
|
"tags": [ "code" ],
|
|
13
14
|
"function": function MD014(params, onError) {
|
|
14
15
|
[ "code_block", "fence" ].forEach(function forType(type) {
|
|
15
|
-
|
|
16
|
+
filterTokens(params, type, function forToken(token) {
|
|
16
17
|
let allBlank = true;
|
|
17
|
-
if (token.content && token.content.split(
|
|
18
|
+
if (token.content && token.content.split(newLineRe)
|
|
18
19
|
.every(function forLine(line) {
|
|
19
20
|
return !line || (allBlank = false) || dollarCommandRe.test(line);
|
|
20
21
|
}) && !allBlank) {
|
|
21
|
-
|
|
22
|
-
token.content.split(
|
|
23
|
-
|
|
22
|
+
addErrorContext(onError, token.lineNumber,
|
|
23
|
+
token.content.split(newLineRe)[0].trim(), null, null,
|
|
24
|
+
rangeFromRegExp(token.line, dollarCommandRe));
|
|
24
25
|
}
|
|
25
26
|
});
|
|
26
27
|
});
|
package/lib/md018.js
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorContext, atxHeadingSpaceRe, forEachLine,
|
|
6
|
+
rangeFromRegExp } = require("../helpers");
|
|
7
|
+
const { lineMetadata } = require("./cache");
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
"names": [ "MD018", "no-missing-space-atx" ],
|
|
9
11
|
"description": "No space after hash on atx style heading",
|
|
10
12
|
"tags": [ "headings", "headers", "atx", "spaces" ],
|
|
11
13
|
"function": function MD018(params, onError) {
|
|
12
|
-
|
|
14
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
13
15
|
if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) {
|
|
14
|
-
|
|
15
|
-
null,
|
|
16
|
+
addErrorContext(onError, lineIndex + 1, line.trim(), null,
|
|
17
|
+
null, rangeFromRegExp(line, atxHeadingSpaceRe));
|
|
16
18
|
}
|
|
17
19
|
});
|
|
18
20
|
}
|
package/lib/md019.js
CHANGED
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorContext, atxHeadingSpaceRe, filterTokens, headingStyleFor,
|
|
6
|
+
rangeFromRegExp } = require("../helpers");
|
|
6
7
|
|
|
7
8
|
module.exports = {
|
|
8
9
|
"names": [ "MD019", "no-multiple-space-atx" ],
|
|
9
10
|
"description": "Multiple spaces after hash on atx style heading",
|
|
10
11
|
"tags": [ "headings", "headers", "atx", "spaces" ],
|
|
11
12
|
"function": function MD019(params, onError) {
|
|
12
|
-
|
|
13
|
-
if ((
|
|
13
|
+
filterTokens(params, "heading_open", function forToken(token) {
|
|
14
|
+
if ((headingStyleFor(token) === "atx") &&
|
|
14
15
|
/^#+\s\s/.test(token.line)) {
|
|
15
|
-
|
|
16
|
+
addErrorContext(onError, token.lineNumber, token.line.trim(),
|
|
16
17
|
null, null,
|
|
17
|
-
|
|
18
|
+
rangeFromRegExp(token.line, atxHeadingSpaceRe));
|
|
18
19
|
}
|
|
19
20
|
});
|
|
20
21
|
}
|
package/lib/md020.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorContext, forEachLine, rangeFromRegExp } = require("../helpers");
|
|
6
|
+
const { lineMetadata } = require("./cache");
|
|
6
7
|
|
|
7
8
|
const atxClosedHeadingNoSpaceRe = /(?:^#+[^#\s])|(?:[^#\s]#+\s*$)/;
|
|
8
9
|
|
|
@@ -11,13 +12,13 @@ module.exports = {
|
|
|
11
12
|
"description": "No space inside hashes on closed atx style heading",
|
|
12
13
|
"tags": [ "headings", "headers", "atx_closed", "spaces" ],
|
|
13
14
|
"function": function MD020(params, onError) {
|
|
14
|
-
|
|
15
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
15
16
|
if (!inCode && /^#+[^#]*[^\\]#+$/.test(line)) {
|
|
16
17
|
const left = /^#+[^#\s]/.test(line);
|
|
17
18
|
const right = /[^#\s]#+$/.test(line);
|
|
18
19
|
if (left || right) {
|
|
19
|
-
|
|
20
|
-
right,
|
|
20
|
+
addErrorContext(onError, lineIndex + 1, line.trim(), left,
|
|
21
|
+
right, rangeFromRegExp(line, atxClosedHeadingNoSpaceRe));
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
});
|
package/lib/md021.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorContext, filterTokens, headingStyleFor, rangeFromRegExp } =
|
|
6
|
+
require("../helpers");
|
|
6
7
|
|
|
7
8
|
const atxClosedHeadingSpaceRe = /(?:^#+\s\s+?\S)|(?:\S\s\s+?#+\s*$)/;
|
|
8
9
|
|
|
@@ -11,14 +12,14 @@ module.exports = {
|
|
|
11
12
|
"description": "Multiple spaces inside hashes on closed atx style heading",
|
|
12
13
|
"tags": [ "headings", "headers", "atx_closed", "spaces" ],
|
|
13
14
|
"function": function MD021(params, onError) {
|
|
14
|
-
|
|
15
|
-
if (
|
|
15
|
+
filterTokens(params, "heading_open", function forToken(token) {
|
|
16
|
+
if (headingStyleFor(token) === "atx_closed") {
|
|
16
17
|
const left = /^#+\s\s/.test(token.line);
|
|
17
18
|
const right = /\s\s#+$/.test(token.line);
|
|
18
19
|
if (left || right) {
|
|
19
|
-
|
|
20
|
+
addErrorContext(onError, token.lineNumber, token.line.trim(),
|
|
20
21
|
left, right,
|
|
21
|
-
|
|
22
|
+
rangeFromRegExp(token.line, atxClosedHeadingSpaceRe));
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
});
|
package/lib/md022.js
CHANGED
|
@@ -2,37 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { addErrorDetailIf, filterTokens, isBlankLine } = require("../helpers");
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
"names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ],
|
|
9
9
|
"description": "Headings should be surrounded by blank lines",
|
|
10
10
|
"tags": [ "headings", "headers", "blank_lines" ],
|
|
11
11
|
"function": function MD022(params, onError) {
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
let linesAbove = params.config.lines_above;
|
|
13
|
+
if (linesAbove === undefined) {
|
|
14
|
+
linesAbove = 1;
|
|
15
|
+
}
|
|
16
|
+
let linesBelow = params.config.lines_below;
|
|
17
|
+
if (linesBelow === undefined) {
|
|
18
|
+
linesBelow = 1;
|
|
19
|
+
}
|
|
20
|
+
const { lines } = params;
|
|
21
|
+
filterTokens(params, "heading_open", (token) => {
|
|
22
|
+
const [ topIndex, nextIndex ] = token.map;
|
|
23
|
+
for (let i = 0; i < linesAbove; i++) {
|
|
24
|
+
if (!isBlankLine(lines[topIndex - i - 1])) {
|
|
25
|
+
addErrorDetailIf(onError, topIndex + 1, linesAbove, i, "Above",
|
|
26
|
+
lines[topIndex].trim());
|
|
27
|
+
return;
|
|
20
28
|
}
|
|
21
|
-
} else if (token.type === "heading_close") {
|
|
22
|
-
needBlankLine = true;
|
|
23
29
|
}
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
needBlankLine = false;
|
|
30
|
+
for (let i = 0; i < linesBelow; i++) {
|
|
31
|
+
if (!isBlankLine(lines[nextIndex + i])) {
|
|
32
|
+
addErrorDetailIf(onError, topIndex + 1, linesBelow, i, "Below",
|
|
33
|
+
lines[topIndex].trim());
|
|
34
|
+
return;
|
|
31
35
|
}
|
|
32
|
-
prevMaxLineIndex = Math.max(prevMaxLineIndex, token.map[1]);
|
|
33
|
-
}
|
|
34
|
-
if (token.type === "heading_open") {
|
|
35
|
-
prevHeadingLineNumber = token.lineNumber;
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
}
|