Rule - MD043#
| Property | Value |
|---|---|
| Aliases | md043, required-headings, required-headers |
| Autofix Available | No |
| Enabled By Default | Yes |
Summary#
Require the document to contain a specific, configuration-defined heading structure.
Reasoning#
Consistency#
Documents that share a common outline (e.g., templates, API reference pages, or generated reports) are easier to read when their heading structure is predictable. This rule lets authors encode that expected outline in configuration and flags any document that deviates from it.
Examples#
Failure Scenarios#
This rule triggers when the document headings do not match the configured required
structure. In this example, the configuration # Level 1,## Level 2 expects a Level
1 heading followed by a Level 2 heading, but the document starts with a Level 2
heading.
Explanation: The rule fails because the first heading is
## Level 1(Level 2), but the configuration requires the first heading to be# Level 1(Level 1). The heading level does not match the required structure.
Unlike the previous example, this case uses the correct heading levels but incorrect
heading text. The configuration expects Level 2, but the document contains
Level Two.
Explanation: The rule fails because the second heading text is
Level Two, but the configuration requires the text to beLevel 2. The heading text does not match the required structure.
Unlike the previous examples, this case uses the correct heading levels and text but in the wrong order. The configuration expects Level 1 before Level 2, but the document has Level 2 before Level 1.
Explanation: The rule fails because the headings appear in the order
## Level 2then# Level 1, but the configuration requires# Level 1to appear before## Level 2. The heading order does not match the required structure.
Unlike the previous examples, this case demonstrates a missing required heading.
The configuration expects # Level 1 followed by ## Level 2, but the document
only contains # Level 1.
Explanation: The rule fails because the document is missing the required
## Level 2heading. The configuration requires both headings to be present, but only the first one exists.
Unlike the previous examples, this case demonstrates that extra headings present
in the document cause a failure when the configuration does not include a wildcard
to allow them. The configuration # Level 1,## Level 2 expects exactly those two
headings, but the document contains an additional ### Level 3 heading.
Explanation: The rule fails because the document contains
### Level 3, which is not included in the configuration# Level 1,## Level 2. Since the configuration does not use a wildcard (*) to allow additional headings, any extra headings violate the required structure.
Unlike the previous examples, this case demonstrates that the rule inspects the
level of a Setext heading, not just its text. The configuration
# Level 1,## Level 2 requires a Level 1 heading followed by a Level 2
heading. The document uses Setext syntax, but the first heading is a Level 2
Setext heading (single-dash underline) where a Level 1 heading is required, and
the second heading is a Level 3 Setext heading (triple-dash underline) where a
Level 2 heading is required.
Explanation: The rule fails because the levels of the Setext headings do not match the configuration. The first Setext heading (
Level 1underlined with a single-) is a Level 2 heading, but the configuration requires a Level 1 heading (# Level 1). The second Setext heading (Level 2underlined with three-characters) is a Level 3 heading, but the configuration requires a Level 2 heading (## Level 2). The text of both headings is correct, but the underline length determines the level, and both levels are wrong.
Correct Scenarios#
This rule does not trigger when the document headings exactly match the configured
required structure. In this example, the configuration # Level 1,## Level 2 is
satisfied by the document having a Level 1 heading followed by a Level 2 heading
with the correct text.
Explanation: The rule passes because the document headings
# Level 1and## Level 2match the required structure specified in the configuration# Level 1,## Level 2in both level, text, and order.
Unlike the previous example, this case demonstrates the use of a wildcard (*)
in the configuration to allow for flexible content between required headings. The
configuration ## Header,*,## Footer requires a "Header" section and a "Footer"
section, with any number of headings (or none) allowed in between.
Explanation: The rule passes because the document starts with
## Headerand ends with## Footer, satisfying the configuration## Header,*,## Footer. The wildcard*allows for the intermediate### Subheading 1and### Subheading 2headings to exist without violating the rule.
Unlike the previous example, this case demonstrates the use of multiple wildcards
(*) in the configuration to allow flexible content in separate sections of the
document. The configuration ## Header,*,## Middle,*,## Footer requires "Header",
"Middle", and "Footer" sections, with any number of headings allowed between each
pair.
Explanation: The rule passes because the document contains
## Header,## Middle, and## Footerin the correct order. The configuration## Header,*,## Middle,*,## Footeruses two wildcards, allowing### Introductionand### Backgroundbetween the first two required headings, and### Databetween the next pair, without violating the rule.
Unlike the previous example, this case demonstrates that a Setext heading in the
document satisfies a configuration entry written in Atx form. The configuration
# Level 1,## Level 2 requires a Level 1 and a Level 2 heading, but the
document expresses both as Setext headings (underline-style) rather than Atx
headings (#-style).
Explanation: The rule passes because the configuration specifies heading levels and text, not the syntactic form. The first line
Level 1followed by=======is a Setext Level 1 heading, andLevel 2followed by-------is a Setext Level 2 heading. Both match the required# Level 1and## Level 2entries in the configuration# Level 1,## Level 2, confirming that Setext headings in the document are accepted regardless of the Atx form used in the configuration.
Unlike the previous example, this case demonstrates that a wildcard (*) may
match zero intermediate headings, not only one or more. The configuration
## Header,*,## Footer requires a ## Header heading followed by a
## Footer heading, with any number of headings (including none) allowed
between them. This document contains only the two required headings, with no
headings in between.
Explanation: The rule passes because the document begins with
## Headerand ends with## Footer, satisfying the configuration## Header,*,## Footer. The wildcard*matches zero intermediate headings in this case, which is permitted by its semantics ("zero or more non-matching headings"). The absence of any heading between## Headerand## Footerdoes not violate the rule.
Fix Description#
Auto-fixing is not available due to combinatorial explosion. While simple configurations
(e.g., ## Header, ## Footer) could be fixed, the use of the * wildcard creates
a large number of possible heading structures, making it computationally infeasible
to determine the correct fix automatically.
Configuration#
| Prefixes |
|---|
plugins.md043. |
plugins.required-headings. |
plugins.required-headers. |
| Value Name | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
True |
Whether the Rule Plugin is enabled. |
required_headings |
string |
"" |
Comma-separated list of headings to require the document to have. |
The comma-separated list of items is a string with a format of {item},...,{item}.
Any leading or trailing space characters surrounding the {item} are trimmed during
processing. Any empty {item} value left after this trimming has been applied will
generate a configuration error.
Each element must be in one of two forms. The first form is that of an uncomplicated
text Atx Heading,
such as # Heading 1. Regardless of whether the heading in the document is an
Atx Heading element or a Setext Heading element, this form must be used.
The second form is that of a single wildcard character. Currently, only
the * character is allowed, specifying that zero or more non-matching
headings may occur.
Origination of Rule#
This rule is largely inspired by the MarkdownLint rule MD043.