@@ -21,13 +21,45 @@ pub struct MangleOptions {
2121 /// Default: `false`
2222 pub top_level : bool ,
2323
24+ /// Keep function / class names
25+ pub keep_names : MangleOptionsKeepNames ,
26+
2427 /// Use more readable mangled names
2528 /// (e.g. `slot_0`, `slot_1`, `slot_2`, ...) for debugging.
2629 ///
2730 /// Uses base54 if false.
2831 pub debug : bool ,
2932}
3033
34+ #[ derive( Debug , Clone , Copy , Default ) ]
35+ pub struct MangleOptionsKeepNames {
36+ /// Keep function names so that `Function.prototype.name` is preserved.
37+ ///
38+ /// Default `false`
39+ pub function : bool ,
40+
41+ /// Keep class names so that `Class.prototype.name` is preserved.
42+ ///
43+ /// Default `false`
44+ pub class : bool ,
45+ }
46+
47+ impl MangleOptionsKeepNames {
48+ pub fn all_false ( ) -> Self {
49+ Self { function : false , class : false }
50+ }
51+
52+ pub fn all_true ( ) -> Self {
53+ Self { function : true , class : true }
54+ }
55+ }
56+
57+ impl From < bool > for MangleOptionsKeepNames {
58+ fn from ( keep_names : bool ) -> Self {
59+ if keep_names { Self :: all_true ( ) } else { Self :: all_false ( ) }
60+ }
61+ }
62+
3163type Slot = usize ;
3264
3365/// # Name Mangler / Symbol Minification
@@ -206,6 +238,8 @@ impl Mangler {
206238 } else {
207239 Default :: default ( )
208240 } ;
241+ let ( keep_name_names, keep_name_symbols) =
242+ Mangler :: collect_keep_name_symbols ( self . options . keep_names , & scoping) ;
209243
210244 let allocator = Allocator :: default ( ) ;
211245
@@ -225,6 +259,16 @@ impl Mangler {
225259 continue ;
226260 }
227261
262+ // Sort `bindings` in declaration order.
263+ tmp_bindings. clear ( ) ;
264+ tmp_bindings. extend (
265+ bindings. values ( ) . copied ( ) . filter ( |binding| !keep_name_symbols. contains ( binding) ) ,
266+ ) ;
267+ tmp_bindings. sort_unstable ( ) ;
268+ if tmp_bindings. is_empty ( ) {
269+ continue ;
270+ }
271+
228272 let mut slot = slot_liveness. len ( ) ;
229273
230274 reusable_slots. clear ( ) ;
@@ -235,11 +279,11 @@ impl Mangler {
235279 . enumerate ( )
236280 . filter ( |( _, slot_liveness) | !slot_liveness. contains ( scope_id. index ( ) ) )
237281 . map ( |( slot, _) | slot)
238- . take ( bindings . len ( ) ) ,
282+ . take ( tmp_bindings . len ( ) ) ,
239283 ) ;
240284
241285 // The number of new slots that needs to be allocated.
242- let remaining_count = bindings . len ( ) - reusable_slots. len ( ) ;
286+ let remaining_count = tmp_bindings . len ( ) - reusable_slots. len ( ) ;
243287 reusable_slots. extend ( slot..slot + remaining_count) ;
244288
245289 slot += remaining_count;
@@ -248,10 +292,6 @@ impl Mangler {
248292 . resize_with ( slot, || FixedBitSet :: with_capacity ( scoping. scopes_len ( ) ) ) ;
249293 }
250294
251- // Sort `bindings` in declaration order.
252- tmp_bindings. clear ( ) ;
253- tmp_bindings. extend ( bindings. values ( ) . copied ( ) ) ;
254- tmp_bindings. sort_unstable ( ) ;
255295 for ( & symbol_id, assigned_slot) in
256296 tmp_bindings. iter ( ) . zip ( reusable_slots. iter ( ) . copied ( ) )
257297 {
@@ -282,6 +322,7 @@ impl Mangler {
282322 let frequencies = self . tally_slot_frequencies (
283323 & scoping,
284324 & exported_symbols,
325+ & keep_name_symbols,
285326 total_number_of_slots,
286327 & slots,
287328 & allocator,
@@ -304,6 +345,8 @@ impl Mangler {
304345 && !root_unresolved_references. contains_key ( n)
305346 && !( root_bindings. contains_key ( n)
306347 && ( !self . options . top_level || exported_names. contains ( n) ) )
348+ // TODO: only skip the names that are kept in the current scope
349+ && !keep_name_names. contains ( n)
307350 {
308351 break name;
309352 }
@@ -368,6 +411,7 @@ impl Mangler {
368411 & ' a self ,
369412 scoping : & Scoping ,
370413 exported_symbols : & FxHashSet < SymbolId > ,
414+ keep_name_symbols : & FxHashSet < SymbolId > ,
371415 total_number_of_slots : usize ,
372416 slots : & [ Slot ] ,
373417 allocator : & ' a Allocator ,
@@ -388,6 +432,9 @@ impl Mangler {
388432 if is_special_name ( scoping. symbol_name ( symbol_id) ) {
389433 continue ;
390434 }
435+ if keep_name_symbols. contains ( & symbol_id) {
436+ continue ;
437+ }
391438 let index = slot;
392439 frequencies[ index] . slot = slot;
393440 frequencies[ index] . frequency += scoping. get_resolved_reference_ids ( symbol_id) . len ( ) ;
@@ -421,6 +468,21 @@ impl Mangler {
421468 . map ( |id| ( id. name , id. symbol_id ( ) ) )
422469 . collect ( )
423470 }
471+
472+ fn collect_keep_name_symbols (
473+ keep_names : MangleOptionsKeepNames ,
474+ scoping : & Scoping ,
475+ ) -> ( FxHashSet < & str > , FxHashSet < SymbolId > ) {
476+ let ids: FxHashSet < SymbolId > = keep_names
477+ . function
478+ . then ( || scoping. function_name_symbols ( ) )
479+ . into_iter ( )
480+ . flatten ( )
481+ . chain ( keep_names. class . then ( || scoping. class_name_symbols ( ) ) . into_iter ( ) . flatten ( ) )
482+ . copied ( )
483+ . collect ( ) ;
484+ ( ids. iter ( ) . map ( |id| scoping. symbol_name ( * id) ) . collect ( ) , ids)
485+ }
424486}
425487
426488fn is_special_name ( name : & str ) -> bool {
0 commit comments