intlayer_swc_plugin/
ast.rs1use base62::encode as base62_encode;
5use std::hash::{BuildHasher, BuildHasherDefault, Hasher};
6use swc_core::{
7 common::{SyntaxContext, DUMMY_SP},
8 ecma::{ast::*, atoms::Atom},
9};
10use twox_hash::XxHash64;
11
12#[cfg(swc_ast_unknown)]
27pub fn unsupported_ast_node(node_kind: &str) -> ! {
28 panic!(
29 "@intlayer/swc does not understand the `{node_kind}` node your bundler's \
30 SWC produced — the plugin is older than the syntax in this file. \
31 Upgrade @intlayer/swc, or set `build.optimize: false` in your Intlayer \
32 configuration to build without the transform."
33 )
34}
35
36pub fn split_namespace(namespace: &str) -> (&str, &str) {
44 if let Some(dot_position) = namespace.find('.') {
45 (&namespace[..dot_position], &namespace[dot_position + 1..])
46 } else {
47 (namespace, "")
48 }
49}
50
51pub fn read_static_string(expr: &Expr) -> Option<String> {
54 match expr {
55 Expr::Lit(Lit::Str(Str { value, .. })) => Some(value.to_string_lossy().into_owned()),
56 Expr::Tpl(Tpl { exprs, quasis, .. }) if exprs.is_empty() && quasis.len() == 1 => {
57 Some(quasis[0].raw.to_string())
58 }
59 _ => None,
60 }
61}
62
63pub fn prop_name_matches(key: &PropName, property: &str) -> bool {
65 match key {
66 PropName::Ident(ident) => ident.sym.as_str() == property,
67 PropName::Str(string_key) => string_key.value.to_string_lossy() == property,
68 _ => false,
69 }
70}
71
72pub fn read_prop_name(key: &PropName) -> Option<String> {
75 match key {
76 PropName::Ident(ident) => Some(ident.sym.to_string()),
77 PropName::Str(string_key) => Some(string_key.value.to_string_lossy().into_owned()),
78 _ => None,
79 }
80}
81
82pub fn read_member_prop_name(prop: &MemberProp) -> Option<String> {
85 match prop {
86 MemberProp::Ident(ident) => Some(ident.sym.to_string()),
87 MemberProp::Computed(computed) => match &*computed.expr {
88 Expr::Lit(Lit::Str(Str { value, .. })) => Some(value.to_string_lossy().into_owned()),
89 _ => None,
90 },
91 MemberProp::PrivateName(_) => None,
92 #[cfg(swc_ast_unknown)]
93 _ => unsupported_ast_node("MemberProp"),
94 }
95}
96
97pub fn write_member_prop_name(prop: &mut MemberProp, name: &str) {
100 match prop {
101 MemberProp::Ident(ident) => ident.sym = Atom::from(name),
102 MemberProp::Computed(computed) => {
103 *computed.expr = Expr::Lit(Lit::Str(make_str(name)));
104 }
105 MemberProp::PrivateName(_) => {}
106 #[cfg(swc_ast_unknown)]
107 _ => unsupported_ast_node("MemberProp"),
108 }
109}
110
111pub fn is_numeric_index_prop(prop: &MemberProp) -> bool {
113 matches!(prop, MemberProp::Computed(computed) if matches!(&*computed.expr, Expr::Lit(Lit::Num(_))))
114}
115
116pub fn unwrap_expr(expr: &Expr) -> &Expr {
119 match expr {
120 Expr::Paren(paren) => unwrap_expr(&paren.expr),
121 Expr::TsAs(ts_as) => unwrap_expr(&ts_as.expr),
122 Expr::TsNonNull(ts_non_null) => unwrap_expr(&ts_non_null.expr),
123 Expr::TsSatisfies(ts_satisfies) => unwrap_expr(&ts_satisfies.expr),
124 other => other,
125 }
126}
127
128pub fn make_str(value: &str) -> Str {
130 Str {
131 span: DUMMY_SP,
132 value: Atom::from(value).into(),
133 raw: None,
134 }
135}
136
137pub fn make_ident(name: &str) -> Ident {
139 Ident::new(Atom::from(name), DUMMY_SP, SyntaxContext::empty())
140}
141
142pub fn make_string_arg(value: &str) -> ExprOrSpread {
144 ExprOrSpread {
145 spread: None,
146 expr: Box::new(Expr::Lit(Lit::Str(make_str(value)))),
147 }
148}
149
150pub fn make_ident_arg(ident: Ident) -> ExprOrSpread {
152 ExprOrSpread {
153 spread: None,
154 expr: Box::new(Expr::Ident(ident)),
155 }
156}
157
158pub fn make_hashed_ident(key: &str, suffix: &str) -> Ident {
162 let mut hasher = BuildHasherDefault::<XxHash64>::default().build_hasher();
163 hasher.write(key.as_bytes());
164 let hash = hasher.finish();
165 let mut encoded = base62_encode(hash);
166 encoded.insert(0, '_');
167 encoded.push_str(suffix);
168 make_ident(&encoded)
169}
170
171pub fn callee_ident_name(callee: &Callee) -> Option<&str> {
173 match callee {
174 Callee::Expr(callee_expr) => match &**callee_expr {
175 Expr::Ident(ident) => Some(ident.sym.as_ref()),
176 _ => None,
177 },
178 _ => None,
179 }
180}
181
182pub fn imported_specifier_name(named: &ImportNamedSpecifier) -> String {
185 match &named.imported {
186 Some(ModuleExportName::Ident(ident)) => ident.sym.to_string(),
187 Some(ModuleExportName::Str(string_name)) => {
188 string_name.value.to_string_lossy().into_owned()
189 }
190 None => named.local.sym.to_string(),
191 #[cfg(swc_ast_unknown)]
192 Some(_) => unsupported_ast_node("ModuleExportName"),
193 }
194}