defmodule Mix.Tasks.Phx.Routes do use Mix.Task alias Phoenix.Router.ConsoleFormatter @shortdoc "Prints all routes" @moduledoc """ Prints all routes for the default or a given router. $ mix phx.routes $ mix phx.routes MyApp.AnotherRouter The default router is inflected from the application name unless a configuration named `:namespace` is set inside your application configuration. For example, the configuration: config :my_app, namespace: My.App will exhibit the routes for `My.App.Router` when this task is invoked without arguments. Umbrella projects do not have a default router and therefore always expect a router to be given. An alias can be added to mix.exs to automate this: defp aliases do [ "phx.routes": "phx.routes MyAppWeb.Router", # aliases... ] """ @doc false def run(args, base \\ Mix.Phoenix.base()) do Mix.Task.run("compile", args) Mix.Task.reenable("phx.routes") {router_mod, opts} = case OptionParser.parse(args, switches: [endpoint: :string, router: :string]) do {opts, [passed_router], _} -> {router(passed_router, base), opts} {opts, [], _} -> {router(opts[:router], base), opts} end router_mod |> ConsoleFormatter.format(endpoint(opts[:endpoint], base)) |> Mix.shell().info() end defp endpoint(nil, base) do loaded(web_mod(base, "Endpoint")) end defp endpoint(module, _base) do loaded(Module.concat([module])) end defp router(nil, base) do if Mix.Project.umbrella?() do Mix.raise """ umbrella applications require an explicit router to be given to phx.routes, for example: $ mix phx.routes MyAppWeb.Router An alias can be added to mix.exs aliases to automate this: "phx.routes": "phx.routes MyAppWeb.Router" """ end web_router = web_mod(base, "Router") old_router = app_mod(base, "Router") loaded(web_router) || loaded(old_router) || Mix.raise """ no router found at #{inspect web_router} or #{inspect old_router}. An explicit router module may be given to phx.routes, for example: $ mix phx.routes MyAppWeb.Router An alias can be added to mix.exs aliases to automate this: "phx.routes": "phx.routes MyAppWeb.Router" """ end defp router(router_name, _base) do arg_router = Module.concat([router_name]) loaded(arg_router) || Mix.raise "the provided router, #{inspect(arg_router)}, does not exist" end defp loaded(module) do if Code.ensure_loaded?(module), do: module end defp app_mod(base, name), do: Module.concat([base, name]) defp web_mod(base, name), do: Module.concat(["#{base}Web", name]) end