Browse Source

improve macro ergonomics

Evan Almloff 2 năm trước cách đây
mục cha
commit
502d670dff

+ 0 - 6
packages/router-macro/src/layout.rs

@@ -9,7 +9,6 @@ pub struct LayoutId(pub usize);
 
 
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct Layout {
 pub struct Layout {
-    pub layout_name: Ident,
     pub comp: Ident,
     pub comp: Ident,
     pub props_name: Ident,
     pub props_name: Ident,
     pub active_nests: Vec<NestId>,
     pub active_nests: Vec<NestId>,
@@ -37,10 +36,6 @@ impl Layout {
 
 
 impl Layout {
 impl Layout {
     pub fn parse(input: syn::parse::ParseStream, active_nests: Vec<NestId>) -> syn::Result<Self> {
     pub fn parse(input: syn::parse::ParseStream, active_nests: Vec<NestId>) -> syn::Result<Self> {
-        // Then parse the layout name
-        let _ = input.parse::<syn::Token![,]>();
-        let layout_name: syn::Ident = input.parse()?;
-
         // Then parse the component name
         // Then parse the component name
         let _ = input.parse::<syn::Token![,]>();
         let _ = input.parse::<syn::Token![,]>();
         let comp: Ident = input.parse()?;
         let comp: Ident = input.parse()?;
@@ -52,7 +47,6 @@ impl Layout {
             .unwrap_or_else(|_| format_ident!("{}Props", comp.to_string()));
             .unwrap_or_else(|_| format_ident!("{}Props", comp.to_string()));
 
 
         Ok(Self {
         Ok(Self {
-            layout_name,
             comp,
             comp,
             props_name,
             props_name,
             active_nests,
             active_nests,

+ 29 - 24
packages/router-macro/src/lib.rs

@@ -5,7 +5,7 @@ use nest::{Nest, NestId};
 use proc_macro::TokenStream;
 use proc_macro::TokenStream;
 use quote::{__private::Span, format_ident, quote, ToTokens};
 use quote::{__private::Span, format_ident, quote, ToTokens};
 use route::Route;
 use route::Route;
-use syn::{parse::ParseStream, parse_macro_input, Ident};
+use syn::{parse::ParseStream, parse_macro_input, Ident, Token};
 
 
 use proc_macro2::TokenStream as TokenStream2;
 use proc_macro2::TokenStream as TokenStream2;
 
 
@@ -18,9 +18,8 @@ mod route;
 mod route_tree;
 mod route_tree;
 mod segment;
 mod segment;
 
 
-// #[proc_macro_derive(Routable, attributes(route, nest, end_nest))]
-#[proc_macro_attribute]
-pub fn routable(_: TokenStream, input: TokenStream) -> TokenStream {
+#[proc_macro_derive(Routable, attributes(route, nest, end_nest, layout, end_layout))]
+pub fn routable(input: TokenStream) -> TokenStream {
     let routes_enum = parse_macro_input!(input as syn::ItemEnum);
     let routes_enum = parse_macro_input!(input as syn::ItemEnum);
 
 
     let route_enum = match RouteEnum::parse(routes_enum) {
     let route_enum = match RouteEnum::parse(routes_enum) {
@@ -48,8 +47,6 @@ pub fn routable(_: TokenStream, input: TokenStream) -> TokenStream {
 }
 }
 
 
 struct RouteEnum {
 struct RouteEnum {
-    attrs: Vec<syn::Attribute>,
-    vis: syn::Visibility,
     name: Ident,
     name: Ident,
     routes: Vec<Route>,
     routes: Vec<Route>,
     nests: Vec<Nest>,
     nests: Vec<Nest>,
@@ -62,13 +59,14 @@ impl RouteEnum {
 
 
         let mut routes = Vec::new();
         let mut routes = Vec::new();
 
 
-        let mut layouts = Vec::new();
+        let mut layouts: Vec<Layout> = Vec::new();
         let mut layout_stack = Vec::new();
         let mut layout_stack = Vec::new();
 
 
         let mut nests = Vec::new();
         let mut nests = Vec::new();
         let mut nest_stack = Vec::new();
         let mut nest_stack = Vec::new();
 
 
         for variant in &data.variants {
         for variant in &data.variants {
+            let mut excluded = Vec::new();
             // Apply the any nesting attributes in order
             // Apply the any nesting attributes in order
             for attr in &variant.attrs {
             for attr in &variant.attrs {
                 if attr.path.is_ident("nest") {
                 if attr.path.is_ident("nest") {
@@ -113,15 +111,31 @@ impl RouteEnum {
                 } else if attr.path.is_ident("end_nest") {
                 } else if attr.path.is_ident("end_nest") {
                     nest_stack.pop();
                     nest_stack.pop();
                 } else if attr.path.is_ident("layout") {
                 } else if attr.path.is_ident("layout") {
-                    let layout_index = layouts.len();
-
                     let parser = |input: ParseStream| {
                     let parser = |input: ParseStream| {
-                        Layout::parse(input, nest_stack.iter().rev().cloned().collect())
+                        let bang: Option<Token![!]> = input.parse().ok();
+                        let exclude = bang.is_some();
+                        Ok((
+                            exclude,
+                            Layout::parse(input, nest_stack.iter().rev().cloned().collect())?,
+                        ))
                     };
                     };
-                    let layout = attr.parse_args_with(parser)?;
-
-                    layouts.push(layout);
-                    layout_stack.push(LayoutId(layout_index));
+                    let (exclude, layout): (bool, Layout) = attr.parse_args_with(parser)?;
+
+                    if exclude {
+                        let Some(layout_index) =
+                            layouts.iter().position(|l| l.comp == layout.comp)else{
+                                return Err(syn::Error::new(
+                                    Span::call_site(),
+                                    "Attempted to exclude a layout that does not exist",
+                                ));
+                            }
+                                ;
+                        excluded.push(LayoutId(layout_index));
+                    } else {
+                        let layout_index = layouts.len();
+                        layouts.push(layout);
+                        layout_stack.push(LayoutId(layout_index));
+                    }
                 } else if attr.path.is_ident("end_layout") {
                 } else if attr.path.is_ident("end_layout") {
                     layout_stack.pop();
                     layout_stack.pop();
                 }
                 }
@@ -130,6 +144,7 @@ impl RouteEnum {
             let mut active_nests = nest_stack.clone();
             let mut active_nests = nest_stack.clone();
             active_nests.reverse();
             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.reverse();
             active_layouts.reverse();
 
 
             let route = Route::parse(active_nests, active_layouts, variant.clone())?;
             let route = Route::parse(active_nests, active_layouts, variant.clone())?;
@@ -139,8 +154,6 @@ impl RouteEnum {
 
 
         let myself = Self {
         let myself = Self {
             name: name.clone(),
             name: name.clone(),
-            attrs: data.attrs,
-            vis: data.vis,
             routes,
             routes,
             nests,
             nests,
             layouts,
             layouts,
@@ -315,16 +328,8 @@ impl RouteEnum {
 impl ToTokens for RouteEnum {
 impl ToTokens for RouteEnum {
     fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) {
     fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) {
         let routes = &self.routes;
         let routes = &self.routes;
-        let vis = &self.vis;
-        let name = &self.name;
-        let attrs = &self.attrs;
-        let variants = routes.iter().map(|r| r.variant());
 
 
         tokens.extend(quote!(
         tokens.extend(quote!(
-            #(#attrs)*
-            #vis enum #name {
-                #(#variants),*
-            }
 
 
             #[path = "pages"]
             #[path = "pages"]
             mod pages {
             mod pages {

+ 3 - 23
packages/router-macro/src/route.rs

@@ -186,13 +186,10 @@ impl Route {
                 }
                 }
             }
             }
             for segment in &self.segments {
             for segment in &self.segments {
-                match segment {
-                    RouteSegment::Dynamic(name, _) => {
-                        if name == f.ident.as_ref().unwrap() {
-                            from_route = true
-                        }
+                if let RouteSegment::Dynamic(name, ..) = segment {
+                    if name == f.ident.as_ref().unwrap() {
+                        from_route = true
                     }
                     }
-                    _ => {}
                 }
                 }
             }
             }
 
 
@@ -273,23 +270,6 @@ impl Route {
         }
         }
     }
     }
 
 
-    pub fn variant(&self) -> TokenStream2 {
-        let name = &self.route_name;
-        let fields = self.fields.named.iter().map(|f| {
-            let mut new = f.clone();
-            new.attrs.retain(|a| {
-                !a.path.is_ident("nest")
-                    && !a.path.is_ident("end_nest")
-                    && !a.path.is_ident("layout")
-                    && !a.path.is_ident("end_layout")
-            });
-            new
-        });
-
-        quote! {
-            #name { #(#fields,)* }
-        }
-    }
 }
 }
 
 
 impl ToTokens for Route {
 impl ToTokens for Route {

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

@@ -48,7 +48,7 @@ pub mod prelude {
     pub use crate::contexts::*;
     pub use crate::contexts::*;
     pub use crate::hooks::*;
     pub use crate::hooks::*;
     pub use crate::router_cfg::RouterConfiguration;
     pub use crate::router_cfg::RouterConfiguration;
-    pub use dioxus_router_macro::routable;
+    pub use dioxus_router_macro::Routable;
 }
 }
 
 
 mod utils {
 mod utils {