from __future__ import annotations from pathlib import Path from typing import Dict, Iterable, List import glob from docforge.nav.spec import NavSpec class ResolvedNav: def __init__( self, home: str | None, groups: Dict[str, List[Path]], docs_root: Path | None = None, ) -> None: self.home = home self.groups = groups self._docs_root = docs_root def all_files(self) -> Iterable[Path]: if self.home: if self._docs_root is None: raise RuntimeError("docs_root is required to resolve home path") yield self._docs_root / self.home for paths in self.groups.values(): for p in paths: yield p def resolve_nav( spec: NavSpec, docs_root: Path, ) -> ResolvedNav: if not docs_root.exists(): raise FileNotFoundError(docs_root) def resolve_pattern(pattern: str) -> List[Path]: full = docs_root / pattern matches = sorted( Path(p) for p in glob.glob(str(full), recursive=True) ) if not matches: raise FileNotFoundError(pattern) return matches # Resolve home home: str | None = None if spec.home: home_path = docs_root / spec.home if not home_path.exists(): raise FileNotFoundError(spec.home) home = spec.home # Resolve groups resolved_groups: Dict[str, List[Path]] = {} for group, patterns in spec.groups.items(): files: List[Path] = [] for pattern in patterns: files.extend(resolve_pattern(pattern)) resolved_groups[group] = files return ResolvedNav( home=home, groups=resolved_groups, docs_root=docs_root, )