diff --git a/crates/oxc_transformer/src/plugins/styled_components.rs b/crates/oxc_transformer/src/plugins/styled_components.rs index bb76ac3cfb953..90bee5c40122e 100644 --- a/crates/oxc_transformer/src/plugins/styled_components.rs +++ b/crates/oxc_transformer/src/plugins/styled_components.rs @@ -1061,7 +1061,16 @@ fn minify_template_literal<'a>(lit: &mut TemplateLiteral<'a>, ast: AstBuilder<'a } // Skip and compress whitespace. _ if cur_byte.is_ascii_whitespace() => { - i += 1; + // Consume any following whitespace + let mut next_byte; + loop { + i += 1; + next_byte = bytes.get(i); + if next_byte.is_none_or(|&b| !b.is_ascii_whitespace()) { + break; + } + } + // Decide whether to preserve this whitespace character. // CSS allows removing spaces around certain delimiters without changing meaning: // - `color: red` -> `color:red` (spaces around colons) @@ -1085,7 +1094,7 @@ fn minify_template_literal<'a>(lit: &mut TemplateLiteral<'a>, ast: AstBuilder<'a // are significant in CSS. ` :hover` (descendant pseudo-selector) is different // from `:hover` (direct pseudo-selector). Example: `.parent :hover` selects any // hovered descendant, while `.parent:hover` selects the parent when hovered. - && bytes.get(i).is_none_or(|&next| !matches!(next, b'{' | b'}' | b',' | b';')) + && next_byte.is_none_or(|&next| !matches!(next, b'{' | b'}' | b',' | b';')) { // Preserve this space character. // Examples: diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 0eeec2fe5cb77..94c6c09a414d6 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 41d96516 -Passed: 183/306 +Passed: 184/307 # All Passed: * babel-plugin-transform-class-static-block @@ -1612,7 +1612,7 @@ after transform: ["Function", "babelHelpers"] rebuilt : ["babelHelpers", "dec"] -# plugin-styled-components (21/36) +# plugin-styled-components (22/37) * styled-components/add-identifier-with-top-level-import-paths/input.js x Output mismatch diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/input.js b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/input.js new file mode 100644 index 0000000000000..02652ca2f135b --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/input.js @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +const A = styled.div` + .a { } + .b { } + .c + { + } +`; + +const B = styled.div` + str: "x y"; +`; diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/options.json b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/options.json new file mode 100644 index 0000000000000..92abfec80959e --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/options.json @@ -0,0 +1,18 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "modules": false, + "targets": "defaults" + } + ] + ], + "plugins": [ + ["styled-components", { + "ssr": false, + "displayName": false, + "transpileTemplateLiterals": false + }] + ] +} diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/output.js b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/output.js new file mode 100644 index 0000000000000..c1e786e1e242e --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-repeated/output.js @@ -0,0 +1,3 @@ +import styled from 'styled-components'; +const A = styled.div`.a{}.b{}.c{}`; +const B = styled.div`str:"x y";`;