` patterns to stat_card() primitive.
Per motto_v3 §11, this mechanical migration consolidates stat-card patterns
under the canonical primitive. Four common cases:
1. Simple stat-card with just a heading: `stat_card(value, label)`
2. Stat-card with a section heading: `stat_card("", "", body_html="
...
...")`
3. Stat-card with complex content (e.g. barcode info, swiggy section header)
4. Stat-card with additional attributes (role, id) - skipped for manual review
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
SCREENS_DIR = Path("shopstack/ui/screens")
# Stat-card with a heading AND body content (e.g. swiggy section header).
# The body contains `
...
` plus other content.
# `
TITLE
BODY`
P_HEADING_BODY = re.compile(
r"
([^<]+)
(.*?)\s*\n?",
re.DOTALL,
)
# Plain stat-card wrapper (just opens a stat-card section).
# `
` or `
CONTENT
`
P_PLAIN = re.compile(
r"
(.*?)
\s*\n?",
re.DOTALL,
)
def migrate(content: str) -> tuple[str, int]:
"""Apply stat-card migrations. Conservative — skips ambiguous patterns."""
count = 0
def _replace_heading_body(m: re.Match) -> str:
nonlocal count
count += 1
style, title, body = m.group(1), m.group(2), m.group(3)
body_html = f"
{title}
{body}"
if style:
return f"stat_card(value='', label='', body_html={body_html!r}, style={style!r})\n"
return f"stat_card(value='', label='', body_html={body_html!r})\n"
# First pass: heading+body pattern (most specific)
content = P_HEADING_BODY.sub(_replace_heading_body, content)
return content, count
def process_file(path: Path) -> int:
src = path.read_text(encoding="utf-8")
if "stat-card" not in src:
return 0
new_src, count = migrate(src)
if count == 0:
return 0
path.write_text(new_src, encoding="utf-8")
return count
def main() -> int:
total = 0
for path in sorted(SCREENS_DIR.glob("*.py")):
if path.name in ("__init__.py", "_utils.py", "_legacy") or path.name.startswith("_"):
continue
count = process_file(path)
if count > 0:
print(f"{path.name}: {count} migrations")
total += count
print(f"\nTOTAL: {total} stat-card heading+body patterns migrated to stat_card(body_html=)")
return total
if __name__ == "__main__":
sys.exit(0 if main() >= 0 else 1)