115 lines
3.3 KiB
Python
115 lines
3.3 KiB
Python
from functools import cache
|
|
from pathlib import Path
|
|
from typing import Any, Iterable, Iterator
|
|
|
|
from markdown import Markdown
|
|
from yaml import Loader, load
|
|
|
|
|
|
class Content:
|
|
current_language: str | None = None
|
|
|
|
def __init__(self, path: Path) -> None:
|
|
self.__path = path
|
|
|
|
@property
|
|
def path(self) -> Path:
|
|
return self.__path
|
|
|
|
|
|
class ContentDirectory(Content):
|
|
def load(self, subpath: str | Path) -> Content:
|
|
subpath = Path(subpath)
|
|
current: Content = self
|
|
for part in subpath.parts:
|
|
if not isinstance(current, ContentDirectory):
|
|
raise NotADirectoryError(self.path)
|
|
|
|
current = current.__load_children(part)
|
|
|
|
return current
|
|
|
|
def glob(self, pattern: str) -> Iterable[Content]:
|
|
for item in self.path.glob(pattern):
|
|
yield self.load(str(item.relative_to(self.path)))
|
|
|
|
def __load_children(self, name: str) -> Content:
|
|
child_path = self.__get_localized_path(self.path / name)
|
|
return self.__load_path(child_path)
|
|
|
|
@cache # noqa: B019
|
|
def __load_path(self, child_path: Path) -> Content:
|
|
if not child_path.exists():
|
|
raise FileNotFoundError(child_path)
|
|
|
|
if child_path.is_dir():
|
|
return ContentDirectory(child_path)
|
|
|
|
if child_path.is_file():
|
|
if child_path.suffix in [".yml", ".yaml", ".json"]:
|
|
return DataFile(child_path)
|
|
if child_path.suffix == ".md":
|
|
return MarkdownFile(child_path)
|
|
|
|
raise NotImplementedError()
|
|
|
|
@staticmethod
|
|
def __get_localized_path(path: Path) -> Path:
|
|
if Content.current_language is None:
|
|
return path
|
|
localized_path = path.with_name(f"{path.stem}-{Content.current_language}{path.suffix}")
|
|
print(localized_path)
|
|
if not localized_path.exists():
|
|
return path
|
|
|
|
return localized_path
|
|
|
|
|
|
class DataField:
|
|
def __init__(self, file_path: Path, value: Any) -> None:
|
|
self.__file_path = file_path
|
|
self.__value = value
|
|
|
|
def as_path(self) -> Path:
|
|
return self.__file_path.parent / str(self.__value)
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.__value)
|
|
|
|
def __getitem__(self, key: Any) -> Any:
|
|
return DataField(self.__file_path, self.__value.get(key))
|
|
|
|
def __iter__(self) -> Iterator[Any]:
|
|
for it in self.__value:
|
|
yield DataField(self.__file_path, it)
|
|
|
|
|
|
class DataFile(Content):
|
|
def __init__(self, path: Path) -> None:
|
|
super().__init__(path)
|
|
with path.open("r", encoding="utf-8") as data_file:
|
|
self.__data = load(data_file, Loader)
|
|
|
|
def __getitem__(self, key: Any) -> Any:
|
|
return DataField(self.path, self.__data.get(key))
|
|
|
|
def __iter__(self) -> Iterator[Any]:
|
|
for it in self.__data:
|
|
yield DataField(self.path, it)
|
|
|
|
|
|
class MarkdownFile(Content):
|
|
def __init__(self, path: Path) -> None:
|
|
super().__init__(path)
|
|
with path.open("r", encoding="utf-8") as markdown_file:
|
|
self.__markdown = Markdown(extensions=["full_yaml_metadata"])
|
|
self.__html = self.__markdown.convert(markdown_file.read())
|
|
|
|
@property
|
|
def html(self) -> str:
|
|
return self.__html
|
|
|
|
@property
|
|
def meta(self) -> Any:
|
|
return DataField(self.path, self.__markdown.Meta) # type: ignore
|