[GH-ISSUE #1613] MD01/heading-increment does not take front matter titles into account as level 1 heading #2568

Closed
opened 2026-03-07 20:08:57 +03:00 by kerem · 7 comments
Owner

Originally created by @afeblot on GitHub (May 23, 2025).
Original GitHub issue: https://github.com/DavidAnson/markdownlint/issues/1613

With markdownlint 0.38 (markdownlint-cli 0.45.0, ) all rules enabled with the default config:

This document generates the expected error:

# level 1

### level 3

mdtest.md:3 MD001/heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]

However, this one where the level 1 heading is replaced by the front-matter title does not:

---
title: "level 1"
---

### level 3

Given MD025/single-title and MD041/first-line-heading do consider this front matter as a level 1 heading, I would expect MD01 to behave consistently and do so as well.

If it does not, I have no clean way the check that pages with a front matter title start with a level 2 heading.

Originally created by @afeblot on GitHub (May 23, 2025). Original GitHub issue: https://github.com/DavidAnson/markdownlint/issues/1613 With markdownlint 0.38 (markdownlint-cli 0.45.0, ) all rules enabled with the default config: This document generates the expected error: ```md # level 1 ### level 3 ``` **mdtest.md:3 MD001/heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]** However, this one where the level 1 heading is replaced by the front-matter title does not: ```md --- title: "level 1" --- ### level 3 ``` Given **MD025/single-title** and **MD041/first-line-heading** do consider this front matter as a level 1 heading, I would expect MD01 to behave consistently and do so as well. If it does not, I have no clean way the check that pages with a front matter title start with a level 2 heading.
kerem 2026-03-07 20:08:57 +03:00
Author
Owner

@DavidAnson commented on GitHub (May 24, 2025):

MD001 is not appropriate for ensuring the first heading is an H2 whether or not YAML is present. For example, it does not trigger here: https://dlaa.me/markdownlint/#%25m%23%23%20Heading%0A

This test file should show how to achieve what you want using MD041: github.com/DavidAnson/markdownlint@224987d727/test/md041-yaml-title-and-first-line-heading.md

<!-- gh-comment-id:2906268137 --> @DavidAnson commented on GitHub (May 24, 2025): MD001 is not appropriate for ensuring the first heading is an H2 whether or not YAML is present. For example, it does not trigger here: https://dlaa.me/markdownlint/#%25m%23%23%20Heading%0A This test file should show how to achieve what you want using MD041: https://github.com/DavidAnson/markdownlint/blob/224987d727ebada36752074d2466a061c9e03ff0/test/md041-yaml-title-and-first-line-heading.md?plain=1
Author
Owner

@afeblot commented on GitHub (May 24, 2025):

@DavidAnson , thanks for your quick response.

But it does not help: I confirm your example works;

With this config,

first-line-heading:
  level: 2

this doc

---
path: "/post"
date: "2012-06-21T10:14:00.000+02:00"
title: "First level heading"
---

## level 2

does not trigger a warning. Which is what I expect.

However,

---
path: "/post"
date: "2012-06-21T10:14:00.000+02:00"
title: "First level heading"
---

### level 3

does not trigger a warning either. Whereas I would expect a warning here.

What I would like is that:

  • the title is considered as the first heading in the page, and to be a level 1 heading (this is the default behavior with MD0025)
  • Obviously, be allowed to have multiple level 2 headings.
  • A warning if the next heading after the title is not a level 2 (don't we agree this should be reported by default by mardownlint?).

I'm able to achieve this with the below config:

default: true

first-line-heading:
  level: 2
  front_matter_title: dontFindTitle
  allow_preamble: true

single-title:
  level: 1
  front_matter_title: dontFindTitle

no-duplicate-heading:
  siblings_only: true

This config does trigger a warning on

---
title: "TEST-A"
---

### level 3

and as well on

---
title: "TEST-B"
---

# level 1

But the triggered rule for these 2 files is MD041/first-line-heading. Whereas IMHO, it would be more appropriate to have MD001/heading-increment reporting TEST-A, and MD025/single-title reporting TEST-B.

And also, obviously, obtaining this result by disabling the front matter detection seems more like a workaround, considering that markdownlint default behavior is to take front matter into account as first heading provider. I assume it is as well reasonnable to consider as a default behavior that after such a title, the next heading level must only be 2, which I why I made my initial report regarding MD001 as a bug.

Where is it that we disagree on these statements, so that the default behavior does not report TEST-B as erroneous?

Thanks

<!-- gh-comment-id:2906921980 --> @afeblot commented on GitHub (May 24, 2025): @DavidAnson , thanks for your quick response. But it does not help: I confirm your example works; With this config, ```yaml first-line-heading: level: 2 ``` this doc ```md --- path: "/post" date: "2012-06-21T10:14:00.000+02:00" title: "First level heading" --- ## level 2 ``` does not trigger a warning. Which is what I expect. However, ```md --- path: "/post" date: "2012-06-21T10:14:00.000+02:00" title: "First level heading" --- ### level 3 ``` does not trigger a warning either. Whereas I would expect a warning here. What I would like is that: - the title is considered as the first heading in the page, and to be a level 1 heading (this is the default behavior with MD0025) - Obviously, be allowed to have multiple level 2 headings. - A warning if the next heading after the title is not a level 2 (don't we agree this should be reported by default by mardownlint?). I'm able to achieve this with the below config: ```yaml default: true first-line-heading: level: 2 front_matter_title: dontFindTitle allow_preamble: true single-title: level: 1 front_matter_title: dontFindTitle no-duplicate-heading: siblings_only: true ``` This config does trigger a warning on ```md --- title: "TEST-A" --- ### level 3 ``` and as well on ```md --- title: "TEST-B" --- # level 1 ``` But the triggered rule for these 2 files is `MD041/first-line-heading`. Whereas IMHO, it would be more appropriate to have `MD001/heading-increment` reporting TEST-A, and `MD025/single-title` reporting TEST-B. And also, obviously, obtaining this result by disabling the front matter detection seems more like a workaround, considering that markdownlint default behavior is to take front matter into account as first heading provider. I assume it is as well reasonnable to consider as a default behavior that after such a title, the next heading level must only be 2, which I why I made my initial report regarding MD001 as a bug. Where is it that we disagree on these statements, so that the default behavior does not report TEST-B as erroneous? Thanks
Author
Owner

@DavidAnson commented on GitHub (May 24, 2025):

Here is how to use the example I pointed out to achieve the result you want:

https://dlaa.me/markdownlint/#%25m---%0Atitle%3A%20%22Title%22%0A---%0A%0A%23%23%23%20Heading%0A%0A%3C!--%20markdownlint-configure-file%20%7B%0A%20%20%22first-line-heading%22%3A%20%7B%0A%20%20%20%20%22level%22%3A%202%2C%0A%20%20%20%20%22front_matter_title%22%3A%20%22ignore%22%0A%20%20%7D%0A%7D%20--%3E%0A

Note that it reports an issue as configured because the first heading is level 3 and it is configured for level 2. Changing that heading to level 2 removes the issue as I believe you intend for your scenario.

<!-- gh-comment-id:2906971402 --> @DavidAnson commented on GitHub (May 24, 2025): Here is how to use the example I pointed out to achieve the result you want: https://dlaa.me/markdownlint/#%25m---%0Atitle%3A%20%22Title%22%0A---%0A%0A%23%23%23%20Heading%0A%0A%3C!--%20markdownlint-configure-file%20%7B%0A%20%20%22first-line-heading%22%3A%20%7B%0A%20%20%20%20%22level%22%3A%202%2C%0A%20%20%20%20%22front_matter_title%22%3A%20%22ignore%22%0A%20%20%7D%0A%7D%20--%3E%0A Note that it reports an issue as configured because the first heading is level 3 and it is configured for level 2. Changing that heading to level 2 removes the issue as I believe you intend for your scenario.
Author
Owner

@afeblot commented on GitHub (May 26, 2025):

Well, yes, that's exactly what I showed in my previous message as a "workaround config". It does indeed report this level 3 title:

MD041 / first-line-heading First line in a file should be a top-level heading [Context: "### Heading"]

But it's misleading to have some rules refering to "top-level heading" for titles/level 1, and other rules for level 2. I just wished I could have a better report with a more relevant error message. Namely:

MD001 / heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]

Anyway, if that's what I can get for now, so be it, and my users will eventually figure out their mistakes.

Thanks.

<!-- gh-comment-id:2908898867 --> @afeblot commented on GitHub (May 26, 2025): Well, yes, that's exactly what I showed in my previous message as a "workaround config". It does indeed report this level 3 title: > MD041 / first-line-heading First line in a file should be a top-level heading [Context: "### Heading"] But it's misleading to have some rules refering to "top-level heading" for titles/level 1, and other rules for level 2. I just wished I could have a better report with a more relevant error message. Namely: > MD001 / heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3] Anyway, if that's what I can get for now, so be it, and my users will eventually figure out their mistakes. Thanks.
Author
Owner

@DavidAnson commented on GitHub (May 26, 2025):

Ah, thanks, I hadn't realized you showed the same configuration. The issue with using MD001 here is that its behavior looks to see if a heading level that increases vs. the previous increases by exactly 1. It doesn't currently have an explicit awareness of the first heading in a file. In code, it works by assuming the implied 0th heading level is very large. It could be modified to do what you want by allowing the user to configure the implicit level of the implied 0th heading. But doing so would veer away from the defined purpose of this rule: "This rule is triggered when you skip heading levels in a Markdown document". It probably wouldn't be the worst thing ever to add this and bend the definition slightly, especially as it would be optional.

<!-- gh-comment-id:2910384186 --> @DavidAnson commented on GitHub (May 26, 2025): Ah, thanks, I hadn't realized you showed the same configuration. The issue with using MD001 here is that its behavior looks to see if a heading level that increases vs. the previous increases by exactly 1. It doesn't currently have an explicit awareness of the first heading in a file. In code, it works by assuming the implied 0th heading level is very large. It could be modified to do what you want by allowing the user to configure the implicit level of the implied 0th heading. But doing so would veer away from the defined purpose of this rule: "This rule is triggered when you skip heading levels in a Markdown document". It probably wouldn't be the worst thing ever to add this and bend the definition slightly, especially as it would be optional.
Author
Owner

@afeblot commented on GitHub (May 26, 2025):

I'd really be grateful if you did this change.

I still have the feeling though, that if MD001 was able to detect a front matter title, and consider it as a heading (of level 1 by default, or defined by the front_matter_title param), exactly as done by rules 25 and 41, we'd get ths same behavior, with no deviation from the rule purpose. That title would just be considered as the first heading of the page, instead of the actual first heading. The rest of the rule implementation would probably not even differ.

<!-- gh-comment-id:2910557946 --> @afeblot commented on GitHub (May 26, 2025): I'd really be grateful if you did this change. I still have the feeling though, that if MD001 was able to detect a front matter title, and consider it as a heading (of level 1 by default, or defined by the front_matter_title param), exactly as done by rules 25 and 41, we'd get ths same behavior, with no deviation from the rule purpose. That title would just be considered as the first heading of the page, instead of the actual first heading. The rest of the rule implementation would probably not even differ.
Author
Owner

@DavidAnson commented on GitHub (Aug 3, 2025):

Fixed by #1617

<!-- gh-comment-id:3148731064 --> @DavidAnson commented on GitHub (Aug 3, 2025): Fixed by #1617
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/markdownlint#2568
No description provided.