markdownlint 0.24.0 → 0.26.0
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/CONTRIBUTING.md +15 -3
- package/LICENSE +1 -1
- package/README.md +138 -87
- package/demo/markdownlint-browser.js +2028 -1364
- package/doc/CustomRules.md +15 -4
- package/doc/Rules.md +217 -26
- package/helpers/LICENSE +1 -1
- package/helpers/helpers.js +541 -188
- package/helpers/package.json +4 -1
- package/lib/cache.js +15 -25
- package/lib/constants.js +7 -0
- package/lib/markdownlint.d.ts +27 -19
- package/lib/markdownlint.js +438 -344
- package/lib/md004.js +4 -4
- package/lib/md005.js +4 -4
- package/lib/md006.js +4 -4
- package/lib/md007.js +8 -6
- package/lib/md009.js +20 -13
- package/lib/md010.js +34 -16
- package/lib/md011.js +4 -4
- package/lib/md013.js +4 -5
- package/lib/md014.js +4 -4
- package/lib/md021.js +3 -1
- package/lib/md026.js +1 -1
- package/lib/md027.js +2 -2
- package/lib/md028.js +2 -2
- package/lib/md029.js +5 -4
- package/lib/md030.js +4 -4
- package/lib/md031.js +2 -2
- package/lib/md032.js +3 -2
- package/lib/md033.js +12 -9
- package/lib/md034.js +2 -2
- package/lib/md035.js +10 -5
- package/lib/md036.js +2 -2
- package/lib/md037.js +5 -3
- package/lib/md038.js +7 -4
- package/lib/md039.js +8 -5
- package/lib/md042.js +17 -10
- package/lib/md043.js +2 -3
- package/lib/md044.js +21 -10
- package/lib/md046.js +14 -13
- package/lib/md048.js +13 -14
- package/lib/md049-md050.js +73 -0
- package/lib/md051.js +84 -0
- package/lib/md052.js +35 -0
- package/lib/md053.js +52 -0
- package/lib/rules.js +8 -6
- package/package.json +37 -32
- package/schema/.markdownlint.jsonc +30 -3
- package/schema/.markdownlint.yaml +26 -1
- package/schema/markdownlint-config-schema.json +159 -683
package/lib/md004.js
CHANGED
|
@@ -26,12 +26,12 @@ module.exports = {
|
|
|
26
26
|
const style = String(params.config.style || "consistent");
|
|
27
27
|
let expectedStyle = style;
|
|
28
28
|
const nestingStyles = [];
|
|
29
|
-
flattenedLists()
|
|
29
|
+
for (const list of flattenedLists()) {
|
|
30
30
|
if (list.unordered) {
|
|
31
31
|
if (expectedStyle === "consistent") {
|
|
32
32
|
expectedStyle = unorderedListStyleFor(list.items[0]);
|
|
33
33
|
}
|
|
34
|
-
list.items
|
|
34
|
+
for (const item of list.items) {
|
|
35
35
|
const itemStyle = unorderedListStyleFor(item);
|
|
36
36
|
if (style === "sublist") {
|
|
37
37
|
const nesting = list.nesting;
|
|
@@ -69,8 +69,8 @@ module.exports = {
|
|
|
69
69
|
range,
|
|
70
70
|
fixInfo
|
|
71
71
|
);
|
|
72
|
-
}
|
|
72
|
+
}
|
|
73
73
|
}
|
|
74
|
-
}
|
|
74
|
+
}
|
|
75
75
|
}
|
|
76
76
|
};
|
package/lib/md005.js
CHANGED
|
@@ -11,12 +11,12 @@ module.exports = {
|
|
|
11
11
|
"description": "Inconsistent indentation for list items at the same level",
|
|
12
12
|
"tags": [ "bullet", "ul", "indentation" ],
|
|
13
13
|
"function": function MD005(params, onError) {
|
|
14
|
-
flattenedLists()
|
|
14
|
+
for (const list of flattenedLists()) {
|
|
15
15
|
const expectedIndent = list.indent;
|
|
16
16
|
let expectedEnd = 0;
|
|
17
17
|
let actualEnd = -1;
|
|
18
18
|
let endMatching = false;
|
|
19
|
-
list.items
|
|
19
|
+
for (const item of list.items) {
|
|
20
20
|
const { line, lineNumber } = item;
|
|
21
21
|
const actualIndent = indentFor(item);
|
|
22
22
|
let match = null;
|
|
@@ -63,7 +63,7 @@ module.exports = {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
68
|
}
|
|
69
69
|
};
|
package/lib/md006.js
CHANGED
|
@@ -12,9 +12,9 @@ module.exports = {
|
|
|
12
12
|
"Consider starting bulleted lists at the beginning of the line",
|
|
13
13
|
"tags": [ "bullet", "ul", "indentation" ],
|
|
14
14
|
"function": function MD006(params, onError) {
|
|
15
|
-
flattenedLists()
|
|
15
|
+
for (const list of flattenedLists()) {
|
|
16
16
|
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
|
17
|
-
list.items
|
|
17
|
+
for (const item of list.items) {
|
|
18
18
|
const { lineNumber, line } = item;
|
|
19
19
|
addErrorDetailIf(
|
|
20
20
|
onError,
|
|
@@ -27,8 +27,8 @@ module.exports = {
|
|
|
27
27
|
{
|
|
28
28
|
"deleteCount": line.length - line.trimStart().length
|
|
29
29
|
});
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
}
|
|
32
|
-
}
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
};
|
package/lib/md007.js
CHANGED
|
@@ -13,12 +13,14 @@ module.exports = {
|
|
|
13
13
|
"function": function MD007(params, onError) {
|
|
14
14
|
const indent = Number(params.config.indent || 2);
|
|
15
15
|
const startIndented = !!params.config.start_indented;
|
|
16
|
-
|
|
16
|
+
const startIndent = Number(params.config.start_indent || indent);
|
|
17
|
+
for (const list of flattenedLists()) {
|
|
17
18
|
if (list.unordered && list.parentsUnordered) {
|
|
18
|
-
list.items
|
|
19
|
+
for (const item of list.items) {
|
|
19
20
|
const { lineNumber, line } = item;
|
|
20
|
-
const
|
|
21
|
-
|
|
21
|
+
const expectedIndent =
|
|
22
|
+
(startIndented ? startIndent : 0) +
|
|
23
|
+
(list.nesting * indent);
|
|
22
24
|
const actualIndent = indentFor(item);
|
|
23
25
|
let range = null;
|
|
24
26
|
let editColumn = 1;
|
|
@@ -40,8 +42,8 @@ module.exports = {
|
|
|
40
42
|
"deleteCount": actualIndent,
|
|
41
43
|
"insertText": "".padEnd(expectedIndent)
|
|
42
44
|
});
|
|
43
|
-
}
|
|
45
|
+
}
|
|
44
46
|
}
|
|
45
|
-
}
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
};
|
package/lib/md009.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError, filterTokens,
|
|
6
|
-
|
|
5
|
+
const { addError, filterTokens, forEachLine, includesSorted,
|
|
6
|
+
numericSortAscending } = require("../helpers");
|
|
7
7
|
const { lineMetadata } = require("./cache");
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
@@ -32,19 +32,26 @@ module.exports = {
|
|
|
32
32
|
paragraphLineNumbers.push(i + 1);
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
-
|
|
35
|
+
const addLineNumberRange = (start, end) => {
|
|
36
|
+
for (let i = start; i < end; i++) {
|
|
37
|
+
codeInlineLineNumbers.push(i);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
36
40
|
filterTokens(params, "inline", (token) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
let start = 0;
|
|
42
|
+
for (const child of token.children) {
|
|
43
|
+
if (start > 0) {
|
|
44
|
+
addLineNumberRange(start, child.lineNumber);
|
|
45
|
+
start = 0;
|
|
46
|
+
}
|
|
47
|
+
if (child.type === "code_inline") {
|
|
48
|
+
start = child.lineNumber;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (start > 0) {
|
|
52
|
+
addLineNumberRange(start, token.map[1]);
|
|
45
53
|
}
|
|
46
54
|
});
|
|
47
|
-
codeInlineLineNumbers.sort(numericSortAscending);
|
|
48
55
|
}
|
|
49
56
|
const expected = (brSpaces < 2) ? 0 : brSpaces;
|
|
50
57
|
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
@@ -67,7 +74,7 @@ module.exports = {
|
|
|
67
74
|
lineNumber,
|
|
68
75
|
"Expected: " + (expected === 0 ? "" : "0 or ") +
|
|
69
76
|
expected + "; Actual: " + trailingSpaces,
|
|
70
|
-
|
|
77
|
+
undefined,
|
|
71
78
|
[ column, trailingSpaces ],
|
|
72
79
|
{
|
|
73
80
|
"editColumn": column,
|
package/lib/md010.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError, forEachLine } =
|
|
6
|
-
|
|
5
|
+
const { addError, filterTokens, forEachLine, withinAnyRange } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
const { codeBlockAndSpanRanges, lineMetadata } = require("./cache");
|
|
7
8
|
|
|
8
9
|
const tabRe = /\t+/g;
|
|
9
10
|
|
|
@@ -13,28 +14,45 @@ module.exports = {
|
|
|
13
14
|
"tags": [ "whitespace", "hard_tab" ],
|
|
14
15
|
"function": function MD010(params, onError) {
|
|
15
16
|
const codeBlocks = params.config.code_blocks;
|
|
16
|
-
const
|
|
17
|
+
const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
18
|
+
const ignoreCodeLanguages = new Set(
|
|
19
|
+
(params.config.ignore_code_languages || [])
|
|
20
|
+
.map((language) => language.toLowerCase())
|
|
21
|
+
);
|
|
17
22
|
const spacesPerTab = params.config.spaces_per_tab;
|
|
18
23
|
const spaceMultiplier = (spacesPerTab === undefined) ?
|
|
19
24
|
1 :
|
|
20
25
|
Math.max(0, Number(spacesPerTab));
|
|
26
|
+
const exclusions = includeCode ? [] : codeBlockAndSpanRanges();
|
|
27
|
+
filterTokens(params, "fence", (token) => {
|
|
28
|
+
const language = token.info.trim().toLowerCase();
|
|
29
|
+
if (ignoreCodeLanguages.has(language)) {
|
|
30
|
+
for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
|
|
31
|
+
exclusions.push([ i, 0, params.lines[i].length ]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
21
35
|
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
22
|
-
if (
|
|
36
|
+
if (includeCode || !inCode) {
|
|
23
37
|
let match = null;
|
|
24
38
|
while ((match = tabRe.exec(line)) !== null) {
|
|
25
|
-
const
|
|
39
|
+
const { index } = match;
|
|
40
|
+
const column = index + 1;
|
|
26
41
|
const length = match[0].length;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
if (!withinAnyRange(exclusions, lineIndex, index, length)) {
|
|
43
|
+
addError(
|
|
44
|
+
onError,
|
|
45
|
+
lineIndex + 1,
|
|
46
|
+
"Column: " + column,
|
|
47
|
+
null,
|
|
48
|
+
[ column, length ],
|
|
49
|
+
{
|
|
50
|
+
"editColumn": column,
|
|
51
|
+
"deleteCount": length,
|
|
52
|
+
"insertText": "".padEnd(length * spaceMultiplier)
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
38
56
|
}
|
|
39
57
|
}
|
|
40
58
|
});
|
package/lib/md011.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError, forEachLine,
|
|
6
|
-
const {
|
|
5
|
+
const { addError, forEachLine, withinAnyRange } = require("../helpers");
|
|
6
|
+
const { codeBlockAndSpanRanges, lineMetadata } = require("./cache");
|
|
7
7
|
|
|
8
8
|
const reversedLinkRe =
|
|
9
9
|
/(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g;
|
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
|
13
13
|
"description": "Reversed link syntax",
|
|
14
14
|
"tags": [ "links" ],
|
|
15
15
|
"function": function MD011(params, onError) {
|
|
16
|
-
const exclusions =
|
|
16
|
+
const exclusions = codeBlockAndSpanRanges();
|
|
17
17
|
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => {
|
|
18
18
|
if (!inCode && !onFence) {
|
|
19
19
|
let match = null;
|
|
@@ -24,7 +24,7 @@ module.exports = {
|
|
|
24
24
|
if (
|
|
25
25
|
!linkText.endsWith("\\") &&
|
|
26
26
|
!linkDestination.endsWith("\\") &&
|
|
27
|
-
!
|
|
27
|
+
!withinAnyRange(exclusions, lineIndex, index, length)
|
|
28
28
|
) {
|
|
29
29
|
addError(
|
|
30
30
|
onError,
|
package/lib/md013.js
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
|
|
6
|
-
includesSorted } = require("../helpers");
|
|
6
|
+
includesSorted, linkReferenceDefinitionRe } = require("../helpers");
|
|
7
7
|
const { lineMetadata } = require("./cache");
|
|
8
8
|
|
|
9
9
|
const longLineRePrefix = "^.{";
|
|
10
10
|
const longLineRePostfixRelaxed = "}.*\\s.*$";
|
|
11
11
|
const longLineRePostfixStrict = "}.+$";
|
|
12
|
-
const labelRe = /^\s*\[.*[^\\]]:/;
|
|
13
12
|
const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/;
|
|
14
13
|
const sternModeRe = /^([#>\s]*\s)?\S*$/;
|
|
15
14
|
const tokenTypeMap = {
|
|
@@ -59,11 +58,11 @@ module.exports = {
|
|
|
59
58
|
const linkOnlyLineNumbers = [];
|
|
60
59
|
filterTokens(params, "inline", (token) => {
|
|
61
60
|
let childTokenTypes = "";
|
|
62
|
-
token.children
|
|
61
|
+
for (const child of token.children) {
|
|
63
62
|
if (child.type !== "text" || child.content !== "") {
|
|
64
63
|
childTokenTypes += tokenTypeMap[child.type] || "x";
|
|
65
64
|
}
|
|
66
|
-
}
|
|
65
|
+
}
|
|
67
66
|
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
|
68
67
|
linkOnlyLineNumbers.push(token.lineNumber);
|
|
69
68
|
}
|
|
@@ -83,7 +82,7 @@ module.exports = {
|
|
|
83
82
|
(strict ||
|
|
84
83
|
(!(stern && sternModeRe.test(line)) &&
|
|
85
84
|
!includesSorted(linkOnlyLineNumbers, lineNumber) &&
|
|
86
|
-
!
|
|
85
|
+
!linkReferenceDefinitionRe.test(line))) &&
|
|
87
86
|
lengthRe.test(line)) {
|
|
88
87
|
addErrorDetailIf(
|
|
89
88
|
onError,
|
package/lib/md014.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
"description": "Dollar signs used before commands without showing output",
|
|
12
12
|
"tags": [ "code" ],
|
|
13
13
|
"function": function MD014(params, onError) {
|
|
14
|
-
[ "code_block", "fence" ]
|
|
14
|
+
for (const type of [ "code_block", "fence" ]) {
|
|
15
15
|
filterTokens(params, type, (token) => {
|
|
16
16
|
const margin = (token.type === "fence") ? 1 : 0;
|
|
17
17
|
const dollarInstances = [];
|
|
@@ -31,7 +31,7 @@ module.exports = {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
if (allDollars) {
|
|
34
|
-
|
|
34
|
+
for (const instance of dollarInstances) {
|
|
35
35
|
const [ i, lineTrim, column, length ] = instance;
|
|
36
36
|
addErrorContext(
|
|
37
37
|
onError,
|
|
@@ -45,9 +45,9 @@ module.exports = {
|
|
|
45
45
|
"deleteCount": length
|
|
46
46
|
}
|
|
47
47
|
);
|
|
48
|
-
}
|
|
48
|
+
}
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
|
-
}
|
|
51
|
+
}
|
|
52
52
|
}
|
|
53
53
|
};
|
package/lib/md021.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
const { addErrorContext, filterTokens, headingStyleFor } =
|
|
6
6
|
require("../helpers");
|
|
7
7
|
|
|
8
|
+
const closedAtxRe = /^(#+)([ \t]+)([^ \t]|[^ \t].*[^ \t])([ \t]+)(#+)(\s*)$/;
|
|
9
|
+
|
|
8
10
|
module.exports = {
|
|
9
11
|
"names": [ "MD021", "no-multiple-space-closed-atx" ],
|
|
10
12
|
"description": "Multiple spaces inside hashes on closed atx style heading",
|
|
@@ -13,7 +15,7 @@ module.exports = {
|
|
|
13
15
|
filterTokens(params, "heading_open", (token) => {
|
|
14
16
|
if (headingStyleFor(token) === "atx_closed") {
|
|
15
17
|
const { line, lineNumber } = token;
|
|
16
|
-
const match =
|
|
18
|
+
const match = closedAtxRe.exec(line);
|
|
17
19
|
if (match) {
|
|
18
20
|
const [
|
|
19
21
|
,
|
package/lib/md026.js
CHANGED
|
@@ -20,7 +20,7 @@ module.exports = {
|
|
|
20
20
|
new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
|
|
21
21
|
forEachHeading(params, (heading) => {
|
|
22
22
|
const { line, lineNumber } = heading;
|
|
23
|
-
const trimmedLine = line.replace(/[\s#]
|
|
23
|
+
const trimmedLine = line.replace(/([^\s#])[\s#]+$/, "$1");
|
|
24
24
|
const match = trailingPunctuationRe.exec(trimmedLine);
|
|
25
25
|
if (match && !endOfLineHtmlEntityRe.test(trimmedLine)) {
|
|
26
26
|
const fullMatch = match[0];
|
package/lib/md027.js
CHANGED
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
|
13
13
|
"function": function MD027(params, onError) {
|
|
14
14
|
let blockquoteNesting = 0;
|
|
15
15
|
let listItemNesting = 0;
|
|
16
|
-
params.tokens
|
|
16
|
+
for (const token of params.tokens) {
|
|
17
17
|
const { content, lineNumber, type } = token;
|
|
18
18
|
if (type === "blockquote_open") {
|
|
19
19
|
blockquoteNesting++;
|
|
@@ -51,6 +51,6 @@ module.exports = {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
55
|
}
|
|
56
56
|
};
|
package/lib/md028.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
"function": function MD028(params, onError) {
|
|
12
12
|
let prevToken = {};
|
|
13
13
|
let prevLineNumber = null;
|
|
14
|
-
params.tokens
|
|
14
|
+
for (const token of params.tokens) {
|
|
15
15
|
if ((token.type === "blockquote_open") &&
|
|
16
16
|
(prevToken.type === "blockquote_close")) {
|
|
17
17
|
for (
|
|
@@ -25,6 +25,6 @@ module.exports = {
|
|
|
25
25
|
if (token.type === "blockquote_open") {
|
|
26
26
|
prevLineNumber = token.map[1] + 1;
|
|
27
27
|
}
|
|
28
|
-
}
|
|
28
|
+
}
|
|
29
29
|
}
|
|
30
30
|
};
|
package/lib/md029.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = {
|
|
|
18
18
|
"tags": [ "ol" ],
|
|
19
19
|
"function": function MD029(params, onError) {
|
|
20
20
|
const style = String(params.config.style || "one_or_ordered");
|
|
21
|
-
flattenedLists().filter((list) => !list.unordered)
|
|
21
|
+
const filteredLists = flattenedLists().filter((list) => !list.unordered);
|
|
22
|
+
for (const list of filteredLists) {
|
|
22
23
|
const { items } = list;
|
|
23
24
|
let current = 1;
|
|
24
25
|
let incrementing = false;
|
|
@@ -49,7 +50,7 @@ module.exports = {
|
|
|
49
50
|
current = 1;
|
|
50
51
|
}
|
|
51
52
|
// Validate each list item marker
|
|
52
|
-
|
|
53
|
+
for (const item of items) {
|
|
53
54
|
const match = orderedListItemMarkerRe.exec(item.line);
|
|
54
55
|
if (match) {
|
|
55
56
|
addErrorDetailIf(onError, item.lineNumber,
|
|
@@ -60,7 +61,7 @@ module.exports = {
|
|
|
60
61
|
current++;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
65
66
|
}
|
|
66
67
|
};
|
package/lib/md030.js
CHANGED
|
@@ -14,13 +14,13 @@ module.exports = {
|
|
|
14
14
|
const olSingle = Number(params.config.ol_single || 1);
|
|
15
15
|
const ulMulti = Number(params.config.ul_multi || 1);
|
|
16
16
|
const olMulti = Number(params.config.ol_multi || 1);
|
|
17
|
-
flattenedLists()
|
|
17
|
+
for (const list of flattenedLists()) {
|
|
18
18
|
const lineCount = list.lastLineIndex - list.open.map[0];
|
|
19
19
|
const allSingle = lineCount === list.items.length;
|
|
20
20
|
const expectedSpaces = list.unordered ?
|
|
21
21
|
(allSingle ? ulSingle : ulMulti) :
|
|
22
22
|
(allSingle ? olSingle : olMulti);
|
|
23
|
-
list.items
|
|
23
|
+
for (const item of list.items) {
|
|
24
24
|
const { line, lineNumber } = item;
|
|
25
25
|
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
|
26
26
|
const [ { "length": matchLength }, { "length": actualSpaces } ] = match;
|
|
@@ -44,7 +44,7 @@ module.exports = {
|
|
|
44
44
|
fixInfo
|
|
45
45
|
);
|
|
46
46
|
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
49
|
}
|
|
50
50
|
};
|
package/lib/md031.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const { addErrorContext, forEachLine, isBlankLine } = require("../helpers");
|
|
6
6
|
const { lineMetadata } = require("./cache");
|
|
7
7
|
|
|
8
|
-
const codeFencePrefixRe = /^(.*?)
|
|
8
|
+
const codeFencePrefixRe = /^(.*?)[`~]/;
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
11
|
"names": [ "MD031", "blanks-around-fences" ],
|
|
@@ -24,7 +24,7 @@ module.exports = {
|
|
|
24
24
|
const [ , prefix ] = line.match(codeFencePrefixRe) || [];
|
|
25
25
|
const fixInfo = (prefix === undefined) ? null : {
|
|
26
26
|
"lineNumber": i + (onTopFence ? 1 : 2),
|
|
27
|
-
"insertText": `${prefix}\n`
|
|
27
|
+
"insertText": `${prefix.replace(/[^>]/g, " ").trim()}\n`
|
|
28
28
|
};
|
|
29
29
|
addErrorContext(
|
|
30
30
|
onError,
|
package/lib/md032.js
CHANGED
|
@@ -13,7 +13,8 @@ module.exports = {
|
|
|
13
13
|
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
|
|
14
14
|
"function": function MD032(params, onError) {
|
|
15
15
|
const { lines } = params;
|
|
16
|
-
flattenedLists().filter((list) => !list.nesting)
|
|
16
|
+
const filteredLists = flattenedLists().filter((list) => !list.nesting);
|
|
17
|
+
for (const list of filteredLists) {
|
|
17
18
|
const firstIndex = list.open.map[0];
|
|
18
19
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
|
19
20
|
const line = lines[firstIndex];
|
|
@@ -45,6 +46,6 @@ module.exports = {
|
|
|
45
46
|
"insertText": `${quotePrefix}\n`
|
|
46
47
|
});
|
|
47
48
|
}
|
|
48
|
-
}
|
|
49
|
+
}
|
|
49
50
|
}
|
|
50
51
|
};
|
package/lib/md033.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const {
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown
|
|
7
|
+
} = require("../helpers");
|
|
8
|
+
const { codeBlockAndSpanRanges, lineMetadata } = require("./cache");
|
|
7
9
|
|
|
8
|
-
const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?)\/?>/g;
|
|
9
10
|
const linkDestinationRe = /]\(\s*$/;
|
|
10
|
-
const inlineCodeRe = /^[^`]*(`+[^`]+`+[^`]+)*`+[^`]*$/;
|
|
11
11
|
// See https://spec.commonmark.org/0.29/#autolinks
|
|
12
12
|
const emailAddressRe =
|
|
13
13
|
// eslint-disable-next-line max-len
|
|
@@ -21,19 +21,22 @@ module.exports = {
|
|
|
21
21
|
let allowedElements = params.config.allowed_elements;
|
|
22
22
|
allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
|
|
23
23
|
allowedElements = allowedElements.map((element) => element.toLowerCase());
|
|
24
|
+
const exclusions = codeBlockAndSpanRanges();
|
|
24
25
|
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
25
26
|
let match = null;
|
|
26
27
|
// eslint-disable-next-line no-unmodified-loop-condition
|
|
27
28
|
while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) {
|
|
28
29
|
const [ tag, content, element ] = match;
|
|
29
|
-
if (
|
|
30
|
+
if (
|
|
31
|
+
!allowedElements.includes(element.toLowerCase()) &&
|
|
30
32
|
!tag.endsWith("\\>") &&
|
|
31
|
-
!emailAddressRe.test(content)
|
|
33
|
+
!emailAddressRe.test(content) &&
|
|
34
|
+
!withinAnyRange(exclusions, lineIndex, match.index, match[0].length)
|
|
35
|
+
) {
|
|
32
36
|
const prefix = line.substring(0, match.index);
|
|
33
|
-
if (!linkDestinationRe.test(prefix)
|
|
37
|
+
if (!linkDestinationRe.test(prefix)) {
|
|
34
38
|
const unescaped = unescapeMarkdown(prefix + "<", "_");
|
|
35
|
-
if (!unescaped.endsWith("_")
|
|
36
|
-
((unescaped + "`").match(/`/g).length % 2)) {
|
|
39
|
+
if (!unescaped.endsWith("_")) {
|
|
37
40
|
addError(onError, lineIndex + 1, "Element: " + element,
|
|
38
41
|
null, [ match.index + 1, tag.length ]);
|
|
39
42
|
}
|
package/lib/md034.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
"function": function MD034(params, onError) {
|
|
12
12
|
filterTokens(params, "inline", (token) => {
|
|
13
13
|
let inLink = false;
|
|
14
|
-
token.children
|
|
14
|
+
for (const child of token.children) {
|
|
15
15
|
const { content, line, lineNumber, type } = child;
|
|
16
16
|
let match = null;
|
|
17
17
|
if (type === "link_open") {
|
|
@@ -55,7 +55,7 @@ module.exports = {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
};
|
package/lib/md035.js
CHANGED
|
@@ -9,13 +9,18 @@ module.exports = {
|
|
|
9
9
|
"description": "Horizontal rule style",
|
|
10
10
|
"tags": [ "hr" ],
|
|
11
11
|
"function": function MD035(params, onError) {
|
|
12
|
-
let style = String(params.config.style || "consistent");
|
|
13
|
-
filterTokens(params, "hr",
|
|
14
|
-
const
|
|
12
|
+
let style = String(params.config.style || "consistent").trim();
|
|
13
|
+
filterTokens(params, "hr", (token) => {
|
|
14
|
+
const { line, lineNumber } = token;
|
|
15
|
+
let { markup } = token;
|
|
16
|
+
const match = line.match(/[_*\-\s\t]+$/);
|
|
17
|
+
if (match) {
|
|
18
|
+
markup = match[0].trim();
|
|
19
|
+
}
|
|
15
20
|
if (style === "consistent") {
|
|
16
|
-
style =
|
|
21
|
+
style = markup;
|
|
17
22
|
}
|
|
18
|
-
addErrorDetailIf(onError,
|
|
23
|
+
addErrorDetailIf(onError, lineNumber, style, markup);
|
|
19
24
|
});
|
|
20
25
|
}
|
|
21
26
|
};
|
package/lib/md036.js
CHANGED
package/lib/md037.js
CHANGED
|
@@ -7,6 +7,7 @@ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } =
|
|
|
7
7
|
const { lineMetadata } = require("./cache");
|
|
8
8
|
|
|
9
9
|
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
|
|
10
|
+
const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
|
|
10
11
|
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
11
12
|
const leftSpaceRe = /^\s+/;
|
|
12
13
|
const rightSpaceRe = /\s+$/;
|
|
@@ -98,14 +99,15 @@ module.exports = {
|
|
|
98
99
|
// Emphasis has no meaning here
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
102
|
+
let patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2");
|
|
101
103
|
if (onItemStart) {
|
|
102
104
|
// Trim overlapping '*' list item marker
|
|
103
|
-
|
|
105
|
+
patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
104
106
|
}
|
|
105
107
|
let match = null;
|
|
106
108
|
// Match all emphasis-looking runs in the line...
|
|
107
|
-
while ((match = emphasisRe.exec(
|
|
108
|
-
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex]
|
|
109
|
+
while ((match = emphasisRe.exec(patchedLine))) {
|
|
110
|
+
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex];
|
|
109
111
|
const matchIndex = match.index + match[1].length;
|
|
110
112
|
if (ignoreMarkersForLine.includes(matchIndex)) {
|
|
111
113
|
// Ignore emphasis markers inside code spans and links
|
package/lib/md038.js
CHANGED
|
@@ -7,7 +7,11 @@ const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } =
|
|
|
7
7
|
|
|
8
8
|
const leftSpaceRe = /^\s([^`]|$)/;
|
|
9
9
|
const rightSpaceRe = /[^`]\s$/;
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
const spaceInsideCodeInline = (token) => (
|
|
12
|
+
(token.type === "code_inline") &&
|
|
13
|
+
(leftSpaceRe.test(token.content) || rightSpaceRe.test(token.content))
|
|
14
|
+
);
|
|
11
15
|
|
|
12
16
|
module.exports = {
|
|
13
17
|
"names": [ "MD038", "no-space-in-code" ],
|
|
@@ -15,7 +19,7 @@ module.exports = {
|
|
|
15
19
|
"tags": [ "whitespace", "code" ],
|
|
16
20
|
"function": function MD038(params, onError) {
|
|
17
21
|
filterTokens(params, "inline", (token) => {
|
|
18
|
-
if (token.children.some(
|
|
22
|
+
if (token.children.some(spaceInsideCodeInline)) {
|
|
19
23
|
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
|
20
24
|
forEachInlineCodeSpan(
|
|
21
25
|
tokenLines.join("\n"),
|
|
@@ -33,8 +37,7 @@ module.exports = {
|
|
|
33
37
|
rangeLineOffset = codeLines.length - 1;
|
|
34
38
|
fixIndex = 0;
|
|
35
39
|
}
|
|
36
|
-
|
|
37
|
-
if ((left || right) && !allowed) {
|
|
40
|
+
if (left || right) {
|
|
38
41
|
const codeLinesRange = codeLines[rangeLineOffset];
|
|
39
42
|
if (codeLines.length > 1) {
|
|
40
43
|
rangeLength = codeLinesRange.length + tickCount;
|