import re import sys from pathlib import Path from django.conf import settings from django.core.management.base import BaseCommand, CommandError from api.models import Aspect, Hero, Item # Add data directory to path for imports sys.path.insert(0, str(Path(settings.BASE_DIR) / "data")) from facets import HERO_FACETS def _strip_comments(text: str) -> str: """Remove single-line and block comments from TypeScript data.""" text = re.sub(r"/\*.*?\*/", "", text, flags=re.S) lines = [] for line in text.splitlines(): stripped = line.strip() if stripped.startswith("//"): continue lines.append(line) return "\n".join(lines) def _extract_objects(text: str, require_primary: bool = False): cleaned = _strip_comments(text) objects = [] for match in re.finditer(r"\{[^}]*\}", cleaned): chunk = match.group(0) entry = {} id_match = re.search(r"['\"]?id['\"]?\s*:\s*(['\"])(.*?)\1", chunk) name_match = re.search(r"['\"]?name['\"]?\s*:\s*(['\"])(.*?)\1", chunk) if not (id_match and name_match): continue entry["slug"] = id_match.group(2) entry["name"] = name_match.group(2) if require_primary: primary_match = re.search(r"['\"]?primary['\"]?\s*:\s*(['\"])(.*?)\1", chunk) if not primary_match: continue entry["primary"] = primary_match.group(2) if len(entry) == (3 if require_primary else 2): objects.append(entry) return objects class Command(BaseCommand): help = "Load heroes, items and facets from data files into the database." def handle(self, *args, **options): base_dir = Path(settings.BASE_DIR) heroes_path = base_dir / "data" / "heroes.ts" items_path = base_dir / "data" / "items.ts" if not heroes_path.exists() or not items_path.exists(): raise CommandError("Missing data files in the ./data directory.") heroes = _extract_objects(heroes_path.read_text(encoding="utf-8"), require_primary=True) items = _extract_objects(items_path.read_text(encoding="utf-8"), require_primary=False) if not heroes: raise CommandError("Failed to parse heroes.ts") if not items: raise CommandError("Failed to parse items.ts") hero_created = item_created = aspect_created = 0 for hero in heroes: hero_obj, created = Hero.objects.update_or_create( name=hero["name"], defaults={ "primary": hero["primary"], }, ) hero_created += int(created) # Load facets for this hero facets = HERO_FACETS.get(hero["name"], []) for facet_name in facets: _, facet_created = Aspect.objects.update_or_create( hero=hero_obj, name=facet_name, ) aspect_created += int(facet_created) for item in items: _, created = Item.objects.update_or_create( name=item["name"], ) item_created += int(created) self.stdout.write( self.style.SUCCESS( f"Loaded {len(heroes)} heroes ({hero_created} new), " f"{len(items)} items ({item_created} new), " f"and {aspect_created} new facets." ) )