fix reversed nests

This commit is contained in:
Evan Almloff committed 2023-07-14 11:40:38 -07:00
1 parent 35a3880b88
commit d19a33d59c
5 files changed
+64 -51

No files matched your search

+3 -11
View File
@@ -364,10 +364,7 @@ impl RouteEnum {
let parser = |input: ParseStream| { let parser = |input: ParseStream| {
let bang: Option<Token![!]> = input.parse().ok(); let bang: Option<Token![!]> = input.parse().ok();
let exclude = bang.is_some(); let exclude = bang.is_some();
Ok(( Ok((exclude, Layout::parse(input, nest_stack.clone())?))
exclude,
Layout::parse(input, nest_stack.iter().rev().cloned().collect())?,
))
}; };
let (exclude, layout): (bool, Layout) = attr.parse_args_with(parser)?; let (exclude, layout): (bool, Layout) = attr.parse_args_with(parser)?;
@@ -389,19 +386,14 @@ impl RouteEnum {
layout_stack.pop(); layout_stack.pop();
} else if attr.path.is_ident("redirect") { } else if attr.path.is_ident("redirect") {
let parser = |input: ParseStream| { let parser = |input: ParseStream| {
Redirect::parse( Redirect::parse(input, nest_stack.clone(), redirects.len())
input,
nest_stack.iter().rev().cloned().collect(),
redirects.len(),
)
}; };
let redirect = attr.parse_args_with(parser)?; let redirect = attr.parse_args_with(parser)?;
redirects.push(redirect); redirects.push(redirect);
} }
} }
let mut active_nests = nest_stack.clone(); let active_nests = nest_stack.clone();
active_nests.reverse();
let mut active_layouts = layout_stack.clone(); let mut active_layouts = layout_stack.clone();
active_layouts.retain(|&id| !excluded.contains(&id)); active_layouts.retain(|&id| !excluded.contains(&id));
+17 -6
View File
@@ -186,26 +186,37 @@ impl Route {
pub fn display_match(&self, nests: &[Nest]) -> TokenStream2 { pub fn display_match(&self, nests: &[Nest]) -> TokenStream2 {
let name = &self.route_name; let name = &self.route_name;
let dynamic_segments = self.dynamic_segments(); let dynamic_segments = self.dynamic_segments();
let write_layouts = self.nests.iter().map(|id| nests[id.0].write());
let write_segments = self.segments.iter().map(|s| s.write_segment());
let write_query = self.query.as_ref().map(|q| q.write()); let write_query = self.query.as_ref().map(|q| q.write());
match &self.ty { match &self.ty {
RouteType::Child(field) => { RouteType::Child(field) => {
let write_nests = self.nests.iter().map(|id| nests[id.0].write());
let write_segments = self.segments.iter().map(|s| s.write_segment());
let child = field.ident.as_ref().unwrap(); let child = field.ident.as_ref().unwrap();
quote! { quote! {
Self::#name { #(#dynamic_segments,)* #child } => { Self::#name { #(#dynamic_segments,)* #child } => {
use std::fmt::Display; use std::fmt::Display;
#(#write_layouts)* use std::fmt::Write;
#(#write_segments)* let mut route = String::new();
#child.fmt(f); {
let f = &mut route;
#(#write_nests)*
#(#write_segments)*
}
if route.ends_with('/') {
route.pop();
}
f.write_str(&route)?;
#child.fmt(f)?;
} }
} }
} }
RouteType::Leaf { .. } => { RouteType::Leaf { .. } => {
let write_nests = self.nests.iter().map(|id| nests[id.0].write());
let write_segments = self.segments.iter().map(|s| s.write_segment());
quote! { quote! {
Self::#name { #(#dynamic_segments,)* } => { Self::#name { #(#dynamic_segments,)* } => {
#(#write_layouts)* #(#write_nests)*
#(#write_segments)* #(#write_segments)*
#write_query #write_query
} }
+1 -1
View File
@@ -314,7 +314,7 @@ impl<'a> RouteTreeSegmentData<'a> {
#(#children)* #(#children)*
} }
else { else {
errors.push(#error_enum_name::#enum_varient(#varient_parse_error::#error_ident)) errors.push(#error_enum_name::#enum_varient(#varient_parse_error::#error_ident(segment.to_string())))
} }
} }
} }
+5 -4
View File
@@ -58,10 +58,11 @@ impl RouteSegment {
quote! { quote! {
{ {
let mut segments = segments.clone(); let mut segments = segments.clone();
let parsed = if let Some(#segment) = segments.next() { let segment = segments.next();
let parsed = if let Some(#segment) = segment {
Ok(()) Ok(())
} else { } else {
Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name)) Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(segment.map(|s|s.to_string()).unwrap_or_default())))
}; };
match parsed { match parsed {
Ok(_) => { Ok(_) => {
@@ -234,8 +235,8 @@ pub(crate) fn create_error_type(
let error_name = segment.error_name(i); let error_name = segment.error_name(i);
match segment { match segment {
RouteSegment::Static(index) => { RouteSegment::Static(index) => {
error_variants.push(quote! { #error_name }); error_variants.push(quote! { #error_name(String) });
display_match.push(quote! { Self::#error_name => write!(f, "Static segment '{}' did not match", #index)? }); display_match.push(quote! { Self::#error_name(found) => write!(f, "Static segment '{}' did not match instead found '{found}'", #index)? });
} }
RouteSegment::Dynamic(ident, ty) => { RouteSegment::Dynamic(ident, ty) => {
let missing_error = segment.missing_error_name().unwrap(); let missing_error = segment.missing_error_name().unwrap();
+38 -29
View File
@@ -96,21 +96,28 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
p { "Site Map" } p { "Site Map" }
pre { "{site_map:#?}" } pre { "{site_map:#?}" }
p { "Dynamic link" } p { "Dynamic link" }
if let Ok(route) = parsed { match parsed {
if route != current_route { Ok(route) => {
if route != current_route {
render! {
Link {
target: route.clone(),
"{route}"
}
}
}
else {
None
}
}
Err(err) => {
render! { render! {
Link { pre {
target: route.clone(), color: "red",
"{route}" "Invalid route:\n{err}"
} }
} }
} }
else {
None
}
}
else {
None
} }
} }
} }
@@ -118,24 +125,26 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
#[rustfmt::skip] #[rustfmt::skip]
#[derive(Clone, Debug, PartialEq, Routable)] #[derive(Clone, Debug, PartialEq, Routable)]
enum Route { enum Route {
// Nests with parameters have types taken from child routes #[nest("/test")]
#[nest("/user/:user_id")] // Nests with parameters have types taken from child routes
// Everything inside the nest has the added parameter `user_id: usize` #[nest("/user/:user_id")]
// UserFrame is a layout component that will receive the `user_id: usize` parameter // Everything inside the nest has the added parameter `user_id: usize`
#[layout(UserFrame)] // UserFrame is a layout component that will receive the `user_id: usize` parameter
#[route("/:dynamic?:query")] #[layout(UserFrame)]
Route1 { #[route("/:dynamic?:query")]
// The type is taken from the first instance of the dynamic parameter Route1 {
user_id: usize, // The type is taken from the first instance of the dynamic parameter
dynamic: usize, user_id: usize,
query: String, dynamic: usize,
extra: String, query: String,
}, extra: String,
#[route("/hello_world")] },
// You can opt out of the layout by using the `!` prefix #[route("/hello_world")]
#[layout(!UserFrame)] // You can opt out of the layout by using the `!` prefix
Route2 { user_id: usize }, #[layout(!UserFrame)]
#[end_layout] Route2 { user_id: usize },
#[end_layout]
#[end_nest]
#[end_nest] #[end_nest]
#[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})] #[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
#[route("/:dynamic")] #[route("/:dynamic")]