eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
136 lines
4.4 KiB
Python
136 lines
4.4 KiB
Python
"""Convierte call specs del registry en una coleccion Hoppscotch importable.
|
|
|
|
Mitad "exportar al GUI" del puente entre el motor de replay del registry y
|
|
Hoppscotch. La funcion inversa es parse_hoppscotch_collection.
|
|
"""
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
def _request_name(call: dict, fallback_index: int) -> str:
|
|
"""Deriva un nombre legible para la request a partir del metodo y el path.
|
|
|
|
Args:
|
|
call: call spec con (opcional) method y url.
|
|
fallback_index: indice de la call dentro de la lista (no usado en el
|
|
nombre derivado, reservado para desambiguar si hiciera falta).
|
|
|
|
Returns:
|
|
nombre del estilo "GET /api/search".
|
|
"""
|
|
method = str(call.get("method") or "GET").upper()
|
|
url = str(call.get("url") or "")
|
|
path = urlparse(url).path or "/"
|
|
return f"{method} {path}"
|
|
|
|
|
|
def _build_headers(call: dict) -> list[dict]:
|
|
"""Construye la lista de headers Hoppscotch desde el dict del call spec.
|
|
|
|
Convierte el dict headers (preservando orden de insercion) a la lista
|
|
[{"key", "value", "active": True}, ...] y, si el call spec trae cookies no
|
|
vacias, anade un header extra "Cookie" al final con formato "k1=v1; k2=v2".
|
|
|
|
Args:
|
|
call: call spec con (opcional) headers y cookies.
|
|
|
|
Returns:
|
|
lista de headers Hoppscotch.
|
|
"""
|
|
headers: list[dict] = []
|
|
raw_headers = call.get("headers") or {}
|
|
for key, value in raw_headers.items():
|
|
headers.append({"key": key, "value": value, "active": True})
|
|
|
|
cookies = call.get("cookies") or {}
|
|
if cookies:
|
|
cookie_value = "; ".join(f"{name}={val}" for name, val in cookies.items())
|
|
headers.append({"key": "Cookie", "value": cookie_value, "active": True})
|
|
|
|
return headers
|
|
|
|
|
|
def _build_body(call: dict) -> dict:
|
|
"""Construye el objeto body Hoppscotch segun body_type del call spec.
|
|
|
|
Args:
|
|
call: call spec con (opcional) body y body_type.
|
|
|
|
Returns:
|
|
dict con contentType y body. Si no hay body o el body_type es
|
|
desconocido/None, ambos campos son None.
|
|
"""
|
|
body = call.get("body")
|
|
body_type = call.get("body_type")
|
|
|
|
content_types = {
|
|
"json": "application/json",
|
|
"form": "application/x-www-form-urlencoded",
|
|
"raw": "text/plain",
|
|
}
|
|
|
|
if body is None or body_type not in content_types:
|
|
return {"contentType": None, "body": None}
|
|
|
|
return {"contentType": content_types[body_type], "body": body}
|
|
|
|
|
|
def build_hoppscotch_collection(
|
|
calls: list[dict],
|
|
*,
|
|
name: str = "Collection",
|
|
request_names: list[str] | None = None,
|
|
) -> dict:
|
|
"""Convierte una lista de call specs en una coleccion Hoppscotch importable.
|
|
|
|
Genera el formato canonico estable (coleccion v:1, request v:"2") que
|
|
Hoppscotch migra a la ultima version al importar. Pura: sin I/O ni red,
|
|
solo stdlib, determinista.
|
|
|
|
Args:
|
|
calls: lista de call specs (salida de har_extract_calls). Cada elemento
|
|
es un dict con claves opcionales: method, url, headers, cookies,
|
|
body, body_type. Otras claves (status, sets_cookies, ...) se ignoran.
|
|
name: nombre de la coleccion Hoppscotch.
|
|
request_names: nombres explicitos por request, alineados por indice. Si
|
|
se pasa y existe el indice, sobreescribe el nombre derivado. None =
|
|
derivar todos los nombres como "<METHOD> <path>".
|
|
|
|
Returns:
|
|
dict con la coleccion Hoppscotch: {"v": 1, "name", "folders": [],
|
|
"requests": [...]}. JSON-serializable.
|
|
"""
|
|
requests: list[dict] = []
|
|
|
|
for index, call in enumerate(calls):
|
|
if request_names is not None and index < len(request_names):
|
|
req_name = request_names[index]
|
|
else:
|
|
req_name = _request_name(call, index)
|
|
|
|
endpoint = str(call.get("url") or "")
|
|
method = str(call.get("method") or "GET").upper()
|
|
|
|
requests.append(
|
|
{
|
|
"v": "2",
|
|
"endpoint": endpoint,
|
|
"name": req_name,
|
|
"params": [],
|
|
"headers": _build_headers(call),
|
|
"method": method,
|
|
"auth": {"authType": "none", "authActive": True},
|
|
"preRequestScript": "",
|
|
"testScript": "",
|
|
"body": _build_body(call),
|
|
"requestVariables": [],
|
|
}
|
|
)
|
|
|
|
return {
|
|
"v": 1,
|
|
"name": name,
|
|
"folders": [],
|
|
"requests": requests,
|
|
}
|