autopulse_utils/
rewrite.rs

1use regex::Regex;
2use serde::Deserialize;
3
4/// Rewrites
5///
6/// This struct allows for a flexible way to define path rewrites using regex.
7///
8/// It can handle both single and multiple rewrites, where each rewrite consists of a `from` regex pattern and a `to` replacement string.
9///
10/// ```yml
11/// rewrite:
12///   from: '^/old/path/(.*)$'
13///   to: '/new/path/$1'
14/// ```
15/// or
16/// ```yml
17/// rewrite:
18///   - from: /testing
19///     to: /production
20///   - from: '^/old/path/(.*)$'
21///     to: '/new/path/$1'
22/// ``````
23#[derive(Clone)]
24pub struct Rewrite {
25    pub(crate) rewrites: Vec<SingleRewrite>,
26}
27
28impl<'de> Deserialize<'de> for Rewrite {
29    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30    where
31        D: serde::Deserializer<'de>,
32    {
33        #[derive(Deserialize)]
34        #[serde(untagged)]
35        enum Inner {
36            Single(SingleRewrite),
37            Multiple(Vec<SingleRewrite>),
38        }
39
40        let inner = Inner::deserialize(deserializer)?;
41
42        let rewrites = match inner {
43            Inner::Single(single) => {
44                vec![single]
45            }
46            Inner::Multiple(multiple) => multiple,
47        };
48
49        Ok(Rewrite { rewrites })
50    }
51}
52
53#[derive(Deserialize, Clone)]
54pub struct SingleRewrite {
55    /// Path to rewrite from
56    pub from: String,
57    /// Path to rewrite to
58    pub to: String,
59}
60
61impl Rewrite {
62    pub fn rewrite_path(&self, path: String) -> String {
63        let mut result = path;
64
65        for rewrite in &self.rewrites {
66            let from_regex = Regex::new(&rewrite.from).expect("Invalid regex in 'from' field");
67            result = from_regex.replace_all(&result, &rewrite.to).to_string();
68        }
69
70        result
71    }
72
73    #[cfg(test)]
74    pub fn single(from: &str, to: &str) -> Self {
75        Rewrite {
76            rewrites: vec![SingleRewrite {
77                from: from.to_string(),
78                to: to.to_string(),
79            }],
80        }
81    }
82
83    #[cfg(test)]
84    pub fn multiple(rewrites: Vec<(&str, &str)>) -> Self {
85        Rewrite {
86            rewrites: rewrites
87                .into_iter()
88                .map(|(from, to)| SingleRewrite {
89                    from: from.to_string(),
90                    to: to.to_string(),
91                })
92                .collect(),
93        }
94    }
95}