Packages
igniter
0.6.2
0.8.2
0.8.1
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.30
0.6.29
0.6.28
0.6.27
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.52
0.5.51
0.5.50
0.5.49
0.5.48
0.5.47
0.5.46
0.5.45
0.5.44
0.5.43
0.5.42
0.5.41
0.5.40
0.5.39
0.5.38
0.5.37
0.5.36
0.5.35
0.5.34
0.5.33
0.5.32
0.5.31
0.5.30
0.5.29
0.5.28
0.5.27
0.5.26
0.5.25
0.5.24
0.5.23
0.5.22
0.5.21
0.5.20
0.5.19
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.78
0.3.77
0.3.76
0.3.75
0.3.74
0.3.73
0.3.72
0.3.71
0.3.70
0.3.69
0.3.68
0.3.67
0.3.66
0.3.65
0.3.64
0.3.63
0.3.62
0.3.61
0.3.60
0.3.59
0.3.58
0.3.57
0.3.56
0.3.55
0.3.54
0.3.53
0.3.52
0.3.51
0.3.50
0.3.49
0.3.48
0.3.47
0.3.46
0.3.45
0.3.44
0.3.43
0.3.42
0.3.41
0.3.40
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A code generation and project patching framework
Current section
Files
Jump to
Current section
Files
lib/igniter/project/task_aliases.ex
defmodule Igniter.Project.TaskAliases do
@moduledoc "Codemods and utilities for interacting with task aliases in the mix.exs file"
@doc """
Adds an alias to the mix.exs file
# Options
- `:if_exists` - How to alter the alias if it already exists. Options are:
- `:ignore` - Do nothing if the alias already exists. This is the default.
- `:prepend` - Add the new alias to the beginning of the list (if it is not already present).
- `{:prepend, value}` - Add a different value than the originally supplied alias to the beginning of the list (if it is not already present).
- `{:replace_or_append, old, new}` - If the old value is in the list, it is replaced with the new value. Otherwise the new value is appended (if it is not already present).
- `:append` - Add the new alias to the end of the list (if it is not already present).
- `{:append, value}` - Add a different value than the originally supplied alias to the end of the list (if it is not already present).
- `:warn` - Print a warning if the alias already exists.
"""
@spec add_alias(
Igniter.t(),
atom() | String.t(),
String.t() | {:code, term()} | list(String.t() | {:code, term()}),
opts :: Keyword.t()
) :: Igniter.t()
def add_alias(igniter, name, value, opts \\ []) do
alter =
case Keyword.get(opts, :if_exists, :ignore) do
:append -> {:append, value}
:prepend -> {:prepend, value}
other -> other
end
name =
if is_binary(name) do
String.to_atom(name)
else
name
end
igniter
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
case go_to_aliases(zipper) do
{:ok, zipper} ->
case alter do
{:replace_or_append, old, new} ->
case Igniter.Code.Keyword.set_keyword_key(
zipper,
name,
value,
&replace_or_append(&1, old, new, value)
) do
{:ok, zipper} ->
{:ok, zipper}
:error ->
{:warning,
"""
Could not modify mix task aliases. Attempted to alias `#{name}` to:
#{Sourceror.to_string(value)}
Please manually modify your `mix.exs` file accordingly.
"""}
end
{prepend_or_append, add_value} when prepend_or_append in [:prepend, :append] ->
case Igniter.Code.Keyword.set_keyword_key(
zipper,
name,
value,
&prepend_or_append(&1, add_value, prepend_or_append)
) do
{:ok, zipper} ->
{:ok, zipper}
:error ->
{:warning,
"""
Could not modify mix task aliases. Attempted to alias `#{name}` to:
#{Sourceror.to_string(value)}
Please manually modify your `mix.exs` file accordingly.
"""}
end
other ->
case Igniter.Code.Keyword.get_key(zipper, name) do
{:ok, _} ->
case other do
:ignore ->
{:ok, zipper}
:warn ->
{:warning,
"""
Could not add alias for `#{name}` in `mix.exs` because it already exists. Attempted to alias it to:
#{Sourceror.to_string(value)}
"""}
end
:error ->
case Igniter.Code.Keyword.set_keyword_key(zipper, name, value, &{:ok, &1}) do
{:ok, zipper} ->
{:ok, zipper}
:error ->
{:warning,
"""
Could not modify mix task aliases. Attempted to alias `#{name}` to:
#{Sourceror.to_string(value)}
Please manually modify your `mix.exs` file accordingly.
"""}
end
end
end
:error ->
{:warning,
"""
Could not modify mix task aliases. Attempted to alias `#{name}` to:
#{Sourceror.to_string(value)}
Please manually modify your `mix.exs` file accordingly.
"""}
end
end)
end
@doc "Modifies an existing alias, doing nothing if it doesn't exist"
@spec modify_existing_alias(
Igniter.t(),
atom() | String.t(),
(Sourceror.Zipper.t() ->
{:ok, Sourceror.Zipper.t()} | :error)
) :: Igniter.t()
def modify_existing_alias(igniter, name, updater) do
igniter
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
name =
if is_binary(name) do
String.to_atom(name)
else
name
end
case go_to_aliases(zipper) do
{:ok, zipper} ->
case Igniter.Code.Keyword.get_key(zipper, name) do
{:ok, zipper} ->
updater.(zipper)
:error ->
zipper
end
:error ->
zipper
end
end)
end
defp prepend_or_append(zipper, value, prepend_or_append) when is_list(value) do
if prepend_or_append == :prepend do
Enum.reverse(value)
else
value
end
|> Enum.reduce_while({:ok, zipper}, fn value, {:ok, zipper} ->
case prepend_or_append(zipper, value, prepend_or_append) do
{:ok, zipper} -> {:cont, {:ok, zipper}}
:error -> {:halt, :error}
end
end)
end
defp prepend_or_append(zipper, value, :append) do
zipper =
if Igniter.Code.List.list?(zipper) do
zipper
else
Igniter.Code.Common.replace_code(zipper, [zipper.node])
end
Igniter.Code.List.append_new_to_list(zipper, value)
end
defp prepend_or_append(zipper, value, :prepend) do
zipper =
if Igniter.Code.List.list?(zipper) do
zipper
else
Igniter.Code.Common.replace_code(zipper, [zipper.node])
end
Igniter.Code.List.prepend_new_to_list(zipper, value)
end
defp replace_or_append(zipper, old, new, value) do
zipper =
if Igniter.Code.List.list?(zipper) do
zipper
else
Igniter.Code.Common.replace_code(zipper, [zipper.node])
end
case Igniter.Code.List.move_to_list_item(zipper, &Igniter.Code.Common.nodes_equal?(&1, old)) do
{:ok, zipper} ->
# TODO: this is very dumb. We need a special value that signifies you've
# been given AST vs a value, like `%Igniter.AST{}` or something, and default to assuming
# that what you've been given is a value.
new =
if is_binary(new) do
{:__block__,
[
trailing_comments: [],
leading_comments: [],
delimiter: "\""
], [new]}
else
new
end
{:ok, Igniter.Code.Common.replace_code(zipper, new)}
_ ->
Igniter.Code.List.append_new_to_list(zipper, value)
end
end
defp go_to_aliases(zipper) do
with {:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, :aliases, 0),
zipper <- Igniter.Code.Common.rightmost(zipper),
true <- Igniter.Code.List.list?(zipper) do
{:ok, zipper}
else
_ ->
with {:ok, zipper} <- Igniter.Code.Function.move_to_def(zipper, :project, 0),
zipper <- Igniter.Code.Common.rightmost(zipper),
true <- Igniter.Code.List.list?(zipper),
{:aliases_key, _zipper, {:ok, zipper}} <-
{:aliases_key, zipper, Igniter.Code.Keyword.get_key(zipper, :aliases)},
{:aliases_is_list?, zipper, true} <-
{:aliases_is_list?, zipper, Igniter.Code.List.list?(zipper)} do
{:ok, zipper}
else
{:aliases_key, zipper, :error} ->
with {:ok, zipper} <-
Igniter.Code.Keyword.set_keyword_key(
zipper,
:aliases,
quote do
aliases()
end,
&{:ok, &1}
),
{:ok, zipper} <-
Igniter.Code.Common.move_upwards(
zipper,
&Igniter.Code.Function.function_call?(&1, :defmodule)
),
{:ok, zipper} <- Igniter.Code.Common.move_to_do_block(zipper) do
zipper
|> Igniter.Code.Common.add_code("""
defp aliases() do
[]
end
""")
|> go_to_aliases()
else
_ ->
:error
end
{:aliases_is_list?, zipper, false} ->
if Igniter.Code.Function.function_call?(zipper) do
case Igniter.Code.Function.get_local_function_call_name(zipper) do
{:ok, name} ->
with {:ok, zipper} <-
Igniter.Code.Common.move_upwards(
zipper,
&Igniter.Code.Function.function_call?(&1, :defmodule)
),
{:ok, zipper} <- Igniter.Code.Common.move_to_do_block(zipper),
{:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, name, 0),
zipper <- Igniter.Code.Common.rightmost(zipper),
true <- Igniter.Code.List.list?(zipper) do
{:ok, zipper}
else
_ ->
:error
end
:error ->
:error
end
else
:error
end
_ ->
:error
end
end
end
end