Current section
Files
Jump to
Current section
Files
lib/documenter/phoenix/router.ex
defmodule APIDoc.PhoenixRouterDocumenter do
@moduledoc ~S"""
"""
require Logger
alias APIDoc.{Doc.Endpoint, Documenter.Helper}
defmacro __using__(_) do
quote do
unquote(Helper.register())
@before_compile APIDoc.PhoenixRouterDocumenter
end
end
defmacro __before_compile__(env) do
doc =
env.module
|> Module.get_attribute(:phoenix_routes)
|> Enum.sort_by(& &1.line)
|> document(
Module.get_attribute(env.module, :param),
Module.get_attribute(env.module, :response)
)
|> :lists.reverse()
quote do
@doc false
@spec __api_doc__ :: [APIDoc.Doc.Endpoint.t()]
def __api_doc__ do
unquote(Macro.escape(doc))
|> Enum.map(fn
%{lookup: {module, _, :forward}, fallback: fallback = %{path: path}} ->
if {:__api_doc__, 0} in module.__info__(:functions) do
Enum.map(
module.__api_doc__,
fn e = %Endpoint{path: p} -> %{e | path: path ++ p} end
)
else
fallback
end
%{lookup: {module, name, _}, fallback: fallback} ->
if {:__controller_doc__, 0} in module.__info__(:functions) do
case Map.fetch(module.__controller_doc__(), name) do
{:ok, doc} -> %{doc | method: fallback.method, path: fallback.path}
_ -> fallback
end
else
fallback
end
end)
|> List.flatten()
end
end
end
defp document(routes, params, response, acc \\ [])
defp document([], _params, _responses, acc), do: acc
defp document([%{verb: :*, kind: kind} | routes], params, responses, acc) when kind != :forward,
do: document(routes, params, responses, acc)
defp document([route | routes], params, responses, acc) do
params_g = Enum.group_by(params, &(&1.line < route.line))
responses_g = Enum.group_by(responses, &(&1.line < route.line))
document(routes, params_g[false] || [], responses_g[false] || [], [
%{
lookup: {route.plug, Map.get(route, :opts, Map.get(route, :plug_opts)), route.kind},
fallback: %Endpoint{
id: route.path,
tags: [],
summary: nil,
method: route.verb,
path: parse_path(route.path),
description: nil,
parameters: params_g[true] || [],
responses: responses_g[true] || []
}
}
| acc
])
end
defp parse_path(path) do
path
|> String.trim_leading("/")
|> String.split("/")
|> Enum.map(fn
"*" <> var -> String.to_atom(var)
":" <> var -> String.to_atom(var)
var -> var
end)
end
end