route.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. use quote::{format_ident, quote};
  2. use syn::parse::Parse;
  3. use syn::parse::ParseStream;
  4. use syn::parse_quote;
  5. use syn::Field;
  6. use syn::Path;
  7. use syn::Type;
  8. use syn::{Ident, LitStr};
  9. use proc_macro2::TokenStream as TokenStream2;
  10. use crate::layout::Layout;
  11. use crate::layout::LayoutId;
  12. use crate::nest::Nest;
  13. use crate::nest::NestId;
  14. use crate::query::QuerySegment;
  15. use crate::segment::create_error_type;
  16. use crate::segment::parse_route_segments;
  17. use crate::segment::RouteSegment;
  18. struct RouteArgs {
  19. route: LitStr,
  20. comp_name: Option<Path>,
  21. }
  22. impl Parse for RouteArgs {
  23. fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
  24. let route = input.parse::<LitStr>()?;
  25. Ok(RouteArgs {
  26. route,
  27. comp_name: {
  28. let _ = input.parse::<syn::Token![,]>();
  29. input.parse().ok()
  30. },
  31. })
  32. }
  33. }
  34. struct ChildArgs {
  35. route: LitStr,
  36. }
  37. impl Parse for ChildArgs {
  38. fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
  39. let route = input.parse::<LitStr>()?;
  40. Ok(ChildArgs { route })
  41. }
  42. }
  43. #[derive(Debug)]
  44. pub(crate) struct Route {
  45. pub route_name: Ident,
  46. pub ty: RouteType,
  47. pub route: String,
  48. pub segments: Vec<RouteSegment>,
  49. pub query: Option<QuerySegment>,
  50. pub nests: Vec<NestId>,
  51. pub layouts: Vec<LayoutId>,
  52. fields: Vec<(Ident, Type)>,
  53. }
  54. impl Route {
  55. pub fn parse(
  56. nests: Vec<NestId>,
  57. layouts: Vec<LayoutId>,
  58. variant: syn::Variant,
  59. ) -> syn::Result<Self> {
  60. let route_attr = variant
  61. .attrs
  62. .iter()
  63. .find(|attr| attr.path().is_ident("route"));
  64. let route;
  65. let ty;
  66. let route_name = variant.ident.clone();
  67. match route_attr {
  68. Some(attr) => {
  69. let args = attr.parse_args::<RouteArgs>()?;
  70. let comp_name = args.comp_name.unwrap_or_else(|| parse_quote!(#route_name));
  71. ty = RouteType::Leaf {
  72. component: comp_name,
  73. };
  74. route = args.route.value();
  75. }
  76. None => {
  77. if let Some(route_attr) = variant
  78. .attrs
  79. .iter()
  80. .find(|attr| attr.path().is_ident("child"))
  81. {
  82. let args = route_attr.parse_args::<ChildArgs>()?;
  83. route = args.route.value();
  84. match &variant.fields {
  85. syn::Fields::Named(fields) => {
  86. // find either a field with #[child] or a field named "child"
  87. let child_field = fields.named.iter().find(|f| {
  88. f.attrs
  89. .iter()
  90. .any(|attr| attr.path().is_ident("child"))
  91. || *f.ident.as_ref().unwrap() == "child"
  92. });
  93. match child_field{
  94. Some(child) => {
  95. ty = RouteType::Child(child.clone());
  96. }
  97. None => {
  98. return Err(syn::Error::new_spanned(
  99. variant.clone(),
  100. "Routable variants with a #[child(..)] attribute must have a field named \"child\" or a field with a #[child] attribute",
  101. ));
  102. }
  103. }
  104. }
  105. _ => {
  106. return Err(syn::Error::new_spanned(
  107. variant.clone(),
  108. "Routable variants with a #[child(..)] attribute must have named fields",
  109. ))
  110. }
  111. }
  112. } else {
  113. return Err(syn::Error::new_spanned(
  114. variant.clone(),
  115. "Routable variants must either have a #[route(..)] attribute or a #[child(..)] attribute",
  116. ));
  117. }
  118. }
  119. };
  120. let fields = match &variant.fields {
  121. syn::Fields::Named(fields) => fields
  122. .named
  123. .iter()
  124. .filter_map(|f| {
  125. if let RouteType::Child(child) = &ty {
  126. if f.ident == child.ident {
  127. return None;
  128. }
  129. }
  130. Some((f.ident.clone().unwrap(), f.ty.clone()))
  131. })
  132. .collect(),
  133. _ => Vec::new(),
  134. };
  135. let (route_segments, query) = {
  136. parse_route_segments(
  137. variant.ident.span(),
  138. fields.iter().map(|f| (&f.0, &f.1)),
  139. &route,
  140. )?
  141. };
  142. Ok(Self {
  143. ty,
  144. route_name,
  145. segments: route_segments,
  146. route,
  147. query,
  148. nests,
  149. layouts,
  150. fields,
  151. })
  152. }
  153. pub fn display_match(&self, nests: &[Nest]) -> TokenStream2 {
  154. let name = &self.route_name;
  155. let dynamic_segments = self.dynamic_segments();
  156. let write_query = self.query.as_ref().map(|q| q.write());
  157. match &self.ty {
  158. RouteType::Child(field) => {
  159. let write_nests = self.nests.iter().map(|id| nests[id.0].write());
  160. let write_segments = self.segments.iter().map(|s| s.write_segment());
  161. let child = field.ident.as_ref().unwrap();
  162. quote! {
  163. Self::#name { #(#dynamic_segments,)* #child } => {
  164. use std::fmt::Display;
  165. use std::fmt::Write;
  166. let mut route = String::new();
  167. {
  168. let f = &mut route;
  169. #(#write_nests)*
  170. #(#write_segments)*
  171. }
  172. if route.ends_with('/') {
  173. route.pop();
  174. }
  175. f.write_str(&route)?;
  176. #child.fmt(f)?;
  177. }
  178. }
  179. }
  180. RouteType::Leaf { .. } => {
  181. let write_nests = self.nests.iter().map(|id| nests[id.0].write());
  182. let write_segments = self.segments.iter().map(|s| s.write_segment());
  183. quote! {
  184. Self::#name { #(#dynamic_segments,)* } => {
  185. #(#write_nests)*
  186. #(#write_segments)*
  187. #write_query
  188. }
  189. }
  190. }
  191. }
  192. }
  193. pub fn routable_match(&self, layouts: &[Layout], nests: &[Nest]) -> TokenStream2 {
  194. let name = &self.route_name;
  195. let mut tokens = TokenStream2::new();
  196. // First match all layouts
  197. for (idx, layout_id) in self.layouts.iter().copied().enumerate() {
  198. let render_layout = layouts[layout_id.0].routable_match(nests);
  199. let dynamic_segments = self.dynamic_segments();
  200. let mut field_name = None;
  201. if let RouteType::Child(field) = &self.ty {
  202. field_name = field.ident.as_ref();
  203. }
  204. let field_name = field_name.map(|f| quote!(#f,));
  205. // This is a layout
  206. tokens.extend(quote! {
  207. #[allow(unused)]
  208. (#idx, Self::#name { #(#dynamic_segments,)* #field_name .. }) => {
  209. #render_layout
  210. }
  211. });
  212. }
  213. // Then match the route
  214. let last_index = self.layouts.len();
  215. tokens.extend(match &self.ty {
  216. RouteType::Child(field) => {
  217. let field_name = field.ident.as_ref().unwrap();
  218. quote! {
  219. #[allow(unused)]
  220. (#last_index.., Self::#name { #field_name, .. }) => {
  221. #field_name.render(level - #last_index)
  222. }
  223. }
  224. }
  225. RouteType::Leaf { component } => {
  226. let dynamic_segments = self.dynamic_segments();
  227. let dynamic_segments_from_route = self.dynamic_segments();
  228. quote! {
  229. #[allow(unused)]
  230. (#last_index, Self::#name { #(#dynamic_segments,)* }) => {
  231. rsx! {
  232. #component {
  233. #(#dynamic_segments_from_route: #dynamic_segments_from_route,)*
  234. }
  235. }
  236. }
  237. }
  238. }
  239. });
  240. tokens
  241. }
  242. fn dynamic_segments(&self) -> impl Iterator<Item = TokenStream2> + '_ {
  243. self.fields.iter().map(|(name, _)| {
  244. quote! {#name}
  245. })
  246. }
  247. pub fn construct(&self, nests: &[Nest], enum_name: Ident) -> TokenStream2 {
  248. let segments = self.fields.iter().map(|(name, _)| {
  249. let mut from_route = false;
  250. for id in &self.nests {
  251. let nest = &nests[id.0];
  252. if nest.dynamic_segments_names().any(|i| &i == name) {
  253. from_route = true
  254. }
  255. }
  256. for segment in &self.segments {
  257. if segment.name().as_ref() == Some(name) {
  258. from_route = true
  259. }
  260. }
  261. if let Some(query) = &self.query {
  262. if query.contains_ident(name) {
  263. from_route = true
  264. }
  265. }
  266. if from_route {
  267. quote! {#name}
  268. } else {
  269. quote! {#name: Default::default()}
  270. }
  271. });
  272. match &self.ty {
  273. RouteType::Child(field) => {
  274. let name = &self.route_name;
  275. let child_name = field.ident.as_ref().unwrap();
  276. quote! {
  277. #enum_name::#name {
  278. #child_name,
  279. #(#segments,)*
  280. }
  281. }
  282. }
  283. RouteType::Leaf { .. } => {
  284. let name = &self.route_name;
  285. quote! {
  286. #enum_name::#name {
  287. #(#segments,)*
  288. }
  289. }
  290. }
  291. }
  292. }
  293. pub fn error_ident(&self) -> Ident {
  294. format_ident!("{}ParseError", self.route_name)
  295. }
  296. pub fn error_type(&self) -> TokenStream2 {
  297. let error_name = self.error_ident();
  298. let child_type = match &self.ty {
  299. RouteType::Child(field) => Some(&field.ty),
  300. RouteType::Leaf { .. } => None,
  301. };
  302. create_error_type(error_name, &self.segments, child_type)
  303. }
  304. pub fn parse_query(&self) -> TokenStream2 {
  305. match &self.query {
  306. Some(query) => query.parse(),
  307. None => quote! {},
  308. }
  309. }
  310. }
  311. #[derive(Debug)]
  312. pub(crate) enum RouteType {
  313. Child(Field),
  314. Leaf { component: Path },
  315. }