## Summary
Implements the `typeof undefined === 'u'` minification optimization from
esbuild in Bun's minifier, and fixes dead code elimination (DCE) for
typeof comparisons with string literals.
### Part 1: Minification Optimization
This optimization transforms:
- `typeof x === "undefined"` → `typeof x > "u"`
- `typeof x !== "undefined"` → `typeof x < "u"`
- `typeof x == "undefined"` → `typeof x > "u"`
- `typeof x != "undefined"` → `typeof x < "u"`
Also handles flipped operands (`"undefined" === typeof x`).
### Part 2: DCE Fix for Typeof Comparisons
Fixed dead code elimination to properly handle typeof comparisons with
strings (e.g., `typeof x <= 'u'`). These patterns can now be correctly
eliminated when they reference unbound identifiers that would throw
ReferenceErrors.
## Before/After
### Minification
Before:
```javascript
console.log(typeof x === "undefined");
```
After:
```javascript
console.log(typeof x > "u");
```
### Dead Code Elimination
Before (incorrectly kept):
```javascript
var REMOVE_1 = typeof x <= 'u' ? x : null;
```
After (correctly eliminated):
```javascript
// removed
```
## Implementation
### Minification
- Added `tryOptimizeTypeofUndefined` function in
`src/ast/visitBinaryExpression.zig`
- Handles all 4 equality operators and both operand orders
- Only optimizes when both sides match the expected pattern (typeof
expression + "undefined" string)
- Replaces "undefined" with "u" and changes operators to `>` (for
equality) or `<` (for inequality)
### DCE Improvements
- Extended `isSideEffectFreeUnboundIdentifierRef` in `src/ast/P.zig` to
handle comparison operators (`<`, `>`, `<=`, `>=`)
- Added comparison operators to `simplifyUnusedExpr` in
`src/ast/SideEffects.zig`
- Now correctly identifies when typeof comparisons guard against
undefined references
## Test Plan
✅ Added comprehensive test in `test/bundler/bundler_minify.test.ts` that
verifies:
- All 8 variations work correctly (4 operators × 2 operand orders)
- Cases that shouldn't be optimized are left unchanged
- Matches esbuild's behavior exactly using inline snapshots
✅ DCE test `dce/DCETypeOfCompareStringGuardCondition` now passes:
- Correctly eliminates dead code with typeof comparison patterns
- Maintains compatibility with esbuild's DCE behavior
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
## Summary
- Fix transpiler bug where comma expressions like `(0, obj.method)()`
were incorrectly optimized to `obj.method()`
- This preserved the `this` binding instead of stripping it as per
JavaScript semantics
- Add comprehensive regression test to prevent future issues
## Root Cause
The comma operator optimization in `src/js_parser.zig:7281` was directly
returning the right operand when the left operand had no side effects,
without checking if the expression was being used as a call target.
## Solution
- Added the same `is_call_target` check that other operators (nullish
coalescing, logical OR/AND) use
- When a comma expression is used as a call target AND the right operand
has a value for `this`, preserve the comma expression to strip the
`this` binding
- Follows existing patterns in the codebase for consistent behavior
## Test Plan
- [x] Reproduce the original bug: `(0, obj.method)()` incorrectly
preserved `this`
- [x] Verify fix: comma expressions now correctly strip `this` binding
in function calls
- [x] All existing transpiler tests continue to pass
- [x] Added regression test covering various comma expression scenarios
- [x] Tested edge cases: nested comma expressions, side effects,
different operand types
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Splits up js_parser.zig into multiple files. Also changes visitExprInOut
to use function calls rather than switch
Not ready:
- [ ] P.zig is ~70,000 tokens, still needs to get smaller
- [x] ~~measure zig build time before & after (is it slower?)~~ no
significant impact
---------
Co-authored-by: pfgithub <6010774+pfgithub@users.noreply.github.com>