file loading

This commit is contained in:
John Lancaster
2026-06-21 10:06:25 -05:00
parent dab539489a
commit 993dc6a879
+30 -20
View File
@@ -1,10 +1,33 @@
from collections.abc import Generator from collections.abc import Generator
from dataclasses import dataclass
from importlib.abc import Traversable from importlib.abc import Traversable
from itertools import starmap
from pathlib import PurePosixPath from pathlib import PurePosixPath
from typing import Self
import yaml
from .models.skill import SkillFrontmatter @dataclass(frozen=True, slots=True)
class LoadedMarkdownDocument:
"""Represents a loaded markdown document with its content and frontmatter."""
relpath: PurePosixPath
"""The relative path of the document within the package resources."""
content: str
"""The raw markdown content of the document."""
frontmatter: str
"""The raw YAML frontmatter of the document, if present."""
@classmethod
def from_root(cls, root: Traversable) -> set[Self]:
"""Recursively load all markdown documents from the root resource."""
return set(starmap(cls.from_resource, walk_resources(root)))
@classmethod
def from_resource(cls, relpath: PurePosixPath, resource: Traversable) -> Self:
"""Load a markdown document from a package resource."""
raw = resource.read_text(encoding="utf-8")
frontmatter = get_raw_frontmatter(raw)
return cls(relpath=relpath, content=raw, frontmatter=frontmatter)
def walk_resources( def walk_resources(
@@ -25,27 +48,14 @@ def walk_resources(
yield relpath.as_posix(), child yield relpath.as_posix(), child
def get_markdown_content(resource: Traversable) -> dict[str, str]:
"""Read the content of a markdown resource as text."""
return {relpath: doc_file.read_text(encoding="utf-8") for relpath, doc_file in walk_resources(resource)}
def get_idx(raw):
for i, line in enumerate(raw.splitlines()):
if line.strip().startswith("---"):
yield i
def get_raw_frontmatter(raw: str) -> str: def get_raw_frontmatter(raw: str) -> str:
delimiter = iter(get_idx(raw)) delimiter = iter(get_frontmatter_delim_idx(raw, delimiter="---"))
start = next(delimiter) + 1 start = next(delimiter) + 1
end = next(delimiter) end = next(delimiter)
return "\n".join(raw.splitlines()[start:end]) return "\n".join(raw.splitlines()[start:end])
def gen_valid_frontmatter(content: dict[str, str]) -> Generator[SkillFrontmatter]: def get_frontmatter_delim_idx(raw: str, *, delimiter: str = "---") -> Generator[int]:
for relpath, raw in content.items(): for i, line in enumerate(raw.splitlines()):
if relpath.endswith("SKILL.md"): if line.strip().startswith(delimiter):
fm = get_raw_frontmatter(raw) yield i
validated = SkillFrontmatter.model_validate(yaml.safe_load(fm))
yield validated