Skip to content

Commit

Permalink
fix #804: minify of ".0" in css
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 13, 2021
1 parent 3d34cef commit 15eeefa
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 28 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

* Fix minification of `.0` in CSS ([#804](https://github.com/evanw/esbuild/issues/804))

If you write `.0` instead of `0` in CSS and enabled `--minify`, esbuild would previously minify this token incorrectly (the token was deleted). This bug has been fixed and esbuild should now minify this token to `0`.

## 0.8.45

* Add the `--servedir=` flag ([#796](https://github.com/evanw/esbuild/issues/796))
Expand Down
8 changes: 7 additions & 1 deletion internal/css_parser/css_decls.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,11 +650,17 @@ func (p *parser) mangleColor(token css_ast.Token) css_ast.Token {
token.Kind = css_lexer.TFunction
token.Text = "rgba"
commaToken := p.commaToken()
alpha := floatToString(float64(hexA(hex)) / 255)
if p.options.MangleSyntax {
if text, ok := mangleNumber(alpha); ok {
alpha = text
}
}
token.Children = &[]css_ast.Token{
{Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken,
{Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken,
{Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken,
{Kind: css_lexer.TNumber, Text: floatToString(float64(hexA(hex)) / 255)},
{Kind: css_lexer.TNumber, Text: alpha},
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions internal/css_parser/css_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@ func mangleNumber(t string) (string, bool) {
// Remove the decimal point if it's unnecessary
if dot+1 == len(t) {
t = t[:dot]
if t == "" || t == "+" || t == "-" {
t += "0"
}
} else {
// Remove a leading zero
if len(t) >= 3 && t[0] == '0' && t[1] == '.' && t[2] >= '0' && t[2] <= '9' {
Expand Down
42 changes: 42 additions & 0 deletions internal/css_parser/css_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ func expectPrintedMangle(t *testing.T, contents string, expected string) {
})
}

func expectPrintedLowerMangle(t *testing.T, contents string, expected string) {
t.Helper()
expectPrintedCommon(t, contents+" [mangle]", contents, expected, config.Options{
UnsupportedCSSFeatures: ^compat.CSSFeature(0),
MangleSyntax: true,
})
}

func TestEscapes(t *testing.T) {
// TIdent
expectPrinted(t, "a { value: id\\65nt }", "a {\n value: ident;\n}\n")
Expand Down Expand Up @@ -256,18 +264,46 @@ func TestString(t *testing.T) {

func TestNumber(t *testing.T) {
for _, ext := range []string{"", "%", "px+"} {
expectPrinted(t, "a { width: .0"+ext+"; }", "a {\n width: .0"+ext+";\n}\n")
expectPrinted(t, "a { width: .00"+ext+"; }", "a {\n width: .00"+ext+";\n}\n")
expectPrinted(t, "a { width: .10"+ext+"; }", "a {\n width: .10"+ext+";\n}\n")
expectPrinted(t, "a { width: 0."+ext+"; }", "a {\n width: 0."+ext+";\n}\n")
expectPrinted(t, "a { width: 0.0"+ext+"; }", "a {\n width: 0.0"+ext+";\n}\n")
expectPrinted(t, "a { width: 0.1"+ext+"; }", "a {\n width: 0.1"+ext+";\n}\n")

expectPrinted(t, "a { width: +.0"+ext+"; }", "a {\n width: +.0"+ext+";\n}\n")
expectPrinted(t, "a { width: +.00"+ext+"; }", "a {\n width: +.00"+ext+";\n}\n")
expectPrinted(t, "a { width: +.10"+ext+"; }", "a {\n width: +.10"+ext+";\n}\n")
expectPrinted(t, "a { width: +0."+ext+"; }", "a {\n width: +0."+ext+";\n}\n")
expectPrinted(t, "a { width: +0.0"+ext+"; }", "a {\n width: +0.0"+ext+";\n}\n")
expectPrinted(t, "a { width: +0.1"+ext+"; }", "a {\n width: +0.1"+ext+";\n}\n")

expectPrinted(t, "a { width: -.0"+ext+"; }", "a {\n width: -.0"+ext+";\n}\n")
expectPrinted(t, "a { width: -.00"+ext+"; }", "a {\n width: -.00"+ext+";\n}\n")
expectPrinted(t, "a { width: -.10"+ext+"; }", "a {\n width: -.10"+ext+";\n}\n")
expectPrinted(t, "a { width: -0."+ext+"; }", "a {\n width: -0."+ext+";\n}\n")
expectPrinted(t, "a { width: -0.0"+ext+"; }", "a {\n width: -0.0"+ext+";\n}\n")
expectPrinted(t, "a { width: -0.1"+ext+"; }", "a {\n width: -0.1"+ext+";\n}\n")

expectPrintedMangle(t, "a { width: .0"+ext+"; }", "a {\n width: 0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: .00"+ext+"; }", "a {\n width: 0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: .10"+ext+"; }", "a {\n width: .1"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: 0."+ext+"; }", "a {\n width: 0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: 0.0"+ext+"; }", "a {\n width: 0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: 0.1"+ext+"; }", "a {\n width: .1"+ext+";\n}\n")

expectPrintedMangle(t, "a { width: +.0"+ext+"; }", "a {\n width: +0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: +.00"+ext+"; }", "a {\n width: +0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: +.10"+ext+"; }", "a {\n width: +.1"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: +0."+ext+"; }", "a {\n width: +0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: +0.0"+ext+"; }", "a {\n width: +0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: +0.1"+ext+"; }", "a {\n width: +.1"+ext+";\n}\n")

expectPrintedMangle(t, "a { width: -.0"+ext+"; }", "a {\n width: -0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: -.00"+ext+"; }", "a {\n width: -0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: -.10"+ext+"; }", "a {\n width: -.1"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: -0."+ext+"; }", "a {\n width: -0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: -0.0"+ext+"; }", "a {\n width: -0"+ext+";\n}\n")
expectPrintedMangle(t, "a { width: -0.1"+ext+"; }", "a {\n width: -.1"+ext+";\n}\n")
}
}
Expand Down Expand Up @@ -430,6 +466,9 @@ func TestColorRGBA(t *testing.T) {
expectPrintedMangle(t, "a { color: rgba(1% 2% 3% / 50%) }", "a {\n color: #0305087f;\n}\n")
expectPrintedMangle(t, "a { color: rgba(1%, 2%, 3%, 0.5) }", "a {\n color: #03050880;\n}\n")
expectPrintedMangle(t, "a { color: rgba(1%, 2%, 3%, 50%) }", "a {\n color: #0305087f;\n}\n")

expectPrintedLowerMangle(t, "a { color: rgb(1, 2, 3, 0.4) }", "a {\n color: rgba(1, 2, 3, .4);\n}\n")
expectPrintedLowerMangle(t, "a { color: rgba(1, 2, 3, 40%) }", "a {\n color: rgba(1, 2, 3, .4);\n}\n")
}

func TestColorHSLA(t *testing.T) {
Expand All @@ -444,6 +483,9 @@ func TestColorHSLA(t *testing.T) {

expectPrintedMangle(t, "a { color: hsl(30 25% 50% / 50%) }", "a {\n color: #9f80607f;\n}\n")
expectPrintedMangle(t, "a { color: hsla(30 25% 50% / 50%) }", "a {\n color: #9f80607f;\n}\n")

expectPrintedLowerMangle(t, "a { color: hsl(1, 2%, 3%, 0.4) }", "a {\n color: rgba(8, 8, 7, .4);\n}\n")
expectPrintedLowerMangle(t, "a { color: hsla(1, 2%, 3%, 40%) }", "a {\n color: rgba(8, 8, 7, .4);\n}\n")
}

func TestLowerColor(t *testing.T) {
Expand Down
19 changes: 1 addition & 18 deletions internal/css_printer/css_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,16 +553,6 @@ func (p *printer) printIdent(text string, mode identMode, whitespace trailingWhi
}
}

// TODO: Unify this with the numeric printing path in the JavaScript printer
func (p *printer) printNumber(text string) {
// Remove the leading "0" from numbers starting with "0."
if p.RemoveWhitespace && len(text) > 2 && strings.HasPrefix(text, "0.") {
text = text[1:]
}

p.print(text)
}

func (p *printer) printIndent(indent int) {
for i := 0; i < indent; i++ {
p.sb.WriteString(" ")
Expand Down Expand Up @@ -595,15 +585,8 @@ func (p *printer) printTokens(tokens []css_ast.Token) bool {
p.printIdent(t.Text, identNormal, whitespace)
p.print("(")

case css_lexer.TNumber:
p.printNumber(t.Text)

case css_lexer.TPercentage:
p.printNumber(t.PercentValue())
p.print("%")

case css_lexer.TDimension:
p.printNumber(t.DimensionValue())
p.print(t.DimensionValue())
p.printIdent(t.DimensionUnit(), identDimensionUnit, whitespace)

case css_lexer.TAtKeyword:
Expand Down
9 changes: 0 additions & 9 deletions internal/css_printer/css_printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,6 @@ func TestURLQuote(t *testing.T) {
expectPrinted(t, "* { background: url('\"foo\"') }", "* {\n background: url('\"foo\"');\n}\n")
}

func TestNumber(t *testing.T) {
expectPrinted(t, "div { opacity: 0.2 }", "div {\n opacity: 0.2;\n}\n")
expectPrinted(t, "div { opacity: 0.2% }", "div {\n opacity: 0.2%;\n}\n")
expectPrinted(t, "div { opacity: 0.2px }", "div {\n opacity: 0.2px;\n}\n")
expectPrintedMinify(t, "div { opacity: 0.2 }", "div{opacity:.2}")
expectPrintedMinify(t, "div { opacity: 0.2% }", "div{opacity:.2%}")
expectPrintedMinify(t, "div { opacity: 0.2px }", "div{opacity:.2px}")
}

func TestImportant(t *testing.T) {
expectPrinted(t, "a { b: c!important }", "a {\n b: c !important;\n}\n")
expectPrinted(t, "a { b: c!important; }", "a {\n b: c !important;\n}\n")
Expand Down

0 comments on commit 15eeefa

Please sign in to comment.