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 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 import markdown as zmd
from zona.templates import Templater from zona.templates import Templater
from zona import util from zona import util
@ -82,17 +82,23 @@ def discover(root: Path, out_dir: Path) -> list[Item]:
def build(root: Path, items: list[Item]): def build(root: Path, items: list[Item]):
ctx = BuildCtx(root=root)
templater = Templater(root / "templates") 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) # print(item_map)
for item in item_map.values(): for item in ctx.item_map.values():
dst = item.destination dst = item.destination
# print(item) # print(item)
# create parent dirs if needed # create parent dirs if needed
if item.type == ItemType.MARKDOWN: if item.type == ItemType.MARKDOWN:
assert item.content is not None assert item.content is not None
# parse markdown and render as html # 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 # TODO: test this
rendered = templater.render_item(item, raw_html) rendered = templater.render_item(item, raw_html)
util.ensure_parents(dst) util.ensure_parents(dst)

View file

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

View file

@ -1,7 +1,7 @@
from pathlib import Path from pathlib import Path
from enum import Enum from enum import Enum
from datetime import date from datetime import date
from dataclasses import dataclass from dataclasses import dataclass, field
@dataclass @dataclass
@ -30,3 +30,9 @@ class Item:
content: str | None = None content: str | None = None
type: ItemType | None = None type: ItemType | None = None
copy: bool = True 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 name = path.stem
words = name.replace("-", " ").replace("_", " ") words = name.replace("-", " ").replace("_", " ")
return string.capwords(words) return string.capwords(words)
def normalize_url(url: str) -> str:
if not url.startswith("/"):
url = "/" + url
return url