diff --git a/crates/swc_css_codegen/src/lib.rs b/crates/swc_css_codegen/src/lib.rs index 59668b246a6..4c7941ad180 100644 --- a/crates/swc_css_codegen/src/lib.rs +++ b/crates/swc_css_codegen/src/lib.rs @@ -703,7 +703,11 @@ where for (idx, node) in iter.enumerate() { emit!(self, node); - if idx != len - 1 { + let is_current_preserved_token = matches!(node, ComponentValue::PreservedToken(_)); + let next = nodes.get(idx + 1); + let is_next_preserved_token = matches!(next, Some(ComponentValue::PreservedToken(_))); + + if idx != len - 1 && !is_current_preserved_token && !is_next_preserved_token { let need_delim = match node { ComponentValue::SimpleBlock(_) | ComponentValue::Function(_) @@ -711,14 +715,14 @@ where | ComponentValue::Delimiter(_) | ComponentValue::Str(_) | ComponentValue::Url(_) - | ComponentValue::Percentage(_) => match nodes.get(idx + 1) { + | ComponentValue::Percentage(_) => match next { Some(ComponentValue::Delimiter(Delimiter { value: DelimiterValue::Comma, .. })) => false, _ => !self.config.minify, }, - ComponentValue::Ident(_) => match nodes.get(idx + 1) { + ComponentValue::Ident(_) => match next { Some(ComponentValue::SimpleBlock(_)) | Some(ComponentValue::Color(Color::HexColor(_))) | Some(ComponentValue::Str(_)) => !self.config.minify, @@ -753,7 +757,7 @@ where } _ => true, }, - _ => match nodes.get(idx + 1) { + _ => match next { Some(ComponentValue::SimpleBlock(_)) | Some(ComponentValue::Color(Color::HexColor(_))) => !self.config.minify, Some(ComponentValue::Delimiter(_)) => false, diff --git a/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.css b/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.css index 34b2dcad7c9..59b212af1cf 100644 --- a/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.css +++ b/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.css @@ -1,7 +1,7 @@ .slide { width: __styled-jsx-placeholder__7px; height: __styled-jsx-placeholder__7px; -margin: 0 calc(__styled-jsx-placeholder__7vw - __styled-jsx-placeholder__7px); +margin: 0 calc(__styled-jsx-placeholder__7vw - __styled-jsx-placeholder__7px); border-radius: 7px; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.08), 0 5px 12px rgba(0, 0, 0, 0.1); transition: all 0.5s ease; diff --git a/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.min.css b/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.min.css index 0248ebbb22c..52dec94e91d 100644 --- a/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.min.css +++ b/crates/swc_css_codegen/tests/fixture/preserved-token/function/output.min.css @@ -1 +1 @@ -.slide{width:__styled-jsx-placeholder__7px;height:__styled-jsx-placeholder__7px;margin:0 calc(__styled-jsx-placeholder__7vw - __styled-jsx-placeholder__7px);border-radius:7px;box-shadow:0 10px 20px rgba(0,0,0,.08),0 5px 12px rgba(0,0,0,.1);transition:all.5s ease;cursor:pointer;overflow:hidden;background:white} +.slide{width:__styled-jsx-placeholder__7px;height:__styled-jsx-placeholder__7px;margin:0 calc(__styled-jsx-placeholder__7vw - __styled-jsx-placeholder__7px);border-radius:7px;box-shadow:0 10px 20px rgba(0,0,0,.08),0 5px 12px rgba(0,0,0,.1);transition:all.5s ease;cursor:pointer;overflow:hidden;background:white} diff --git a/crates/swc_css_codegen/tests/fixture/values/dimension/input.css b/crates/swc_css_codegen/tests/fixture/values/dimension/input.css index f932eff1fee..d3fde6fe40b 100644 --- a/crates/swc_css_codegen/tests/fixture/values/dimension/input.css +++ b/crates/swc_css_codegen/tests/fixture/values/dimension/input.css @@ -4,3 +4,7 @@ div { transition: top 1s ease-out 0.5s; text-shadow: 1px 1px 2px black, 0 0 1em red; } + +.fpp { + padding: __ident__px __ident__; +} diff --git a/crates/swc_css_codegen/tests/fixture/values/dimension/output.css b/crates/swc_css_codegen/tests/fixture/values/dimension/output.css index bb6a891c69b..60485105603 100644 --- a/crates/swc_css_codegen/tests/fixture/values/dimension/output.css +++ b/crates/swc_css_codegen/tests/fixture/values/dimension/output.css @@ -4,3 +4,6 @@ border: 1px solid black; transition: top 1s ease-out 0.5s; text-shadow: 1px 1px 2px black, 0 0 1em red; } +.fpp { +padding: __ident__px __ident__; +} diff --git a/crates/swc_css_codegen/tests/fixture/values/dimension/output.min.css b/crates/swc_css_codegen/tests/fixture/values/dimension/output.min.css index a738699fc0a..70fcd7c5e18 100644 --- a/crates/swc_css_codegen/tests/fixture/values/dimension/output.min.css +++ b/crates/swc_css_codegen/tests/fixture/values/dimension/output.min.css @@ -1 +1 @@ -div{padding:10px 10px;border:1px solid black;transition:top 1s ease-out.5s;text-shadow:1px 1px 2px black,0 0 1em red} +div{padding:10px 10px;border:1px solid black;transition:top 1s ease-out.5s;text-shadow:1px 1px 2px black,0 0 1em red}.fpp{padding:__ident__px __ident__} diff --git a/crates/swc_css_codegen/tests/fixture/values/percentage/input.css b/crates/swc_css_codegen/tests/fixture/values/percentage/input.css index c0d2087538f..b80b53725f4 100644 --- a/crates/swc_css_codegen/tests/fixture/values/percentage/input.css +++ b/crates/swc_css_codegen/tests/fixture/values/percentage/input.css @@ -53,3 +53,17 @@ div { width: 10.0e5%; width: 10.0E5%; } + +.geist-list { + display: flex; + flex-wrap: wrap; + margin: __ident__; + box-sizing: border-box; +} + +.geist-list :global(> .geist-list-item) { + padding: __ident__; + flex-grow: 0; + flex-basis: __ident__%; + min-width: 0; +} diff --git a/crates/swc_css_codegen/tests/fixture/values/percentage/output.css b/crates/swc_css_codegen/tests/fixture/values/percentage/output.css index 38f528fd716..59532989b9e 100644 --- a/crates/swc_css_codegen/tests/fixture/values/percentage/output.css +++ b/crates/swc_css_codegen/tests/fixture/values/percentage/output.css @@ -47,3 +47,15 @@ width: 10.0e2%; width: 10.0e5%; width: 10.0E5%; } +.geist-list { +display: flex; +flex-wrap: wrap; +margin: __ident__; +box-sizing: border-box; +} +.geist-list :global(> .geist-list-item) { +padding: __ident__; +flex-grow: 0; +flex-basis: __ident__%; +min-width: 0; +} diff --git a/crates/swc_css_codegen/tests/fixture/values/percentage/output.min.css b/crates/swc_css_codegen/tests/fixture/values/percentage/output.min.css index 48c9477cecd..974233b9938 100644 --- a/crates/swc_css_codegen/tests/fixture/values/percentage/output.min.css +++ b/crates/swc_css_codegen/tests/fixture/values/percentage/output.min.css @@ -1 +1 @@ -div{padding:100%20%;margin:100%20px;background-position:50%50%,calc(50% + 20px)calc(50% + 20px);margin:20px 100%}div{background:image-set(url("image.png")1x)100%;background:100%image-set(url("image.png")1x)}div{background:50%red}div{margin:100%20px 100%40em}div{background:rgba(0,0,0,0)image-set(url("image.png")1x)repeat scroll 0%0%}div{width:100%;width:100.01%}div{width:0%;width:.1%;width:100%;width:100.5%;width:100.1%;width:1%;width:10%;width:100%;width:1%;width:1e-4%;width:1e3%;width:1200%;width:0%;width:-0%;width:0%;width:0%;width:10.5%;width:10.5%;width:10%;width:0%;width:-0%;width:1e3%;width:1e6%;width:1e6%} +div{padding:100%20%;margin:100%20px;background-position:50%50%,calc(50% + 20px)calc(50% + 20px);margin:20px 100%}div{background:image-set(url("image.png")1x)100%;background:100%image-set(url("image.png")1x)}div{background:50%red}div{margin:100%20px 100%40em}div{background:rgba(0,0,0,0)image-set(url("image.png")1x)repeat scroll 0%0%}div{width:100%;width:100.01%}div{width:0%;width:.1%;width:100%;width:100.5%;width:100.1%;width:1%;width:10%;width:100%;width:1%;width:1e-4%;width:1e3%;width:1200%;width:0%;width:-0%;width:0%;width:0%;width:10.5%;width:10.5%;width:10%;width:0%;width:-0%;width:1e3%;width:1e6%;width:1e6%}.geist-list{display:flex;flex-wrap:wrap;margin:__ident__;box-sizing:border-box}.geist-list :global(> .geist-list-item){padding:__ident__;flex-grow:0;flex-basis:__ident__%;min-width:0} diff --git a/crates/swc_css_codegen/tests/fixture/values/url/1/input.css b/crates/swc_css_codegen/tests/fixture/values/url/1/input.css index 3409622ae81..a01c4913e9e 100644 --- a/crates/swc_css_codegen/tests/fixture/values/url/1/input.css +++ b/crates/swc_css_codegen/tests/fixture/values/url/1/input.css @@ -59,3 +59,7 @@ div { .baz { background: url("http://example.com/image.svg" param(--color var(--primary-color))); } + +.foo { + background: url(__ident__); +} diff --git a/crates/swc_css_codegen/tests/fixture/values/url/1/output.css b/crates/swc_css_codegen/tests/fixture/values/url/1/output.css index 6be0052b7a4..07042cf071c 100644 --- a/crates/swc_css_codegen/tests/fixture/values/url/1/output.css +++ b/crates/swc_css_codegen/tests/fixture/values/url/1/output.css @@ -50,3 +50,6 @@ background: url(http://example.com/image.svg param(--color var(--primary-color); .baz { background: url("http://example.com/image.svg" param(--color var(--primary-color))); } +.foo { +background: url(__ident__); +} diff --git a/crates/swc_css_codegen/tests/fixture/values/url/1/output.min.css b/crates/swc_css_codegen/tests/fixture/values/url/1/output.min.css index 6fc82f5b650..7d16e6595f4 100644 --- a/crates/swc_css_codegen/tests/fixture/values/url/1/output.min.css +++ b/crates/swc_css_codegen/tests/fixture/values/url/1/output.min.css @@ -1 +1 @@ -div{background:url(https://example.com/image.png);background:URL(https://example.com/image.png);background:\URL(https://example.com/image.png);background:url("https://example.com/image.png");background:url("https://example.com/image.png");background:URL("https://example.com/image.png");background:\URL("https://example.com/image.png");background:url(data:image/png;base64,iRxVB0);background:url(#IDofSVGpath);background:url("//aa.com/img.svg"prefetch);background:url("//aa.com/img.svg"foo bar baz func(test));background:url("http://example.com/image.svg"param(--color var(--primary-color)));background:url();background:url("");background:url("");--foo:"http://www.example.com/pinkish.gif";background:src("http://www.example.com/pinkish.gif");background:SRC("http://www.example.com/pinkish.gif");background:src(var(--foo));background:url(https://example.com/image.png);background:u\rl(https://example.com/image.png);background:url(https://example.com/image.png);background:url(https://example.com/image.png);background:url(image.png힙)}div{background:url(foo.img)red}*{background:url("foo");background:url("f o");background:url("f o");background:url("foo)");background:url("(foo");background:url("(foo)");background:url('"foo"')}.bar{background:url(http://example.com/image.svg param(--color var(--primary-color);))}.baz{background:url("http://example.com/image.svg"param(--color var(--primary-color)))} +div{background:url(https://example.com/image.png);background:URL(https://example.com/image.png);background:\URL(https://example.com/image.png);background:url("https://example.com/image.png");background:url("https://example.com/image.png");background:URL("https://example.com/image.png");background:\URL("https://example.com/image.png");background:url(data:image/png;base64,iRxVB0);background:url(#IDofSVGpath);background:url("//aa.com/img.svg"prefetch);background:url("//aa.com/img.svg"foo bar baz func(test));background:url("http://example.com/image.svg"param(--color var(--primary-color)));background:url();background:url("");background:url("");--foo:"http://www.example.com/pinkish.gif";background:src("http://www.example.com/pinkish.gif");background:SRC("http://www.example.com/pinkish.gif");background:src(var(--foo));background:url(https://example.com/image.png);background:u\rl(https://example.com/image.png);background:url(https://example.com/image.png);background:url(https://example.com/image.png);background:url(image.png힙)}div{background:url(foo.img)red}*{background:url("foo");background:url("f o");background:url("f o");background:url("foo)");background:url("(foo");background:url("(foo)");background:url('"foo"')}.bar{background:url(http://example.com/image.svg param(--color var(--primary-color);))}.baz{background:url("http://example.com/image.svg"param(--color var(--primary-color)))}.foo{background:url(__ident__)} diff --git a/crates/swc_css_parser/tests/recovery/vercel/003/input.css b/crates/swc_css_parser/tests/recovery/vercel/003/input.css new file mode 100644 index 00000000000..914bac07e44 --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/vercel/003/input.css @@ -0,0 +1,12 @@ +.geist-list { + display: flex; + flex-wrap: wrap; + margin: __ident__; + box-sizing: border-box; +} +.geist-list :global(> .geist-list-item) { + padding: __ident__; + flex-grow: 0; + flex-basis: __ident__%; + min-width: 0; +} diff --git a/crates/swc_css_parser/tests/recovery/vercel/003/output.json b/crates/swc_css_parser/tests/recovery/vercel/003/output.json new file mode 100644 index 00000000000..8b32b6aac7a --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/vercel/003/output.json @@ -0,0 +1,503 @@ +{ + "type": "Stylesheet", + "span": { + "start": 0, + "end": 239, + "ctxt": 0 + }, + "rules": [ + { + "type": "QualifiedRule", + "span": { + "start": 0, + "end": 106, + "ctxt": 0 + }, + "prelude": { + "type": "SelectorList", + "span": { + "start": 0, + "end": 11, + "ctxt": 0 + }, + "children": [ + { + "type": "ComplexSelector", + "span": { + "start": 0, + "end": 11, + "ctxt": 0 + }, + "children": [ + { + "type": "CompoundSelector", + "span": { + "start": 0, + "end": 11, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "ClassSelector", + "span": { + "start": 0, + "end": 11, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 1, + "end": 11, + "ctxt": 0 + }, + "value": "geist-list", + "raw": "geist-list" + } + } + ] + } + ] + } + ] + }, + "block": { + "type": "SimpleBlock", + "span": { + "start": 12, + "end": 106, + "ctxt": 0 + }, + "name": "{", + "value": [ + { + "type": "Declaration", + "span": { + "start": 18, + "end": 31, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 18, + "end": 25, + "ctxt": 0 + }, + "value": "display", + "raw": "display" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 27, + "end": 31, + "ctxt": 0 + }, + "value": "flex", + "raw": "flex" + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 37, + "end": 52, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 37, + "end": 46, + "ctxt": 0 + }, + "value": "flex-wrap", + "raw": "flex-wrap" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 48, + "end": 52, + "ctxt": 0 + }, + "value": "wrap", + "raw": "wrap" + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 58, + "end": 75, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 58, + "end": 64, + "ctxt": 0 + }, + "value": "margin", + "raw": "margin" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 66, + "end": 75, + "ctxt": 0 + }, + "value": "__ident__", + "raw": "__ident__" + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 81, + "end": 103, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 81, + "end": 91, + "ctxt": 0 + }, + "value": "box-sizing", + "raw": "box-sizing" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 93, + "end": 103, + "ctxt": 0 + }, + "value": "border-box", + "raw": "border-box" + } + ], + "important": null + } + ] + } + }, + { + "type": "QualifiedRule", + "span": { + "start": 107, + "end": 238, + "ctxt": 0 + }, + "prelude": { + "type": "SelectorList", + "span": { + "start": 107, + "end": 146, + "ctxt": 0 + }, + "children": [ + { + "type": "ComplexSelector", + "span": { + "start": 107, + "end": 146, + "ctxt": 0 + }, + "children": [ + { + "type": "CompoundSelector", + "span": { + "start": 107, + "end": 118, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "ClassSelector", + "span": { + "start": 107, + "end": 118, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 108, + "end": 118, + "ctxt": 0 + }, + "value": "geist-list", + "raw": "geist-list" + } + } + ] + }, + { + "type": "Combinator", + "span": { + "start": 118, + "end": 119, + "ctxt": 0 + }, + "value": " " + }, + { + "type": "CompoundSelector", + "span": { + "start": 119, + "end": 146, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "PseudoClassSelector", + "span": { + "start": 119, + "end": 146, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 120, + "end": 126, + "ctxt": 0 + }, + "value": "global", + "raw": "global" + }, + "children": [ + { + "type": "PreservedToken", + "span": { + "start": 127, + "end": 128, + "ctxt": 0 + }, + "token": { + "Delim": { + "value": ">" + } + } + }, + { + "type": "PreservedToken", + "span": { + "start": 128, + "end": 129, + "ctxt": 0 + }, + "token": { + "WhiteSpace": { + "value": " " + } + } + }, + { + "type": "PreservedToken", + "span": { + "start": 129, + "end": 130, + "ctxt": 0 + }, + "token": { + "Delim": { + "value": "." + } + } + }, + { + "type": "PreservedToken", + "span": { + "start": 130, + "end": 145, + "ctxt": 0 + }, + "token": { + "Ident": { + "value": "geist-list-item", + "raw": "geist-list-item" + } + } + } + ] + } + ] + } + ] + } + ] + }, + "block": { + "type": "SimpleBlock", + "span": { + "start": 147, + "end": 238, + "ctxt": 0 + }, + "name": "{", + "value": [ + { + "type": "Declaration", + "span": { + "start": 153, + "end": 171, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 153, + "end": 160, + "ctxt": 0 + }, + "value": "padding", + "raw": "padding" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 162, + "end": 171, + "ctxt": 0 + }, + "value": "__ident__", + "raw": "__ident__" + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 177, + "end": 189, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 177, + "end": 186, + "ctxt": 0 + }, + "value": "flex-grow", + "raw": "flex-grow" + }, + "value": [ + { + "type": "Integer", + "span": { + "start": 188, + "end": 189, + "ctxt": 0 + }, + "value": 0, + "raw": "0" + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 195, + "end": 217, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 195, + "end": 205, + "ctxt": 0 + }, + "value": "flex-basis", + "raw": "flex-basis" + }, + "value": [ + { + "type": "Ident", + "span": { + "start": 207, + "end": 216, + "ctxt": 0 + }, + "value": "__ident__", + "raw": "__ident__" + }, + { + "type": "PreservedToken", + "span": { + "start": 216, + "end": 217, + "ctxt": 0 + }, + "token": { + "Delim": { + "value": "%" + } + } + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 223, + "end": 235, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 223, + "end": 232, + "ctxt": 0 + }, + "value": "min-width", + "raw": "min-width" + }, + "value": [ + { + "type": "Integer", + "span": { + "start": 234, + "end": 235, + "ctxt": 0 + }, + "value": 0, + "raw": "0" + } + ], + "important": null + } + ] + } + } + ] +} diff --git a/crates/swc_css_parser/tests/recovery/vercel/003/output.swc-stderr b/crates/swc_css_parser/tests/recovery/vercel/003/output.swc-stderr new file mode 100644 index 00000000000..92c659569ed --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/vercel/003/output.swc-stderr @@ -0,0 +1,6 @@ +error: Expected Declaration value + --> $DIR/tests/recovery/vercel/003/input.css:10:26 + | +10 | flex-basis: __ident__%; + | ^ +