From 583d5e7c514bdeabeadcb5aa9b6b4c6edb2bb996 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 3 May 2026 00:15:25 +0800 Subject: [PATCH] feat(website): assert unique slugs across categories and groups Categories and groups will share the /categories/ URL namespace. Fail the build with a clear error message if a future README change introduces a collision. Co-Authored-By: Claude Opus 4.7 (1M context) --- website/build.py | 9 +++++++++ website/tests/test_build.py | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/website/build.py b/website/build.py index e030da37..0583a464 100644 --- a/website/build.py +++ b/website/build.py @@ -277,6 +277,15 @@ def build(repo_root: Path) -> None: sponsors = parse_sponsors(readme_text) categories = [cat for g in parsed_groups for cat in g["categories"]] + cat_slugs = [cat["slug"] for cat in categories] + group_slugs = [g["slug"] for g in parsed_groups] + all_top_level_slugs = cat_slugs + group_slugs + duplicates = {s for s in all_top_level_slugs if all_top_level_slugs.count(s) > 1} + if duplicates: + raise ValueError( + f"slug collision in /categories/ namespace: {sorted(duplicates)}. " + "Rename a category or group so their slugs differ." + ) total_entries = sum(c["entry_count"] for c in categories) entries = extract_entries(categories, parsed_groups) build_date = datetime.now(UTC) diff --git a/website/tests/test_build.py b/website/tests/test_build.py index 0f666fb4..f64d44a1 100644 --- a/website/tests/test_build.py +++ b/website/tests/test_build.py @@ -484,6 +484,27 @@ class TestBuild: # Expand content present assert "expand-content" in html + def test_build_fails_when_group_and_category_slug_collide(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + --- + + **Widgets** + + ## Widgets + + - [w1](https://example.com) - W. + + # Contributing + + Done. + """) + self._make_repo(tmp_path, readme) + import pytest + with pytest.raises(ValueError, match="slug collision"): + build(tmp_path) + def test_index_contains_aligned_homepage_metadata(self, tmp_path): readme = (Path(__file__).parents[2] / "README.md").read_text(encoding="utf-8") (tmp_path / "README.md").write_text(readme, encoding="utf-8")