defmodule Phosphor.Generated.Builder do @moduledoc false alias Phosphor.Generated.Manifest @weights Manifest.weights() defmacro __using__(_opts) do icons = Manifest.icons() icon_modules = for icon <- icons do build_icon_module(icon) end function_components = for icon <- icons do build_function_component(icon) end quote do unquote_splicing(icon_modules) unquote_splicing(function_components) end end defp build_icon_module(icon) do name = Map.fetch!(icon, :name) module = icon_module(name) weights = ordered_weights(icon) default_weight = icon_default_weight(icon, weights) weight_defs = for weight <- weights do svg = icon |> Map.fetch!(:svgs) |> Map.fetch!(weight) svg_ast = Macro.escape(svg) weight_fun = weight quote do @doc false def unquote(weight_fun)(assigns) do Phosphor.__render_svg__(assigns, unquote(svg_ast), [:weight, :name]) end end end weights_ast = Macro.escape(weights) default_ast = Macro.escape(default_weight) quote do defmodule unquote(module) do use Phoenix.Component @moduledoc false @weights unquote(weights_ast) @default_weight unquote(default_ast) def icon(assigns) do assigns = Phosphor.__ensure_assigns__(assigns) requested = Map.get(assigns, :weight) weight = Phosphor.__resolve_weight__(requested, @weights, @default_weight) apply(__MODULE__, weight, [assigns]) end @doc false def weights, do: @weights unquote_splicing(weight_defs) end end end defp build_function_component(icon) do name = Map.fetch!(icon, :name) module = icon_module(name) function_name = icon_function(name) quote do @doc false def unquote(function_name)(assigns) do unquote(module).icon(assigns) end end end defp icon_module(name) do camel = name |> String.replace("-", "_") |> Macro.camelize() Module.concat(Phosphor, camel) end defp icon_function(name) do name |> String.replace("-", "_") |> String.to_atom() end defp ordered_weights(icon) do icon_weights = icon |> Map.fetch!(:svgs) |> Map.keys() |> MapSet.new() @weights |> Enum.filter(&MapSet.member?(icon_weights, &1)) end defp icon_default_weight(icon, []), do: Map.get(icon, :default_weight, :regular) defp icon_default_weight(icon, weights) do case Map.get(icon, :default_weight) do nil -> Enum.find(weights, fn weight -> weight == :regular end) || hd(weights) weight -> if weight in weights do weight else Enum.find(weights, fn candidate -> candidate == :regular end) || hd(weights) end end end end