Skip to content

Commit

Permalink
Merge pull request #167 from liveview-native/bc-mix-lvn-setup
Browse files Browse the repository at this point in the history
mix lvn.setup
  • Loading branch information
bcardarella authored Apr 16, 2024
2 parents 54b8c45 + 560ba8a commit 3ccf0c2
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 102 deletions.
85 changes: 50 additions & 35 deletions lib/live_view_native/component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -121,54 +121,69 @@ defmodule LiveViewNative.Component do

declarative_opts = Keyword.drop(opts, [:as, :format, :root])

case LiveViewNative.fetch_plugin(format) do
component_ast = quote do
import Phoenix.LiveView.Helpers
import Kernel, except: [def: 2, defp: 2]
import Phoenix.Component, except: [
embed_templates: 1, embed_templates: 2,
sigitl_H: 2,

async_result: 1,
dynamic_tag: 1,
focus_wrap: 1,
form: 1,
inputs_for: 1,
intersperse: 1,
link: 1,
live_component: 1,
live_file_input: 1,
live_img_preview: 1,
live_title: 1
]
import Phoenix.Component.Declarative
require Phoenix.Template

for {prefix_match, value} <- Phoenix.Component.Declarative.__setup__(__MODULE__, unquote(declarative_opts)) do
@doc false
def __global__?(prefix_match), do: value
end

import LiveViewNative.Renderer, only: [
delegate_to_target: 1,
delegate_to_target: 2,
embed_templates: 1,
embed_templates: 2
]

def __native_opts__, do: @native_opts
end

plugin_component_ast = case LiveViewNative.fetch_plugin(format) do
{:ok, plugin} ->
quote do
import Phoenix.LiveView.Helpers
import Kernel, except: [def: 2, defp: 2]
import Phoenix.Component, except: [
embed_templates: 1, embed_templates: 2,
sigitl_H: 2,

async_result: 1,
dynamic_tag: 1,
focus_wrap: 1,
form: 1,
inputs_for: 1,
intersperse: 1,
link: 1,
live_component: 1,
live_file_input: 1,
live_img_preview: 1,
live_title: 1
]
import Phoenix.Component.Declarative
require Phoenix.Template

for {prefix_match, value} <- Phoenix.Component.Declarative.__setup__(__MODULE__, unquote(declarative_opts)) do
@doc false
def __global__?(prefix_match), do: value
end

use unquote(plugin.component)
import LiveViewNative.Renderer, only: [
delegate_to_target: 1,
delegate_to_target: 2,
embed_templates: 1,
embed_templates: 2
]

if (unquote(opts[:as])) do
@before_compile LiveViewNative.Renderer
end

@before_compile LiveViewNative.Component
end

:error ->
IO.warn("tried to load LiveViewNative plugin for format #{inspect(format)} but none was found")
if is_nil(format) do
quote do
import LiveViewNative.Component, only: [sigil_LVN: 2]
end
else
IO.warn("tried to load LiveViewNative plugin for format #{inspect(format)} but none was found")

[]
end

[]
end

[component_ast, plugin_component_ast]
end

@doc false
Expand Down
15 changes: 12 additions & 3 deletions lib/mix/live_view_native/context.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
defmodule Mix.LiveViewNative.Context do
@moduledoc false

defstruct context_app: nil,
base_module: nil,
schema_module: nil,
Expand All @@ -16,14 +18,14 @@ defmodule Mix.LiveViewNative.Context do
|> caller.validate_args!()
|> parse_args()

ctx_app = parsed_opts[:context_app] || Mix.Phoenix.context_app()
base_module = Module.concat([Mix.Phoenix.context_base(ctx_app)])
context_app = parsed_opts[:context_app] || Mix.Phoenix.context_app()
base_module = Module.concat([Mix.Phoenix.context_base(context_app)])
native_module = Module.concat([inspect(base_module) <> "Native"])
web_module = Mix.Phoenix.web_module(base_module)
native_path = Path.join(["native", Atom.to_string(format)])

%__MODULE__{
context_app: ctx_app,
context_app: context_app,
base_module: base_module,
schema_module: schema_module,
native_module: native_module,
Expand Down Expand Up @@ -112,4 +114,11 @@ defmodule Mix.LiveViewNative.Context do
defp put_context_app(opts, string) do
Keyword.put(opts, :context_app, String.to_atom(string))
end

defmacro compile_string(string) do
EEx.compile_string(string)
end

def last?(plugins, plugin),
do: Enum.at(plugins, -1) == plugin
end
93 changes: 39 additions & 54 deletions lib/mix/tasks/lvn.gen.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
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__)

files = files_to_be_generated(context)
if Keyword.get(context.opts, :copy, true) do
files = files_to_be_generated(context)
Context.prompt_for_conflicts(files)

Context.prompt_for_conflicts(files)
copy_new_files(context, files)
end

context
|> copy_new_files(files)
|> print_shell_instructions()
if Keyword.get(context.opts, :info, true) do
print_shell_instructions(context)
end
end

def print_shell_instructions(context) do
Expand All @@ -19,15 +26,6 @@ defmodule Mix.Tasks.Lvn.Gen do
|> print_config()
|> print_router()
|> print_endpoint()
|> print_post_instructions()
end

def last?(plugins, plugin) do
Enum.at(plugins, -1) == plugin
end

defmacro compile_string(string) do
EEx.compile_string(string)
end

def print_instructions(context) do
Expand All @@ -48,51 +46,37 @@ defmodule Mix.Tasks.Lvn.Gen do

plugins? = length(plugins) > 0

stylesheet? =
Mix.Project.deps_apps()
|> Enum.member?(:live_view_native_stylesheet)

"""
\e[93;1m# config/config.exs\e[0m
# LVN - registers each available plugin<%= unless plugins? do %>
# \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
]
# LVN - Each format must be registered as a mime type
# add to existing configuration if one exists as this will
# overwrite
# \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 you want to inspect LVN stylesheets from your browser add the `style` type
# "text/styles" => ["styles"],<%= 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
}
<%= if stylesheet? do %># LVN - Required, you must configure LiveView Native Stylesheets
# on which file path patterns class names should be extracted from
config :live_view_native_stylesheet,
content: [\e[32;1m<%= if plugins? do %><%= for plugin <- plugins do %>
<%= plugin.format %>: [
"lib/**/*<%= plugin.format %>*"
]<%= unless last?(plugins, plugin) do %>,<% end %><% end %><% else %>
# swiftui: ["lib/**/*swiftui*"]<% end %>\e[0m
],
output: "priv/static/assets"
<% end %>
# LVN - Required, you must configure Phoenix to know how
# to encode for the swiftui format
# \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
]
# LVN - Required, you must configure Phoenix so it knows
# how to compile LVN's neex templates
# \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
]
Expand All @@ -118,15 +102,17 @@ defmodule Mix.Tasks.Lvn.Gen do
))

"""
\e[93;1m# lib/<%= Phoenix.Naming.underscore(context.web_module) %>/router.ex\e[0m
\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 %>
Expand All @@ -142,9 +128,10 @@ defmodule Mix.Tasks.Lvn.Gen do

def print_endpoint(context) do
"""
\e[93;1m# lib/<%= Phoenix.Naming.underscore(context.web_module) %>/endpoint.ex\e[0m
\e[93;1m# lib/<%= Macro.underscore(context.web_module) %>/endpoint.ex\e[0m
# add the LiveViewNative.LiveRealoder to your endpoint
# \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
Expand All @@ -159,36 +146,28 @@ defmodule Mix.Tasks.Lvn.Gen do
context
end

def print_post_instructions(context) do
"""
After you have configured your application you should run the following:
* `mix lvn.gen.layout <plaform>`
* `mix lvn.gen.stylsheet <platform> App`
"""
|> Mix.shell().info()

context
end

def switches, do: [
context_app: :string,
web: :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 = Phoenix.Naming.underscore(context.native_module) <> ".ex"
file = Macro.underscore(context.native_module) <> ".ex"

[{:eex, "app_name_native.ex", Path.join(path, file)}]
end
Expand All @@ -200,12 +179,18 @@ defmodule Mix.Tasks.Lvn.Gen do

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)
Expand Down
Loading

0 comments on commit 3ccf0c2

Please sign in to comment.