@@ -2,15 +2,15 @@ use std::iter::{self, repeat_with};
22
33use itertools:: Itertools ;
44use keep_names:: collect_name_symbols;
5- use rustc_hash:: FxHashSet ;
5+ use rustc_hash:: { FxHashMap , FxHashSet } ;
66
77use base54:: base54;
88use oxc_allocator:: { Allocator , BitSet , Vec } ;
99use oxc_ast:: ast:: { Declaration , Program , Statement } ;
1010use oxc_data_structures:: inline_string:: InlineString ;
1111use oxc_index:: Idx ;
1212use oxc_semantic:: { AstNodes , Scoping , Semantic , SemanticBuilder , SymbolId } ;
13- use oxc_span:: Atom ;
13+ use oxc_span:: { Atom , CompactStr } ;
1414
1515pub ( crate ) mod base54;
1616mod keep_names;
@@ -56,6 +56,13 @@ impl TempAllocator<'_> {
5656 }
5757}
5858
59+ pub struct ManglerReturn {
60+ pub scoping : Scoping ,
61+ /// A vector where each element corresponds to a class in declaration order.
62+ /// Each element is a mapping from original private member names to their mangled names.
63+ pub class_private_mappings : std:: vec:: Vec < FxHashMap < String , CompactStr > > ,
64+ }
65+
5966/// # Name Mangler / Symbol Minification
6067///
6168/// ## Example
@@ -257,11 +264,12 @@ impl<'t> Mangler<'t> {
257264 /// Mangles the program. The resulting SymbolTable contains the mangled symbols - `program` is not modified.
258265 /// Pass the symbol table to oxc_codegen to generate the mangled code.
259266 #[ must_use]
260- pub fn build ( self , program : & Program < ' _ > ) -> Scoping {
267+ pub fn build ( self , program : & Program < ' _ > ) -> ManglerReturn {
261268 let mut semantic =
262269 SemanticBuilder :: new ( ) . with_scope_tree_child_ids ( true ) . build ( program) . semantic ;
270+ let class_private_mappings = Self :: collect_private_members_from_semantic ( & semantic) ;
263271 self . build_with_semantic ( & mut semantic, program) ;
264- semantic. into_scoping ( )
272+ ManglerReturn { scoping : semantic. into_scoping ( ) , class_private_mappings }
265273 }
266274
267275 /// # Panics
@@ -548,6 +556,50 @@ impl<'t> Mangler<'t> {
548556 let ids = collect_name_symbols ( keep_names, scoping, nodes) ;
549557 ( ids. iter ( ) . map ( |id| scoping. symbol_name ( * id) ) . collect ( ) , ids)
550558 }
559+
560+ /// Collects and generates mangled names for private members using semantic information
561+ /// Returns a Vec where each element corresponds to a class in declaration order
562+ fn collect_private_members_from_semantic (
563+ semantic : & Semantic < ' _ > ,
564+ ) -> std:: vec:: Vec < FxHashMap < String , CompactStr > > {
565+ let classes = semantic. classes ( ) ;
566+ let mut result = std:: vec:: Vec :: new ( ) ;
567+
568+ // Process each class in declaration order
569+ for class_elements in & classes. elements {
570+ let mut private_members = FxHashSet :: default ( ) ;
571+
572+ // Collect private member names for this class
573+ for element in class_elements {
574+ if element. is_private {
575+ private_members. insert ( element. name . as_ref ( ) . to_string ( ) ) ;
576+ }
577+ }
578+
579+ // Generate mapping for this class (reusing names across classes)
580+ let mut mapping = FxHashMap :: default ( ) ;
581+ let mut count = 0 ;
582+
583+ for name in & private_members {
584+ let mangled = loop {
585+ let candidate = base54 ( count) ;
586+ count += 1 ;
587+
588+ // Ensure the mangled name doesn't conflict with JavaScript keywords
589+ let candidate_str = candidate. as_str ( ) ;
590+ if !is_keyword ( candidate_str) && !is_special_name ( candidate_str) {
591+ break CompactStr :: new ( candidate_str) ;
592+ }
593+ } ;
594+
595+ mapping. insert ( name. clone ( ) , mangled) ;
596+ }
597+
598+ result. push ( mapping) ;
599+ }
600+
601+ result
602+ }
551603}
552604
553605fn is_special_name ( name : & str ) -> bool {
0 commit comments