mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(minifier): add constant folding to remove dead code (#4058)
This commit is contained in:
parent
edb557c02b
commit
0da9dfbf09
7 changed files with 38 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1551,6 +1551,7 @@ dependencies = [
|
||||||
name = "oxc_minifier"
|
name = "oxc_minifier"
|
||||||
version = "0.16.3"
|
version = "0.16.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"insta",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
|
@ -1564,6 +1565,7 @@ dependencies = [
|
||||||
"oxc_span",
|
"oxc_span",
|
||||||
"oxc_syntax",
|
"oxc_syntax",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,6 @@ num-traits = { workspace = true }
|
||||||
oxc_parser = { workspace = true }
|
oxc_parser = { workspace = true }
|
||||||
oxc_codegen = { workspace = true }
|
oxc_codegen = { workspace = true }
|
||||||
|
|
||||||
# insta = { workspace = true }
|
insta = { workspace = true }
|
||||||
# walkdir = { workspace = true }
|
walkdir = { workspace = true }
|
||||||
pico-args = { workspace = true }
|
pico-args = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,34 @@ use oxc_allocator::Allocator;
|
||||||
use oxc_ast::{ast::*, visit::walk_mut, AstBuilder, VisitMut};
|
use oxc_ast::{ast::*, visit::walk_mut, AstBuilder, VisitMut};
|
||||||
use oxc_span::SPAN;
|
use oxc_span::SPAN;
|
||||||
|
|
||||||
|
use crate::{compressor::ast_util::get_boolean_value, folder::Folder};
|
||||||
|
|
||||||
/// Remove Dead Code from the AST.
|
/// Remove Dead Code from the AST.
|
||||||
///
|
///
|
||||||
/// Terser option: `dead_code: true`.
|
/// Terser option: `dead_code: true`.
|
||||||
pub struct RemoveDeadCode<'a> {
|
pub struct RemoveDeadCode<'a> {
|
||||||
ast: AstBuilder<'a>,
|
ast: AstBuilder<'a>,
|
||||||
|
folder: Folder<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RemoveDeadCode<'a> {
|
impl<'a> RemoveDeadCode<'a> {
|
||||||
pub fn new(allocator: &'a Allocator) -> Self {
|
pub fn new(allocator: &'a Allocator) -> Self {
|
||||||
Self { ast: AstBuilder::new(allocator) }
|
let ast = AstBuilder::new(allocator);
|
||||||
|
Self { ast, folder: Folder::new(ast) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(&mut self, program: &mut Program<'a>) {
|
pub fn build(&mut self, program: &mut Program<'a>) {
|
||||||
self.visit_program(program);
|
self.visit_program(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_expression(&mut self, expr: &mut Expression<'a>) -> Option<bool> {
|
||||||
|
self.folder.fold_expression(expr);
|
||||||
|
get_boolean_value(expr)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_if(&mut self, stmt: &mut Statement<'a>) {
|
pub fn remove_if(&mut self, stmt: &mut Statement<'a>) {
|
||||||
let Statement::IfStatement(if_stmt) = stmt else { return };
|
let Statement::IfStatement(if_stmt) = stmt else { return };
|
||||||
match if_stmt.test.get_boolean_value() {
|
match self.test_expression(&mut if_stmt.test) {
|
||||||
Some(true) => {
|
Some(true) => {
|
||||||
*stmt = self.ast.move_statement(&mut if_stmt.consequent);
|
*stmt = self.ast.move_statement(&mut if_stmt.consequent);
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +50,7 @@ impl<'a> RemoveDeadCode<'a> {
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match conditional_expr.test.get_boolean_value() {
|
match self.test_expression(&mut conditional_expr.test) {
|
||||||
Some(true) => {
|
Some(true) => {
|
||||||
expression_stmt.expression =
|
expression_stmt.expression =
|
||||||
self.ast.move_expression(&mut conditional_expr.consequent);
|
self.ast.move_expression(&mut conditional_expr.consequent);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ impl<'a> Folder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fold_expression<'b>(&mut self, expr: &'b mut Expression<'a>) {
|
pub fn fold_expression<'b>(&mut self, expr: &'b mut Expression<'a>) {
|
||||||
let folded_expr = match expr {
|
let folded_expr = match expr {
|
||||||
Expression::BinaryExpression(binary_expr) => match binary_expr.operator {
|
Expression::BinaryExpression(binary_expr) => match binary_expr.operator {
|
||||||
BinaryOperator::Equality
|
BinaryOperator::Equality
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
mod closure;
|
#![allow(unused)]
|
||||||
mod esbuild;
|
// mod closure;
|
||||||
|
// mod esbuild;
|
||||||
mod oxc;
|
mod oxc;
|
||||||
mod tdewolff;
|
// mod tdewolff;
|
||||||
mod terser;
|
// mod terser;
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::Allocator;
|
||||||
use oxc_codegen::WhitespaceRemover;
|
use oxc_codegen::WhitespaceRemover;
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
mod code_removal;
|
mod code_removal;
|
||||||
mod folding;
|
mod folding;
|
||||||
mod precedence;
|
// mod precedence;
|
||||||
mod remove_dead_code;
|
mod remove_dead_code;
|
||||||
mod replace_global_defines;
|
mod replace_global_defines;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,21 @@ fn remove_dead_code() {
|
||||||
test("if (true) { foo } else { bar }", "{foo}");
|
test("if (true) { foo } else { bar }", "{foo}");
|
||||||
test("if (false) { foo } else { bar }", "{bar}");
|
test("if (false) { foo } else { bar }", "{bar}");
|
||||||
|
|
||||||
|
test("if (!false) { foo }", "{foo}");
|
||||||
|
test("if (!true) { foo } else { bar }", "{bar}");
|
||||||
|
|
||||||
|
test("if ('production' == 'production') { foo } else { bar }", "{foo}");
|
||||||
|
test("if ('development' == 'production') { foo } else { bar }", "{bar}");
|
||||||
|
|
||||||
|
test("if ('production' === 'production') { foo } else { bar }", "{foo}");
|
||||||
|
test("if ('development' === 'production') { foo } else { bar }", "{bar}");
|
||||||
|
|
||||||
test("false ? foo : bar;", "bar");
|
test("false ? foo : bar;", "bar");
|
||||||
test("true ? foo : bar;", "foo");
|
test("true ? foo : bar;", "foo");
|
||||||
|
|
||||||
|
test("!true ? foo : bar;", "bar");
|
||||||
|
test("!false ? foo : bar;", "foo");
|
||||||
|
|
||||||
|
test("!!false ? foo : bar;", "bar");
|
||||||
|
test("!!true ? foo : bar;", "foo");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue