Repository: derekkraan/curl_req
Pull request #9 (2024-06-16 12:15:00)

Multiline Curl commands
This PR parses the URI from the rest of the `OptionParser`. This makes it more stable and reliable and supports newlines because they get filtered out


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf0cf51..8d9d8be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 # Changelog
 
 ## 0.98.5
+- Multiline Curl commands are now supported
 
 ## 0.98.4
 - Add CurlReq.Plugin
diff --git a/README.md b/README.md
index ad7514d..7e5e9bf 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ The docs can be found at <https://hexdocs.pm/curl_req>.
 
 Contributions are welcome! There are gaps in the library, and this is open source, so let's work together to fill them!
 
-- [ ] ~CURL sigil handles newlines
+- [x] ~CURL sigil handles newlines
 - [x] curl [url]
 - [x] curl -H
 - [x] curl -X
diff --git a/lib/curl_req/macro.ex b/lib/curl_req/macro.ex
index 609c74b..86e1ff8 100644
--- a/lib/curl_req/macro.ex
+++ b/lib/curl_req/macro.ex
@@ -1,8 +1,6 @@
 defmodule CurlReq.Macro do
   @moduledoc false
 
-  # TODO: handle newlines
-
   @spec parse(String.t()) :: Req.Request.t()
   def parse(command) do
     command =
@@ -10,7 +8,7 @@ defmodule CurlReq.Macro do
       |> String.trim()
       |> String.trim_leading("curl")
 
-    {options, [url], _invalid} =
+    {options, rest, _invalid} =
       command
       |> OptionParser.split()
       |> OptionParser.parse(
@@ -36,10 +34,19 @@ defmodule CurlReq.Macro do
         ]
       )
 
-    url = String.trim(url)
+    [url] =
+      rest
+      |> Enum.flat_map(fn part ->
+        case URI.new(part) do
+          {:ok, uri} -> [uri]
+          _ -> []
+        end
+      end)
 
     %Req.Request{}
-    |> Req.merge(url: url)
+    # Req would accept an URI struct but here we use to_string/1 because Req uses URI.parse/1 which sets the deprecated `authority` field which upsets the test assertions.
+    # Can be removed the Req uses URI.new/1
+    |> Req.merge(url: URI.to_string(url))
     |> add_header(options)
     |> add_method(options)
     |> add_body(options)


Test patch:
diff --git a/test/curl_req/macro_test.exs b/test/curl_req/macro_test.exs
index fe0862c..cd9ce93 100644
--- a/test/curl_req/macro_test.exs
+++ b/test/curl_req/macro_test.exs
@@ -122,4 +122,39 @@ defmodule CurlReq.MacroTest do
                }
     end
   end
+
+  describe "newlines" do
+    test "sigil_CURL supports newlines" do
+      curl = ~CURL"""
+        curl -X POST \
+         --location \ 
+         https://example.com
+      """
+
+      assert curl == %Req.Request{
+               method: :post,
+               url: URI.parse("https://example.com"),
+               registered_options: MapSet.new([:redirect]),
+               options: %{redirect: true},
+               response_steps: [redirect: &Req.Steps.redirect/1]
+             }
+    end
+
+    test "from_curl supports newlines" do
+      curl =
+        from_curl("""
+          curl -X POST \
+           --location \ 
+           https://example.com
+        """)
+
+      assert curl == %Req.Request{
+               method: :post,
+               url: URI.parse("https://example.com"),
+               registered_options: MapSet.new([:redirect]),
+               options: %{redirect: true},
+               response_steps: [redirect: &Req.Steps.redirect/1]
+             }
+    end
+  end
 end