bonfire-app/lib/mix/tasks/docs/docs_deps.ex
Mayel de Borniol 9abca8200a misc
2022-11-25 10:34:43 +13:00

110 lines
3 KiB
Elixir

defmodule Mix.Tasks.Docs.Deps do
use Mix.Task
@shortdoc "Generates docs for your app and its all deps"
@recursive true
@root Bonfire.Common.Config.get(:root_path)
@moduledoc """
`mix docs.deps`
## Command line options
* `--only` - the environment to include dependencies for
* `--target` - the target to include dependencies for
* `--exclude` - exclude dependencies which you do not want to see in docs.
* any arguments supported by `mix docs` will be passed along
"""
@switches [only: :string, target: :string, exclude: :keep]
@impl true
def run(args) do
Mix.Project.get!()
{opts, args, _} = OptionParser.parse(args, switches: @switches)
deps_opts =
for {switch, key} <- [only: :env, target: :target],
value = opts[switch],
do: {key, :"#{value}"}
excluded = Keyword.get_values(opts, :exclude)
deps =
Mix.Dep.load_on_environment(deps_opts)
|> prepare_list(opts)
|> List.flatten()
|> Enum.reject(&(Atom.to_string(dep_name(&1)) in excluded))
|> Enum.uniq_by(&dep_name(&1))
config = Mix.Project.config()
build_path = Mix.Project.build_path()
docs_config = Keyword.get(config, :docs, [])
docs_config =
docs_config
|> Keyword.put(:deps, Enum.map(deps, &{dep_name(&1), "./"}))
|> Keyword.put(
:source_beam,
Enum.map(
deps,
&Path.join([build_path, "lib", Atom.to_string(dep_name(&1)), "ebin"])
)
)
|> Keyword.put(
:extras,
Keyword.get(docs_config, :extras, []) ++
Enum.flat_map(deps, &readme_path/1)
)
Mix.Tasks.Docs.run(args, Keyword.put(config, :docs, docs_config))
end
defp prepare_list(deps, opts) when is_list(deps) do
Enum.flat_map(deps, fn
%Mix.Dep{deps: nested_deps} = dep ->
[dep] ++ prepare_list(nested_deps, opts)
dep ->
[dep]
end)
end
defp readme_path(dep) when not is_nil(dep),
do: dep_paths(dep, "README.md") |> List.first() |> readme_path(dep)
defp readme_path(path, dep) when not is_nil(path),
do: [{String.to_atom(path), [filename: "extension-#{dep_name(dep)}"]}]
defp readme_path(_, _), do: []
defp dep_path(dep) do
path =
if is_list(dep) && dep[:path],
do: dep[:path],
else: (Mix.Project.deps_path() <> "/#{dep_name(dep)}") |> Path.expand(@root)
path_if_exists(path)
end
defp dep_paths(dep, extra) when is_list(extra),
do: Enum.flat_map(extra, &dep_paths(dep, &1))
defp dep_paths(dep, extra) when is_binary(extra) do
dep_path = dep_path(dep)
if dep_path do
path = Path.join(dep_path, extra) |> path_if_exists()
if path, do: [path], else: []
else
[]
end
end
defp dep_name(%Mix.Dep{app: dep}) when is_atom(dep), do: dep
defp dep_name(dep) when is_tuple(dep), do: elem(dep, 0) |> dep_name()
defp dep_name(dep) when is_atom(dep), do: dep
defp dep_name(dep) when is_binary(dep), do: dep
defp path_if_exists(path), do: if(File.exists?(path), do: path)
end