swc_ecma_minifier/compress/pure/
properties.rs1use swc_atoms::Atom;
2use swc_ecma_ast::*;
3
4use super::Pure;
5use crate::compress::util::is_valid_identifier;
6
7impl Pure<'_> {
8 pub(super) fn optimize_property_of_member_expr(
9 &mut self,
10 obj: Option<&Expr>,
11 c: &mut ComputedPropName,
12 ) -> Option<IdentName> {
13 if !self.options.props {
14 return None;
15 }
16 if let Some(Expr::Array(..) | Expr::Await(..) | Expr::Yield(..) | Expr::Lit(..)) = obj {
17 return None;
18 }
19
20 match &*c.expr {
21 Expr::Lit(Lit::Str(s)) => {
22 let value = s.value.as_str()?;
23 if value.is_reserved()
24 || value.is_reserved_in_es3()
25 || is_valid_identifier(value, true)
26 {
27 self.changed = true;
28 report_change!(
29 "properties: Computed member => member expr with identifier as a prop"
30 );
31
32 Some(IdentName {
33 span: s.span,
34 sym: unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
36 })
37 } else {
38 None
39 }
40 }
41
42 _ => None,
43 }
44 }
45
46 pub(super) fn optimize_computed_prop_name_as_normal(&mut self, p: &mut PropName) {
49 if !self.options.computed_props {
50 return;
51 }
52
53 if let PropName::Computed(c) = p {
54 match &mut *c.expr {
55 Expr::Lit(Lit::Str(s)) => {
56 let Some(value) = s.value.as_str() else {
57 return;
58 };
59 if value == "constructor" || value == "__proto__" {
60 return;
61 }
62
63 if value.is_reserved()
64 || value.is_reserved_in_es3()
65 || is_valid_identifier(value, false)
66 {
67 *p = PropName::Ident(IdentName::new(
68 unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
70 s.span,
71 ));
72 } else {
73 *p = PropName::Str(s.clone());
74 }
75 }
76 Expr::Lit(Lit::Num(n)) => {
77 if n.value.is_sign_positive() {
78 *p = PropName::Num(n.clone());
79 }
80 }
81 _ => {}
82 }
83 }
84 }
85
86 pub(super) fn optimize_prop_name(&mut self, name: &mut PropName) {
87 if let PropName::Str(s) = name {
88 let Some(value) = s.value.as_str() else {
89 return;
90 };
91 if value.is_reserved()
92 || value.is_reserved_in_es3()
93 || is_valid_identifier(value, false)
94 {
95 self.changed = true;
96 report_change!("misc: Optimizing string property name");
97 *name = PropName::Ident(IdentName {
98 span: s.span,
99 sym: unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
101 });
102 return;
103 }
104
105 if (!value.starts_with('0') && !value.starts_with('+')) || value.len() <= 1 {
106 if let Ok(v) = value.parse::<u32>() {
107 self.changed = true;
108 report_change!("misc: Optimizing numeric property name");
109 *name = PropName::Num(Number {
110 span: s.span,
111 value: v as _,
112 raw: None,
113 });
114 }
115 }
116 }
117 }
118
119 pub(super) fn handle_known_computed_member_expr(
120 &mut self,
121 c: &mut ComputedPropName,
122 ) -> Option<IdentName> {
123 if !self.options.props || !self.options.evaluate {
124 return None;
125 }
126
127 match &*c.expr {
128 Expr::Lit(Lit::Str(s)) => {
129 let value = s.value.as_str()?;
130 if value.is_empty()
131 || value.starts_with(|c: char| c.is_ascii_digit())
132 || value
133 .contains(|c: char| !matches!(c, '0'..='9' | 'a'..='z' | 'A'..='Z' | '$'))
134 {
135 return None;
136 }
137
138 self.changed = true;
139
140 Some(IdentName::new(
141 unsafe { Atom::from_wtf8_unchecked(s.value.clone()) },
143 s.span,
144 ))
145 }
146 _ => None,
147 }
148 }
149}