lambda_router_macros/router_macro/
route.rs1use lazy_regex::regex;
2use proc_macro2::Span;
3use quote::{quote, ToTokens, TokenStreamExt};
4use syn::{
5 parse::{Parse, ParseStream},
6 Error, Lit, LitStr, Result,
7};
8
9#[derive(Debug)]
10pub struct Route {
11 raw_route: String,
12 route_no_slash: String,
13 span: Span,
14}
15
16impl Parse for Route {
17 fn parse(input: ParseStream) -> Result<Self> {
18 let lit: Lit = input.parse()?;
19
20 let str_lit = match lit {
21 Lit::Str(str_lit) => str_lit,
22 _ => {
23 return Err(Error::new(lit.span(), "expected string literal for route"));
24 }
25 };
26 let route_string = str_lit.value();
27
28 let re = regex!(r#"\/"#);
29 let no_slashes = re.replace_all(route_string.as_str(), "");
30
31 Ok(Self {
32 route_no_slash: no_slashes.to_string(),
33 raw_route: route_string,
34 span: str_lit.span(),
35 })
36 }
37}
38
39impl Route {
40 pub fn lint(&self) -> Result<()> {
41 let re = regex!(r#"^\/[a-zA-Z0-9_\-]+$"#);
42
43 let err_msg = "invalid route, routes must start with a leading slash \"/\" and only consist of 0-9, a-z, A-Z, _, - ";
44
45 if !re.is_match(self.raw_route.as_str()) {
46 return Err(Error::new(self.span, err_msg));
47 }
48
49 Ok(())
50 }
51}
52
53impl ToTokens for Route {
54 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
55 let str_lit = LitStr::new(self.route_no_slash.as_str(), self.span);
56
57 let quoted = quote! {
58 #str_lit
59 };
60
61 tokens.append_all(quoted);
62 }
63}