From 59c3205be37c59dc7f9316710370dfd6895cec06 Mon Sep 17 00:00:00 2001 From: Daniils Petrovs Date: Fri, 12 Nov 2021 14:09:41 +0100 Subject: [PATCH] Implement Elixir HTTPoison target --- src/targets/elixir/httpoison.js | 136 ++++++++++++++++++ src/targets/elixir/index.js | 11 ++ src/targets/index.js | 1 + test/fixtures/available-targets.json | 14 ++ .../httpoison/application-form-encoded.ex | 6 + .../elixir/httpoison/application-json.ex | 6 + .../output/elixir/httpoison/cookies.ex | 7 + .../output/elixir/httpoison/custom-method.ex | 5 + test/fixtures/output/elixir/httpoison/full.ex | 7 + .../output/elixir/httpoison/headers.ex | 6 + .../fixtures/output/elixir/httpoison/https.ex | 5 + .../elixir/httpoison/jsonObj-multiline.ex | 8 ++ .../elixir/httpoison/jsonObj-null-value.ex | 6 + .../output/elixir/httpoison/multipart-data.ex | 6 + .../output/elixir/httpoison/multipart-file.ex | 6 + .../elixir/httpoison/multipart-form-data.ex | 6 + .../output/elixir/httpoison/nested.ex | 5 + .../fixtures/output/elixir/httpoison/query.ex | 5 + .../fixtures/output/elixir/httpoison/short.ex | 5 + .../output/elixir/httpoison/text-plain.ex | 6 + test/targets/elixir/httpoison.js | 3 + 21 files changed, 260 insertions(+) create mode 100644 src/targets/elixir/httpoison.js create mode 100644 src/targets/elixir/index.js create mode 100644 test/fixtures/output/elixir/httpoison/application-form-encoded.ex create mode 100644 test/fixtures/output/elixir/httpoison/application-json.ex create mode 100644 test/fixtures/output/elixir/httpoison/cookies.ex create mode 100644 test/fixtures/output/elixir/httpoison/custom-method.ex create mode 100644 test/fixtures/output/elixir/httpoison/full.ex create mode 100644 test/fixtures/output/elixir/httpoison/headers.ex create mode 100644 test/fixtures/output/elixir/httpoison/https.ex create mode 100644 test/fixtures/output/elixir/httpoison/jsonObj-multiline.ex create mode 100644 test/fixtures/output/elixir/httpoison/jsonObj-null-value.ex create mode 100644 test/fixtures/output/elixir/httpoison/multipart-data.ex create mode 100644 test/fixtures/output/elixir/httpoison/multipart-file.ex create mode 100644 test/fixtures/output/elixir/httpoison/multipart-form-data.ex create mode 100644 test/fixtures/output/elixir/httpoison/nested.ex create mode 100644 test/fixtures/output/elixir/httpoison/query.ex create mode 100644 test/fixtures/output/elixir/httpoison/short.ex create mode 100644 test/fixtures/output/elixir/httpoison/text-plain.ex create mode 100644 test/targets/elixir/httpoison.js diff --git a/src/targets/elixir/httpoison.js b/src/targets/elixir/httpoison.js new file mode 100644 index 000000000..e8adaab19 --- /dev/null +++ b/src/targets/elixir/httpoison.js @@ -0,0 +1,136 @@ +/** + * @description + * HTTPoison Elixir HTTP client code snippet generator. + * + * @author + * @danirukun + * + * For any questions or issues regarding the generated code snippet, + * please open an issue mentioning the author. + */ + +'use strict' + +const CodeBuilder = require('../../helpers/code-builder') + +/** + Converts an ES6 list of objects to an Elixir KW list +*/ +const jsListToKwList = (jsList) => { + if (jsList.length === 0) return '[]' + + const kwList = jsList + .map(obj => `{"${obj.name}", "${obj.value}"}`) + .join(', ') + return `[${kwList}]` +} + +/** + Converts a list containing cookies objects into an + HTTPoison `cookie` parameter argument. +*/ +const jsCookiesToExBin = (jsCookiesList) => { + if (jsCookiesList.length === 0) return '""' + + const exBinary = jsCookiesList + .map(cookie => `${cookie.name}=${cookie.value}`) + .join('; ') + return `"${exBinary}"` +} + +/** + Converts a list of params to a Poison multipart form payload. +*/ +const jsMultiPartParamsToPoisonPayload = (jsMultiParams) => { + const [params] = jsMultiParams + const isFileUpload = 'fileName' in params + let multiPart + + if (isFileUpload) { + const { fileName, name } = params + const formData = [ + { name: 'name', value: name }, + { name: 'filename', value: fileName }] + const formDataKwList = jsListToKwList(formData) + const headers = jsListToKwList([{ name: 'content-type', value: 'multipart/form-data' }]) + + multiPart = `[{:file, "${fileName}", {"form-data", ${formDataKwList}}, ${headers}}]` + } else { + multiPart = jsListToKwList(jsMultiParams) + } + + return `{:multipart, ${multiPart}}` +} + +const isJson = (mimeType) => { + return [ + 'application/json', + 'application/x-json', + 'text/json' + ].includes(mimeType) +} + +const isMultiPartForm = (mimeType) => { + return mimeType === 'multipart/form-data' +} + +const escapeExString = (text) => { + return `~s(${text})` +} + +module.exports = (source, _options) => { + const code = new CodeBuilder() + + const { method, headers, cookies, postData: { mimeType, params } } = source + const text = `"${(source.postData.text || '')}"` + const escapedText = isJson(mimeType) + ? escapeExString(text) + : text + const payload = isMultiPartForm(mimeType) + ? jsMultiPartParamsToPoisonPayload(params) + : escapedText + + function appendHeaders (headers) { + const exHeaders = jsListToKwList(headers) + + argPlaceholders += ',\n %s' + poisonArgs = poisonArgs.concat([exHeaders]) + } + + function appendCookies (cookies) { + const exCookies = jsCookiesToExBin(cookies) + const poisonOpts = `hackney: [cookie: ${exCookies}]` + + argPlaceholders += ',\n %s' + poisonArgs = poisonArgs.concat([poisonOpts]) + } + + function appendPayload (payload) { + argPlaceholders += ',\n %s' + poisonArgs = poisonArgs.concat([payload]) + } + + let argPlaceholders = '\n :%s,\n "%s"' + let poisonArgs = [method.toLowerCase(), source.fullUrl] + + appendPayload(payload) + + if (headers.length > 0) appendHeaders(headers) + if (cookies.length > 0) { + if (headers.length === 0) appendHeaders([]) + appendCookies(cookies) + } + + argPlaceholders += '\n' + + code.push(`HTTPoison.request(${argPlaceholders})`, ...poisonArgs) + + return code.join() +} + +module.exports.info = { + key: 'httpoison', + title: 'HTTPoison', + link: 'https://github.com/edgurgel/httpoison', + description: 'HTTP client for Elixir, based on HTTPotion.' +} diff --git a/src/targets/elixir/index.js b/src/targets/elixir/index.js new file mode 100644 index 000000000..284de4da5 --- /dev/null +++ b/src/targets/elixir/index.js @@ -0,0 +1,11 @@ +'use strict' + +module.exports = { + info: { + key: 'elixir', + title: 'Elixir', + extname: '.ex', + default: 'httpoison' + }, + httpoison: require('./httpoison') +} diff --git a/src/targets/index.js b/src/targets/index.js index dd90b4874..c8a15e526 100644 --- a/src/targets/index.js +++ b/src/targets/index.js @@ -4,6 +4,7 @@ module.exports = { c: require('./c'), clojure: require('./clojure'), csharp: require('./csharp'), + elixir: require('./elixir'), go: require('./go'), http: require('./http'), java: require('./java'), diff --git a/test/fixtures/available-targets.json b/test/fixtures/available-targets.json index 7ad7857ab..9de8abeea 100644 --- a/test/fixtures/available-targets.json +++ b/test/fixtures/available-targets.json @@ -241,6 +241,20 @@ "link": "http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html", "description": "Ruby HTTP client" } + ] + }, + { + "key": "elixir", + "title": "Elixir", + "extname": ".ex", + "default": "httpoison", + "clients": [ + { + "key": "httpoison", + "title": "HTTPoison", + "link": "https://github.com/edgurgel/httpoison", + "description": "HTTP client for Elixir, based on HTTPotion." + } ] }, { diff --git a/test/fixtures/output/elixir/httpoison/application-form-encoded.ex b/test/fixtures/output/elixir/httpoison/application-form-encoded.ex new file mode 100644 index 000000000..164bfbaf1 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/application-form-encoded.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + "foo=bar&hello=world", + [{"content-type", "application/x-www-form-urlencoded"}] +) diff --git a/test/fixtures/output/elixir/httpoison/application-json.ex b/test/fixtures/output/elixir/httpoison/application-json.ex new file mode 100644 index 000000000..5c98e64e8 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/application-json.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + ~s("{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}"), + [{"content-type", "application/json"}] +) diff --git a/test/fixtures/output/elixir/httpoison/cookies.ex b/test/fixtures/output/elixir/httpoison/cookies.ex new file mode 100644 index 000000000..347717f5f --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/cookies.ex @@ -0,0 +1,7 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + "", + [], + hackney: [cookie: "foo=bar; bar=baz"] +) diff --git a/test/fixtures/output/elixir/httpoison/custom-method.ex b/test/fixtures/output/elixir/httpoison/custom-method.ex new file mode 100644 index 000000000..c80e51e7a --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/custom-method.ex @@ -0,0 +1,5 @@ +HTTPoison.request( + :propfind, + "http://mockbin.com/har", + "" +) diff --git a/test/fixtures/output/elixir/httpoison/full.ex b/test/fixtures/output/elixir/httpoison/full.ex new file mode 100644 index 000000000..ed647115f --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/full.ex @@ -0,0 +1,7 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value", + "foo=bar", + [{"accept", "application/json"}, {"content-type", "application/x-www-form-urlencoded"}], + hackney: [cookie: "foo=bar; bar=baz"] +) diff --git a/test/fixtures/output/elixir/httpoison/headers.ex b/test/fixtures/output/elixir/httpoison/headers.ex new file mode 100644 index 000000000..27c38f693 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/headers.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :get, + "http://mockbin.com/har", + "", + [{"accept", "application/json"}, {"x-foo", "Bar"}] +) diff --git a/test/fixtures/output/elixir/httpoison/https.ex b/test/fixtures/output/elixir/httpoison/https.ex new file mode 100644 index 000000000..d7cf1fa71 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/https.ex @@ -0,0 +1,5 @@ +HTTPoison.request( + :get, + "https://mockbin.com/har", + "" +) diff --git a/test/fixtures/output/elixir/httpoison/jsonObj-multiline.ex b/test/fixtures/output/elixir/httpoison/jsonObj-multiline.ex new file mode 100644 index 000000000..67c0123cf --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/jsonObj-multiline.ex @@ -0,0 +1,8 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + ~s("{ + "foo": "bar" +}"), + [{"content-type", "application/json"}] +) diff --git a/test/fixtures/output/elixir/httpoison/jsonObj-null-value.ex b/test/fixtures/output/elixir/httpoison/jsonObj-null-value.ex new file mode 100644 index 000000000..d19facc42 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/jsonObj-null-value.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + ~s("{"foo":null}"), + [{"content-type", "application/json"}] +) diff --git a/test/fixtures/output/elixir/httpoison/multipart-data.ex b/test/fixtures/output/elixir/httpoison/multipart-data.ex new file mode 100644 index 000000000..6c159a416 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/multipart-data.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + {:multipart, [{:file, "hello.txt", {"form-data", [{"name", "foo"}, {"filename", "hello.txt"}]}, [{"content-type", "multipart/form-data"}]}]}, + [{"content-type", "multipart/form-data"}] +) diff --git a/test/fixtures/output/elixir/httpoison/multipart-file.ex b/test/fixtures/output/elixir/httpoison/multipart-file.ex new file mode 100644 index 000000000..16769fdc7 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/multipart-file.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + {:multipart, [{:file, "test/fixtures/files/hello.txt", {"form-data", [{"name", "foo"}, {"filename", "test/fixtures/files/hello.txt"}]}, [{"content-type", "multipart/form-data"}]}]}, + [{"content-type", "multipart/form-data"}] +) diff --git a/test/fixtures/output/elixir/httpoison/multipart-form-data.ex b/test/fixtures/output/elixir/httpoison/multipart-form-data.ex new file mode 100644 index 000000000..a5ea78688 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/multipart-form-data.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + {:multipart, [{"foo", "bar"}]}, + [{"Content-Type", "multipart/form-data"}] +) diff --git a/test/fixtures/output/elixir/httpoison/nested.ex b/test/fixtures/output/elixir/httpoison/nested.ex new file mode 100644 index 000000000..b424c8013 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/nested.ex @@ -0,0 +1,5 @@ +HTTPoison.request( + :get, + "http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value", + "" +) diff --git a/test/fixtures/output/elixir/httpoison/query.ex b/test/fixtures/output/elixir/httpoison/query.ex new file mode 100644 index 000000000..2231219cf --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/query.ex @@ -0,0 +1,5 @@ +HTTPoison.request( + :get, + "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value", + "" +) diff --git a/test/fixtures/output/elixir/httpoison/short.ex b/test/fixtures/output/elixir/httpoison/short.ex new file mode 100644 index 000000000..f2f4de855 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/short.ex @@ -0,0 +1,5 @@ +HTTPoison.request( + :get, + "http://mockbin.com/har", + "" +) diff --git a/test/fixtures/output/elixir/httpoison/text-plain.ex b/test/fixtures/output/elixir/httpoison/text-plain.ex new file mode 100644 index 000000000..ee91fd737 --- /dev/null +++ b/test/fixtures/output/elixir/httpoison/text-plain.ex @@ -0,0 +1,6 @@ +HTTPoison.request( + :post, + "http://mockbin.com/har", + "Hello World", + [{"content-type", "text/plain"}] +) diff --git a/test/targets/elixir/httpoison.js b/test/targets/elixir/httpoison.js new file mode 100644 index 000000000..b77cc77e7 --- /dev/null +++ b/test/targets/elixir/httpoison.js @@ -0,0 +1,3 @@ +'use strict' + +module.exports = function (snippet, fixtures) {}