igniter/lib/deps.ex

119 lines
3.8 KiB
Elixir
Raw Normal View History

2024-05-28 15:30:41 +12:00
defmodule Igniter.Deps do
@moduledoc "Codemods and utilities for managing dependencies declared in mix.exs"
2024-06-13 10:22:08 +12:00
require Igniter.Code.Common
alias Igniter.Code.Common
alias Sourceror.Zipper
2024-05-28 15:30:41 +12:00
2024-06-04 15:14:36 +12:00
def add_dependency(igniter, name, version, yes? \\ false) do
if name in List.wrap(igniter.assigns[:manually_installed]) do
igniter
else
case get_dependency_declaration(igniter, name) do
nil ->
do_add_dependency(igniter, name, version)
2024-05-28 15:30:41 +12:00
2024-06-04 15:14:36 +12:00
current ->
desired = "`{#{inspect(name)}, #{inspect(version)}}`"
current = "`#{current}`"
2024-05-28 15:30:41 +12:00
2024-06-04 15:14:36 +12:00
if desired == current do
2024-05-28 15:30:41 +12:00
igniter
else
2024-06-04 15:14:36 +12:00
if yes? ||
Mix.shell().yes?("""
Dependency #{name} is already in mix.exs. Should we replace it?
Desired: #{desired}
Found: #{current}
""") do
igniter
|> remove_dependency(name)
|> do_add_dependency(name, version)
else
igniter
end
2024-05-28 15:30:41 +12:00
end
2024-06-04 15:14:36 +12:00
end
2024-05-28 15:30:41 +12:00
end
end
def get_dependency_declaration(igniter, name) do
zipper =
igniter
|> Igniter.include_existing_elixir_file("mix.exs")
|> Map.get(:rewrite)
|> Rewrite.source!("mix.exs")
|> Rewrite.Source.get(:quoted)
|> Zipper.zip()
2024-06-13 10:22:08 +12:00
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
true <- Common.node_matches_pattern?(zipper, value when is_list(value)),
{:ok, current_declaration} <-
2024-06-13 10:22:08 +12:00
Igniter.Code.List.move_to_list_item(zipper, fn item ->
if Igniter.Code.Tuple.tuple?(item) do
case Igniter.Code.Tuple.tuple_elem(item, 0) do
{:ok, first_elem} ->
Common.node_matches_pattern?(first_elem, ^name)
:error ->
false
end
end
end) do
current_declaration
|> Zipper.subtree()
|> Zipper.node()
|> Sourceror.to_string()
else
_ ->
nil
end
end
2024-05-28 15:30:41 +12:00
defp remove_dependency(igniter, name) do
igniter
2024-06-04 05:13:49 +12:00
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
2024-06-13 10:22:08 +12:00
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
2024-06-04 05:13:49 +12:00
true <- Common.node_matches_pattern?(zipper, value when is_list(value)),
current_declaration_index when not is_nil(current_declaration_index) <-
2024-06-13 10:22:08 +12:00
Igniter.Code.List.find_list_item_index(zipper, fn item ->
if Igniter.Code.Tuple.tuple?(item) do
case Igniter.Code.Tuple.tuple_elem(item, 0) do
{:ok, first_elem} ->
Common.node_matches_pattern?(first_elem, ^name)
:error ->
false
end
2024-06-04 05:13:49 +12:00
end
end) do
2024-06-13 10:22:08 +12:00
Igniter.Code.List.remove_index(zipper, current_declaration_index)
2024-05-28 15:30:41 +12:00
else
2024-06-04 05:13:49 +12:00
_ ->
{:error, "Failed to remove dependency #{inspect(name)}"}
2024-05-28 15:30:41 +12:00
end
end)
end
defp do_add_dependency(igniter, name, version) do
igniter
2024-06-04 05:13:49 +12:00
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
2024-06-13 10:22:08 +12:00
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
2024-06-04 05:13:49 +12:00
true <- Common.node_matches_pattern?(zipper, value when is_list(value)) do
quoted =
quote do
{unquote(name), unquote(version)}
end
2024-05-28 15:30:41 +12:00
2024-06-13 10:22:08 +12:00
Igniter.Code.List.prepend_to_list(zipper, quoted)
2024-05-28 15:30:41 +12:00
else
2024-06-04 05:13:49 +12:00
_ ->
{:error, "Failed to add dependency #{inspect({inspect(name), inspect(version)})}"}
2024-05-28 15:30:41 +12:00
end
end)
end
end