Implement hash fragments in the router (#2320)
* implement hash fragments in the router * clean up query and search example --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
dd8e69635b
commit
08da9a1253
17 files changed
+550
-190
No files matched your search
@@ -3,7 +3,7 @@ use syn::{Ident, Type};
|
||||
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
|
||||
use crate::query::{FullQuerySegment, QueryArgument, QuerySegment};
|
||||
use crate::{hash::HashFragment, query::QuerySegment};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RouteSegment {
|
||||
@@ -24,7 +24,12 @@ impl RouteSegment {
|
||||
pub fn write_segment(&self) -> TokenStream2 {
|
||||
match self {
|
||||
Self::Static(segment) => quote! { write!(f, "/{}", #segment)?; },
|
||||
Self::Dynamic(ident, _) => quote! { write!(f, "/{}", #ident)?; },
|
||||
Self::Dynamic(ident, _) => quote! {
|
||||
{
|
||||
let as_string = #ident.to_string();
|
||||
write!(f, "/{}", dioxus_router::exports::urlencoding::encode(&as_string))?;
|
||||
}
|
||||
},
|
||||
Self::CatchAll(ident, _) => quote! { #ident.display_route_segments(f)?; },
|
||||
}
|
||||
}
|
||||
@@ -130,15 +135,38 @@ pub fn static_segment_idx(idx: usize) -> Ident {
|
||||
|
||||
pub fn parse_route_segments<'a>(
|
||||
route_span: Span,
|
||||
fields: impl Iterator<Item = (&'a Ident, &'a Type)> + Clone,
|
||||
mut fields: impl Iterator<Item = (&'a Ident, &'a Type)> + Clone,
|
||||
route: &str,
|
||||
) -> syn::Result<(Vec<RouteSegment>, Option<QuerySegment>)> {
|
||||
) -> syn::Result<(
|
||||
Vec<RouteSegment>,
|
||||
Option<QuerySegment>,
|
||||
Option<HashFragment>,
|
||||
)> {
|
||||
let mut route_segments = Vec::new();
|
||||
|
||||
let (route_string, query) = match route.rsplit_once('?') {
|
||||
Some((route, query)) => (route, Some(query)),
|
||||
let (route_string, hash) = match route.rsplit_once('#') {
|
||||
Some((route, hash)) => (
|
||||
route,
|
||||
Some(HashFragment::parse_from_str(
|
||||
route_span,
|
||||
fields.clone(),
|
||||
hash,
|
||||
)?),
|
||||
),
|
||||
None => (route, None),
|
||||
};
|
||||
|
||||
let (route_string, query) = match route_string.rsplit_once('?') {
|
||||
Some((route, query)) => (
|
||||
route,
|
||||
Some(QuerySegment::parse_from_str(
|
||||
route_span,
|
||||
fields.clone(),
|
||||
query,
|
||||
)?),
|
||||
),
|
||||
None => (route_string, None),
|
||||
};
|
||||
let mut iterator = route_string.split('/');
|
||||
|
||||
// skip the first empty segment
|
||||
@@ -198,66 +226,7 @@ pub fn parse_route_segments<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
// check if the route has a query string
|
||||
let parsed_query = match query {
|
||||
Some(query) => {
|
||||
if let Some(query) = query.strip_prefix(":..") {
|
||||
let query_ident = Ident::new(query, Span::call_site());
|
||||
let field = fields.clone().find(|(name, _)| *name == &query_ident);
|
||||
|
||||
let ty = if let Some((_, ty)) = field {
|
||||
ty.clone()
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
route_span,
|
||||
format!("Could not find a field with the name '{}'", query_ident),
|
||||
));
|
||||
};
|
||||
|
||||
Some(QuerySegment::Single(FullQuerySegment {
|
||||
ident: query_ident,
|
||||
ty,
|
||||
}))
|
||||
} else {
|
||||
let mut query_arguments = Vec::new();
|
||||
for segment in query.split('&') {
|
||||
if segment.is_empty() {
|
||||
return Err(syn::Error::new(
|
||||
route_span,
|
||||
"Query segments should be non-empty",
|
||||
));
|
||||
}
|
||||
if let Some(query_argument) = segment.strip_prefix(':') {
|
||||
let query_ident = Ident::new(query_argument, Span::call_site());
|
||||
let field = fields.clone().find(|(name, _)| *name == &query_ident);
|
||||
|
||||
let ty = if let Some((_, ty)) = field {
|
||||
ty.clone()
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
route_span,
|
||||
format!("Could not find a field with the name '{}'", query_ident),
|
||||
));
|
||||
};
|
||||
|
||||
query_arguments.push(QueryArgument {
|
||||
ident: query_ident,
|
||||
ty,
|
||||
});
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
route_span,
|
||||
"Query segments should be a : followed by the name of the query argument",
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(QuerySegment::Segments(query_arguments))
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok((route_segments, parsed_query))
|
||||
Ok((route_segments, query, hash))
|
||||
}
|
||||
|
||||
pub(crate) fn create_error_type(
|
||||
|
||||
Reference in new issue
Block a user