Skip to content
13 changes: 10 additions & 3 deletions mdit_py_plugins/front_matter/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,19 @@ def _front_matter_rule(
# unclosed block should be autoclosed by end of document.
return False

if state.src[start:maximum] == "...":
break

start = state.bMarks[nextLine] + state.tShift[nextLine]
maximum = state.eMarks[nextLine]

if (
state.sCount[nextLine] == 0
and state.src.startswith("...", start)
and state.skipSpaces(start + 3) >= maximum
):
# YAML document-end marker: `...` at column 0, trailing spaces allowed.
# It is checked on the current line and consumed, so it is not content.
auto_closed = True
break

if start < maximum and state.sCount[nextLine] < state.blkIndent:
# non-empty line with negative indent should stop the list:
# - ```
Expand Down
55 changes: 55 additions & 0 deletions tests/fixtures/front_matter.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,61 @@ x: 1
<h1>Head</h1>
.

should parse triple dots at end of document:
.
---
x: 1
...
.
.

should ignore spaces after triple dots:
.
---
x: 1
...
# Head
.

<h1>Head</h1>
.

should not close on indented triple dots:
.
---
text: |
...
---
# Head
.

<h1>Head</h1>
.

should not close on four dots:
.
---
x: 1
....
---
# Head
.

<h1>Head</h1>
.

should not close on triple dots followed by text:
.
---
x: 1
...x
---
# Head
.

<h1>Head</h1>
.

should parse front matter with indentation:
.
---
Expand Down
24 changes: 24 additions & 0 deletions tests/test_front_matter.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ def test_token():
]


@pytest.mark.parametrize("closer", ["---", "...", "... "])
def test_token_content_excludes_the_closer(closer):
"""The closing marker must not be left inside the extracted content.

``...`` is the YAML document-end marker and is exercised by the fixture file,
so it has to be consumed like the dashed form rather than kept in the block.
"""
md = MarkdownIt("commonmark").use(front_matter_plugin)
tokens = md.parse(f"---\na: 1\n{closer}")
assert [token.type for token in tokens] == ["front_matter"]
assert tokens[0].content == "a: 1"


def test_dots_closer_on_the_last_line():
"""A block closed by ``...`` on the final line is still front matter.

``test_all`` cannot see this: the front_matter token is hidden, so only the
rendered output is asserted, and a block that is dropped rather than closed
renders as visible text instead of disappearing.
"""
md = MarkdownIt("commonmark").use(front_matter_plugin)
assert md.render("---\na: 1\n...\n") == md.render("---\na: 1\n---\n") == ""


def test_short_source():
md = MarkdownIt("commonmark").use(front_matter_plugin)

Expand Down
Loading