mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(minifier): compute void number as undefined (#6028)
This commit is contained in:
parent
539751cd13
commit
e0a895962d
5 changed files with 41 additions and 22 deletions
|
|
@ -23,11 +23,13 @@ fn main() -> std::io::Result<()> {
|
|||
let source_text = std::fs::read_to_string(path)?;
|
||||
let source_type = SourceType::from_path(path).unwrap();
|
||||
|
||||
let printed = minify(&source_text, source_type, mangle);
|
||||
let mut allocator = Allocator::default();
|
||||
let printed = minify(&allocator, &source_text, source_type, mangle);
|
||||
println!("{printed}");
|
||||
|
||||
if twice {
|
||||
let printed2 = minify(&printed, source_type, mangle);
|
||||
allocator.reset();
|
||||
let printed2 = minify(&allocator, &printed, source_type, mangle);
|
||||
println!("{printed2}");
|
||||
println!("same = {}", printed == printed2);
|
||||
}
|
||||
|
|
@ -35,11 +37,15 @@ fn main() -> std::io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn minify(source_text: &str, source_type: SourceType, mangle: bool) -> String {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let options = MinifierOptions { mangle, compress: CompressOptions::all_true() };
|
||||
let ret = Minifier::new(options).build(&allocator, program);
|
||||
CodeGenerator::new().with_mangler(ret.mangler).build(program).source_text
|
||||
fn minify(
|
||||
allocator: &Allocator,
|
||||
source_text: &str,
|
||||
source_type: SourceType,
|
||||
mangle: bool,
|
||||
) -> String {
|
||||
let ret = Parser::new(allocator, source_text, source_type).parse();
|
||||
let mut program = ret.program;
|
||||
let options = MinifierOptions { mangle, compress: CompressOptions::default() };
|
||||
let ret = Minifier::new(options).build(allocator, &mut program);
|
||||
CodeGenerator::new().with_mangler(ret.mangler).build(&program).source_text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{cmp::Ordering, mem};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use oxc_ast::ast::*;
|
||||
|
|
@ -105,12 +105,12 @@ impl<'a> PeepholeFoldConstants {
|
|||
}
|
||||
|
||||
fn try_fold_unary_expression(
|
||||
&self,
|
||||
&mut self,
|
||||
expr: &mut UnaryExpression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Option<Expression<'a>> {
|
||||
match expr.operator {
|
||||
UnaryOperator::Void => Self::try_reduce_void(expr, ctx),
|
||||
UnaryOperator::Void => self.try_reduce_void(expr, ctx),
|
||||
UnaryOperator::Typeof => self.try_fold_type_of(expr, ctx),
|
||||
#[allow(clippy::float_cmp)]
|
||||
UnaryOperator::LogicalNot => {
|
||||
|
|
@ -135,13 +135,15 @@ impl<'a> PeepholeFoldConstants {
|
|||
|
||||
/// `void 1` -> `void 0`
|
||||
fn try_reduce_void(
|
||||
&mut self,
|
||||
expr: &mut UnaryExpression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Option<Expression<'a>> {
|
||||
if (!expr.argument.is_number() || !expr.argument.is_number_0())
|
||||
&& !expr.may_have_side_effects()
|
||||
{
|
||||
let _ = mem::replace(&mut expr.argument, ctx.ast.number_0());
|
||||
expr.argument = ctx.ast.number_0();
|
||||
self.changed = true;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
fn enter_variable_declaration(
|
||||
&mut self,
|
||||
decl: &mut VariableDeclaration<'a>,
|
||||
_ctx: &mut TraverseCtx<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
for declarator in decl.declarations.iter_mut() {
|
||||
self.compress_variable_declarator(declarator);
|
||||
self.compress_variable_declarator(declarator, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,11 +247,15 @@ impl<'a> PeepholeSubstituteAlternateSyntax {
|
|||
}
|
||||
}
|
||||
|
||||
fn compress_variable_declarator(&mut self, decl: &mut VariableDeclarator<'a>) {
|
||||
fn compress_variable_declarator(
|
||||
&mut self,
|
||||
decl: &mut VariableDeclarator<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if decl.kind.is_const() {
|
||||
return;
|
||||
}
|
||||
if decl.init.as_ref().is_some_and(|init| init.is_undefined() || init.is_void_0()) {
|
||||
if decl.init.as_ref().is_some_and(|init| ctx.is_expression_undefined(init)) {
|
||||
decl.init = None;
|
||||
self.changed = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,10 +41,13 @@ pub trait NodeUtil {
|
|||
fn scopes(&self) -> &ScopeTree;
|
||||
|
||||
fn is_expression_undefined(&self, expr: &Expression) -> bool {
|
||||
if let Expression::Identifier(ident) = expr {
|
||||
return self.is_identifier_undefined(ident);
|
||||
};
|
||||
false
|
||||
match expr {
|
||||
Expression::Identifier(ident) if self.is_identifier_undefined(ident) => true,
|
||||
Expression::UnaryExpression(e) if e.operator.is_void() && e.argument.is_number() => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use oxc_allocator::CloneIn;
|
|||
use oxc_ast_macros::ast;
|
||||
use oxc_span::{cmp::ContentEq, hash::ContentHash};
|
||||
#[cfg(feature = "serialize")]
|
||||
use ::{serde::Serialize, tsify::Tsify};
|
||||
use {serde::Serialize, tsify::Tsify};
|
||||
|
||||
use crate::precedence::{GetPrecedence, Precedence};
|
||||
|
||||
|
|
@ -356,6 +356,10 @@ impl UnaryOperator {
|
|||
matches!(self, Self::BitwiseNot)
|
||||
}
|
||||
|
||||
pub fn is_void(self) -> bool {
|
||||
matches!(self, Self::Void)
|
||||
}
|
||||
|
||||
pub fn is_keyword(self) -> bool {
|
||||
matches!(self, Self::Typeof | Self::Void | Self::Delete)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue