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:
@@ -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:
|
||||||
|
|||||||
29
tests/fixtures/frontmatter_test_files/toml_frontmatter.md
vendored
Normal file
29
tests/fixtures/frontmatter_test_files/toml_frontmatter.md
vendored
Normal 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.
|
||||||
Reference in New Issue
Block a user