]> danix's work - publisher.git/commitdiff
feat: TOML frontmatter parse/write with tomlkit
authorDanilo M. <redacted>
Fri, 1 May 2026 10:51:54 +0000 (12:51 +0200)
committerDanilo M. <redacted>
Fri, 1 May 2026 10:51:54 +0000 (12:51 +0200)
core/frontmatter.py [new file with mode: 0644]
tests/test_frontmatter.py [new file with mode: 0644]

diff --git a/core/frontmatter.py b/core/frontmatter.py
new file mode 100644 (file)
index 0000000..4e9eff3
--- /dev/null
@@ -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 (file)
index 0000000..2257a8a
--- /dev/null
@@ -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)