From a7f7aad947bfeb52aee4dcdb361999c4dc6f3203 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 28 Jun 2023 11:27:11 -0700 Subject: [PATCH] fix errors for nested routes --- packages/fullstack/Cargo.toml | 4 +-- .../examples/axum-hello-world/Cargo.toml | 2 +- packages/router-macro/src/nest.rs | 2 +- packages/router-macro/src/redirect.rs | 2 +- packages/router-macro/src/route.rs | 21 +++++--------- packages/router-macro/src/route_tree.rs | 29 +++++++++++++++++-- packages/router-macro/src/segment.rs | 26 +++++++++++++++-- 7 files changed, 64 insertions(+), 22 deletions(-) diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 7ccdcb987..2977610bf 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -61,11 +61,11 @@ web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "Ht [features] default = ["hot-reload", "default-tls"] router = ["dioxus-router"] -hot-reload = ["serde_json", "tokio-stream", "futures-util"] +hot-reload = ["serde_json", "futures-util"] warp = ["dep:warp", "http-body", "ssr"] axum = ["dep:axum", "tower-http", "ssr"] salvo = ["dep:salvo", "ssr"] -ssr = ["server_fn/ssr", "tokio", "dioxus-ssr", "hyper", "http", "dioxus-router/ssr"] +ssr = ["server_fn/ssr", "tokio", "dioxus-ssr", "hyper", "http", "dioxus-router/ssr", "tokio-stream"] default-tls = ["server_fn/default-tls"] rustls = ["server_fn/rustls"] diff --git a/packages/fullstack/examples/axum-hello-world/Cargo.toml b/packages/fullstack/examples/axum-hello-world/Cargo.toml index cc8226de7..0d7cfdd17 100644 --- a/packages/fullstack/examples/axum-hello-world/Cargo.toml +++ b/packages/fullstack/examples/axum-hello-world/Cargo.toml @@ -7,7 +7,7 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dioxus-web = { workspace = true, features=["hydrate"], optional = true } +dioxus-web = { workspace = true, features = ["hydrate"], optional = true } dioxus = { workspace = true } dioxus-fullstack = { workspace = true } axum = { version = "0.6.12", optional = true } diff --git a/packages/router-macro/src/nest.rs b/packages/router-macro/src/nest.rs index 1aaff68f4..7b315c1d2 100644 --- a/packages/router-macro/src/nest.rs +++ b/packages/router-macro/src/nest.rs @@ -82,6 +82,6 @@ impl Nest { pub fn error_type(&self) -> TokenStream { let error_name = self.error_ident(); - create_error_type(error_name, &self.segments) + create_error_type(error_name, &self.segments, None) } } diff --git a/packages/router-macro/src/redirect.rs b/packages/router-macro/src/redirect.rs index 5978e2cb8..c1efb8b4d 100644 --- a/packages/router-macro/src/redirect.rs +++ b/packages/router-macro/src/redirect.rs @@ -30,7 +30,7 @@ impl Redirect { pub fn error_type(&self) -> TokenStream { let error_name = self.error_ident(); - create_error_type(error_name, &self.segments) + create_error_type(error_name, &self.segments, None) } pub fn parse_query(&self) -> TokenStream { diff --git a/packages/router-macro/src/route.rs b/packages/router-macro/src/route.rs index 0174eb8bf..3120f4cca 100644 --- a/packages/router-macro/src/route.rs +++ b/packages/router-macro/src/route.rs @@ -308,20 +308,11 @@ impl Route { RouteType::Child(field) => { let name = &self.route_name; let child_name = field.ident.as_ref().unwrap(); - let ty = &field.ty; quote! { - { - let mut trailing = String::new(); - for seg in segments { - trailing += seg; - trailing += "/"; - } - trailing.pop(); - #enum_name::#name { - #child_name: #ty::from_str(&trailing).unwrap(), - #(#segments,)* - } + #enum_name::#name { + #child_name, + #(#segments,)* } } } @@ -343,8 +334,12 @@ impl Route { pub fn error_type(&self) -> TokenStream2 { let error_name = self.error_ident(); + let child_type = match &self.ty { + RouteType::Child(field) => Some(&field.ty), + RouteType::Leaf { .. } => None, + }; - create_error_type(error_name, &self.segments) + create_error_type(error_name, &self.segments, child_type) } pub fn parse_query(&self) -> TokenStream2 { diff --git a/packages/router-macro/src/route_tree.rs b/packages/router-macro/src/route_tree.rs index 523065e20..c531175cd 100644 --- a/packages/router-macro/src/route_tree.rs +++ b/packages/router-macro/src/route_tree.rs @@ -343,7 +343,7 @@ impl<'a> RouteTreeSegmentData<'a> { RouteType::Child(_) => false, }; - print_route_segment( + let print_route_segment = print_route_segment( route_segments.peekable(), return_constructed( insure_not_trailing, @@ -356,7 +356,32 @@ impl<'a> RouteTreeSegmentData<'a> { &error_enum_name, enum_varient, &varient_parse_error, - ) + ); + + match &route.ty { + RouteType::Child(child) => { + let ty = &child.ty; + let child_name = &child.ident; + + quote! { + let mut trailing = String::new(); + for seg in segments.clone() { + trailing += seg; + trailing += "/"; + } + trailing.pop(); + match #ty::from_str(&trailing).map_err(|err| #error_enum_name::#enum_varient(#varient_parse_error::ChildRoute(err))) { + Ok(#child_name) => { + #print_route_segment + } + Err(err) => { + errors.push(err); + } + } + } + } + RouteType::Leaf { .. } => print_route_segment, + } } Self::Nest { nest, children } => { // At this point, we have matched all static segments, so we can just check if the remaining segments match the route diff --git a/packages/router-macro/src/segment.rs b/packages/router-macro/src/segment.rs index 6295a8a26..e59f7bba6 100644 --- a/packages/router-macro/src/segment.rs +++ b/packages/router-macro/src/segment.rs @@ -222,7 +222,11 @@ pub fn parse_route_segments<'a>( Ok((route_segments, parsed_query)) } -pub(crate) fn create_error_type(error_name: Ident, segments: &[RouteSegment]) -> TokenStream2 { +pub(crate) fn create_error_type( + error_name: Ident, + segments: &[RouteSegment], + child_type: Option<&Type>, +) -> TokenStream2 { let mut error_variants = Vec::new(); let mut display_match = Vec::new(); @@ -249,11 +253,28 @@ pub(crate) fn create_error_type(error_name: Ident, segments: &[RouteSegment]) -> } } + let child_type_variant = child_type + .map(|child_type| { + quote! { ChildRoute(<#child_type as std::str::FromStr>::Err) } + }) + .into_iter(); + + let child_type_error = child_type + .map(|_| { + quote! { + Self::ChildRoute(error) => { + write!(f, "{}", error)? + } + } + }) + .into_iter(); + quote! { #[allow(non_camel_case_types)] #[derive(Debug, PartialEq)] pub enum #error_name { ExtraSegments(String), + #(#child_type_variant,)* #(#error_variants,)* } @@ -262,7 +283,8 @@ pub(crate) fn create_error_type(error_name: Ident, segments: &[RouteSegment]) -> match self { Self::ExtraSegments(segments) => { write!(f, "Found additional trailing segments: {}", segments)? - } + }, + #(#child_type_error,)* #(#display_match,)* } Ok(())