swc_typescript/fast_dts/util/
ast_ext.rs

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use std::borrow::Cow;

use swc_atoms::Atom;
use swc_ecma_ast::{
    BindingIdent, Expr, Ident, Lit, MemberProp, ObjectPatProp, Pat, PropName, TsTypeAnn,
};

pub trait ExprExit {
    fn get_root_ident(&self) -> Option<&Ident>;
}

impl ExprExit for Expr {
    fn get_root_ident(&self) -> Option<&Ident> {
        match self {
            Expr::Member(member_expr) => member_expr.obj.get_root_ident(),
            Expr::Ident(ident) => Some(ident),
            Expr::OptChain(opt_chain_expr) => opt_chain_expr
                .base
                .as_member()
                .and_then(|member_expr| member_expr.obj.get_root_ident()),
            _ => None,
        }
    }
}

pub trait PatExt {
    fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>>;
    fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>);
    fn bound_names<F: FnMut(&BindingIdent)>(&self, f: &mut F);
}

impl PatExt for Pat {
    fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>> {
        let pat = match self {
            Pat::Assign(assign_pat) => &assign_pat.left,
            _ => self,
        };

        match pat {
            Pat::Ident(binding_ident) => &binding_ident.type_ann,
            Pat::Array(array_pat) => &array_pat.type_ann,
            Pat::Rest(rest_pat) => &rest_pat.type_ann,
            Pat::Object(object_pat) => &object_pat.type_ann,
            Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => &None,
        }
    }

    fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>) {
        let pat = match self {
            Pat::Assign(assign_pat) => &mut assign_pat.left,
            _ => self,
        };

        match pat {
            Pat::Ident(binding_ident) => binding_ident.type_ann = type_anno,
            Pat::Array(array_pat) => array_pat.type_ann = type_anno,
            Pat::Rest(rest_pat) => rest_pat.type_ann = type_anno,
            Pat::Object(object_pat) => object_pat.type_ann = type_anno,
            Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => {}
        }
    }

    fn bound_names<F: FnMut(&BindingIdent)>(&self, f: &mut F) {
        match self {
            Pat::Ident(binding_ident) => f(binding_ident),
            Pat::Array(array_pat) => {
                for pat in array_pat.elems.iter().flatten() {
                    pat.bound_names(f);
                }
            }
            Pat::Rest(rest_pat) => rest_pat.arg.bound_names(f),
            Pat::Object(object_pat) => {
                for pat in &object_pat.props {
                    match pat {
                        ObjectPatProp::KeyValue(key_value_pat_prop) => {
                            key_value_pat_prop.value.bound_names(f)
                        }
                        ObjectPatProp::Assign(assign_pat_prop) => f(&assign_pat_prop.key),
                        ObjectPatProp::Rest(rest_pat) => rest_pat.arg.bound_names(f),
                    }
                }
            }
            Pat::Assign(assign_pat) => assign_pat.left.bound_names(f),
            Pat::Invalid(_) | Pat::Expr(_) => todo!(),
        }
    }
}

pub trait PropNameExit {
    fn static_name(&self) -> Option<Cow<str>>;
}

impl PropNameExit for PropName {
    fn static_name(&self) -> Option<Cow<str>> {
        match self {
            PropName::Ident(ident_name) => Some(Cow::Borrowed(ident_name.sym.as_str())),
            PropName::Str(string) => Some(Cow::Borrowed(string.value.as_str())),
            PropName::Num(number) => Some(Cow::Owned(number.value.to_string())),
            PropName::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())),
            PropName::Computed(computed_prop_name) => match computed_prop_name.expr.as_ref() {
                Expr::Lit(lit) => match lit {
                    Lit::Str(string) => Some(Cow::Borrowed(string.value.as_str())),
                    Lit::Bool(b) => Some(Cow::Owned(b.value.to_string())),
                    Lit::Null(_) => Some(Cow::Borrowed("null")),
                    Lit::Num(number) => Some(Cow::Owned(number.value.to_string())),
                    Lit::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())),
                    Lit::Regex(regex) => Some(Cow::Owned(regex.exp.to_string())),
                    Lit::JSXText(_) => None,
                },
                Expr::Tpl(tpl) if tpl.exprs.is_empty() => tpl
                    .quasis
                    .first()
                    .and_then(|e| e.cooked.as_ref())
                    .map(|atom| Cow::Borrowed(atom.as_str())),
                _ => None,
            },
        }
    }
}

pub trait MemberPropExt {
    fn static_name(&self) -> Option<&Atom>;
}

impl MemberPropExt for MemberProp {
    fn static_name(&self) -> Option<&Atom> {
        match self {
            MemberProp::Ident(ident_name) => Some(&ident_name.sym),
            MemberProp::Computed(computed_prop_name) => match computed_prop_name.expr.as_ref() {
                Expr::Lit(Lit::Str(s)) => Some(&s.value),
                Expr::Tpl(tpl) if tpl.quasis.len() == 1 && tpl.exprs.is_empty() => {
                    Some(&tpl.quasis[0].raw)
                }
                _ => None,
            },
            MemberProp::PrivateName(_) => None,
        }
    }
}