Add "error" as a rule/tag/default value in Configuration object, add tests for similar values, resolve some new type-checking issues.

This commit is contained in:
David Anson 2025-09-16 20:47:08 -07:00
parent 9065f74bb8
commit a4ae56ab94
7 changed files with 1999 additions and 384 deletions

View file

@ -362,20 +362,23 @@ of `files` or `strings` should be set to provide input.
##### options.config
Type: `Object` mapping `String` to `Boolean | Object`
Type: `Object` mapping `String` to `Boolean | "error" | Object`
Configures the rules to use.
Object keys are rule names/aliases; object values are the rule's configuration.
The value `false` disables a rule, `true` enables its default configuration,
and passing an object value customizes that rule. Setting the special `default`
rule to `true` or `false` includes/excludes all rules by default. In the absence
of a configuration object, all rules are enabled. Enabling or disabling a tag
name (ex: `whitespace`) affects all rules having that tag.
The value `false` disables a rule. The values `true` or `"error"` enable a rule
in its default configuration and report violations as errors. Passing an object
enables and customizes the rule. The special `default` rule assigns the default
for all rules. Using a tag name (e.g., `whitespace`) and a setting of `false`,
`true`, or `"error"` applies that setting to all rules with that tag. When no
configuration object is passed or the optional `default` setting is not present,
all rules are enabled.
The `default` rule is applied first, then keys are processed in order from top
to bottom with later values overriding earlier ones. Keys (including rule names,
aliases, tags, and `default`) are not case-sensitive.
To evaluate a configuration object, the `default` setting is applied first, then
keys are processed in order from top to bottom. If multiple values apply to a
rule (because of tag names or duplication), later values override earlier ones.
Keys (including rule names, aliases, tags, or `default`) are not case-sensitive.
Example:

View file

@ -13,7 +13,7 @@ export interface ConfigurationStrict {
/**
* Default state for all rules
*/
default?: boolean;
default?: boolean | "error";
/**
* Path to configuration file to extend
*/
@ -23,6 +23,7 @@ export interface ConfigurationStrict {
*/
MD001?:
| boolean
| "error"
| {
/**
* RegExp for matching title in front matter
@ -34,6 +35,7 @@ export interface ConfigurationStrict {
*/
"heading-increment"?:
| boolean
| "error"
| {
/**
* RegExp for matching title in front matter
@ -45,6 +47,7 @@ export interface ConfigurationStrict {
*/
MD003?:
| boolean
| "error"
| {
/**
* Heading style
@ -56,6 +59,7 @@ export interface ConfigurationStrict {
*/
"heading-style"?:
| boolean
| "error"
| {
/**
* Heading style
@ -67,6 +71,7 @@ export interface ConfigurationStrict {
*/
MD004?:
| boolean
| "error"
| {
/**
* List style
@ -78,6 +83,7 @@ export interface ConfigurationStrict {
*/
"ul-style"?:
| boolean
| "error"
| {
/**
* List style
@ -87,16 +93,17 @@ export interface ConfigurationStrict {
/**
* MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md005.md
*/
MD005?: boolean;
MD005?: boolean | "error";
/**
* MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md005.md
*/
"list-indent"?: boolean;
"list-indent"?: boolean | "error";
/**
* MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md007.md
*/
MD007?:
| boolean
| "error"
| {
/**
* Spaces for indent
@ -116,6 +123,7 @@ export interface ConfigurationStrict {
*/
"ul-indent"?:
| boolean
| "error"
| {
/**
* Spaces for indent
@ -135,6 +143,7 @@ export interface ConfigurationStrict {
*/
MD009?:
| boolean
| "error"
| {
/**
* Spaces for line break
@ -154,6 +163,7 @@ export interface ConfigurationStrict {
*/
"no-trailing-spaces"?:
| boolean
| "error"
| {
/**
* Spaces for line break
@ -173,6 +183,7 @@ export interface ConfigurationStrict {
*/
MD010?:
| boolean
| "error"
| {
/**
* Include code blocks
@ -192,6 +203,7 @@ export interface ConfigurationStrict {
*/
"no-hard-tabs"?:
| boolean
| "error"
| {
/**
* Include code blocks
@ -209,16 +221,17 @@ export interface ConfigurationStrict {
/**
* MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md011.md
*/
MD011?: boolean;
MD011?: boolean | "error";
/**
* MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md011.md
*/
"no-reversed-links"?: boolean;
"no-reversed-links"?: boolean | "error";
/**
* MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md012.md
*/
MD012?:
| boolean
| "error"
| {
/**
* Consecutive blank lines
@ -230,6 +243,7 @@ export interface ConfigurationStrict {
*/
"no-multiple-blanks"?:
| boolean
| "error"
| {
/**
* Consecutive blank lines
@ -241,6 +255,7 @@ export interface ConfigurationStrict {
*/
MD013?:
| boolean
| "error"
| {
/**
* Number of characters
@ -280,6 +295,7 @@ export interface ConfigurationStrict {
*/
"line-length"?:
| boolean
| "error"
| {
/**
* Number of characters
@ -317,48 +333,49 @@ export interface ConfigurationStrict {
/**
* MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md014.md
*/
MD014?: boolean;
MD014?: boolean | "error";
/**
* MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md014.md
*/
"commands-show-output"?: boolean;
"commands-show-output"?: boolean | "error";
/**
* MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md018.md
*/
MD018?: boolean;
MD018?: boolean | "error";
/**
* MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md018.md
*/
"no-missing-space-atx"?: boolean;
"no-missing-space-atx"?: boolean | "error";
/**
* MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md019.md
*/
MD019?: boolean;
MD019?: boolean | "error";
/**
* MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md019.md
*/
"no-multiple-space-atx"?: boolean;
"no-multiple-space-atx"?: boolean | "error";
/**
* MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md020.md
*/
MD020?: boolean;
MD020?: boolean | "error";
/**
* MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md020.md
*/
"no-missing-space-closed-atx"?: boolean;
"no-missing-space-closed-atx"?: boolean | "error";
/**
* MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md021.md
*/
MD021?: boolean;
MD021?: boolean | "error";
/**
* MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md021.md
*/
"no-multiple-space-closed-atx"?: boolean;
"no-multiple-space-closed-atx"?: boolean | "error";
/**
* MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md022.md
*/
MD022?:
| boolean
| "error"
| {
/**
* Blank lines above heading
@ -374,6 +391,7 @@ export interface ConfigurationStrict {
*/
"blanks-around-headings"?:
| boolean
| "error"
| {
/**
* Blank lines above heading
@ -387,16 +405,17 @@ export interface ConfigurationStrict {
/**
* MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md023.md
*/
MD023?: boolean;
MD023?: boolean | "error";
/**
* MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md023.md
*/
"heading-start-left"?: boolean;
"heading-start-left"?: boolean | "error";
/**
* MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md024.md
*/
MD024?:
| boolean
| "error"
| {
/**
* Only check sibling headings
@ -408,6 +427,7 @@ export interface ConfigurationStrict {
*/
"no-duplicate-heading"?:
| boolean
| "error"
| {
/**
* Only check sibling headings
@ -419,6 +439,7 @@ export interface ConfigurationStrict {
*/
MD025?:
| boolean
| "error"
| {
/**
* RegExp for matching title in front matter
@ -434,6 +455,7 @@ export interface ConfigurationStrict {
*/
"single-title"?:
| boolean
| "error"
| {
/**
* RegExp for matching title in front matter
@ -449,6 +471,7 @@ export interface ConfigurationStrict {
*/
"single-h1"?:
| boolean
| "error"
| {
/**
* RegExp for matching title in front matter
@ -464,6 +487,7 @@ export interface ConfigurationStrict {
*/
MD026?:
| boolean
| "error"
| {
/**
* Punctuation characters
@ -475,6 +499,7 @@ export interface ConfigurationStrict {
*/
"no-trailing-punctuation"?:
| boolean
| "error"
| {
/**
* Punctuation characters
@ -486,6 +511,7 @@ export interface ConfigurationStrict {
*/
MD027?:
| boolean
| "error"
| {
/**
* Include list items
@ -497,6 +523,7 @@ export interface ConfigurationStrict {
*/
"no-multiple-space-blockquote"?:
| boolean
| "error"
| {
/**
* Include list items
@ -506,16 +533,17 @@ export interface ConfigurationStrict {
/**
* MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md028.md
*/
MD028?: boolean;
MD028?: boolean | "error";
/**
* MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md028.md
*/
"no-blanks-blockquote"?: boolean;
"no-blanks-blockquote"?: boolean | "error";
/**
* MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md029.md
*/
MD029?:
| boolean
| "error"
| {
/**
* List style
@ -527,6 +555,7 @@ export interface ConfigurationStrict {
*/
"ol-prefix"?:
| boolean
| "error"
| {
/**
* List style
@ -538,6 +567,7 @@ export interface ConfigurationStrict {
*/
MD030?:
| boolean
| "error"
| {
/**
* Spaces for single-line unordered list items
@ -561,6 +591,7 @@ export interface ConfigurationStrict {
*/
"list-marker-space"?:
| boolean
| "error"
| {
/**
* Spaces for single-line unordered list items
@ -584,6 +615,7 @@ export interface ConfigurationStrict {
*/
MD031?:
| boolean
| "error"
| {
/**
* Include list items
@ -595,6 +627,7 @@ export interface ConfigurationStrict {
*/
"blanks-around-fences"?:
| boolean
| "error"
| {
/**
* Include list items
@ -604,16 +637,17 @@ export interface ConfigurationStrict {
/**
* MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md032.md
*/
MD032?: boolean;
MD032?: boolean | "error";
/**
* MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md032.md
*/
"blanks-around-lists"?: boolean;
"blanks-around-lists"?: boolean | "error";
/**
* MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md033.md
*/
MD033?:
| boolean
| "error"
| {
/**
* Allowed elements
@ -629,6 +663,7 @@ export interface ConfigurationStrict {
*/
"no-inline-html"?:
| boolean
| "error"
| {
/**
* Allowed elements
@ -642,16 +677,17 @@ export interface ConfigurationStrict {
/**
* MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md034.md
*/
MD034?: boolean;
MD034?: boolean | "error";
/**
* MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md034.md
*/
"no-bare-urls"?: boolean;
"no-bare-urls"?: boolean | "error";
/**
* MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md035.md
*/
MD035?:
| boolean
| "error"
| {
/**
* Horizontal rule style
@ -663,6 +699,7 @@ export interface ConfigurationStrict {
*/
"hr-style"?:
| boolean
| "error"
| {
/**
* Horizontal rule style
@ -674,6 +711,7 @@ export interface ConfigurationStrict {
*/
MD036?:
| boolean
| "error"
| {
/**
* Punctuation characters
@ -685,6 +723,7 @@ export interface ConfigurationStrict {
*/
"no-emphasis-as-heading"?:
| boolean
| "error"
| {
/**
* Punctuation characters
@ -694,32 +733,33 @@ export interface ConfigurationStrict {
/**
* MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md037.md
*/
MD037?: boolean;
MD037?: boolean | "error";
/**
* MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md037.md
*/
"no-space-in-emphasis"?: boolean;
"no-space-in-emphasis"?: boolean | "error";
/**
* MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md038.md
*/
MD038?: boolean;
MD038?: boolean | "error";
/**
* MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md038.md
*/
"no-space-in-code"?: boolean;
"no-space-in-code"?: boolean | "error";
/**
* MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md039.md
*/
MD039?: boolean;
MD039?: boolean | "error";
/**
* MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md039.md
*/
"no-space-in-links"?: boolean;
"no-space-in-links"?: boolean | "error";
/**
* MD040/fenced-code-language : Fenced code blocks should have a language specified : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md040.md
*/
MD040?:
| boolean
| "error"
| {
/**
* List of languages
@ -735,6 +775,7 @@ export interface ConfigurationStrict {
*/
"fenced-code-language"?:
| boolean
| "error"
| {
/**
* List of languages
@ -750,6 +791,7 @@ export interface ConfigurationStrict {
*/
MD041?:
| boolean
| "error"
| {
/**
* Allow content before first heading
@ -769,6 +811,7 @@ export interface ConfigurationStrict {
*/
"first-line-heading"?:
| boolean
| "error"
| {
/**
* Allow content before first heading
@ -788,6 +831,7 @@ export interface ConfigurationStrict {
*/
"first-line-h1"?:
| boolean
| "error"
| {
/**
* Allow content before first heading
@ -805,16 +849,17 @@ export interface ConfigurationStrict {
/**
* MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md042.md
*/
MD042?: boolean;
MD042?: boolean | "error";
/**
* MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md042.md
*/
"no-empty-links"?: boolean;
"no-empty-links"?: boolean | "error";
/**
* MD043/required-headings : Required heading structure : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md043.md
*/
MD043?:
| boolean
| "error"
| {
/**
* List of headings
@ -830,6 +875,7 @@ export interface ConfigurationStrict {
*/
"required-headings"?:
| boolean
| "error"
| {
/**
* List of headings
@ -845,6 +891,7 @@ export interface ConfigurationStrict {
*/
MD044?:
| boolean
| "error"
| {
/**
* List of proper names
@ -864,6 +911,7 @@ export interface ConfigurationStrict {
*/
"proper-names"?:
| boolean
| "error"
| {
/**
* List of proper names
@ -881,16 +929,17 @@ export interface ConfigurationStrict {
/**
* MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md045.md
*/
MD045?: boolean;
MD045?: boolean | "error";
/**
* MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md045.md
*/
"no-alt-text"?: boolean;
"no-alt-text"?: boolean | "error";
/**
* MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md046.md
*/
MD046?:
| boolean
| "error"
| {
/**
* Block style
@ -902,6 +951,7 @@ export interface ConfigurationStrict {
*/
"code-block-style"?:
| boolean
| "error"
| {
/**
* Block style
@ -911,16 +961,17 @@ export interface ConfigurationStrict {
/**
* MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md047.md
*/
MD047?: boolean;
MD047?: boolean | "error";
/**
* MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md047.md
*/
"single-trailing-newline"?: boolean;
"single-trailing-newline"?: boolean | "error";
/**
* MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md048.md
*/
MD048?:
| boolean
| "error"
| {
/**
* Code fence style
@ -932,6 +983,7 @@ export interface ConfigurationStrict {
*/
"code-fence-style"?:
| boolean
| "error"
| {
/**
* Code fence style
@ -943,6 +995,7 @@ export interface ConfigurationStrict {
*/
MD049?:
| boolean
| "error"
| {
/**
* Emphasis style
@ -954,6 +1007,7 @@ export interface ConfigurationStrict {
*/
"emphasis-style"?:
| boolean
| "error"
| {
/**
* Emphasis style
@ -965,6 +1019,7 @@ export interface ConfigurationStrict {
*/
MD050?:
| boolean
| "error"
| {
/**
* Strong style
@ -976,6 +1031,7 @@ export interface ConfigurationStrict {
*/
"strong-style"?:
| boolean
| "error"
| {
/**
* Strong style
@ -987,6 +1043,7 @@ export interface ConfigurationStrict {
*/
MD051?:
| boolean
| "error"
| {
/**
* Ignore case of fragments
@ -1002,6 +1059,7 @@ export interface ConfigurationStrict {
*/
"link-fragments"?:
| boolean
| "error"
| {
/**
* Ignore case of fragments
@ -1017,6 +1075,7 @@ export interface ConfigurationStrict {
*/
MD052?:
| boolean
| "error"
| {
/**
* Ignored link labels
@ -1032,6 +1091,7 @@ export interface ConfigurationStrict {
*/
"reference-links-images"?:
| boolean
| "error"
| {
/**
* Ignored link labels
@ -1047,6 +1107,7 @@ export interface ConfigurationStrict {
*/
MD053?:
| boolean
| "error"
| {
/**
* Ignored definitions
@ -1058,6 +1119,7 @@ export interface ConfigurationStrict {
*/
"link-image-reference-definitions"?:
| boolean
| "error"
| {
/**
* Ignored definitions
@ -1069,6 +1131,7 @@ export interface ConfigurationStrict {
*/
MD054?:
| boolean
| "error"
| {
/**
* Allow autolinks
@ -1100,6 +1163,7 @@ export interface ConfigurationStrict {
*/
"link-image-style"?:
| boolean
| "error"
| {
/**
* Allow autolinks
@ -1131,6 +1195,7 @@ export interface ConfigurationStrict {
*/
MD055?:
| boolean
| "error"
| {
/**
* Table pipe style
@ -1142,6 +1207,7 @@ export interface ConfigurationStrict {
*/
"table-pipe-style"?:
| boolean
| "error"
| {
/**
* Table pipe style
@ -1151,24 +1217,25 @@ export interface ConfigurationStrict {
/**
* MD056/table-column-count : Table column count : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md056.md
*/
MD056?: boolean;
MD056?: boolean | "error";
/**
* MD056/table-column-count : Table column count : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md056.md
*/
"table-column-count"?: boolean;
"table-column-count"?: boolean | "error";
/**
* MD058/blanks-around-tables : Tables should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md058.md
*/
MD058?: boolean;
MD058?: boolean | "error";
/**
* MD058/blanks-around-tables : Tables should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md058.md
*/
"blanks-around-tables"?: boolean;
"blanks-around-tables"?: boolean | "error";
/**
* MD059/descriptive-link-text : Link text should be descriptive : https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
*/
MD059?:
| boolean
| "error"
| {
/**
* Prohibited link texts
@ -1180,6 +1247,7 @@ export interface ConfigurationStrict {
*/
"descriptive-link-text"?:
| boolean
| "error"
| {
/**
* Prohibited link texts
@ -1191,6 +1259,7 @@ export interface ConfigurationStrict {
*/
MD060?:
| boolean
| "error"
| {
/**
* Table column style
@ -1202,6 +1271,7 @@ export interface ConfigurationStrict {
*/
"table-column-style"?:
| boolean
| "error"
| {
/**
* Table column style
@ -1211,97 +1281,97 @@ export interface ConfigurationStrict {
/**
* headings : MD001, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043
*/
headings?: boolean;
headings?: boolean | "error";
/**
* bullet : MD004, MD005, MD007, MD032
*/
bullet?: boolean;
bullet?: boolean | "error";
/**
* ul : MD004, MD005, MD007, MD030, MD032
*/
ul?: boolean;
ul?: boolean | "error";
/**
* indentation : MD005, MD007, MD027
*/
indentation?: boolean;
indentation?: boolean | "error";
/**
* whitespace : MD009, MD010, MD012, MD027, MD028, MD030, MD037, MD038, MD039
*/
whitespace?: boolean;
whitespace?: boolean | "error";
/**
* hard_tab : MD010
*/
hard_tab?: boolean;
hard_tab?: boolean | "error";
/**
* links : MD011, MD034, MD039, MD042, MD051, MD052, MD053, MD054, MD059
*/
links?: boolean;
links?: boolean | "error";
/**
* blank_lines : MD012, MD022, MD031, MD032, MD047
*/
blank_lines?: boolean;
blank_lines?: boolean | "error";
/**
* line_length : MD013
*/
line_length?: boolean;
line_length?: boolean | "error";
/**
* code : MD014, MD031, MD038, MD040, MD046, MD048
*/
code?: boolean;
code?: boolean | "error";
/**
* atx : MD018, MD019
*/
atx?: boolean;
atx?: boolean | "error";
/**
* spaces : MD018, MD019, MD020, MD021, MD023
*/
spaces?: boolean;
spaces?: boolean | "error";
/**
* atx_closed : MD020, MD021
*/
atx_closed?: boolean;
atx_closed?: boolean | "error";
/**
* blockquote : MD027, MD028
*/
blockquote?: boolean;
blockquote?: boolean | "error";
/**
* ol : MD029, MD030, MD032
*/
ol?: boolean;
ol?: boolean | "error";
/**
* html : MD033
*/
html?: boolean;
html?: boolean | "error";
/**
* url : MD034
*/
url?: boolean;
url?: boolean | "error";
/**
* hr : MD035
*/
hr?: boolean;
hr?: boolean | "error";
/**
* emphasis : MD036, MD037, MD049, MD050
*/
emphasis?: boolean;
emphasis?: boolean | "error";
/**
* language : MD040
*/
language?: boolean;
language?: boolean | "error";
/**
* spelling : MD044
*/
spelling?: boolean;
spelling?: boolean | "error";
/**
* accessibility : MD045, MD059
*/
accessibility?: boolean;
accessibility?: boolean | "error";
/**
* images : MD045, MD052, MD053, MD054
*/
images?: boolean;
images?: boolean | "error";
/**
* table : MD055, MD056, MD058, MD060
*/
table?: boolean;
table?: boolean | "error";
}

View file

@ -19,6 +19,7 @@ const schema = {
"$id": schemaUri,
"title": "markdownlint configuration schema",
"type": "object",
/** @type {Object.<string, object>} */
"properties": {
"$schema": {
"description": "JSON Schema URI (expected by some editors)",
@ -28,8 +29,8 @@ const schema = {
"default": {
"description": "Default state for all rules",
"oneOf": [
{ "type": "boolean" }
// { "enum": [ "error", "warning" ] }
{ "type": "boolean" },
{ "enum": [ "error" ] }
],
"default": true
},
@ -49,6 +50,7 @@ const schema = {
]
}
};
/** @type {Object.<string, string[]>} */
const tags = {};
// Add rules
@ -63,11 +65,12 @@ for (const rule of rules) {
"description":
`${rule.names.join("/")} : ${rule.description} : ${rule.information}`,
"oneOf": [
{ "type": "boolean" }
// { "enum": [ "error", "warning" ] }
{ "type": "boolean" },
{ "enum": [ "error" ] }
],
"default": true
};
/** @type {{type: "object", additionalProperties: boolean, properties?: object}} */
const subscheme = {
"type": "object",
"additionalProperties": false
@ -649,7 +652,10 @@ for (const rule of rules) {
for (const [ tag, tagTags ] of Object.entries(tags)) {
const scheme = {
"description": `${tag} : ${tagTags.join(", ")}`,
"type": "boolean",
"oneOf": [
{ "type": "boolean" },
{ "enum": [ "error" ] }
],
"default": true
};
schema.properties[tag] = scheme;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,13 @@ import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
/* eslint-disable jsdoc/no-undefined-types */
/**
* Gets the file name of the current module.
* Shims import.meta.filename for Node 18.
*
* @param {Object} meta ESM import.meta object.
* @param {ImportMeta} meta ESM import.meta object.
* @returns {string} File name.
*/
// eslint-disable-next-line no-underscore-dangle
@ -18,7 +20,7 @@ export const __filename = (meta) => fileURLToPath(meta.url);
* Gets the directory name of the current module.
* Shims import.meta.dirname for Node 18.
*
* @param {Object} meta ESM import.meta object.
* @param {ImportMeta} meta ESM import.meta object.
* @returns {string} Directory name.
*/
// eslint-disable-next-line no-underscore-dangle
@ -28,9 +30,9 @@ export const __dirname = (meta) => path.dirname(__filename(meta));
* Imports a file as JSON.
* Avoids "ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time".
*
* @param {Object} meta ESM import.meta object.
* @param {ImportMeta} meta ESM import.meta object.
* @param {string} file JSON file to import.
* @returns {Promise<Object>} JSON object.
* @returns {Promise<any>} JSON object.
*/
export const importWithTypeJson = async(meta, file) => (
// @ts-ignore

View file

@ -22,7 +22,9 @@ import * as constants from "../lib/constants.mjs";
import rules from "../lib/rules.mjs";
import customRules from "./rules/rules.cjs";
import { __dirname, importWithTypeJson } from "./esm-helpers.mjs";
/** @type {{exports: Object.<string, string>, homepage: string, version: string}} */
const packageJson = await importWithTypeJson(import.meta, "../package.json");
/** @type {{$id: string, properties: Object<string, any>}} */
const configSchema = await importWithTypeJson(import.meta, "../schema/markdownlint-config-schema.json");
const configSchemaStrict = await importWithTypeJson(import.meta, "../schema/markdownlint-config-schema-strict.json");
@ -31,6 +33,10 @@ const ajvOptions = {
"allowUnionTypes": true
};
/** @typedef {import("ava").ImplementationFn<[]>} ImplementationFn */
/** @typedef {import("markdownlint").Configuration} Configuration */
/** @typedef {import("markdownlint").LintResults} LintResults */
/**
* Gets an instance of a markdown-it factory, suitable for use with options.markdownItFactory.
*
@ -140,270 +146,272 @@ test("inputOnlyNewline", (t) => new Promise((resolve) => {
});
}));
test("defaultTrue", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
"default": true
},
"noInlineConfig": true,
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD018": [ 1 ],
"MD019": [ 3, 5 ],
"MD041": [ 1 ]
},
"./test/first_heading_bad_atx.md": {
"MD041": [ 1 ]
/** @typedef {Object<string, string[]>} NormalizedLintResults */
/**
* Normalizes LintResults.
*
* @param {LintResults} results LintResults.
* @returns {NormalizedLintResults} Normalized LintResults.
*/
function normalizeLintResults(results) {
return Object.fromEntries(
Object.entries(results).map(
([ source, errors ]) => [
source,
errors.map(
({ lineNumber, ruleNames, severity }) => `${ruleNames[0]} ${lineNumber} ${severity}`
)
]
)
);
}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
test("defaultFalse", (t) => new Promise((resolve) => {
t.plan(2);
/**
* Gets a Configuration value test implementation.
*
* @param {Configuration} config Configuration object.
* @param {NormalizedLintResults} expected Expected result.
* @returns {ImplementationFn} Test implementation.
*/
function getConfigTestImplementation(config, expected) {
return async(t) => {
t.plan(1);
const options = {
config,
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
"default": false
},
"noInlineConfig": true,
"resultVersion": 0
"noInlineConfig": true
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {},
"./test/first_heading_bad_atx.md": {}
const actual = await lintPromise(options);
t.deepEqual(normalizeLintResults(actual), expected);
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
test("defaultUndefined", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {},
"noInlineConfig": true,
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD018": [ 1 ],
"MD019": [ 3, 5 ],
"MD041": [ 1 ]
},
"./test/first_heading_bad_atx.md": {
"MD041": [ 1 ]
}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
test("disableRules", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/no_first_line_heading.md"
const configTestExpected = {
"./test/atx_heading_spacing.md": [],
"./test/first_heading_bad_atx.md": []
};
const configTestExpected1 = {
"./test/atx_heading_spacing.md": [
"MD018 1 error"
],
"config": {
"./test/first_heading_bad_atx.md": []
};
const configTestExpected11 = {
"./test/atx_heading_spacing.md": [
"MD041 1 error"
],
"./test/first_heading_bad_atx.md": [
"MD041 1 error"
]
};
const configTestExpected135 = {
"./test/atx_heading_spacing.md": [
"MD018 1 error",
"MD019 3 error",
"MD019 5 error"
],
"./test/first_heading_bad_atx.md": []
};
const configTestExpected3511 = {
"./test/atx_heading_spacing.md": [
"MD019 3 error",
"MD019 5 error",
"MD041 1 error"
],
"./test/first_heading_bad_atx.md": [
"MD041 1 error"
]
};
const configTestExpected13511 = {
"./test/atx_heading_spacing.md": [
"MD018 1 error",
"MD019 3 error",
"MD019 5 error",
"MD041 1 error"
],
"./test/first_heading_bad_atx.md": [
"MD041 1 error"
]
};
test("defaultUnset", getConfigTestImplementation(
{},
configTestExpected13511
));
test("defaultTrue", getConfigTestImplementation(
{ "default": true },
configTestExpected13511
));
test("defaultFalse", getConfigTestImplementation(
{ "default": false },
configTestExpected
));
test("defaultTruthy", getConfigTestImplementation(
// @ts-ignore
{ "default": 1 },
configTestExpected13511
));
test("defaultFalsy", getConfigTestImplementation(
// @ts-ignore
{ "default": 0 },
configTestExpected
));
test("defaultError", getConfigTestImplementation(
{ "default": "error" },
configTestExpected13511
));
test("defaultWarning", getConfigTestImplementation(
// @ts-ignore
{ "default": "warning" },
configTestExpected13511
));
test("defaultOff", getConfigTestImplementation(
// @ts-ignore
{ "default": "off" },
configTestExpected13511
));
test("disableRules", getConfigTestImplementation(
{
"default": true,
"MD019": false,
"first-line-h1": false
"first-line-h1": false,
"extra": false
},
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD018": [ 1 ]
},
"./test/no_first_line_heading.md": {}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
configTestExpected1
));
test("enableRules", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
test("disableRulesFalsy", getConfigTestImplementation(
{
"default": true,
// @ts-ignore
"MD019": 0,
// @ts-ignore
"first-line-h1": 0,
"extra": 0
},
configTestExpected1
));
test("enableRules", getConfigTestImplementation(
{
"MD041": true,
"default": false,
"no-multiple-space-atx": true
"no-multiple-space-atx": true,
"extra": true
},
"noInlineConfig": true,
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD019": [ 3, 5 ],
"MD041": [ 1 ]
},
"./test/first_heading_bad_atx.md": {
"MD041": [ 1 ]
}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
configTestExpected3511
));
test("enableRulesMixedCase", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
test("enableRulesMixedCase", getConfigTestImplementation(
{
"Md041": true,
"DeFaUlT": false,
"nO-mUlTiPlE-sPaCe-AtX": true
"nO-mUlTiPlE-sPaCe-AtX": true,
"ExTrA": true
},
"noInlineConfig": true,
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD019": [ 3, 5 ],
"MD041": [ 1 ]
},
"./test/first_heading_bad_atx.md": {
"MD041": [ 1 ]
}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
configTestExpected3511
));
test("disableTag", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
test("enableRulesTruthy", getConfigTestImplementation(
{
// @ts-ignore
"MD041": 1,
"default": false,
// @ts-ignore
"no-multiple-space-atx": 1,
"extra": 1
},
configTestExpected3511
));
test("enableRulesString", getConfigTestImplementation(
{
"MD041": "error",
"default": false,
"no-multiple-space-atx": "error",
"extra": "error"
},
configTestExpected3511
));
test("enableRulesEmptyObject", getConfigTestImplementation(
{
"MD041": {},
"default": false,
// @ts-ignore
"no-multiple-space-atx": {},
"extra": {}
},
configTestExpected3511
));
test("disableTag", getConfigTestImplementation(
{
"default": true,
"spaces": false
"spaces": false,
"extra": false
},
"noInlineConfig": true,
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD041": [ 1 ]
},
"./test/first_heading_bad_atx.md": {
"MD041": [ 1 ]
}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
configTestExpected11
));
test("enableTag", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
test("disableTagFalsy", getConfigTestImplementation(
{
"default": true,
// @ts-ignore
"spaces": 0,
"extra": 0
},
configTestExpected11
));
test("enableTag", getConfigTestImplementation(
{
"default": false,
"spaces": true,
"notatag": true
"extra": true
},
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD018": [ 1 ],
"MD019": [ 3, 5 ]
},
"./test/first_heading_bad_atx.md": {}
};
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
configTestExpected135
));
test("enableTagMixedCase", (t) => new Promise((resolve) => {
t.plan(2);
const options = {
"files": [
"./test/atx_heading_spacing.md",
"./test/first_heading_bad_atx.md"
],
"config": {
test("enableTagMixedCase", getConfigTestImplementation(
{
"DeFaUlT": false,
"SpAcEs": true,
"NoTaTaG": true
"ExTrA": true
},
"resultVersion": 0
};
lintAsync(options, function callback(err, actualResult) {
t.falsy(err);
const expectedResult = {
"./test/atx_heading_spacing.md": {
"MD018": [ 1 ],
"MD019": [ 3, 5 ]
},
"./test/first_heading_bad_atx.md": {}
};
configTestExpected135
));
test("enableTagTruthy", getConfigTestImplementation(
{
"default": false,
// @ts-ignore
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve();
});
}));
"spaces": 1,
"extra": 1
},
configTestExpected135
));
test("enableTagString", getConfigTestImplementation(
{
"default": false,
"spaces": "error",
"extra": "error"
},
configTestExpected135
));
test("styleFiles", async(t) => {
t.plan(8);
@ -802,6 +810,7 @@ test("customFileSystemSync", (t) => {
t.plan(2);
const file = "/dir/file.md";
const fsApi = {
// @ts-ignore
"readFileSync": (p) => {
t.is(p, file);
return "# Heading";
@ -818,6 +827,7 @@ test("customFileSystemAsync", (t) => new Promise((resolve) => {
t.plan(3);
const file = "/dir/file.md";
const fsApi = {
// @ts-ignore
"readFile": (p, o, cb) => {
t.is(p, file);
cb(null, "# Heading");
@ -836,6 +846,7 @@ test("customFileSystemAsync", (t) => new Promise((resolve) => {
test("readme", async(t) => {
t.plan(132);
/** @type {Object.<string, string[]>} */
const tagToRules = {};
for (const rule of rules) {
for (const tag of rule.tags) {
@ -894,7 +905,7 @@ test("readme", async(t) => {
} else if (inTags) {
const parts =
token.content.replace(/[`*]/g, "").split(/ - |, |,\n/);
const tag = parts.shift();
const tag = parts.shift() || "";
t.deepEqual(parts, tagToRules[tag] || [],
"Rule mismatch for tag " + tag + ".");
delete tagToRules[tag];
@ -1248,6 +1259,7 @@ test("token-map-spans", (t) => {
"tags": [ "tms" ],
"parser": "markdownit",
"function": function tokenMapSpans(params) {
/** @type {number[]} */
const tokenLines = [];
let lastLineNumber = -1;
const inlines = params.parsers.markdownit.tokens.filter(