Commit 08652f2
authored
Print Infinity and negative numeric property keys as computed properties (#31328)
### Problem
Fuzzer-found invariant violation: `printed output does not reparse
(loader=ts)`.
```js
new Bun.Transpiler({ loader: "ts", minifyWhitespace: true })
.transformSync("(class {999…(325 digits)…999() {}})")
// => (class{1/0(){}}); ← syntax error
```
A numeric property name that overflows to `Infinity` (a few hundred
digits, or just `1e999`) is printed by `print_number` as `1/0` / `1 /
0`, which is not valid syntax in property-name position. The same
happens for:
- object literal properties, methods, getters/setters: `x={1/0:1}`,
`x={get 1/0(){}}`
- class methods and fields: `class{1/0(){}}`, `class{static 1/0=1}`
- destructuring patterns: `const{1/0:x}=obj`
- negative keys produced by cross-module `const enum` inlining with
`--minify`: `{-1:1,1/0:2}`
None of these reparse, so `bun build --minify` output can be
unparseable.
### Fix
In `src/js_printer/lib.rs`, when a non-computed property key is an
`ENumber` whose printed form would not be a valid property name (sign
bit set, or `+Infinity` in the configurations where `print_number` emits
`1/0`), print it as a computed property instead:
- `print_property` (object literals, classes) — mirrors esbuild's
`printProperty` ("Automatically print numbers that would cause a syntax
error as computed properties").
- `print_binding` (destructuring object patterns) — same check;
esbuild's `printBinding` lacks it and has the same bug with `--minify`,
so this goes one step further.
Output now matches esbuild: `(class{[1/0](){}})`, `{[-1]:1,[1/0]:2}`,
`const{[1/0]:x}=obj`. Semantics are unchanged since `[1/0]`/`[-1]`
evaluate to the same property keys (`"Infinity"`, `"-1"`).
### Verification
- `test/bundler/transpiler/transpiler.test.js` — new `describe("numeric
property keys that overflow to Infinity")`: exact printed output with
and without `minifyWhitespace` for object/class/destructuring positions,
the original 325-digit fuzz input, and a runtime check that the minified
output evaluates and the key is still `"Infinity"`.
- `test/bundler/bundler_minify.test.ts` — new
`itBundled("minify/NumericPropertyKeysPrintedAsComputed")`: bundles
`1e999` keys plus an imported `const enum { Negative = -1 }` used as a
computed key, and runs the output.
Both tests fail on current canary (`(class{1/0(){}})`, bundle fails to
parse) and pass with this change; the full files pass with the debug
build (150 + 33 tests, 0 fail).
### Linked issue
Fixes #14687 — the negative-key half of this change is exactly that
report (imported `const enum` member `-1` used as an object key with
`minify: true`). Verified with the issue's repro:
```js
// before: var e={-1:"foo",1:"bar"};export{e as FooRecord}; ← syntax error
// after: var e={[-1]:"foo",1:"bar"};export{e as FooRecord};
```1 parent dd0883d commit 08652f2
3 files changed
Lines changed: 98 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4664 | 4664 | | |
4665 | 4665 | | |
4666 | 4666 | | |
| 4667 | + | |
| 4668 | + | |
| 4669 | + | |
| 4670 | + | |
| 4671 | + | |
| 4672 | + | |
| 4673 | + | |
| 4674 | + | |
| 4675 | + | |
4667 | 4676 | | |
4668 | 4677 | | |
4669 | 4678 | | |
| |||
4789 | 4798 | | |
4790 | 4799 | | |
4791 | 4800 | | |
| 4801 | + | |
| 4802 | + | |
| 4803 | + | |
| 4804 | + | |
| 4805 | + | |
| 4806 | + | |
| 4807 | + | |
| 4808 | + | |
| 4809 | + | |
| 4810 | + | |
4792 | 4811 | | |
4793 | 4812 | | |
4794 | 4813 | | |
| |||
5061 | 5080 | | |
5062 | 5081 | | |
5063 | 5082 | | |
5064 | | - | |
| 5083 | + | |
| 5084 | + | |
| 5085 | + | |
| 5086 | + | |
| 5087 | + | |
| 5088 | + | |
| 5089 | + | |
| 5090 | + | |
| 5091 | + | |
5065 | 5092 | | |
5066 | 5093 | | |
5067 | 5094 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
272 | 272 | | |
273 | 273 | | |
274 | 274 | | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
275 | 300 | | |
276 | 301 | | |
277 | 302 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4411 | 4411 | | |
4412 | 4412 | | |
4413 | 4413 | | |
| 4414 | + | |
| 4415 | + | |
| 4416 | + | |
| 4417 | + | |
| 4418 | + | |
| 4419 | + | |
| 4420 | + | |
| 4421 | + | |
| 4422 | + | |
| 4423 | + | |
| 4424 | + | |
| 4425 | + | |
| 4426 | + | |
| 4427 | + | |
| 4428 | + | |
| 4429 | + | |
| 4430 | + | |
| 4431 | + | |
| 4432 | + | |
| 4433 | + | |
| 4434 | + | |
| 4435 | + | |
| 4436 | + | |
| 4437 | + | |
| 4438 | + | |
| 4439 | + | |
| 4440 | + | |
| 4441 | + | |
| 4442 | + | |
| 4443 | + | |
| 4444 | + | |
| 4445 | + | |
| 4446 | + | |
| 4447 | + | |
| 4448 | + | |
| 4449 | + | |
| 4450 | + | |
| 4451 | + | |
| 4452 | + | |
| 4453 | + | |
| 4454 | + | |
| 4455 | + | |
| 4456 | + | |
| 4457 | + | |
| 4458 | + | |
0 commit comments