lib/fragmentor/parser/url.ex

defmodule Fragmentor.Parser.Url do
  @moduledoc """
  Module responsible for managing links and images urls
  inside markdown strings.
  """

  @doc """
  Returns a list of images found inside a markdown file
  considering the following types png, jpg, jpeg e gif.

  ## Example

      iex> markdown_with_images =
        \"\"\"
        content [image](https://url-to-image.com/image.jpg)
        content [ignored_image](https://url-to-image.com/image)
        link [link](https://url-to-link.com/link)
        \"\"\"

      iex> Fragmentor.Parser.Url.find_images_marks(markdown_with_images)
      [%{name: "image", url: "https://url-to-image.com/image.jpg"}]
  """
  @spec find_images_marks(nil | binary) :: list(map())
  def find_images_marks(nil), do: []

  def find_images_marks(markdown_content) do
    ~r/!\[(.+?)\]\((.+?)\)/
    |> Regex.scan(markdown_content)
    |> Enum.map(&name_captures/1)
  end

  defp name_captures([_, name, url]), do: %{name: name, url: url}

  @doc """
  Replaces urls from markdown content
  """
  @spec replace_markdown_url(binary(), list() | binary() | nil) :: binary()
  def replace_markdown_url(markdown_content, nil), do: markdown_content

  def replace_markdown_url(markdown_content, urls_list) when is_list(urls_list) do
    Enum.reduce(urls_list, markdown_content, fn url, acc ->
      case extract_link_from_markdown(url, acc) do
        %{"alt" => _alt, "link" => link} -> String.replace(acc, link, url)
        nil -> acc
      end
    end)
  end

  def replace_markdown_url(markdown_content, url) do
    case extract_link_from_markdown(url, markdown_content) do
      %{"alt" => _alt, "link" => link} -> String.replace(markdown_content, link, url)
      nil -> markdown_content
    end
  end

  defp extract_link_from_markdown(link_name, markdown) do
    regex = ~r/!(?<alt>\[#{link_name}\])\((?<link>.+?)\)/s
    Regex.named_captures(regex, markdown)
  end
end