feat(minifier): minimize x["0"] -> x[0] (#8316)

This commit is contained in:
Boshen 2025-01-07 13:12:35 +00:00
parent a542013773
commit 051fbb6909
4 changed files with 78 additions and 19 deletions

View file

@ -46,15 +46,22 @@ impl<'a> ConvertToDottedProperties {
) {
if let MemberExpression::ComputedMemberExpression(e) = expr {
let Expression::StringLiteral(s) = &e.expression else { return };
if !is_identifier_name(&s.value) {
if is_identifier_name(&s.value) {
let property = ctx.ast.identifier_name(s.span, s.value.clone());
let object = ctx.ast.move_expression(&mut e.object);
*expr = MemberExpression::StaticMemberExpression(
ctx.ast.alloc_static_member_expression(e.span, object, property, e.optional),
);
self.changed = true;
return;
}
let property = ctx.ast.identifier_name(s.span, s.value.clone());
let object = ctx.ast.move_expression(&mut e.object);
*expr = MemberExpression::StaticMemberExpression(
ctx.ast.alloc_static_member_expression(e.span, object, property, e.optional),
);
self.changed = true;
let v = s.value.as_str();
if !e.optional {
if let Some(n) = Ctx::string_to_equivalent_number_value(v) {
e.expression =
ctx.ast.expression_numeric_literal(s.span, n, None, NumberBase::Decimal);
}
}
}
}
}
@ -110,7 +117,6 @@ mod test {
test_same("a[';']");
test_same("a[':']");
test_same("a['.']");
test_same("a['0']");
test_same("a['p ']");
test_same("a['p' + '']");
test_same("a[p]");
@ -282,4 +288,29 @@ mod test {
",
);
}
#[test]
fn test_index() {
test("x['y']", "x.y;");
test_same("x['y z']");
test("x?.['y']", "x?.y;");
test_same("x?.['y z']");
test("x?.['y']()", "x?.y();");
test_same("x?.['y z']()");
test_same("x['y' + 'z']");
test_same("x?.['y' + 'z']");
test("x['0']", "x[0];");
test("x['123']", "x[123];");
test("x['-123']", "x[-123];");
test_same("x['-0']");
test_same("x['+0']");
test_same("x['01']");
test_same("x['-01']");
test_same("x['0x1']");
test_same("x['-0x1']");
test("x['2147483647']", "x[2147483647]");
test_same("x['2147483648']");
test_same("x['-2147483648']");
test_same("x['-2147483649']");
}
}

View file

@ -843,16 +843,14 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
*key = PropertyKey::StaticIdentifier(
ctx.ast.alloc_identifier_name(s.span, s.value.clone()),
);
} else if (!s.value.starts_with('0') && !s.value.starts_with('+')) || s.value.len() <= 1 {
if let Ok(value) = s.value.parse::<u32>() {
self.changed = true;
*key = PropertyKey::NumericLiteral(ctx.ast.alloc_numeric_literal(
s.span,
value as f64,
None,
NumberBase::Decimal,
));
}
} else if let Some(value) = Ctx::string_to_equivalent_number_value(s.value.as_str()) {
self.changed = true;
*key = PropertyKey::NumericLiteral(ctx.ast.alloc_numeric_literal(
s.span,
value,
None,
NumberBase::Decimal,
));
}
}

View file

@ -82,4 +82,34 @@ impl<'a> Ctx<'a, '_> {
}
false
}
// https://github.com/evanw/esbuild/blob/v0.24.2/internal/js_ast/js_ast_helpers.go#L2641
pub fn string_to_equivalent_number_value(s: &str) -> Option<f64> {
if s.is_empty() {
return None;
}
let mut is_negative = false;
let mut int_value = 0i32;
let mut start = 0;
let bytes = s.as_bytes();
if bytes[0] == b'-' && s.len() > 1 {
is_negative = true;
start += 1;
}
if bytes[start] == b'0' && s.len() > 1 {
return None;
}
for b in &bytes[start..] {
if b.is_ascii_digit() {
int_value =
int_value.checked_mul(10).and_then(|v| v.checked_add(i32::from(b & 15)))?;
} else {
return None;
}
}
if is_negative {
int_value = -int_value;
}
Some(f64::from(int_value))
}
}

View file

@ -21,7 +21,7 @@ Original | minified | minified | gzip | gzip | Fixture
3.20 MB | 1.01 MB | 1.01 MB | 331.88 kB | 331.56 kB | echarts.js
6.69 MB | 2.32 MB | 2.31 MB | 492.76 kB | 488.28 kB | antd.js
6.69 MB | 2.32 MB | 2.31 MB | 492.77 kB | 488.28 kB | antd.js
10.95 MB | 3.50 MB | 3.49 MB | 909.12 kB | 915.50 kB | typescript.js