defmodule MishkaInstaller.Helper.Extra do
@moduledoc """
You can find some utility functions in this module. It will be merged with the other helper module.
"""
@doc """
With this function, you can extract some basic information from a `mix` file by AST.
## Examples
```elixir
MishkaInstaller.Helper.Extra .ast_mix_file_basic_information(ast, [:app, :version, :source_url], [{:tag, tag}])
```
### Reference
- https://elixirforum.com/t/getting-basic-information-of-a-elixir-project-from-github/48231/7
"""
def ast_mix_file_basic_information(ast, selection, extra \\ []) do
Enum.map(selection, fn item ->
{_ast, acc} =
Macro.postwalk(ast, %{"#{item}": nil, attributes: %{}}, fn
{:@, _, [{name, _, value}]} = ast, acc when is_atom(name) and not is_nil(value) ->
{ast, put_in(acc.attributes[name], value)}
{^item, {:@, _, [{name, _, nil}]}} = ast, acc ->
{ast, Map.put(acc, item, {:attribute, name})}
{^item, value} = ast, acc ->
{ast, Map.put(acc, item, value)}
ast, acc ->
{ast, acc}
end)
convert_ast_output(acc)
end) ++ extra
end
# I duplicated the code to make this operation clear instead of getting dynamically and make it complicated.
defp convert_ast_output(%{version: {:attribute, item}, attributes: attributes}),
do: {:version, List.first(Map.get(attributes, item))}
defp convert_ast_output(%{version: ver, attributes: _attributes}) when is_binary(ver),
do: {:version, ver}
defp convert_ast_output(%{app: {:attribute, item}, attributes: attributes}),
do: {:app, List.first(Map.get(attributes, item))}
defp convert_ast_output(%{app: ver, attributes: _attributes}) when is_atom(ver), do: {:app, ver}
defp convert_ast_output(%{source_url: {:attribute, item}, attributes: attributes}),
do: {:source_url, List.first(Map.get(attributes, item))}
defp convert_ast_output(%{source_url: ver, attributes: _attributes}) when is_binary(ver),
do: {:source_url, ver}
defp convert_ast_output(_), do: {:error, :package, :convert_ast_output}
end