fix(codegen): don't emit space between postfix -- and > when minifying (#23036)

## What

`a-- > b` was minified as `a-- >b` (a space before `>`) to avoid producing the `-->` token sequence. But `-->` is only an HTML close comment (`SingleLineHTMLCloseComment`) at the **start of a line**, and a postfix `--` always has an operand before it — so `a-->b` is never a comment and always parses as `(a--) > b`.

| Input | Before | After |
| --- | --- | --- |
| `while (i-- > 0) f()` | `while(i-- >0)f()` | `while(i-->0)f()` |
| `x = a-- > b` | `x=a-- >b` | `x=a-->b` |

Verified in node (`while(i-->0)` yields `[2,1,0]`). This goes one step beyond esbuild, which keeps the conservative space.

The `< ! --` guard (avoiding `<!--`, which *can* appear mid-line) is left untouched.
This commit is contained in:
Boshen committed 2026-06-07 02:52:51 +00:00
1 parent a4b1bf7337
commit 37169ffa75
3 files changed
+7 -6

No files matched your search

+3 -4
View File
@@ -826,22 +826,21 @@ impl<'a> Codegen<'a> {
// "x + + y" => "x+ +y"
// "x ++ + y" => "x+++y"
// "x + ++ y" => "x+ ++y"
// "-- >" => "-- >"
// "< ! --" => "<! --"
// Note: `a-- > b` does not need a space (`a-->b` is `(a--) > b`); `-->` is
// only an HTML close comment at the start of a line, and a postfix `--`
// always has an operand before it.
let bin_op_add = Operator::Binary(BinaryOperator::Addition);
let bin_op_sub = Operator::Binary(BinaryOperator::Subtraction);
let un_op_pos = Operator::Unary(UnaryOperator::UnaryPlus);
let un_op_pre_inc = Operator::Update(UpdateOperator::Increment);
let un_op_neg = Operator::Unary(UnaryOperator::UnaryNegation);
let un_op_pre_dec = Operator::Update(UpdateOperator::Decrement);
let un_op_post_dec = Operator::Update(UpdateOperator::Decrement);
let bin_op_gt = Operator::Binary(BinaryOperator::GreaterThan);
let un_op_not = Operator::Unary(UnaryOperator::LogicalNot);
if ((prev == bin_op_add || prev == un_op_pos)
&& (next == bin_op_add || next == un_op_pos || next == un_op_pre_inc))
|| ((prev == bin_op_sub || prev == un_op_neg)
&& (next == bin_op_sub || next == un_op_neg || next == un_op_pre_dec))
|| (prev == un_op_post_dec && next == bin_op_gt)
|| (prev == un_op_not
&& next == un_op_pre_dec
// `prev == UnaryOperator::LogicalNot` which means last byte is ASCII,
@@ -799,7 +799,9 @@ fn test_whitespace() {
test_minify("x + y--", "x+y--;");
test_minify("x - y--", "x-y--;");
test_minify("x-- > y", "x-- >y;");
// `-->` is only an HTML close comment at the start of a line, and `x--` always
// has an operand before it, so no space is needed.
test_minify("x-- > y", "x-->y;");
test_minify("x < !--y", "x<! --y;");
test_minify("x > !--y", "x>!--y;");
test_minify("!--y", "!--y;");
+1 -1
View File
@@ -23,5 +23,5 @@ Original | minified | minified | gzip | gzip | Iterations | Fi
6.69 MB | 2.22 MB | 2.31 MB | 458.45 kB | 488.28 kB | 4 | antd.js
10.95 MB | 3.33 MB | 3.49 MB | 853.33 kB | 915.50 kB | 4 | typescript.js
10.95 MB | 3.33 MB | 3.49 MB | 853.35 kB | 915.50 kB | 4 | typescript.js