Initial commit
This commit is contained in:
80
skills/debate-orchestrator/debate_ops/frontmatter.py
Normal file
80
skills/debate-orchestrator/debate_ops/frontmatter.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""JSON frontmatter parsing - zero dependencies."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class Document:
|
||||
metadata: dict[str, Any]
|
||||
content: str
|
||||
|
||||
def __getitem__(self, key: str) -> Any:
|
||||
return self.metadata[key]
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return self.metadata.get(key, default)
|
||||
|
||||
|
||||
def _find_json_end(text: str) -> int:
|
||||
depth = in_string = escape_next = 0
|
||||
for i, char in enumerate(text):
|
||||
if escape_next:
|
||||
escape_next = 0
|
||||
continue
|
||||
if char == '\\':
|
||||
escape_next = 1
|
||||
continue
|
||||
if char == '"' and not escape_next:
|
||||
in_string = not in_string
|
||||
continue
|
||||
if in_string:
|
||||
continue
|
||||
if char == '{':
|
||||
depth += 1
|
||||
elif char == '}':
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return i + 1
|
||||
return -1
|
||||
|
||||
|
||||
def parse(text: str) -> Document:
|
||||
text = text.lstrip()
|
||||
if not text.startswith('{'):
|
||||
raise ValueError("JSON frontmatter must start with '{'")
|
||||
|
||||
end_pos = _find_json_end(text)
|
||||
if end_pos == -1:
|
||||
raise ValueError("JSON frontmatter not properly closed")
|
||||
|
||||
try:
|
||||
metadata = json.loads(text[:end_pos])
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON in frontmatter: {e}")
|
||||
|
||||
if not isinstance(metadata, dict):
|
||||
raise ValueError("JSON frontmatter must be object")
|
||||
|
||||
return Document(metadata=metadata, content=text[end_pos:].lstrip('\n'))
|
||||
|
||||
|
||||
def dumps(metadata: dict[str, Any], content: str) -> str:
|
||||
return f"{json.dumps(metadata, indent=2)}\n\n{content}"
|
||||
|
||||
|
||||
def load(filepath: Path | str) -> Document:
|
||||
return parse(Path(filepath).read_text())
|
||||
|
||||
|
||||
def dump(doc: Document, filepath: Path | str) -> None:
|
||||
Path(filepath).write_text(dumps(doc.metadata, doc.content))
|
||||
|
||||
|
||||
def update_metadata(filepath: Path | str, **updates: Any) -> None:
|
||||
doc = load(filepath)
|
||||
doc.metadata.update(updates)
|
||||
dump(doc, filepath)
|
||||
Reference in New Issue
Block a user