@alexlit/lint-kit 189.1.0 → 190.0.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/package.json +1 -1
- package/packages/config-eslint/package.json +7 -7
- package/packages/config-eslint/plugins/json.js +1 -1
- package/packages/config-eslint/plugins/prettier.js +1 -1
- package/packages/config-eslint/plugins/unicorn.js +2 -1
- package/packages/config-markdownlint/node_modules/ansi-regex/index.d.ts +33 -0
- package/packages/config-markdownlint/node_modules/ansi-regex/index.js +14 -0
- package/packages/config-markdownlint/node_modules/ansi-regex/license +9 -0
- package/packages/config-markdownlint/node_modules/ansi-regex/package.json +61 -0
- package/packages/config-markdownlint/node_modules/ansi-regex/readme.md +66 -0
- package/packages/config-markdownlint/node_modules/markdownlint/CHANGELOG.md +529 -0
- package/packages/config-markdownlint/node_modules/markdownlint/CONTRIBUTING.md +92 -0
- package/packages/config-markdownlint/node_modules/markdownlint/LICENSE +21 -0
- package/packages/config-markdownlint/node_modules/markdownlint/README.md +1112 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/CustomRules.md +194 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/Prettier.md +27 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/ReleaseProcess.md +20 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/Rules.md +2858 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md001.md +51 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md003.md +59 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md004.md +50 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md005.md +53 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md007.md +52 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md009.md +50 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md010.md +62 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md011.md +30 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md012.md +38 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md013.md +58 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md014.md +54 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md018.md +27 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md019.md +28 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md020.md +29 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md021.md +31 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md022.md +67 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md023.md +33 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md024.md +44 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md025.md +49 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md026.md +40 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md027.md +32 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md028.md +44 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md029.md +100 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md030.md +82 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md031.md +50 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md032.md +55 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md033.md +33 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md034.md +55 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md035.md +44 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md036.md +45 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md037.md +37 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md038.md +52 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md039.md +21 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md040.md +52 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md041.md +64 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md042.md +38 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md043.md +87 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md044.md +45 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md045.md +48 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md046.md +40 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md047.md +34 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md048.md +42 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md049.md +36 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md050.md +35 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md051.md +117 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md052.md +52 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md053.md +38 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md054.md +100 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md055.md +55 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md056.md +37 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md058.md +48 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md059.md +33 -0
- package/packages/config-markdownlint/node_modules/markdownlint/doc/md060.md +130 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/LICENSE +21 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/README.md +29 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/helpers.cjs +695 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/micromark-helpers.cjs +332 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/package.json +26 -0
- package/packages/config-markdownlint/node_modules/markdownlint/helpers/shared.cjs +16 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/cache.mjs +80 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/configuration-strict.d.ts +2417 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/configuration.d.ts +8 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/constants.mjs +14 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/defer-require.cjs +18 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-async.d.mts +1 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-async.mjs +3 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-promise.d.mts +1 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-promise.mjs +3 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-sync.d.mts +1 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports-sync.mjs +3 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports.d.mts +30 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/exports.mjs +33 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/markdownit.cjs +171 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/markdownlint.d.mts +615 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/markdownlint.mjs +1592 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md001.mjs +32 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md003.mjs +47 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md004.mjs +72 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md005.mjs +69 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md007.mjs +84 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md009.mjs +96 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md010.mjs +78 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md011.mjs +56 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md012.mjs +40 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md013.mjs +91 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md014.mjs +47 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md018.mjs +43 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md019-md021.mjs +77 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md020.mjs +68 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md022.mjs +103 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md023.mjs +37 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md024.mjs +45 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md025.mjs +45 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md026.mjs +46 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md027.mjs +50 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md028.mjs +39 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md029.mjs +84 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md030.mjs +57 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md031.mjs +61 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md032.mjs +78 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md033.mjs +46 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md034.mjs +92 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md035.mjs +23 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md036.mjs +55 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md037.mjs +94 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md038.mjs +73 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md039.mjs +59 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md040.mjs +32 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md041.mjs +71 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md042.mjs +58 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md043.mjs +72 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md044.mjs +110 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md045.mjs +61 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md046.mjs +31 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md047.mjs +28 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md048.mjs +47 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md049-md050.mjs +115 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md051.mjs +173 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md052.mjs +40 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md053.mjs +60 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md054.mjs +122 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md055.mjs +72 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md056.mjs +50 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md058.mjs +57 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md059.mjs +71 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/md060.mjs +209 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/micromark-parse.mjs +337 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/micromark-types.d.mts +11 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/node-imports-browser.mjs +22 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/node-imports-node.mjs +11 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/parse-configuration.mjs +47 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/resolve-module.cjs +52 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/resolve-module.d.cts +34 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/rules.mjs +122 -0
- package/packages/config-markdownlint/node_modules/markdownlint/lib/types.d.mts +13 -0
- package/packages/config-markdownlint/node_modules/markdownlint/package.json +120 -0
- package/packages/config-markdownlint/node_modules/markdownlint/schema/.markdownlint.jsonc +349 -0
- package/packages/config-markdownlint/node_modules/markdownlint/schema/.markdownlint.yaml +310 -0
- package/packages/config-markdownlint/node_modules/markdownlint/schema/ValidatingConfiguration.md +26 -0
- package/packages/config-markdownlint/node_modules/markdownlint/schema/markdownlint-config-schema-strict.json +5138 -0
- package/packages/config-markdownlint/node_modules/markdownlint/schema/markdownlint-config-schema.json +5143 -0
- package/packages/config-markdownlint/node_modules/markdownlint/style/all.json +5 -0
- package/packages/config-markdownlint/node_modules/markdownlint/style/cirosantilli.json +22 -0
- package/packages/config-markdownlint/node_modules/markdownlint/style/prettier.json +27 -0
- package/packages/config-markdownlint/node_modules/markdownlint/style/relaxed.json +12 -0
- package/packages/config-markdownlint/node_modules/string-width/index.d.ts +39 -0
- package/packages/config-markdownlint/node_modules/string-width/index.js +203 -0
- package/packages/config-markdownlint/node_modules/string-width/license +9 -0
- package/packages/config-markdownlint/node_modules/string-width/package.json +65 -0
- package/packages/config-markdownlint/node_modules/string-width/readme.md +66 -0
- package/packages/config-markdownlint/node_modules/strip-ansi/index.d.ts +15 -0
- package/packages/config-markdownlint/node_modules/strip-ansi/index.js +19 -0
- package/packages/config-markdownlint/node_modules/strip-ansi/license +9 -0
- package/packages/config-markdownlint/node_modules/strip-ansi/package.json +59 -0
- package/packages/config-markdownlint/node_modules/strip-ansi/readme.md +37 -0
- package/packages/config-markdownlint/package.json +2 -2
- package/packages/config-npmlint/package.json +2 -2
- package/packages/config-stylelint/package.json +2 -2
- package/packages/config-stylelint/plugins/scss.js +1 -1
- package/packages/config-stylelint/plugins/selector-no-empty.js +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addError } from "../helpers/helpers.cjs";
|
|
4
|
+
import { filterByPredicate, getDescendantsByType } from "../helpers/micromark-helpers.cjs";
|
|
5
|
+
|
|
6
|
+
const intrawordRe = /^\w$/;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Return the string representation of a emphasis or strong markup character.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} markup Emphasis or strong string.
|
|
12
|
+
* @returns {"asterisk" | "underscore"} String representation.
|
|
13
|
+
*/
|
|
14
|
+
function emphasisOrStrongStyleFor(markup) {
|
|
15
|
+
switch (markup[0]) {
|
|
16
|
+
case "*":
|
|
17
|
+
return "asterisk";
|
|
18
|
+
default:
|
|
19
|
+
return "underscore";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {import("markdownlint").RuleParams} params Rule parameters.
|
|
25
|
+
* @param {import("markdownlint").RuleOnError} onError Error-reporting callback.
|
|
26
|
+
* @param {import("micromark-util-types").TokenType} type Token type.
|
|
27
|
+
* @param {import("micromark-util-types").TokenType} typeSequence Token sequence type.
|
|
28
|
+
* @param {"*" | "**"} asterisk Asterisk kind.
|
|
29
|
+
* @param {"_" | "__"} underline Underline kind.
|
|
30
|
+
* @param {"asterisk" | "consistent" | "underscore"} style Style string.
|
|
31
|
+
*/
|
|
32
|
+
const impl =
|
|
33
|
+
(params, onError, type, typeSequence, asterisk, underline, style = "consistent") => {
|
|
34
|
+
const { lines, parsers } = params;
|
|
35
|
+
const emphasisTokens = filterByPredicate(
|
|
36
|
+
parsers.micromark.tokens,
|
|
37
|
+
(token) => token.type === type,
|
|
38
|
+
(token) => ((token.type === "htmlFlow") ? [] : token.children)
|
|
39
|
+
);
|
|
40
|
+
for (const token of emphasisTokens) {
|
|
41
|
+
const sequences = getDescendantsByType(token, [ typeSequence ]);
|
|
42
|
+
const startSequence = sequences[0];
|
|
43
|
+
const endSequence = sequences[sequences.length - 1];
|
|
44
|
+
if (startSequence && endSequence) {
|
|
45
|
+
const markupStyle = emphasisOrStrongStyleFor(startSequence.text);
|
|
46
|
+
if (style === "consistent") {
|
|
47
|
+
style = markupStyle;
|
|
48
|
+
}
|
|
49
|
+
if (style !== markupStyle) {
|
|
50
|
+
const underscoreIntraword = (style === "underscore") && (
|
|
51
|
+
intrawordRe.test(
|
|
52
|
+
lines[startSequence.startLine - 1][startSequence.startColumn - 2]
|
|
53
|
+
) ||
|
|
54
|
+
intrawordRe.test(
|
|
55
|
+
lines[endSequence.endLine - 1][endSequence.endColumn - 1]
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
if (!underscoreIntraword) {
|
|
59
|
+
for (const sequence of [ startSequence, endSequence ]) {
|
|
60
|
+
addError(
|
|
61
|
+
onError,
|
|
62
|
+
sequence.startLine,
|
|
63
|
+
`Expected: ${style}; Actual: ${markupStyle}`,
|
|
64
|
+
undefined,
|
|
65
|
+
[ sequence.startColumn, sequence.text.length ],
|
|
66
|
+
{
|
|
67
|
+
"editColumn": sequence.startColumn,
|
|
68
|
+
"deleteCount": sequence.text.length,
|
|
69
|
+
"insertText": (style === "asterisk") ? asterisk : underline
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** @type {import("markdownlint").Rule[]} */
|
|
80
|
+
export default [
|
|
81
|
+
{
|
|
82
|
+
"names": [ "MD049", "emphasis-style" ],
|
|
83
|
+
"description": "Emphasis style",
|
|
84
|
+
"tags": [ "emphasis" ],
|
|
85
|
+
"parser": "micromark",
|
|
86
|
+
"function": function MD049(params, onError) {
|
|
87
|
+
return impl(
|
|
88
|
+
params,
|
|
89
|
+
onError,
|
|
90
|
+
"emphasis",
|
|
91
|
+
"emphasisSequence",
|
|
92
|
+
"*",
|
|
93
|
+
"_",
|
|
94
|
+
params.config.style || undefined
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"names": [ "MD050", "strong-style" ],
|
|
100
|
+
"description": "Strong style",
|
|
101
|
+
"tags": [ "emphasis" ],
|
|
102
|
+
"parser": "micromark",
|
|
103
|
+
"function": function MD050(params, onError) {
|
|
104
|
+
return impl(
|
|
105
|
+
params,
|
|
106
|
+
onError,
|
|
107
|
+
"strong",
|
|
108
|
+
"strongSequence",
|
|
109
|
+
"**",
|
|
110
|
+
"__",
|
|
111
|
+
params.config.style || undefined
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
];
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addError, getHtmlAttributeRe } from "../helpers/helpers.cjs";
|
|
4
|
+
import { filterByPredicate, filterByTypes, getHtmlTagInfo, isDocfxTab } from "../helpers/micromark-helpers.cjs";
|
|
5
|
+
import { filterByTypesCached } from "./cache.mjs";
|
|
6
|
+
|
|
7
|
+
// Regular expression for identifying HTML anchor names
|
|
8
|
+
const idRe = getHtmlAttributeRe("id");
|
|
9
|
+
const nameRe = getHtmlAttributeRe("name");
|
|
10
|
+
const anchorRe = /\{(#[a-z\d]+(?:[-_][a-z\d]+)*)\}/gu;
|
|
11
|
+
const lineFragmentRe = /^#(?:L\d+(?:C\d+)?-L\d+(?:C\d+)?|L\d+)$/;
|
|
12
|
+
|
|
13
|
+
// Sets for filtering heading tokens during conversion
|
|
14
|
+
const childrenExclude = new Set([ "image", "reference", "resource" ]);
|
|
15
|
+
const tokensInclude = new Set(
|
|
16
|
+
[ "characterEscapeValue", "codeTextData", "data", "mathTextData" ]
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Converts a Markdown heading into an HTML fragment according to the rules
|
|
21
|
+
* used by GitHub.
|
|
22
|
+
*
|
|
23
|
+
* @param {import("markdownlint").MicromarkToken} headingText Heading text token.
|
|
24
|
+
* @returns {string} Fragment string for heading.
|
|
25
|
+
*/
|
|
26
|
+
function convertHeadingToHTMLFragment(headingText) {
|
|
27
|
+
const inlineText =
|
|
28
|
+
filterByPredicate(
|
|
29
|
+
headingText.children,
|
|
30
|
+
(token) => tokensInclude.has(token.type),
|
|
31
|
+
(token) => (childrenExclude.has(token.type) ? [] : token.children)
|
|
32
|
+
)
|
|
33
|
+
.map((token) => token.text)
|
|
34
|
+
.join("");
|
|
35
|
+
return "#" + encodeURIComponent(
|
|
36
|
+
inlineText
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
// RegExp source with Ruby's \p{Word} expanded into its General Categories
|
|
39
|
+
// https://github.com/gjtorikian/html-pipeline/blob/main/lib/html/pipeline/toc_filter.rb
|
|
40
|
+
// https://ruby-doc.org/core-3.0.2/Regexp.html
|
|
41
|
+
.replace(
|
|
42
|
+
/[^\p{Letter}\p{Mark}\p{Number}\p{Connector_Punctuation}\- ]/gu,
|
|
43
|
+
""
|
|
44
|
+
)
|
|
45
|
+
.replace(/ /gu, "-")
|
|
46
|
+
.toWellFormed()
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Unescapes the text of a String-type micromark Token.
|
|
52
|
+
*
|
|
53
|
+
* @param {import("markdownlint").MicromarkToken} token String-type micromark Token.
|
|
54
|
+
* @returns {string} Unescaped token text.
|
|
55
|
+
*/
|
|
56
|
+
function unescapeStringTokenText(token) {
|
|
57
|
+
return filterByTypes(token.children, [ "characterEscapeValue", "data" ])
|
|
58
|
+
.map((child) => child.text)
|
|
59
|
+
.join("");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** @type {import("markdownlint").Rule} */
|
|
63
|
+
export default {
|
|
64
|
+
"names": [ "MD051", "link-fragments" ],
|
|
65
|
+
"description": "Link fragments should be valid",
|
|
66
|
+
"tags": [ "links" ],
|
|
67
|
+
"parser": "micromark",
|
|
68
|
+
"function": function MD051(params, onError) {
|
|
69
|
+
const ignoreCase = params.config.ignore_case || false;
|
|
70
|
+
const ignoredPattern = params.config.ignored_pattern || "";
|
|
71
|
+
const ignoredPatternRe = new RegExp(ignoredPattern || "^$");
|
|
72
|
+
/** @type {Map<string, number>} */
|
|
73
|
+
const fragments = new Map([ [ "#top", 0 ] ]);
|
|
74
|
+
|
|
75
|
+
// Process headings
|
|
76
|
+
const headingTexts = filterByTypesCached([ "atxHeadingText", "setextHeadingText" ]);
|
|
77
|
+
for (const headingText of headingTexts) {
|
|
78
|
+
const fragment = convertHeadingToHTMLFragment(headingText);
|
|
79
|
+
if (fragment !== "#") {
|
|
80
|
+
const count = fragments.get(fragment) || 0;
|
|
81
|
+
if (count) {
|
|
82
|
+
fragments.set(`${fragment}-${count}`, 0);
|
|
83
|
+
}
|
|
84
|
+
fragments.set(fragment, count + 1);
|
|
85
|
+
let match = null;
|
|
86
|
+
while ((match = anchorRe.exec(headingText.text)) !== null) {
|
|
87
|
+
const [ , anchor ] = match;
|
|
88
|
+
if (!fragments.has(anchor)) {
|
|
89
|
+
fragments.set(anchor, 1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Process HTML anchors
|
|
96
|
+
for (const token of filterByTypesCached([ "htmlText" ], true)) {
|
|
97
|
+
const htmlTagInfo = getHtmlTagInfo(token);
|
|
98
|
+
if (htmlTagInfo && !htmlTagInfo.close) {
|
|
99
|
+
const anchorMatch = idRe.exec(token.text) ||
|
|
100
|
+
(htmlTagInfo.name.toLowerCase() === "a" && nameRe.exec(token.text));
|
|
101
|
+
if (anchorMatch && anchorMatch.length > 0) {
|
|
102
|
+
fragments.set(`#${anchorMatch[1]}`, 0);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Process link and definition fragments
|
|
108
|
+
/** @type {import("markdownlint").MicromarkTokenType[][]} */
|
|
109
|
+
const parentChilds = [
|
|
110
|
+
[ "link", "resourceDestinationString" ],
|
|
111
|
+
[ "definition", "definitionDestinationString" ]
|
|
112
|
+
];
|
|
113
|
+
for (const [ parentType, definitionType ] of parentChilds) {
|
|
114
|
+
const links = filterByTypesCached([ parentType ])
|
|
115
|
+
.filter(
|
|
116
|
+
(link) => !((link.parent?.type === "atxHeadingText") && isDocfxTab(link.parent.parent))
|
|
117
|
+
);
|
|
118
|
+
for (const link of links) {
|
|
119
|
+
const definitions = filterByTypes(link.children, [ definitionType ]);
|
|
120
|
+
for (const definition of definitions) {
|
|
121
|
+
const { endColumn, startColumn } = definition;
|
|
122
|
+
const text = unescapeStringTokenText(definition);
|
|
123
|
+
const textSliceOne = text.slice(1);
|
|
124
|
+
const encodedText = `#${encodeURIComponent(textSliceOne.toWellFormed())}`;
|
|
125
|
+
if (
|
|
126
|
+
(text.length > 1) &&
|
|
127
|
+
text.startsWith("#") &&
|
|
128
|
+
!fragments.has(encodedText) &&
|
|
129
|
+
!lineFragmentRe.test(encodedText) &&
|
|
130
|
+
!ignoredPatternRe.test(textSliceOne)
|
|
131
|
+
) {
|
|
132
|
+
let context = undefined;
|
|
133
|
+
let range = undefined;
|
|
134
|
+
let fixInfo = undefined;
|
|
135
|
+
if (link.startLine === link.endLine) {
|
|
136
|
+
context = link.text;
|
|
137
|
+
range = [ link.startColumn, link.endColumn - link.startColumn ];
|
|
138
|
+
fixInfo = {
|
|
139
|
+
"editColumn": startColumn,
|
|
140
|
+
"deleteCount": endColumn - startColumn
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const textLower = text.toLowerCase();
|
|
144
|
+
const mixedCaseKey = [ ...fragments.keys() ]
|
|
145
|
+
.find((key) => textLower === key.toLowerCase());
|
|
146
|
+
if (mixedCaseKey) {
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
(fixInfo || {}).insertText = mixedCaseKey;
|
|
149
|
+
if (!ignoreCase && (mixedCaseKey !== text)) {
|
|
150
|
+
addError(
|
|
151
|
+
onError,
|
|
152
|
+
link.startLine,
|
|
153
|
+
`Expected: ${mixedCaseKey}; Actual: ${text}`,
|
|
154
|
+
context,
|
|
155
|
+
range,
|
|
156
|
+
fixInfo
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
addError(
|
|
161
|
+
onError,
|
|
162
|
+
link.startLine,
|
|
163
|
+
undefined,
|
|
164
|
+
context,
|
|
165
|
+
range
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addError } from "../helpers/helpers.cjs";
|
|
4
|
+
import { getReferenceLinkImageData } from "./cache.mjs";
|
|
5
|
+
|
|
6
|
+
/** @type {import("markdownlint").Rule} */
|
|
7
|
+
export default {
|
|
8
|
+
"names": [ "MD052", "reference-links-images" ],
|
|
9
|
+
"description":
|
|
10
|
+
"Reference links and images should use a label that is defined",
|
|
11
|
+
"tags": [ "images", "links" ],
|
|
12
|
+
"parser": "none",
|
|
13
|
+
"function": function MD052(params, onError) {
|
|
14
|
+
const { config, lines } = params;
|
|
15
|
+
const shortcutSyntax = config.shortcut_syntax || false;
|
|
16
|
+
const ignoredLabels = new Set(config.ignored_labels || [ "x" ]);
|
|
17
|
+
const { definitions, references, shortcuts } = getReferenceLinkImageData();
|
|
18
|
+
const entries = shortcutSyntax ?
|
|
19
|
+
[ ...references.entries(), ...shortcuts.entries() ] :
|
|
20
|
+
references.entries();
|
|
21
|
+
// Look for links/images that use an undefined link reference
|
|
22
|
+
for (const reference of entries) {
|
|
23
|
+
const [ label, datas ] = reference;
|
|
24
|
+
if (!definitions.has(label) && !ignoredLabels.has(label)) {
|
|
25
|
+
for (const data of datas) {
|
|
26
|
+
const [ lineIndex, index, length ] = data;
|
|
27
|
+
// Context will be incomplete if reporting for a multi-line link
|
|
28
|
+
const context = lines[lineIndex].slice(index, index + length);
|
|
29
|
+
addError(
|
|
30
|
+
onError,
|
|
31
|
+
lineIndex + 1,
|
|
32
|
+
`Missing link or image reference definition: "${label}"`,
|
|
33
|
+
context,
|
|
34
|
+
[ index + 1, context.length ]
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addError, ellipsify } from "../helpers/helpers.cjs";
|
|
4
|
+
import { getReferenceLinkImageData } from "./cache.mjs";
|
|
5
|
+
|
|
6
|
+
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
|
|
7
|
+
|
|
8
|
+
/** @type {import("markdownlint").Rule} */
|
|
9
|
+
export default {
|
|
10
|
+
"names": [ "MD053", "link-image-reference-definitions" ],
|
|
11
|
+
"description": "Link and image reference definitions should be needed",
|
|
12
|
+
"tags": [ "images", "links" ],
|
|
13
|
+
"parser": "none",
|
|
14
|
+
"function": function MD053(params, onError) {
|
|
15
|
+
const ignored = new Set(params.config.ignored_definitions || [ "//" ]);
|
|
16
|
+
const lines = params.lines;
|
|
17
|
+
const { references, shortcuts, definitions, duplicateDefinitions } =
|
|
18
|
+
getReferenceLinkImageData();
|
|
19
|
+
const singleLineDefinition = (/** @type {string} */ line) => (
|
|
20
|
+
line.replace(linkReferenceDefinitionRe, "").trim().length > 0
|
|
21
|
+
);
|
|
22
|
+
const deleteFixInfo = {
|
|
23
|
+
"deleteCount": -1
|
|
24
|
+
};
|
|
25
|
+
// Look for unused link references (unreferenced by any link/image)
|
|
26
|
+
for (const definition of definitions.entries()) {
|
|
27
|
+
const [ label, [ lineIndex ] ] = definition;
|
|
28
|
+
if (
|
|
29
|
+
!ignored.has(label) &&
|
|
30
|
+
!references.has(label) &&
|
|
31
|
+
!shortcuts.has(label)
|
|
32
|
+
) {
|
|
33
|
+
const line = lines[lineIndex];
|
|
34
|
+
addError(
|
|
35
|
+
onError,
|
|
36
|
+
lineIndex + 1,
|
|
37
|
+
`Unused link or image reference definition: "${label}"`,
|
|
38
|
+
ellipsify(line),
|
|
39
|
+
[ 1, line.length ],
|
|
40
|
+
singleLineDefinition(line) ? deleteFixInfo : undefined
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Look for duplicate link references (defined more than once)
|
|
45
|
+
for (const duplicateDefinition of duplicateDefinitions) {
|
|
46
|
+
const [ label, lineIndex ] = duplicateDefinition;
|
|
47
|
+
if (!ignored.has(label)) {
|
|
48
|
+
const line = lines[lineIndex];
|
|
49
|
+
addError(
|
|
50
|
+
onError,
|
|
51
|
+
lineIndex + 1,
|
|
52
|
+
`Duplicate link or image reference definition: "${label}"`,
|
|
53
|
+
ellipsify(line),
|
|
54
|
+
[ 1, line.length ],
|
|
55
|
+
singleLineDefinition(line) ? deleteFixInfo : undefined
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addErrorContext, nextLinesRe } from "../helpers/helpers.cjs";
|
|
4
|
+
import { getDescendantsByType } from "../helpers/micromark-helpers.cjs";
|
|
5
|
+
import { getReferenceLinkImageData, filterByTypesCached } from "./cache.mjs";
|
|
6
|
+
|
|
7
|
+
const backslashEscapeRe = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g;
|
|
8
|
+
const removeBackslashEscapes = (/** @type {string} **/ text) => text.replace(backslashEscapeRe, "$1");
|
|
9
|
+
const autolinkDisallowedRe = /[ <>]/;
|
|
10
|
+
const autolinkAble = (/** @type {string} */ destination) => {
|
|
11
|
+
try {
|
|
12
|
+
// eslint-disable-next-line no-new
|
|
13
|
+
new URL(destination);
|
|
14
|
+
} catch {
|
|
15
|
+
// Not an absolute URL
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return !autolinkDisallowedRe.test(destination);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** @type {import("markdownlint").Rule} */
|
|
22
|
+
export default {
|
|
23
|
+
"names": [ "MD054", "link-image-style" ],
|
|
24
|
+
"description": "Link and image style",
|
|
25
|
+
"tags": [ "images", "links" ],
|
|
26
|
+
"parser": "micromark",
|
|
27
|
+
"function": (params, onError) => {
|
|
28
|
+
const config = params.config;
|
|
29
|
+
const autolink = (config.autolink === undefined) || !!config.autolink;
|
|
30
|
+
const inline = (config.inline === undefined) || !!config.inline;
|
|
31
|
+
const full = (config.full === undefined) || !!config.full;
|
|
32
|
+
const collapsed = (config.collapsed === undefined) || !!config.collapsed;
|
|
33
|
+
const shortcut = (config.shortcut === undefined) || !!config.shortcut;
|
|
34
|
+
const urlInline = (config.url_inline === undefined) || !!config.url_inline;
|
|
35
|
+
if (autolink && inline && full && collapsed && shortcut && urlInline) {
|
|
36
|
+
// Everything allowed, nothing to check
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { definitions } = getReferenceLinkImageData();
|
|
40
|
+
const links = filterByTypesCached([ "autolink", "image", "link" ]);
|
|
41
|
+
for (const link of links) {
|
|
42
|
+
let label = null;
|
|
43
|
+
let destination = null;
|
|
44
|
+
const {
|
|
45
|
+
endColumn, endLine, startColumn, startLine, text, type
|
|
46
|
+
} = link;
|
|
47
|
+
const image = (type === "image");
|
|
48
|
+
let isError = false;
|
|
49
|
+
if (type === "autolink") {
|
|
50
|
+
// link kind is an autolink
|
|
51
|
+
destination = getDescendantsByType(link, [ [ "autolinkEmail", "autolinkProtocol" ] ])[0]?.text;
|
|
52
|
+
label = destination;
|
|
53
|
+
isError = !autolink && Boolean(destination);
|
|
54
|
+
} else {
|
|
55
|
+
// link type is "image" or "link"
|
|
56
|
+
label = getDescendantsByType(link, [ "label", "labelText" ])[0].text;
|
|
57
|
+
destination =
|
|
58
|
+
getDescendantsByType(link, [ "resource", "resourceDestination", [ "resourceDestinationLiteral", "resourceDestinationRaw" ], "resourceDestinationString" ])[0]?.text;
|
|
59
|
+
if (destination) {
|
|
60
|
+
// link kind is an inline link
|
|
61
|
+
const title = getDescendantsByType(link, [ "resource", "resourceTitle", "resourceTitleString" ])[0]?.text;
|
|
62
|
+
isError = !inline || (
|
|
63
|
+
!urlInline &&
|
|
64
|
+
autolink &&
|
|
65
|
+
!image &&
|
|
66
|
+
!title &&
|
|
67
|
+
(label === destination) &&
|
|
68
|
+
autolinkAble(destination)
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
// link kind is a full/collapsed/shortcut reference link
|
|
72
|
+
const isShortcut = getDescendantsByType(link, [ "reference" ]).length === 0;
|
|
73
|
+
const referenceString = getDescendantsByType(link, [ "reference", "referenceString" ])[0]?.text;
|
|
74
|
+
const isCollapsed = (referenceString === undefined);
|
|
75
|
+
const definition = definitions.get(referenceString || label);
|
|
76
|
+
destination = (definition && definition[1]) || "";
|
|
77
|
+
isError = Boolean(
|
|
78
|
+
destination &&
|
|
79
|
+
(isShortcut ? !shortcut : (isCollapsed ? !collapsed : !full))
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (isError) {
|
|
84
|
+
let range = undefined;
|
|
85
|
+
let fixInfo = undefined;
|
|
86
|
+
if (startLine === endLine) {
|
|
87
|
+
range = [ startColumn, endColumn - startColumn ];
|
|
88
|
+
let insertText = null;
|
|
89
|
+
const canInline = (inline && label);
|
|
90
|
+
const canAutolink = (autolink && !image && autolinkAble(destination));
|
|
91
|
+
if (canInline && (urlInline || !canAutolink)) {
|
|
92
|
+
// Most useful form
|
|
93
|
+
const prefix = (image ? "!" : "");
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
const escapedLabel = label.replace(/[[\]]/g, "\\$&");
|
|
96
|
+
const escapedDestination = destination.replace(/[()]/g, "\\$&");
|
|
97
|
+
insertText = `${prefix}[${escapedLabel}](${escapedDestination})`;
|
|
98
|
+
} else if (canAutolink) {
|
|
99
|
+
// Simplest form
|
|
100
|
+
insertText = `<${removeBackslashEscapes(destination)}>`;
|
|
101
|
+
}
|
|
102
|
+
if (insertText) {
|
|
103
|
+
fixInfo = {
|
|
104
|
+
"editColumn": range[0],
|
|
105
|
+
insertText,
|
|
106
|
+
"deleteCount": range[1]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
addErrorContext(
|
|
111
|
+
onError,
|
|
112
|
+
startLine,
|
|
113
|
+
text.replace(nextLinesRe, ""),
|
|
114
|
+
undefined,
|
|
115
|
+
undefined,
|
|
116
|
+
range,
|
|
117
|
+
fixInfo
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addErrorDetailIf } from "../helpers/helpers.cjs";
|
|
4
|
+
import { filterByTypesCached } from "./cache.mjs";
|
|
5
|
+
|
|
6
|
+
/** @typedef {import("markdownlint").MicromarkToken} MicromarkToken */
|
|
7
|
+
/** @typedef {import("micromark-extension-gfm-table")} */
|
|
8
|
+
|
|
9
|
+
const whitespaceTypes = new Set([ "linePrefix", "whitespace" ]);
|
|
10
|
+
const ignoreWhitespace = (/** @type {MicromarkToken[]} */ tokens) => tokens.filter(
|
|
11
|
+
(token) => !whitespaceTypes.has(token.type)
|
|
12
|
+
);
|
|
13
|
+
const firstOrNothing = (/** @type {MicromarkToken[]} */ items) => items[0];
|
|
14
|
+
const lastOrNothing = (/** @type {MicromarkToken[]} */ items) => items[items.length - 1];
|
|
15
|
+
const makeRange = (/** @type {number} */ start, /** @type {number} */ end) => [ start, end - start + 1 ];
|
|
16
|
+
|
|
17
|
+
/** @type {import("markdownlint").Rule} */
|
|
18
|
+
export default {
|
|
19
|
+
"names": [ "MD055", "table-pipe-style" ],
|
|
20
|
+
"description": "Table pipe style",
|
|
21
|
+
"tags": [ "table" ],
|
|
22
|
+
"parser": "micromark",
|
|
23
|
+
"function": function MD055(params, onError) {
|
|
24
|
+
const style = String(params.config.style || "consistent");
|
|
25
|
+
let expectedStyle = style;
|
|
26
|
+
let expectedLeadingPipe =
|
|
27
|
+
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "trailing_only"));
|
|
28
|
+
let expectedTrailingPipe =
|
|
29
|
+
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "leading_only"));
|
|
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
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { addErrorDetailIf } from "../helpers/helpers.cjs";
|
|
4
|
+
import { getParentOfType } from "../helpers/micromark-helpers.cjs";
|
|
5
|
+
import { filterByTypesCached } from "./cache.mjs";
|
|
6
|
+
|
|
7
|
+
const makeRange = (/** @type {number} */ start, /** @type {number} */ end) => [ start, end - start + 1 ];
|
|
8
|
+
|
|
9
|
+
/** @typedef {import("micromark-extension-gfm-table")} */
|
|
10
|
+
|
|
11
|
+
/** @type {import("markdownlint").Rule} */
|
|
12
|
+
export default {
|
|
13
|
+
"names": [ "MD056", "table-column-count" ],
|
|
14
|
+
"description": "Table column count",
|
|
15
|
+
"tags": [ "table" ],
|
|
16
|
+
"parser": "micromark",
|
|
17
|
+
"function": function MD056(params, onError) {
|
|
18
|
+
const rows = filterByTypesCached([ "tableDelimiterRow", "tableRow" ]);
|
|
19
|
+
let expectedCount = 0;
|
|
20
|
+
let currentTable = null;
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
const table = getParentOfType(row, [ "table" ]);
|
|
23
|
+
if (currentTable !== table) {
|
|
24
|
+
expectedCount = 0;
|
|
25
|
+
currentTable = table;
|
|
26
|
+
}
|
|
27
|
+
const cells = row.children.filter((child) => [ "tableData", "tableDelimiter", "tableHeader" ].includes(child.type));
|
|
28
|
+
const actualCount = cells.length;
|
|
29
|
+
expectedCount ||= actualCount;
|
|
30
|
+
let detail = undefined;
|
|
31
|
+
let range = undefined;
|
|
32
|
+
if (actualCount < expectedCount) {
|
|
33
|
+
detail = "Too few cells, row will be missing data";
|
|
34
|
+
range = [ row.endColumn - 1, 1 ];
|
|
35
|
+
} else if (expectedCount < actualCount) {
|
|
36
|
+
detail = "Too many cells, extra data will be missing";
|
|
37
|
+
range = makeRange(cells[expectedCount].startColumn, row.endColumn - 1);
|
|
38
|
+
}
|
|
39
|
+
addErrorDetailIf(
|
|
40
|
+
onError,
|
|
41
|
+
row.endLine,
|
|
42
|
+
expectedCount,
|
|
43
|
+
actualCount,
|
|
44
|
+
detail,
|
|
45
|
+
undefined,
|
|
46
|
+
range
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|