defmodule Mix.Tasks.Lvn.Gen do alias Mix.LiveViewNative.Context import Mix.LiveViewNative.Context, only: [ compile_string: 1, last?: 2 ] def run(args) do context = Context.build(args, __MODULE__) if Keyword.get(context.opts, :copy, true) do files = files_to_be_generated(context) Context.prompt_for_conflicts(files) copy_new_files(context, files) end if Keyword.get(context.opts, :info, true) do print_shell_instructions(context) end end def print_shell_instructions(context) do context |> print_instructions() |> print_config() |> print_dev() |> print_router() |> print_endpoint() end def print_instructions(context) do """ The following are configurations that should be added to your application. Follow each section as there are multiple files that require editing. """ |> Mix.shell().info() context end def print_config(context) do plugins = LiveViewNative.plugins() |> Map.values() plugins? = length(plugins) > 0 """ \e[93;1m# config/config.exs\e[0m # \e[91;1mLVN - Required\e[0m # Registers each available plugin<%= unless plugins? do %> \e[93;1m# Hint: if you add this config to your app populated with client plugins # and run `mix lvn.gen` this configuration's placeholders will be populated\e[0m<% end %> config :live_view_native, plugins: [\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %> LiveViewNative.<%= plugin.module_suffix %><%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %> # LiveViewNative.SwiftUI<% end %>\e[0m ] # \e[91;1mLVN - Required\e[0m # Each format must be registered as a mime type add to # existing configuration if one exists as this will overwrite config :mime, :types, %{\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %> "text/<%= plugin.format %>" => ["<%= plugin.format %>"]<%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %> # "text/swiftui" => ["swiftui"]<% end %>\e[0m } # \e[91;1mLVN - Required\e[0m # Phoenix must know how to encode each LVN format config :phoenix_template, :format_encoders, [\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %> <%= plugin.format %>: Phoenix.HTML.Engine<%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %> # swiftui: Phoenix.HTML.Engine<% end %>\e[0m ] # \e[91;1mLVN - Required\e[0m # Phoenix must know how to compile neex templates config :phoenix, :template_engines, [ \e[32;1mneex: LiveViewNative.Engine\e[0m ] """ |> compile_string() |> Mix.shell().info() context end def print_dev(context) do """ \e[93;1m# config/dev.exs\e[0m # \e[36mLVN - Optional\e[0m # Allows LVN templates to be subject to LiveReload changes config :<% context.context_app %>, <%= inspect context.web_module %>.Endpoint, live_reload: [ patterns: [ ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", ~r"priv/gettext/.*(po)$", ~r"lib/anotherone_web/(controllers|live|components)/.*(ex|heex\e[32;1m|neex\e[0m)$" ] ] """ |> compile_string() |> Mix.shell().info() context end def print_router(context) do plugins = LiveViewNative.plugins() |> Map.values() plugins? = length(plugins) > 0 layouts = [html: {Module.concat(context.web_module, Layouts), :root}] |> Kernel.++( plugins |> Enum.map(&({&1.format, {Module.concat([context.web_module, Layouts, &1.module_suffix]), :root}}) )) """ \e[93;1m# lib/<%= Macro.underscore(context.web_module) %>/router.ex\e[0m # \e[91;1mLVN - Required\e[0m # add the formats to the `accepts` plug for the pipeline used by your LiveView Native app plug :accepts, [ "html",\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %> "<%= plugin.format %>"<%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %> # "swiftui"<% end %>\e[0m ] # \e[91;1mLVN - Required\e[0m # add the root layout for each format plug :put_root_layout, [ html: <%= inspect(layouts[:html]) %>,\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %> <%= plugin.format %>: <%= inspect(layouts[plugin.format]) %><%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %> # swiftui: {<%= inspect(layouts[:html] |> elem(0)) %>, :root}<% end %>\e[0m ] """ |> compile_string() |> Mix.shell().info() context end def print_endpoint(context) do """ \e[93;1m# lib/<%= Macro.underscore(context.web_module) %>/endpoint.ex\e[0m # \e[36mLVN - Optional\e[0m # Add the LiveViewNative.LiveRealoder to your endpoint if code_reloading? do socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket plug Phoenix.LiveReloader \e[32;1mplug LiveViewNative.LiveReloader\e[0m plug Phoenix.CodeReloader plug Phoenix.Ecto.CheckRepoStatus, otp_app: :form_demo end """ |> compile_string() |> Mix.shell.info() context end def switches, do: [ context_app: :string, web: :string, info: :boolean, copy: :boolean, live_form: :boolean ] def validate_args!([]), do: [nil] def validate_args!(_args) do Mix.raise(""" mix lvn.gen does not take any arguments, only the following switches: --no-live-form --context-app --web """) end defp files_to_be_generated(context) do path = Mix.Phoenix.context_app_path(context.context_app, "lib") file = Macro.underscore(context.native_module) <> ".ex" [{:eex, "app_name_native.ex", Path.join(path, file)}] end defp copy_new_files(%Context{} = context, files) do plugins = LiveViewNative.plugins() |> Map.values() plugins? = length(plugins) > 0 apps = Mix.Project.deps_apps() live_form? = Keyword.get(context.opts, :live_form, true) && Enum.member?(apps, :live_view_native_live_form) binding = [ context: context, plugins: plugins, plugins?: plugins?, last?: &last?/2, assigns: %{ live_form?: live_form?, gettext: true, formats: formats(), layouts: layouts(context.web_module) } ] Mix.Phoenix.copy_from([".", :live_view_native], "priv/templates/lvn.gen", binding, files) context end defp formats do LiveViewNative.available_formats() end defp layouts(web_module) do Enum.map(formats(), fn(format) -> format_module = format |> LiveViewNative.fetch_plugin!() |> Map.fetch!(:module_suffix) {format, {Module.concat([web_module, Layouts, format_module]), :app}} end) end end