lambda_router_macros/router_macro/
route.rs

1use 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}