mirror of
https://github.com/ash-project/igniter.git
synced 2024-09-19 13:02:51 +12:00
fix: properly scope configuration modification code
fix: properly add blocks of code together
This commit is contained in:
parent
35bce0035e
commit
bff6275c24
3 changed files with 139 additions and 114 deletions
|
@ -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.
|
||||
|
|
|
@ -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`."
|
||||
|
|
|
@ -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 """
|
||||
|
|
Loading…
Reference in a new issue