]> danix's work - publisher.git/commitdiff
feat: article scanner with translation pair detection
authorDanilo M. <redacted>
Sun, 3 May 2026 08:01:57 +0000 (10:01 +0200)
committerDanilo M. <redacted>
Sun, 3 May 2026 08:01:57 +0000 (10:01 +0200)
core/article_scanner.py [new file with mode: 0644]
tests/test_article_scanner.py [new file with mode: 0644]

diff --git a/core/article_scanner.py b/core/article_scanner.py
new file mode 100644 (file)
index 0000000..ea6579a
--- /dev/null
@@ -0,0 +1,34 @@
+from __future__ import annotations
+from pathlib import Path
+from core.models import Article
+from core.frontmatter import parse_frontmatter
+
+def scan_articles(blog_root: Path) -> list[Article]:
+    articles: list[Article] = []
+    by_slug: dict[tuple[str, str], Path] = {}
+
+    for lang in ("it", "en"):
+        content_dir = blog_root / "content" / lang / "articles"
+        if not content_dir.exists():
+            continue
+        for index_md in sorted(content_dir.glob("*/index.md")):
+            slug = index_md.parent.name
+            by_slug[(lang, slug)] = index_md
+
+    for (lang, slug), path in by_slug.items():
+        other_lang = "en" if lang == "it" else "it"
+        translation_path = by_slug.get((other_lang, slug))
+        try:
+            fm, _ = parse_frontmatter(path)
+        except (ValueError, Exception):
+            fm = {}
+        articles.append(Article(
+            slug=slug,
+            lang=lang,
+            path=path,
+            frontmatter=fm,
+            has_translation=translation_path is not None,
+            translation_path=translation_path,
+        ))
+
+    return articles
diff --git a/tests/test_article_scanner.py b/tests/test_article_scanner.py
new file mode 100644 (file)
index 0000000..66daf83
--- /dev/null
@@ -0,0 +1,41 @@
+# tests/test_article_scanner.py
+from pathlib import Path
+from core.article_scanner import scan_articles
+
+def _make_article(base: Path, lang: str, slug: str, fm_extra: str = "") -> Path:
+    p = base / "content" / lang / "articles" / slug
+    p.mkdir(parents=True)
+    (p / "index.md").write_text(f"+++\ntitle = \"{slug}\"\ntype = \"Tech\"\n{fm_extra}+++\n\nBody.\n")
+    return p / "index.md"
+
+def test_scan_finds_articles(tmp_path):
+    _make_article(tmp_path, "it", "primo-post")
+    _make_article(tmp_path, "en", "first-post")
+    articles = scan_articles(tmp_path)
+    slugs = [a.slug for a in articles]
+    assert "primo-post" in slugs
+    assert "first-post" in slugs
+
+def test_scan_detects_translation_pair(tmp_path):
+    _make_article(tmp_path, "it", "shared-slug")
+    _make_article(tmp_path, "en", "shared-slug")
+    articles = scan_articles(tmp_path)
+    it_art = next(a for a in articles if a.lang == "it" and a.slug == "shared-slug")
+    en_art = next(a for a in articles if a.lang == "en" and a.slug == "shared-slug")
+    assert it_art.has_translation is True
+    assert it_art.translation_path == en_art.path
+    assert en_art.has_translation is True
+
+def test_scan_detects_missing_translation(tmp_path):
+    _make_article(tmp_path, "it", "solo-italiano")
+    articles = scan_articles(tmp_path)
+    art = next(a for a in articles if a.slug == "solo-italiano")
+    assert art.has_translation is False
+    assert art.translation_path is None
+
+def test_scan_parses_frontmatter(tmp_path):
+    _make_article(tmp_path, "it", "con-fm", 'tags = ["linux"]\n')
+    articles = scan_articles(tmp_path)
+    art = next(a for a in articles if a.slug == "con-fm")
+    assert art.frontmatter["title"] == "con-fm"
+    assert "linux" in art.frontmatter["tags"]