diff --git a/CHANGELOG.md b/CHANGELOG.md index 113eac7abf9..1bb36003d9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,27 @@ a,b{color:red} ``` +* Shorten `top`, `right`, `bottom`, `left` CSS property into `inset` when it is supported ([#1758](https://github.com/evanw/esbuild/pull/1758)) + + This release enables collapsing of `inset` related properties: + + ```css + /* Original code */ + div { + top: 0; + right: 0; + bottom: 0; + left: 0; + } + + /* Output with "--minify-syntax" */ + div { + inset: 0; + } + ``` + + This minification rule is only enabled when `inset` property is supported by the target environment. Make sure to set esbuild's `target` setting correctly when minifying if the code will be running in an older environment (e.g. earlier than Chrome 87). + ## 0.13.12 * Implement initial support for simplifying `calc()` expressions in CSS ([#1607](https://github.com/evanw/esbuild/issues/1607)) diff --git a/internal/compat/css_table.go b/internal/compat/css_table.go index 4fdd2db313e..892ae418ce6 100644 --- a/internal/compat/css_table.go +++ b/internal/compat/css_table.go @@ -13,6 +13,8 @@ const ( // - rgb() can accept alpha values // - Space-separated functional color notations Modern_RGB_HSL + + InsetProperty ) func (features CSSFeature) Has(feature CSSFeature) bool { @@ -42,6 +44,14 @@ var cssTable = map[CSSFeature]map[Engine][]int{ IOS: {12, 2}, Safari: {12, 1}, }, + // Data from: https://developer.mozilla.org/en-US/docs/Web/CSS/inset + InsetProperty: { + Chrome: {87}, + Edge: {87}, + Firefox: {66}, + IOS: {14, 5}, + Safari: {14, 1}, + }, } // Return all features that are not available in at least one environment diff --git a/internal/css_ast/css_decl_table.go b/internal/css_ast/css_decl_table.go index 558663215ee..a73eabb77a7 100644 --- a/internal/css_ast/css_decl_table.go +++ b/internal/css_ast/css_decl_table.go @@ -171,6 +171,7 @@ const ( DImageOrientation DImageRendering DInlineSize + DInset DJustifyContent DJustifyItems DJustifySelf @@ -489,6 +490,7 @@ var KnownDeclarations = map[string]D{ "image-orientation": DImageOrientation, "image-rendering": DImageRendering, "inline-size": DInlineSize, + "inset": DInset, "justify-content": DJustifyContent, "justify-items": DJustifyItems, "justify-self": DJustifySelf, diff --git a/internal/css_parser/css_decls.go b/internal/css_parser/css_decls.go index ebb4369dbb0..e62024401c6 100644 --- a/internal/css_parser/css_decls.go +++ b/internal/css_parser/css_decls.go @@ -1,6 +1,7 @@ package css_parser import ( + "github.com/evanw/esbuild/internal/compat" "github.com/evanw/esbuild/internal/css_ast" "github.com/evanw/esbuild/internal/css_lexer" ) @@ -77,8 +78,9 @@ func compactTokenQuad(a css_ast.Token, b css_ast.Token, c css_ast.Token, d css_a } func (p *parser) processDeclarations(rules []css_ast.Rule) []css_ast.Rule { - margin := boxTracker{} - padding := boxTracker{} + margin := newBoxTracker(css_ast.DMargin, "margin", true) + padding := newBoxTracker(css_ast.DPadding, "padding", false) + inset := newBoxTracker(css_ast.DInset, "inset", true) borderRadius := borderRadiusTracker{} for i, rule := range rules { @@ -131,6 +133,27 @@ func (p *parser) processDeclarations(rules []css_ast.Rule) []css_ast.Rule { decl.Value = p.mangleBoxShadows(decl.Value) } + case css_ast.DMargin: + if p.options.MangleSyntax { + margin.mangleSides(rules, decl, i, p.options.RemoveWhitespace) + } + case css_ast.DMarginTop: + if p.options.MangleSyntax { + margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxTop) + } + case css_ast.DMarginRight: + if p.options.MangleSyntax { + margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxRight) + } + case css_ast.DMarginBottom: + if p.options.MangleSyntax { + margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxBottom) + } + case css_ast.DMarginLeft: + if p.options.MangleSyntax { + margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxLeft) + } + case css_ast.DPadding: if p.options.MangleSyntax { padding.mangleSides(rules, decl, i, p.options.RemoveWhitespace) @@ -152,25 +175,25 @@ func (p *parser) processDeclarations(rules []css_ast.Rule) []css_ast.Rule { padding.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxLeft) } - case css_ast.DMargin: - if p.options.MangleSyntax { - margin.mangleSides(rules, decl, i, p.options.RemoveWhitespace) + case css_ast.DInset: + if !p.options.UnsupportedCSSFeatures.Has(compat.InsetProperty) && p.options.MangleSyntax { + inset.mangleSides(rules, decl, i, p.options.RemoveWhitespace) } - case css_ast.DMarginTop: - if p.options.MangleSyntax { - margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxTop) + case css_ast.DTop: + if !p.options.UnsupportedCSSFeatures.Has(compat.InsetProperty) && p.options.MangleSyntax { + inset.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxTop) } - case css_ast.DMarginRight: - if p.options.MangleSyntax { - margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxRight) + case css_ast.DRight: + if !p.options.UnsupportedCSSFeatures.Has(compat.InsetProperty) && p.options.MangleSyntax { + inset.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxRight) } - case css_ast.DMarginBottom: - if p.options.MangleSyntax { - margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxBottom) + case css_ast.DBottom: + if !p.options.UnsupportedCSSFeatures.Has(compat.InsetProperty) && p.options.MangleSyntax { + inset.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxBottom) } - case css_ast.DMarginLeft: - if p.options.MangleSyntax { - margin.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxLeft) + case css_ast.DLeft: + if !p.options.UnsupportedCSSFeatures.Has(compat.InsetProperty) && p.options.MangleSyntax { + inset.mangleSide(rules, decl, i, p.options.RemoveWhitespace, boxLeft) } case css_ast.DBorderRadius: diff --git a/internal/css_parser/css_decls_box.go b/internal/css_parser/css_decls_box.go index 5637f175e11..92e7e0ca3e5 100644 --- a/internal/css_parser/css_decls_box.go +++ b/internal/css_parser/css_decls_box.go @@ -20,10 +20,22 @@ type boxSide struct { } type boxTracker struct { + key css_ast.D + keyText string + allowAuto bool + sides [4]boxSide important bool } +func newBoxTracker(key css_ast.D, keyText string, allowAuto bool) boxTracker { + return boxTracker{ + key: key, + keyText: keyText, + allowAuto: allowAuto, + } +} + func (box *boxTracker) updateSide(rules []css_ast.Rule, side int, new boxSide) { if old := box.sides[side]; old.token.Kind != css_lexer.TEndOfFile && (!new.single || old.single) { rules[old.index] = css_ast.Rule{} @@ -39,8 +51,7 @@ func (box *boxTracker) mangleSides(rules []css_ast.Rule, decl *css_ast.RDeclarat } allowedIdent := "" - isMargin := decl.Key == css_ast.DMargin - if isMargin { + if box.allowAuto { allowedIdent = "auto" } if quad, ok := expandTokenQuad(decl.Value, allowedIdent); ok { @@ -48,7 +59,7 @@ func (box *boxTracker) mangleSides(rules []css_ast.Rule, decl *css_ast.RDeclarat t.TurnLengthIntoNumberIfZero() box.updateSide(rules, side, boxSide{token: t, index: uint32(index)}) } - box.compactRules(rules, decl.KeyRange, removeWhitespace, isMargin) + box.compactRules(rules, decl.KeyRange, removeWhitespace) } else { box.sides = [4]boxSide{} } @@ -61,19 +72,13 @@ func (box *boxTracker) mangleSide(rules []css_ast.Rule, decl *css_ast.RDeclarati box.important = decl.Important } - isMargin := false - switch decl.Key { - case css_ast.DMarginTop, css_ast.DMarginRight, css_ast.DMarginBottom, css_ast.DMarginLeft: - isMargin = true - } - if tokens := decl.Value; len(tokens) == 1 { - if t := tokens[0]; t.Kind.IsNumeric() || (t.Kind == css_lexer.TIdent && isMargin && t.Text == "auto") { + if t := tokens[0]; t.Kind.IsNumeric() || (t.Kind == css_lexer.TIdent && box.allowAuto && t.Text == "auto") { if t.TurnLengthIntoNumberIfZero() { tokens[0] = t } box.updateSide(rules, side, boxSide{token: t, index: uint32(index), single: true}) - box.compactRules(rules, decl.KeyRange, removeWhitespace, isMargin) + box.compactRules(rules, decl.KeyRange, removeWhitespace) return } } @@ -81,7 +86,7 @@ func (box *boxTracker) mangleSide(rules []css_ast.Rule, decl *css_ast.RDeclarati box.sides = [4]boxSide{} } -func (box *boxTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, removeWhitespace bool, isMargin bool) { +func (box *boxTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, removeWhitespace bool) { // All tokens must be present if eof := css_lexer.TEndOfFile; box.sides[0].token.Kind == eof || box.sides[1].token.Kind == eof || box.sides[2].token.Kind == eof || box.sides[3].token.Kind == eof { @@ -104,18 +109,9 @@ func (box *boxTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, rules[box.sides[3].index] = css_ast.Rule{} // Insert the combined declaration where the last rule was - var key css_ast.D - var keyText string - if isMargin { - key = css_ast.DMargin - keyText = "margin" - } else { - key = css_ast.DPadding - keyText = "padding" - } rules[box.sides[3].index].Data = &css_ast.RDeclaration{ - Key: key, - KeyText: keyText, + Key: box.key, + KeyText: box.keyText, Value: tokens, KeyRange: keyRange, Important: box.important, diff --git a/internal/css_parser/css_parser_test.go b/internal/css_parser/css_parser_test.go index 770b619d6e1..14bd8257924 100644 --- a/internal/css_parser/css_parser_test.go +++ b/internal/css_parser/css_parser_test.go @@ -932,20 +932,31 @@ func TestEmptyRule(t *testing.T) { expectPrintedMangleMinify(t, "@keyframes test { from { color: red } to {} }", "@keyframes test{0%{color:red}}") } -func TestMarginAndPadding(t *testing.T) { - for _, x := range []string{"margin", "padding"} { +func TestMarginAndPaddingAndInset(t *testing.T) { + for _, x := range []string{"margin", "padding", "inset"} { + xTop := x + "-top" + xRight := x + "-right" + xBottom := x + "-bottom" + xLeft := x + "-left" + if x == "inset" { + xTop = "top" + xRight = "right" + xBottom = "bottom" + xLeft = "left" + } + expectPrinted(t, "a { "+x+": 0 1 0 1 }", "a {\n "+x+": 0 1 0 1;\n}\n") expectPrinted(t, "a { "+x+": 0 1 0px 1px }", "a {\n "+x+": 0 1 0px 1px;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 0px }", "a {\n "+x+"-top: 0;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 0px }", "a {\n "+x+"-right: 0;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 0px }", "a {\n "+x+"-bottom: 0;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 0px }", "a {\n "+x+"-left: 0;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 0px }", "a {\n "+xTop+": 0;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 0px }", "a {\n "+xRight+": 0;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 0px }", "a {\n "+xBottom+": 0;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 0px }", "a {\n "+xLeft+": 0;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 1px }", "a {\n "+x+"-top: 1px;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 1px }", "a {\n "+x+"-right: 1px;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 1px }", "a {\n "+x+"-bottom: 1px;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1px }", "a {\n "+x+"-left: 1px;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 1px }", "a {\n "+xTop+": 1px;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 1px }", "a {\n "+xRight+": 1px;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 1px }", "a {\n "+xBottom+": 1px;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1px }", "a {\n "+xLeft+": 1px;\n}\n") expectPrintedMangle(t, "a { "+x+": 0 1 0 0 }", "a {\n "+x+": 0 1 0 0;\n}\n") expectPrintedMangle(t, "a { "+x+": 0 1 2 1 }", "a {\n "+x+": 0 1 2;\n}\n") @@ -955,72 +966,77 @@ func TestMarginAndPadding(t *testing.T) { expectPrintedMangle(t, "a { "+x+": 0 1px 0px 1px }", "a {\n "+x+": 0 1px;\n}\n") expectPrintedMangle(t, "a { "+x+": 0 1 0px 1px }", "a {\n "+x+": 0 1 0 1px;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-top: 5 }", "a {\n "+x+": 5 2 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-right: 5 }", "a {\n "+x+": 1 5 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-bottom: 5 }", "a {\n "+x+": 1 2 5 4;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-left: 5 }", "a {\n "+x+": 1 2 3 5;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xTop+": 5 }", "a {\n "+x+": 5 2 3 4;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xRight+": 5 }", "a {\n "+x+": 1 5 3 4;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xBottom+": 5 }", "a {\n "+x+": 1 2 5 4;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xLeft+": 5 }", "a {\n "+x+": 1 2 3 5;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 5; "+x+": 1 2 3 4 }", "a {\n "+x+": 1 2 3 4;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 1; "+x+"-top: 2 }", "a {\n "+x+"-top: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 1; "+x+"-right: 2 }", "a {\n "+x+"-right: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 1; "+x+"-bottom: 2 }", "a {\n "+x+"-bottom: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1; "+x+"-left: 2 }", "a {\n "+x+"-left: 2;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 1; "+xTop+": 2 }", "a {\n "+xTop+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 1; "+xRight+": 2 }", "a {\n "+xRight+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 1; "+xBottom+": 2 }", "a {\n "+xBottom+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1; "+xLeft+": 2 }", "a {\n "+xLeft+": 2;\n}\n") expectPrintedMangle(t, "a { "+x+": 1; "+x+": 2 !important }", "a {\n "+x+": 1;\n "+x+": 2 !important;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 1; "+x+"-top: 2 !important }", - "a {\n "+x+"-top: 1;\n "+x+"-top: 2 !important;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 1; "+x+"-right: 2 !important }", - "a {\n "+x+"-right: 1;\n "+x+"-right: 2 !important;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 1; "+x+"-bottom: 2 !important }", - "a {\n "+x+"-bottom: 1;\n "+x+"-bottom: 2 !important;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1; "+x+"-left: 2 !important }", - "a {\n "+x+"-left: 1;\n "+x+"-left: 2 !important;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 1; "+xTop+": 2 !important }", + "a {\n "+xTop+": 1;\n "+xTop+": 2 !important;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 1; "+xRight+": 2 !important }", + "a {\n "+xRight+": 1;\n "+xRight+": 2 !important;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 1; "+xBottom+": 2 !important }", + "a {\n "+xBottom+": 1;\n "+xBottom+": 2 !important;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1; "+xLeft+": 2 !important }", + "a {\n "+xLeft+": 1;\n "+xLeft+": 2 !important;\n}\n") expectPrintedMangle(t, "a { "+x+": 1 !important; "+x+": 2 }", "a {\n "+x+": 1 !important;\n "+x+": 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 1 !important; "+x+"-top: 2 }", - "a {\n "+x+"-top: 1 !important;\n "+x+"-top: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-right: 1 !important; "+x+"-right: 2 }", - "a {\n "+x+"-right: 1 !important;\n "+x+"-right: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-bottom: 1 !important; "+x+"-bottom: 2 }", - "a {\n "+x+"-bottom: 1 !important;\n "+x+"-bottom: 2;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1 !important; "+x+"-left: 2 }", - "a {\n "+x+"-left: 1 !important;\n "+x+"-left: 2;\n}\n") - - expectPrintedMangle(t, "a { "+x+"-top: 1; "+x+"-top: }", "a {\n "+x+"-top: 1;\n "+x+"-top:;\n}\n") - expectPrintedMangle(t, "a { "+x+"-top: 1; "+x+"-top: 2 3 }", "a {\n "+x+"-top: 1;\n "+x+"-top: 2 3;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-left: -4; "+x+"-right: -2 }", "a {\n "+x+": 1 -2 3 -4;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2; "+x+"-top: 5 }", "a {\n "+x+": 5 2 1;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1; "+x+"-top: 5 }", "a {\n "+x+": 5 1 1;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 1 !important; "+xTop+": 2 }", + "a {\n "+xTop+": 1 !important;\n "+xTop+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xRight+": 1 !important; "+xRight+": 2 }", + "a {\n "+xRight+": 1 !important;\n "+xRight+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xBottom+": 1 !important; "+xBottom+": 2 }", + "a {\n "+xBottom+": 1 !important;\n "+xBottom+": 2;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1 !important; "+xLeft+": 2 }", + "a {\n "+xLeft+": 1 !important;\n "+xLeft+": 2;\n}\n") + + expectPrintedMangle(t, "a { "+xTop+": 1; "+xTop+": }", "a {\n "+xTop+": 1;\n "+xTop+":;\n}\n") + expectPrintedMangle(t, "a { "+xTop+": 1; "+xTop+": 2 3 }", "a {\n "+xTop+": 1;\n "+xTop+": 2 3;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xLeft+": -4; "+xRight+": -2 }", "a {\n "+x+": 1 -2 3 -4;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2; "+xTop+": 5 }", "a {\n "+x+": 5 2 1;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1; "+xTop+": 5 }", "a {\n "+x+": 5 1 1;\n}\n") // This doesn't collapse because if the "calc" has an error it // will be ignored and the original rule will show through - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-right: calc(1 + var(--x)) }", "a {\n "+x+": 1 2 3 4;\n "+x+"-right: calc(1 + var(--x));\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xRight+": calc(1 + var(--x)) }", "a {\n "+x+": 1 2 3 4;\n "+xRight+": calc(1 + var(--x));\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1; "+x+"-right: 2; "+x+"-top: 3; "+x+"-bottom: 4 }", "a {\n "+x+": 3 2 4 1;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+x+"-right: 5 !important }", - "a {\n "+x+": 1 2 3 4;\n "+x+"-right: 5 !important;\n}\n") - expectPrintedMangle(t, "a { "+x+": 1 2 3 4 !important; "+x+"-right: 5 }", - "a {\n "+x+": 1 2 3 4 !important;\n "+x+"-right: 5;\n}\n") - expectPrintedMangle(t, "a { "+x+"-left: 1 !important; "+x+"-right: 2; "+x+"-top: 3 !important; "+x+"-bottom: 4 }", - "a {\n "+x+"-left: 1 !important;\n "+x+"-right: 2;\n "+x+"-top: 3 !important;\n "+x+"-bottom: 4;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1; "+xRight+": 2; "+xTop+": 3; "+xBottom+": 4 }", "a {\n "+x+": 3 2 4 1;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4; "+xRight+": 5 !important }", + "a {\n "+x+": 1 2 3 4;\n "+xRight+": 5 !important;\n}\n") + expectPrintedMangle(t, "a { "+x+": 1 2 3 4 !important; "+xRight+": 5 }", + "a {\n "+x+": 1 2 3 4 !important;\n "+xRight+": 5;\n}\n") + expectPrintedMangle(t, "a { "+xLeft+": 1 !important; "+xRight+": 2; "+xTop+": 3 !important; "+xBottom+": 4 }", + "a {\n "+xLeft+": 1 !important;\n "+xRight+": 2;\n "+xTop+": 3 !important;\n "+xBottom+": 4;\n}\n") // This should not be changed because "--x" and "--z" could be empty expectPrintedMangle(t, "a { "+x+": var(--x) var(--y) var(--z) var(--y) }", "a {\n "+x+": var(--x) var(--y) var(--z) var(--y);\n}\n") } - // "auto" is the only keyword allowed in a quad, and only for "margin" not for "padding" + // "auto" is the only keyword allowed in a quad, and only for "margin" and "inset" not for "padding" expectPrintedMangle(t, "a { margin: 1 auto 3 4; margin-left: auto }", "a {\n margin: 1 auto 3;\n}\n") + expectPrintedMangle(t, "a { inset: 1 auto 3 4; left: auto }", "a {\n inset: 1 auto 3;\n}\n") expectPrintedMangle(t, "a { padding: 1 auto 3 4; padding-left: auto }", "a {\n padding: 1 auto 3 4;\n padding-left: auto;\n}\n") expectPrintedMangle(t, "a { margin: auto; margin-left: 1px }", "a {\n margin: auto auto auto 1px;\n}\n") + expectPrintedMangle(t, "a { inset: auto; left: 1px }", "a {\n inset: auto auto auto 1px;\n}\n") expectPrintedMangle(t, "a { padding: auto; padding-left: 1px }", "a {\n padding: auto;\n padding-left: 1px;\n}\n") expectPrintedMangle(t, "a { margin: inherit; margin-left: 1px }", "a {\n margin: inherit;\n margin-left: 1px;\n}\n") + expectPrintedMangle(t, "a { inset: inherit; left: 1px }", "a {\n inset: inherit;\n left: 1px;\n}\n") expectPrintedMangle(t, "a { padding: inherit; padding-left: 1px }", "a {\n padding: inherit;\n padding-left: 1px;\n}\n") + + expectPrintedLowerMangle(t, "a { top: 0; right: 0; bottom: 0; left: 0; }", "a {\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n") } func TestBorderRadius(t *testing.T) {