use swc_atoms::Atom;
use swc_ecma_ast::*;
use super::Pure;
use crate::compress::util::is_valid_identifier;
impl Pure<'_> {
pub(super) fn optimize_property_of_member_expr(
&mut self,
obj: Option<&Expr>,
c: &mut ComputedPropName,
) -> Option<IdentName> {
if !self.options.props {
return None;
}
if let Some(Expr::Array(..) | Expr::Await(..) | Expr::Yield(..) | Expr::Lit(..)) = obj {
return None;
}
match &*c.expr {
Expr::Lit(Lit::Str(s)) => {
let value = s.value.as_str()?;
if value.is_reserved()
|| value.is_reserved_in_es3()
|| is_valid_identifier(value, true)
{
self.changed = true;
report_change!(
"properties: Computed member => member expr with identifier as a prop"
);
Some(IdentName {
span: s.span,
sym: unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
})
} else {
None
}
}
_ => None,
}
}
pub(super) fn optimize_computed_prop_name_as_normal(&mut self, p: &mut PropName) {
if !self.options.computed_props {
return;
}
if let PropName::Computed(c) = p {
match &mut *c.expr {
Expr::Lit(Lit::Str(s)) => {
let Some(value) = s.value.as_str() else {
return;
};
if value == "constructor" || value == "__proto__" {
return;
}
if value.is_reserved()
|| value.is_reserved_in_es3()
|| is_valid_identifier(value, false)
{
*p = PropName::Ident(IdentName::new(
unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
s.span,
));
} else {
*p = PropName::Str(s.clone());
}
}
Expr::Lit(Lit::Num(n)) if n.value.is_sign_positive() => {
*p = PropName::Num(n.clone());
}
Expr::Lit(Lit::Num(..)) => {}
_ => {}
}
}
}
pub(super) fn optimize_prop_name(&mut self, name: &mut PropName) {
if let PropName::Str(s) = name {
let Some(value) = s.value.as_str() else {
return;
};
if value.is_reserved()
|| value.is_reserved_in_es3()
|| is_valid_identifier(value, false)
{
self.changed = true;
report_change!("misc: Optimizing string property name");
*name = PropName::Ident(IdentName {
span: s.span,
sym: unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
});
return;
}
if (!value.starts_with('0') && !value.starts_with('+')) || value.len() <= 1 {
if let Ok(v) = value.parse::<u32>() {
self.changed = true;
report_change!("misc: Optimizing numeric property name");
*name = PropName::Num(Number {
span: s.span,
value: v as _,
raw: None,
});
}
}
}
}
pub(super) fn handle_known_computed_member_expr(
&mut self,
c: &mut ComputedPropName,
) -> Option<IdentName> {
if !self.options.props || !self.options.evaluate {
return None;
}
match &*c.expr {
Expr::Lit(Lit::Str(s)) => {
let value = s.value.as_str()?;
if value.is_empty()
|| value.starts_with(|c: char| c.is_ascii_digit())
|| value
.contains(|c: char| !matches!(c, '0'..='9' | 'a'..='z' | 'A'..='Z' | '$'))
{
return None;
}
self.changed = true;
Some(IdentName::new(
unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
s.span,
))
}
_ => None,
}
}
}