refactor: parse thematic groups from README bold markers instead of hardcoding them

The website builder previously relied on a hardcoded SECTION_GROUPS list in
build.py to organize categories into thematic groups. This was fragile: any
rename or addition to README.md required a matching code change.

Replace this with a parser-driven approach:
- readme_parser.py now detects bold-only paragraphs (**Group Name**) as
  group boundary markers and groups H2 categories beneath them into
  ParsedGroup structs.
- build.py drops SECTION_GROUPS entirely; group_categories() now just
  passes parsed groups through and appends the Resources group.
- sort.py is removed as it relied on the old flat section model.
- Tests updated throughout to reflect the new (groups, resources) return
  shape and to cover the new grouping logic.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vinta Chen
2026-03-20 18:43:09 +08:00
parent fd9b2665ed
commit 4322026817
5 changed files with 346 additions and 324 deletions

View File

@@ -48,28 +48,33 @@ class TestSlugify:
class TestGroupCategories:
def test_groups_known_categories(self):
cats = [
{"name": "Web Frameworks", "slug": "web-frameworks"},
{"name": "Testing", "slug": "testing"},
def test_appends_resources(self):
parsed_groups = [
{"name": "G1", "slug": "g1", "categories": [{"name": "Cat1"}]},
]
groups = group_categories(cats, [])
group_names = [g["name"] for g in groups]
assert "Web & API" in group_names
assert "Development Tools" in group_names
def test_ungrouped_go_to_other(self):
cats = [{"name": "Unknown Category", "slug": "unknown-category"}]
groups = group_categories(cats, [])
group_names = [g["name"] for g in groups]
assert "Other" in group_names
def test_resources_grouped(self):
resources = [{"name": "Newsletters", "slug": "newsletters"}]
groups = group_categories([], resources)
groups = group_categories(parsed_groups, resources)
group_names = [g["name"] for g in groups]
assert "G1" in group_names
assert "Resources" in group_names
def test_no_resources_no_extra_group(self):
parsed_groups = [
{"name": "G1", "slug": "g1", "categories": [{"name": "Cat1"}]},
]
groups = group_categories(parsed_groups, [])
assert len(groups) == 1
assert groups[0]["name"] == "G1"
def test_preserves_group_order(self):
parsed_groups = [
{"name": "Second", "slug": "second", "categories": [{"name": "C2"}]},
{"name": "First", "slug": "first", "categories": [{"name": "C1"}]},
]
groups = group_categories(parsed_groups, [])
assert groups[0]["name"] == "Second"
assert groups[1]["name"] == "First"
# ---------------------------------------------------------------------------
# build (integration)
@@ -114,6 +119,8 @@ class TestBuild:
---
**Tools**
## Widgets
_Widget libraries._
@@ -176,10 +183,14 @@ class TestBuild:
---
**Group A**
## Alpha
- [a](https://x.com) - A.
**Group B**
## Beta
- [b](https://x.com) - B.
@@ -194,6 +205,8 @@ class TestBuild:
index_html = (tmp_path / "website" / "output" / "index.html").read_text()
assert "Alpha" in index_html
assert "Beta" in index_html
assert "Group A" in index_html
assert "Group B" in index_html
def test_index_contains_preview_text(self, tmp_path):
readme = textwrap.dedent("""\