mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-06 13:15:45 +08:00
89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
"""Parse zensical.toml nav structure into a flat list of doc entries.
|
|
|
|
Reads the nav tree from zensical.toml and produces a flat list of
|
|
{title, path, breadcrumb} dicts suitable for the sync orchestrator.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tomllib
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
SKIP_FILES = frozenset({"index.md", "README.md"})
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class NavEntry:
|
|
"""A single navigable documentation page."""
|
|
|
|
title: str
|
|
path: str
|
|
breadcrumb: tuple[str, ...] = field(default_factory=tuple)
|
|
|
|
|
|
def parse(config_path: str | Path) -> list[NavEntry]:
|
|
"""Parse zensical.toml and return all nav entries.
|
|
|
|
Args:
|
|
config_path: Path to zensical.toml.
|
|
|
|
Returns:
|
|
Flat list of NavEntry for every page in the nav tree,
|
|
excluding index.md, README.md, and external links.
|
|
"""
|
|
config_path = Path(config_path)
|
|
with config_path.open("rb") as f:
|
|
config = tomllib.load(f)
|
|
|
|
nav = config.get("project", {}).get("nav", [])
|
|
entries = _flatten_nav(nav)
|
|
return [e for e in entries if Path(e.path).name not in SKIP_FILES]
|
|
|
|
|
|
def parse_all(config_path: str | Path) -> list[NavEntry]:
|
|
"""Like parse(), but includes index.md and README.md entries."""
|
|
config_path = Path(config_path)
|
|
with config_path.open("rb") as f:
|
|
config = tomllib.load(f)
|
|
|
|
nav = config.get("project", {}).get("nav", [])
|
|
return _flatten_nav(nav)
|
|
|
|
|
|
def _flatten_nav(
|
|
items: list[dict[str, str | list] | str],
|
|
breadcrumb: tuple[str, ...] = (),
|
|
) -> list[NavEntry]:
|
|
"""Recursively flatten the nav tree into NavEntry objects."""
|
|
result: list[NavEntry] = []
|
|
|
|
for item in items:
|
|
if isinstance(item, dict):
|
|
for title, value in item.items():
|
|
if isinstance(value, str):
|
|
# Skip external links
|
|
if value.startswith("http"):
|
|
continue
|
|
result.append(NavEntry(
|
|
title=title,
|
|
path=value,
|
|
breadcrumb=breadcrumb + (title,),
|
|
))
|
|
elif isinstance(value, list):
|
|
result.extend(
|
|
_flatten_nav(value, breadcrumb + (title,))
|
|
)
|
|
elif isinstance(item, str):
|
|
# Bare path without title
|
|
if item.startswith("http"):
|
|
continue
|
|
name = Path(item).stem.replace("-", " ").capitalize()
|
|
result.append(NavEntry(
|
|
title=name,
|
|
path=item,
|
|
breadcrumb=breadcrumb + (name,),
|
|
))
|
|
|
|
return result
|