shopstack / tools /migrate_stat_card.py
pranaysuyash's picture
Sync ShopStack HEAD 6f8adfc
d999bba verified
Raw
History Blame Contribute Delete
2.7 kB
"""Migrate inline `<div class='stat-card'>` 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="<h4>...</h4>...")`
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 `<h4>...</h4>` plus other content.
# `<div class='stat-card' style='...'><h4>TITLE</h4>BODY</div>`
P_HEADING_BODY = re.compile(
r"<div class='stat-card'(?: style='([^']*)')?><h4>([^<]+)</h4>(.*?)</div>\s*\n?",
re.DOTALL,
)
# Plain stat-card wrapper (just opens a stat-card section).
# `<div class='stat-card' style='...'></div>` or `<div class='stat-card'>CONTENT</div>`
P_PLAIN = re.compile(
r"<div class='stat-card'(?: style='([^']*)')?>(.*?)</div>\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"<h4>{title}</h4>{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)