fix: properly scope configuration modification code

fix: properly add blocks of code together
This commit is contained in:
Zach Daniel 2024-07-19 12:33:07 -04:00
parent 35bce0035e
commit bff6275c24
3 changed files with 139 additions and 114 deletions

View file

@ -132,6 +132,8 @@ defmodule Igniter.Code.Common do
end
defp do_add_code(zipper, new_code, placement, expand_env? \\ true) do
upwards = Zipper.up(zipper)
new_code =
if expand_env? do
use_aliases(new_code, zipper)
@ -139,61 +141,73 @@ defmodule Igniter.Code.Common do
new_code
end
case zipper.node do
{:__block__, meta, stuff} when length(stuff) > 1 or stuff == [] ->
new_stuff =
case new_code do
{:__block__, _, new_stuff} when length(new_stuff) > 1 or new_stuff == [] ->
if placement == :after do
stuff ++ new_stuff
else
new_code ++ stuff
end
if upwards && extendable_block?(upwards.node) do
{:__block__, _, upwards_code} = upwards.node
index = Enum.find_index(upwards_code, &(&1 == zipper.node))
new_code ->
if placement == :after do
stuff ++ [new_code]
else
[new_code | stuff]
end
to_insert =
if extendable_block?(new_code) do
{:__block__, _, new_code} = new_code
new_code
else
[new_code]
end
{head, tail} =
if placement == :after do
Enum.split(upwards_code, index + 1)
else
Enum.split(upwards_code, index)
end
Zipper.replace(upwards, {:__block__, [], head ++ to_insert ++ tail})
else
if extendable_block?(zipper.node) && extendable_block?(new_code) do
{:__block__, _, stuff} = zipper.node
{:__block__, _, new_stuff} = new_code
new_stuff =
if placement == :after do
stuff ++ new_stuff
else
new_stuff ++ stuff
end
Zipper.replace(zipper, {:__block__, meta, new_stuff})
Zipper.replace(zipper, {:__block__, [], new_stuff})
else
if extendable_block?(zipper.node) do
{:__block__, _, stuff} = zipper.node
code ->
zipper
|> Zipper.up()
|> case do
%Zipper{node: {:__block__, meta, stuff}} = upwards
when length(stuff) > 1 or stuff == [] ->
index = Enum.find_index(stuff, &(&1 == code))
new_index =
if placement == :after do
index + 1
else
index
end
new_stuff =
case new_code do
{:__block__, _, new_stuff} when length(new_stuff) > 1 or new_stuff == [] ->
{lead, trail} = Enum.split(stuff, new_index)
lead ++ new_stuff ++ trail
_ ->
List.insert_at(stuff, new_index, new_code)
end
Zipper.replace(upwards, {:__block__, meta, new_stuff})
_ ->
new_stuff =
if placement == :after do
Zipper.replace(zipper, {:__block__, [], [code, new_code]})
stuff ++ [new_code]
else
Zipper.replace(zipper, {:__block__, [], [new_code, code]})
[new_code] ++ stuff
end
Zipper.replace(zipper, {:__block__, [], new_stuff})
else
code =
if extendable_block?(new_code) do
{:__block__, _, new_stuff} = new_code
if placement == :after do
[zipper.node] ++ new_stuff
else
new_stuff ++ [zipper.node]
end
else
if placement == :after do
[zipper.node, new_code]
else
[new_code, zipper.node]
end
end
Zipper.replace(zipper, {:__block__, [], code})
end
end
end
end
@ -202,10 +216,16 @@ defmodule Igniter.Code.Common do
end
def replace_code(zipper, code) do
code = use_aliases(code, zipper)
# code = use_aliases(code, zipper)
Zipper.replace(zipper, code)
end
def extendable_block?({:__block__, meta, contents}) when is_list(contents) do
!meta[:token] && !meta[:format]
end
def extendable_block?(_), do: false
@doc """
Replaces full module names in `new_code` with any aliases for that
module found in the `current_code` environment.

View file

@ -19,21 +19,23 @@ defmodule Igniter.Code.List do
@spec prepend_new_to_list(Zipper.t(), quoted :: Macro.t(), equality_pred) ::
{:ok, Zipper.t()} | :error
def prepend_new_to_list(zipper, quoted, equality_pred \\ &Common.nodes_equal?/2) do
if list?(zipper) do
zipper
|> find_list_item_index(fn value ->
equality_pred.(value, quoted)
end)
|> case do
nil ->
prepend_to_list(zipper, quoted)
Common.within(zipper, fn zipper ->
if list?(zipper) do
zipper
|> find_list_item_index(fn value ->
equality_pred.(value, quoted)
end)
|> case do
nil ->
prepend_to_list(zipper, quoted)
_ ->
{:ok, zipper}
_ ->
{:ok, zipper}
end
else
:error
end
else
:error
end
end)
end
@doc "Appends `quoted` to the list unless it is already present, determined by `equality_pred`."

View file

@ -72,7 +72,7 @@ defmodule Igniter.Project.Config do
nil ->
{:warning, bad_config_message(app_name, file_path, config_path, value, opts)}
zipper ->
_ ->
modify_configuration_code(zipper, config_path, app_name, value, updater)
end
end)
@ -167,62 +167,65 @@ defmodule Igniter.Project.Config do
def modify_configuration_code(zipper, config_path, app_name, value, updater \\ nil) do
updater = updater || fn zipper -> {:ok, Common.replace_code(zipper, value)} end
case try_update_three_arg(zipper, config_path, app_name, value, updater) do
{:ok, zipper} ->
zipper
Zipper.within(zipper, fn zipper ->
case try_update_three_arg(zipper, config_path, app_name, value, updater) do
{:ok, zipper} ->
zipper
:error ->
case try_update_two_arg(zipper, config_path, app_name, value, updater) do
{:ok, zipper} ->
zipper
:error ->
case try_update_two_arg(zipper, config_path, app_name, value, updater) do
{:ok, zipper} ->
zipper
:error ->
[first | rest] = config_path
:error ->
[first | rest] = config_path
# this indicates its a module / not a "pretty" atom
config =
if is_atom(first) && String.downcase(to_string(first)) != to_string(first) do
{:config, [], [app_name, first, Igniter.Code.Keyword.keywordify(rest, value)]}
else
{:config, [], [app_name, [{first, Igniter.Code.Keyword.keywordify(rest, value)}]]}
# this indicates its a module / not a "pretty" atom
config =
if is_atom(first) && String.downcase(to_string(first)) != to_string(first) do
{:config, [], [app_name, first, Igniter.Code.Keyword.keywordify(rest, value)]}
else
{:config, [],
[app_name, [{first, Igniter.Code.Keyword.keywordify(rest, value)}]]}
end
case Igniter.Code.Function.move_to_function_call_in_current_scope(
zipper,
:import,
1,
fn function_call ->
Igniter.Code.Function.argument_matches_predicate?(
function_call,
0,
&Common.nodes_equal?(&1, Config)
)
end
) do
{:ok, zipper} ->
zipper
|> Zipper.right()
|> case do
nil ->
Common.add_code(zipper, config)
zipper ->
Common.add_code(zipper, config, :before)
end
:error ->
zipper
|> Zipper.right()
|> case do
nil ->
Common.add_code(zipper, config)
zipper ->
Common.add_code(zipper, config, :before)
end
end
case Igniter.Code.Function.move_to_function_call_in_current_scope(
zipper,
:import,
1,
fn function_call ->
Igniter.Code.Function.argument_matches_predicate?(
function_call,
0,
&Common.nodes_equal?(&1, Config)
)
end
) do
{:ok, zipper} ->
zipper
|> Zipper.right()
|> case do
nil ->
Common.add_code(zipper, config)
zipper ->
Common.add_code(zipper, config, :before)
end
:error ->
zipper
|> Zipper.right()
|> case do
nil ->
Common.add_code(zipper, config)
zipper ->
Common.add_code(zipper, config, :before)
end
end
end
end
end
end
end)
end
@doc """