Skip to content

Commit 6a37316

Browse files
adhami3310masenf
authored andcommitted
bring back the "route" in router data (#5483)
* bring back the "route" in router data * heh * typo * typo * fix the unit tests * fix dynamic route test * huh???? * fix one unit test
1 parent b644380 commit 6a37316

11 files changed

Lines changed: 262 additions & 195 deletions

File tree

reflex/.templates/web/app/routes.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { route } from "@react-router/dev/routes";
22
import { flatRoutes } from "@react-router/fs-routes";
33

44
export default [
5-
route("404", "routes/[404]_._index.jsx", { id: "404" }),
5+
route("404", "routes/[404]._index.jsx", { id: "404" }),
66
...(await flatRoutes({
7-
ignoredRouteFiles: ["routes/\\[404\\]_._index.jsx"],
7+
ignoredRouteFiles: ["routes/\\[404\\]._index.jsx"],
88
})),
9-
route("*", "routes/[404]_._index.jsx"),
9+
route("*", "routes/[404]._index.jsx"),
1010
];

reflex/app.py

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -765,9 +765,9 @@ def add_page(
765765
msg = "Route must be set if component is not a callable."
766766
raise exceptions.RouteValueError(msg)
767767
# Format the route.
768-
route = format.format_route(component.__name__)
768+
route = format.format_route(format.to_kebab_case(component.__name__))
769769
else:
770-
route = format.format_route(route, format_case=False)
770+
route = format.format_route(route)
771771

772772
if route == constants.Page404.SLUG:
773773
if component is None:
@@ -822,10 +822,11 @@ def add_page(
822822
state = self._state if self._state else State
823823
state.setup_dynamic_args(get_route_args(route))
824824

825-
if on_load:
826-
self._load_events[route] = (
827-
on_load if isinstance(on_load, list) else [on_load]
828-
)
825+
self._load_events[route] = (
826+
(on_load if isinstance(on_load, list) else [on_load])
827+
if on_load is not None
828+
else []
829+
)
829830

830831
self._unevaluated_pages[route] = unevaluated_page
831832

@@ -854,48 +855,35 @@ def _compile_page(self, route: str, save_page: bool = True):
854855
if save_page:
855856
self._pages[route] = component
856857

857-
def get_load_events(self, route: str) -> list[IndividualEventType[()]]:
858+
@functools.cached_property
859+
def router(self) -> Callable[[str], str | None]:
860+
"""Get the route computer function.
861+
862+
Returns:
863+
The route computer function.
864+
"""
865+
from reflex.route import get_router
866+
867+
return get_router(list(self._pages))
868+
869+
def get_load_events(self, path: str) -> list[IndividualEventType[()]]:
858870
"""Get the load events for a route.
859871
860872
Args:
861-
route: The route to get the load events for.
873+
path: The route to get the load events for.
862874
863875
Returns:
864876
The load events for the route.
865877
"""
866-
route = route.lstrip("/").rstrip("/")
867-
if route == "":
868-
return self._load_events.get(constants.PageNames.INDEX_ROUTE, [])
869-
870-
# Separate the pages by route type.
871-
static_page_paths_to_page_route = {}
872-
dynamic_page_paths_to_page_route = {}
873-
for page_route in list(self._pages) + list(self._unevaluated_pages):
874-
page_path = page_route.lstrip("/").rstrip("/")
875-
if "[" in page_path and "]" in page_path:
876-
dynamic_page_paths_to_page_route[page_path] = page_route
877-
else:
878-
static_page_paths_to_page_route[page_path] = page_route
879-
880-
# Check for static routes.
881-
if (page_route := static_page_paths_to_page_route.get(route)) is not None:
882-
return self._load_events.get(page_route, [])
883-
884-
# Check for dynamic routes.
885-
parts = route.split("/")
886-
for page_path, page_route in dynamic_page_paths_to_page_route.items():
887-
page_parts = page_path.split("/")
888-
if len(page_parts) != len(parts):
889-
continue
890-
if all(
891-
part == page_part
892-
or (page_part.startswith("[") and page_part.endswith("]"))
893-
for part, page_part in zip(parts, page_parts, strict=False)
894-
):
895-
return self._load_events.get(page_route, [])
896-
897-
# Default to 404 page load events if no match found.
898-
return self._load_events.get("404", [])
878+
four_oh_four_load_events = self._load_events.get("404", [])
879+
route = self.router(path)
880+
if not route:
881+
# If the path is not a valid route, return the 404 page load events.
882+
return four_oh_four_load_events
883+
return self._load_events.get(
884+
route,
885+
four_oh_four_load_events,
886+
)
899887

900888
def _check_routes_conflict(self, new_route: str):
901889
"""Verify if there is any conflict between the new route and any existing route.
@@ -916,7 +904,6 @@ def _check_routes_conflict(self, new_route: str):
916904
segments = (
917905
constants.RouteRegex.SINGLE_SEGMENT,
918906
constants.RouteRegex.DOUBLE_SEGMENT,
919-
constants.RouteRegex.SINGLE_CATCHALL_SEGMENT,
920907
constants.RouteRegex.DOUBLE_CATCHALL_SEGMENT,
921908
)
922909
for route in self._pages:
@@ -1742,6 +1729,11 @@ async def process(
17421729
# assignment will recurse into substates and force recalculation of
17431730
# dependent ComputedVar (dynamic route variables)
17441731
state.router_data = router_data
1732+
router_data[constants.RouteVar.PATH] = "/" + (
1733+
app.router(path) or "404"
1734+
if (path := router_data.get(constants.RouteVar.PATH))
1735+
else "404"
1736+
).removeprefix("/")
17451737
state.router = RouterData(router_data)
17461738

17471739
# Preprocess the event.

reflex/compiler/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,11 @@ def _format_route_part(part: str) -> str:
417417
if part.startswith("[") and part.endswith("]"):
418418
if part.startswith(("[...", "[[...")):
419419
return "$"
420+
if part.startswith("[["):
421+
return "($" + part.removeprefix("[[").removesuffix("]]") + ")"
420422
# We don't add [] here since we are reusing them from the input
421-
return "$" + part + "_"
422-
return "[" + part + "]_"
423+
return "$" + part
424+
return "[" + part + "]"
423425

424426

425427
def _path_to_file_stem(path: str) -> str:

reflex/constants/route.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,30 @@ class RouteRegex(SimpleNamespace):
4141
_CLOSING_BRACKET = r"\]"
4242
_ARG_NAME = r"[a-zA-Z_]\w*"
4343

44+
# The regex for a valid arg name, e.g. "slug" in "[slug]"
45+
_ARG_NAME_PATTERN = re.compile(_ARG_NAME)
46+
47+
SLUG = re.compile(r"[a-zA-Z0-9_-]+")
4448
# match a single arg (i.e. "[slug]"), returns the name of the arg
4549
ARG = re.compile(rf"{_OPENING_BRACKET}({_ARG_NAME}){_CLOSING_BRACKET}")
46-
# match a single catch-all arg (i.e. "[...slug]" or "[[...slug]]"), returns the name of the arg
47-
CATCHALL = re.compile(
48-
rf"({_OPENING_BRACKET}?{_OPENING_BRACKET}{_DOT_DOT_DOT}[^[{_CLOSING_BRACKET}]*{_CLOSING_BRACKET}?{_CLOSING_BRACKET})"
50+
# match a single optional arg (i.e. "[[slug]]"), returns the name of the arg
51+
OPTIONAL_ARG = re.compile(
52+
rf"{_OPENING_BRACKET * 2}({_ARG_NAME}){_CLOSING_BRACKET * 2}"
4953
)
54+
5055
# match a single non-optional catch-all arg (i.e. "[...slug]"), returns the name of the arg
5156
STRICT_CATCHALL = re.compile(
5257
rf"{_OPENING_BRACKET}{_DOT_DOT_DOT}({_ARG_NAME}){_CLOSING_BRACKET}"
5358
)
54-
# match a snigle optional catch-all arg (i.e. "[[...slug]]"), returns the name of the arg
55-
OPT_CATCHALL = re.compile(
59+
60+
# match a single optional catch-all arg (i.e. "[[...slug]]"), returns the name of the arg
61+
OPTIONAL_CATCHALL = re.compile(
5662
rf"{_OPENING_BRACKET * 2}{_DOT_DOT_DOT}({_ARG_NAME}){_CLOSING_BRACKET * 2}"
5763
)
64+
65+
SPLAT_CATCHALL = "[[...splat]]"
5866
SINGLE_SEGMENT = "__SINGLE_SEGMENT__"
5967
DOUBLE_SEGMENT = "__DOUBLE_SEGMENT__"
60-
SINGLE_CATCHALL_SEGMENT = "__SINGLE_CATCHALL_SEGMENT__"
6168
DOUBLE_CATCHALL_SEGMENT = "__DOUBLE_CATCHALL_SEGMENT__"
6269

6370

0 commit comments

Comments
 (0)