Turns paths in the app directory into routes. Pure: paths in, structs out.
Only scan/1 reads the filesystem.
Folder names follow the Next.js App Router:
runbooksa static URL segment(auth)a route group: groups pages and layouts, adds nothing tothe URL. It grants nothing by itself; authentication stays in Phoenix pipelines and `live_session`.[id]a dynamic segment,:id[...path]a catch-all segment,*path; must be the last folder_namea private folder: never routed, for colocated components
Four special files:
page.exmakes its folder a route: the UI for that URLlayout.exframes every page in its folder and below, outermostfirstpersistent.exoptional; the persistent part of thelayout.exin thesame folder: a LiveView that stays alive while the user moves between that layout's pages. Requires the `layout.ex`, whose frame places it.live.exoptional; one LiveView owns every page in its folder andbelow, so switching between them is a patch that keeps the process and its state. The nearest `live.ex` wins, so a nested one starts a new owner. Pages without one are their own LiveView.
Summary
Functions
Every page.ex, layout.ex, persistent.ex and live.ex under root,
relative to it and sorted.
Hidden folders are skipped. Xenia.Routes compares this list between
compilations to notice added and removed pages.
The page at file, given the app's layout.ex, persistent.ex and
live.ex files (all relative paths). Other files in the list are ignored.
All pages in a list of relative paths, in the order Phoenix should match them: static segments before dynamic ones, catch-alls last.
Reads the app folder at root and returns its pages, see pages/1.
Paths in the result are relative to root.
Functions
Every page.ex, layout.ex, persistent.ex and live.ex under root,
relative to it and sorted.
Hidden folders are skipped. Xenia.Routes compares this list between
compilations to notice added and removed pages.
@spec page(String.t(), [String.t()]) :: Xenia.Routes.Page.t()
The page at file, given the app's layout.ex, persistent.ex and
live.ex files (all relative paths). Other files in the list are ignored.
iex> Xenia.Routes.Discovery.page("(auth)/runbooks/[id]/page.ex", [
...> "layout.ex",
...> "(auth)/layout.ex",
...> "(auth)/persistent.ex"
...> ])
%Xenia.Routes.Page{
file: "(auth)/runbooks/[id]/page.ex",
path: "/runbooks/:id",
params: ["id"],
groups: ["auth"],
layouts: ["layout.ex", "(auth)/layout.ex"],
persistent: %{"(auth)/layout.ex" => "(auth)/persistent.ex"},
live: nil
}Raises ArgumentError for a file that isn't a page.ex and for invalid
folder names.
@spec pages([String.t()], keyword()) :: [Xenia.Routes.Page.t()]
All pages in a list of relative paths, in the order Phoenix should match them: static segments before dynamic ones, catch-alls last.
Other files, and anything inside a private _folder, are ignored.
Raises ArgumentError when two pages resolve to the same path, when
a live.ex owns no page, and when a persistent.ex has no layout.ex
next to it.
With check_owners: false, a live.ex that owns no page yet is allowed:
the generators use it, because an unfinished folder isn't the new file's
problem.
@spec scan(Path.t()) :: [Xenia.Routes.Page.t()]
Reads the app folder at root and returns its pages, see pages/1.
Paths in the result are relative to root.