swc_typescript/fast_dts/util/
ast_ext.rs1use std::borrow::Cow;
2
3use swc_atoms::Atom;
4use swc_common::Mark;
5use swc_ecma_ast::{
6 BindingIdent, ComputedPropName, Expr, Ident, Lit, MemberProp, ObjectPatProp, Pat, Prop,
7 PropName, TsTypeAnn,
8};
9
10pub trait ExprExit {
11 fn get_root_ident(&self) -> Option<&Ident>;
12 fn get_global_symbol_prop(&self, unresolved_mark: Mark) -> Option<&MemberProp>;
13}
14
15impl ExprExit for Expr {
16 fn get_root_ident(&self) -> Option<&Ident> {
17 match self {
18 Expr::Member(member_expr) => member_expr.obj.get_root_ident(),
19 Expr::Ident(ident) => Some(ident),
20 Expr::OptChain(opt_chain_expr) => opt_chain_expr
21 .base
22 .as_member()
23 .and_then(|member_expr| member_expr.obj.get_root_ident()),
24 _ => None,
25 }
26 }
27
28 fn get_global_symbol_prop(&self, unresolved_mark: Mark) -> Option<&MemberProp> {
29 let (obj, prop) = (match self {
30 Expr::Member(member) => Some((&member.obj, &member.prop)),
31 Expr::OptChain(opt_chain) => opt_chain
32 .base
33 .as_member()
34 .map(|member| (&member.obj, &member.prop)),
35 _ => None,
36 })?;
37
38 if let Some(ident) = obj.as_ident() {
40 return if ident.sym.as_str() == "Symbol" && ident.ctxt.has_mark(unresolved_mark) {
43 Some(prop)
44 } else {
45 None
46 };
47 }
48
49 if let Some(member_expr) = obj.as_member() {
50 if let Some(ident) = member_expr.obj.as_ident() {
53 if ident.sym.as_str() == "globalThis"
54 && ident.ctxt.has_mark(unresolved_mark)
55 && member_expr.prop.is_ident_with("Symbol")
56 {
57 return Some(prop);
58 }
59 }
60 }
61
62 None
63 }
64}
65
66pub trait PatExt {
67 fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>>;
68 fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>);
69 fn bound_names<F: FnMut(&BindingIdent)>(&self, f: &mut F);
70}
71
72impl PatExt for Pat {
73 fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>> {
74 let pat = match self {
75 Pat::Assign(assign_pat) => &assign_pat.left,
76 _ => self,
77 };
78
79 match pat {
80 Pat::Ident(binding_ident) => &binding_ident.type_ann,
81 Pat::Array(array_pat) => &array_pat.type_ann,
82 Pat::Rest(rest_pat) => &rest_pat.type_ann,
83 Pat::Object(object_pat) => &object_pat.type_ann,
84 Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => &None,
85 #[cfg(swc_ast_unknown)]
86 _ => panic!("unable to access unknown nodes"),
87 }
88 }
89
90 fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>) {
91 let pat = match self {
92 Pat::Assign(assign_pat) => &mut assign_pat.left,
93 _ => self,
94 };
95
96 match pat {
97 Pat::Ident(binding_ident) => binding_ident.type_ann = type_anno,
98 Pat::Array(array_pat) => array_pat.type_ann = type_anno,
99 Pat::Rest(rest_pat) => rest_pat.type_ann = type_anno,
100 Pat::Object(object_pat) => object_pat.type_ann = type_anno,
101 Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => {}
102 #[cfg(swc_ast_unknown)]
103 _ => panic!("unable to access unknown nodes"),
104 }
105 }
106
107 fn bound_names<F: FnMut(&BindingIdent)>(&self, f: &mut F) {
108 match self {
109 Pat::Ident(binding_ident) => f(binding_ident),
110 Pat::Array(array_pat) => {
111 for pat in array_pat.elems.iter().flatten() {
112 pat.bound_names(f);
113 }
114 }
115 Pat::Rest(rest_pat) => rest_pat.arg.bound_names(f),
116 Pat::Object(object_pat) => {
117 for pat in &object_pat.props {
118 match pat {
119 ObjectPatProp::KeyValue(key_value_pat_prop) => {
120 key_value_pat_prop.value.bound_names(f)
121 }
122 ObjectPatProp::Assign(assign_pat_prop) => f(&assign_pat_prop.key),
123 ObjectPatProp::Rest(rest_pat) => rest_pat.arg.bound_names(f),
124 #[cfg(swc_ast_unknown)]
125 _ => panic!("unable to access unknown nodes"),
126 }
127 }
128 }
129 Pat::Assign(assign_pat) => assign_pat.left.bound_names(f),
130 Pat::Invalid(_) | Pat::Expr(_) => todo!(),
131 #[cfg(swc_ast_unknown)]
132 _ => panic!("unable to access unknown nodes"),
133 }
134 }
135}
136
137pub trait PropNameExit {
138 fn static_name(&self) -> Option<Cow<str>>;
139 fn static_prop(&self, unresolved_mark: Mark) -> Option<StaticProp>;
140}
141
142impl PropNameExit for PropName {
143 fn static_name(&self) -> Option<Cow<str>> {
144 match self {
145 PropName::Ident(ident_name) => Some(Cow::Borrowed(ident_name.sym.as_str())),
146 PropName::Str(string) => Some(Cow::Borrowed(string.value.as_str()?)),
147 PropName::Num(number) => Some(Cow::Owned(number.value.to_string())),
148 PropName::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())),
149 PropName::Computed(computed_prop_name) => computed_prop_name.static_name(),
150 #[cfg(swc_ast_unknown)]
151 _ => panic!("unable to access unknown nodes"),
152 }
153 }
154
155 fn static_prop(&self, unresolved_mark: Mark) -> Option<StaticProp> {
156 match self {
157 PropName::Computed(c) => c.static_prop(unresolved_mark),
158 prop => prop.static_name().map(Into::into).map(StaticProp::Name),
159 }
160 }
161}
162
163impl PropNameExit for ComputedPropName {
164 fn static_name(&self) -> Option<Cow<str>> {
165 match self.expr.as_ref() {
166 Expr::Lit(lit) => match lit {
167 Lit::Str(string) => Some(Cow::Borrowed(string.value.as_str()?)),
168 Lit::Bool(b) => Some(Cow::Owned(b.value.to_string())),
169 Lit::Null(_) => Some(Cow::Borrowed("null")),
170 Lit::Num(number) => Some(Cow::Owned(number.value.to_string())),
171 Lit::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())),
172 Lit::Regex(regex) => Some(Cow::Owned(regex.exp.to_string())),
173 Lit::JSXText(_) => None,
174 #[cfg(swc_ast_unknown)]
175 _ => panic!("unable to access unknown nodes"),
176 },
177 Expr::Tpl(tpl) if tpl.exprs.is_empty() => tpl
178 .quasis
179 .first()
180 .and_then(|e| e.cooked.as_ref())
181 .and_then(|atom| atom.as_str().map(Cow::Borrowed)),
182 _ => None,
183 }
184 }
185
186 fn static_prop(&self, unresolved_mark: Mark) -> Option<StaticProp> {
187 match self.expr.as_ref() {
188 Expr::Member(..) | Expr::OptChain(..) => self
189 .expr
190 .get_global_symbol_prop(unresolved_mark)
191 .and_then(|prop| match prop {
192 MemberProp::Ident(ident_name) => {
193 Some(StaticProp::Symbol(ident_name.sym.clone()))
194 }
195 MemberProp::Computed(c) => {
196 c.static_name().map(Into::into).map(StaticProp::Symbol)
197 }
198 MemberProp::PrivateName(..) => None,
199 #[cfg(swc_ast_unknown)]
200 _ => panic!("unable to access unknown nodes"),
201 }),
202 _ => self.static_name().map(Into::into).map(StaticProp::Name),
203 }
204 }
205}
206
207impl PropNameExit for Prop {
208 fn static_name(&self) -> Option<Cow<str>> {
209 match self {
210 Self::Shorthand(ident_name) => Some(Cow::Borrowed(ident_name.sym.as_str())),
211 Self::KeyValue(key_value_prop) => key_value_prop.key.static_name(),
212 Self::Assign(..) => None,
213 Self::Getter(getter_prop) => getter_prop.key.static_name(),
214 Self::Setter(setter_prop) => setter_prop.key.static_name(),
215 Self::Method(method_prop) => method_prop.key.static_name(),
216 #[cfg(swc_ast_unknown)]
217 _ => panic!("unable to access unknown nodes"),
218 }
219 }
220
221 fn static_prop(&self, unresolved_mark: Mark) -> Option<StaticProp> {
222 match self {
223 Self::Shorthand(ident_name) => Some(StaticProp::Name(ident_name.sym.clone())),
224 Self::KeyValue(key_value_prop) => key_value_prop.key.static_prop(unresolved_mark),
225 Self::Assign(..) => None,
226 Self::Getter(getter_prop) => getter_prop.key.static_prop(unresolved_mark),
227 Self::Setter(setter_prop) => setter_prop.key.static_prop(unresolved_mark),
228 Self::Method(method_prop) => method_prop.key.static_prop(unresolved_mark),
229 #[cfg(swc_ast_unknown)]
230 _ => panic!("unable to access unknown nodes"),
231 }
232 }
233}
234
235pub trait MemberPropExt {
236 fn static_name(&self) -> Option<&Atom>;
237}
238
239impl MemberPropExt for MemberProp {
240 fn static_name(&self) -> Option<&Atom> {
241 match self {
242 MemberProp::Ident(ident_name) => Some(&ident_name.sym),
243 MemberProp::Computed(computed_prop_name) => match computed_prop_name.expr.as_ref() {
244 Expr::Lit(Lit::Str(s)) => s.value.as_atom(),
245 Expr::Tpl(tpl) if tpl.quasis.len() == 1 && tpl.exprs.is_empty() => {
246 Some(&tpl.quasis[0].raw)
247 }
248 _ => None,
249 },
250 MemberProp::PrivateName(_) => None,
251 #[cfg(swc_ast_unknown)]
252 _ => panic!("unable to access unknown nodes"),
253 }
254 }
255}
256
257#[derive(Eq, Hash, PartialEq, Clone)]
258pub(crate) enum StaticProp {
259 Name(Atom),
260 Symbol(Atom),
261}