mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(mangler,codegen): do not mangle top level symbols (#5965)
This commit is contained in:
parent
fd1c46ca9e
commit
362c427b94
4 changed files with 64 additions and 37 deletions
|
|
@ -762,24 +762,10 @@ impl<'a> Gen for ImportDeclaration<'a> {
|
||||||
p.print_str("type ");
|
p.print_str("type ");
|
||||||
}
|
}
|
||||||
|
|
||||||
let imported_name = match &spec.imported {
|
spec.imported.print(p, ctx);
|
||||||
ModuleExportName::IdentifierName(identifier) => {
|
let local_name = p.get_binding_identifier_name(&spec.local);
|
||||||
identifier.print(p, ctx);
|
let imported_name = get_module_export_name(&spec.imported, p);
|
||||||
identifier.name.as_str()
|
if imported_name.is_none() || imported_name != Some(local_name) {
|
||||||
}
|
|
||||||
ModuleExportName::IdentifierReference(identifier) => {
|
|
||||||
identifier.print(p, ctx);
|
|
||||||
identifier.name.as_str()
|
|
||||||
}
|
|
||||||
ModuleExportName::StringLiteral(literal) => {
|
|
||||||
literal.print(p, ctx);
|
|
||||||
literal.value.as_str()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let local_name = spec.local.name.as_str();
|
|
||||||
|
|
||||||
if imported_name != local_name {
|
|
||||||
p.print_str(" as ");
|
p.print_str(" as ");
|
||||||
spec.local.print(p, ctx);
|
spec.local.print(p, ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -919,13 +905,28 @@ impl<'a> Gen for TSNamespaceExportDeclaration<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_module_export_name<'a>(
|
||||||
|
module_export_name: &ModuleExportName<'a>,
|
||||||
|
p: &Codegen<'a>,
|
||||||
|
) -> Option<&'a str> {
|
||||||
|
match module_export_name {
|
||||||
|
ModuleExportName::IdentifierName(ident) => Some(ident.name.as_str()),
|
||||||
|
ModuleExportName::IdentifierReference(ident) => {
|
||||||
|
Some(p.get_identifier_reference_name(ident))
|
||||||
|
}
|
||||||
|
ModuleExportName::StringLiteral(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Gen for ExportSpecifier<'a> {
|
impl<'a> Gen for ExportSpecifier<'a> {
|
||||||
fn gen(&self, p: &mut Codegen, ctx: Context) {
|
fn gen(&self, p: &mut Codegen, ctx: Context) {
|
||||||
if self.export_kind.is_type() {
|
if self.export_kind.is_type() {
|
||||||
p.print_str("type ");
|
p.print_str("type ");
|
||||||
}
|
}
|
||||||
self.local.print(p, ctx);
|
self.local.print(p, ctx);
|
||||||
if self.local.name() != self.exported.name() {
|
let local_name = get_module_export_name(&self.local, p);
|
||||||
|
let exported_name = get_module_export_name(&self.exported, p);
|
||||||
|
if exported_name.is_none() || local_name != exported_name {
|
||||||
p.print_str(" as ");
|
p.print_str(" as ");
|
||||||
self.exported.print(p, ctx);
|
self.exported.print(p, ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -935,8 +936,8 @@ impl<'a> Gen for ExportSpecifier<'a> {
|
||||||
impl<'a> Gen for ModuleExportName<'a> {
|
impl<'a> Gen for ModuleExportName<'a> {
|
||||||
fn gen(&self, p: &mut Codegen, ctx: Context) {
|
fn gen(&self, p: &mut Codegen, ctx: Context) {
|
||||||
match self {
|
match self {
|
||||||
Self::IdentifierName(identifier) => p.print_str(identifier.name.as_str()),
|
Self::IdentifierName(ident) => ident.print(p, ctx),
|
||||||
Self::IdentifierReference(identifier) => identifier.print(p, ctx),
|
Self::IdentifierReference(ident) => ident.print(p, ctx),
|
||||||
Self::StringLiteral(literal) => literal.print(p, ctx),
|
Self::StringLiteral(literal) => literal.print(p, ctx),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use oxc_ast::ast::Program;
|
use oxc_ast::ast::Program;
|
||||||
use oxc_index::{index_vec, Idx, IndexVec};
|
use oxc_index::{index_vec, Idx, IndexVec};
|
||||||
use oxc_semantic::{ReferenceId, SemanticBuilder, SymbolId, SymbolTable};
|
use oxc_semantic::{ReferenceId, ScopeTree, SemanticBuilder, SymbolId, SymbolTable};
|
||||||
use oxc_span::CompactStr;
|
use oxc_span::CompactStr;
|
||||||
|
|
||||||
type Slot = usize;
|
type Slot = usize;
|
||||||
|
|
@ -124,9 +124,12 @@ impl Mangler {
|
||||||
}
|
}
|
||||||
|
|
||||||
let frequencies =
|
let frequencies =
|
||||||
Self::tally_slot_frequencies(&symbol_table, total_number_of_slots, &slots);
|
Self::tally_slot_frequencies(&symbol_table, &scope_tree, total_number_of_slots, &slots);
|
||||||
|
|
||||||
let mut names = Vec::with_capacity(total_number_of_slots);
|
let root_unresolved_references = scope_tree.root_unresolved_references();
|
||||||
|
let root_bindings = scope_tree.get_bindings(scope_tree.root_scope_id());
|
||||||
|
|
||||||
|
let mut reserved_names = Vec::with_capacity(total_number_of_slots);
|
||||||
|
|
||||||
let generate_name = if self.options.debug { debug_name } else { base54 };
|
let generate_name = if self.options.debug { debug_name } else { base54 };
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
@ -135,13 +138,16 @@ impl Mangler {
|
||||||
let name = generate_name(count);
|
let name = generate_name(count);
|
||||||
count += 1;
|
count += 1;
|
||||||
// Do not mangle keywords and unresolved references
|
// Do not mangle keywords and unresolved references
|
||||||
if !is_keyword(&name)
|
let n = name.as_str();
|
||||||
&& !scope_tree.root_unresolved_references().contains_key(name.as_str())
|
if !is_keyword(n)
|
||||||
|
&& !is_special_name(n)
|
||||||
|
&& !root_unresolved_references.contains_key(n)
|
||||||
|
&& !root_bindings.contains_key(n)
|
||||||
{
|
{
|
||||||
break name;
|
break name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
names.push(name);
|
reserved_names.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group similar symbols for smaller gzipped file
|
// Group similar symbols for smaller gzipped file
|
||||||
|
|
@ -160,7 +166,9 @@ impl Mangler {
|
||||||
|
|
||||||
let mut freq_iter = frequencies.iter();
|
let mut freq_iter = frequencies.iter();
|
||||||
// 2. "N number of vars are going to be assigned names of the same length"
|
// 2. "N number of vars are going to be assigned names of the same length"
|
||||||
for (_, slice_of_same_len_strings_group) in &names.into_iter().chunk_by(CompactStr::len) {
|
for (_, slice_of_same_len_strings_group) in
|
||||||
|
&reserved_names.into_iter().chunk_by(CompactStr::len)
|
||||||
|
{
|
||||||
// 1. "The most frequent vars get the shorter names"
|
// 1. "The most frequent vars get the shorter names"
|
||||||
// (freq_iter is sorted by frequency from highest to lowest,
|
// (freq_iter is sorted by frequency from highest to lowest,
|
||||||
// so taking means take the N most frequent symbols remaining)
|
// so taking means take the N most frequent symbols remaining)
|
||||||
|
|
@ -194,14 +202,17 @@ impl Mangler {
|
||||||
|
|
||||||
fn tally_slot_frequencies(
|
fn tally_slot_frequencies(
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
scope_tree: &ScopeTree,
|
||||||
total_number_of_slots: usize,
|
total_number_of_slots: usize,
|
||||||
slots: &IndexVec<SymbolId, Slot>,
|
slots: &IndexVec<SymbolId, Slot>,
|
||||||
) -> Vec<SlotFrequency> {
|
) -> Vec<SlotFrequency> {
|
||||||
|
let root_scope_id = scope_tree.root_scope_id();
|
||||||
let mut frequencies = vec![SlotFrequency::default(); total_number_of_slots];
|
let mut frequencies = vec![SlotFrequency::default(); total_number_of_slots];
|
||||||
for (symbol_id, slot) in slots.iter_enumerated() {
|
for (symbol_id, slot) in slots.iter_enumerated() {
|
||||||
let symbol_flags = symbol_table.get_flags(symbol_id);
|
if symbol_table.get_scope_id(symbol_id) == root_scope_id {
|
||||||
// omit renaming `export { x }`
|
continue;
|
||||||
if !symbol_flags.is_variable() || symbol_flags.is_export() {
|
}
|
||||||
|
if is_special_name(symbol_table.get_name(symbol_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let index = *slot;
|
let index = *slot;
|
||||||
|
|
@ -215,6 +226,10 @@ impl Mangler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_special_name(name: &str) -> bool {
|
||||||
|
matches!(name, "exports" | "arguments")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
struct SlotFrequency {
|
struct SlotFrequency {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ fn mangler() {
|
||||||
"function foo(a) { let _ = { x } }",
|
"function foo(a) { let _ = { x } }",
|
||||||
"function foo(a) { let { x } = y }",
|
"function foo(a) { let { x } = y }",
|
||||||
"var x; function foo(a) { ({ x } = y) }",
|
"var x; function foo(a) { ({ x } = y) }",
|
||||||
|
"import { x } from 's'; export { x }",
|
||||||
|
"function _ (exports) { Object.defineProperty(exports, '__esModule', { value: true }) }",
|
||||||
];
|
];
|
||||||
|
|
||||||
let snapshot = cases.into_iter().fold(String::new(), |mut w, case| {
|
let snapshot = cases.into_iter().fold(String::new(), |mut w, case| {
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,31 @@
|
||||||
source: crates/oxc_minifier/tests/mangler/mod.rs
|
source: crates/oxc_minifier/tests/mangler/mod.rs
|
||||||
---
|
---
|
||||||
function foo(a) {a}
|
function foo(a) {a}
|
||||||
function a(b) {
|
function foo(b) {
|
||||||
b;
|
b;
|
||||||
}
|
}
|
||||||
|
|
||||||
function foo(a) { let _ = { x } }
|
function foo(a) { let _ = { x } }
|
||||||
function a(b) {
|
function foo(b) {
|
||||||
let c = { x };
|
let c = { x };
|
||||||
}
|
}
|
||||||
|
|
||||||
function foo(a) { let { x } = y }
|
function foo(a) { let { x } = y }
|
||||||
function a(b) {
|
function foo(b) {
|
||||||
let { x: c } = y;
|
let { x: c } = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
var x; function foo(a) { ({ x } = y) }
|
var x; function foo(a) { ({ x } = y) }
|
||||||
var a;
|
var x;
|
||||||
function b(c) {
|
function foo(c) {
|
||||||
({x: a} = y);
|
({x} = y);
|
||||||
|
}
|
||||||
|
|
||||||
|
import { x } from 's'; export { x }
|
||||||
|
import { x } from "s";
|
||||||
|
export { x };
|
||||||
|
|
||||||
|
function _ (exports) { Object.defineProperty(exports, '__esModule', { value: true }) }
|
||||||
|
function _(exports) {
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue