diff --git a/__init__.py b/__init__.py deleted file mode 100644 index 963207d..0000000 --- a/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -__init__.py for curl-to-code-converter package. -""" - -from .parser import CurlParser, ParsedCurl -from .generators import CodeGenerators -from .__main__ import main as run - -__version__ = "1.0.0" -__all__ = ["CurlParser", "ParsedCurl", "CodeGenerators", "run"] diff --git a/__main__.py b/__main__.py deleted file mode 100644 index aeff659..0000000 --- a/__main__.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -cURL to Code Converter - -A CLI tool that converts cURL commands into code snippets in various programming languages. -""" - -import argparse -import sys -from curl_to_code_converter.parser import CurlParser -from curl_to_code_converter.generators import CodeGenerators - - -def main(): - parser = argparse.ArgumentParser( - description="Convert cURL commands to code snippets in various languages", - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" -Examples: - %(prog)s 'curl https://api.example.com/data' - %(prog)s 'curl -X POST https://api.example.com -d "{\"key\":\"value\"}"' -l python - %(prog)s 'curl -H "Authorization: Bearer token" https://api.example.com' -l javascript - """ - ) - parser.add_argument( - "curl_command", - help="The cURL command to convert" - ) - parser.add_argument( - "-l", "--language", - choices=["python", "javascript", "go", "ruby", "php", "java"], - default="python", - help="Target programming language (default: python)" - ) - parser.add_argument( - "-o", "--output", - help="Output file path (optional)" - ) - parser.add_argument( - "-v", "--verbose", - action="store_true", - help="Show verbose output" - ) - - args = parser.parse_args() - - try: - curl_parser = CurlParser(args.curl_command) - parsed_data = curl_parser.parse() - - if args.verbose: - print(f"Parsed cURL command:") - print(f" URL: {parsed_data.url}") - print(f" Method: {parsed_data.method}") - print(f" Headers: {parsed_data.headers}") - print(f" Data: {parsed_data.data}") - print(f" Auth: {parsed_data.auth}") - print() - - generators = CodeGenerators() - code = generators.generate(parsed_data, args.language) - - if args.output: - with open(args.output, 'w') as f: - f.write(code) - print(f"Code written to {args.output}") - else: - print(code) - - except Exception as e: - print(f"Error: {e}", file=sys.stderr) - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/curl_to_code_converter/pyproject.toml b/curl_to_code_converter/pyproject.toml deleted file mode 100644 index 17fbe76..0000000 --- a/curl_to_code_converter/pyproject.toml +++ /dev/null @@ -1,39 +0,0 @@ -[build-system] -requires = ["setuptools>=61.0"] -build-backend = "setuptools.build_meta" - -[project] -name = "curl-to-code-converter" -version = "1.0.0" -description = "A CLI tool that converts cURL commands into code snippets in various programming languages" -readme = "README.md" -license = {text = "MIT"} -requires-python = ">=3.7" -classifiers = [ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", -] -keywords = ["curl", "converter", "cli", "code-generation", "http"] - -[project.scripts] -curl-to-code = "curl_to_code_converter.__main__:main" - -[project.urls] -Homepage = "https://github.com/example/curl-to-code-converter" - -[project.optional-dependencies] -dev = [ - "pytest>=7.0.0", - "ruff>=0.1.0", -] - -[tool.setuptools.packages.find] -where = ["*"] -include = ["curl_to_code_converter*"] diff --git a/generators.py b/generators.py deleted file mode 100644 index 6d49a78..0000000 --- a/generators.py +++ /dev/null @@ -1,302 +0,0 @@ -""" -Code generators for different programming languages. -""" - -import json -from typing import Optional -from .parser import ParsedCurl - - -class CodeGenerators: - def generate(self, parsed: ParsedCurl, language: str) -> str: - """Generate code snippet for the given language.""" - generators = { - 'python': self._generate_python, - 'javascript': self._generate_javascript, - 'go': self._generate_go, - 'ruby': self._generate_ruby, - 'php': self._generate_php, - 'java': self._generate_java, - } - - generator = generators.get(language) - if not generator: - raise ValueError(f"Unsupported language: {language}") - - return generator(parsed) - - def _generate_python(self, parsed: ParsedCurl) -> str: - """Generate Python code using requests library.""" - code = ["import requests\n"] - - if parsed.auth: - code.append(f"response = requests.{parsed.method.lower()}(") - else: - code.append(f"response = requests.{parsed.method.lower()}(") - - code.append(f" '{parsed.url}'\n") - - if parsed.headers: - code.append(f" headers={json.dumps(parsed.headers, indent=8)}\n") - - if parsed.data: - if parsed.content_type and 'application/json' in parsed.content_type: - try: - json_data = json.loads(parsed.data) - code.append(f" json={json.dumps(json_data, indent=8)}\n") - except json.JSONDecodeError: - code.append(f" data='{parsed.data}'\n") - else: - data_str = parsed.data.replace("'", "\\'") - code.append(f" data='{data_str}'\n") - - if parsed.auth: - code.append(f" auth={parsed.auth}\n") - - code.append(")\n") - code.append(f"\nprint(response.status_code)") - code.append(f"\nprint(response.text)") - - return ''.join(code) - - def _generate_javascript(self, parsed: ParsedCurl) -> str: - """Generate JavaScript code using fetch API.""" - code = ["const fetchData = async () => {\n"] - code.append(" try {\n") - - options_parts = [f"method: '{parsed.method}'"] - - if parsed.headers: - options_parts.append(f"headers: {json.dumps(parsed.headers)}") - - if parsed.data: - if parsed.content_type and 'application/json' in parsed.content_type: - options_parts.append(f"body: JSON.stringify({parsed.data})") - else: - data_str = parsed.data.replace("'", "\\'") - options_parts.append(f"body: '{data_str}'") - - code.append(" const options = {\n") - for i, part in enumerate(options_parts): - if i > 0: - code.append(",\n") - code.append(f" {part}") - code.append("\n };\n\n") - - code.append(f" const response = await fetch('{parsed.url}', options);\n") - code.append(" const data = await response.json();\n") - code.append(" console.log(data);\n") - code.append(" return data;\n") - code.append(" } catch (error) {\n") - code.append(" console.error('Error:', error);\n") - code.append(" }\n") - code.append("}\n\n") - code.append("fetchData();") - - return ''.join(code) - - def _generate_go(self, parsed: ParsedCurl) -> str: - """Generate Go code using net/http package.""" - code = ["package main\n\n"] - code.append("import (\n") - code.append(' "bytes"\n') - code.append(' "encoding/json"\n') - code.append(' "fmt"\n') - code.append(' "io/ioutil"\n') - code.append(' "net/http"\n') - code.append(')\n\n') - - code.append("func main() {\n") - code.append(f" url := \"{parsed.url}\"\n\n") - - if parsed.method == "GET": - code.append(" req, err := http.NewRequest(\"GET\", url, nil)\n") - else: - data_str = parsed.data if parsed.data else "" - code.append(f" jsonData := `{data_str}`\n") - code.append(" req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(jsonData)))\n") - - code.append(" if err != nil {\n") - code.append(" panic(err)\n") - code.append(" }\n\n") - - if parsed.headers: - for key, value in parsed.headers.items(): - code.append(f' req.Header.Set(\"{key}\", \"{value}\")\n') - code.append("\n") - - if parsed.auth: - code.append(f' req.SetBasicAuth(\"{parsed.auth[0]}\", \"{parsed.auth[1]}\")\n\n') - - code.append(" client := &http.Client{}\n") - code.append(" resp, err := client.Do(req)\n") - code.append(" if err != nil {\n") - code.append(" panic(err)\n") - code.append(" }\n") - code.append(" defer resp.Body.Close()\n\n") - - code.append(" body, err := ioutil.ReadAll(resp.Body)\n") - code.append(" if err != nil {\n") - code.append(" panic(err)\n") - code.append(" }\n\n") - - code.append(" fmt.Println(string(body))\n") - code.append("}\n") - - return ''.join(code) - - def _generate_ruby(self, parsed: ParsedCurl) -> str: - """Generate Ruby code using Net::HTTP.""" - code = ["require 'net/http'\n"] - code.append("require 'uri'\n") - code.append("require 'json'\n\n") - - code.append(f"uri = URI.parse(\"{parsed.url}\")\n\n") - - code.append("http = Net::HTTP.new(uri.host, uri.port)\n") - code.append("http.use_ssl = true if uri.scheme == 'https'\n\n") - - if parsed.method == "GET": - code.append("request = Net::HTTP::Get.new(uri)\n") - elif parsed.method == "POST": - code.append("request = Net::HTTP::Post.new(uri)\n") - elif parsed.method == "PUT": - code.append("request = Net::HTTP::Put.new(uri)\n") - elif parsed.method == "DELETE": - code.append("request = Net::HTTP::Delete.new(uri)\n") - else: - code.append(f"request = Net::HTTP::#{parsed.method}.new(uri)\n") - - for key, value in parsed.headers.items(): - code.append(f'request[\"{key}\"] = \"{value}\"\n') - - if parsed.data: - if parsed.content_type and 'application/json' in parsed.content_type: - code.append(f"request.body = {parsed.data}\n") - else: - data_str = parsed.data.replace('"', '\\"') - code.append(f"request.body = \"{data_str}\"\n") - - if parsed.auth: - code.append(f'request.basic_auth \"{parsed.auth[0]}\", \"{parsed.auth[1]}\"\n') - - code.append("\nresponse = http.request(request)\n") - code.append("puts response.code\n") - code.append("puts response.body\n") - - return ''.join(code) - - def _generate_php(self, parsed: ParsedCurl) -> str: - """Generate PHP code using cURL.""" - code = ["\n") - - return ''.join(code) - - def _generate_java(self, parsed: ParsedCurl) -> str: - """Generate Java code using HttpURLConnection.""" - code = ["import java.io.*;\n"] - code.append("import java.net.*;\n") - code.append("import java.nio.charset.StandardCharsets;\n\n") - - code.append("public class ApiClient {\n") - code.append(" public static void main(String[] args) {\n") - code.append(" try {\n") - code.append(f" String url = \"{parsed.url}\";\n\n") - - code.append(" URL obj = new URL(url);\n") - code.append(" HttpURLConnection con = (HttpURLConnection) obj.openConnection();\n\n") - - code.append(f" con.setRequestMethod(\"{parsed.method}\");\n\n") - - for key, value in parsed.headers.items(): - code.append(f' con.setRequestProperty(\"{key}\", \"{value}\");\n') - - if parsed.auth: - code.append(f' String auth = \"{parsed.auth[0]}:{parsed.auth[1]}\";\n') - code.append(' String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));\n') - code.append(' con.setRequestProperty(\"Authorization\", \"Basic \" + encodedAuth);\n') - - if parsed.data: - code.append("\n String urlParameters = ") - data_str = parsed.data.replace('"', '\\"') - code.append(f'"{data_str}";\n') - code.append("\n con.setDoOutput(true);\n") - code.append(" try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {\n") - code.append(" wr.writeBytes(urlParameters);\n") - code.append(" wr.flush();\n") - code.append(" }\n") - - code.append("\n int responseCode = con.getResponseCode();\n") - code.append(" System.out.println(\"Response Code: \" + responseCode);\n\n") - - code.append(" try (BufferedReader in = new BufferedReader(\n") - code.append(" new InputStreamReader(con.getInputStream()))) {\n") - code.append(" String inputLine;\n") - code.append(" StringBuffer response = new StringBuffer();\n") - code.append(" while ((inputLine = in.readLine()) != null) {\n") - code.append(" response.append(inputLine);\n") - code.append(" }\n") - code.append(" System.out.println(response.toString());\n") - code.append(" }\n") - - code.append(" } catch (Exception e) {\n") - code.append(" e.printStackTrace();\n") - code.append(" }\n") - code.append(" }\n") - code.append("}\n") - - return ''.join(code) - - -if __name__ == "__main__": - parsed = ParsedCurl( - url="https://api.example.com/data", - method="POST", - headers={"Content-Type": "application/json", "Authorization": "Bearer token"}, - data='{"key": "value"}', - auth=("user", "pass") - ) - gen = CodeGenerators() - print("Python:") - print(gen._generate_python(parsed)) - print("\n" + "="*50 + "\n") - print("JavaScript:") - print(gen._generate_javascript(parsed)) diff --git a/parser.py b/parser.py deleted file mode 100644 index a4a324f..0000000 --- a/parser.py +++ /dev/null @@ -1,188 +0,0 @@ -""" -cURL command parser module. -""" - -import re -import shlex -from dataclasses import dataclass, field -from typing import Optional - - -@dataclass -class ParsedCurl: - url: str = "" - method: str = "GET" - headers: dict = field(default_factory=dict) - data: Optional[str] = None - auth: Optional[tuple] = None - content_type: Optional[str] = None - insecure: bool = False - - -class CurlParser: - def __init__(self, curl_command: str): - self.curl_command = curl_command - - def parse(self) -> ParsedCurl: - """Parse a cURL command and return structured data.""" - result = ParsedCurl() - - command = self._normalize_command() - tokens = self._tokenize(command) - - i = 0 - while i < len(tokens): - token = tokens[i] - - if token == 'curl': - i += 1 - continue - - if token.startswith('-'): - if token in ['-X', '--request']: - i += 1 - result.method = tokens[i].upper() if i < len(tokens) else 'GET' - elif token in ['-H', '--header']: - i += 1 - header = "" - if i < len(tokens): - header = tokens[i] - if header.endswith(':'): - i += 1 - while i < len(tokens) and not tokens[i].startswith('-'): - if '://' in tokens[i]: - i -= 1 - break - header += ' ' + tokens[i] - i += 1 - if header: - self._parse_header(header, result) - continue - elif token in ['-d', '--data', '--data-raw', '--data-binary']: - i += 1 - result.data = tokens[i] if i < len(tokens) else '' - if not result.method or result.method == 'GET': - result.method = 'POST' - continue - elif token in ['-u', '--user']: - i += 1 - if i < len(tokens): - auth = tokens[i] - if ':' in auth: - parts = auth.split(':', 1) - result.auth = (parts[0], parts[1]) - i += 1 - continue - elif token == '--url': - i += 1 - result.url = tokens[i] if i < len(tokens) else '' - continue - elif token in ['-b', '--cookie', '--cookie-jar']: - i += 1 - cookie = tokens[i] - if '=' in cookie: - name, value = cookie.split('=', 1) - result.headers['Cookie'] = value - continue - elif token in ['-A', '--user-agent']: - i += 1 - result.headers['User-Agent'] = tokens[i] if i < len(tokens) else '' - continue - elif token == '--compressed': - result.headers['Accept-Encoding'] = 'gzip, deflate' - elif token in ['-k', '--insecure']: - result.insecure = True - i += 1 - else: - if not result.url: - result.url = token - i += 1 - - return result - - def _normalize_command(self) -> str: - """Normalize the cURL command for parsing.""" - command = self.curl_command.strip() - command = re.sub(r'\\\n', '', command) - command = re.sub(r'\s+', ' ', command) - return command - - def _tokenize(self, command: str) -> list: - """Tokenize the cURL command.""" - tokens = [] - current = "" - in_quote = False - quote_char = None - - i = 0 - while i < len(command): - char = command[i] - - if char in ['"', "'"] and not in_quote: - in_quote = True - quote_char = char - i += 1 - continue - elif char == quote_char and in_quote: - in_quote = False - quote_char = None - i += 1 - continue - - if in_quote: - if char == '\\' and i + 1 < len(command): - current += char - current += command[i + 1] - i += 2 - continue - elif char == ' ': - if current: - tokens.append(current) - current = "" - i += 1 - continue - - if char == ' ' and not in_quote: - if current: - tokens.append(current) - current = "" - i += 1 - continue - - current += char - i += 1 - - if current: - tokens.append(current) - - unescaped_tokens = [] - for token in tokens: - token = token.replace('\\:', ':') - token = token.replace('\\"', '"') - token = token.replace("\\'", "'") - token = token.replace('\\n', '\n') - unescaped_tokens.append(token) - - return unescaped_tokens - - def _parse_header(self, header: str, result: ParsedCurl): - """Parse a header string and update the result.""" - if ':' in header: - parts = header.split(':', 1) - key = parts[0].strip() - value = parts[1].strip() - result.headers[key] = value - - if key.lower() == 'content-type': - result.content_type = value - - -if __name__ == "__main__": - import sys - parser = CurlParser(' '.join(sys.argv[1:])) - result = parser.parse() - print(f"URL: {result.url}") - print(f"Method: {result.method}") - print(f"Headers: {result.headers}") - print(f"Data: {result.data}") - print(f"Auth: {result.auth}")