Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mangle Infinity #1385

Merged
merged 5 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@

It's now possible to use `--target=es2021` to target the newly-released JavaScript version ES2021. The only difference between that and `--target=es2020` is that logical assignment operators such as `a ||= b` are not converted to regular assignment operators such as `a || (a = b)`.

* Minify Syntax `Infinity` to `1/0`
* Minify the syntax `Infinity` to `1 / 0` ([#1385](https://github.com/evanw/esbuild/pull/1385))

`--minify-syntax` will now minify the `Infinity` keyword to `1/0` which is less in bytes.
The `--minify-syntax` flag (automatically enabled by `--minify`) will now minify the expression `Infinity` to `1 / 0`, which uses fewer bytes:

```js
// Original code
const a = Infinity;

const b = 0 * Infinity;

// Output with "--mangle-syntax"
const a = 1/0;

const b = 0 * 1/0;
// Output with "--minify-syntax"
const a = 1 / 0;
```

This change was contributed by [@Gusted](https://github.com/Gusted).

## 0.12.9

* Allow `this` with `--define` ([#1361](https://github.com/evanw/esbuild/issues/1361))
Expand Down
33 changes: 20 additions & 13 deletions internal/js_printer/js_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2129,23 +2129,30 @@ func (p *printer) printExpr(expr js_ast.Expr, level js_ast.L, flags printExprFla
value := e.Value
absValue := math.Abs(value)

infinity := "Infinity"
if p.options.MangleSyntax {
infinity = "1/0"
}

if value != value {
p.printSpaceBeforeIdentifier()
p.print("NaN")
} else if value == positiveInfinity {
p.printSpaceBeforeIdentifier()
p.print(infinity)
} else if value == negativeInfinity {
if level >= js_ast.LPrefix {
p.print("(-" + infinity + ")")
} else {
} else if value == positiveInfinity || value == negativeInfinity {
wrap := (p.options.MangleSyntax && level >= js_ast.LMultiply) ||
(value == negativeInfinity && level >= js_ast.LPrefix)
if wrap {
p.print("(")
}
if value == negativeInfinity {
p.printSpaceBeforeOperator(js_ast.UnOpNeg)
p.print("-" + infinity)
p.print("-")
} else {
p.printSpaceBeforeIdentifier()
}
if !p.options.MangleSyntax {
p.print("Infinity")
} else if p.options.RemoveWhitespace {
p.print("1/0")
} else {
p.print("1 / 0")
}
if wrap {
p.print(")")
}
} else {
if !math.Signbit(value) {
Expand Down
63 changes: 55 additions & 8 deletions internal/js_printer/js_printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -932,13 +932,60 @@ func TestAvoidSlashScript(t *testing.T) {
expectPrintedMinify(t, "x = 1 << / script/.exec(y).length", "x=1<</ script/.exec(y).length;")
}

func TestMangledENumber(t *testing.T) {
expectPrintedMangle(t, "x = Infinity", "x = 1/0;\n")
expectPrintedMangle(t, "x = -Infinity+2", "x = -1/0 + 2;\n")
expectPrintedMangle(t, "x = (-Infinity+2) / 3", "x = (-1/0 + 2) / 3;\n")
func TestInfinity(t *testing.T) {
expectPrinted(t, "x = Infinity", "x = Infinity;\n")
expectPrinted(t, "x = -Infinity", "x = -Infinity;\n")
expectPrinted(t, "x = (Infinity).toString", "x = Infinity.toString;\n")
expectPrinted(t, "x = (-Infinity).toString", "x = (-Infinity).toString;\n")
expectPrinted(t, "x = (Infinity) ** 2", "x = Infinity ** 2;\n")
expectPrinted(t, "x = (-Infinity) ** 2", "x = (-Infinity) ** 2;\n")
expectPrinted(t, "x = ~Infinity", "x = ~Infinity;\n")
expectPrinted(t, "x = ~-Infinity", "x = ~-Infinity;\n")
expectPrinted(t, "x = Infinity * y", "x = Infinity * y;\n")
expectPrinted(t, "x = Infinity / y", "x = Infinity / y;\n")
expectPrinted(t, "x = y * Infinity", "x = y * Infinity;\n")
expectPrinted(t, "x = y / Infinity", "x = y / Infinity;\n")
expectPrinted(t, "throw Infinity", "throw Infinity;\n")

expectPrintedMinify(t, "x = Infinity", "x=Infinity;")
expectPrintedMinify(t, "x = -Infinity", "x=-Infinity;")
expectPrintedMinify(t, "x = (Infinity).toString", "x=Infinity.toString;")
expectPrintedMinify(t, "x = (-Infinity).toString", "x=(-Infinity).toString;")
expectPrintedMinify(t, "x = (Infinity) ** 2", "x=Infinity**2;")
expectPrintedMinify(t, "x = (-Infinity) ** 2", "x=(-Infinity)**2;")
expectPrintedMinify(t, "x = ~Infinity", "x=~Infinity;")
expectPrintedMinify(t, "x = ~-Infinity", "x=~-Infinity;")
expectPrintedMinify(t, "x = Infinity * y", "x=Infinity*y;")
expectPrintedMinify(t, "x = Infinity / y", "x=Infinity/y;")
expectPrintedMinify(t, "x = y * Infinity", "x=y*Infinity;")
expectPrintedMinify(t, "x = y / Infinity", "x=y/Infinity;")
expectPrintedMinify(t, "throw Infinity", "throw Infinity;")

expectPrintedMangle(t, "x = Infinity", "x = 1 / 0;\n")
expectPrintedMangle(t, "x = -Infinity", "x = -1 / 0;\n")
expectPrintedMangle(t, "x = (Infinity).toString", "x = (1 / 0).toString;\n")
expectPrintedMangle(t, "x = (-Infinity).toString", "x = (-1 / 0).toString;\n")
expectPrintedMangle(t, "x = Infinity ** 2", "x = (1 / 0) ** 2;\n")
expectPrintedMangle(t, "x = (-Infinity) ** 2", "x = (-1 / 0) ** 2;\n")
expectPrintedMangle(t, "x = ~Infinity", "x = ~(1 / 0);\n")
expectPrintedMangle(t, "x = ~-Infinity", "x = ~(-1 / 0);\n")
expectPrintedMangle(t, "x = Infinity * y", "x = 1 / 0 * y;\n")
expectPrintedMangle(t, "x = Infinity / y", "x = 1 / 0 / y;\n")
expectPrintedMangle(t, "x = y * Infinity", "x = y * (1 / 0);\n")
expectPrintedMangle(t, "x = y / Infinity", "x = y / (1 / 0);\n")
expectPrintedMangle(t, "throw Infinity", "throw 1 / 0;\n")

expectPrintedMangleMinify(t, "x = Infinity", "x=1/0;")
expectPrintedMangleMinify(t, "x = -Infinity+2", "x=-1/0+2;")
expectPrintedMangleMinify(t, "x = (-Infinity+2) / 3", "x=(-1/0+2)/3;")
expectPrintedMangleMinify(t, "1 + -Infinity", "1+-1/0;")
expectPrintedMangleMinify(t, "1 - -Infinity", "1- -1/0;")
expectPrintedMangleMinify(t, "x = -Infinity", "x=-1/0;")
expectPrintedMangleMinify(t, "x = (Infinity).toString", "x=(1/0).toString;")
expectPrintedMangleMinify(t, "x = (-Infinity).toString", "x=(-1/0).toString;")
expectPrintedMangleMinify(t, "x = Infinity ** 2", "x=(1/0)**2;")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've might overlook this but 1/0 ** 2 will result in Infinity as well. Can the parentheses be "turned off" for different level's? Or will that cause more problems 😅.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expressions (a / b) ** c and a / (b ** c) have different ASTs. Having minification turn one into the other is not generally correct, even if it's correct in that specific case. For example, changing console.log(0 ** Infinity ** 1); into console.log(0 ** 1 / 0 ** 1); changes the output from 0 to NaN.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks for the explanation 🎉

expectPrintedMangleMinify(t, "x = (-Infinity) ** 2", "x=(-1/0)**2;")
expectPrintedMangleMinify(t, "x = ~Infinity", "x=~(1/0);")
expectPrintedMangleMinify(t, "x = ~-Infinity", "x=~(-1/0);")
expectPrintedMangleMinify(t, "x = Infinity * y", "x=1/0*y;")
expectPrintedMangleMinify(t, "x = Infinity / y", "x=1/0/y;")
expectPrintedMangleMinify(t, "x = y * Infinity", "x=y*(1/0);")
expectPrintedMangleMinify(t, "x = y / Infinity", "x=y/(1/0);")
expectPrintedMangleMinify(t, "throw Infinity", "throw 1/0;")
}