markdownlint 0.40.0 → 0.41.1
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 +15 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +13 -25
- package/doc/CustomRules.md +1 -1
- package/doc/Rules.md +80 -26
- package/doc/md001.md +1 -1
- package/doc/md011.md +1 -1
- package/doc/md022.md +15 -0
- package/doc/md025.md +1 -1
- package/doc/md026.md +1 -1
- package/doc/md028.md +13 -9
- package/doc/md029.md +11 -1
- package/doc/md034.md +1 -1
- package/doc/md035.md +12 -5
- package/doc/md041.md +2 -2
- package/doc/md042.md +6 -0
- package/doc/md045.md +1 -1
- package/doc/md060.md +15 -3
- package/helpers/README.md +4 -4
- package/helpers/helpers.cjs +55 -49
- package/helpers/micromark-helpers.cjs +5 -5
- package/helpers/package.json +2 -2
- package/helpers/shared.cjs +2 -2
- package/lib/cache.mjs +1 -0
- package/lib/configuration-strict.d.ts +116 -108
- package/lib/constants.mjs +2 -2
- package/lib/exports.d.mts +1 -0
- package/lib/exports.mjs +1 -0
- package/lib/markdownit.cjs +8 -7
- package/lib/markdownlint.d.mts +56 -41
- package/lib/markdownlint.mjs +40 -105
- package/lib/md004.mjs +1 -0
- package/lib/md005.mjs +1 -1
- package/lib/md019-md021.mjs +1 -0
- package/lib/md022.mjs +15 -11
- package/lib/md024.mjs +1 -1
- package/lib/md029.mjs +37 -25
- package/lib/md032.mjs +5 -4
- package/lib/md036.mjs +1 -0
- package/lib/md037.mjs +1 -2
- package/lib/md051.mjs +3 -1
- package/lib/md060.mjs +47 -8
- package/lib/micromark-parse.mjs +21 -5
- package/lib/resolve-module.cjs +4 -3
- package/lib/resolve-module.d.cts +1 -1
- package/package.json +37 -38
- package/schema/.markdownlint.jsonc +55 -53
- package/schema/.markdownlint.yaml +77 -75
- package/schema/markdownlint-config-schema-strict.json +120 -110
- package/schema/markdownlint-config-schema.json +120 -110
package/doc/md060.md
CHANGED
|
@@ -10,6 +10,8 @@ Parameters:
|
|
|
10
10
|
- `style`: Table column style (`string`, default `any`, values `aligned` /
|
|
11
11
|
`any` / `compact` / `tight`)
|
|
12
12
|
|
|
13
|
+
Fixable: Some violations can be fixed by tooling
|
|
14
|
+
|
|
13
15
|
This rule is triggered when the column separator pipe characters (`|`) of a
|
|
14
16
|
[GitHub Flavored Markdown table][gfm-table-060] are used inconsistently.
|
|
15
17
|
|
|
@@ -81,6 +83,16 @@ Style `tight` with `aligned_delimiter`:
|
|
|
81
83
|
|N|No|
|
|
82
84
|
```
|
|
83
85
|
|
|
86
|
+
Violations for styles `compact` and `tight` are simple/independent and can be
|
|
87
|
+
fixed automatically. However, fixing even single violations for style `aligned`
|
|
88
|
+
may require modifying the entire table, and therefore are not automatic:
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
|Alpha |Delta|
|
|
92
|
+
|------|-----|
|
|
93
|
+
|Charlie|Beta|
|
|
94
|
+
```
|
|
95
|
+
|
|
84
96
|
**Note**: This rule does not require leading/trailing pipe characters, so this
|
|
85
97
|
is also a valid table for style `compact`:
|
|
86
98
|
|
|
@@ -112,7 +124,7 @@ appear aligned in most editors and monospaced fonts:
|
|
|
112
124
|
|
|
113
125
|
Rationale: Consistent formatting makes it easier to understand a document.
|
|
114
126
|
|
|
115
|
-
[cjk-characters]: https://
|
|
116
|
-
[emoji]: https://
|
|
127
|
+
[cjk-characters]: https://wikipedia.org/wiki/CJK_characters
|
|
128
|
+
[emoji]: https://wikipedia.org/wiki/Emoji
|
|
117
129
|
[gfm-table-060]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/organizing-information-with-tables
|
|
118
|
-
[latin-script]: https://
|
|
130
|
+
[latin-script]: https://wikipedia.org/wiki/Latin_script
|
package/helpers/README.md
CHANGED
|
@@ -22,8 +22,8 @@ be useful to custom rule authors and may avoid duplicating code.
|
|
|
22
22
|
*None* - The entire body of code is tested to 100% coverage by the core
|
|
23
23
|
`markdownlint` project, so there are no additional tests here.
|
|
24
24
|
|
|
25
|
-
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
26
|
-
[jsdoc]: https://
|
|
27
|
-
[markdown]: https://
|
|
25
|
+
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.41.1/doc/CustomRules.md
|
|
26
|
+
[jsdoc]: https://wikipedia.org/wiki/JSDoc
|
|
27
|
+
[markdown]: https://wikipedia.org/wiki/Markdown
|
|
28
28
|
[markdownlint]: https://github.com/DavidAnson/markdownlint
|
|
29
|
-
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
29
|
+
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.41.1/doc/Rules.md
|
package/helpers/helpers.cjs
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/* eslint-disable unicorn/comment-content */
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const micromark = require("./micromark-helpers.cjs");
|
|
8
|
+
const { newlineRe, nextLinesRe } = require("./shared.cjs");
|
|
8
9
|
|
|
9
|
-
module.exports.newLineRe =
|
|
10
|
+
module.exports.newLineRe = newlineRe;
|
|
10
11
|
module.exports.nextLinesRe = nextLinesRe;
|
|
11
12
|
|
|
12
13
|
/** @typedef {import("../lib/exports.mjs").RuleOnError} RuleOnError */
|
|
@@ -20,6 +21,7 @@ module.exports.nextLinesRe = nextLinesRe;
|
|
|
20
21
|
// Regular expression for matching common front matter (YAML and TOML)
|
|
21
22
|
// @ts-ignore
|
|
22
23
|
module.exports.frontMatterRe =
|
|
24
|
+
// eslint-disable-next-line unicorn/prefer-unicode-code-point-escapes
|
|
23
25
|
/((^---[^\S\r\n\u2028\u2029]*$[\s\S]+?^---\s*)|(^\+\+\+[^\S\r\n\u2028\u2029]*$[\s\S]+?^(\+\+\+|\.\.\.)\s*)|(^\{[^\S\r\n\u2028\u2029]*$[\s\S]+?^\}\s*))(\r\n|\r|\n|$)/m;
|
|
24
26
|
|
|
25
27
|
// Regular expression for matching the start of inline disable/enable comments
|
|
@@ -178,6 +180,7 @@ const startsWithPipeRe = /^ *\|/;
|
|
|
178
180
|
const notCrLfRe = /[^\r\n]/g;
|
|
179
181
|
const notSpaceCrLfRe = /[^ \r\n]/g;
|
|
180
182
|
const trailingSpaceRe = / +[\r\n]/g;
|
|
183
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement
|
|
181
184
|
const replaceTrailingSpace = (/** @type {string} */ s) => s.replace(notCrLfRe, safeCommentCharacter);
|
|
182
185
|
module.exports.clearHtmlCommentText = function clearHtmlCommentText(/** @type {string} */ text) {
|
|
183
186
|
let i = 0;
|
|
@@ -207,7 +210,9 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(/** @type {s
|
|
|
207
210
|
// If a valid block/inline comment...
|
|
208
211
|
if (isValid) {
|
|
209
212
|
const clearedContent = content
|
|
213
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement
|
|
210
214
|
.replace(notSpaceCrLfRe, safeCommentCharacter)
|
|
215
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement
|
|
211
216
|
.replace(trailingSpaceRe, replaceTrailingSpace);
|
|
212
217
|
text =
|
|
213
218
|
text.slice(0, i + htmlCommentBegin.length) +
|
|
@@ -222,6 +227,7 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(/** @type {s
|
|
|
222
227
|
|
|
223
228
|
// Escapes a string for use in a RegExp
|
|
224
229
|
module.exports.escapeForRegExp = function escapeForRegExp(/** @type {string} */ str) {
|
|
230
|
+
// eslint-disable-next-line unicorn/prefer-regexp-escape
|
|
225
231
|
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
226
232
|
};
|
|
227
233
|
|
|
@@ -311,7 +317,7 @@ module.exports.addErrorDetailIf = addErrorDetailIf;
|
|
|
311
317
|
*/
|
|
312
318
|
function addErrorContext(onError, lineNumber, context, start, end, range, fixInfo) {
|
|
313
319
|
// Normalize new line characters so Linux and Windows trim consistently
|
|
314
|
-
context = ellipsify(context.replace(
|
|
320
|
+
context = ellipsify(context.replace(newlineRe, "\n"), start, end);
|
|
315
321
|
addError(onError, lineNumber, undefined, context, range, fixInfo);
|
|
316
322
|
}
|
|
317
323
|
module.exports.addErrorContext = addErrorContext;
|
|
@@ -438,59 +444,59 @@ function getReferenceLinkImageData(tokens) {
|
|
|
438
444
|
case "gfmFootnoteDefinitionLabelString":
|
|
439
445
|
labelPrefix = "^";
|
|
440
446
|
case "definitionLabelString": // eslint-disable-line no-fallthrough
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
447
|
+
{
|
|
448
|
+
// definitions and definitionLineIndices
|
|
449
|
+
const reference = normalizeReference(`${labelPrefix}${token.text}`);
|
|
450
|
+
if (definitions.has(reference)) {
|
|
451
|
+
duplicateDefinitions.push([ reference, token.startLine - 1 ]);
|
|
452
|
+
} else {
|
|
453
|
+
const parent =
|
|
454
|
+
micromark.getParentOfType(token, [ "definition" ]);
|
|
455
|
+
const destinationString = parent &&
|
|
456
|
+
micromark.getDescendantsByType(parent, [ "definitionDestination", "definitionDestinationRaw", "definitionDestinationString" ])[0]?.text;
|
|
457
|
+
definitions.set(
|
|
458
|
+
reference,
|
|
459
|
+
[ token.startLine - 1, destinationString || "" ]
|
|
460
|
+
);
|
|
456
461
|
}
|
|
457
462
|
break;
|
|
463
|
+
}
|
|
458
464
|
case "gfmFootnoteCall":
|
|
459
465
|
case "image":
|
|
460
466
|
case "link":
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
// Track link (handle shortcuts separately due to ambiguity in "text [text] text")
|
|
479
|
-
if (isShortcut || isFullOrCollapsed) {
|
|
480
|
-
addReferenceToDictionary(token, getText(referenceString) || label, isShortcut);
|
|
467
|
+
{
|
|
468
|
+
// Identify if shortcut or full/collapsed
|
|
469
|
+
let isShortcut = (token.children.length === 1);
|
|
470
|
+
const isFullOrCollapsed = (token.children.length === 2) && !token.children.some((t) => t.type === "resource");
|
|
471
|
+
const [ labelText ] = micromark.getDescendantsByType(token, [ "label", "labelText" ]);
|
|
472
|
+
const [ referenceString ] = micromark.getDescendantsByType(token, [ "reference", "referenceString" ]);
|
|
473
|
+
let label = getText(labelText);
|
|
474
|
+
// Identify if footnote
|
|
475
|
+
if (!isShortcut && !isFullOrCollapsed) {
|
|
476
|
+
const [ footnoteCallMarker, footnoteCallString ] = token.children.filter(
|
|
477
|
+
(t) => [ "gfmFootnoteCallMarker", "gfmFootnoteCallString" ].includes(t.type)
|
|
478
|
+
);
|
|
479
|
+
if (footnoteCallMarker && footnoteCallString) {
|
|
480
|
+
label = `${footnoteCallMarker.text}${footnoteCallString.text}`;
|
|
481
|
+
isShortcut = true;
|
|
481
482
|
}
|
|
482
483
|
}
|
|
484
|
+
// Track link (handle shortcuts separately due to ambiguity in "text [text] text")
|
|
485
|
+
if (isShortcut || isFullOrCollapsed) {
|
|
486
|
+
addReferenceToDictionary(token, getText(referenceString) || label, isShortcut);
|
|
487
|
+
}
|
|
483
488
|
break;
|
|
489
|
+
}
|
|
484
490
|
case "undefinedReferenceCollapsed":
|
|
485
491
|
case "undefinedReferenceFull":
|
|
486
492
|
case "undefinedReferenceShortcut":
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
+
{
|
|
494
|
+
const undefinedReference = micromark.getDescendantsByType(token, [ "undefinedReference" ])[0];
|
|
495
|
+
const label = undefinedReference.children.map((t) => t.text).join("");
|
|
496
|
+
const isShortcut = (token.type === "undefinedReferenceShortcut");
|
|
497
|
+
addReferenceToDictionary(token, label, isShortcut);
|
|
493
498
|
break;
|
|
499
|
+
}
|
|
494
500
|
}
|
|
495
501
|
}
|
|
496
502
|
return {
|
|
@@ -514,7 +520,7 @@ function getPreferredLineEnding(input, os) {
|
|
|
514
520
|
let cr = 0;
|
|
515
521
|
let lf = 0;
|
|
516
522
|
let crlf = 0;
|
|
517
|
-
const endings = input.match(
|
|
523
|
+
const endings = input.match(newlineRe) || [];
|
|
518
524
|
for (const ending of endings) {
|
|
519
525
|
// eslint-disable-next-line default-case
|
|
520
526
|
switch (ending) {
|
|
@@ -552,6 +558,7 @@ module.exports.getPreferredLineEnding = getPreferredLineEnding;
|
|
|
552
558
|
*/
|
|
553
559
|
function expandTildePath(file, os) {
|
|
554
560
|
const homedir = os && os.homedir && os.homedir();
|
|
561
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement
|
|
555
562
|
return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
|
|
556
563
|
}
|
|
557
564
|
module.exports.expandTildePath = expandTildePath;
|
|
@@ -630,9 +637,8 @@ function convertLintErrorsVersion2To0(errors) {
|
|
|
630
637
|
function copyAndTransformResults(results, transform) {
|
|
631
638
|
/** @type {Object.<string, LintErrors>} */
|
|
632
639
|
const newResults = {};
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const arr = results[key].map((r) => ({ ...r }));
|
|
640
|
+
for (const [ key, value ] of Object.entries(results)) {
|
|
641
|
+
const arr = value.map((r) => ({ ...r }));
|
|
636
642
|
newResults[key] = transform(arr);
|
|
637
643
|
}
|
|
638
644
|
// @ts-ignore
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { flatTokensSymbol, htmlFlowSymbol,
|
|
5
|
+
const { flatTokensSymbol, htmlFlowSymbol, newlineRe } = require("./shared.cjs");
|
|
6
6
|
|
|
7
7
|
// eslint-disable-next-line jsdoc/valid-types
|
|
8
8
|
/** @typedef {import("micromark-util-types", { with: { "resolution-mode": "import" } }).TokenType} TokenType */
|
|
@@ -17,8 +17,7 @@ const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = require("./shared.cjs");
|
|
|
17
17
|
* @returns {boolean} True iff the token is within an htmlFlow type.
|
|
18
18
|
*/
|
|
19
19
|
function inHtmlFlow(token) {
|
|
20
|
-
|
|
21
|
-
return Boolean(token[htmlFlowSymbol]);
|
|
20
|
+
return Object.hasOwn(token, htmlFlowSymbol);
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
/**
|
|
@@ -152,7 +151,6 @@ function getBlockQuotePrefixText(tokens, lineNumber, count = 1) {
|
|
|
152
151
|
.map((prefix) => prefix.text)
|
|
153
152
|
.join("")
|
|
154
153
|
.trimEnd()
|
|
155
|
-
// eslint-disable-next-line unicorn/prefer-spread
|
|
156
154
|
.concat("\n")
|
|
157
155
|
.repeat(count);
|
|
158
156
|
};
|
|
@@ -224,7 +222,7 @@ function getHeadingText(heading) {
|
|
|
224
222
|
.flatMap((descendant) => descendant.children.filter((child) => child.type !== "htmlText"))
|
|
225
223
|
.map((data) => data.text)
|
|
226
224
|
.join("")
|
|
227
|
-
.replace(
|
|
225
|
+
.replace(newlineRe, " ");
|
|
228
226
|
}
|
|
229
227
|
|
|
230
228
|
/**
|
|
@@ -285,7 +283,9 @@ function isDocfxTab(heading) {
|
|
|
285
283
|
// See https://dotnet.github.io/docfx/docs/markdown.html?tabs=linux%2Cdotnet#tabs
|
|
286
284
|
if (heading?.type === "atxHeading") {
|
|
287
285
|
const headingTexts = getDescendantsByType(heading, [ "atxHeadingText" ]);
|
|
286
|
+
// eslint-disable-next-line unicorn/better-dom-traversing
|
|
288
287
|
if ((headingTexts.length === 1) && (headingTexts[0].children.length === 1) && (headingTexts[0].children[0].type === "link")) {
|
|
288
|
+
// eslint-disable-next-line unicorn/better-dom-traversing
|
|
289
289
|
const resourceDestinationStrings = filterByTypes(headingTexts[0].children[0].children, [ "resourceDestinationString" ]);
|
|
290
290
|
return (resourceDestinationStrings.length === 1) && docfxTabSyntaxRe.test(resourceDestinationStrings[0].text);
|
|
291
291
|
}
|
package/helpers/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdownlint-rule-helpers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "A collection of markdownlint helper functions for custom rules",
|
|
5
5
|
"main": "./helpers.cjs",
|
|
6
6
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"bugs": "https://github.com/DavidAnson/markdownlint/issues",
|
|
18
18
|
"funding": "https://github.com/sponsors/DavidAnson",
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=22"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"markdownlint",
|
package/helpers/shared.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
// Symbol for
|
|
5
|
+
// Symbol for identifying the flat tokens array from micromark parse
|
|
6
6
|
module.exports.flatTokensSymbol = Symbol("flat-tokens");
|
|
7
7
|
|
|
8
8
|
// Symbol for identifying the htmlFlow token from micromark parse
|
|
@@ -10,7 +10,7 @@ module.exports.htmlFlowSymbol = Symbol("html-flow");
|
|
|
10
10
|
|
|
11
11
|
// Regular expression for matching common newline characters
|
|
12
12
|
// See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js
|
|
13
|
-
module.exports.
|
|
13
|
+
module.exports.newlineRe = /\r\n?|\n/g;
|
|
14
14
|
|
|
15
15
|
// Regular expression for matching next lines
|
|
16
16
|
module.exports.nextLinesRe = /[\r\n][\s\S]*$/;
|