defmodule Mix.Tasks.Moon.Convert.Component do @shortdoc "Converts surface component to phoenix_live_view" @moduledoc """ Converts component from surface to live_view format $ mix moon.convert.component Form.MyModule """ use Mix.Task import Mix.Generator import Moon.Convert import Moon.Convert.{Ast} import String, only: [replace: 3, downcase: 1, split: 2] import List, only: [last: 1] require Logger defstruct name: nil @doc false def run([name]) do name |> to_module() |> context() |> copy_templates() |> print_shell_instructions() end defp to_module(name, pathes \\ ~w(Design Moon)) do Module.safe_concat([name | pathes] |> Enum.reverse()) rescue ArgumentError -> to_module(name, tl(pathes)) end defp context(module) do %{ module: module, short: module |> to_string() |> split(".") |> last(), component_type: module.component_type(), level: 0, config: %{ use_translates: fn [:Moon, :StatelessComponent] -> [:Moon, :Light, :Component] [:Moon, :StatefulComponent] -> [:Moon, :Light, :LiveComponent] other -> other end, defmodule_translates: fn [:Moon, :Design | others] -> [:Moon, :Light | others] [:Moon, :Lego | others] -> [:Moon, :Light, :Lego | others] [:MoonWeb, :Examples, :Design | others] -> [:MoonWeb, :Examples, :Light | others] end, module_translates: fn mod -> [ :"Elixir" | mod |> to_string() |> String.replace("Elixir.", "") |> String.split(".") |> Enum.map(&String.to_atom/1) |> (fn [:Moon, :Design | others] -> [:Moon, :Light | others] [:Moon, :Lego | others] -> [:Moon, :Light, :Lego | others] [:MoonWeb, :Examples, :Design | others] -> [:MoonWeb, :Examples, :Light | others] other -> other end).() ] |> Enum.join(".") |> String.to_atom() end } } end defp copy_templates(context = %{component_type: Surface.LiveComponent}) do context.module |> context.config.module_translates.() |> module_to_path() |> create_file( surface_to_liveview(context) |> Macro.to_string() |> String.replace(" :skip\n", "") ) context end defp copy_templates(context = %{component_type: Surface.Component}) do target_module = context.module |> parent_module() |> context.config.module_translates.() target_module |> module_to_path() |> create_file( case target_module |> Code.ensure_compiled() do {:module, _} -> target_module |> module_ast() {:error, :nofile} -> "priv/templates/moon.convert.component/empty_module.ex" |> EEx.eval_file(name: target_module) |> Code.string_to_quoted!() end |> merge_ast(surface_to_liveview(context)) |> Macro.to_string() |> String.replace(" :skip\n", "") ) context end defp module_to_path(module) do (module |> to_string() |> replace(~r/([a-z])([A-Z])/, "\\1_\\2") |> downcase() |> replace(".", "/") |> replace("elixir/", "lib/")) <> ".exs" end def print_shell_instructions(_) do Mix.shell().info(""" """) end end