diff --git a/internal/css_printer/css_printer.go b/internal/css_printer/css_printer.go index e42947ba0a..4c1a184794 100644 --- a/internal/css_printer/css_printer.go +++ b/internal/css_printer/css_printer.go @@ -444,7 +444,14 @@ func (p *printer) printMediaQuery(query css_ast.MediaQuery, flags mqFlags) { p.printIdent(q.Type, identNormal, 0) if q.AndOrNull.Data != nil { p.print(" and ") - p.printMediaQuery(q.AndOrNull, 0) + // An "or" condition after a media type must be wrapped in parentheses + // to preserve grouping, e.g. "screen and ((a) or (b))" must keep the + // outer parentheses since "screen and (a) or (b)" is invalid CSS. + andFlags := mqFlags(0) + if binary, ok := q.AndOrNull.Data.(*css_ast.MQBinary); ok && binary.Op == css_ast.MQBinaryOpOr { + andFlags = mqNeedsParens + } + p.printMediaQuery(q.AndOrNull, andFlags) } case *css_ast.MQNot: diff --git a/internal/css_printer/css_printer_test.go b/internal/css_printer/css_printer_test.go index f02dbf7dd3..c0403d74e3 100644 --- a/internal/css_printer/css_printer_test.go +++ b/internal/css_printer/css_printer_test.go @@ -370,6 +370,11 @@ func TestAtMedia(t *testing.T) { expectPrintedMinify(t, "@media not ( (a) or (b) ) {div{color:red}}", "@media not ((a)or (b)){div{color:red}}") expectPrintedMinify(t, "@media not ( (a) and (b) ) {div{color:red}}", "@media not ((a)and (b)){div{color:red}}") + // Nested "or" inside a media type must preserve outer parentheses (https://github.com/evanw/esbuild/issues/4395) + expectPrintedMinify(t, "@media only screen and ((min-width: 10px) or (min-height: 10px)) {div{color:red}}", "@media only screen and ((min-width:10px)or (min-height:10px)){div{color:red}}") + expectPrintedMinify(t, "@media screen and ((a) or (b)) {div{color:red}}", "@media screen and ((a)or (b)){div{color:red}}") + expectPrinted(t, "@media only screen and ((min-width: 10px) or (min-height: 10px)) { div { color: red } }", "@media only screen and ((min-width: 10px) or (min-height: 10px)) {\n div {\n color: red;\n }\n}\n") + expectPrintedMinify(t, "@media (width < 2px) {div{color:red}}", "@media(width<2px){div{color:red}}") expectPrintedMinify(t, "@media (1px < width) {div{color:red}}", "@media(1px