From cde2805078f243d4e075e40935878a0e9b8a3c8a Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 2 Oct 2025 09:32:16 +0200 Subject: [PATCH] feat: Complete Issue #41 - Add TOML frontmatter support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enhanced frontmatter parser to detect and parse TOML format - Added TOML format detection heuristics before YAML parsing - Created TOML test fixture with nested sections - Fixed parsing order to prevent TOML-to-string conversion - All frontmatter formats (YAML, JSON, TOML) now fully supported - Validated all acceptance criteria for Issue #41 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- markitect/matter_frontmatter/parser.py | 40 +++++++++++++------ .../toml_frontmatter.md | 29 ++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 tests/fixtures/frontmatter_test_files/toml_frontmatter.md diff --git a/markitect/matter_frontmatter/parser.py b/markitect/matter_frontmatter/parser.py index a8b4e197..47c10ebf 100644 --- a/markitect/matter_frontmatter/parser.py +++ b/markitect/matter_frontmatter/parser.py @@ -5,6 +5,7 @@ Frontmatter parser for extracting and manipulating YAML/JSON/TOML frontmatter. import re import yaml import json +import toml from typing import Dict, Any, List, Optional from .stats import FrontmatterStats @@ -27,20 +28,32 @@ class FrontmatterParser: if not frontmatter_content: return {} - # Try to parse as YAML first (most common) + # Try to detect format first for better parsing + content = frontmatter_content.strip() + + # Try TOML first if it looks like TOML + if '=' in content and ('[' in content or '"' in content): + try: + return toml.loads(frontmatter_content) + except toml.TomlDecodeError: + pass + + # Try JSON if it looks like JSON + if content.startswith('{') and content.endswith('}'): + try: + return json.loads(frontmatter_content) + except json.JSONDecodeError: + pass + + # Default to YAML (most common) try: - return yaml.safe_load(frontmatter_content) or {} + result = yaml.safe_load(frontmatter_content) + # Ensure we got a dictionary, not a string + if isinstance(result, dict): + return result except yaml.YAMLError: pass - # Try to parse as JSON - try: - return json.loads(frontmatter_content) - except json.JSONDecodeError: - pass - - # TODO: Add TOML support in future iterations - return {} def set_frontmatter_value(self, text: str, key: str, value: Any) -> str: @@ -118,7 +131,7 @@ class FrontmatterParser: """ frontmatter = self.extract_frontmatter(text) - if not frontmatter: + if not frontmatter or not isinstance(frontmatter, dict): return FrontmatterStats( has_frontmatter=False, total_fields=0, @@ -166,8 +179,11 @@ class FrontmatterParser: content = content.strip() if content.startswith('{') and content.endswith('}'): return "json" + elif '=' in content and '[' in content: + # Simple heuristic for TOML + return "toml" else: - # Default to YAML for now + # Default to YAML return "yaml" def _set_nested_value(self, data: Dict[str, Any], key: str, value: Any) -> None: diff --git a/tests/fixtures/frontmatter_test_files/toml_frontmatter.md b/tests/fixtures/frontmatter_test_files/toml_frontmatter.md new file mode 100644 index 00000000..7442fba6 --- /dev/null +++ b/tests/fixtures/frontmatter_test_files/toml_frontmatter.md @@ -0,0 +1,29 @@ +--- +title = "TOML Frontmatter Test Document" +author = "Test Author" +date = "2025-10-02" +tags = ["toml", "frontmatter", "testing"] +version = 1.4 +published = true + +[config] +theme = "light" +language = "en" +debug = false + +[features] +search = true +toc = true +navigation = true +--- + +# TOML Frontmatter Test Document + +This document uses TOML format for frontmatter instead of YAML or JSON. + +The frontmatter parser should handle TOML format correctly and extract values like: +- title: "TOML Frontmatter Test Document" +- config.theme: "light" +- features.search: true + +This tests the parser's ability to handle all three frontmatter formats as required by Issue #41. \ No newline at end of file