relative link resolution working

This commit is contained in:
Daniel Fichtinger 2025-06-22 14:02:16 -04:00
parent 2c4de0b72d
commit 3b9a653e34
4 changed files with 43 additions and 17 deletions

View file

@ -1,5 +1,5 @@
from rich import print
from zona.models import Item, Metadata, ItemType
from zona.models import Item, Metadata, ItemType, BuildCtx
from zona import markdown as zmd
from zona.templates import Templater
from zona import util
@ -82,17 +82,23 @@ def discover(root: Path, out_dir: Path) -> list[Item]:
def build(root: Path, items: list[Item]):
ctx = BuildCtx(root=root)
templater = Templater(root / "templates")
item_map = {item.source.resolve(): item for item in items}
ctx.item_map = {item.source.resolve(): item for item in items}
# print(item_map)
for item in item_map.values():
for item in ctx.item_map.values():
dst = item.destination
# print(item)
# create parent dirs if needed
if item.type == ItemType.MARKDOWN:
assert item.content is not None
# parse markdown and render as html
raw_html = zmd.md_to_html(item.content)
raw_html = zmd.md_to_html(
content=item.content,
resolve_links=True,
source=item.source,
ctx=ctx,
)
# TODO: test this
rendered = templater.render_item(item, raw_html)
util.ensure_parents(dst)

View file

@ -1,11 +1,12 @@
from rich import print
from typing import Any, override
from pathlib import Path
from marko import Markdown
from marko.inline import Link, Image
from marko.html_renderer import HTMLRenderer
from marko.parser import Parser
from zona.models import Item
from zona.models import BuildCtx, Item
from zona import util
class ZonaRenderer(HTMLRenderer):
@ -13,28 +14,31 @@ class ZonaRenderer(HTMLRenderer):
self,
resolve: bool = False,
source: Path | None = None,
item_map: dict[Path, Item] | None = None,
ctx: BuildCtx | None = None,
):
# print("Zona renderer initializing...")
super().__init__()
self.resolve: bool = resolve
if self.resolve:
# print("Resolve is set")
assert source is not None
assert item_map is not None
assert ctx is not None
self.source: Path = source.resolve()
self.map: dict[Path, Item] = item_map
self.ctx: BuildCtx = ctx
# TODO: resolve relative links and replace with url?
@override
def render_link(self, element: Link):
href = element.dest
print(f"Rendering link, original: {href}")
assert isinstance(href, str)
if self.resolve:
cur = Path(href)
# TODO: fix relative path issue
if not href.startswith(("http", "https")) and cur.is_relative_to(
self.source
):
href = self.map[self.source].url
_href = href
resolved = (self.source.parent / cur).resolve()
if resolved.exists():
href = util.normalize_url(self.ctx.item_map[resolved].url)
print(f"Link in file {self.source}: {_href} resolved to {href}")
body: Any = self.render_children(element)
return f'<a href="{href}" target="_blank">{body}</a>'
@ -56,9 +60,13 @@ def md_to_html(
content: str,
resolve_links: bool = False,
source: Path | None = None,
item_map: dict[Path, Item] | None = None,
ctx: BuildCtx | None = None,
) -> str:
if resolve_links and (source is None or ctx is None):
raise TypeError(
"md_to_html() missing source and ctx when resolve_links is true"
)
parser = Parser()
ast = parser.parse(content)
renderer = ZonaRenderer(resolve_links, source, item_map)
renderer = ZonaRenderer(resolve_links, source, ctx)
return renderer.render(ast)

View file

@ -1,7 +1,7 @@
from pathlib import Path
from enum import Enum
from datetime import date
from dataclasses import dataclass
from dataclasses import dataclass, field
@dataclass
@ -30,3 +30,9 @@ class Item:
content: str | None = None
type: ItemType | None = None
copy: bool = True
@dataclass
class BuildCtx:
root: Path
item_map: dict[Path, Item] = field(default_factory=dict)

View file

@ -18,3 +18,9 @@ def filename_to_title(path: Path) -> str:
name = path.stem
words = name.replace("-", " ").replace("_", " ")
return string.capwords(words)
def normalize_url(url: str) -> str:
if not url.startswith("/"):
url = "/" + url
return url