mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(minifier): finish implementing folding array expressions (#6575)
This commit is contained in:
parent
7a028b30e0
commit
590925a40c
2 changed files with 92 additions and 11 deletions
|
|
@ -126,6 +126,14 @@ impl<'a> AstBuilder<'a> {
|
||||||
mem::replace(decl, empty_decl)
|
mem::replace(decl, empty_decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_array_expression_element(
|
||||||
|
self,
|
||||||
|
element: &mut ArrayExpressionElement<'a>,
|
||||||
|
) -> ArrayExpressionElement<'a> {
|
||||||
|
let empty_element = self.array_expression_element_elision(Span::default());
|
||||||
|
mem::replace(element, empty_element)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn move_vec<T>(self, vec: &mut Vec<'a, T>) -> Vec<'a, T> {
|
pub fn move_vec<T>(self, vec: &mut Vec<'a, T>) -> Vec<'a, T> {
|
||||||
mem::replace(vec, self.vec())
|
mem::replace(vec, self.vec())
|
||||||
|
|
|
||||||
|
|
@ -242,17 +242,90 @@ impl<'a, 'b> PeepholeRemoveDeadCode {
|
||||||
// This is the only scenario where we can't remove it even if `ExpressionStatement`.
|
// This is the only scenario where we can't remove it even if `ExpressionStatement`.
|
||||||
// TODO find a better way to handle this.
|
// TODO find a better way to handle this.
|
||||||
|
|
||||||
stmt.expression
|
|
||||||
.is_literal_value(false)
|
|
||||||
.then(|| {
|
|
||||||
if let Ancestor::ArrowFunctionExpressionBody(body) = ctx.ancestry.ancestor(1) {
|
if let Ancestor::ArrowFunctionExpressionBody(body) = ctx.ancestry.ancestor(1) {
|
||||||
if *body.expression() {
|
if *body.expression() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ctx.ast.statement_empty(SPAN))
|
|
||||||
|
stmt.expression
|
||||||
|
.is_literal_value(false)
|
||||||
|
.then(|| Some(ctx.ast.statement_empty(SPAN)))
|
||||||
|
.unwrap_or_else(|| match &mut stmt.expression {
|
||||||
|
Expression::ArrayExpression(expr) => Self::try_fold_array_expression(expr, ctx),
|
||||||
|
// TODO: handle object expression
|
||||||
|
Expression::ObjectExpression(_object_expr) => None,
|
||||||
|
_ => None,
|
||||||
})
|
})
|
||||||
.unwrap_or(None)
|
}
|
||||||
|
|
||||||
|
// `([1,2,3, foo()])` -> `foo()`
|
||||||
|
fn try_fold_array_expression(
|
||||||
|
array_expr: &mut ArrayExpression<'a>,
|
||||||
|
ctx: Ctx<'a, 'b>,
|
||||||
|
) -> Option<Statement<'a>> {
|
||||||
|
let mut transformed_elements = ctx.ast.vec();
|
||||||
|
let mut pending_spread_elements = ctx.ast.vec();
|
||||||
|
|
||||||
|
if array_expr.elements.len() == 0
|
||||||
|
|| array_expr
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.all(|el| matches!(el, ArrayExpressionElement::SpreadElement(_)))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for el in array_expr.elements.iter_mut() {
|
||||||
|
match el {
|
||||||
|
ArrayExpressionElement::SpreadElement(_) => {
|
||||||
|
let spread_element = ctx.ast.move_array_expression_element(el);
|
||||||
|
pending_spread_elements.push(spread_element);
|
||||||
|
}
|
||||||
|
ArrayExpressionElement::Elision(_) => {}
|
||||||
|
match_expression!(ArrayExpressionElement) => {
|
||||||
|
let el = el.to_expression_mut();
|
||||||
|
let el_expr = ctx.ast.move_expression(el);
|
||||||
|
if !el_expr.is_literal_value(false)
|
||||||
|
&& !matches!(el_expr, Expression::Identifier(_))
|
||||||
|
{
|
||||||
|
if pending_spread_elements.len() > 0 {
|
||||||
|
// flush pending spread elements
|
||||||
|
transformed_elements.push(ctx.ast.expression_array(
|
||||||
|
SPAN,
|
||||||
|
pending_spread_elements,
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
pending_spread_elements = ctx.ast.vec();
|
||||||
|
}
|
||||||
|
transformed_elements.push(el_expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pending_spread_elements.len() > 0 {
|
||||||
|
transformed_elements.push(ctx.ast.expression_array(
|
||||||
|
SPAN,
|
||||||
|
pending_spread_elements,
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if transformed_elements.is_empty() {
|
||||||
|
return Some(ctx.ast.statement_empty(SPAN));
|
||||||
|
} else if transformed_elements.len() == 1 {
|
||||||
|
return Some(
|
||||||
|
ctx.ast.statement_expression(array_expr.span, transformed_elements.pop().unwrap()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(ctx.ast.statement_expression(
|
||||||
|
array_expr.span,
|
||||||
|
ctx.ast.expression_from_sequence(
|
||||||
|
ctx.ast.sequence_expression(array_expr.span, transformed_elements),
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try folding conditional expression (?:) if the condition results of the condition is known.
|
/// Try folding conditional expression (?:) if the condition results of the condition is known.
|
||||||
|
|
@ -398,17 +471,17 @@ mod test {
|
||||||
fn test_array_literal() {
|
fn test_array_literal() {
|
||||||
fold("([])", "");
|
fold("([])", "");
|
||||||
fold("([1])", "");
|
fold("([1])", "");
|
||||||
// fold("([a])", "a");
|
fold("([a])", "");
|
||||||
// fold("([foo()])", "foo()");
|
fold("([foo()])", "foo()");
|
||||||
|
fold_same("baz.map((v) => [v])");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn test_array_literal_containing_spread() {
|
fn test_array_literal_containing_spread() {
|
||||||
fold_same("([...c])");
|
fold_same("([...c])");
|
||||||
fold("([4, ...c, a])", "([...c])");
|
fold("([4, ...c, a])", "([...c])");
|
||||||
fold("([foo(), ...c, bar()])", "(foo(), [...c], bar())");
|
fold("([foo(), ...c, bar()])", "(foo(), [...c], bar())");
|
||||||
fold("([...a, b, ...c])", "([...a], [...c])");
|
fold("([...a, b, ...c])", "([...a, ...c])");
|
||||||
fold_same("([...b, ...c])"); // It would also be fine if the spreads were split apart.
|
fold_same("([...b, ...c])"); // It would also be fine if the spreads were split apart.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue