lib/ash/resource/transformers/default_accept.ex

defmodule Ash.Resource.Transformers.DefaultAccept do
  @moduledoc "Sets the default `accept` for each action"

  use Spark.Dsl.Transformer

  alias Spark.Dsl.Transformer

  def transform(dsl_state) do
    public_attribute_names =
      dsl_state
      |> Transformer.get_entities([:attributes])
      |> Enum.reject(& &1.private?)
      |> Enum.map(& &1.name)

    default_accept =
      Transformer.get_option(
        dsl_state,
        [:actions],
        :default_accept
      ) || public_attribute_names

    dsl_state
    |> Transformer.get_entities([:actions])
    |> Enum.reduce({:ok, dsl_state}, fn
      %{type: :read}, {:ok, _dsl_state} = acc ->
        acc

      action, {:ok, dsl_state} ->
        if is_list(action.accept) && is_list(action.reject) &&
             !MapSet.disjoint?(MapSet.new(action.accept), MapSet.new(action.reject)) do
          raise Spark.Error.DslError,
            path: [:actions, action.name],
            message: "accept and reject keys cannot overlap"
        end

        {accept, reject} =
          case {action.accept, action.reject} do
            {_, :all} ->
              {[], public_attribute_names}

            {nil, reject} ->
              {reject(if(action.type != :destroy, do: default_accept, else: []), reject), reject}

            {:all, reject} ->
              {reject(public_attribute_names, reject), reject}

            {accept, reject} ->
              {reject(accept, reject), reject}
          end

        new_dsl_state =
          Transformer.replace_entity(
            dsl_state,
            [:actions],
            %{action | accept: accept, reject: reject},
            &(&1.name == action.name && &1.type == action.type)
          )

        {:ok, new_dsl_state}
    end)
  end

  defp reject(list, reject) do
    Enum.reject(list, &(&1 in reject))
  end

  def after?(Ash.Resource.Transformers.BelongsToSourceField), do: true
  def after?(Ash.Resource.Transformers.BelongsToAttribute), do: true
  def after?(Ash.Resource.Transformers.CreateJoinRelationship), do: true
  def after?(Ash.Resource.Transformers.ValidatePrimaryActions), do: true
  def after?(_), do: false
end