UNPKG

curlconverter

Version:

convert curl commands to Python, JavaScript, Go, PHP and more

332 lines 12.3 kB
import { isInt } from "../../utils.js"; import { Word, eq } from "../../shell/Word.js"; import { parse, getFirst, COMMON_SUPPORTED_ARGS } from "../../parse.js"; import { parseQueryString } from "../../Query.js"; import { reprStr, repr, reprStringToStringList, reprObj, toURLSearchParams, asParseFloatTimes1000, addImport, reprImports, } from "./javascript.js"; export const supportedArgs = new Set([ ...COMMON_SUPPORTED_ARGS, "max-time", "form", "form-string", "proxy", "proxy-user", ]); // TODO: @ function _getDataString(request, imports) { if (!request.data) { return [null, null]; } const originalStringRepr = repr(request.data, imports); const contentType = request.headers.getContentType(); // can have things like ; charset=utf-8 which we want to preserve const exactContentType = request.headers.get("content-type"); if (contentType === "application/json" && request.data.isString()) { const dataStr = request.data.toString(); const parsed = JSON.parse(dataStr); // Only arrays and {} can be passed to axios to be encoded as JSON // TODO: check this in other generators if (typeof parsed !== "object" || parsed === null) { return [originalStringRepr, null]; } const roundtrips = JSON.stringify(parsed) === dataStr; const jsonAsJavaScript = reprObj(parsed, 1); if (roundtrips && eq(exactContentType, "application/json") && eq(request.headers.get("accept"), "application/json, text/plain, */*")) { request.headers.delete("content-type"); request.headers.delete("accept"); } return [jsonAsJavaScript, roundtrips ? null : originalStringRepr]; } if (contentType === "application/x-www-form-urlencoded") { const [queryList, queryDict] = parseQueryString(request.data); if (queryList) { // Technically axios sends // application/x-www-form-urlencoded;charset=utf-8 if (eq(exactContentType, "application/x-www-form-urlencoded")) { request.headers.delete("content-type"); } // TODO: check roundtrip, add a comment return [toURLSearchParams([queryList, queryDict], imports), null]; } else { return [originalStringRepr, null]; } } return [null, null]; } function getDataString(request, imports) { if (!request.data) { return [null, null]; } let dataString = null; let commentedOutDataString = null; try { [dataString, commentedOutDataString] = _getDataString(request, imports); } catch (_a) { } if (!dataString) { dataString = repr(request.data, imports); } return [dataString, commentedOutDataString]; } function buildConfigObject(request, method, methodStr, methods, dataMethods, hasSearchParams, imports) { let code = "{\n"; if (!methods.includes(methodStr)) { // Axios uppercases methods code += " method: " + repr(method, imports) + ",\n"; } if (hasSearchParams) { // code += " params,\n"; code += " params: params,\n"; } else if (request.urls[0].queryDict) { code += " params: " + reprStringToStringList(request.urls[0].queryDict, 1, imports) + ",\n"; } const [dataString, commentedOutDataString] = getDataString(request, imports); // can delete headers if (request.headers.length || request.multipartUploads) { code += " headers: {\n"; if (request.multipartUploads) { code += " ...form.getHeaders(),\n"; } for (const [key, value] of request.headers) { code += " " + repr(key, imports) + ": " + repr(value !== null && value !== void 0 ? value : new Word(), imports) + ",\n"; } if (code.endsWith(",\n")) { code = code.slice(0, -2); code += "\n"; } code += " },\n"; } if (request.urls[0].auth) { const [username, password] = request.urls[0].auth; code += " auth: {\n"; code += " username: " + repr(username, imports); if (password.toBool()) { code += ",\n"; code += " password: " + repr(password, imports) + "\n"; } else { code += "\n"; } code += " },\n"; } if (!dataMethods.includes(methodStr)) { if (request.multipartUploads) { code += " data: form,\n"; } else if (request.data) { if (commentedOutDataString) { code += " // data: " + commentedOutDataString + ",\n"; } code += " data: " + dataString + ",\n"; } } if (request.timeout) { if (parseFloat(request.timeout.toString()) !== 0) { code += " timeout: " + asParseFloatTimes1000(request.timeout, imports) + ",\n"; } } if (request.proxy && request.proxy.toString() === "") { // TODO: this probably won't be set if it's empty // TODO: could have --socks5 proxy code += " proxy: false,\n"; } else if (request.proxy) { // TODO: do this parsing in utils.ts const proxy = request.proxy.includes("://") ? request.proxy : request.proxy.prepend("http://"); let [protocol, host] = proxy.split("://", 2); protocol = protocol.toLowerCase().toString() === "socks" ? new Word("socks4") : protocol.toLowerCase(); let port = "1080"; const proxyPart = host.match(/:([0-9]+$)/); // TODO: this shouldn't be a regex if (proxyPart) { host = host.slice(0, proxyPart.index); port = proxyPart[1]; } code += " proxy: {\n"; code += " protocol: " + repr(protocol, imports) + ",\n"; code += " host: " + repr(host, imports) + ",\n"; if (isInt(port)) { code += " port: " + port + ",\n"; } else { code += " port: " + reprStr(port) + ",\n"; } if (request.proxyAuth) { const [proxyUser, proxyPassword] = request.proxyAuth.split(":", 2); code += " auth: {\n"; code += " user: " + repr(proxyUser, imports); if (proxyPassword !== undefined) { code += ",\n"; code += " password: " + repr(proxyPassword, imports) + "\n"; } else { code += "\n"; } code += " },\n"; } if (code.endsWith(",\n")) { code = code.slice(0, -2); code += "\n"; } code += " },\n"; } if (code.endsWith(",\n")) { code = code.slice(0, -2); } code += "\n}"; return code; } export function _toNodeAxios(requests, warnings = []) { const request = getFirst(requests, warnings); let importCode = "import axios from 'axios';\n"; const imports = []; let code = ""; const hasSearchParams = request.urls[0].queryList && (!request.urls[0].queryDict || // https://stackoverflow.com/questions/42898009/multiple-fields-with-same-key-in-query-params-axios-request request.urls[0].queryDict.some((q) => Array.isArray(q[1]))); if (hasSearchParams && request.urls[0].queryList) { code += "const params = new URLSearchParams();\n"; for (const [key, value] of request.urls[0].queryList) { code += "params.append(" + repr(key, imports) + ", " + repr(value, imports) + ");\n"; } code += "\n"; } if (request.multipartUploads) { importCode += "import FormData from 'form-data';\n"; code += "const form = new FormData();\n"; for (const m of request.multipartUploads) { code += "form.append(" + repr(m.name, imports) + ", "; if ("contentFile" in m) { addImport(imports, "* as fs", "fs"); if (eq(m.contentFile, "-")) { code += "fs.readFileSync(0).toString()"; } else { code += "fs.readFileSync(" + repr(m.contentFile, imports) + ")"; } if ("filename" in m && m.filename) { code += ", " + repr(m.filename, imports); } } else { code += repr(m.content, imports); } code += ");\n"; } code += "\n"; } const method = request.urls[0].method.toLowerCase(); const methodStr = method.toString(); const methods = ["get", "delete", "head", "options", "post", "put", "patch"]; code += "const response = await axios"; if (methods.includes(methodStr)) { code += "." + methodStr; } code += "("; const url = request.urls[0].queryDict || hasSearchParams ? request.urls[0].urlWithoutQueryList : request.urls[0].url; // axios only supports posting data with these HTTP methods // You can also post data with OPTIONS, but that has to go in the config object const dataMethods = ["post", "put", "patch"]; let needsConfig = !!(!methods.includes(methodStr) || request.urls[0].queryList || request.urls[0].queryDict || request.headers.length || request.urls[0].auth || request.multipartUploads || (request.data && !dataMethods.includes(methodStr)) || request.timeout || request.proxy); const needsData = dataMethods.includes(methodStr) && (request.data || request.multipartUploads || needsConfig); let dataString, commentedOutDataString; if (needsData) { code += "\n"; code += " " + repr(url, imports) + ",\n"; if (request.multipartUploads) { code += " form"; } else if (request.data) { try { [dataString, commentedOutDataString] = getDataString(request, imports); if (!dataString) { dataString = repr(request.data, imports); } } catch (_a) { dataString = repr(request.data, imports); } if (commentedOutDataString) { code += " // " + commentedOutDataString + ",\n"; } code += " " + dataString; } else if (needsConfig) { // TODO: this works but maybe undefined would be more correct? code += " ''"; } } else { code += repr(url, imports); } // getDataString() can delete a header, so we can end up with an empty config needsConfig = !!(!methods.includes(methodStr) || request.urls[0].queryList || request.urls[0].queryDict || request.headers.length || request.urls[0].auth || request.multipartUploads || (request.data && !dataMethods.includes(methodStr)) || request.timeout || request.proxy); if (needsConfig) { const config = buildConfigObject(request, method, methodStr, methods, dataMethods, !!hasSearchParams, imports); if (needsData) { code += ",\n"; for (const line of config.split("\n")) { code += " " + line + "\n"; } } else { code += ", "; code += config; } } else if (needsData) { code += "\n"; } code += ");\n"; importCode += reprImports(imports); return importCode + "\n" + code; } export function toNodeAxiosWarn(curlCommand, warnings = []) { const requests = parse(curlCommand, supportedArgs, warnings); const nodeAxios = _toNodeAxios(requests, warnings); return [nodeAxios, warnings]; } export function toNodeAxios(curlCommand) { return toNodeAxiosWarn(curlCommand)[0]; } //# sourceMappingURL=axios.js.map