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
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use swc_atoms::{js_word, JsWord};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Parallel;
use swc_ecma_transforms_macros::parallel;
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};

pub fn reserved_words() -> impl 'static + Fold + VisitMut {
    as_folder(EsReservedWord)
}

#[derive(Clone, Copy)]
struct EsReservedWord;

impl Parallel for EsReservedWord {
    fn create(&self) -> Self {
        *self
    }

    fn merge(&mut self, _: Self) {}
}

#[parallel]
impl VisitMut for EsReservedWord {
    noop_visit_mut_type!();

    fn visit_mut_export_specifier(&mut self, _n: &mut ExportSpecifier) {}

    fn visit_mut_ident(&mut self, i: &mut Ident) {
        rename_ident(&mut i.sym, true);
    }

    fn visit_mut_import_named_specifier(&mut self, s: &mut ImportNamedSpecifier) {
        s.local.visit_mut_with(self);
    }

    fn visit_mut_member_expr(&mut self, e: &mut MemberExpr) {
        match &e.obj {
            ExprOrSuper::Super(_) => {}
            ExprOrSuper::Expr(obj) => match &**obj {
                Expr::Ident(Ident {
                    sym: js_word!("new"),
                    ..
                })
                | Expr::Ident(Ident {
                    sym: js_word!("import"),
                    ..
                }) => return,
                _ => {}
            },
        }
        e.obj.visit_mut_with(self);

        if e.computed {
            e.prop.visit_mut_with(self);
        }
    }

    fn visit_mut_meta_prop_expr(&mut self, _n: &mut MetaPropExpr) {}

    fn visit_mut_prop_name(&mut self, _n: &mut PropName) {}
}

fn is_reserved(sym: &JsWord) -> bool {
    match *sym {
        js_word!("enum")
        | js_word!("implements")
        | js_word!("package")
        | js_word!("protected")
        | js_word!("interface")
        | js_word!("private")
        | js_word!("public")
        | js_word!("await")
        | js_word!("break")
        | js_word!("case")
        | js_word!("catch")
        | js_word!("class")
        | js_word!("const")
        | js_word!("continue")
        | js_word!("debugger")
        | js_word!("default")
        | js_word!("delete")
        | js_word!("do")
        | js_word!("else")
        | js_word!("export")
        | js_word!("extends")
        | js_word!("finally")
        | js_word!("for")
        | js_word!("function")
        | js_word!("if")
        | js_word!("in")
        | js_word!("instanceof")
        | js_word!("new")
        | js_word!("return")
        | js_word!("super")
        | js_word!("switch")
        | js_word!("this")
        | js_word!("throw")
        | js_word!("try")
        | js_word!("typeof")
        | js_word!("var")
        | js_word!("void")
        | js_word!("while")
        | js_word!("with")
        | js_word!("yield") => true,

        _ => false,
    }
}

fn rename_ident(sym: &mut JsWord, _strict: bool) {
    // Es
    if is_reserved(&*sym) {
        let s = format!("_{}", sym).into();
        *sym = s;
    }
}