oxc_minifier/
compressor.rs1use oxc_allocator::Allocator;
2use oxc_ast::ast::*;
3use oxc_semantic::{Scoping, SemanticBuilder};
4use oxc_traverse::ReusableTraverseCtx;
5
6use crate::{
7 CompressOptions,
8 peephole::{Normalize, NormalizeOptions, PeepholeOptimizations},
9 state::MinifierState,
10};
11
12pub struct Compressor<'a> {
13 allocator: &'a Allocator,
14}
15
16impl<'a> Compressor<'a> {
17 pub fn new(allocator: &'a Allocator) -> Self {
18 Self { allocator }
19 }
20
21 pub fn build(self, program: &mut Program<'a>, options: CompressOptions) {
22 let scoping = SemanticBuilder::new().build(program).semantic.into_scoping();
23 self.build_with_scoping(program, scoping, options);
24 }
25
26 pub fn build_with_scoping(
28 self,
29 program: &mut Program<'a>,
30 scoping: Scoping,
31 options: CompressOptions,
32 ) -> u8 {
33 let max_iterations = options.max_iterations;
34 let state = MinifierState::new(program.source_type, options, false);
35 let mut ctx = ReusableTraverseCtx::new(state, scoping, self.allocator);
36 let normalize_options = NormalizeOptions {
37 convert_while_to_fors: true,
38 convert_const_to_let: true,
39 remove_unnecessary_use_strict: true,
40 };
41 Normalize::new(normalize_options).build(program, &mut ctx);
42 Self::run_in_loop(max_iterations, program, &mut ctx)
43 }
44
45 pub fn dead_code_elimination(self, program: &mut Program<'a>, options: CompressOptions) -> u8 {
46 let scoping = SemanticBuilder::new().build(program).semantic.into_scoping();
47 self.dead_code_elimination_with_scoping(program, scoping, options)
48 }
49
50 pub fn dead_code_elimination_with_scoping(
52 self,
53 program: &mut Program<'a>,
54 scoping: Scoping,
55 options: CompressOptions,
56 ) -> u8 {
57 let max_iterations = options.max_iterations;
58 let state = MinifierState::new(program.source_type, options, true);
59 let mut ctx = ReusableTraverseCtx::new(state, scoping, self.allocator);
60 let normalize_options = NormalizeOptions {
61 convert_while_to_fors: false,
62 convert_const_to_let: false,
63 remove_unnecessary_use_strict: false,
64 };
65 Normalize::new(normalize_options).build(program, &mut ctx);
66 Self::run_in_loop(max_iterations, program, &mut ctx)
67 }
68
69 fn run_in_loop(
71 max_iterations: Option<u8>,
72 program: &mut Program<'a>,
73 ctx: &mut ReusableTraverseCtx<'a, MinifierState<'a>>,
74 ) -> u8 {
75 let mut iteration = 0u8;
76 loop {
77 PeepholeOptimizations.run_once(program, ctx);
78 if !ctx.state().changed {
79 break;
80 }
81 if let Some(max) = max_iterations {
82 if iteration >= max {
83 break;
84 }
85 } else if iteration > 10 {
86 debug_assert!(false, "Ran loop more than 10 times.");
87 break;
88 }
89 iteration += 1;
90 }
91 iteration
92 }
93}