From: Danilo M. Date: Fri, 1 May 2026 10:51:54 +0000 (+0200) Subject: feat: TOML frontmatter parse/write with tomlkit X-Git-Tag: v1.0~28 X-Git-Url: https://git.danix.xyz/?a=commitdiff_plain;h=b4d3b526e232804e06b84d93628244cecd035df5;p=publisher.git feat: TOML frontmatter parse/write with tomlkit --- diff --git a/core/frontmatter.py b/core/frontmatter.py new file mode 100644 index 0000000..4e9eff3 --- /dev/null +++ b/core/frontmatter.py @@ -0,0 +1,28 @@ +from __future__ import annotations +from pathlib import Path +import tomlkit + +def parse_frontmatter(path: Path) -> tuple[dict, str]: + """Parse TOML frontmatter delimited by +++. Returns (frontmatter_dict, body_str).""" + text = path.read_text(encoding="utf-8") + if not text.startswith("+++"): + raise ValueError(f"No TOML frontmatter found in {path}") + parts = text.split("+++", 2) + if len(parts) < 3: + raise ValueError(f"Malformed frontmatter in {path}") + _, toml_block, body = parts + fm = dict(tomlkit.loads(toml_block)) + return fm, body.lstrip("\n") + +def write_frontmatter(path: Path, frontmatter: dict, body: str) -> None: + """Write frontmatter + body back to file, preserving TOML format.""" + text = path.read_text(encoding="utf-8") + parts = text.split("+++", 2) + if len(parts) < 3: + raise ValueError(f"Malformed frontmatter in {path}") + _, original_toml, _ = parts + doc = tomlkit.loads(original_toml) + for k, v in frontmatter.items(): + doc[k] = v + new_text = f"+++\n{tomlkit.dumps(doc)}+++\n\n{body}" + path.write_text(new_text, encoding="utf-8") diff --git a/tests/test_frontmatter.py b/tests/test_frontmatter.py new file mode 100644 index 0000000..2257a8a --- /dev/null +++ b/tests/test_frontmatter.py @@ -0,0 +1,49 @@ +import pytest +from pathlib import Path +import tempfile +from core.frontmatter import parse_frontmatter, write_frontmatter + +SAMPLE_MD = """\ ++++ +title = "Test Article" +type = "Tech" +draft = false +tags = ["linux", "python"] ++++ + +# Body + +Some content here. +""" + +def test_parse_returns_frontmatter_dict(tmp_path): + f = tmp_path / "index.md" + f.write_text(SAMPLE_MD) + fm, body = parse_frontmatter(f) + assert fm["title"] == "Test Article" + assert fm["type"] == "Tech" + assert fm["draft"] is False + assert "linux" in fm["tags"] + +def test_parse_returns_body(tmp_path): + f = tmp_path / "index.md" + f.write_text(SAMPLE_MD) + fm, body = parse_frontmatter(f) + assert "# Body" in body + assert "Some content here." in body + +def test_write_preserves_format(tmp_path): + f = tmp_path / "index.md" + f.write_text(SAMPLE_MD) + fm, body = parse_frontmatter(f) + fm["title"] = "Updated Title" + write_frontmatter(f, fm, body) + fm2, _ = parse_frontmatter(f) + assert fm2["title"] == "Updated Title" + assert fm2["type"] == "Tech" + +def test_parse_raises_on_missing_delimiters(tmp_path): + f = tmp_path / "index.md" + f.write_text("# No frontmatter\n\nJust body.") + with pytest.raises(ValueError, match="frontmatter"): + parse_frontmatter(f)