#!/usr/bin/env python import importlib import inspect import os import sys from enum import Enum, IntEnum, StrEnum # Adjust these for your project PY_MODULE = "draft.constants" # where your enums live OUTPUT_PATH = "frontend/src/apps/draft/constants.js" # Optionally allow running from any cwd PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) PROJECT_ROOT = os.path.abspath(os.path.join(PROJECT_ROOT, "..")) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) def js_quote(s: str) -> str: return s.replace("\\", "\\\\").replace('"', '\\"') def titleize(name: str) -> str: # e.g., "DETERMINE_ORDER" -> "Determine Order" return name.replace("_", " ").title() def emit_header(): return "// AUTO-GENERATED. Do not edit by hand.\n" \ "// Run: python scripts/generate_js_constants.py\n\n" def emit_str_enum(name: str, enum_cls) -> str: """ Emit a JS object for StrEnum: export const DraftMessage = { KEY: "value", ... }; """ lines = [f"export const {name} = {{"] # ESM export for member in enum_cls: lines.append(f' {member.name}: "{js_quote(member.value)}",') lines.append("};\n") return "\n".join(lines) def emit_int_enum(name: str, enum_cls) -> str: """ Emit a JS object + labels + ordered list for IntEnum: export const DraftPhase = { KEY: number, ... }; export const DraftPhaseLabel = { [number]: "Pretty", ... }; export const DraftPhasesOrdered = [numbers...]; """ lines = [f"export const {name} = {{"] # ESM export items = list(enum_cls) # object map for member in items: lines.append(f" {member.name}: {int(member.value)},") lines.append("};\n") # label map (use .pretty_name if you added it; else derive from name or __str__) lines.append(f"export const {name}Label = {{") for member in items: if hasattr(member, "pretty_name"): label = getattr(member, "pretty_name") else: # fall back: __str__ if you overload it, else Title Case of name label = str(member) if label == f"{enum_cls.__name__}.{member.name}": label = titleize(member.name) lines.append(f' [{name}.{member.name}]: "{js_quote(label)}",') lines.append("};\n") # ordered list ordered = sorted(items, key=lambda m: int(m.value)) ordered_vals = ", ".join(f"{name}.{m.name}" for m in ordered) lines.append(f"export const {name}sOrdered = [{ordered_vals}];\n") return "\n".join(lines) def main(): mod = importlib.import_module(PY_MODULE) out = [emit_header()] # Pick which enums to export. You can filter here if you don’t want all. for name, obj in inspect.getmembers(mod): ignore_classes = [Enum, IntEnum, StrEnum] if inspect.isclass(obj) and issubclass(obj, Enum) and not obj in ignore_classes: # Skip helper classes that aren’t actual Enums if name.startswith("_"): continue if issubclass(obj, IntEnum): out.append(emit_int_enum(name, obj)) else: out.append(emit_str_enum(name, obj)) os.makedirs(os.path.dirname(OUTPUT_PATH), exist_ok=True) with open(OUTPUT_PATH, "w", encoding="utf-8") as f: f.write("\n".join(out)) print(f"✅ Wrote {OUTPUT_PATH}") if __name__ == "__main__": main()