markdownlint 0.34.0 → 0.36.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 +21 -0
- package/README.md +97 -45
- package/demo/markdownlint-browser.js +2186 -2164
- package/doc/CustomRules.md +66 -255
- package/doc/Rules.md +102 -29
- package/doc/md003.md +2 -2
- package/doc/md004.md +4 -3
- package/doc/md034.md +5 -0
- package/doc/md035.md +3 -8
- package/doc/md044.md +10 -0
- package/doc/md046.md +2 -2
- package/doc/md048.md +3 -2
- package/doc/md049.md +4 -3
- package/doc/md050.md +4 -4
- package/doc/md051.md +11 -3
- package/doc/md055.md +3 -2
- package/doc/md058.md +48 -0
- package/helpers/README.md +2 -45
- package/helpers/helpers.js +115 -607
- package/helpers/micromark-helpers.cjs +296 -0
- package/helpers/micromark-parse.cjs +313 -0
- package/helpers/package.json +5 -2
- package/helpers/shared.js +6 -0
- package/helpers/test.cjs +28 -0
- package/lib/cache.js +62 -13
- package/lib/configuration-strict.d.ts +1199 -0
- package/lib/configuration.d.ts +3 -1173
- package/lib/constants.js +3 -2
- package/lib/markdownit.cjs +172 -0
- package/lib/markdownlint.d.ts +103 -56
- package/lib/markdownlint.js +180 -120
- 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 +7 -11
- package/lib/md009.js +50 -44
- package/lib/md010.js +52 -33
- package/lib/md011.js +32 -23
- package/lib/md012.js +17 -9
- package/lib/md013.js +44 -38
- package/lib/md014.js +31 -38
- package/lib/md018.js +17 -9
- package/lib/md019-md021.js +80 -0
- package/lib/md020.js +14 -8
- package/lib/md022.js +13 -29
- 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 +7 -12
- package/lib/md028.js +3 -8
- package/lib/md029.js +40 -34
- package/lib/md030.js +4 -10
- package/lib/md031.js +45 -23
- package/lib/md032.js +33 -31
- package/lib/md033.js +3 -8
- package/lib/md034.js +21 -34
- package/lib/md035.js +2 -7
- package/lib/md036.js +19 -24
- package/lib/md037.js +3 -8
- package/lib/md038.js +11 -22
- package/lib/md039.js +64 -54
- package/lib/md040.js +13 -20
- package/lib/md041.js +5 -5
- package/lib/md042.js +44 -38
- package/lib/md043.js +20 -14
- package/lib/md044.js +34 -36
- package/lib/md045.js +5 -10
- package/lib/md046.js +2 -8
- package/lib/md048.js +30 -23
- package/lib/md049-md050.js +22 -12
- package/lib/md051.js +20 -28
- package/lib/md052.js +2 -2
- package/lib/md053.js +7 -6
- package/lib/md054.js +16 -23
- package/lib/md055.js +41 -49
- package/lib/md056.js +32 -33
- package/lib/md058.js +58 -0
- package/lib/rules.js +11 -4
- package/package.json +23 -20
- package/schema/.markdownlint.jsonc +58 -52
- package/schema/.markdownlint.yaml +56 -51
- package/schema/ValidatingConfiguration.md +6 -8
- package/schema/markdownlint-config-schema-strict.json +1841 -0
- package/schema/markdownlint-config-schema.json +141 -109
- package/style/prettier.json +1 -0
- package/helpers/micromark.cjs +0 -445
- package/lib/md019.js +0 -42
- package/lib/md021.js +0 -65
package/lib/md049-md050.js
CHANGED
|
@@ -2,11 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError
|
|
6
|
-
const { filterByPredicate,
|
|
5
|
+
const { addError } = require("../helpers");
|
|
6
|
+
const { filterByPredicate, getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
|
|
7
7
|
|
|
8
8
|
const intrawordRe = /^\w$/;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Return the string representation of a emphasis or strong markup character.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} markup Emphasis or strong string.
|
|
14
|
+
* @returns {"asterisk" | "underscore"} String representation.
|
|
15
|
+
*/
|
|
16
|
+
function emphasisOrStrongStyleFor(markup) {
|
|
17
|
+
switch (markup[0]) {
|
|
18
|
+
case "*":
|
|
19
|
+
return "asterisk";
|
|
20
|
+
default:
|
|
21
|
+
return "underscore";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
10
25
|
/**
|
|
11
26
|
* @param {import("./markdownlint").RuleParams} params Rule parameters.
|
|
12
27
|
* @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
|
|
@@ -18,21 +33,16 @@ const intrawordRe = /^\w$/;
|
|
|
18
33
|
*/
|
|
19
34
|
const impl =
|
|
20
35
|
(params, onError, type, typeSequence, asterisk, underline, style = "consistent") => {
|
|
21
|
-
|
|
22
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
23
|
-
const micromarkTokens =
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
params.parsers.micromark.tokens;
|
|
26
|
-
const { lines } = params;
|
|
36
|
+
const { lines, parsers } = params;
|
|
27
37
|
const emphasisTokens = filterByPredicate(
|
|
28
|
-
|
|
38
|
+
parsers.micromark.tokens,
|
|
29
39
|
(token) => token.type === type,
|
|
30
40
|
(token) => ((token.type === "htmlFlow") ? [] : token.children)
|
|
31
41
|
);
|
|
32
42
|
for (const token of emphasisTokens) {
|
|
33
|
-
const
|
|
34
|
-
const startSequence =
|
|
35
|
-
const endSequence =
|
|
43
|
+
const sequences = getDescendantsByType(token, [ typeSequence ]);
|
|
44
|
+
const startSequence = sequences[0];
|
|
45
|
+
const endSequence = sequences[sequences.length - 1];
|
|
36
46
|
if (startSequence && endSequence) {
|
|
37
47
|
const markupStyle = emphasisOrStrongStyleFor(startSequence.text);
|
|
38
48
|
if (style === "consistent") {
|
package/lib/md051.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError,
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
require("../helpers/micromark.cjs");
|
|
5
|
+
const { addError, getHtmlAttributeRe } = require("../helpers");
|
|
6
|
+
const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark-helpers.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
9
8
|
|
|
10
9
|
// Regular expression for identifying HTML anchor names
|
|
11
10
|
const idRe = getHtmlAttributeRe("id");
|
|
@@ -23,7 +22,7 @@ const tokensInclude = new Set(
|
|
|
23
22
|
* Converts a Markdown heading into an HTML fragment according to the rules
|
|
24
23
|
* used by GitHub.
|
|
25
24
|
*
|
|
26
|
-
* @param {import("../helpers/micromark.cjs").Token} headingText Heading text token.
|
|
25
|
+
* @param {import("../helpers/micromark-helpers.cjs").Token} headingText Heading text token.
|
|
27
26
|
* @returns {string} Fragment string for heading.
|
|
28
27
|
*/
|
|
29
28
|
function convertHeadingToHTMLFragment(headingText) {
|
|
@@ -52,7 +51,7 @@ function convertHeadingToHTMLFragment(headingText) {
|
|
|
52
51
|
/**
|
|
53
52
|
* Unescapes the text of a String-type micromark Token.
|
|
54
53
|
*
|
|
55
|
-
* @param {import("../helpers/micromark.cjs").Token} token String-type micromark Token.
|
|
54
|
+
* @param {import("../helpers/micromark-helpers.cjs").Token} token String-type micromark Token.
|
|
56
55
|
* @returns {string} Unescaped token text.
|
|
57
56
|
*/
|
|
58
57
|
function unescapeStringTokenText(token) {
|
|
@@ -69,15 +68,11 @@ module.exports = {
|
|
|
69
68
|
"tags": [ "links" ],
|
|
70
69
|
"parser": "micromark",
|
|
71
70
|
"function": function MD051(params, onError) {
|
|
72
|
-
|
|
73
|
-
/** @type import("../helpers/micromark.cjs").Token[] */
|
|
74
|
-
const micromarkTokens =
|
|
75
|
-
// @ts-ignore
|
|
76
|
-
params.parsers.micromark.tokens;
|
|
71
|
+
const ignoreCase = params.config.ignore_case || false;
|
|
77
72
|
const fragments = new Map();
|
|
78
73
|
|
|
79
74
|
// Process headings
|
|
80
|
-
const headingTexts =
|
|
75
|
+
const headingTexts = filterByTypesCached([ "atxHeadingText", "setextHeadingText" ]);
|
|
81
76
|
for (const headingText of headingTexts) {
|
|
82
77
|
const fragment = convertHeadingToHTMLFragment(headingText);
|
|
83
78
|
if (fragment !== "#") {
|
|
@@ -97,7 +92,7 @@ module.exports = {
|
|
|
97
92
|
}
|
|
98
93
|
|
|
99
94
|
// Process HTML anchors
|
|
100
|
-
for (const token of
|
|
95
|
+
for (const token of filterByTypesCached([ "htmlText" ], true)) {
|
|
101
96
|
const htmlTagInfo = getHtmlTagInfo(token);
|
|
102
97
|
if (htmlTagInfo && !htmlTagInfo.close) {
|
|
103
98
|
const anchorMatch = idRe.exec(token.text) ||
|
|
@@ -110,13 +105,13 @@ module.exports = {
|
|
|
110
105
|
|
|
111
106
|
// Process link and definition fragments
|
|
112
107
|
// eslint-disable-next-line jsdoc/valid-types
|
|
113
|
-
/** @type import("../helpers/micromark.cjs").TokenType[][] */
|
|
108
|
+
/** @type import("../helpers/micromark-helpers.cjs").TokenType[][] */
|
|
114
109
|
const parentChilds = [
|
|
115
110
|
[ "link", "resourceDestinationString" ],
|
|
116
111
|
[ "definition", "definitionDestinationString" ]
|
|
117
112
|
];
|
|
118
113
|
for (const [ parentType, definitionType ] of parentChilds) {
|
|
119
|
-
const links =
|
|
114
|
+
const links = filterByTypesCached([ parentType ]);
|
|
120
115
|
for (const link of links) {
|
|
121
116
|
const definitions = filterByTypes(link.children, [ definitionType ]);
|
|
122
117
|
for (const definition of definitions) {
|
|
@@ -129,11 +124,8 @@ module.exports = {
|
|
|
129
124
|
!fragments.has(encodedText) &&
|
|
130
125
|
!lineFragmentRe.test(encodedText)
|
|
131
126
|
) {
|
|
132
|
-
// eslint-disable-next-line no-undef-init
|
|
133
127
|
let context = undefined;
|
|
134
|
-
// eslint-disable-next-line no-undef-init
|
|
135
128
|
let range = undefined;
|
|
136
|
-
// eslint-disable-next-line no-undef-init
|
|
137
129
|
let fixInfo = undefined;
|
|
138
130
|
if (link.startLine === link.endLine) {
|
|
139
131
|
context = link.text;
|
|
@@ -149,16 +141,16 @@ module.exports = {
|
|
|
149
141
|
if (mixedCaseKey) {
|
|
150
142
|
// @ts-ignore
|
|
151
143
|
(fixInfo || {}).insertText = mixedCaseKey;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
if (!ignoreCase && (mixedCaseKey !== text)) {
|
|
145
|
+
addError(
|
|
146
|
+
onError,
|
|
147
|
+
link.startLine,
|
|
148
|
+
`Expected: ${mixedCaseKey}; Actual: ${text}`,
|
|
149
|
+
context,
|
|
150
|
+
range,
|
|
151
|
+
fixInfo
|
|
152
|
+
);
|
|
153
|
+
}
|
|
162
154
|
} else {
|
|
163
155
|
addError(
|
|
164
156
|
onError,
|
package/lib/md052.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addError } = require("../helpers");
|
|
6
|
-
const {
|
|
6
|
+
const { getReferenceLinkImageData } = require("./cache");
|
|
7
7
|
|
|
8
8
|
// eslint-disable-next-line jsdoc/valid-types
|
|
9
9
|
/** @type import("./markdownlint").Rule */
|
|
@@ -16,7 +16,7 @@ module.exports = {
|
|
|
16
16
|
"function": function MD052(params, onError) {
|
|
17
17
|
const { config, lines } = params;
|
|
18
18
|
const shortcutSyntax = config.shortcut_syntax || false;
|
|
19
|
-
const { definitions, references, shortcuts } =
|
|
19
|
+
const { definitions, references, shortcuts } = getReferenceLinkImageData();
|
|
20
20
|
const entries = shortcutSyntax ?
|
|
21
21
|
[ ...references.entries(), ...shortcuts.entries() ] :
|
|
22
22
|
references.entries();
|
package/lib/md053.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addError, ellipsify
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const { addError, ellipsify } = require("../helpers");
|
|
6
|
+
const { getReferenceLinkImageData } = require("./cache");
|
|
7
|
+
|
|
8
|
+
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line jsdoc/valid-types
|
|
10
11
|
/** @type import("./markdownlint").Rule */
|
|
@@ -17,7 +18,7 @@ module.exports = {
|
|
|
17
18
|
const ignored = new Set(params.config.ignored_definitions || [ "//" ]);
|
|
18
19
|
const lines = params.lines;
|
|
19
20
|
const { references, shortcuts, definitions, duplicateDefinitions } =
|
|
20
|
-
|
|
21
|
+
getReferenceLinkImageData();
|
|
21
22
|
const singleLineDefinition = (line) => (
|
|
22
23
|
line.replace(linkReferenceDefinitionRe, "").trim().length > 0
|
|
23
24
|
);
|
|
@@ -39,7 +40,7 @@ module.exports = {
|
|
|
39
40
|
`Unused link or image reference definition: "${label}"`,
|
|
40
41
|
ellipsify(line),
|
|
41
42
|
[ 1, line.length ],
|
|
42
|
-
singleLineDefinition(line) ? deleteFixInfo :
|
|
43
|
+
singleLineDefinition(line) ? deleteFixInfo : undefined
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -54,7 +55,7 @@ module.exports = {
|
|
|
54
55
|
`Duplicate link or image reference definition: "${label}"`,
|
|
55
56
|
ellipsify(line),
|
|
56
57
|
[ 1, line.length ],
|
|
57
|
-
singleLineDefinition(line) ? deleteFixInfo :
|
|
58
|
+
singleLineDefinition(line) ? deleteFixInfo : undefined
|
|
58
59
|
);
|
|
59
60
|
}
|
|
60
61
|
}
|
package/lib/md054.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorContext, nextLinesRe } = require("../helpers");
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
const { referenceLinkImageData } = require("./cache");
|
|
6
|
+
const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
|
|
7
|
+
const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
|
|
9
8
|
|
|
10
9
|
const backslashEscapeRe = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g;
|
|
11
10
|
const removeBackslashEscapes = (text) => text.replace(backslashEscapeRe, "$1");
|
|
@@ -40,35 +39,29 @@ module.exports = {
|
|
|
40
39
|
// Everything allowed, nothing to check
|
|
41
40
|
return;
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const micromarkTokens =
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
params.parsers.micromark.tokens;
|
|
48
|
-
const { definitions } = referenceLinkImageData();
|
|
49
|
-
const links = filterByTypes(micromarkTokens, [ "autolink", "image", "link" ]);
|
|
42
|
+
const { definitions } = getReferenceLinkImageData();
|
|
43
|
+
const links = filterByTypesCached([ "autolink", "image", "link" ]);
|
|
50
44
|
for (const link of links) {
|
|
51
45
|
let label = null;
|
|
52
46
|
let destination = null;
|
|
53
47
|
const {
|
|
54
|
-
|
|
48
|
+
endColumn, endLine, startColumn, startLine, text, type
|
|
55
49
|
} = link;
|
|
56
50
|
const image = (type === "image");
|
|
57
51
|
let isError = false;
|
|
58
52
|
if (type === "autolink") {
|
|
59
53
|
// link kind is an autolink
|
|
60
|
-
destination =
|
|
54
|
+
destination = getDescendantsByType(link, [ "autolinkProtocol" ])[0].text;
|
|
61
55
|
label = destination;
|
|
62
56
|
isError = !autolink;
|
|
63
57
|
} else {
|
|
64
58
|
// link type is "image" or "link"
|
|
65
|
-
|
|
66
|
-
label = getTokenTextByType(descendents, "labelText");
|
|
59
|
+
label = getDescendantsByType(link, [ "label", "labelText" ])[0].text;
|
|
67
60
|
destination =
|
|
68
|
-
|
|
61
|
+
getDescendantsByType(link, [ "resource", "resourceDestination", [ "resourceDestinationLiteral", "resourceDestinationRaw" ], "resourceDestinationString" ])[0]?.text;
|
|
69
62
|
if (destination) {
|
|
70
63
|
// link kind is an inline link
|
|
71
|
-
const title =
|
|
64
|
+
const title = getDescendantsByType(link, [ "resource", "resourceTitle", "resourceTitleString" ])[0]?.text;
|
|
72
65
|
isError = !inline || (
|
|
73
66
|
!urlInline &&
|
|
74
67
|
autolink &&
|
|
@@ -79,9 +72,9 @@ module.exports = {
|
|
|
79
72
|
);
|
|
80
73
|
} else {
|
|
81
74
|
// link kind is a full/collapsed/shortcut reference link
|
|
82
|
-
const isShortcut =
|
|
83
|
-
const referenceString =
|
|
84
|
-
const isCollapsed = (referenceString ===
|
|
75
|
+
const isShortcut = getDescendantsByType(link, [ "reference" ]).length === 0;
|
|
76
|
+
const referenceString = getDescendantsByType(link, [ "reference", "referenceString" ])[0]?.text;
|
|
77
|
+
const isCollapsed = (referenceString === undefined);
|
|
85
78
|
const definition = definitions.get(referenceString || label);
|
|
86
79
|
destination = definition && definition[1];
|
|
87
80
|
isError = destination &&
|
|
@@ -89,8 +82,8 @@ module.exports = {
|
|
|
89
82
|
}
|
|
90
83
|
}
|
|
91
84
|
if (isError) {
|
|
92
|
-
let range =
|
|
93
|
-
let fixInfo =
|
|
85
|
+
let range = undefined;
|
|
86
|
+
let fixInfo = undefined;
|
|
94
87
|
if (startLine === endLine) {
|
|
95
88
|
range = [ startColumn, endColumn - startColumn ];
|
|
96
89
|
let insertText = null;
|
|
@@ -119,8 +112,8 @@ module.exports = {
|
|
|
119
112
|
onError,
|
|
120
113
|
startLine,
|
|
121
114
|
text.replace(nextLinesRe, ""),
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
undefined,
|
|
116
|
+
undefined,
|
|
124
117
|
range,
|
|
125
118
|
fixInfo
|
|
126
119
|
);
|
package/lib/md055.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
|
const whitespaceTypes = new Set([ "linePrefix", "whitespace" ]);
|
|
9
9
|
const ignoreWhitespace = (tokens) => tokens.filter(
|
|
@@ -27,54 +27,46 @@ module.exports = {
|
|
|
27
27
|
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "trailing_only"));
|
|
28
28
|
let expectedTrailingPipe =
|
|
29
29
|
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "leading_only"));
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
lastCell.endLine,
|
|
70
|
-
expectedStyle,
|
|
71
|
-
actualStyle,
|
|
72
|
-
`${expectedTrailingPipe ? "Missing" : "Unexpected"} trailing pipe`,
|
|
73
|
-
undefined,
|
|
74
|
-
makeRange(lastCell.endColumn - 1, row.endColumn - 1)
|
|
75
|
-
);
|
|
76
|
-
}
|
|
30
|
+
const rows = filterByTypesCached([ "tableDelimiterRow", "tableRow" ]);
|
|
31
|
+
for (const row of rows) {
|
|
32
|
+
// The following uses of first/lastOrNothing lack fallback handling
|
|
33
|
+
// because it seems not to be possible (i.e., 0% coverage)
|
|
34
|
+
const firstCell = firstOrNothing(row.children);
|
|
35
|
+
const leadingToken = firstOrNothing(ignoreWhitespace(firstCell.children));
|
|
36
|
+
const actualLeadingPipe = (leadingToken.type === "tableCellDivider");
|
|
37
|
+
const lastCell = lastOrNothing(row.children);
|
|
38
|
+
const trailingToken = lastOrNothing(ignoreWhitespace(lastCell.children));
|
|
39
|
+
const actualTrailingPipe = (trailingToken.type === "tableCellDivider");
|
|
40
|
+
const actualStyle = actualLeadingPipe ?
|
|
41
|
+
(actualTrailingPipe ? "leading_and_trailing" : "leading_only") :
|
|
42
|
+
(actualTrailingPipe ? "trailing_only" : "no_leading_or_trailing");
|
|
43
|
+
if (expectedStyle === "consistent") {
|
|
44
|
+
expectedStyle = actualStyle;
|
|
45
|
+
expectedLeadingPipe = actualLeadingPipe;
|
|
46
|
+
expectedTrailingPipe = actualTrailingPipe;
|
|
47
|
+
}
|
|
48
|
+
if (actualLeadingPipe !== expectedLeadingPipe) {
|
|
49
|
+
addErrorDetailIf(
|
|
50
|
+
onError,
|
|
51
|
+
firstCell.startLine,
|
|
52
|
+
expectedStyle,
|
|
53
|
+
actualStyle,
|
|
54
|
+
`${expectedLeadingPipe ? "Missing" : "Unexpected"} leading pipe`,
|
|
55
|
+
undefined,
|
|
56
|
+
makeRange(row.startColumn, firstCell.startColumn)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (actualTrailingPipe !== expectedTrailingPipe) {
|
|
60
|
+
addErrorDetailIf(
|
|
61
|
+
onError,
|
|
62
|
+
lastCell.endLine,
|
|
63
|
+
expectedStyle,
|
|
64
|
+
actualStyle,
|
|
65
|
+
`${expectedTrailingPipe ? "Missing" : "Unexpected"} trailing pipe`,
|
|
66
|
+
undefined,
|
|
67
|
+
makeRange(lastCell.endColumn - 1, row.endColumn - 1)
|
|
68
|
+
);
|
|
77
69
|
}
|
|
78
70
|
}
|
|
79
71
|
}
|
|
80
|
-
}
|
|
72
|
+
};
|
package/lib/md056.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
|
-
const {
|
|
6
|
+
const { getParentOfType } = require("../helpers/micromark-helpers.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
7
8
|
|
|
8
9
|
const makeRange = (start, end) => [ start, end - start + 1 ];
|
|
9
10
|
|
|
@@ -15,38 +16,36 @@ module.exports = {
|
|
|
15
16
|
"tags": [ "table" ],
|
|
16
17
|
"parser": "micromark",
|
|
17
18
|
"function": function MD056(params, onError) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let expectedCount = 0;
|
|
27
|
-
for (const row of rows) {
|
|
28
|
-
const cells = filterByTypes(row.children, [ "tableData", "tableDelimiter", "tableHeader" ]);
|
|
29
|
-
const actualCount = cells.length;
|
|
30
|
-
expectedCount ||= actualCount;
|
|
31
|
-
let detail = null;
|
|
32
|
-
let range = null;
|
|
33
|
-
if (actualCount < expectedCount) {
|
|
34
|
-
detail = "Too few cells, row will be missing data";
|
|
35
|
-
range = [ row.endColumn - 1, 1 ];
|
|
36
|
-
} else if (expectedCount < actualCount) {
|
|
37
|
-
detail = "Too many cells, extra data will be missing";
|
|
38
|
-
range = makeRange(cells[expectedCount].startColumn, row.endColumn - 1);
|
|
39
|
-
}
|
|
40
|
-
addErrorDetailIf(
|
|
41
|
-
onError,
|
|
42
|
-
row.endLine,
|
|
43
|
-
expectedCount,
|
|
44
|
-
actualCount,
|
|
45
|
-
detail,
|
|
46
|
-
null,
|
|
47
|
-
range
|
|
48
|
-
);
|
|
19
|
+
const rows = filterByTypesCached([ "tableDelimiterRow", "tableRow" ]);
|
|
20
|
+
let expectedCount = 0;
|
|
21
|
+
let currentTable = null;
|
|
22
|
+
for (const row of rows) {
|
|
23
|
+
const table = getParentOfType(row, [ "table" ]);
|
|
24
|
+
if (currentTable !== table) {
|
|
25
|
+
expectedCount = 0;
|
|
26
|
+
currentTable = table;
|
|
49
27
|
}
|
|
28
|
+
const cells = row.children.filter((child) => [ "tableData", "tableDelimiter", "tableHeader" ].includes(child.type));
|
|
29
|
+
const actualCount = cells.length;
|
|
30
|
+
expectedCount ||= actualCount;
|
|
31
|
+
let detail = undefined;
|
|
32
|
+
let range = undefined;
|
|
33
|
+
if (actualCount < expectedCount) {
|
|
34
|
+
detail = "Too few cells, row will be missing data";
|
|
35
|
+
range = [ row.endColumn - 1, 1 ];
|
|
36
|
+
} else if (expectedCount < actualCount) {
|
|
37
|
+
detail = "Too many cells, extra data will be missing";
|
|
38
|
+
range = makeRange(cells[expectedCount].startColumn, row.endColumn - 1);
|
|
39
|
+
}
|
|
40
|
+
addErrorDetailIf(
|
|
41
|
+
onError,
|
|
42
|
+
row.endLine,
|
|
43
|
+
expectedCount,
|
|
44
|
+
actualCount,
|
|
45
|
+
detail,
|
|
46
|
+
undefined,
|
|
47
|
+
range
|
|
48
|
+
);
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
|
-
}
|
|
51
|
+
};
|
package/lib/md058.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, isBlankLine } = require("../helpers");
|
|
6
|
+
const { getBlockQuotePrefixText } = require("../helpers/micromark-helpers.cjs");
|
|
7
|
+
const { filterByTypesCached } = require("./cache");
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
10
|
+
/** @type import("./markdownlint").Rule */
|
|
11
|
+
module.exports = {
|
|
12
|
+
"names": [ "MD058", "blanks-around-tables" ],
|
|
13
|
+
"description": "Tables should be surrounded by blank lines",
|
|
14
|
+
"tags": [ "table" ],
|
|
15
|
+
"parser": "micromark",
|
|
16
|
+
"function": function MD058(params, onError) {
|
|
17
|
+
const { lines } = params;
|
|
18
|
+
const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
|
|
19
|
+
|
|
20
|
+
// For every table...
|
|
21
|
+
const tables = filterByTypesCached([ "table" ]);
|
|
22
|
+
for (const table of tables) {
|
|
23
|
+
|
|
24
|
+
// Look for a blank line above the table
|
|
25
|
+
const firstLineNumber = table.startLine;
|
|
26
|
+
if (!isBlankLine(lines[firstLineNumber - 2])) {
|
|
27
|
+
addErrorContext(
|
|
28
|
+
onError,
|
|
29
|
+
firstLineNumber,
|
|
30
|
+
lines[firstLineNumber - 1].trim(),
|
|
31
|
+
undefined,
|
|
32
|
+
undefined,
|
|
33
|
+
undefined,
|
|
34
|
+
{
|
|
35
|
+
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, firstLineNumber)
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Look for a blank line below the table
|
|
41
|
+
const lastLineNumber = table.endLine;
|
|
42
|
+
if (!isBlankLine(lines[lastLineNumber])) {
|
|
43
|
+
addErrorContext(
|
|
44
|
+
onError,
|
|
45
|
+
lastLineNumber,
|
|
46
|
+
lines[lastLineNumber - 1].trim(),
|
|
47
|
+
undefined,
|
|
48
|
+
undefined,
|
|
49
|
+
undefined,
|
|
50
|
+
{
|
|
51
|
+
"lineNumber": lastLineNumber + 1,
|
|
52
|
+
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, lastLineNumber)
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
package/lib/rules.js
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
const { homepage, version } = require("./constants");
|
|
6
6
|
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const [ md019, md021 ] = require("./md019-md021");
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
const [ md049, md050 ] = require("./md049-md050");
|
|
11
|
+
|
|
7
12
|
const rules = [
|
|
8
13
|
require("./md001"),
|
|
9
14
|
// md002: Deprecated and removed
|
|
@@ -19,9 +24,9 @@ const rules = [
|
|
|
19
24
|
require("./md013"),
|
|
20
25
|
require("./md014"),
|
|
21
26
|
require("./md018"),
|
|
22
|
-
|
|
27
|
+
md019,
|
|
23
28
|
require("./md020"),
|
|
24
|
-
|
|
29
|
+
md021,
|
|
25
30
|
require("./md022"),
|
|
26
31
|
require("./md023"),
|
|
27
32
|
require("./md024"),
|
|
@@ -49,14 +54,16 @@ const rules = [
|
|
|
49
54
|
require("./md046"),
|
|
50
55
|
require("./md047"),
|
|
51
56
|
require("./md048"),
|
|
52
|
-
|
|
57
|
+
md049,
|
|
58
|
+
md050,
|
|
53
59
|
require("./md051"),
|
|
54
60
|
require("./md052"),
|
|
55
61
|
require("./md053"),
|
|
56
62
|
require("./md054"),
|
|
57
63
|
require("./md055"),
|
|
58
|
-
require("./md056")
|
|
64
|
+
require("./md056"),
|
|
59
65
|
// md057: See https://github.com/markdownlint/markdownlint
|
|
66
|
+
require("./md058")
|
|
60
67
|
];
|
|
61
68
|
for (const rule of rules) {
|
|
62
69
|
const name = rule.names[0].toLowerCase();
|