In my humble opinion, trying to do this with Credo is a masochistic exercise. Consider the following bit of valid code:
defmodule MyAppWeb.Schema.Finance.MoneyTypes do
use Absinthe.Schema.Notation
@desc "UNUSED 1"
@desc "MONEY 1"
object :money do
description("MONEY 2")
field :amount, :decimal
@desc "CURRENCY 1"
field :currency, :string do
description("CURRENCY 2")
end
end
end
The credo checker will have to handle (possibly flag) unused @desc attributes, identify duplicate descriptions (which can use different syntax), and deal with the fact the you will have to consider AST tuples with first element in [:object, :node, :field], each of which may or may not have an associated do block.
It's not impossible but it's arduous and prone to breaking (if Absinthe introduces a new object syntax or description shorthand).
In short, I think what you are trying to do should be done using already well-developed GraphQL introspection tools.
Consider the following module:
defmodule MyAppWeb.Schema.IntrospectionUtils do
@moduledoc """
Convenience functions for inspecting the schema
"""
@doc """
iex> missing_desc_list(MyAppWeb.Schema)
[...]
"""
def missing_desc_list(schema_module) do
schema_module
|> type_names_and_descs()
|> missing_descs()
end
defp type_names_and_descs(schema_module) do
case " {__schema {types {name description fields {name description}}}} "
|> Absinthe.run(schema_module) do
{:ok, %{data: %{"__schema" => %{"types" => types}}}} -> types
_ -> raise("Unable to get types name and descs map")
end
end
defp missing_descs(types) do
types
|> Enum.reduce([], &missing_type_descs/2)
end
# ignore type names that start with double underscore
defp missing_type_descs(%{"name" => "__" <> _}, acc), do: acc
defp missing_type_descs(%{"name" => name, "description" => nil, "fields" => fields}, acc) do
missing_field_descs(fields, ["type #{name} is missing a description" | acc], name)
end
defp missing_type_descs(%{"name" => name, "description" => desc, "fields" => fields}, acc)
when is_binary(desc) do
missing_field_descs(fields, acc, name)
end
defp missing_field_descs(nil, acc, _type_name), do: acc
# ignore type names that start with double underscore
defp missing_field_descs(_fields, acc, "__" <> _), do: acc
defp missing_field_descs(fields, acc, type_name) when is_list(fields) do
fields
|> Enum.reduce(acc, &missing_field_descs(&1, &2, type_name))
end
defp missing_field_descs(%{"name" => name, "description" => nil}, acc, type_name) do
["field #{name} on type #{type_name} is missing a description" | acc]
end
defp missing_field_descs(_field, acc, _type_name), do: acc
end
It's not very elegant but it shows how you easily get a list of all missing documentation by spinning up your app with iex -S mix (or iex -S mix phx.server) and typing:
MyAppWeb.Schema.IntrospectionUtils.missing_desc_list(MyAppWeb.Schema)
Note that I have added some functions to "ignore" schema type names starting with 2 underscores __. This indicates a built-in GQ type and should not require a description.
Note also that my code is only illustrative of an approach and has not been tested or reviewed. It could probably be a lot better.
This approach can be used as part of CI or similar but it cannot be run like a normal Mix task or Credo checker because the app needs to be running for it to work.