use base62::encode as base62_encode;
use std::hash::{BuildHasher, BuildHasherDefault, Hasher};
use swc_core::{
common::{SyntaxContext, DUMMY_SP},
ecma::{ast::*, atoms::Atom},
};
use twox_hash::XxHash64;
#[cfg(swc_ast_unknown)]
pub fn unsupported_ast_node(node_kind: &str) -> ! {
panic!(
"@intlayer/swc does not understand the `{node_kind}` node your bundler's \
SWC produced — the plugin is older than the syntax in this file. \
Upgrade @intlayer/swc, or set `build.optimize: false` in your Intlayer \
configuration to build without the transform."
)
}
pub fn split_namespace(namespace: &str) -> (&str, &str) {
if let Some(dot_position) = namespace.find('.') {
(&namespace[..dot_position], &namespace[dot_position + 1..])
} else {
(namespace, "")
}
}
pub fn read_static_string(expr: &Expr) -> Option<String> {
match expr {
Expr::Lit(Lit::Str(Str { value, .. })) => Some(value.to_string_lossy().into_owned()),
Expr::Tpl(Tpl { exprs, quasis, .. }) if exprs.is_empty() && quasis.len() == 1 => {
Some(quasis[0].raw.to_string())
}
_ => None,
}
}
pub fn prop_name_matches(key: &PropName, property: &str) -> bool {
match key {
PropName::Ident(ident) => ident.sym.as_str() == property,
PropName::Str(string_key) => string_key.value.to_string_lossy() == property,
_ => false,
}
}
pub fn read_prop_name(key: &PropName) -> Option<String> {
match key {
PropName::Ident(ident) => Some(ident.sym.to_string()),
PropName::Str(string_key) => Some(string_key.value.to_string_lossy().into_owned()),
_ => None,
}
}
pub fn read_member_prop_name(prop: &MemberProp) -> Option<String> {
match prop {
MemberProp::Ident(ident) => Some(ident.sym.to_string()),
MemberProp::Computed(computed) => match &*computed.expr {
Expr::Lit(Lit::Str(Str { value, .. })) => Some(value.to_string_lossy().into_owned()),
_ => None,
},
MemberProp::PrivateName(_) => None,
#[cfg(swc_ast_unknown)]
_ => unsupported_ast_node("MemberProp"),
}
}
pub fn write_member_prop_name(prop: &mut MemberProp, name: &str) {
match prop {
MemberProp::Ident(ident) => ident.sym = Atom::from(name),
MemberProp::Computed(computed) => {
*computed.expr = Expr::Lit(Lit::Str(make_str(name)));
}
MemberProp::PrivateName(_) => {}
#[cfg(swc_ast_unknown)]
_ => unsupported_ast_node("MemberProp"),
}
}
pub fn is_numeric_index_prop(prop: &MemberProp) -> bool {
matches!(prop, MemberProp::Computed(computed) if matches!(&*computed.expr, Expr::Lit(Lit::Num(_))))
}
pub fn unwrap_expr(expr: &Expr) -> &Expr {
match expr {
Expr::Paren(paren) => unwrap_expr(&paren.expr),
Expr::TsAs(ts_as) => unwrap_expr(&ts_as.expr),
Expr::TsNonNull(ts_non_null) => unwrap_expr(&ts_non_null.expr),
Expr::TsSatisfies(ts_satisfies) => unwrap_expr(&ts_satisfies.expr),
other => other,
}
}
pub fn make_str(value: &str) -> Str {
Str {
span: DUMMY_SP,
value: Atom::from(value).into(),
raw: None,
}
}
pub fn make_ident(name: &str) -> Ident {
Ident::new(Atom::from(name), DUMMY_SP, SyntaxContext::empty())
}
pub fn make_string_arg(value: &str) -> ExprOrSpread {
ExprOrSpread {
spread: None,
expr: Box::new(Expr::Lit(Lit::Str(make_str(value)))),
}
}
pub fn make_ident_arg(ident: Ident) -> ExprOrSpread {
ExprOrSpread {
spread: None,
expr: Box::new(Expr::Ident(ident)),
}
}
pub fn make_hashed_ident(key: &str, suffix: &str) -> Ident {
let mut hasher = BuildHasherDefault::<XxHash64>::default().build_hasher();
hasher.write(key.as_bytes());
let hash = hasher.finish();
let mut encoded = base62_encode(hash);
encoded.insert(0, '_');
encoded.push_str(suffix);
make_ident(&encoded)
}
pub fn callee_ident_name(callee: &Callee) -> Option<&str> {
match callee {
Callee::Expr(callee_expr) => match &**callee_expr {
Expr::Ident(ident) => Some(ident.sym.as_ref()),
_ => None,
},
_ => None,
}
}
pub fn imported_specifier_name(named: &ImportNamedSpecifier) -> String {
match &named.imported {
Some(ModuleExportName::Ident(ident)) => ident.sym.to_string(),
Some(ModuleExportName::Str(string_name)) => {
string_name.value.to_string_lossy().into_owned()
}
None => named.local.sym.to_string(),
#[cfg(swc_ast_unknown)]
Some(_) => unsupported_ast_node("ModuleExportName"),
}
}