1#![cfg_attr(not(feature = "extra-serde"), allow(unused))]
2
3use std::sync::Arc;
4
5use parking_lot::RwLock;
6use rustc_hash::FxHashMap;
7use serde::{Deserialize, Serialize};
8use swc_atoms::Atom;
9use swc_common::Mark;
10use swc_config::{merge::Merge, CachedRegex};
11use swc_ecma_ast::{EsVersion, Expr, Id};
12
13macro_rules! impl_default {
15 ($T:ty) => {
16 impl Default for $T {
17 fn default() -> Self {
18 serde_json::from_value(serde_json::Value::Object(Default::default())).unwrap()
19 }
20 }
21 };
22}
23
24pub mod terser;
25
26pub struct ExtraOptions {
28 pub unresolved_mark: Mark,
30
31 pub top_level_mark: Mark,
33
34 pub mangle_name_cache: Option<Arc<dyn MangleCache>>,
35}
36
37#[derive(Debug, Default, Clone)]
38#[cfg_attr(feature = "extra-serde", derive(Serialize, Deserialize))]
39#[cfg_attr(feature = "extra-serde", serde(rename_all = "camelCase"))]
40#[cfg_attr(feature = "extra-serde", serde(deny_unknown_fields))]
41pub struct MinifyOptions {
42 #[cfg_attr(feature = "extra-serde", serde(default))]
43 pub rename: bool,
44 #[cfg_attr(feature = "extra-serde", serde(default))]
45 pub compress: Option<CompressOptions>,
46 #[cfg_attr(feature = "extra-serde", serde(default))]
47 pub mangle: Option<MangleOptions>,
48 #[cfg_attr(feature = "extra-serde", serde(default))]
49 pub wrap: bool,
50 #[cfg_attr(feature = "extra-serde", serde(default))]
51 pub enclose: bool,
52}
53
54#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56#[serde(deny_unknown_fields)]
57pub struct TopLevelOptions {
58 pub functions: bool,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(rename_all = "camelCase")]
63#[serde(deny_unknown_fields)]
64pub struct MangleOptions {
65 #[serde(default, alias = "properties")]
66 pub props: Option<ManglePropertiesOptions>,
67
68 #[serde(default, alias = "toplevel")]
69 pub top_level: Option<bool>,
70
71 #[serde(default, alias = "keep_classnames")]
72 pub keep_class_names: bool,
73
74 #[serde(default, alias = "keep_fnames")]
75 pub keep_fn_names: bool,
76
77 #[serde(default, alias = "keep_private_props")]
78 pub keep_private_props: bool,
79
80 #[serde(default, alias = "ie8")]
81 pub ie8: bool,
82
83 #[deprecated = "This field is no longer required to work around bugs in Safari 10."]
84 #[serde(default, alias = "safari10")]
85 pub safari10: bool,
86
87 #[serde(default, alias = "reserved")]
88 pub reserved: Vec<Atom>,
89
90 #[serde(default)]
92 pub eval: bool,
93}
94
95#[derive(Debug, Clone, Default, Serialize, Deserialize, Merge)]
96#[serde(rename_all = "camelCase")]
97pub struct ManglePropertiesOptions {
98 #[serde(default, alias = "reserved")]
99 pub reserved: Vec<Atom>,
100 #[serde(default, alias = "undeclared")]
101 pub undeclared: Option<bool>,
102 #[serde(default)]
103 pub regex: Option<CachedRegex>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[serde(deny_unknown_fields)]
108#[serde(untagged)]
109pub enum PureGetterOption {
110 Bool(bool),
111 #[serde(rename = "strict")]
112 Strict,
113 Str(Vec<Atom>),
114}
115
116impl Default for PureGetterOption {
117 fn default() -> Self {
118 Self::Strict
119 }
120}
121
122#[derive(Debug, Clone)]
124#[cfg_attr(feature = "extra-serde", derive(Serialize, Deserialize))]
125#[cfg_attr(feature = "extra-serde", serde(rename_all = "camelCase"))]
126#[cfg_attr(feature = "extra-serde", serde(deny_unknown_fields))]
127pub struct CompressOptions {
128 #[cfg_attr(feature = "extra-serde", serde(default))]
129 #[cfg_attr(feature = "extra-serde", serde(alias = "arguments"))]
130 pub arguments: bool,
131
132 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
133 pub arrows: bool,
134
135 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
136 #[cfg_attr(feature = "extra-serde", serde(alias = "booleans"))]
137 pub bools: bool,
138
139 #[cfg_attr(feature = "extra-serde", serde(default))]
140 #[cfg_attr(feature = "extra-serde", serde(alias = "booleans_as_integers"))]
141 pub bools_as_ints: bool,
142
143 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
144 #[cfg_attr(feature = "extra-serde", serde(alias = "collapse_vars"))]
145 pub collapse_vars: bool,
146
147 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
148 #[cfg_attr(feature = "extra-serde", serde(alias = "comparisons"))]
149 pub comparisons: bool,
150
151 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
152 #[cfg_attr(feature = "extra-serde", serde(alias = "computed_props"))]
153 pub computed_props: bool,
154
155 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
156 #[cfg_attr(feature = "extra-serde", serde(alias = "conditionals"))]
157 pub conditionals: bool,
158
159 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
160 #[cfg_attr(feature = "extra-serde", serde(alias = "dead_code"))]
161 pub dead_code: bool,
162
163 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
164 #[cfg_attr(feature = "extra-serde", serde(alias = "directives"))]
165 pub directives: bool,
166
167 #[cfg_attr(feature = "extra-serde", serde(default))]
168 #[cfg_attr(feature = "extra-serde", serde(alias = "drop_console"))]
169 pub drop_console: bool,
170
171 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
172 #[cfg_attr(feature = "extra-serde", serde(alias = "drop_debugger"))]
173 pub drop_debugger: bool,
174
175 #[cfg_attr(feature = "extra-serde", serde(default = "default_ecma"))]
176 pub ecma: EsVersion,
177
178 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
179 #[cfg_attr(feature = "extra-serde", serde(alias = "evaluate"))]
180 pub evaluate: bool,
181
182 #[cfg_attr(feature = "extra-serde", serde(default))]
184 #[cfg_attr(feature = "extra-serde", serde(alias = "expression"))]
185 pub expr: bool,
186
187 #[cfg_attr(feature = "extra-serde", serde(skip))]
190 #[cfg_attr(feature = "extra-serde", serde(alias = "global_defs"))]
191 pub global_defs: FxHashMap<Box<Expr>, Box<Expr>>,
192
193 #[cfg_attr(feature = "extra-serde", serde(default))]
194 #[cfg_attr(feature = "extra-serde", serde(alias = "hoist_funs"))]
195 pub hoist_fns: bool,
196
197 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
198 #[cfg_attr(feature = "extra-serde", serde(alias = "hoist_props"))]
199 pub hoist_props: bool,
200
201 #[cfg_attr(feature = "extra-serde", serde(default))]
202 #[cfg_attr(feature = "extra-serde", serde(alias = "hoist_vars"))]
203 pub hoist_vars: bool,
204
205 #[cfg_attr(feature = "extra-serde", serde(default))]
207 #[cfg_attr(feature = "extra-serde", serde(alias = "ie8"))]
208 pub ie8: bool,
209
210 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
211 #[cfg_attr(feature = "extra-serde", serde(alias = "if_return"))]
212 pub if_return: bool,
213
214 #[cfg_attr(feature = "extra-serde", serde(default = "three_by_default"))]
221 #[cfg_attr(feature = "extra-serde", serde(alias = "inline"))]
222 pub inline: u8,
223
224 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
225 #[cfg_attr(feature = "extra-serde", serde(alias = "join_vars"))]
226 pub join_vars: bool,
227
228 #[cfg_attr(feature = "extra-serde", serde(default))]
229 #[cfg_attr(feature = "extra-serde", serde(alias = "keep_classnames"))]
230 pub keep_classnames: bool,
231
232 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
233 #[cfg_attr(feature = "extra-serde", serde(alias = "keep_fargs"))]
234 pub keep_fargs: bool,
235
236 #[cfg_attr(feature = "extra-serde", serde(default))]
237 #[cfg_attr(feature = "extra-serde", serde(alias = "keep_fnames"))]
238 pub keep_fnames: bool,
239
240 #[cfg_attr(feature = "extra-serde", serde(default))]
241 #[cfg_attr(feature = "extra-serde", serde(alias = "keep_infinity"))]
242 pub keep_infinity: bool,
243
244 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
245 #[cfg_attr(feature = "extra-serde", serde(alias = "loops"))]
246 pub loops: bool,
247
248 #[cfg_attr(feature = "extra-serde", serde(default))]
249 pub module: bool,
250
251 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
252 #[cfg_attr(feature = "extra-serde", serde(alias = "negate_iife"))]
253 pub negate_iife: bool,
254
255 #[cfg_attr(feature = "extra-serde", serde(default = "default_passes"))]
258 #[cfg_attr(feature = "extra-serde", serde(alias = "passes"))]
259 pub passes: usize,
260
261 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
262 #[cfg_attr(feature = "extra-serde", serde(alias = "properties"))]
263 pub props: bool,
264
265 #[cfg_attr(feature = "extra-serde", serde(default))]
266 #[cfg_attr(feature = "extra-serde", serde(alias = "pure_getters"))]
267 pub pure_getters: PureGetterOption,
268
269 #[cfg_attr(feature = "extra-serde", serde(default))]
270 #[cfg_attr(feature = "extra-serde", serde(alias = "pure_funcs"))]
271 pub pure_funcs: Vec<Box<Expr>>,
272
273 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
274 #[cfg_attr(feature = "extra-serde", serde(alias = "reduce_funcs"))]
275 pub reduce_fns: bool,
276 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
277 #[cfg_attr(feature = "extra-serde", serde(alias = "reduce_vars"))]
278 pub reduce_vars: bool,
279
280 #[cfg_attr(feature = "extra-serde", serde(default = "three_by_default"))]
281 #[cfg_attr(feature = "extra-serde", serde(alias = "sequences"))]
282 pub sequences: u8,
283
284 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
285 #[cfg_attr(feature = "extra-serde", serde(alias = "side_effects"))]
286 pub side_effects: bool,
287
288 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
289 #[cfg_attr(feature = "extra-serde", serde(alias = "switches"))]
290 pub switches: bool,
291
292 #[cfg_attr(feature = "extra-serde", serde(default))]
294 #[cfg_attr(feature = "extra-serde", serde(alias = "top_retain"))]
295 pub top_retain: Vec<Atom>,
296
297 #[cfg_attr(feature = "extra-serde", serde(default))]
298 #[cfg_attr(feature = "extra-serde", serde(alias = "toplevel"))]
299 pub top_level: Option<TopLevelOptions>,
300
301 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
302 #[cfg_attr(feature = "extra-serde", serde(alias = "typeofs"))]
303 pub typeofs: bool,
304
305 #[cfg_attr(feature = "extra-serde", serde(default))]
306 #[cfg_attr(feature = "extra-serde", serde(rename = "unsafe"))]
307 pub unsafe_passes: bool,
308
309 #[cfg_attr(feature = "extra-serde", serde(default))]
310 pub unsafe_arrows: bool,
311
312 #[cfg_attr(feature = "extra-serde", serde(default))]
313 pub unsafe_comps: bool,
314
315 #[cfg_attr(feature = "extra-serde", serde(default))]
316 #[cfg_attr(feature = "extra-serde", serde(alias = "unsafe_Function"))]
317 pub unsafe_function: bool,
318
319 #[cfg_attr(feature = "extra-serde", serde(default))]
320 pub unsafe_math: bool,
321
322 #[cfg_attr(feature = "extra-serde", serde(default))]
323 pub unsafe_symbols: bool,
324
325 #[cfg_attr(feature = "extra-serde", serde(default))]
326 pub unsafe_methods: bool,
327
328 #[cfg_attr(feature = "extra-serde", serde(default))]
329 pub unsafe_proto: bool,
330
331 #[cfg_attr(feature = "extra-serde", serde(default))]
332 pub unsafe_regexp: bool,
333
334 #[cfg_attr(feature = "extra-serde", serde(default))]
335 pub unsafe_undefined: bool,
336
337 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
338 pub unused: bool,
339
340 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
341 pub const_to_let: bool,
342
343 #[cfg_attr(feature = "extra-serde", serde(default = "true_by_default"))]
347 pub pristine_globals: bool,
348}
349
350impl CompressOptions {
351 pub(crate) fn sequences(&self) -> bool {
352 self.sequences != 0
353 }
354
355 pub(crate) fn top_level(&self) -> bool {
357 if !self.top_retain.is_empty() {
358 return true;
359 }
360
361 self.top_level.map(|v| v.functions).unwrap_or(false) || self.module
362 }
363}
364
365const fn true_by_default() -> bool {
366 true
367}
368
369const fn default_passes() -> usize {
370 2
371}
372
373const fn three_by_default() -> u8 {
374 3
375}
376
377const fn default_ecma() -> EsVersion {
378 EsVersion::Es5
379}
380
381impl_default!(MangleOptions);
382
383impl Default for CompressOptions {
384 fn default() -> Self {
385 Self {
386 arguments: false,
387 arrows: true,
388 bools: true,
389 bools_as_ints: false,
390 collapse_vars: true,
391 comparisons: true,
392 computed_props: true,
393 conditionals: true,
394 dead_code: true,
395 directives: true,
396 drop_console: false,
397 drop_debugger: true,
398 ecma: default_ecma(),
399 evaluate: true,
400 expr: false,
401 global_defs: Default::default(),
402 hoist_fns: false,
403 hoist_props: true,
404 hoist_vars: false,
405 ie8: false,
406 if_return: true,
407 inline: 3,
408 join_vars: true,
409 keep_classnames: false,
410 keep_fargs: true,
411 keep_fnames: false,
412 keep_infinity: false,
413 loops: true,
414 module: false,
415 negate_iife: true,
416 passes: default_passes(),
417 props: true,
418 pure_getters: Default::default(),
419 pure_funcs: Default::default(),
420 reduce_fns: true,
421 reduce_vars: false,
422 sequences: 3,
423 side_effects: true,
424 switches: true,
425 top_retain: Default::default(),
426 top_level: Default::default(),
427 typeofs: true,
428 unsafe_passes: false,
429 unsafe_arrows: false,
430 unsafe_comps: false,
431 unsafe_function: false,
432 unsafe_math: false,
433 unsafe_methods: false,
434 unsafe_proto: false,
435 unsafe_regexp: false,
436 unsafe_symbols: false,
437 unsafe_undefined: false,
438 unused: true,
439 const_to_let: true,
440 pristine_globals: true,
441 }
442 }
443}
444
445pub trait MangleCache: Send + Sync {
446 fn vars_cache(&self, op: &mut dyn FnMut(&FxHashMap<Id, Atom>));
447
448 fn props_cache(&self, op: &mut dyn FnMut(&FxHashMap<Atom, Atom>));
449
450 fn update_vars_cache(&self, new_data: &FxHashMap<Id, Atom>);
451
452 fn update_props_cache(&self, new_data: &FxHashMap<Atom, Atom>);
453}
454
455#[derive(Debug, Default)]
456pub struct SimpleMangleCache {
457 pub vars: RwLock<FxHashMap<Id, Atom>>,
458 pub props: RwLock<FxHashMap<Atom, Atom>>,
459}
460
461impl MangleCache for SimpleMangleCache {
462 fn vars_cache(&self, op: &mut dyn FnMut(&FxHashMap<Id, Atom>)) {
463 let vars = self.vars.read();
464 op(&vars);
465 }
466
467 fn props_cache(&self, op: &mut dyn FnMut(&FxHashMap<Atom, Atom>)) {
468 let props = self.props.read();
469 op(&props);
470 }
471
472 fn update_vars_cache(&self, new_data: &FxHashMap<Id, Atom>) {
473 let mut vars = self.vars.write();
474 vars.extend(new_data.iter().map(|(k, v)| (k.clone(), v.clone())));
475 }
476
477 fn update_props_cache(&self, new_data: &FxHashMap<Atom, Atom>) {
478 let mut props = self.props.write();
479 props.extend(new_data.iter().map(|(k, v)| (k.clone(), v.clone())));
480 }
481}