lib/absinthe_generator.ex

defmodule AbsintheGenerator do
  @doc "This callback is for each resource to create it's own struct"
  @callback run(resource_struct :: struct) :: any

  @moduledoc File.read!("./README.md")

  @locals_without_parens [
    import_types: 1,
    import_fields: 1,
    arg: 2,
    field: 2,
    field: 3,
    middleware: 1,
    middleware: 2,
    resolve: 1,
    value: 1,
    value: 2
  ]

  def moduledoc, do: @moduledoc

  def run(%resource_struct{} = struct_data), do: resource_struct.run(struct_data)

  def ensure_list_of_structs(list, struct, field_name) do
    case Enum.find(list, &(not is_struct(&1, struct))) do
      nil -> :ok
      non_struct -> raise "The list of #{field_name} must be a list of %#{inspect struct}{} but instead found:\n#{inspect non_struct}"
    end
  end

  def template_path(template_name, ext \\ "ex") do
    Path.join(:code.priv_dir(:absinthe_generator), "templates/#{template_name}.#{ext}.eex")
  end

  def evaluate_template(template_path, assigns) do
    template_path
      |> EEx.eval_file(assigns)
      |> attempt_to_format_template
  end

  defp attempt_to_format_template(code) do
    Code.format_string!(code, locals_without_parens: @locals_without_parens)

    rescue
      SyntaxError ->
        reraise "Error inside the resulting template: \n #{code}", __STACKTRACE__
  end

  def serialize_struct_to_config(structs) when is_list(structs) do
    Enum.map(structs, &serialize_struct_to_config/1)
  end

  def serialize_struct_to_config(struct) when is_struct(struct) do
    struct
      |> Map.from_struct
      |> serialize_struct_to_config
  end

  def serialize_struct_to_config(struct) when is_map(struct) do
    Enum.reduce(struct, [], fn
      ({_, nil}, acc) -> acc

      ({key, value}, acc) when is_struct(value) or is_list(value) ->
        Keyword.put(acc, key, serialize_struct_to_config(value))

      ({key, value}, acc) when is_map(value) ->
        Keyword.put(acc, key, serialize_struct_to_config(value))

      ({key, value}, acc) -> Keyword.put(acc, key, value)
    end)
  end

  def serialize_struct_to_config(value) do
    value
  end
end