Re-upload: CI infrastructure issue resolved, all tests verified passing
This commit is contained in:
263
http_log_explorer/exporters/code_exporter.py
Normal file
263
http_log_explorer/exporters/code_exporter.py
Normal file
@@ -0,0 +1,263 @@
|
||||
"""Code exporter for HTTP entries (Python, JavaScript, Go)."""
|
||||
|
||||
import json
|
||||
|
||||
from http_log_explorer.models import HTTPEntry
|
||||
|
||||
|
||||
class CodeExporter:
|
||||
"""Export HTTP entries as code snippets in various languages."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize code exporter."""
|
||||
self._template_dir = ""
|
||||
|
||||
PYTHON_TEMPLATE = '''import requests
|
||||
|
||||
headers = {headers}
|
||||
{data}
|
||||
response = requests.{method}(
|
||||
"{url}"{params}
|
||||
{headers_param})
|
||||
{body}
|
||||
print(response.status_code)
|
||||
print(response.json())
|
||||
'''
|
||||
|
||||
JAVASCRIPT_TEMPLATE = '''const axios = require('axios');
|
||||
|
||||
const config = {{
|
||||
method: '{method}',
|
||||
url: '{url}',
|
||||
{headers_js}
|
||||
{data_js}
|
||||
{body_js}
|
||||
}};
|
||||
|
||||
axios(config)
|
||||
.then(response => {{
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
}})
|
||||
.catch(error => {{
|
||||
console.error(error);
|
||||
}});
|
||||
'''
|
||||
|
||||
GO_TEMPLATE = '''package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {{
|
||||
{headers_go}
|
||||
{data_go}
|
||||
body{data_var} := {body_val}
|
||||
{body_prep}
|
||||
req, err := http.NewRequest("{method}", "{url}", {body_ref})
|
||||
if err != nil {{
|
||||
panic(err)
|
||||
}}
|
||||
{set_headers}
|
||||
client := &http.Client{{}}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {{
|
||||
panic(err)
|
||||
}}
|
||||
defer resp.Body.Close()
|
||||
|
||||
fmt.Println("Status:", resp.Status)
|
||||
}}
|
||||
|
||||
'''
|
||||
|
||||
def export_python(self, entry: HTTPEntry) -> str:
|
||||
"""Export entry as Python code.
|
||||
|
||||
Args:
|
||||
entry: HTTPEntry object
|
||||
|
||||
Returns:
|
||||
Python code string
|
||||
"""
|
||||
headers_str = self._format_python_dict(entry.request.headers)
|
||||
|
||||
data_line = ""
|
||||
body_line = ""
|
||||
params_line = ""
|
||||
|
||||
if entry.request.query_params:
|
||||
params_line = f", params={self._format_python_dict(entry.request.query_params)}"
|
||||
|
||||
if entry.request.body:
|
||||
body_line = "data=data,"
|
||||
|
||||
if entry.request.headers:
|
||||
headers_param = "\n headers=headers"
|
||||
else:
|
||||
headers_param = ""
|
||||
|
||||
method_lower = entry.request.method.lower()
|
||||
|
||||
return self.PYTHON_TEMPLATE.format(
|
||||
method=method_lower,
|
||||
url=entry.request.url,
|
||||
headers=headers_str,
|
||||
params=params_line,
|
||||
headers_param=headers_param,
|
||||
data=data_line,
|
||||
body=body_line,
|
||||
)
|
||||
|
||||
def export_javascript(self, entry: HTTPEntry) -> str:
|
||||
"""Export entry as JavaScript code.
|
||||
|
||||
Args:
|
||||
entry: HTTPEntry object
|
||||
|
||||
Returns:
|
||||
JavaScript code string
|
||||
"""
|
||||
headers_lines = []
|
||||
for name, value in entry.request.headers.items():
|
||||
headers_lines.append(f' "{name}": "{value}",')
|
||||
|
||||
headers_js = "\n".join(headers_lines)
|
||||
if headers_js:
|
||||
headers_js = "headers: {\n" + headers_js + "\n},"
|
||||
|
||||
data_js = ""
|
||||
data_val = "{}"
|
||||
body_js = ""
|
||||
|
||||
if entry.request.body:
|
||||
data_val = json.dumps(entry.request.body)
|
||||
data_js = f"const data = {data_val};"
|
||||
body_js = "data: data,"
|
||||
|
||||
if entry.request.query_params:
|
||||
data_val = json.dumps(entry.request.query_params)
|
||||
data_js = f"const params = {data_val};"
|
||||
body_js = "params: params,"
|
||||
|
||||
return self.JAVASCRIPT_TEMPLATE.format(
|
||||
method=entry.request.method.lower(),
|
||||
url=entry.request.url,
|
||||
headers_js=headers_js,
|
||||
data_js=data_js,
|
||||
body_js=body_js,
|
||||
)
|
||||
|
||||
def export_go(self, entry: HTTPEntry) -> str:
|
||||
"""Export entry as Go code.
|
||||
|
||||
Args:
|
||||
entry: HTTPEntry object
|
||||
|
||||
Returns:
|
||||
Go code string
|
||||
"""
|
||||
headers_lines = []
|
||||
for name, value in entry.request.headers.items():
|
||||
headers_lines.append(f' req.Header.Set("{name}", "{value}")')
|
||||
|
||||
headers_go = "\n".join(headers_lines)
|
||||
|
||||
data_val = "nil"
|
||||
data_var = ""
|
||||
body_prep = ""
|
||||
body_ref = "nil"
|
||||
data_go = ""
|
||||
|
||||
if entry.request.body:
|
||||
escaped = self._escape_go_string(entry.request.body)
|
||||
data_val = f"`{escaped}`"
|
||||
body_prep = f' body := bytes.NewBufferString({data_val})'
|
||||
body_ref = "body"
|
||||
|
||||
set_headers = headers_go if headers_go else " // No headers"
|
||||
|
||||
return self.GO_TEMPLATE.format(
|
||||
method=entry.request.method,
|
||||
url=entry.request.url,
|
||||
headers_go=headers_go,
|
||||
data_go=data_go,
|
||||
data_var=data_var,
|
||||
body_val=data_val,
|
||||
body_prep=body_prep,
|
||||
body_ref=body_ref,
|
||||
set_headers=set_headers,
|
||||
)
|
||||
|
||||
def export_batch(
|
||||
self, entries: list[HTTPEntry], language: str
|
||||
) -> list[str]:
|
||||
"""Export multiple entries as code snippets.
|
||||
|
||||
Args:
|
||||
entries: List of HTTPEntry objects
|
||||
language: Target language (python, javascript, go)
|
||||
|
||||
Returns:
|
||||
List of code strings
|
||||
|
||||
Raises:
|
||||
ValueError: If language is not supported
|
||||
"""
|
||||
language = language.lower()
|
||||
if language == "python":
|
||||
return [self.export_python(e) for e in entries]
|
||||
elif language == "javascript":
|
||||
return [self.export_javascript(e) for e in entries]
|
||||
elif language == "go":
|
||||
return [self.export_go(e) for e in entries]
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported language: {language}. "
|
||||
f"Supported: python, javascript, go"
|
||||
)
|
||||
|
||||
def _format_python_dict(self, d: dict[str, str]) -> str:
|
||||
"""Format dictionary as Python code.
|
||||
|
||||
Args:
|
||||
d: Dictionary to format
|
||||
|
||||
Returns:
|
||||
Python dict string
|
||||
"""
|
||||
if not d:
|
||||
return "{}"
|
||||
items = [f'"{k}": "{v}"' for k, v in d.items()]
|
||||
return "{\n " + ",\n ".join(items) + "\n}"
|
||||
|
||||
def _escape_go_string(self, s: str) -> str:
|
||||
"""Escape string for Go.
|
||||
|
||||
Args:
|
||||
s: String to escape
|
||||
|
||||
Returns:
|
||||
Escaped string
|
||||
"""
|
||||
return s.replace("\\", "\\\\").replace("`", "\\`").replace("$", "\\$")
|
||||
|
||||
def to_file(
|
||||
self, entries: list[HTTPEntry], path: str, language: str
|
||||
) -> None:
|
||||
"""Write code snippets to file.
|
||||
|
||||
Args:
|
||||
entries: List of HTTPEntry objects
|
||||
path: Output file path
|
||||
language: Target language
|
||||
"""
|
||||
snippets = self.export_batch(entries, language)
|
||||
with open(path, "w") as f:
|
||||
for snippet in snippets:
|
||||
f.write(snippet)
|
||||
f.write("\n\n")
|
||||
Reference in New Issue
Block a user