use oxc_ecmascript::constant_evaluation::ConstantValue;
use rustc_hash::{FxHashMap, FxHashSet};
use oxc_allocator::{Allocator, BitSet};
use oxc_data_structures::stack::NonEmptyStack;
use oxc_semantic::Scoping;
use oxc_span::SourceType;
use oxc_str::Str;
use oxc_syntax::{scope::ScopeId, symbol::SymbolId};
use crate::{CompressOptions, symbol_value::SymbolValues};
pub struct PassDirty<'a> {
pub(crate) dead_refs: BitSet<'a>,
pub(crate) eval_dropped: bool,
}
impl<'a> PassDirty<'a> {
pub fn new(references_len: usize, allocator: &'a Allocator) -> Self {
Self { dead_refs: BitSet::new_in(references_len, allocator), eval_dropped: false }
}
}
pub struct MinifierState<'a> {
pub source_type: SourceType,
pub options: CompressOptions,
pub dce: bool,
pub pure_functions: FxHashMap<SymbolId, Option<ConstantValue<'a>>>,
pub symbol_values: SymbolValues<'a>,
pub class_symbols_stack: ClassSymbolsStack<'a>,
pub proto_write_symbols: FxHashSet<SymbolId>,
pub body_unsafe_stack: NonEmptyStack<(ScopeId, bool)>,
mutated: bool,
pub(crate) dirty: PassDirty<'a>,
pub concat_scratch: String,
}
impl<'a> MinifierState<'a> {
pub fn new(
source_type: SourceType,
options: CompressOptions,
dce: bool,
scoping: &Scoping,
allocator: &'a Allocator,
) -> Self {
Self {
source_type,
options,
dce,
pure_functions: FxHashMap::default(),
symbol_values: SymbolValues::new(scoping.symbols_len()),
class_symbols_stack: ClassSymbolsStack::new(),
proto_write_symbols: FxHashSet::default(),
body_unsafe_stack: NonEmptyStack::new((scoping.root_scope_id(), false)),
mutated: false,
dirty: PassDirty::new(scoping.references_len(), allocator),
concat_scratch: String::new(),
}
}
pub(crate) fn take_mutated(&mut self) -> bool {
std::mem::take(&mut self.mutated)
}
pub(crate) fn record_mutation(&mut self) {
self.mutated = true;
}
}
pub struct ClassSymbolsStack<'a> {
stack: NonEmptyStack<FxHashSet<Str<'a>>>,
}
impl<'a> ClassSymbolsStack<'a> {
pub fn new() -> Self {
Self { stack: NonEmptyStack::new(FxHashSet::default()) }
}
pub fn is_exhausted(&self) -> bool {
self.stack.is_exhausted()
}
pub fn push_class_scope(&mut self) {
self.stack.push(FxHashSet::default());
}
pub fn pop_class_scope(&mut self, declared_private_symbols: impl Iterator<Item = Str<'a>>) {
let mut used_private_symbols = self.stack.pop();
declared_private_symbols.for_each(|name| {
used_private_symbols.remove(&name);
});
self.stack.last_mut().extend(used_private_symbols);
}
pub fn push_private_member_to_current_class(&mut self, name: Str<'a>) {
self.stack.last_mut().insert(name);
}
pub fn is_private_member_used_in_current_class(&self, name: &Str<'a>) -> bool {
self.stack.last().contains(name)
}
}