feat: Complete Issue #41 - Add TOML frontmatter support

- 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 <noreply@anthropic.com>
This commit is contained in:
2025-10-02 09:32:16 +02:00
parent 494e1b7128
commit cde2805078
2 changed files with 57 additions and 12 deletions

View File

@@ -5,6 +5,7 @@ Frontmatter parser for extracting and manipulating YAML/JSON/TOML frontmatter.
import re import re
import yaml import yaml
import json import json
import toml
from typing import Dict, Any, List, Optional from typing import Dict, Any, List, Optional
from .stats import FrontmatterStats from .stats import FrontmatterStats
@@ -27,20 +28,32 @@ class FrontmatterParser:
if not frontmatter_content: if not frontmatter_content:
return {} 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: 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: except yaml.YAMLError:
pass pass
# Try to parse as JSON
try:
return json.loads(frontmatter_content)
except json.JSONDecodeError:
pass
# TODO: Add TOML support in future iterations
return {} return {}
def set_frontmatter_value(self, text: str, key: str, value: Any) -> str: def set_frontmatter_value(self, text: str, key: str, value: Any) -> str:
@@ -118,7 +131,7 @@ class FrontmatterParser:
""" """
frontmatter = self.extract_frontmatter(text) frontmatter = self.extract_frontmatter(text)
if not frontmatter: if not frontmatter or not isinstance(frontmatter, dict):
return FrontmatterStats( return FrontmatterStats(
has_frontmatter=False, has_frontmatter=False,
total_fields=0, total_fields=0,
@@ -166,8 +179,11 @@ class FrontmatterParser:
content = content.strip() content = content.strip()
if content.startswith('{') and content.endswith('}'): if content.startswith('{') and content.endswith('}'):
return "json" return "json"
elif '=' in content and '[' in content:
# Simple heuristic for TOML
return "toml"
else: else:
# Default to YAML for now # Default to YAML
return "yaml" return "yaml"
def _set_nested_value(self, data: Dict[str, Any], key: str, value: Any) -> None: def _set_nested_value(self, data: Dict[str, Any], key: str, value: Any) -> None:

View File

@@ -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.