Add "severity"/"error" to rule in Configuration object, add corresponding documentation, resolve some new type-checking issues.

This commit is contained in:
David Anson 2025-09-18 21:21:12 -07:00
parent 1d2d3ed581
commit c6f248321e
13 changed files with 4030 additions and 688 deletions

View file

@ -375,12 +375,48 @@ for all rules. Using a tag name (e.g., `whitespace`) and a setting of `false`,
configuration object is passed or the optional `default` setting is not present, configuration object is passed or the optional `default` setting is not present,
all rules are enabled. all rules are enabled.
The following syntax disables the specified rule, tag, or `default`:
```javascript
{
"rule_name": false
}
```
The following syntax enables the specified rule, tag, or `default`:
```javascript
{
"rule_name": true
// OR
"rule_name": "error"
}
```
The following syntax enables and configures the specified rule:
```javascript
{
"rule_name": {
"parameter": "value"
}
// OR
"rule_name": {
"parameter": "value",
"severity": "error"
}
}
```
> Note that `error` and `severity` are not supported by library versions earlier
> than `0.39.0`. However, all examples above behave the same.
To evaluate a configuration object, the `default` setting is applied first, then 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 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. rule (because of tag names or duplication), later values override earlier ones.
Keys (including rule names, aliases, tags, or `default`) are not case-sensitive. Keys (including rule names, aliases, tags, or `default`) are not case-sensitive.
Example: Example using `default`, rule names, and tag names together:
```json ```json
{ {

View file

@ -61,8 +61,12 @@ for (const rule of rules) {
"" ""
); );
const ruleData = schema.properties[name]; const ruleData = schema.properties[name];
const ruleProperties = ruleData.oneOf.at(-1).properties; const ruleProperties = Object.fromEntries(
if (ruleProperties) { Object.entries(
ruleData.oneOf.at(-1).properties
).filter(([ key ]) => key !== "severity")
);
if (Object.keys(ruleProperties).length > 0) {
section.push( section.push(
"Parameters:", "Parameters:",
"" ""

File diff suppressed because it is too large Load diff

View file

@ -262,9 +262,9 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
for (const key of Object.keys(config)) { for (const key of Object.keys(config)) {
let value = config[key]; let value = config[key];
if (value) { if (value) {
if (!(value instanceof Object)) { value = (value instanceof Object) ?
value = {}; Object.fromEntries(Object.entries(value).filter(([ k ]) => k !== "severity")) :
} {};
} else { } else {
value = false; value = false;
} }

View file

@ -6,14 +6,20 @@ import yaml from "js-yaml";
import { __dirname, importWithTypeJson } from "../test/esm-helpers.mjs"; import { __dirname, importWithTypeJson } from "../test/esm-helpers.mjs";
const configSchema = await importWithTypeJson(import.meta, "../schema/markdownlint-config-schema.json"); const configSchema = await importWithTypeJson(import.meta, "../schema/markdownlint-config-schema.json");
/** @type {Object<string, any>} */
const configExample = {}; const configExample = {};
for (const rule in configSchema.properties) { for (const rule in configSchema.properties) {
if (/^(?:MD\d{3}|default|extends)$/.test(rule)) { if (/^(?:MD\d{3}|default|extends)$/.test(rule)) {
const properties = configSchema.properties[rule]; const properties = configSchema.properties[rule];
configExample[rule + "-description"] = properties.description; configExample[rule + "-description"] = properties.description;
configExample[rule] = properties.default; configExample[rule] = properties.default;
const subproperties = properties.oneOf?.at(-1).properties; const subproperties = Object.fromEntries(
if (subproperties) { Object.entries(
properties.oneOf?.at(-1).properties || []
).filter(([ key ]) => key !== "severity")
);
if (Object.keys(subproperties).length > 0) {
/** @type {Object<string, any>} */
const ruleExample = {}; const ruleExample = {};
// eslint-disable-next-line guard-for-in // eslint-disable-next-line guard-for-in
for (const property in subproperties) { for (const property in subproperties) {
@ -26,6 +32,13 @@ for (const rule in configSchema.properties) {
} }
} }
/**
* Transforms comments to use the specified prefix.
*
* @param {string} input Markdown input.
* @param {string} commentPrefix Comment prefix.
* @returns {string} Transformed input.
*/
const transformComments = (input, commentPrefix) => ( const transformComments = (input, commentPrefix) => (
commentPrefix + commentPrefix +
" Example markdownlint configuration with all properties set to their default value\n" + " Example markdownlint configuration with all properties set to their default value\n" +

View file

@ -70,25 +70,34 @@ for (const rule of rules) {
], ],
"default": true "default": true
}; };
/** @type {{type: "object", additionalProperties: boolean, properties?: object}} */
const subscheme = { const subscheme = {
"type": "object", "type": "object",
"additionalProperties": false "additionalProperties": false,
"properties": {
"severity": {
"description": "Rule severity",
"type": "string",
"enum": [
"error"
],
"default": "error"
}
}
}; };
let custom = true; scheme.oneOf.push(subscheme);
/* eslint-disable camelcase */
switch (ruleName) { switch (ruleName) {
case "MD001": case "MD001":
subscheme.properties = { // @ts-ignore
"front_matter_title": { subscheme.properties.front_matter_title = {
"description": "RegExp for matching title in front matter", "description": "RegExp for matching title in front matter",
"type": "string", "type": "string",
"default": "^\\s*title\\s*[:=]" "default": "^\\s*title\\s*[:=]"
}
}; };
break; break;
case "MD003": case "MD003":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Heading style", "description": "Heading style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -100,12 +109,11 @@ for (const rule of rules) {
"setext_with_atx_closed" "setext_with_atx_closed"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD004": case "MD004":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "List style", "description": "List style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -116,134 +124,141 @@ for (const rule of rules) {
"sublist" "sublist"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD007": case "MD007":
subscheme.properties = { // @ts-ignore
"indent": { subscheme.properties.indent = {
"description": "Spaces for indent", "description": "Spaces for indent",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 2 "default": 2
}, };
"start_indented": { // @ts-ignore
subscheme.properties.start_indented = {
"description": "Whether to indent the first level of the list", "description": "Whether to indent the first level of the list",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, };
"start_indent": { // @ts-ignore
subscheme.properties.start_indent = {
"description": "description":
"Spaces for first level indent (when start_indented is set)", "Spaces for first level indent (when start_indented is set)",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 2 "default": 2
}
}; };
break; break;
case "MD009": case "MD009":
subscheme.properties = { // @ts-ignore
"br_spaces": { subscheme.properties.br_spaces = {
"description": "Spaces for line break", "description": "Spaces for line break",
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 2 "default": 2
}, };
"list_item_empty_lines": { // @ts-ignore
subscheme.properties.list_item_empty_lines = {
"description": "Allow spaces for empty lines in list items", "description": "Allow spaces for empty lines in list items",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, };
"strict": { // @ts-ignore
subscheme.properties.strict = {
"description": "Include unnecessary breaks", "description": "Include unnecessary breaks",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD010": case "MD010":
subscheme.properties = { // @ts-ignore
"code_blocks": { subscheme.properties.code_blocks = {
"description": "Include code blocks", "description": "Include code blocks",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"ignore_code_languages": { // @ts-ignore
subscheme.properties.ignore_code_languages = {
"description": "Fenced code languages to ignore", "description": "Fenced code languages to ignore",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [] "default": []
}, };
"spaces_per_tab": { // @ts-ignore
subscheme.properties.spaces_per_tab = {
"description": "Number of spaces for each hard tab", "description": "Number of spaces for each hard tab",
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 1 "default": 1
}
}; };
break; break;
case "MD012": case "MD012":
subscheme.properties = { // @ts-ignore
"maximum": { subscheme.properties.maximum = {
"description": "Consecutive blank lines", "description": "Consecutive blank lines",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 1 "default": 1
}
}; };
break; break;
case "MD013": case "MD013":
subscheme.properties = { // @ts-ignore
"line_length": { subscheme.properties.line_length = {
"description": "Number of characters", "description": "Number of characters",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 80 "default": 80
}, };
"heading_line_length": { // @ts-ignore
subscheme.properties.heading_line_length = {
"description": "Number of characters for headings", "description": "Number of characters for headings",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 80 "default": 80
}, };
"code_block_line_length": { // @ts-ignore
subscheme.properties.code_block_line_length = {
"description": "Number of characters for code blocks", "description": "Number of characters for code blocks",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 80 "default": 80
}, };
"code_blocks": { // @ts-ignore
subscheme.properties.code_blocks = {
"description": "Include code blocks", "description": "Include code blocks",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"tables": { // @ts-ignore
subscheme.properties.tables = {
"description": "Include tables", "description": "Include tables",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"headings": { // @ts-ignore
subscheme.properties.headings = {
"description": "Include headings", "description": "Include headings",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"strict": { // @ts-ignore
subscheme.properties.strict = {
"description": "Strict length checking", "description": "Strict length checking",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, };
"stern": { // @ts-ignore
subscheme.properties.stern = {
"description": "Stern length checking", "description": "Stern length checking",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD022": case "MD022":
subscheme.properties = { // @ts-ignore
"lines_above": { subscheme.properties.lines_above = {
"description": "Blank lines above heading", "description": "Blank lines above heading",
"type": [ "type": [
"integer", "integer",
@ -254,8 +269,9 @@ for (const rule of rules) {
}, },
"minimum": -1, "minimum": -1,
"default": 1 "default": 1
}, };
"lines_below": { // @ts-ignore
subscheme.properties.lines_below = {
"description": "Blank lines below heading", "description": "Blank lines below heading",
"type": [ "type": [
"integer", "integer",
@ -266,40 +282,36 @@ for (const rule of rules) {
}, },
"minimum": -1, "minimum": -1,
"default": 1 "default": 1
}
}; };
break; break;
case "MD024": case "MD024":
subscheme.properties = { // @ts-ignore
"siblings_only": { subscheme.properties.siblings_only = {
"description": "Only check sibling headings", "description": "Only check sibling headings",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD026": case "MD026":
case "MD036": case "MD036":
subscheme.properties = { // @ts-ignore
"punctuation": { subscheme.properties.punctuation = {
"description": "Punctuation characters", "description": "Punctuation characters",
"type": "string", "type": "string",
"default": (ruleName === "MD026") ? ".,;:!。,;:!" : ".,;:!?。,;:!?" "default": (ruleName === "MD026") ? ".,;:!。,;:!" : ".,;:!?。,;:!?"
}
}; };
break; break;
case "MD027": case "MD027":
subscheme.properties = { // @ts-ignore
"list_items": { subscheme.properties.list_items = {
"description": "Include list items", "description": "Include list items",
"type": "boolean", "type": "boolean",
"default": true "default": true
}
}; };
break; break;
case "MD029": case "MD029":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "List style", "description": "List style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -309,124 +321,119 @@ for (const rule of rules) {
"zero" "zero"
], ],
"default": "one_or_ordered" "default": "one_or_ordered"
}
}; };
break; break;
case "MD030": case "MD030":
subscheme.properties = { // @ts-ignore
"ul_single": { subscheme.properties.ul_single = {
"description": "Spaces for single-line unordered list items", "description": "Spaces for single-line unordered list items",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 1 "default": 1
}, };
"ol_single": { // @ts-ignore
subscheme.properties.ol_single = {
"description": "Spaces for single-line ordered list items", "description": "Spaces for single-line ordered list items",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 1 "default": 1
}, };
"ul_multi": { // @ts-ignore
subscheme.properties.ul_multi = {
"description": "Spaces for multi-line unordered list items", "description": "Spaces for multi-line unordered list items",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 1 "default": 1
}, };
"ol_multi": { // @ts-ignore
subscheme.properties.ol_multi = {
"description": "Spaces for multi-line ordered list items", "description": "Spaces for multi-line ordered list items",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"default": 1 "default": 1
}
}; };
break; break;
case "MD031": case "MD031":
subscheme.properties = { // @ts-ignore
"list_items": { subscheme.properties.list_items = {
"description": "Include list items", "description": "Include list items",
"type": "boolean", "type": "boolean",
"default": true "default": true
}
}; };
break; break;
case "MD033": case "MD033":
subscheme.properties = { // @ts-ignore
"allowed_elements": { subscheme.properties.allowed_elements = {
"description": "Allowed elements", "description": "Allowed elements",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [] "default": []
}, };
"table_allowed_elements": { // @ts-ignore
subscheme.properties.table_allowed_elements = {
"description": "Allowed elements in tables", "description": "Allowed elements in tables",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [] "default": []
}
}; };
break; break;
case "MD035": case "MD035":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Horizontal rule style", "description": "Horizontal rule style",
"type": "string", "type": "string",
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD040": case "MD040":
subscheme.properties = { // @ts-ignore
"allowed_languages": { subscheme.properties.allowed_languages = {
"description": "List of languages", "description": "List of languages",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [] "default": []
}, };
"language_only": { // @ts-ignore
subscheme.properties.language_only = {
"description": "Require language only", "description": "Require language only",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD025": case "MD025":
case "MD041": case "MD041":
{ if (ruleName === "MD041") {
const md041Properties = (ruleName === "MD041") ? // @ts-ignore
{ subscheme.properties.allow_preamble = {
"allow_preamble": {
"description": "Allow content before first heading", "description": "Allow content before first heading",
"type": "boolean", "type": "boolean",
"default": false "default": false
};
} }
} : // @ts-ignore
{}; subscheme.properties.front_matter_title = {
subscheme.properties = {
...md041Properties,
"front_matter_title": {
"description": "RegExp for matching title in front matter", "description": "RegExp for matching title in front matter",
"type": "string", "type": "string",
"default": "^\\s*title\\s*[:=]" "default": "^\\s*title\\s*[:=]"
}, };
"level": { // @ts-ignore
subscheme.properties.level = {
"description": "Heading level", "description": "Heading level",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"maximum": 6, "maximum": 6,
"default": 1 "default": 1
}
}; };
}
break; break;
case "MD043": case "MD043":
subscheme.properties = { // @ts-ignore
"headings": { subscheme.properties.headings = {
"description": "List of headings", "description": "List of headings",
"type": "array", "type": "array",
"items": { "items": {
@ -434,39 +441,40 @@ for (const rule of rules) {
"pattern": "^(\\*|\\+|\\?|#{1,6}\\s+\\S.*)$" "pattern": "^(\\*|\\+|\\?|#{1,6}\\s+\\S.*)$"
}, },
"default": [] "default": []
}, };
"match_case": { // @ts-ignore
subscheme.properties.match_case = {
"description": "Match case of headings", "description": "Match case of headings",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD044": case "MD044":
subscheme.properties = { // @ts-ignore
"names": { subscheme.properties.names = {
"description": "List of proper names", "description": "List of proper names",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [] "default": []
}, };
"code_blocks": { // @ts-ignore
subscheme.properties.code_blocks = {
"description": "Include code blocks", "description": "Include code blocks",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"html_elements": { // @ts-ignore
subscheme.properties.html_elements = {
"description": "Include HTML elements", "description": "Include HTML elements",
"type": "boolean", "type": "boolean",
"default": true "default": true
}
}; };
break; break;
case "MD046": case "MD046":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Block style", "description": "Block style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -475,12 +483,11 @@ for (const rule of rules) {
"indented" "indented"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD048": case "MD048":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Code fence style", "description": "Code fence style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -489,13 +496,12 @@ for (const rule of rules) {
"tilde" "tilde"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD049": case "MD049":
case "MD050": case "MD050":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": (ruleName === "MD049") ? "Emphasis style" : "Strong style", "description": (ruleName === "MD049") ? "Emphasis style" : "Strong style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -504,89 +510,91 @@ for (const rule of rules) {
"underscore" "underscore"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD051": case "MD051":
subscheme.properties = { // @ts-ignore
"ignore_case": { subscheme.properties.ignore_case = {
"description": "Ignore case of fragments", "description": "Ignore case of fragments",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, };
"ignored_pattern": { // @ts-ignore
subscheme.properties.ignored_pattern = {
"description": "Pattern for ignoring additional fragments", "description": "Pattern for ignoring additional fragments",
"type": "string", "type": "string",
"default": "" "default": ""
}
}; };
break; break;
case "MD052": case "MD052":
subscheme.properties = { // @ts-ignore
"ignored_labels": { subscheme.properties.ignored_labels = {
"description": "Ignored link labels", "description": "Ignored link labels",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [ "x" ] "default": [ "x" ]
}, };
"shortcut_syntax": { // @ts-ignore
subscheme.properties.shortcut_syntax = {
"description": "Include shortcut syntax", "description": "Include shortcut syntax",
"type": "boolean", "type": "boolean",
"default": false "default": false
}
}; };
break; break;
case "MD053": case "MD053":
subscheme.properties = { // @ts-ignore
"ignored_definitions": { subscheme.properties.ignored_definitions = {
"description": "Ignored definitions", "description": "Ignored definitions",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, },
"default": [ "//" ] "default": [ "//" ]
}
}; };
break; break;
case "MD054": case "MD054":
subscheme.properties = { // @ts-ignore
"autolink": { subscheme.properties.autolink = {
"description": "Allow autolinks", "description": "Allow autolinks",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"inline": { // @ts-ignore
subscheme.properties.inline = {
"description": "Allow inline links and images", "description": "Allow inline links and images",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"full": { // @ts-ignore
subscheme.properties.full = {
"description": "Allow full reference links and images", "description": "Allow full reference links and images",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"collapsed": { // @ts-ignore
subscheme.properties.collapsed = {
"description": "Allow collapsed reference links and images", "description": "Allow collapsed reference links and images",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"shortcut": { // @ts-ignore
subscheme.properties.shortcut = {
"description": "Allow shortcut reference links and images", "description": "Allow shortcut reference links and images",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, };
"url_inline": { // @ts-ignore
subscheme.properties.url_inline = {
"description": "Allow URLs as inline links", "description": "Allow URLs as inline links",
"type": "boolean", "type": "boolean",
"default": true "default": true
}
}; };
break; break;
case "MD055": case "MD055":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Table pipe style", "description": "Table pipe style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -597,12 +605,11 @@ for (const rule of rules) {
"no_leading_or_trailing" "no_leading_or_trailing"
], ],
"default": "consistent" "default": "consistent"
}
}; };
break; break;
case "MD059": case "MD059":
subscheme.properties = { // @ts-ignore
"prohibited_texts": { subscheme.properties.prohibited_texts = {
"description": "Prohibited link texts", "description": "Prohibited link texts",
"type": "array", "type": "array",
"items": { "items": {
@ -614,12 +621,11 @@ for (const rule of rules) {
"link", "link",
"more" "more"
] ]
}
}; };
break; break;
case "MD060": case "MD060":
subscheme.properties = { // @ts-ignore
"style": { subscheme.properties.style = {
"description": "Table column style", "description": "Table column style",
"type": "string", "type": "string",
"enum": [ "enum": [
@ -629,16 +635,12 @@ for (const rule of rules) {
"tight" "tight"
], ],
"default": "any" "default": "any"
}
}; };
break; break;
default: default:
custom = false;
break; break;
} }
if (custom) { /* eslint-enable camelcase */
scheme.oneOf.push(subscheme);
}
for (const name of rule.names) { for (const name of rule.names) {
schema.properties[name] = scheme; schema.properties[name] = scheme;
// Using $ref causes rule aliases not to get JSDoc comments // Using $ref causes rule aliases not to get JSDoc comments

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
# Configure File With Severity
Text * text* {MD037}
Text ` text` {MD038}
Text [ text](.) {MD039}
+ List item {MD004}
Text (text)[.] {MD011}
2. List item {MD029}
<!-- markdownlint-disable -->
Text * text*
Text ` text`
Text [ text](.)
+ List item
Text (text)[.]
2. List item
<!-- markdownlint-restore -->
Text * text* {MD037}
Text ` text` {MD038}
Text [ text](.) {MD039}
+ List item {MD004}
Text (text)[.] {MD011}
2. List item {MD029}
<!-- markdownlint-configure-file {
"default": false,
"MD037": "error",
"MD038": "error",
"MD039": "error",
"MD004": {
"severity": "error",
"style": "dash"
},
"MD011": {
"severity": "error"
},
"MD029": {
"severity": "error"
}
} -->

View file

@ -29,13 +29,14 @@ test("customRulesV0", (t) => new Promise((resolve) => {
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
t.falsy(err); t.falsy(err);
const expectedResult = {}; const expectedResult = {
expectedResult[customRulesMd] = { [customRulesMd]: {
"any-blockquote-markdown-it": [ 12 ], "any-blockquote-markdown-it": [ 12 ],
"any-blockquote-micromark": [ 12 ], "any-blockquote-micromark": [ 12 ],
"every-n-lines": [ 2, 4, 6, 10, 12 ], "every-n-lines": [ 2, 4, 6, 10, 12 ],
"first-line": [ 1 ], "first-line": [ 1 ],
"letters-E-X": [ 3, 7 ] "letters-E-X": [ 3, 7 ]
}
}; };
t.deepEqual(actualResult, expectedResult, "Undetected issues."); t.deepEqual(actualResult, expectedResult, "Undetected issues.");
// @ts-ignore // @ts-ignore
@ -103,8 +104,8 @@ test("customRulesV1", (t) => new Promise((resolve) => {
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
t.falsy(err); t.falsy(err);
const expectedResult = {}; const expectedResult = {
expectedResult[customRulesMd] = [ [customRulesMd]: [
{ "lineNumber": 12, { "lineNumber": 12,
"ruleName": "any-blockquote-markdown-it", "ruleName": "any-blockquote-markdown-it",
"ruleAlias": "any-blockquote-markdown-it", "ruleAlias": "any-blockquote-markdown-it",
@ -189,7 +190,8 @@ test("customRulesV1", (t) => new Promise((resolve) => {
"errorDetail": null, "errorDetail": null,
"errorContext": "text", "errorContext": "text",
"errorRange": null } "errorRange": null }
]; ]
};
t.deepEqual(actualResult, expectedResult, "Undetected issues."); t.deepEqual(actualResult, expectedResult, "Undetected issues.");
// @ts-ignore // @ts-ignore
const actualMessage = actualResult.toString(); const actualMessage = actualResult.toString();
@ -236,8 +238,8 @@ test("customRulesV2", (t) => new Promise((resolve) => {
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
t.falsy(err); t.falsy(err);
const expectedResult = {}; const expectedResult = {
expectedResult[customRulesMd] = [ [customRulesMd]: [
{ "lineNumber": 12, { "lineNumber": 12,
"ruleNames": [ "any-blockquote-markdown-it" ], "ruleNames": [ "any-blockquote-markdown-it" ],
"ruleDescription": "Rule that reports an error for any blockquote", "ruleDescription": "Rule that reports an error for any blockquote",
@ -312,7 +314,8 @@ test("customRulesV2", (t) => new Promise((resolve) => {
"errorDetail": null, "errorDetail": null,
"errorContext": "text", "errorContext": "text",
"errorRange": null } "errorRange": null }
]; ]
};
t.deepEqual(actualResult, expectedResult, "Undetected issues."); t.deepEqual(actualResult, expectedResult, "Undetected issues.");
// @ts-ignore // @ts-ignore
const actualMessage = actualResult.toString(); const actualMessage = actualResult.toString();
@ -366,13 +369,14 @@ test("customRulesConfig", (t) => new Promise((resolve) => {
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
t.falsy(err); t.falsy(err);
const expectedResult = {}; const expectedResult = {
expectedResult[customRulesMd] = { [customRulesMd]: {
"any-blockquote-markdown-it": [ 12 ], "any-blockquote-markdown-it": [ 12 ],
"any-blockquote-micromark": [ 12 ], "any-blockquote-micromark": [ 12 ],
"every-n-lines": [ 3, 6, 12 ], "every-n-lines": [ 3, 6, 12 ],
"first-line": [ 1 ], "first-line": [ 1 ],
"letters-E-X": [ 7 ] "letters-E-X": [ 7 ]
}
}; };
t.deepEqual(actualResult, expectedResult, "Undetected issues."); t.deepEqual(actualResult, expectedResult, "Undetected issues.");
resolve(); resolve();
@ -445,6 +449,7 @@ test("customRulesBadProperty", (t) => {
const { propertyName, propertyValues } = testCase; const { propertyName, propertyValues } = testCase;
for (const propertyValue of propertyValues) { for (const propertyValue of propertyValues) {
const badRule = { ...customRules.firstLine }; const badRule = { ...customRules.firstLine };
// @ts-ignore
badRule[propertyName] = propertyValue; badRule[propertyName] = propertyValue;
/** @type {import("markdownlint").Options} */ /** @type {import("markdownlint").Options} */
const options = { const options = {
@ -1211,6 +1216,7 @@ test("customRulesOnErrorBad", (t) => {
]) { ]) {
const { propertyName, subPropertyName, propertyValues } = testCase; const { propertyName, subPropertyName, propertyValues } = testCase;
for (const propertyValue of propertyValues) { for (const propertyValue of propertyValues) {
/** @type {Object<string, any>} */
const badObject = { const badObject = {
"lineNumber": 1 "lineNumber": 1
}; };
@ -1232,6 +1238,7 @@ test("customRulesOnErrorBad", (t) => {
"tags": [ "tag" ], "tags": [ "tag" ],
"parser": "none", "parser": "none",
"function": function onErrorBad(params, onError) { "function": function onErrorBad(params, onError) {
// @ts-ignore
onError(badObject); onError(badObject);
} }
} }
@ -1283,6 +1290,7 @@ test("customRulesOnErrorInvalid", (t) => {
]) { ]) {
const { propertyName, subPropertyName, propertyValues } = testCase; const { propertyName, subPropertyName, propertyValues } = testCase;
for (const propertyValue of propertyValues) { for (const propertyValue of propertyValues) {
/** @type {Object<string, any>} */
const badObject = { const badObject = {
"lineNumber": 1 "lineNumber": 1
}; };
@ -1304,6 +1312,7 @@ test("customRulesOnErrorInvalid", (t) => {
"tags": [ "tag" ], "tags": [ "tag" ],
"parser": "none", "parser": "none",
"function": function onErrorInvalid(params, onError) { "function": function onErrorInvalid(params, onError) {
// @ts-ignore
onError(badObject); onError(badObject);
} }
} }
@ -1361,6 +1370,7 @@ test("customRulesOnErrorValid", (t) => {
]) { ]) {
const { propertyName, subPropertyName, propertyValues } = testCase; const { propertyName, subPropertyName, propertyValues } = testCase;
for (const propertyValue of propertyValues) { for (const propertyValue of propertyValues) {
/** @type {Object<string, any>} */
const goodObject = { const goodObject = {
"lineNumber": 1 "lineNumber": 1
}; };
@ -1379,6 +1389,7 @@ test("customRulesOnErrorValid", (t) => {
"tags": [ "tag" ], "tags": [ "tag" ],
"parser": "none", "parser": "none",
"function": function onErrorValid(params, onError) { "function": function onErrorValid(params, onError) {
// @ts-ignore
onError(goodObject); onError(goodObject);
} }
} }
@ -1973,13 +1984,62 @@ test("customRulesAsyncThrowsInSyncContext", (t) => {
); );
}); });
test("customRulesParamsConfigExcludesSeverity", (t) => {
t.plan(4);
/** @type {import("markdownlint").Rule} */
const ruleBase = {
"names": [ "tbd" ],
"description": "description",
"tags": [ "tag" ],
"parser": "none",
"asynchronous": true,
"function": ({ config }) => {
t.is(typeof config, "object");
t.is(typeof config.severity, "undefined");
}
};
/** @type {import("markdownlint").Options} */
const options = {
"config": {
"name1": {
"severity": "error"
},
"name2": {
"key": "value",
"severity": "error"
}
},
"customRules": [
{
...ruleBase,
"names": [ "name1" ]
},
{
...ruleBase,
"names": [ "name2" ]
}
],
"strings": {
"string": "Unused"
}
};
return lintPromise(options);
});
test("customRulesParamsAreFrozen", (t) => { test("customRulesParamsAreFrozen", (t) => {
/**
* Asserts that rule parameters are frozen.
*
* @param {import("markdownlint").RuleParams} params Rule parameters.
* @returns {void}
*/
const assertParamsFrozen = (params) => { const assertParamsFrozen = (params) => {
const pending = [ params ]; const pending = [ params ];
let current = null; let current = null;
while ((current = pending.shift())) { while ((current = pending.shift())) {
t.true(Object.isFrozen(current) || (current === params)); t.true(Object.isFrozen(current) || (current === params));
for (const name of Object.getOwnPropertyNames(current)) { for (const name of Object.getOwnPropertyNames(current)) {
// @ts-ignore
const value = current[name]; const value = current[name];
if ( if (
value && value &&

View file

@ -346,17 +346,104 @@ test("enableRulesString", getConfigTestImplementation(
configTestExpected3511 configTestExpected3511
)); ));
test("enableRulesEmptyObject", getConfigTestImplementation( test("enableRulesObjectEmpty", getConfigTestImplementation(
{ {
"MD041": {}, "MD041": {},
"default": false, "default": false,
// @ts-ignore
"no-multiple-space-atx": {}, "no-multiple-space-atx": {},
"extra": {} "extra": {}
}, },
configTestExpected3511 configTestExpected3511
)); ));
test("enableRulesObjectTruthy", getConfigTestImplementation(
{
"MD041": {
// @ts-ignore
"severity": 1
},
"default": false,
"no-multiple-space-atx": {
// @ts-ignore
"severity": 1
},
"extra": {
"severity": 1
}
},
configTestExpected3511
));
test("enableRulesObjectFalsy", getConfigTestImplementation(
{
"MD041": {
// @ts-ignore
"severity": 0
},
"default": false,
"no-multiple-space-atx": {
// @ts-ignore
"severity": 0
},
"extra": {
"severity": 0
}
},
configTestExpected3511
));
test("enableRulesObjectError", getConfigTestImplementation(
{
"MD041": {
"severity": "error"
},
"default": false,
"no-multiple-space-atx": {
"severity": "error"
},
"extra": {
"severity": "error"
}
},
configTestExpected3511
));
test("enableRulesObjectWarning", getConfigTestImplementation(
{
"MD041": {
// @ts-ignore
"severity": "warning"
},
"default": false,
"no-multiple-space-atx": {
// @ts-ignore
"severity": "warning"
},
"extra": {
"severity": "warning"
}
},
configTestExpected3511
));
test("enableRulesObjectOff", getConfigTestImplementation(
{
"MD041": {
// @ts-ignore
"severity": "off"
},
"default": false,
"no-multiple-space-atx": {
// @ts-ignore
"severity": "off"
},
"extra": {
"severity": "off"
}
},
configTestExpected3511
));
test("disableTag", getConfigTestImplementation( test("disableTag", getConfigTestImplementation(
{ {
"default": true, "default": true,
@ -921,7 +1008,7 @@ test("readme", async(t) => {
}); });
test("validateJsonUsingConfigSchemaStrict", async(t) => { test("validateJsonUsingConfigSchemaStrict", async(t) => {
t.plan(211); t.plan(212);
// @ts-ignore // @ts-ignore
const ajv = new Ajv(ajvOptions); const ajv = new Ajv(ajvOptions);
const validateSchemaStrict = ajv.compile(configSchemaStrict); const validateSchemaStrict = ajv.compile(configSchemaStrict);

View file

@ -11203,6 +11203,320 @@ Generated by [AVA](https://avajs.dev).
`, `,
} }
## configure-file-with-severity.md
> Snapshot 1
{
errors: [
{
errorContext: null,
errorDetail: 'Expected: dash; Actual: plus',
errorRange: [
1,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 1,
insertText: '-',
},
lineNumber: 9,
ruleDescription: 'Unordered list style',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md004.md',
ruleNames: [
'MD004',
'ul-style',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: dash; Actual: plus',
errorRange: [
1,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 1,
insertText: '-',
},
lineNumber: 37,
ruleDescription: 'Unordered list style',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md004.md',
ruleNames: [
'MD004',
'ul-style',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: '(text)[.]',
errorRange: [
6,
9,
],
fixInfo: {
deleteCount: 9,
editColumn: 6,
insertText: '[text](.)',
},
lineNumber: 11,
ruleDescription: 'Reversed link syntax',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md011.md',
ruleNames: [
'MD011',
'no-reversed-links',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: '(text)[.]',
errorRange: [
6,
9,
],
fixInfo: {
deleteCount: 9,
editColumn: 6,
insertText: '[text](.)',
},
lineNumber: 39,
ruleDescription: 'Reversed link syntax',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md011.md',
ruleNames: [
'MD011',
'no-reversed-links',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 1; Actual: 2; Style: 1/1/1',
errorRange: [
1,
3,
],
fixInfo: {
deleteCount: 1,
editColumn: 1,
insertText: '1',
},
lineNumber: 13,
ruleDescription: 'Ordered list item prefix',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md029.md',
ruleNames: [
'MD029',
'ol-prefix',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 1; Actual: 2; Style: 1/1/1',
errorRange: [
1,
3,
],
fixInfo: {
deleteCount: 1,
editColumn: 1,
insertText: '1',
},
lineNumber: 41,
ruleDescription: 'Ordered list item prefix',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md029.md',
ruleNames: [
'MD029',
'ol-prefix',
],
severity: 'error',
},
{
errorContext: '* t',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 3,
ruleDescription: 'Spaces inside emphasis markers',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md037.md',
ruleNames: [
'MD037',
'no-space-in-emphasis',
],
severity: 'error',
},
{
errorContext: '* t',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 31,
ruleDescription: 'Spaces inside emphasis markers',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md037.md',
ruleNames: [
'MD037',
'no-space-in-emphasis',
],
severity: 'error',
},
{
errorContext: '` text`',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 5,
ruleDescription: 'Spaces inside code span elements',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md038.md',
ruleNames: [
'MD038',
'no-space-in-code',
],
severity: 'error',
},
{
errorContext: '` text`',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 33,
ruleDescription: 'Spaces inside code span elements',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md038.md',
ruleNames: [
'MD038',
'no-space-in-code',
],
severity: 'error',
},
{
errorContext: '[ text]',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 7,
ruleDescription: 'Spaces inside link text',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md039.md',
ruleNames: [
'MD039',
'no-space-in-links',
],
severity: 'error',
},
{
errorContext: '[ text]',
errorDetail: null,
errorRange: [
7,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 7,
},
lineNumber: 35,
ruleDescription: 'Spaces inside link text',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md039.md',
ruleNames: [
'MD039',
'no-space-in-links',
],
severity: 'error',
},
],
fixed: `# Configure File With Severity␊
Text *text* {MD037}␊
Text \`text\` {MD038}␊
Text [text](.) {MD039}␊
- List item {MD004}␊
Text [text](.) {MD011}␊
1. List item {MD029}␊
<!-- markdownlint-disable -->
Text * text*
Text \` text\`␊
Text [ text](.)␊
+ List item␊
Text (text)[.]␊
2. List item␊
<!-- markdownlint-restore -->
Text *text* {MD037}␊
Text \`text\` {MD038}␊
Text [text](.) {MD039}␊
- List item {MD004}␊
Text [text](.) {MD011}␊
1. List item {MD029}␊
<!-- markdownlint-configure-file {␊
"default": false,␊
"MD037": "error",␊
"MD038": "error",␊
"MD039": "error",␊
"MD004": {␊
"severity": "error",␊
"style": "dash"␊
},␊
"MD011": {␊
"severity": "error"␊
},␊
"MD029": {␊
"severity": "error"␊
}␊
} -->␊
`,
}
## consecutive_blank_lines.md ## consecutive_blank_lines.md
> Snapshot 1 > Snapshot 1