44from dataclasses import dataclass , field
55from html import unescape
66
7+ from rockgarden .urls import slugify_heading
8+
79HEADING_RE = re .compile (r"<(h[2-6])(\s[^>]*)?>(.+?)</\1>" , re .DOTALL )
810TAG_RE = re .compile (r"<[^>]+>" )
911
@@ -18,14 +20,6 @@ class TocEntry:
1820 children : list ["TocEntry" ] = field (default_factory = list )
1921
2022
21- def _slugify (text : str ) -> str :
22- """Convert heading text to a URL-friendly slug."""
23- text = text .lower ()
24- text = re .sub (r"[^\w\s-]" , "" , text )
25- text = re .sub (r"[\s]+" , "-" , text .strip ())
26- return text
27-
28-
2923def _strip_tags (html : str ) -> str :
3024 """Remove HTML tags and unescape entities to get plain text."""
3125 return unescape (TAG_RE .sub ("" , html ).strip ())
@@ -78,7 +72,7 @@ def _replace_heading(match: re.Match) -> str:
7872 if level < min_level or level > max_level :
7973 # Still inject ID for anchor linking, but don't add to TOC
8074 text = _strip_tags (inner_html )
81- slug = _slugify (text )
75+ slug = slugify_heading (text )
8276 if not slug :
8377 return match .group (0 )
8478 if slug in seen_ids :
@@ -91,7 +85,7 @@ def _replace_heading(match: re.Match) -> str:
9185 return f'<{ tag } { attrs } id="{ slug } ">{ inner_html } </{ tag } >'
9286
9387 text = _strip_tags (inner_html )
94- slug = _slugify (text )
88+ slug = slugify_heading (text )
9589 if not slug :
9690 return match .group (0 )
9791
0 commit comments