Current section

Files

Jump to
aqua lib aquapm project_parser.ex
Raw

lib/aquapm/project_parser.ex

defmodule Aqua.ProjectParser do
@spec parse_project(code :: String.t()) ::
{:ok, Keyword.t()} | {:error, :bad_project} | {:error, :mix_corrupted}
def parse_project(code) do
case get_ast(code) do
{:ok, ast} ->
{module_name, injected_ast} = patch_module(ast)
Code.compile_quoted(injected_ast)
case Kernel.function_exported?(module_name, :project, 0) do
true -> {:ok, Kernel.apply(module_name, :project, [])}
false -> {:error, :bad_project}
end
{:error, _} ->
{:error, :mix_corrupted}
end
end
def get_ast(code) do
Code.string_to_quoted(code)
end
@spec name_for_path(binary(), atom()) :: any()
# Case for absolute path
def name_for_path(<<"./", path::binary()>>, app_name) do
# Throwing away "/lib" and generating as is
case path do
<<"lib/", cleared_path::binary()>> -> do_name_for_path(cleared_path)
weird_path -> do_name_for_path(weird_path, app_name)
end
end
def name_for_path(relative, app_name) do
do_name_for_path(relative, app_name)
end
defp do_name_for_path(path, app_name \\ nil) do
reversed_path =
path
|> String.split("/")
|> Enum.reverse()
[filename | namespace] = reversed_path
normalized_modulename =
case Enum.reverse(String.split(filename, ".")) do
[name | []] -> [name]
[_ext | name] -> name
end
|> Enum.reverse()
|> Enum.join("_")
namespace_path = [normalized_modulename | namespace] |> Enum.reverse()
case app_name do
nil -> namespace_path
atom -> [Atom.to_string(atom) | namespace_path]
end
|> Enum.map(fn path_part -> Macro.camelize(path_part) end)
|> Module.concat()
end
def patch_module(
{:defmodule, defmodule_env, [{:__aliases__, aliases_env, aliases_list}, do_list]}
) do
{
Module.concat([:Aqua | [:Sandbox | aliases_list]]),
{:defmodule, defmodule_env,
[{:__aliases__, aliases_env, [:Aqua | [:Sandbox | aliases_list]]}, patch_do_list(do_list)]}
}
end
defp patch_do_list(do: {:__block__, block_args, do_inner_list}) do
[do: {:__block__, block_args, Enum.map(do_inner_list, &patch_do_inner/1)}]
end
defp patch_do_inner({:use, use_env, [{:__aliases__, aliases_env, [:Mix, :Project]}]}) do
{:use, use_env, [{:__aliases__, aliases_env, [:Aqua, :SandboxProject]}]}
end
defp patch_do_inner(any), do: any
end