Current section
Files
Jump to
Current section
Files
lib/wac_gen/router.ex
defmodule Wac.Gen.Router do
@moduledoc false
alias Sourceror.Zipper
alias Wac.Gen.GeneratorError
@format_opts [
locals_without_parens: [
plug: :*,
get: :*,
scope: :*,
delete: :*,
live: :*,
post: :*,
forward: :*,
live_dashboard: :*,
live_session: :*,
pipe_through: :*
]
]
def update_router(assigns) do
web_snake_case = Keyword.fetch!(assigns, :web_snake_case)
router_path = Path.join(["lib", web_snake_case, "router.ex"])
modified_router_contents =
router_path
|> File.read!()
|> Sourceror.parse_string!()
|> Zipper.zip()
|> Zipper.find(&find_aliases/1)
|> insert_aliases(assigns)
|> Zipper.find(&find_browser_pipeline/1)
|> insert_plugs()
|> Zipper.find(&find_first_scope/1)
|> insert_routes(assigns)
|> Zipper.root()
|> Sourceror.to_string(@format_opts)
File.write!(router_path, modified_router_contents)
status = IO.ANSI.red() <> "* updating " <> IO.ANSI.reset() <> router_path
IO.puts(status)
end
defp insert_aliases(%Zipper{} = zipper, assigns) do
aliases = aliases(assigns)
zipper
|> Zipper.insert_right(aliases)
end
defp insert_aliases(nil, _assigns) do
raise GeneratorError, "Unable to find aliases"
end
defp insert_plugs(%Zipper{} = zipper) do
plug_fetch_current_user = plug_fetch_current_user()
zipper
|> Zipper.insert_right(plug_fetch_current_user)
end
defp insert_plugs(nil) do
raise GeneratorError, "Unable to find the browser pipeline"
end
defp insert_routes(%Zipper{} = zipper, assigns) do
session_routes = session_routes(assigns)
guest_routes = guest_routes(assigns)
authenticated_routes = authenticated_routes(assigns)
zipper
|> Zipper.insert_right(authenticated_routes)
|> Zipper.insert_right(guest_routes)
|> Zipper.insert_right(session_routes)
end
defp insert_routes(nil, _assigns) do
raise GeneratorError, "Unable to find the first router scope"
end
defp find_aliases({:use, _meta, [{_, _, _}, {:__block__, _, [:router]} | _]}), do: true
# defp find_aliases({:defmodule, _meta, [{_, _, _} | _]}), do: true
defp find_aliases(_), do: false
defp find_browser_pipeline({:plug, _, [{:__block__, _, [:put_secure_browser_headers]} | _]}),
do: true
defp find_browser_pipeline(_), do: false
defp find_first_scope({:scope, _, [{:__block__, _, ["/"]} | _]}), do: true
defp find_first_scope(_), do: false
# AST Trees
defp aliases(assigns) do
web_pascal_case = assigns[:web_pascal_case]
"""
alias #{inspect(web_pascal_case)}.SessionHooks.AssignUser
alias #{inspect(web_pascal_case)}.SessionHooks.RequireUser
import #{inspect(web_pascal_case)}.Session, only: [fetch_current_user: 2]
"""
|> Sourceror.parse_string!()
end
defp plug_fetch_current_user do
"""
plug :fetch_current_user
"""
|> Sourceror.parse_string!()
end
defp session_routes(assigns) do
web_pascal_case = assigns[:web_pascal_case]
"""
# HTTP controller routes
scope "/", #{inspect(web_pascal_case)} do
pipe_through :browser
post "/session", Session, :create
delete "/session", Session, :delete
end
"""
|> Sourceror.parse_string!()
end
defp guest_routes(assigns) do
web_pascal_case = assigns[:web_pascal_case]
"""
# Unprotected LiveViews
live_session :guest, on_mount: [AssignUser] do
scope "/", #{inspect(web_pascal_case)} do
pipe_through :browser
live "/sign-in", AuthenticationLive
end
end
"""
|> Sourceror.parse_string!()
end
defp authenticated_routes(assigns) do
web_pascal_case = assigns[:web_pascal_case]
"""
# Protected LiveViews
live_session :authenticated, on_mount: [AssignUser, RequireUser] do
scope "/", #{inspect(web_pascal_case)} do
pipe_through :browser
# Example
# live "/room/:room_id", RoomLive
end
end
"""
|> Sourceror.parse_string!()
end
end