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 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:
|
||||
|
||||
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