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