1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use serde::Deserialize;
use swc_cached::regex::CachedRegex;
use swc_ecma_ast::*;
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};

#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Config {
    All(bool),
    WithOptions(Options),
}

impl Config {
    pub fn truthy(&self) -> bool {
        match self {
            Config::All(b) => *b,
            Config::WithOptions(_) => true,
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct Options {
    #[serde(default)]
    pub properties: Vec<String>,
}

pub fn react_remove_properties(config: Config) -> impl Fold {
    let mut properties: Vec<CachedRegex> = match config {
        Config::WithOptions(x) => x
            .properties
            .iter()
            .map(|pattern| {
                CachedRegex::new(pattern).unwrap_or_else(|e| {
                    panic!("error compiling property regex `{}`: {}", pattern, e);
                })
            })
            .collect(),
        _ => vec![],
    };
    if properties.is_empty() {
        // Keep the default regex identical to `babel-plugin-react-remove-properties`.
        properties.push(CachedRegex::new(r"^data-test").unwrap());
    }
    RemoveProperties { properties }
}

struct RemoveProperties {
    properties: Vec<CachedRegex>,
}

impl RemoveProperties {
    fn should_remove_property(&self, name: &str) -> bool {
        self.properties.iter().any(|p| p.is_match(name))
    }
}

impl Fold for RemoveProperties {
    noop_fold_type!();

    fn fold_jsx_opening_element(&mut self, mut el: JSXOpeningElement) -> JSXOpeningElement {
        el.attrs.retain(|attr| {
            !matches!(attr, JSXAttrOrSpread::JSXAttr(JSXAttr {
              name: JSXAttrName::Ident(ident),
              ..
            }) if self.should_remove_property(ident.sym.as_ref()))
        });
        el.fold_children_with(self)
    }
}