Selaa lähdekoodia

reorganize router macro package

Evan Almloff 2 vuotta sitten
vanhempi
commit
adfc10461e

+ 3 - 0
packages/router-core/tests/macro.rs

@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use dioxus::prelude::*;
 use dioxus_router_core::*;
 use dioxus_router_macro::*;
@@ -57,6 +59,7 @@ fn Route6(cx: Scope, extra: Vec<String>) -> Element {
     }
 }
 
+#[rustfmt::skip]
 #[derive(Routable, Clone, Debug, PartialEq)]
 enum Route {
     #[route("/(dynamic)" Route1)]

+ 11 - 1
packages/router-macro/src/lib.rs

@@ -8,8 +8,11 @@ use syn::{parse_macro_input, Ident};
 
 use proc_macro2::TokenStream as TokenStream2;
 
+mod nest;
+mod query;
 mod route;
 mod route_tree;
+mod segment;
 
 #[proc_macro_derive(Routable, attributes(route))]
 pub fn derive_routable(input: TokenStream) -> TokenStream {
@@ -51,8 +54,15 @@ impl RouteEnum {
         if let syn::Data::Enum(data) = input.data {
             let mut routes = Vec::new();
 
+            let mut current_base_route = String::new();
+
             for variant in data.variants {
-                let route = Route::parse(variant)?;
+                // Apply the any nesting attributes in order
+                for attr in &variant.attrs {
+                    if attr.path.is_ident("nest") {}
+                }
+
+                let route = Route::parse(current_base_route.clone(), variant)?;
                 routes.push(route);
             }
 

+ 1 - 0
packages/router-macro/src/nest.rs

@@ -0,0 +1 @@
+struct Nest {}

+ 31 - 0
packages/router-macro/src/query.rs

@@ -0,0 +1,31 @@
+use quote::quote;
+use syn::{Ident, Type};
+
+use proc_macro2::TokenStream as TokenStream2;
+
+#[derive(Debug)]
+pub struct QuerySegment {
+    pub ident: Ident,
+    pub ty: Type,
+}
+
+impl QuerySegment {
+    pub fn parse(&self) -> TokenStream2 {
+        let ident = &self.ident;
+        let ty = &self.ty;
+        quote! {
+            let #ident = <#ty as dioxus_router_core::router::FromQuery>::from_query(query);
+        }
+    }
+
+    pub fn write(&self) -> TokenStream2 {
+        let ident = &self.ident;
+        quote! {
+            write!(f, "?{}", #ident)?;
+        }
+    }
+
+    pub fn name(&self) -> Ident {
+        self.ident.clone()
+    }
+}

+ 12 - 154
packages/router-macro/src/route.rs

@@ -1,10 +1,13 @@
 use quote::{__private::Span, format_ident, quote, ToTokens};
 use syn::parse::Parse;
 use syn::parse::ParseStream;
-use syn::{Ident, LitStr, Type, Variant};
+use syn::{Ident, LitStr, Variant};
 
 use proc_macro2::TokenStream as TokenStream2;
 
+use crate::query::QuerySegment;
+use crate::segment::RouteSegment;
+
 struct RouteArgs {
     route: LitStr,
     comp_name: Option<Ident>,
@@ -35,13 +38,13 @@ pub struct Route {
     pub route_name: Ident,
     pub comp_name: Ident,
     pub props_name: Ident,
-    pub route: LitStr,
+    pub route: String,
     pub route_segments: Vec<RouteSegment>,
     pub query: Option<QuerySegment>,
 }
 
 impl Route {
-    pub fn parse(input: syn::Variant) -> syn::Result<Self> {
+    pub fn parse(root_route: String, input: syn::Variant) -> syn::Result<Self> {
         let route_attr = input
             .attrs
             .iter()
@@ -55,7 +58,7 @@ impl Route {
 
         let route_name = input.ident.clone();
         let args = route_attr.parse_args::<RouteArgs>()?;
-        let route = args.route;
+        let route = root_route + &args.route.value();
         let file_based = args.comp_name.is_none();
         let comp_name = args
             .comp_name
@@ -209,7 +212,7 @@ impl ToTokens for Route {
             return;
         }
 
-        let without_leading_slash = &self.route.value()[1..];
+        let without_leading_slash = &self.route[1..];
         let route_path = std::path::Path::new(without_leading_slash);
         let with_extension = route_path.with_extension("rs");
         let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
@@ -237,14 +240,13 @@ impl ToTokens for Route {
 
 fn parse_route_segments(
     varient: &Variant,
-    route: &LitStr,
+    route: &str,
 ) -> syn::Result<(Vec<RouteSegment>, Option<QuerySegment>)> {
     let mut route_segments = Vec::new();
 
-    let route_string = route.value();
-    let (route_string, query) = match route_string.rsplit_once('?') {
+    let (route_string, query) = match route.rsplit_once('?') {
         Some((route, query)) => (route, Some(query)),
-        None => (route_string.as_str(), None),
+        None => (route, None),
     };
     let mut iterator = route_string.split('/');
 
@@ -255,7 +257,7 @@ fn parse_route_segments(
             varient,
             format!(
                 "Routes should start with /. Error found in the route '{}'",
-                route.value()
+                route
             ),
         ));
     }
@@ -346,147 +348,3 @@ fn parse_route_segments(
 
     Ok((route_segments, parsed_query))
 }
-
-#[derive(Debug)]
-pub enum RouteSegment {
-    Static(String),
-    Dynamic(Ident, Type),
-    CatchAll(Ident, Type),
-}
-
-impl RouteSegment {
-    pub fn name(&self) -> Option<Ident> {
-        match self {
-            Self::Static(_) => None,
-            Self::Dynamic(ident, _) => Some(ident.clone()),
-            Self::CatchAll(ident, _) => Some(ident.clone()),
-        }
-    }
-
-    pub fn write_segment(&self) -> TokenStream2 {
-        match self {
-            Self::Static(segment) => quote! { write!(f, "/{}", #segment)?; },
-            Self::Dynamic(ident, _) => quote! { write!(f, "/{}", #ident)?; },
-            Self::CatchAll(ident, _) => quote! { #ident.display_route_segements(f)?; },
-        }
-    }
-
-    fn error_name(&self, idx: usize) -> Ident {
-        match self {
-            Self::Static(_) => static_segment_idx(idx),
-            Self::Dynamic(ident, _) => format_ident!("{}ParseError", ident),
-            Self::CatchAll(ident, _) => format_ident!("{}ParseError", ident),
-        }
-    }
-
-    fn missing_error_name(&self) -> Option<Ident> {
-        match self {
-            Self::Dynamic(ident, _) => Some(format_ident!("{}MissingError", ident)),
-            _ => None,
-        }
-    }
-
-    pub fn try_parse(
-        &self,
-        idx: usize,
-        error_enum_name: &Ident,
-        error_enum_varient: &Ident,
-        inner_parse_enum: &Ident,
-        parse_children: TokenStream2,
-    ) -> TokenStream2 {
-        let error_name = self.error_name(idx);
-        match self {
-            Self::Static(segment) => {
-                quote! {
-                    {
-                        let mut segments = segments.clone();
-                        let parsed = if let Some(#segment) = segments.next() {
-                            Ok(())
-                        } else {
-                            Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name))
-                        };
-                        match parsed {
-                            Ok(_) => {
-                                #parse_children
-                            }
-                            Err(err) => {
-                                errors.push(err);
-                            }
-                        }
-                    }
-                }
-            }
-            Self::Dynamic(name, ty) => {
-                let missing_error_name = self.missing_error_name().unwrap();
-                quote! {
-                    {
-                        let mut segments = segments.clone();
-                        let parsed = if let Some(segment) = segments.next() {
-                            <#ty as dioxus_router_core::router::FromRouteSegment>::from_route_segment(segment).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
-                        } else {
-                            Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#missing_error_name))
-                        };
-                        match parsed {
-                            Ok(#name) => {
-                                #parse_children
-                            }
-                            Err(err) => {
-                                errors.push(err);
-                            }
-                        }
-                    }
-                }
-            }
-            Self::CatchAll(name, ty) => {
-                quote! {
-                    {
-                        let parsed = {
-                            let mut segments = segments.clone();
-                            let segments: Vec<_> = segments.collect();
-                            <#ty as dioxus_router_core::router::FromRouteSegments>::from_route_segments(&segments).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
-                        };
-                        match parsed {
-                            Ok(#name) => {
-                                #parse_children
-                            }
-                            Err(err) => {
-                                errors.push(err);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-pub fn static_segment_idx(idx: usize) -> Ident {
-    format_ident!("StaticSegment{}ParseError", idx)
-}
-
-#[derive(Debug)]
-pub struct QuerySegment {
-    ident: Ident,
-    ty: Type,
-}
-
-impl QuerySegment {
-    pub fn parse(&self) -> TokenStream2 {
-        let ident = &self.ident;
-        let ty = &self.ty;
-        quote! {
-            let #ident = <#ty as dioxus_router_core::router::FromQuery>::from_query(query);
-        }
-    }
-
-    pub fn write(&self) -> TokenStream2 {
-        let ident = &self.ident;
-        quote! {
-            write!(f, "?{}", #ident)?;
-        }
-    }
-
-    pub fn name(&self) -> Ident {
-        self.ident.clone()
-    }
-}

+ 4 - 1
packages/router-macro/src/route_tree.rs

@@ -2,7 +2,10 @@ use proc_macro2::TokenStream;
 use quote::quote;
 use syn::Ident;
 
-use crate::route::{static_segment_idx, Route, RouteSegment};
+use crate::{
+    route::Route,
+    segment::{static_segment_idx, RouteSegment},
+};
 
 // First deduplicate the routes by the static part of the route
 #[derive(Debug)]

+ 121 - 0
packages/router-macro/src/segment.rs

@@ -0,0 +1,121 @@
+use quote::{format_ident, quote};
+use syn::{Ident, Type};
+
+use proc_macro2::TokenStream as TokenStream2;
+
+#[derive(Debug)]
+pub enum RouteSegment {
+    Static(String),
+    Dynamic(Ident, Type),
+    CatchAll(Ident, Type),
+}
+
+impl RouteSegment {
+    pub fn name(&self) -> Option<Ident> {
+        match self {
+            Self::Static(_) => None,
+            Self::Dynamic(ident, _) => Some(ident.clone()),
+            Self::CatchAll(ident, _) => Some(ident.clone()),
+        }
+    }
+
+    pub fn write_segment(&self) -> TokenStream2 {
+        match self {
+            Self::Static(segment) => quote! { write!(f, "/{}", #segment)?; },
+            Self::Dynamic(ident, _) => quote! { write!(f, "/{}", #ident)?; },
+            Self::CatchAll(ident, _) => quote! { #ident.display_route_segements(f)?; },
+        }
+    }
+
+    pub fn error_name(&self, idx: usize) -> Ident {
+        match self {
+            Self::Static(_) => static_segment_idx(idx),
+            Self::Dynamic(ident, _) => format_ident!("{}ParseError", ident),
+            Self::CatchAll(ident, _) => format_ident!("{}ParseError", ident),
+        }
+    }
+
+    pub fn missing_error_name(&self) -> Option<Ident> {
+        match self {
+            Self::Dynamic(ident, _) => Some(format_ident!("{}MissingError", ident)),
+            _ => None,
+        }
+    }
+
+    pub fn try_parse(
+        &self,
+        idx: usize,
+        error_enum_name: &Ident,
+        error_enum_varient: &Ident,
+        inner_parse_enum: &Ident,
+        parse_children: TokenStream2,
+    ) -> TokenStream2 {
+        let error_name = self.error_name(idx);
+        match self {
+            Self::Static(segment) => {
+                quote! {
+                    {
+                        let mut segments = segments.clone();
+                        let parsed = if let Some(#segment) = segments.next() {
+                            Ok(())
+                        } else {
+                            Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name))
+                        };
+                        match parsed {
+                            Ok(_) => {
+                                #parse_children
+                            }
+                            Err(err) => {
+                                errors.push(err);
+                            }
+                        }
+                    }
+                }
+            }
+            Self::Dynamic(name, ty) => {
+                let missing_error_name = self.missing_error_name().unwrap();
+                quote! {
+                    {
+                        let mut segments = segments.clone();
+                        let parsed = if let Some(segment) = segments.next() {
+                            <#ty as dioxus_router_core::router::FromRouteSegment>::from_route_segment(segment).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
+                        } else {
+                            Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#missing_error_name))
+                        };
+                        match parsed {
+                            Ok(#name) => {
+                                #parse_children
+                            }
+                            Err(err) => {
+                                errors.push(err);
+                            }
+                        }
+                    }
+                }
+            }
+            Self::CatchAll(name, ty) => {
+                quote! {
+                    {
+                        let parsed = {
+                            let mut segments = segments.clone();
+                            let segments: Vec<_> = segments.collect();
+                            <#ty as dioxus_router_core::router::FromRouteSegments>::from_route_segments(&segments).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
+                        };
+                        match parsed {
+                            Ok(#name) => {
+                                #parse_children
+                            }
+                            Err(err) => {
+                                errors.push(err);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub fn static_segment_idx(idx: usize) -> Ident {
+    format_ident!("StaticSegment{}ParseError", idx)
+}