From 1ff6b38b03a6c0f8319384a658087253cfa74319 Mon Sep 17 00:00:00 2001 From: Dan Schultzer <1254724+danschultzer@users.noreply.github.com> Date: Sun, 19 Nov 2023 16:01:40 -0800 Subject: [PATCH] Enforce formatting --- .formatter.exs | 3 ++ .github/workflows/ci.yml | 1 + lib/premailex/html_inline_styles.ex | 33 +++++++++---- lib/premailex/html_parser/floki.ex | 6 +-- lib/premailex/html_parser/meeseeks.ex | 2 +- lib/premailex/http_adapter.ex | 13 ++--- lib/premailex/http_adapter/httpc.ex | 24 ++++++---- mix.exs | 16 +++++-- test/premailex/html_inline_styles_test.exs | 55 +++++++++++++++------- test/premailex/html_to_plain_text_test.exs | 2 + 10 files changed, 105 insertions(+), 50 deletions(-) create mode 100644 .formatter.exs diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..682fc6c --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,3 @@ +[ + inputs: ["{mix,.formatter}.exs", "{lib,test}/**/*.{ex,exs}"] +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09f5b86..a911300 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ jobs: - run: mix deps.get - run: mix compile --warnings-as-errors - run: mix credo --strict + - run: mix format --check-formatted test: strategy: diff --git a/lib/premailex/html_inline_styles.ex b/lib/premailex/html_inline_styles.ex index 3d99c88..6674d71 100644 --- a/lib/premailex/html_inline_styles.ex +++ b/lib/premailex/html_inline_styles.ex @@ -16,26 +16,34 @@ defmodule Premailex.HTMLInlineStyles do * `:all` - apply all optimization steps * `:remove_style_tags` - Remove style tags (can be combined in a list) """ - @spec process(String.t() | HTMLParser.html_tree(), [CSSParser.rule_set()] | nil, Keyword.t() | nil) :: String.t() + @spec process( + String.t() | HTMLParser.html_tree(), + [CSSParser.rule_set()] | nil, + Keyword.t() | nil + ) :: String.t() def process(html_or_html_tree, css_rule_sets_or_options \\ nil, options \\ nil) + def process(html, css_rule_sets_or_options, options) when is_binary(html) do html |> HTMLParser.parse() |> process(css_rule_sets_or_options, options) end + def process(html_tree, css_rule_sets_or_options, nil) do case Keyword.keyword?(css_rule_sets_or_options) do - true -> process(html_tree, nil, css_rule_sets_or_options) + true -> process(html_tree, nil, css_rule_sets_or_options) false -> process(html_tree, css_rule_sets_or_options, []) end end + def process(html_tree, nil, options) do - css_selector = Keyword.get(options, :css_selector, "style,link[rel=\"stylesheet\"][href]") + css_selector = Keyword.get(options, :css_selector, "style,link[rel=\"stylesheet\"][href]") css_rule_sets = load_styles(html_tree, css_selector) - options = Keyword.put_new(options, :css_selector, css_selector) + options = Keyword.put_new(options, :css_selector, css_selector) process(html_tree, css_rule_sets, options) end + def process(html_tree, css_rules_sets, options) do optimize_steps = Keyword.get(options, :optimize, :none) optimize_options = Keyword.take(options, [:css_selector]) @@ -67,16 +75,17 @@ defmodule Premailex.HTMLInlineStyles do end) visible_html_tree = - Enum.reduce(hidden_elements, html_tree, fn {_index, hidden_element, placeholder}, html_tree -> + Enum.reduce(hidden_elements, html_tree, fn {_index, hidden_element, placeholder}, + html_tree -> Util.traverse_until_first(html_tree, hidden_element, fn _element -> placeholder end) end) styles |> Enum.reduce(visible_html_tree, &add_rule_set_to_html(&1, &2)) |> Util.traverse("premailex", fn {"premailex", attrs, _children} -> - {"data-index", index} = Enum.find(attrs, & elem(&1, 0) == "data-index") + {"data-index", index} = Enum.find(attrs, &(elem(&1, 0) == "data-index")) - {_index, hidden_element, _replacement} = Enum.find(hidden_elements, & elem(&1, 0) == index) + {_index, hidden_element, _replacement} = Enum.find(hidden_elements, &(elem(&1, 0) == index)) hidden_element end) @@ -98,14 +107,17 @@ defmodule Premailex.HTMLInlineStyles do |> parse_body(http_adapter, url) end - defp parse_body({:ok, %{status: status, body: body}}, _http_adapter, _url) when status in 200..399 do + defp parse_body({:ok, %{status: status, body: body}}, _http_adapter, _url) + when status in 200..399 do CSSParser.parse(body) end + defp parse_body({:ok, %{status: status}}, _http_adapter, url) do Logger.warning("Ignoring #{url} styles because received unexpected HTTP status: #{status}") nil end + defp parse_body({:error, error}, http_adapter, url) do Logger.warning( "Ignoring #{url} styles because of unexpected error from #{inspect(http_adapter)}:\n\n#{inspect(error)}" @@ -173,7 +185,7 @@ defmodule Premailex.HTMLInlineStyles do |> CSSParser.merge() |> CSSParser.to_string() |> case do - "" -> current_style + "" -> current_style style -> style end @@ -194,6 +206,7 @@ defmodule Premailex.HTMLInlineStyles do end defp maybe_remove_style_tags(tree, _steps, nil), do: tree + defp maybe_remove_style_tags(tree, steps, css_selector) do case Enum.member?(steps, :remove_style_tags) do true -> HTMLParser.filter(tree, css_selector) @@ -212,7 +225,7 @@ defmodule Premailex.HTMLInlineStyles do defp http_adapter do case Application.get_env(:premailex, :http_adapter, Premailex.HTTPAdapter.Httpc) do {adapter, opts} -> {adapter, opts} - adapter -> {adapter, nil} + adapter -> {adapter, nil} end end end diff --git a/lib/premailex/html_parser/floki.ex b/lib/premailex/html_parser/floki.ex index 490470b..4df1103 100644 --- a/lib/premailex/html_parser/floki.ex +++ b/lib/premailex/html_parser/floki.ex @@ -13,13 +13,13 @@ defmodule Premailex.HTMLParser.Floki do "< 0.24.0" |> floki_version_match?() |> case do - true -> apply(Floki, :parse, args) + true -> apply(Floki, :parse, args) false -> apply(Floki, :parse_document, args) end |> case do - {:ok, [html]} -> html + {:ok, [html]} -> html {:ok, document} -> document - any -> any + any -> any end end diff --git a/lib/premailex/html_parser/meeseeks.ex b/lib/premailex/html_parser/meeseeks.ex index 623a058..3f6032b 100644 --- a/lib/premailex/html_parser/meeseeks.ex +++ b/lib/premailex/html_parser/meeseeks.ex @@ -54,7 +54,7 @@ defmodule Premailex.HTMLParser.Meeseeks do @doc false def filter(tree, selector) do selector = CSS.compile_selectors(selector) - tree = Meeseeks.parse(tree, :tuple_tree) + tree = Meeseeks.parse(tree, :tuple_tree) tree |> Meeseeks.all(selector) diff --git a/lib/premailex/http_adapter.ex b/lib/premailex/http_adapter.ex index 9637a72..0ec7645 100644 --- a/lib/premailex/http_adapter.ex +++ b/lib/premailex/http_adapter.ex @@ -5,11 +5,11 @@ defmodule Premailex.HTTPAdapter do @moduledoc false @type header :: {binary(), binary()} - @type t :: %__MODULE__{ - status: integer(), - headers: [header()], - body: binary() - } + @type t :: %__MODULE__{ + status: integer(), + headers: [header()], + body: binary() + } defstruct status: 200, headers: [], body: "" end @@ -18,7 +18,8 @@ defmodule Premailex.HTTPAdapter do @type body :: binary() | nil @type headers :: [{binary(), binary()}] - @callback request(method(), binary(), body(), headers(), Keyword.t()) :: {:ok, map()} | {:error, any()} + @callback request(method(), binary(), body(), headers(), Keyword.t()) :: + {:ok, map()} | {:error, any()} @spec user_agent_header() :: {binary(), binary()} def user_agent_header do diff --git a/lib/premailex/http_adapter/httpc.ex b/lib/premailex/http_adapter/httpc.ex index c302f21..f3f1446 100644 --- a/lib/premailex/http_adapter/httpc.ex +++ b/lib/premailex/http_adapter/httpc.ex @@ -20,8 +20,8 @@ defmodule Premailex.HTTPAdapter.Httpc do end defp httpc_request(url, body, headers) do - url = to_charlist(url) - headers = Enum.map(headers, fn {k, v} -> {to_charlist(k), to_charlist(v)} end) + url = to_charlist(url) + headers = Enum.map(headers, fn {k, v} -> {to_charlist(k), to_charlist(v)} end) do_httpc_request(url, body, headers) end @@ -29,26 +29,32 @@ defmodule Premailex.HTTPAdapter.Httpc do defp do_httpc_request(url, nil, headers) do {url, headers} end + defp do_httpc_request(url, body, headers) do {content_type, headers} = split_content_type_headers(headers) - body = to_charlist(body) + body = to_charlist(body) {url, headers, content_type, body} end defp split_content_type_headers(headers) do - case List.keytake(headers, 'content-type', 0) do - nil -> {'text/plain', headers} + case List.keytake(headers, ~c"content-type", 0) do + nil -> {~c"text/plain", headers} {{_, ct}, headers} -> {ct, headers} end end defp format_response({:ok, {{_, status, _}, headers, body}}) do - headers = Enum.map(headers, fn {key, value} -> {String.downcase(to_string(key)), to_string(value)} end) - body = IO.iodata_to_binary(body) + headers = + Enum.map(headers, fn {key, value} -> + {String.downcase(to_string(key)), to_string(value)} + end) + + body = IO.iodata_to_binary(body) {:ok, %HTTPResponse{status: status, headers: headers, body: body}} end + defp format_response({:error, error}), do: {:error, error} defp parse_httpc_opts(nil, url), do: default_httpc_opts(url) @@ -56,7 +62,7 @@ defmodule Premailex.HTTPAdapter.Httpc do defp default_httpc_opts(url) do case certifi_and_ssl_verify_fun_available?() do - true -> [ssl: ssl_opts(url)] + true -> [ssl: ssl_opts(url)] false -> [] end end @@ -71,7 +77,7 @@ defmodule Premailex.HTTPAdapter.Httpc do defp app_available?(app) do case :application.get_key(app, :vsn) do {:ok, _vsn} -> true - _ -> false + _ -> false end end diff --git a/mix.exs b/mix.exs index aa8d650..fd64cef 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,16 @@ defmodule Premailex.Mixfile do elixir: "~> 1.11", start_permanent: Mix.env() == :prod, deps: deps(), - xref: [exclude: [:certifi, :httpc, Meeseeks, Meeseeks.Document, Meeseeks.Selector.CSS, :ssl_verify_hostname]], + xref: [ + exclude: [ + :certifi, + :httpc, + Meeseeks, + Meeseeks.Document, + Meeseeks.Selector.CSS, + :ssl_verify_hostname + ] + ], # Hex description: "Add inline styling to your HTML emails, and transform them to text", @@ -31,13 +40,12 @@ defmodule Premailex.Mixfile do defp deps do [ {:floki, "~> 0.19"}, - {:meeseeks, "~> 0.11", optional: true}, {:certifi, ">= 0.0.0", optional: true}, {:ssl_verify_fun, ">= 0.0.0", optional: true}, - - {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, + # Development and test {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, + {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, {:test_server, "~> 0.1.5", only: [:test]} ] end diff --git a/test/premailex/html_inline_styles_test.exs b/test/premailex/html_inline_styles_test.exs index 7ffa7a5..4630ec2 100644 --- a/test/premailex/html_inline_styles_test.exs +++ b/test/premailex/html_inline_styles_test.exs @@ -100,7 +100,10 @@ defmodule Premailex.HTMLInlineStylesTest do @input _ -> - TestServer.add("/styles.css", to: fn conn -> Plug.Conn.send_resp(conn, 200, @css_link_content) end) + TestServer.add("/styles.css", + to: fn conn -> Plug.Conn.send_resp(conn, 200, @css_link_content) end + ) + String.replace(@input, "http://localhost", TestServer.url()) end @@ -134,14 +137,20 @@ defmodule Premailex.HTMLInlineStylesTest do refute parsed =~ "This is a comment" - assert parsed =~ ~r/(#{Regex.escape("")})|(#{Regex.escape("")})/ - assert parsed =~ ~r/(#{Regex.escape("")})|(#{Regex.escape("")})/ assert parsed =~ - "
Downlevel-revealed comment
" - assert parsed =~ ~r/(#{Regex.escape("")})|(#{Regex.escape("")})/ + ~r/(#{Regex.escape("")})|(#{Regex.escape("")})/ + + assert parsed =~ + "Downlevel-revealed comment
" + + assert parsed =~ + ~r/(#{Regex.escape("")})|(#{Regex.escape("")})/ assert parsed =~ "