markdownlint 0.32.1 → 0.34.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 +18 -0
- package/CONTRIBUTING.md +4 -3
- package/README.md +6 -0
- package/demo/markdownlint-browser.js +3866 -3564
- package/doc/CustomRules.md +14 -7
- package/doc/Rules.md +139 -12
- package/doc/md013.md +8 -7
- package/doc/md024.md +2 -5
- package/doc/md049.md +3 -0
- package/doc/md050.md +3 -0
- package/doc/md051.md +26 -0
- package/doc/md055.md +54 -0
- package/doc/md056.md +37 -0
- package/helpers/README.md +5 -3
- package/helpers/helpers.js +5 -5
- package/helpers/micromark.cjs +46 -27
- package/helpers/package.json +2 -2
- package/lib/configuration.d.ts +136 -110
- package/lib/constants.js +1 -1
- package/lib/markdownlint.d.ts +79 -6
- package/lib/markdownlint.js +95 -21
- package/lib/md001.js +3 -0
- package/lib/md003.js +3 -0
- package/lib/md004.js +3 -0
- package/lib/md005.js +12 -4
- package/lib/md007.js +17 -11
- package/lib/md009.js +3 -0
- package/lib/md010.js +4 -1
- package/lib/md011.js +3 -0
- package/lib/md012.js +3 -0
- package/lib/md013.js +3 -0
- package/lib/md014.js +4 -0
- package/lib/md018.js +4 -0
- package/lib/md019.js +3 -0
- package/lib/md020.js +3 -0
- package/lib/md021.js +3 -0
- package/lib/md022.js +10 -2
- package/lib/md023.js +3 -0
- package/lib/md024.js +11 -4
- package/lib/md025.js +3 -0
- package/lib/md026.js +11 -7
- package/lib/md027.js +29 -43
- package/lib/md028.js +31 -14
- package/lib/md029.js +3 -0
- package/lib/md030.js +9 -4
- package/lib/md031.js +3 -0
- package/lib/md032.js +12 -14
- package/lib/md033.js +9 -2
- package/lib/md034.js +31 -5
- package/lib/md035.js +9 -2
- package/lib/md036.js +33 -39
- package/lib/md037.js +10 -2
- package/lib/md038.js +27 -18
- package/lib/md039.js +4 -0
- package/lib/md040.js +26 -21
- package/lib/md041.js +21 -26
- package/lib/md042.js +4 -0
- package/lib/md043.js +3 -0
- package/lib/md044.js +9 -1
- package/lib/md045.js +10 -3
- package/lib/md046.js +14 -7
- package/lib/md047.js +5 -2
- package/lib/md048.js +26 -13
- package/lib/md049-md050.js +26 -7
- package/lib/md051.js +20 -16
- package/lib/md052.js +3 -0
- package/lib/md053.js +3 -0
- package/lib/md054.js +10 -5
- package/lib/md055.js +80 -0
- package/lib/md056.js +52 -0
- package/lib/rules.js +5 -3
- package/package.json +26 -32
- package/schema/.markdownlint.jsonc +58 -51
- package/schema/.markdownlint.yaml +56 -50
- package/schema/ValidatingConfiguration.md +28 -0
- package/schema/markdownlint-config-schema.json +165 -113
package/lib/md020.js
CHANGED
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
const { addErrorContext, forEachLine } = require("../helpers");
|
|
6
6
|
const { lineMetadata } = require("./cache");
|
|
7
7
|
|
|
8
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
9
|
+
/** @type import("./markdownlint").Rule */
|
|
8
10
|
module.exports = {
|
|
9
11
|
"names": [ "MD020", "no-missing-space-closed-atx" ],
|
|
10
12
|
"description": "No space inside hashes on closed atx style heading",
|
|
11
13
|
"tags": [ "headings", "atx_closed", "spaces" ],
|
|
14
|
+
"parser": "none",
|
|
12
15
|
"function": function MD020(params, onError) {
|
|
13
16
|
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
14
17
|
if (!inCode) {
|
package/lib/md021.js
CHANGED
|
@@ -7,10 +7,13 @@ const { addErrorContext, filterTokens, headingStyleFor } =
|
|
|
7
7
|
|
|
8
8
|
const closedAtxRe = /^(#+)([ \t]+)([^ \t]|[^ \t].*[^ \t])([ \t]+)(#+)(\s*)$/;
|
|
9
9
|
|
|
10
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
11
|
+
/** @type import("./markdownlint").Rule */
|
|
10
12
|
module.exports = {
|
|
11
13
|
"names": [ "MD021", "no-multiple-space-closed-atx" ],
|
|
12
14
|
"description": "Multiple spaces inside hashes on closed atx style heading",
|
|
13
15
|
"tags": [ "headings", "atx_closed", "spaces" ],
|
|
16
|
+
"parser": "markdownit",
|
|
14
17
|
"function": function MD021(params, onError) {
|
|
15
18
|
filterTokens(params, "heading_open", (token) => {
|
|
16
19
|
if (headingStyleFor(token) === "atx_closed") {
|
package/lib/md022.js
CHANGED
|
@@ -31,16 +31,24 @@ const getBlockQuote = (str, count) => (
|
|
|
31
31
|
.repeat(count)
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
35
|
+
/** @type import("./markdownlint").Rule */
|
|
34
36
|
module.exports = {
|
|
35
37
|
"names": [ "MD022", "blanks-around-headings" ],
|
|
36
38
|
"description": "Headings should be surrounded by blank lines",
|
|
37
39
|
"tags": [ "headings", "blank_lines" ],
|
|
40
|
+
"parser": "micromark",
|
|
38
41
|
"function": function MD022(params, onError) {
|
|
39
42
|
const getLinesAbove = getLinesFunction(params.config.lines_above);
|
|
40
43
|
const getLinesBelow = getLinesFunction(params.config.lines_below);
|
|
41
|
-
|
|
44
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
45
|
+
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
46
|
+
const micromarkTokens =
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
params.parsers.micromark.tokens;
|
|
49
|
+
const { lines } = params;
|
|
42
50
|
const headings = filterByTypes(
|
|
43
|
-
|
|
51
|
+
micromarkTokens,
|
|
44
52
|
[ "atxHeading", "setextHeading" ]
|
|
45
53
|
).filter((heading) => !inHtmlFlow(heading));
|
|
46
54
|
for (const heading of headings) {
|
package/lib/md023.js
CHANGED
|
@@ -6,10 +6,13 @@ const { addErrorContext, filterTokens } = require("../helpers");
|
|
|
6
6
|
|
|
7
7
|
const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/;
|
|
8
8
|
|
|
9
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
10
|
+
/** @type import("./markdownlint").Rule */
|
|
9
11
|
module.exports = {
|
|
10
12
|
"names": [ "MD023", "heading-start-left" ],
|
|
11
13
|
"description": "Headings must start at the beginning of the line",
|
|
12
14
|
"tags": [ "headings", "spaces" ],
|
|
15
|
+
"parser": "markdownit",
|
|
13
16
|
"function": function MD023(params, onError) {
|
|
14
17
|
filterTokens(params, "heading_open", function forToken(token) {
|
|
15
18
|
const { lineNumber, line } = token;
|
package/lib/md024.js
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
const { addErrorContext, forEachHeading } = require("../helpers");
|
|
6
6
|
|
|
7
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
8
|
+
/** @type import("./markdownlint").Rule */
|
|
7
9
|
module.exports = {
|
|
8
10
|
"names": [ "MD024", "no-duplicate-heading" ],
|
|
9
11
|
"description": "Multiple headings with the same content",
|
|
10
12
|
"tags": [ "headings" ],
|
|
13
|
+
"parser": "markdownit",
|
|
11
14
|
"function": function MD024(params, onError) {
|
|
12
|
-
const siblingsOnly = !!params.config.siblings_only ||
|
|
13
|
-
!!params.config.allow_different_nesting || false;
|
|
15
|
+
const siblingsOnly = !!params.config.siblings_only || false;
|
|
14
16
|
const knownContents = [ null, [] ];
|
|
15
17
|
let lastLevel = 1;
|
|
16
18
|
let knownContent = knownContents[lastLevel];
|
|
@@ -27,10 +29,15 @@ module.exports = {
|
|
|
27
29
|
}
|
|
28
30
|
knownContent = knownContents[newLevel];
|
|
29
31
|
}
|
|
32
|
+
// @ts-ignore
|
|
30
33
|
if (knownContent.includes(content)) {
|
|
31
|
-
addErrorContext(
|
|
32
|
-
|
|
34
|
+
addErrorContext(
|
|
35
|
+
onError,
|
|
36
|
+
heading.lineNumber,
|
|
37
|
+
heading.line.trim()
|
|
38
|
+
);
|
|
33
39
|
} else {
|
|
40
|
+
// @ts-ignore
|
|
34
41
|
knownContent.push(content);
|
|
35
42
|
}
|
|
36
43
|
});
|
package/lib/md025.js
CHANGED
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
const { addErrorContext, filterTokens, frontMatterHasTitle } =
|
|
6
6
|
require("../helpers");
|
|
7
7
|
|
|
8
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
9
|
+
/** @type import("./markdownlint").Rule */
|
|
8
10
|
module.exports = {
|
|
9
11
|
"names": [ "MD025", "single-title", "single-h1" ],
|
|
10
12
|
"description": "Multiple top-level headings in the same document",
|
|
11
13
|
"tags": [ "headings" ],
|
|
14
|
+
"parser": "markdownit",
|
|
12
15
|
"function": function MD025(params, onError) {
|
|
13
16
|
const level = Number(params.config.level || 1);
|
|
14
17
|
const tag = "h" + level;
|
package/lib/md026.js
CHANGED
|
@@ -6,11 +6,13 @@ const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
|
|
|
6
6
|
endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers");
|
|
7
7
|
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
10
|
+
/** @type import("./markdownlint").Rule */
|
|
10
11
|
module.exports = {
|
|
11
12
|
"names": [ "MD026", "no-trailing-punctuation" ],
|
|
12
13
|
"description": "Trailing punctuation in heading",
|
|
13
14
|
"tags": [ "headings" ],
|
|
15
|
+
"parser": "micromark",
|
|
14
16
|
"function": function MD026(params, onError) {
|
|
15
17
|
let punctuation = params.config.punctuation;
|
|
16
18
|
punctuation = String(
|
|
@@ -18,12 +20,14 @@ module.exports = {
|
|
|
18
20
|
);
|
|
19
21
|
const trailingPunctuationRe =
|
|
20
22
|
new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
24
|
+
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
25
|
+
const micromarkTokens =
|
|
26
|
+
// @ts-ignore
|
|
27
|
+
params.parsers.micromark.tokens;
|
|
28
|
+
const headings = filterByTypes(micromarkTokens, [ "atxHeadingText", "setextHeadingText" ]);
|
|
25
29
|
for (const heading of headings) {
|
|
26
|
-
const {
|
|
30
|
+
const { endColumn, endLine, text } = heading;
|
|
27
31
|
const match = trailingPunctuationRe.exec(text);
|
|
28
32
|
if (
|
|
29
33
|
match &&
|
|
@@ -31,8 +35,8 @@ module.exports = {
|
|
|
31
35
|
!endOfLineGemojiCodeRe.test(text)
|
|
32
36
|
) {
|
|
33
37
|
const fullMatch = match[0];
|
|
34
|
-
const column = startColumn + match.index;
|
|
35
38
|
const length = fullMatch.length;
|
|
39
|
+
const column = endColumn - length;
|
|
36
40
|
addError(
|
|
37
41
|
onError,
|
|
38
42
|
endLine,
|
package/lib/md027.js
CHANGED
|
@@ -2,54 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext
|
|
6
|
-
|
|
7
|
-
const spaceAfterBlockQuoteRe = /^((?:\s*>)+)(\s{2,})\S/;
|
|
5
|
+
const { addErrorContext } = require("../helpers");
|
|
6
|
+
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
8
7
|
|
|
8
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
9
|
+
/** @type import("./markdownlint").Rule */
|
|
9
10
|
module.exports = {
|
|
10
|
-
"names": [
|
|
11
|
+
"names": ["MD027", "no-multiple-space-blockquote"],
|
|
11
12
|
"description": "Multiple spaces after blockquote symbol",
|
|
12
|
-
"tags": [
|
|
13
|
+
"tags": ["blockquote", "whitespace", "indentation"],
|
|
14
|
+
"parser": "micromark",
|
|
13
15
|
"function": function MD027(params, onError) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{ "length": spaceLength }
|
|
36
|
-
] = match;
|
|
37
|
-
if (!listItemNesting || (fullMatch[fullMatch.length - 1] === ">")) {
|
|
38
|
-
addErrorContext(
|
|
39
|
-
onError,
|
|
40
|
-
lineNumber + i,
|
|
41
|
-
line,
|
|
42
|
-
null,
|
|
43
|
-
null,
|
|
44
|
-
[ 1, fullMatch.length ],
|
|
45
|
-
{
|
|
46
|
-
"editColumn": blockquoteLength + 1,
|
|
47
|
-
"deleteCount": spaceLength - 1
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
}
|
|
16
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
17
|
+
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
18
|
+
const micromarkTokens =
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
params.parsers.micromark.tokens;
|
|
21
|
+
for (const token of filterByTypes(micromarkTokens, [ "linePrefix" ])) {
|
|
22
|
+
const siblings = token.parent?.children || micromarkTokens;
|
|
23
|
+
if (siblings[siblings.indexOf(token) - 1]?.type === "blockQuotePrefix") {
|
|
24
|
+
const { startColumn, startLine, text } = token;
|
|
25
|
+
const { length } = text;
|
|
26
|
+
const line = params.lines[startLine - 1];
|
|
27
|
+
addErrorContext(
|
|
28
|
+
onError,
|
|
29
|
+
startLine,
|
|
30
|
+
line,
|
|
31
|
+
null,
|
|
32
|
+
null,
|
|
33
|
+
[ startColumn, length ],
|
|
34
|
+
{
|
|
35
|
+
"editColumn": startColumn,
|
|
36
|
+
"deleteCount": length
|
|
51
37
|
}
|
|
52
|
-
|
|
38
|
+
);
|
|
53
39
|
}
|
|
54
40
|
}
|
|
55
41
|
}
|
package/lib/md028.js
CHANGED
|
@@ -3,28 +3,45 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addError } = require("../helpers");
|
|
6
|
+
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
6
7
|
|
|
8
|
+
const ignoreTypes = new Set([ "lineEnding", "listItemIndent", "linePrefix" ]);
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
11
|
+
/** @type import("./markdownlint").Rule */
|
|
7
12
|
module.exports = {
|
|
8
13
|
"names": [ "MD028", "no-blanks-blockquote" ],
|
|
9
14
|
"description": "Blank line inside blockquote",
|
|
10
15
|
"tags": [ "blockquote", "whitespace" ],
|
|
16
|
+
"parser": "micromark",
|
|
11
17
|
"function": function MD028(params, onError) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
+
for (const token of filterByTypes(micromarkTokens, [ "blockQuote" ])) {
|
|
24
|
+
const errorLineNumbers = [];
|
|
25
|
+
const siblings = token.parent?.children || micromarkTokens;
|
|
26
|
+
for (let i = siblings.indexOf(token) + 1; i < siblings.length; i++) {
|
|
27
|
+
const sibling = siblings[i];
|
|
28
|
+
const { startLine, type } = sibling;
|
|
29
|
+
if (type === "lineEndingBlank") {
|
|
30
|
+
// Possible blank between blockquotes
|
|
31
|
+
errorLineNumbers.push(startLine);
|
|
32
|
+
} else if (ignoreTypes.has(type)) {
|
|
33
|
+
// Ignore invisible formatting
|
|
34
|
+
} else if (type === "blockQuote") {
|
|
35
|
+
// Blockquote followed by blockquote
|
|
36
|
+
for (const lineNumber of errorLineNumbers) {
|
|
37
|
+
addError(onError, lineNumber);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
} else {
|
|
41
|
+
// Blockquote not followed by blockquote
|
|
42
|
+
break;
|
|
22
43
|
}
|
|
23
44
|
}
|
|
24
|
-
prevToken = token;
|
|
25
|
-
if (token.type === "blockquote_open") {
|
|
26
|
-
prevLineNumber = token.map[1] + 1;
|
|
27
|
-
}
|
|
28
45
|
}
|
|
29
46
|
}
|
|
30
47
|
};
|
package/lib/md029.js
CHANGED
|
@@ -12,10 +12,13 @@ const listStyleExamples = {
|
|
|
12
12
|
"zero": "0/0/0"
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
16
|
+
/** @type import("./markdownlint").Rule */
|
|
15
17
|
module.exports = {
|
|
16
18
|
"names": [ "MD029", "ol-prefix" ],
|
|
17
19
|
"description": "Ordered list item prefix",
|
|
18
20
|
"tags": [ "ol" ],
|
|
21
|
+
"parser": "none",
|
|
19
22
|
"function": function MD029(params, onError) {
|
|
20
23
|
const style = String(params.config.style || "one_or_ordered");
|
|
21
24
|
const filteredLists = flattenedLists().filter((list) => !list.unordered);
|
package/lib/md030.js
CHANGED
|
@@ -5,19 +5,24 @@
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
6
|
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
7
7
|
|
|
8
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
9
|
+
/** @type import("./markdownlint").Rule */
|
|
8
10
|
module.exports = {
|
|
9
11
|
"names": [ "MD030", "list-marker-space" ],
|
|
10
12
|
"description": "Spaces after list markers",
|
|
11
13
|
"tags": [ "ol", "ul", "whitespace" ],
|
|
14
|
+
"parser": "micromark",
|
|
12
15
|
"function": function MD030(params, onError) {
|
|
13
16
|
const ulSingle = Number(params.config.ul_single || 1);
|
|
14
17
|
const olSingle = Number(params.config.ol_single || 1);
|
|
15
18
|
const ulMulti = Number(params.config.ul_multi || 1);
|
|
16
19
|
const olMulti = Number(params.config.ol_multi || 1);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
21
|
+
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
22
|
+
const micromarkTokens =
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
params.parsers.micromark.tokens;
|
|
25
|
+
const lists = filterByTypes(micromarkTokens, [ "listOrdered", "listUnordered" ]);
|
|
21
26
|
for (const list of lists) {
|
|
22
27
|
const ordered = (list.type === "listOrdered");
|
|
23
28
|
const listItemPrefixes =
|
package/lib/md031.js
CHANGED
|
@@ -7,10 +7,13 @@ const { lineMetadata } = require("./cache");
|
|
|
7
7
|
|
|
8
8
|
const codeFencePrefixRe = /^(.*?)[`~]/;
|
|
9
9
|
|
|
10
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
11
|
+
/** @type import("./markdownlint").Rule */
|
|
10
12
|
module.exports = {
|
|
11
13
|
"names": [ "MD031", "blanks-around-fences" ],
|
|
12
14
|
"description": "Fenced code blocks should be surrounded by blank lines",
|
|
13
15
|
"tags": [ "code", "blank_lines" ],
|
|
16
|
+
"parser": "none",
|
|
14
17
|
"function": function MD031(params, onError) {
|
|
15
18
|
const listItems = params.config.list_items;
|
|
16
19
|
const includeListItems = (listItems === undefined) ? true : !!listItems;
|
package/lib/md032.js
CHANGED
|
@@ -2,19 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext, blockquotePrefixRe, isBlankLine } =
|
|
6
|
-
|
|
7
|
-
const { filterByPredicate } = require("../helpers/micromark.cjs");
|
|
5
|
+
const { addErrorContext, blockquotePrefixRe, isBlankLine } = require("../helpers");
|
|
6
|
+
const { filterByPredicate, nonContentTokens } = require("../helpers/micromark.cjs");
|
|
8
7
|
|
|
9
|
-
const nonContentTokens = new Set([
|
|
10
|
-
"blockQuoteMarker",
|
|
11
|
-
"blockQuotePrefix",
|
|
12
|
-
"blockQuotePrefixWhitespace",
|
|
13
|
-
"lineEnding",
|
|
14
|
-
"lineEndingBlank",
|
|
15
|
-
"linePrefix",
|
|
16
|
-
"listItemIndent"
|
|
17
|
-
]);
|
|
18
8
|
const isList = (token) => (
|
|
19
9
|
(token.type === "listOrdered") || (token.type === "listUnordered")
|
|
20
10
|
);
|
|
@@ -35,16 +25,24 @@ const addBlankLineError = (onError, lines, lineIndex, lineNumber) => {
|
|
|
35
25
|
);
|
|
36
26
|
};
|
|
37
27
|
|
|
28
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
29
|
+
/** @type import("./markdownlint").Rule */
|
|
38
30
|
module.exports = {
|
|
39
31
|
"names": [ "MD032", "blanks-around-lists" ],
|
|
40
32
|
"description": "Lists should be surrounded by blank lines",
|
|
41
33
|
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
|
|
34
|
+
"parser": "micromark",
|
|
42
35
|
"function": function MD032(params, onError) {
|
|
43
|
-
|
|
36
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
37
|
+
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
38
|
+
const micromarkTokens =
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
params.parsers.micromark.tokens;
|
|
41
|
+
const { lines } = params;
|
|
44
42
|
|
|
45
43
|
// For every top-level list...
|
|
46
44
|
const topLevelLists = filterByPredicate(
|
|
47
|
-
|
|
45
|
+
micromarkTokens,
|
|
48
46
|
isList,
|
|
49
47
|
(token) => (
|
|
50
48
|
(isList(token) || (token.type === "htmlFlow")) ? [] : token.children
|
package/lib/md033.js
CHANGED
|
@@ -6,16 +6,23 @@ const { addError, nextLinesRe } = require("../helpers");
|
|
|
6
6
|
const { filterByTypes, getHtmlTagInfo } =
|
|
7
7
|
require("../helpers/micromark.cjs");
|
|
8
8
|
|
|
9
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
10
|
+
/** @type import("./markdownlint").Rule */
|
|
9
11
|
module.exports = {
|
|
10
12
|
"names": [ "MD033", "no-inline-html" ],
|
|
11
13
|
"description": "Inline HTML",
|
|
12
14
|
"tags": [ "html" ],
|
|
15
|
+
"parser": "micromark",
|
|
13
16
|
"function": function MD033(params, onError) {
|
|
14
17
|
let allowedElements = params.config.allowed_elements;
|
|
15
18
|
allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
|
|
16
19
|
allowedElements = allowedElements.map((element) => element.toLowerCase());
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
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" ])) {
|
|
19
26
|
const htmlTagInfo = getHtmlTagInfo(token);
|
|
20
27
|
if (
|
|
21
28
|
htmlTagInfo &&
|
package/lib/md034.js
CHANGED
|
@@ -6,15 +6,44 @@ const { addErrorContext } = require("../helpers");
|
|
|
6
6
|
const { filterByPredicate, filterByTypes, getHtmlTagInfo, inHtmlFlow, parse } =
|
|
7
7
|
require("../helpers/micromark.cjs");
|
|
8
8
|
|
|
9
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
10
|
+
/** @type import("./markdownlint").Rule */
|
|
9
11
|
module.exports = {
|
|
10
12
|
"names": [ "MD034", "no-bare-urls" ],
|
|
11
13
|
"description": "Bare URL used",
|
|
12
14
|
"tags": [ "links", "url" ],
|
|
15
|
+
"parser": "micromark",
|
|
13
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;
|
|
14
22
|
const literalAutolinks = (tokens) => (
|
|
15
23
|
filterByPredicate(
|
|
16
24
|
tokens,
|
|
17
|
-
(token) =>
|
|
25
|
+
(token) => {
|
|
26
|
+
if ((token.type === "literalAutolink") && !inHtmlFlow(token)) {
|
|
27
|
+
// Detect and ignore https://github.com/micromark/micromark/issues/164
|
|
28
|
+
const siblings = token.parent?.children;
|
|
29
|
+
// Commented-out due to not being able to exercise in test/code coverage
|
|
30
|
+
// || micromarkTokens;
|
|
31
|
+
const index = siblings?.indexOf(token);
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
const prev = siblings?.at(index - 1);
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
const next = siblings?.at(index + 1);
|
|
36
|
+
return !(
|
|
37
|
+
prev &&
|
|
38
|
+
next &&
|
|
39
|
+
(prev.type === "data") &&
|
|
40
|
+
(next.type === "data") &&
|
|
41
|
+
prev.text.endsWith("<") &&
|
|
42
|
+
next.text.startsWith(">")
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
},
|
|
18
47
|
(token) => {
|
|
19
48
|
const { children } = token;
|
|
20
49
|
const result = [];
|
|
@@ -46,10 +75,7 @@ module.exports = {
|
|
|
46
75
|
}
|
|
47
76
|
)
|
|
48
77
|
);
|
|
49
|
-
const autoLinks = filterByTypes(
|
|
50
|
-
params.parsers.micromark.tokens,
|
|
51
|
-
[ "literalAutolink" ]
|
|
52
|
-
);
|
|
78
|
+
const autoLinks = filterByTypes(micromarkTokens, [ "literalAutolink" ]);
|
|
53
79
|
if (autoLinks.length > 0) {
|
|
54
80
|
// Re-parse with correct link/image reference definition handling
|
|
55
81
|
const document = params.lines.join("\n");
|
package/lib/md035.js
CHANGED
|
@@ -5,14 +5,21 @@
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
6
|
const { filterByTypes } = require("../helpers/micromark.cjs");
|
|
7
7
|
|
|
8
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
9
|
+
/** @type import("./markdownlint").Rule */
|
|
8
10
|
module.exports = {
|
|
9
11
|
"names": [ "MD035", "hr-style" ],
|
|
10
12
|
"description": "Horizontal rule style",
|
|
11
13
|
"tags": [ "hr" ],
|
|
14
|
+
"parser": "micromark",
|
|
12
15
|
"function": function MD035(params, onError) {
|
|
13
16
|
let style = String(params.config.style || "consistent").trim();
|
|
14
|
-
|
|
15
|
-
|
|
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
|
+
const thematicBreaks = filterByTypes(micromarkTokens, [ "thematicBreak" ]);
|
|
16
23
|
for (const token of thematicBreaks) {
|
|
17
24
|
const { startLine, text } = token;
|
|
18
25
|
if (style === "consistent") {
|
package/lib/md036.js
CHANGED
|
@@ -3,54 +3,48 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorContext, allPunctuation } = require("../helpers");
|
|
6
|
+
const { filterByTypes, matchAndGetTokensByType } = require("../helpers/micromark.cjs");
|
|
6
7
|
|
|
8
|
+
/** @typedef {import("../helpers/micromark.cjs").TokenType} TokenType */
|
|
9
|
+
/** @type {Map<TokenType, TokenType[]>} */
|
|
10
|
+
const emphasisAndChildrenTypes = new Map([
|
|
11
|
+
[ "emphasis", [ "emphasisSequence", "emphasisText", "emphasisSequence" ] ],
|
|
12
|
+
[ "strong", [ "strongSequence", "strongText", "strongSequence" ] ]
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
16
|
+
/** @type import("./markdownlint").Rule */
|
|
7
17
|
module.exports = {
|
|
8
18
|
"names": [ "MD036", "no-emphasis-as-heading" ],
|
|
9
19
|
"description": "Emphasis used instead of a heading",
|
|
10
20
|
"tags": [ "headings", "emphasis" ],
|
|
21
|
+
"parser": "micromark",
|
|
11
22
|
"function": function MD036(params, onError) {
|
|
12
23
|
let punctuation = params.config.punctuation;
|
|
13
|
-
punctuation =
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} else if (token.type === "blockquote_open") {
|
|
35
|
-
return function inBlockquote(t) {
|
|
36
|
-
if (t.type !== "blockquote_close") {
|
|
37
|
-
return inBlockquote;
|
|
24
|
+
punctuation = String((punctuation === undefined) ? allPunctuation : punctuation);
|
|
25
|
+
const punctuationRe = new RegExp("[" + punctuation + "]$");
|
|
26
|
+
const paragraphTokens =
|
|
27
|
+
filterByTypes(params.parsers.micromark.tokens, [ "paragraph" ]).
|
|
28
|
+
filter((token) =>
|
|
29
|
+
(token.parent?.type === "content") && !token.parent?.parent && (token.children.length === 1)
|
|
30
|
+
);
|
|
31
|
+
for (const paragraphToken of paragraphTokens) {
|
|
32
|
+
const childToken = paragraphToken.children[0];
|
|
33
|
+
for (const [ emphasisType, emphasisChildrenTypes ] of emphasisAndChildrenTypes) {
|
|
34
|
+
if (childToken.type === emphasisType) {
|
|
35
|
+
const matchingTokens = matchAndGetTokensByType(childToken.children, emphasisChildrenTypes);
|
|
36
|
+
if (matchingTokens) {
|
|
37
|
+
const textToken = matchingTokens[1];
|
|
38
|
+
if (
|
|
39
|
+
(textToken.children.length === 1) &&
|
|
40
|
+
(textToken.children[0].type === "data") &&
|
|
41
|
+
!punctuationRe.test(textToken.text)
|
|
42
|
+
) {
|
|
43
|
+
addErrorContext(onError, textToken.startLine, textToken.text);
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
} else if (token.type === "list_item_open") {
|
|
42
|
-
return function inListItem(t) {
|
|
43
|
-
if (t.type !== "list_item_close") {
|
|
44
|
-
return inListItem;
|
|
45
|
-
}
|
|
46
|
-
return base;
|
|
47
|
-
};
|
|
46
|
+
}
|
|
48
47
|
}
|
|
49
|
-
return base;
|
|
50
|
-
}
|
|
51
|
-
let state = base;
|
|
52
|
-
for (const token of params.parsers.markdownit.tokens) {
|
|
53
|
-
state = state(token);
|
|
54
48
|
}
|
|
55
49
|
}
|
|
56
50
|
};
|