markdownlint 0.34.0 → 0.35.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/CHANGELOG.md +11 -0
- package/README.md +25 -10
- package/demo/markdownlint-browser.js +1144 -1166
- package/doc/CustomRules.md +11 -6
- package/doc/Rules.md +66 -0
- package/doc/md034.md +5 -0
- package/doc/md044.md +10 -0
- package/doc/md058.md +48 -0
- package/helpers/README.md +3 -29
- package/helpers/helpers.js +56 -288
- package/helpers/micromark.cjs +111 -12
- package/helpers/package.json +1 -1
- package/lib/cache.js +62 -13
- package/lib/configuration-strict.d.ts +1185 -0
- package/lib/configuration.d.ts +3 -1173
- package/lib/constants.js +3 -2
- package/lib/markdownlint.d.ts +65 -56
- package/lib/markdownlint.js +59 -37
- package/lib/md001.js +15 -9
- package/lib/md003.js +14 -9
- package/lib/md004.js +55 -48
- package/lib/md005.js +4 -13
- package/lib/md007.js +5 -9
- package/lib/md009.js +50 -44
- package/lib/md010.js +48 -33
- package/lib/md011.js +16 -8
- package/lib/md012.js +17 -9
- package/lib/md013.js +44 -38
- package/lib/md014.js +35 -38
- package/lib/md018.js +17 -9
- package/lib/md019-md021.js +80 -0
- package/lib/md020.js +13 -7
- package/lib/md022.js +6 -16
- package/lib/md023.js +22 -23
- package/lib/md024.js +12 -9
- package/lib/md025.js +15 -10
- package/lib/md026.js +2 -7
- package/lib/md027.js +5 -10
- package/lib/md028.js +3 -8
- package/lib/md029.js +40 -34
- package/lib/md030.js +4 -10
- package/lib/md031.js +43 -23
- package/lib/md032.js +16 -26
- package/lib/md033.js +3 -8
- package/lib/md034.js +5 -10
- package/lib/md035.js +2 -7
- package/lib/md036.js +3 -2
- package/lib/md037.js +2 -7
- package/lib/md038.js +3 -9
- package/lib/md039.js +66 -54
- package/lib/md040.js +3 -8
- package/lib/md041.js +1 -1
- package/lib/md042.js +48 -38
- package/lib/md043.js +20 -14
- package/lib/md044.js +3 -8
- package/lib/md045.js +3 -8
- package/lib/md046.js +2 -8
- package/lib/md048.js +3 -7
- package/lib/md049-md050.js +2 -7
- package/lib/md051.js +6 -12
- package/lib/md052.js +2 -2
- package/lib/md053.js +2 -2
- package/lib/md054.js +8 -13
- package/lib/md055.js +7 -8
- package/lib/md056.js +15 -11
- package/lib/md058.js +43 -0
- package/lib/rules.js +11 -4
- package/package.json +19 -17
- package/schema/.markdownlint.jsonc +54 -51
- package/schema/.markdownlint.yaml +53 -50
- package/schema/ValidatingConfiguration.md +6 -8
- package/schema/markdownlint-config-schema-strict.json +1819 -0
- package/schema/markdownlint-config-schema.json +115 -105
- package/style/prettier.json +1 -0
- package/lib/md019.js +0 -42
- package/lib/md021.js +0 -65
package/lib/md032.js
CHANGED
|
@@ -2,28 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { addErrorContextForLine, isBlankLine } = require("../helpers");
|
|
6
6
|
const { filterByPredicate, nonContentTokens } = require("../helpers/micromark.cjs");
|
|
7
7
|
|
|
8
8
|
const isList = (token) => (
|
|
9
9
|
(token.type === "listOrdered") || (token.type === "listUnordered")
|
|
10
10
|
);
|
|
11
|
-
const addBlankLineError = (onError, lines, lineIndex, lineNumber) => {
|
|
12
|
-
const line = lines[lineIndex];
|
|
13
|
-
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
14
|
-
addErrorContext(
|
|
15
|
-
onError,
|
|
16
|
-
lineIndex + 1,
|
|
17
|
-
line.trim(),
|
|
18
|
-
null,
|
|
19
|
-
null,
|
|
20
|
-
null,
|
|
21
|
-
{
|
|
22
|
-
lineNumber,
|
|
23
|
-
"insertText": `${quotePrefix}\n`
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
11
|
|
|
28
12
|
// eslint-disable-next-line jsdoc/valid-types
|
|
29
13
|
/** @type import("./markdownlint").Rule */
|
|
@@ -33,16 +17,11 @@ module.exports = {
|
|
|
33
17
|
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
|
|
34
18
|
"parser": "micromark",
|
|
35
19
|
"function": function MD032(params, onError) {
|
|
36
|
-
|
|
37
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
38
|
-
const micromarkTokens =
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
params.parsers.micromark.tokens;
|
|
41
|
-
const { lines } = params;
|
|
20
|
+
const { lines, parsers } = params;
|
|
42
21
|
|
|
43
22
|
// For every top-level list...
|
|
44
23
|
const topLevelLists = filterByPredicate(
|
|
45
|
-
|
|
24
|
+
parsers.micromark.tokens,
|
|
46
25
|
isList,
|
|
47
26
|
(token) => (
|
|
48
27
|
(isList(token) || (token.type === "htmlFlow")) ? [] : token.children
|
|
@@ -53,7 +32,12 @@ module.exports = {
|
|
|
53
32
|
// Look for a blank line above the list
|
|
54
33
|
const firstIndex = list.startLine - 1;
|
|
55
34
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
|
56
|
-
|
|
35
|
+
addErrorContextForLine(
|
|
36
|
+
onError,
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
lines,
|
|
39
|
+
firstIndex
|
|
40
|
+
);
|
|
57
41
|
}
|
|
58
42
|
|
|
59
43
|
// Find the "visual" end of the list
|
|
@@ -69,7 +53,13 @@ module.exports = {
|
|
|
69
53
|
// Look for a blank line below the list
|
|
70
54
|
const lastIndex = endLine - 1;
|
|
71
55
|
if (!isBlankLine(lines[lastIndex + 1])) {
|
|
72
|
-
|
|
56
|
+
addErrorContextForLine(
|
|
57
|
+
onError,
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
lines,
|
|
60
|
+
lastIndex,
|
|
61
|
+
lastIndex + 2
|
|
62
|
+
);
|
|
73
63
|
}
|
|
74
64
|
}
|
|
75
65
|
}
|
package/lib/md033.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addError, nextLinesRe } = require("../helpers");
|
|
6
|
-
const {
|
|
7
|
-
|
|
6
|
+
const { getHtmlTagInfo } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line jsdoc/valid-types
|
|
10
10
|
/** @type import("./markdownlint").Rule */
|
|
@@ -17,12 +17,7 @@ module.exports = {
|
|
|
17
17
|
let allowedElements = params.config.allowed_elements;
|
|
18
18
|
allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
|
|
19
19
|
allowedElements = allowedElements.map((element) => element.toLowerCase());
|
|
20
|
-
|
|
21
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
22
|
-
const micromarkTokens =
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
params.parsers.micromark.tokens;
|
|
25
|
-
for (const token of filterByTypes(micromarkTokens, [ "htmlText" ])) {
|
|
20
|
+
for (const token of filterByTypesCached([ "htmlText" ], true)) {
|
|
26
21
|
const htmlTagInfo = getHtmlTagInfo(token);
|
|
27
22
|
if (
|
|
28
23
|
htmlTagInfo &&
|
package/lib/md034.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorContext } = require("../helpers");
|
|
6
|
-
const { filterByPredicate,
|
|
7
|
-
|
|
6
|
+
const { filterByPredicate, getHtmlTagInfo, inHtmlFlow, parse } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line jsdoc/valid-types
|
|
10
10
|
/** @type import("./markdownlint").Rule */
|
|
@@ -14,11 +14,6 @@ module.exports = {
|
|
|
14
14
|
"tags": [ "links", "url" ],
|
|
15
15
|
"parser": "micromark",
|
|
16
16
|
"function": function MD034(params, onError) {
|
|
17
|
-
// eslint-disable-next-line jsdoc/valid-types
|
|
18
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
19
|
-
const micromarkTokens =
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
params.parsers.micromark.tokens;
|
|
22
17
|
const literalAutolinks = (tokens) => (
|
|
23
18
|
filterByPredicate(
|
|
24
19
|
tokens,
|
|
@@ -75,7 +70,7 @@ module.exports = {
|
|
|
75
70
|
}
|
|
76
71
|
)
|
|
77
72
|
);
|
|
78
|
-
const autoLinks =
|
|
73
|
+
const autoLinks = filterByTypesCached([ "literalAutolink" ]);
|
|
79
74
|
if (autoLinks.length > 0) {
|
|
80
75
|
// Re-parse with correct link/image reference definition handling
|
|
81
76
|
const document = params.lines.join("\n");
|
|
@@ -94,8 +89,8 @@ module.exports = {
|
|
|
94
89
|
onError,
|
|
95
90
|
token.startLine,
|
|
96
91
|
token.text,
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
undefined,
|
|
93
|
+
undefined,
|
|
99
94
|
range,
|
|
100
95
|
fixInfo
|
|
101
96
|
);
|
package/lib/md035.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
|
-
const {
|
|
6
|
+
const { filterByTypesCached } = require("./cache");
|
|
7
7
|
|
|
8
8
|
// eslint-disable-next-line jsdoc/valid-types
|
|
9
9
|
/** @type import("./markdownlint").Rule */
|
|
@@ -14,12 +14,7 @@ module.exports = {
|
|
|
14
14
|
"parser": "micromark",
|
|
15
15
|
"function": function MD035(params, onError) {
|
|
16
16
|
let style = String(params.config.style || "consistent").trim();
|
|
17
|
-
|
|
18
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
19
|
-
const micromarkTokens =
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
params.parsers.micromark.tokens;
|
|
22
|
-
const thematicBreaks = filterByTypes(micromarkTokens, [ "thematicBreak" ]);
|
|
17
|
+
const thematicBreaks = filterByTypesCached([ "thematicBreak" ]);
|
|
23
18
|
for (const token of thematicBreaks) {
|
|
24
19
|
const { startLine, text } = token;
|
|
25
20
|
if (style === "consistent") {
|
package/lib/md036.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorContext, allPunctuation } = require("../helpers");
|
|
6
|
-
const {
|
|
6
|
+
const { matchAndGetTokensByType } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
7
8
|
|
|
8
9
|
/** @typedef {import("../helpers/micromark.cjs").TokenType} TokenType */
|
|
9
10
|
/** @type {Map<TokenType, TokenType[]>} */
|
|
@@ -24,7 +25,7 @@ module.exports = {
|
|
|
24
25
|
punctuation = String((punctuation === undefined) ? allPunctuation : punctuation);
|
|
25
26
|
const punctuationRe = new RegExp("[" + punctuation + "]$");
|
|
26
27
|
const paragraphTokens =
|
|
27
|
-
|
|
28
|
+
filterByTypesCached([ "paragraph" ]).
|
|
28
29
|
filter((token) =>
|
|
29
30
|
(token.parent?.type === "content") && !token.parent?.parent && (token.children.length === 1)
|
|
30
31
|
);
|
package/lib/md037.js
CHANGED
|
@@ -15,18 +15,13 @@ module.exports = {
|
|
|
15
15
|
"function": function MD037(params, onError) {
|
|
16
16
|
|
|
17
17
|
// Initialize variables
|
|
18
|
-
|
|
19
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
20
|
-
const micromarkTokens =
|
|
21
|
-
// @ts-ignore
|
|
22
|
-
params.parsers.micromark.tokens;
|
|
23
|
-
const { lines } = params;
|
|
18
|
+
const { lines, parsers } = params;
|
|
24
19
|
const emphasisTokensByMarker = new Map();
|
|
25
20
|
for (const marker of [ "_", "__", "___", "*", "**", "***" ]) {
|
|
26
21
|
emphasisTokensByMarker.set(marker, []);
|
|
27
22
|
}
|
|
28
23
|
const tokens = filterByPredicate(
|
|
29
|
-
|
|
24
|
+
parsers.micromark.tokens,
|
|
30
25
|
(token) => token.children.some((child) => child.type === "data")
|
|
31
26
|
);
|
|
32
27
|
for (const token of tokens) {
|
package/lib/md038.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorContext } = require("../helpers");
|
|
6
|
-
const {
|
|
7
|
-
|
|
6
|
+
const { tokenIfType } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
const leftSpaceRe = /^\s(?:[^`]|$)/;
|
|
10
10
|
const rightSpaceRe = /[^`]\s$/;
|
|
@@ -27,13 +27,7 @@ module.exports = {
|
|
|
27
27
|
"tags": [ "whitespace", "code" ],
|
|
28
28
|
"parser": "micromark",
|
|
29
29
|
"function": function MD038(params, onError) {
|
|
30
|
-
|
|
31
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
32
|
-
const micromarkTokens =
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
params.parsers.micromark.tokens;
|
|
35
|
-
const codeTexts = filterByTypes(micromarkTokens, [ "codeText" ])
|
|
36
|
-
.filter((codeText) => !inHtmlFlow(codeText));
|
|
30
|
+
const codeTexts = filterByTypesCached([ "codeText" ]);
|
|
37
31
|
for (const codeText of codeTexts) {
|
|
38
32
|
const { children } = codeText;
|
|
39
33
|
const first = 0;
|
package/lib/md039.js
CHANGED
|
@@ -2,10 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext
|
|
5
|
+
const { addErrorContext } = require("../helpers");
|
|
6
|
+
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Adds an error for a label space issue.
|
|
11
|
+
*
|
|
12
|
+
* @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
|
|
13
|
+
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
|
14
|
+
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
|
15
|
+
* @param {boolean} isStart True iff error is at the start of the link.
|
|
16
|
+
*/
|
|
17
|
+
function addLabelSpaceError(onError, label, labelText, isStart) {
|
|
18
|
+
const match = labelText.text.match(isStart ? /^[^\S\r\n]+/ : /[^\S\r\n]+$/);
|
|
19
|
+
const range = match ?
|
|
20
|
+
[
|
|
21
|
+
(isStart ? (labelText.startColumn) : (labelText.endColumn - match[0].length)),
|
|
22
|
+
match[0].length
|
|
23
|
+
] :
|
|
24
|
+
undefined;
|
|
25
|
+
addErrorContext(
|
|
26
|
+
onError,
|
|
27
|
+
isStart ? (labelText.startLine + (match ? 0 : 1)) : (labelText.endLine - (match ? 0 : 1)),
|
|
28
|
+
label.text.replace(/\s+/g, " "),
|
|
29
|
+
isStart,
|
|
30
|
+
!isStart,
|
|
31
|
+
range,
|
|
32
|
+
range ? {
|
|
33
|
+
"editColumn": range[0],
|
|
34
|
+
"deleteCount": range[1]
|
|
35
|
+
} : undefined
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Determines if a link is a valid link (and not a fake shortcut link due to parser tricks).
|
|
41
|
+
*
|
|
42
|
+
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
|
43
|
+
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
|
44
|
+
* @param {Map<string, any>} definitions Map of link definitions.
|
|
45
|
+
* @returns {boolean} True iff the link is valid.
|
|
46
|
+
*/
|
|
47
|
+
function validLink(label, labelText, definitions) {
|
|
48
|
+
return (label.parent?.children.length !== 1) || definitions.has(labelText.text.trim());
|
|
49
|
+
}
|
|
9
50
|
|
|
10
51
|
// eslint-disable-next-line jsdoc/valid-types
|
|
11
52
|
/** @type import("./markdownlint").Rule */
|
|
@@ -13,59 +54,30 @@ module.exports = {
|
|
|
13
54
|
"names": [ "MD039", "no-space-in-links" ],
|
|
14
55
|
"description": "Spaces inside link text",
|
|
15
56
|
"tags": [ "whitespace", "links" ],
|
|
16
|
-
"parser": "
|
|
57
|
+
"parser": "micromark",
|
|
17
58
|
"function": function MD039(params, onError) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (match) {
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
const column = match.index + lineIndex + 1;
|
|
41
|
-
const length = match[0].length;
|
|
42
|
-
range = [ column, length ];
|
|
43
|
-
fixInfo = {
|
|
44
|
-
"editColumn": column + 1,
|
|
45
|
-
"deleteCount": length - 2,
|
|
46
|
-
"insertText": linkText.trim()
|
|
47
|
-
};
|
|
48
|
-
lineIndex = column + length - 1;
|
|
49
|
-
}
|
|
50
|
-
addErrorContext(
|
|
51
|
-
onError,
|
|
52
|
-
lineNumber,
|
|
53
|
-
`[${linkText}]`,
|
|
54
|
-
left,
|
|
55
|
-
right,
|
|
56
|
-
range,
|
|
57
|
-
fixInfo
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
} else if ((type === "softbreak") || (type === "hardbreak")) {
|
|
61
|
-
lineNumber++;
|
|
62
|
-
lineIndex = 0;
|
|
63
|
-
} else if (inLink) {
|
|
64
|
-
linkText += type.endsWith("_inline") ?
|
|
65
|
-
`${markup}${content}${markup}` :
|
|
66
|
-
(content || markup);
|
|
59
|
+
const { definitions } = getReferenceLinkImageData();
|
|
60
|
+
const labels = filterByTypesCached([ "label" ]).
|
|
61
|
+
filter((label) => label.parent?.type === "link");
|
|
62
|
+
for (const label of labels) {
|
|
63
|
+
const labelTexts = filterByTypes(
|
|
64
|
+
label.children,
|
|
65
|
+
[ "labelText" ]
|
|
66
|
+
);
|
|
67
|
+
for (const labelText of labelTexts) {
|
|
68
|
+
if (
|
|
69
|
+
(labelText.text.trimStart().length !== labelText.text.length) &&
|
|
70
|
+
validLink(label, labelText, definitions)
|
|
71
|
+
) {
|
|
72
|
+
addLabelSpaceError(onError, label, labelText, true);
|
|
73
|
+
}
|
|
74
|
+
if (
|
|
75
|
+
(labelText.text.trimEnd().length !== labelText.text.length) &&
|
|
76
|
+
validLink(label, labelText, definitions)
|
|
77
|
+
) {
|
|
78
|
+
addLabelSpaceError(onError, label, labelText, false);
|
|
67
79
|
}
|
|
68
80
|
}
|
|
69
|
-
}
|
|
81
|
+
}
|
|
70
82
|
}
|
|
71
83
|
};
|
package/lib/md040.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addError, addErrorContext } = require("../helpers");
|
|
6
|
-
const {
|
|
7
|
-
|
|
6
|
+
const { getTokenTextByType, tokenIfType } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line jsdoc/valid-types
|
|
10
10
|
/** @type import("./markdownlint").Rule */
|
|
@@ -17,12 +17,7 @@ module.exports = {
|
|
|
17
17
|
let allowed = params.config.allowed_languages;
|
|
18
18
|
allowed = Array.isArray(allowed) ? allowed : [];
|
|
19
19
|
const languageOnly = !!params.config.language_only;
|
|
20
|
-
|
|
21
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
22
|
-
const micromarkTokens =
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
params.parsers.micromark.tokens;
|
|
25
|
-
const fencedCodes = filterByTypes(micromarkTokens, [ "codeFenced" ]);
|
|
20
|
+
const fencedCodes = filterByTypesCached([ "codeFenced" ]);
|
|
26
21
|
for (const fencedCode of fencedCodes) {
|
|
27
22
|
const openingFence = tokenIfType(fencedCode.children[0], "codeFencedFence");
|
|
28
23
|
if (openingFence) {
|
package/lib/md041.js
CHANGED
|
@@ -23,7 +23,7 @@ module.exports = {
|
|
|
23
23
|
if ((token.type === "atxHeading") || (token.type === "setextHeading")) {
|
|
24
24
|
isError = (getHeadingLevel(token) !== level);
|
|
25
25
|
} else if (token.type === "htmlFlow") {
|
|
26
|
-
const htmlTexts = filterByTypes(token.children, [ "htmlText" ]);
|
|
26
|
+
const htmlTexts = filterByTypes(token.children, [ "htmlText" ], true);
|
|
27
27
|
const tagInfo = (htmlTexts.length > 0) && getHtmlTagInfo(htmlTexts[0]);
|
|
28
28
|
isError = !tagInfo || (tagInfo.name.toLowerCase() !== `h${level}`);
|
|
29
29
|
}
|
package/lib/md042.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext
|
|
6
|
-
|
|
5
|
+
const { addErrorContext } = require("../helpers");
|
|
6
|
+
const { getDescendantsByType } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
|
|
7
8
|
|
|
8
9
|
// eslint-disable-next-line jsdoc/valid-types
|
|
9
10
|
/** @type import("./markdownlint").Rule */
|
|
@@ -11,43 +12,52 @@ module.exports = {
|
|
|
11
12
|
"names": [ "MD042", "no-empty-links" ],
|
|
12
13
|
"description": "No empty links",
|
|
13
14
|
"tags": [ "links" ],
|
|
14
|
-
"parser": "
|
|
15
|
+
"parser": "micromark",
|
|
15
16
|
"function": function MD042(params, onError) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
17
|
+
const { definitions } = getReferenceLinkImageData();
|
|
18
|
+
const isReferenceDefinitionHash = (token) => {
|
|
19
|
+
const definition = definitions.get(token.text.trim());
|
|
20
|
+
return (definition && (definition[1] === "#"));
|
|
21
|
+
};
|
|
22
|
+
const links = filterByTypesCached([ "link" ]);
|
|
23
|
+
for (const link of links) {
|
|
24
|
+
const labelText = getDescendantsByType(link, [ "label", "labelText" ]);
|
|
25
|
+
const reference = getDescendantsByType(link, [ "reference" ]);
|
|
26
|
+
const resource = getDescendantsByType(link, [ "resource" ]);
|
|
27
|
+
const referenceString = getDescendantsByType(reference, [ "referenceString" ]);
|
|
28
|
+
const resourceDestination = getDescendantsByType(resource, [ "resourceDestination" ]);
|
|
29
|
+
const resourceDestinationString = [
|
|
30
|
+
...getDescendantsByType(resourceDestination, [ "resourceDestinationRaw", "resourceDestinationString" ]),
|
|
31
|
+
...getDescendantsByType(resourceDestination, [ "resourceDestinationLiteral", "resourceDestinationString" ])
|
|
32
|
+
];
|
|
33
|
+
const hasLabelText = labelText.length > 0;
|
|
34
|
+
const hasReference = reference.length > 0;
|
|
35
|
+
const hasResource = resource.length > 0;
|
|
36
|
+
const hasReferenceString = referenceString.length > 0;
|
|
37
|
+
const hasResourceDestinationString = resourceDestinationString.length > 0;
|
|
38
|
+
let error = false;
|
|
39
|
+
if (
|
|
40
|
+
hasLabelText &&
|
|
41
|
+
((!hasReference && !hasResource) || (hasReference && !hasReferenceString))
|
|
42
|
+
) {
|
|
43
|
+
error = isReferenceDefinitionHash(labelText[0]);
|
|
44
|
+
} else if (hasReferenceString && !hasResourceDestinationString) {
|
|
45
|
+
error = isReferenceDefinitionHash(referenceString[0]);
|
|
46
|
+
} else if (!hasReferenceString && hasResourceDestinationString) {
|
|
47
|
+
error = (resourceDestinationString[0].text.trim() === "#");
|
|
48
|
+
} else if (!hasReferenceString && !hasResourceDestinationString) {
|
|
49
|
+
error = true;
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
if (error) {
|
|
52
|
+
addErrorContext(
|
|
53
|
+
onError,
|
|
54
|
+
link.startLine,
|
|
55
|
+
link.text,
|
|
56
|
+
undefined,
|
|
57
|
+
undefined,
|
|
58
|
+
[ link.startColumn, link.endColumn - link.startColumn ]
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
52
62
|
}
|
|
53
63
|
};
|
package/lib/md043.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext, addErrorDetailIf
|
|
6
|
-
|
|
5
|
+
const { addErrorContext, addErrorDetailIf } = require("../helpers");
|
|
6
|
+
const { getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
7
8
|
|
|
8
9
|
// eslint-disable-next-line jsdoc/valid-types
|
|
9
10
|
/** @type import("./markdownlint").Rule */
|
|
@@ -11,7 +12,7 @@ module.exports = {
|
|
|
11
12
|
"names": [ "MD043", "required-headings" ],
|
|
12
13
|
"description": "Required heading structure",
|
|
13
14
|
"tags": [ "headings" ],
|
|
14
|
-
"parser": "
|
|
15
|
+
"parser": "micromark",
|
|
15
16
|
"function": function MD043(params, onError) {
|
|
16
17
|
const requiredHeadings = params.config.headings;
|
|
17
18
|
if (!Array.isArray(requiredHeadings)) {
|
|
@@ -19,20 +20,18 @@ module.exports = {
|
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
22
|
const matchCase = params.config.match_case || false;
|
|
22
|
-
const levels = {};
|
|
23
|
-
for (const level of [ 1, 2, 3, 4, 5, 6 ]) {
|
|
24
|
-
levels["h" + level] = "######".substr(-level);
|
|
25
|
-
}
|
|
26
23
|
let i = 0;
|
|
27
24
|
let matchAny = false;
|
|
28
25
|
let hasError = false;
|
|
29
26
|
let anyHeadings = false;
|
|
30
27
|
const getExpected = () => requiredHeadings[i++] || "[None]";
|
|
31
28
|
const handleCase = (str) => (matchCase ? str : str.toLowerCase());
|
|
32
|
-
|
|
29
|
+
for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
|
|
33
30
|
if (!hasError) {
|
|
31
|
+
const headingText = getHeadingText(heading);
|
|
32
|
+
const headingLevel = getHeadingLevel(heading);
|
|
34
33
|
anyHeadings = true;
|
|
35
|
-
const actual =
|
|
34
|
+
const actual = `${"".padEnd(headingLevel, "#")} ${headingText}`;
|
|
36
35
|
const expected = getExpected();
|
|
37
36
|
if (expected === "*") {
|
|
38
37
|
const nextExpected = getExpected();
|
|
@@ -47,12 +46,16 @@ module.exports = {
|
|
|
47
46
|
} else if (matchAny) {
|
|
48
47
|
i--;
|
|
49
48
|
} else {
|
|
50
|
-
addErrorDetailIf(
|
|
51
|
-
|
|
49
|
+
addErrorDetailIf(
|
|
50
|
+
onError,
|
|
51
|
+
heading.startLine,
|
|
52
|
+
expected,
|
|
53
|
+
actual
|
|
54
|
+
);
|
|
52
55
|
hasError = true;
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
|
-
}
|
|
58
|
+
}
|
|
56
59
|
const extraHeadings = requiredHeadings.length - i;
|
|
57
60
|
if (
|
|
58
61
|
!hasError &&
|
|
@@ -60,8 +63,11 @@ module.exports = {
|
|
|
60
63
|
((extraHeadings === 1) && (requiredHeadings[i] !== "*"))) &&
|
|
61
64
|
(anyHeadings || !requiredHeadings.every((heading) => heading === "*"))
|
|
62
65
|
) {
|
|
63
|
-
addErrorContext(
|
|
64
|
-
|
|
66
|
+
addErrorContext(
|
|
67
|
+
onError,
|
|
68
|
+
params.lines.length,
|
|
69
|
+
requiredHeadings[i]
|
|
70
|
+
);
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
};
|
package/lib/md044.js
CHANGED
|
@@ -32,11 +32,6 @@ module.exports = {
|
|
|
32
32
|
const htmlElements = params.config.html_elements;
|
|
33
33
|
const includeHtmlElements =
|
|
34
34
|
(htmlElements === undefined) ? true : !!htmlElements;
|
|
35
|
-
// eslint-disable-next-line jsdoc/valid-types
|
|
36
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
37
|
-
const micromarkTokens =
|
|
38
|
-
// @ts-ignore
|
|
39
|
-
params.parsers.micromark.tokens;
|
|
40
35
|
const scannedTypes = new Set([ "data" ]);
|
|
41
36
|
if (includeCodeBlocks) {
|
|
42
37
|
scannedTypes.add("codeFlowValue");
|
|
@@ -48,7 +43,7 @@ module.exports = {
|
|
|
48
43
|
}
|
|
49
44
|
const contentTokens =
|
|
50
45
|
filterByPredicate(
|
|
51
|
-
|
|
46
|
+
params.parsers.micromark.tokens,
|
|
52
47
|
(token) => scannedTypes.has(token.type),
|
|
53
48
|
(token) => (
|
|
54
49
|
token.children.filter((t) => !ignoredChildTypes.has(t.type))
|
|
@@ -96,8 +91,8 @@ module.exports = {
|
|
|
96
91
|
token.startLine,
|
|
97
92
|
name,
|
|
98
93
|
nameMatch,
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
undefined,
|
|
95
|
+
undefined,
|
|
101
96
|
[ column, length ],
|
|
102
97
|
{
|
|
103
98
|
"editColumn": column,
|
package/lib/md045.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const { addError, getHtmlAttributeRe, nextLinesRe } = require("../helpers");
|
|
6
6
|
const { filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
7
8
|
|
|
8
9
|
const altRe = getHtmlAttributeRe("alt");
|
|
9
10
|
|
|
@@ -15,14 +16,8 @@ module.exports = {
|
|
|
15
16
|
"tags": [ "accessibility", "images" ],
|
|
16
17
|
"parser": "micromark",
|
|
17
18
|
"function": function MD045(params, onError) {
|
|
18
|
-
// eslint-disable-next-line jsdoc/valid-types
|
|
19
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
20
|
-
const micromarkTokens =
|
|
21
|
-
// @ts-ignore
|
|
22
|
-
params.parsers.micromark.tokens;
|
|
23
|
-
|
|
24
19
|
// Process Markdown images
|
|
25
|
-
const images =
|
|
20
|
+
const images = filterByTypesCached([ "image" ]);
|
|
26
21
|
for (const image of images) {
|
|
27
22
|
const labelTexts = filterByTypes(image.children, [ "labelText" ]);
|
|
28
23
|
if (labelTexts.some((labelText) => labelText.text.length === 0)) {
|
|
@@ -40,7 +35,7 @@ module.exports = {
|
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
// Process HTML images
|
|
43
|
-
const htmlTexts =
|
|
38
|
+
const htmlTexts = filterByTypesCached([ "htmlText" ], true);
|
|
44
39
|
for (const htmlText of htmlTexts) {
|
|
45
40
|
const { startColumn, startLine, text } = htmlText;
|
|
46
41
|
const htmlTagInfo = getHtmlTagInfo(htmlText);
|