rumdl_lib/utils/
jinja_utils.rs1use regex::Regex;
2use std::sync::LazyLock;
3
4static JINJA_EXPRESSION_REGEX: LazyLock<Regex> =
6 LazyLock::new(|| Regex::new(r"\{\{.*?\}\}").expect("Failed to compile Jinja expression regex"));
7
8static JINJA_STATEMENT_REGEX: LazyLock<Regex> =
9 LazyLock::new(|| Regex::new(r"\{%.*?%\}").expect("Failed to compile Jinja statement regex"));
10
11pub fn find_jinja_ranges(content: &str) -> Vec<(usize, usize)> {
13 let mut ranges = Vec::new();
14
15 for mat in JINJA_EXPRESSION_REGEX.find_iter(content) {
17 ranges.push((mat.start(), mat.end()));
18 }
19
20 for mat in JINJA_STATEMENT_REGEX.find_iter(content) {
22 ranges.push((mat.start(), mat.end()));
23 }
24
25 ranges.sort_by_key(|r| r.0);
27 ranges
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn test_find_jinja_ranges_expressions() {
36 let content = "Some text {{ variable }} more text";
37 let ranges = find_jinja_ranges(content);
38 assert_eq!(ranges.len(), 1);
39 assert_eq!(&content[ranges[0].0..ranges[0].1], "{{ variable }}");
40 }
41
42 #[test]
43 fn test_find_jinja_ranges_statements() {
44 let content = "{% if condition %} text {% endif %}";
45 let ranges = find_jinja_ranges(content);
46 assert_eq!(ranges.len(), 2);
47 assert_eq!(&content[ranges[0].0..ranges[0].1], "{% if condition %}");
48 assert_eq!(&content[ranges[1].0..ranges[1].1], "{% endif %}");
49 }
50
51 #[test]
52 fn test_find_jinja_ranges_complex_expression() {
53 let content = "{{ pd_read_csv()[index] | filter }}";
54 let ranges = find_jinja_ranges(content);
55 assert_eq!(ranges.len(), 1);
56 assert_eq!(ranges[0], (0, content.len()));
57 }
58
59 #[test]
60 fn test_find_jinja_ranges_sorted() {
61 let content = "{% if x %} foo {{ bar }} baz {% endif %}";
62 let ranges = find_jinja_ranges(content);
63 assert_eq!(ranges.len(), 3);
64 assert!(ranges[0].0 < ranges[1].0);
65 assert!(ranges[1].0 < ranges[2].0);
66 }
67}