Skip to content

A --- rule on the first body line is read as a second frontmatter block: body text is deleted by ExtractBody/RemoveFrontmatter or merged into the header #140

Closed

Description

@matt-edmondson

What's wrong

TrySplitFrontmatterBlocks (Frontmatter/Frontmatter.cs ~371-396) loops while (IsDelimiterAt(next)). So after the header closes, a --- on the very next line opens another block, and that block runs to the next --- line anywhere in the document. The fix for #132 stopped horizontal rules further down the body being treated as delimiters, but a rule placed directly under the header is still consumed.

Repro

This was reproduced against current main (13a0d6f) using scratch MSTest methods.

Case A: the text between the rules isn't a YAML mapping, so it is lost.

---
title: A
---
---
Important paragraph

---
More
  • ExtractBody returns "More".
  • RemoveFrontmatter returns "More\n".
  • ReplaceFrontmatter, AddFrontmatter and CombineFrontmatter all emit the header followed by only More.
  • "Important paragraph" and both rules are silently deleted.
  • Expected body: ---\nImportant paragraph\n\n---\nMore.

Case B: the text happens to parse as YAML, so it moves into the header.

---
title: My Post
---
---
Note: read this first

---

# Heading

CombineFrontmatter returns ---\ntitle: My Post\nNote: read this first\n---\n\n# Heading\n. A body paragraph has become a header property.

For comparison, ---\ntitle: A\n---\n---\n\nIntro text\n, which has no second rule, keeps its body correctly.

Why it matters

Placing a thematic break directly under the header is common Markdown. Running any of the rewriting APIs over such a document destroys or relocates content with no error. This isn't #139: that issue is about CombineFrontmatter dropping an unparseable block, whereas this bug is in the splitter and affects every API, including ExtractBody and RemoveFrontmatter.

Suggested fix / acceptance criteria

  • Accept a block after the first only if its content parses as a non-empty YAML mapping. Otherwise stop splitting and leave the --- in the body. This fixes Case A.
  • Case B is ambiguous, because consecutive blocks are supported on purpose (DelimiterLineTests.cs:55). Decide on a tighter rule, for example rejecting a follow-on block whose content is surrounded by blank lines, and add a regression test for it.
  • Add a test for Case A in which ExtractBody returns the full body, including both rules.

Activity

  1. matt-edmondson commented on Sep 27, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions