#!/usr/bin/env python3 """Post-process openapi.json before handing it to Orval. oatpp 1.3's Swagger generator produces a valid spec but with rough edges that make the generated client less ergonomic: - Missing operationIds on some endpoints → orval falls back to path-based names that collide. We synthesise an operationId from method + path. - summary/description strings occasionally contain stray control characters. - Some endpoints have no tags, which throws off orval's file-splitting. Run between `fetch-openapi.sh` and `orval` (see package.json `codegen`). """ import json import re import sys from pathlib import Path SRC = Path("openapi.json") if not SRC.exists(): sys.exit(f"{SRC} not found — run fetch-openapi.sh first") spec = json.loads(SRC.read_text()) def op_id(method: str, path: str) -> str: """`getApiAnnouncementsEntityIdHistory` from `GET /api/announcements/{entity_id}/history`.""" parts = [method.lower()] for seg in path.strip("/").split("/"): if seg.startswith("{") and seg.endswith("}"): parts.append(seg[1:-1]) else: parts.append(seg) return re.sub(r"[^A-Za-z0-9]+(\w)", lambda m: m.group(1).upper(), "_".join(parts)) paths = spec.get("paths", {}) for path, methods in paths.items(): for method, op in methods.items(): if not isinstance(op, dict): continue op.setdefault("operationId", op_id(method, path)) op.setdefault("tags", [path.strip("/").split("/")[1] if "/" in path.strip("/") else "default"]) SRC.write_text(json.dumps(spec, indent=2)) print(f" postprocessed {SRC} — {len(paths)} paths")