Skip to content

Commit

Permalink
close #3026: remove unneeded spaces after numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Apr 1, 2023
1 parent b86e581 commit fa974c2
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@

Note that you need to specify both `--format=cjs` and `--platform=node` to get these node-specific annotations.

* Avoid printing an unnecessary space in between a number and a `.` ([#3026](https://github.com/evanw/esbuild/pull/3026))

JavaScript typically requires a space in between a number token and a `.` token to avoid the `.` being interpreted as a decimal point instead of a member expression. However, this space is not required if the number token itself contains a decimal point, an exponent, or uses a base other than 10. This release of esbuild now avoids printing the unnecessary space in these cases:

```js
// Original input
foo(1000 .x, 0 .x, 0.1 .x, 0.0001 .x, 0xFFFF_0000_FFFF_0000 .x)
// Old output (with --minify)
foo(1e3 .x,0 .x,.1 .x,1e-4 .x,0xffff0000ffff0000 .x);
// New output (with --minify)
foo(1e3.x,0 .x,.1.x,1e-4.x,0xffff0000ffff0000.x);
```

## 0.17.14

* Allow the TypeScript 5.0 `const` modifier in object type declarations ([#3021](https://github.com/evanw/esbuild/issues/3021))
Expand Down
21 changes: 11 additions & 10 deletions internal/js_printer/js_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ type printer struct {
forOfInitStart int

prevOpEnd int
prevNumEnd int
needSpaceBeforeDot int
prevRegExpEnd int
noLeadingNewlineHere int
intToBytesBuffer [64]byte
Expand Down Expand Up @@ -515,9 +515,6 @@ func (p *printer) printNumber(value float64, level js_ast.L) {
if !math.Signbit(value) {
p.printSpaceBeforeIdentifier()
p.printNonNegativeFloat(absValue)

// Remember the end of the latest number
p.prevNumEnd = len(p.js)
} else if level >= js_ast.LPrefix {
// Expressions such as "(-1).toString" need to wrap negative numbers.
// Instead of testing for "value < 0" we test for "signbit(value)" and
Expand All @@ -530,9 +527,6 @@ func (p *printer) printNumber(value float64, level js_ast.L) {
p.printSpaceBeforeOperator(js_ast.UnOpNeg)
p.print("-")
p.printNonNegativeFloat(absValue)

// Remember the end of the latest number
p.prevNumEnd = len(p.js)
}
}
}
Expand Down Expand Up @@ -1415,7 +1409,6 @@ func (p *printer) printUndefined(loc logger.Loc, level js_ast.L) {
p.printSpaceBeforeIdentifier()
p.addSourceMapping(loc)
p.print("void 0")
p.prevNumEnd = len(p.js)
}
}

Expand Down Expand Up @@ -2295,7 +2288,7 @@ func (p *printer) printExpr(expr js_ast.Expr, level js_ast.L, flags printExprFla
}
p.printExpr(e.Target, js_ast.LPostfix, flags&(forbidCall|hasNonOptionalChainParent))
if p.canPrintIdentifier(e.Name) {
if e.OptionalChain != js_ast.OptionalChainStart && p.prevNumEnd == len(p.js) {
if e.OptionalChain != js_ast.OptionalChainStart && p.needSpaceBeforeDot == len(p.js) {
// "1.toString" is a syntax error, so print "1 .toString" instead
p.print(" ")
}
Expand Down Expand Up @@ -3169,6 +3162,9 @@ func (p *printer) printNonNegativeFloat(absValue float64) {
if absValue < 1000 {
if asInt := int64(absValue); absValue == float64(asInt) {
p.printBytes(p.smallIntToBytes(int(asInt)))

// Integers always need a space before "." to avoid making a decimal point
p.needSpaceBeforeDot = len(p.js)
return
}
}
Expand Down Expand Up @@ -3290,6 +3286,11 @@ func (p *printer) printNonNegativeFloat(absValue float64) {
}

p.printBytes(result)

// We'll need a space before "." if it could be parsed as a decimal point
if !bytes.ContainsAny(result, ".ex") {
p.needSpaceBeforeDot = len(p.js)
}
}

func (p *printer) printDeclStmt(isExport bool, keyword string, decls []js_ast.Decl) {
Expand Down Expand Up @@ -4523,7 +4524,7 @@ func Print(tree js_ast.AST, symbols js_ast.SymbolMap, r renamer.Renamer, options
forOfInitStart: -1,

prevOpEnd: -1,
prevNumEnd: -1,
needSpaceBeforeDot: -1,
prevRegExpEnd: -1,
noLeadingNewlineHere: -1,
builder: sourcemap.MakeChunkBuilder(options.InputSourceMap, options.LineOffsetTables, options.ASCIIOnly),
Expand Down
12 changes: 12 additions & 0 deletions internal/js_printer/js_printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,18 @@ func TestNumber(t *testing.T) {
expectPrintedMinify(t, "x = 0xFFFF_FFFF_FFFF_F000", "x=0xfffffffffffff000;")
expectPrintedMinify(t, "x = 0xFFFF_FFFF_FFFF_F800", "x=1844674407370955e4;")
expectPrintedMinify(t, "x = 0xFFFF_FFFF_FFFF_FFFF", "x=18446744073709552e3;")

// Check printing a space in between a number and a subsequent "."
expectPrintedMinify(t, "x = 0.0001 .y", "x=1e-4.y;")
expectPrintedMinify(t, "x = 0.001 .y", "x=.001.y;")
expectPrintedMinify(t, "x = 0.01 .y", "x=.01.y;")
expectPrintedMinify(t, "x = 0.1 .y", "x=.1.y;")
expectPrintedMinify(t, "x = 0 .y", "x=0 .y;")
expectPrintedMinify(t, "x = 10 .y", "x=10 .y;")
expectPrintedMinify(t, "x = 100 .y", "x=100 .y;")
expectPrintedMinify(t, "x = 1000 .y", "x=1e3.y;")
expectPrintedMinify(t, "x = 12345 .y", "x=12345 .y;")
expectPrintedMinify(t, "x = 0xFFFF_0000_FFFF_0000 .y", "x=0xffff0000ffff0000.y;")
}

func TestArray(t *testing.T) {
Expand Down

0 comments on commit fa974c2

Please sign in to comment.