Skip to content

Commit c2a99eb

Browse files
committed
fix(mangler): keep exported symbols
1 parent 8afd356 commit c2a99eb

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/oxc_mangler/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ oxc_ast = { workspace = true }
2626
oxc_index = { workspace = true }
2727
oxc_semantic = { workspace = true }
2828
oxc_span = { workspace = true }
29+
rustc-hash = { workspace = true }

crates/oxc_mangler/src/lib.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use itertools::Itertools;
2-
use oxc_ast::ast::Program;
2+
use oxc_ast::ast::{Declaration, Program, Statement};
33
use oxc_index::{index_vec, Idx, IndexVec};
44
use oxc_semantic::{ReferenceId, ScopeTree, SemanticBuilder, SymbolId, SymbolTable};
55
use oxc_span::CompactStr;
6+
use rustc_hash::FxHashSet;
67

78
type Slot = usize;
89

@@ -85,6 +86,28 @@ impl Mangler {
8586
pub fn build<'a>(mut self, program: &'a Program<'a>) -> Mangler {
8687
let semantic = SemanticBuilder::new().build(program).semantic;
8788

89+
let (exported_names, exported_symbols): (FxHashSet<CompactStr>, FxHashSet<SymbolId>) =
90+
program
91+
.body
92+
.iter()
93+
.filter_map(|statement| {
94+
let Statement::ExportNamedDeclaration(v) = statement else { return None };
95+
v.declaration.as_ref()
96+
})
97+
.flat_map(|decl| {
98+
if let Declaration::VariableDeclaration(decl) = decl {
99+
itertools::Either::Left(
100+
decl.declarations
101+
.iter()
102+
.filter_map(|decl| decl.id.get_binding_identifier()),
103+
)
104+
} else {
105+
itertools::Either::Right(decl.id().into_iter())
106+
}
107+
})
108+
.map(|id| (id.name.to_compact_str(), id.symbol_id()))
109+
.collect();
110+
88111
// Mangle the symbol table by computing slots from the scope tree.
89112
// A slot is the occurrence index of a binding identifier inside a scope.
90113
let (mut symbol_table, scope_tree) = semantic.into_symbol_table_and_scope_tree();
@@ -126,8 +149,13 @@ impl Mangler {
126149
}
127150
}
128151

129-
let frequencies =
130-
self.tally_slot_frequencies(&symbol_table, &scope_tree, total_number_of_slots, &slots);
152+
let frequencies = self.tally_slot_frequencies(
153+
&symbol_table,
154+
&exported_symbols,
155+
&scope_tree,
156+
total_number_of_slots,
157+
&slots,
158+
);
131159

132160
let root_unresolved_references = scope_tree.root_unresolved_references();
133161
let root_bindings = scope_tree.get_bindings(scope_tree.root_scope_id());
@@ -145,7 +173,8 @@ impl Mangler {
145173
if !is_keyword(n)
146174
&& !is_special_name(n)
147175
&& !root_unresolved_references.contains_key(n)
148-
&& (self.options.top_level || !root_bindings.contains_key(n))
176+
&& !(root_bindings.contains_key(n)
177+
&& (!self.options.top_level || exported_names.contains(n)))
149178
{
150179
break name;
151180
}
@@ -206,14 +235,17 @@ impl Mangler {
206235
fn tally_slot_frequencies(
207236
&self,
208237
symbol_table: &SymbolTable,
238+
exported_symbols: &FxHashSet<SymbolId>,
209239
scope_tree: &ScopeTree,
210240
total_number_of_slots: usize,
211241
slots: &IndexVec<SymbolId, Slot>,
212242
) -> Vec<SlotFrequency> {
213243
let root_scope_id = scope_tree.root_scope_id();
214244
let mut frequencies = vec![SlotFrequency::default(); total_number_of_slots];
215245
for (symbol_id, slot) in slots.iter_enumerated() {
216-
if !self.options.top_level && symbol_table.get_scope_id(symbol_id) == root_scope_id {
246+
if symbol_table.get_scope_id(symbol_id) == root_scope_id
247+
&& (!self.options.top_level || exported_symbols.contains(&symbol_id))
248+
{
217249
continue;
218250
}
219251
if is_special_name(symbol_table.get_name(symbol_id)) {

crates/oxc_minifier/tests/mangler/snapshots/mangler.snap

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,18 @@ function a(b) {
3737
}
3838

3939
export function foo() {}; foo()
40-
function a() {}
40+
export function foo() {}
4141
;
42-
a();
43-
export { a as foo };
42+
foo();
4443

4544
export default function foo() {}; foo()
4645
export default function a() {}
4746
;
4847
a();
4948

5049
export const foo = 1; foo
51-
export const a = 1;
52-
a;
53-
export { a as foo };
50+
export const foo = 1;
51+
foo;
5452

5553
const foo = 1; foo; export { foo }
5654
const a = 1;

0 commit comments

Comments
 (0)