From 2405dc6ba0aa227df81fda3db303fc6f523972db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Tue, 7 May 2024 17:43:41 +0900 Subject: [PATCH] fix(css/modules): Fix `:global` selectors without preceding whitespace (#8926) **Related issue:** - Closes #8461 --- crates/swc_css_modules/src/lib.rs | 5 +- .../tests/fixture/issue-8179.compiled.css | 2 +- .../fixture/issue-8461/1/input.compiled.css | 1 + .../tests/fixture/issue-8461/1/input.css | 1 + .../fixture/issue-8461/1/input.transform.json | 14 ++ .../fixture/issue-8461/2/input.compiled.css | 1 + .../tests/fixture/issue-8461/2/input.css | 1 + .../fixture/issue-8461/2/input.transform.json | 14 ++ .../tests/fixture/issue-8461/1/input.css | 1 + .../issue-8461/1/leading-comments.json | 1 + .../tests/fixture/issue-8461/1/output.json | 151 +++++++++++++++ .../fixture/issue-8461/1/span.swc-stderr | 126 +++++++++++++ .../issue-8461/1/trailing-comments.json | 1 + .../tests/fixture/issue-8461/2/input.css | 1 + .../issue-8461/2/leading-comments.json | 1 + .../tests/fixture/issue-8461/2/output.json | 172 ++++++++++++++++++ .../fixture/issue-8461/2/span.swc-stderr | 138 ++++++++++++++ .../issue-8461/2/trailing-comments.json | 1 + 18 files changed, 628 insertions(+), 4 deletions(-) create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/1/input.compiled.css create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/1/input.css create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/1/input.transform.json create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/2/input.compiled.css create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/2/input.css create mode 100644 crates/swc_css_modules/tests/fixture/issue-8461/2/input.transform.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/1/input.css create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/1/leading-comments.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/1/output.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/1/span.swc-stderr create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/1/trailing-comments.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/2/input.css create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/2/leading-comments.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/2/output.json create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/2/span.swc-stderr create mode 100644 crates/swc_css_parser/tests/fixture/issue-8461/2/trailing-comments.json diff --git a/crates/swc_css_modules/src/lib.rs b/crates/swc_css_modules/src/lib.rs index a408691839f0..8137ed799e33 100644 --- a/crates/swc_css_modules/src/lib.rs +++ b/crates/swc_css_modules/src/lib.rs @@ -704,9 +704,8 @@ fn prepend_left_subclass_selectors( { c.subclass_selectors.splice(0..0, sels.drain(..sel_index)); - if sels.len() > sel_index { - c.subclass_selectors - .extend(sels[..sel_index + 1].iter().cloned()); + if !sels.is_empty() { + c.subclass_selectors.extend(sels[..].iter().cloned()); } sel_index = 0; diff --git a/crates/swc_css_modules/tests/fixture/issue-8179.compiled.css b/crates/swc_css_modules/tests/fixture/issue-8179.compiled.css index 5a3818351770..d2b81ad524ea 100644 --- a/crates/swc_css_modules/tests/fixture/issue-8179.compiled.css +++ b/crates/swc_css_modules/tests/fixture/issue-8179.compiled.css @@ -1,3 +1,3 @@ -.__local__a.b .c.__local__d { +.__local__a.b.__local__d .c.__local__d { color: red; } diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/1/input.compiled.css b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.compiled.css new file mode 100644 index 000000000000..e5362a4744e1 --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.compiled.css @@ -0,0 +1 @@ +.__local__foo.bar.__local__baz {} diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/1/input.css b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.css new file mode 100644 index 000000000000..9cad0f225bed --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.css @@ -0,0 +1 @@ +.foo:global(.bar).baz {} \ No newline at end of file diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/1/input.transform.json b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.transform.json new file mode 100644 index 000000000000..6edada8a6266 --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/1/input.transform.json @@ -0,0 +1,14 @@ +{ + "baz": [ + { + "name": "__local__baz", + "type": "local" + } + ], + "foo": [ + { + "name": "__local__foo", + "type": "local" + } + ] +} diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/2/input.compiled.css b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.compiled.css new file mode 100644 index 000000000000..c9b849fa1aef --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.compiled.css @@ -0,0 +1 @@ +.__local__foo .bar.__local__baz {} diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/2/input.css b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.css new file mode 100644 index 000000000000..260b4df2b853 --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.css @@ -0,0 +1 @@ +.foo :global(.bar).baz {} \ No newline at end of file diff --git a/crates/swc_css_modules/tests/fixture/issue-8461/2/input.transform.json b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.transform.json new file mode 100644 index 000000000000..6edada8a6266 --- /dev/null +++ b/crates/swc_css_modules/tests/fixture/issue-8461/2/input.transform.json @@ -0,0 +1,14 @@ +{ + "baz": [ + { + "name": "__local__baz", + "type": "local" + } + ], + "foo": [ + { + "name": "__local__foo", + "type": "local" + } + ] +} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/1/input.css b/crates/swc_css_parser/tests/fixture/issue-8461/1/input.css new file mode 100644 index 000000000000..9cad0f225bed --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/1/input.css @@ -0,0 +1 @@ +.foo:global(.bar).baz {} \ No newline at end of file diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/1/leading-comments.json b/crates/swc_css_parser/tests/fixture/issue-8461/1/leading-comments.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/1/leading-comments.json @@ -0,0 +1 @@ +{} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/1/output.json b/crates/swc_css_parser/tests/fixture/issue-8461/1/output.json new file mode 100644 index 000000000000..37759deb3d1d --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/1/output.json @@ -0,0 +1,151 @@ +{ + "type": "Stylesheet", + "span": { + "start": 1, + "end": 25, + "ctxt": 0 + }, + "rules": [ + { + "type": "QualifiedRule", + "span": { + "start": 1, + "end": 25, + "ctxt": 0 + }, + "prelude": { + "type": "SelectorList", + "span": { + "start": 1, + "end": 22, + "ctxt": 0 + }, + "children": [ + { + "type": "ComplexSelector", + "span": { + "start": 1, + "end": 22, + "ctxt": 0 + }, + "children": [ + { + "type": "CompoundSelector", + "span": { + "start": 1, + "end": 22, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "ClassSelector", + "span": { + "start": 1, + "end": 5, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 2, + "end": 5, + "ctxt": 0 + }, + "value": "foo", + "raw": "foo" + } + }, + { + "type": "PseudoClassSelector", + "span": { + "start": 5, + "end": 18, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 6, + "end": 12, + "ctxt": 0 + }, + "value": "global", + "raw": "global" + }, + "children": [ + { + "type": "PreservedToken", + "span": { + "start": 13, + "end": 14, + "ctxt": 0 + }, + "token": { + "Delim": { + "value": "." + } + } + }, + { + "type": "PreservedToken", + "span": { + "start": 14, + "end": 17, + "ctxt": 0 + }, + "token": { + "Ident": { + "value": "bar", + "raw": "bar" + } + } + } + ] + }, + { + "type": "ClassSelector", + "span": { + "start": 18, + "end": 22, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 19, + "end": 22, + "ctxt": 0 + }, + "value": "baz", + "raw": "baz" + } + } + ] + } + ] + } + ] + }, + "block": { + "type": "SimpleBlock", + "span": { + "start": 23, + "end": 25, + "ctxt": 0 + }, + "name": { + "type": "PreservedToken", + "span": { + "start": 23, + "end": 24, + "ctxt": 0 + }, + "token": "LBrace" + }, + "value": [] + } + } + ] +} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/1/span.swc-stderr b/crates/swc_css_parser/tests/fixture/issue-8461/1/span.swc-stderr new file mode 100644 index 000000000000..87c0aa960b0a --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/1/span.swc-stderr @@ -0,0 +1,126 @@ + + x Stylesheet + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Rule + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x QualifiedRule + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x SelectorList + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^ + `---- + + x ComplexSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^ + `---- + + x CompoundSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^ + `---- + + x ClassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^ + `---- + + x PseudoClassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^^^^^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^^^ + `---- + + x PseudoClassSelectorChildren + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^ + `---- + + x Delim { value: '.' } + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^ + `---- + + x PseudoClassSelectorChildren + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^ + `---- + + x Ident { value: "bar", raw: "bar" } + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^ + `---- + + x ClassSelector + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^^ + `---- + + x SimpleBlock + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^^ + `---- + + x LBrace + ,-[$DIR/tests/fixture/issue-8461/1/input.css:1:1] + 1 | .foo:global(.bar).baz {} + : ^ + `---- diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/1/trailing-comments.json b/crates/swc_css_parser/tests/fixture/issue-8461/1/trailing-comments.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/1/trailing-comments.json @@ -0,0 +1 @@ +{} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/2/input.css b/crates/swc_css_parser/tests/fixture/issue-8461/2/input.css new file mode 100644 index 000000000000..260b4df2b853 --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/2/input.css @@ -0,0 +1 @@ +.foo :global(.bar).baz {} \ No newline at end of file diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/2/leading-comments.json b/crates/swc_css_parser/tests/fixture/issue-8461/2/leading-comments.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/2/leading-comments.json @@ -0,0 +1 @@ +{} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/2/output.json b/crates/swc_css_parser/tests/fixture/issue-8461/2/output.json new file mode 100644 index 000000000000..f7aa4948c8ff --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/2/output.json @@ -0,0 +1,172 @@ +{ + "type": "Stylesheet", + "span": { + "start": 1, + "end": 26, + "ctxt": 0 + }, + "rules": [ + { + "type": "QualifiedRule", + "span": { + "start": 1, + "end": 26, + "ctxt": 0 + }, + "prelude": { + "type": "SelectorList", + "span": { + "start": 1, + "end": 23, + "ctxt": 0 + }, + "children": [ + { + "type": "ComplexSelector", + "span": { + "start": 1, + "end": 23, + "ctxt": 0 + }, + "children": [ + { + "type": "CompoundSelector", + "span": { + "start": 1, + "end": 5, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "ClassSelector", + "span": { + "start": 1, + "end": 5, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 2, + "end": 5, + "ctxt": 0 + }, + "value": "foo", + "raw": "foo" + } + } + ] + }, + { + "type": "Combinator", + "span": { + "start": 5, + "end": 6, + "ctxt": 0 + }, + "value": " " + }, + { + "type": "CompoundSelector", + "span": { + "start": 6, + "end": 23, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "PseudoClassSelector", + "span": { + "start": 6, + "end": 19, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 7, + "end": 13, + "ctxt": 0 + }, + "value": "global", + "raw": "global" + }, + "children": [ + { + "type": "PreservedToken", + "span": { + "start": 14, + "end": 15, + "ctxt": 0 + }, + "token": { + "Delim": { + "value": "." + } + } + }, + { + "type": "PreservedToken", + "span": { + "start": 15, + "end": 18, + "ctxt": 0 + }, + "token": { + "Ident": { + "value": "bar", + "raw": "bar" + } + } + } + ] + }, + { + "type": "ClassSelector", + "span": { + "start": 19, + "end": 23, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 20, + "end": 23, + "ctxt": 0 + }, + "value": "baz", + "raw": "baz" + } + } + ] + } + ] + } + ] + }, + "block": { + "type": "SimpleBlock", + "span": { + "start": 24, + "end": 26, + "ctxt": 0 + }, + "name": { + "type": "PreservedToken", + "span": { + "start": 24, + "end": 25, + "ctxt": 0 + }, + "token": "LBrace" + }, + "value": [] + } + } + ] +} diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/2/span.swc-stderr b/crates/swc_css_parser/tests/fixture/issue-8461/2/span.swc-stderr new file mode 100644 index 000000000000..13e0ca50cc10 --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/2/span.swc-stderr @@ -0,0 +1,138 @@ + + x Stylesheet + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Rule + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x QualifiedRule + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x SelectorList + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x ComplexSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x CompoundSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^ + `---- + + x ClassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^ + `---- + + x Combinator + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^ + `---- + + x CompoundSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^^^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^ + `---- + + x PseudoClassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^^^^^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^^^ + `---- + + x PseudoClassSelectorChildren + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^ + `---- + + x Delim { value: '.' } + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^ + `---- + + x PseudoClassSelectorChildren + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^ + `---- + + x Ident { value: "bar", raw: "bar" } + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^ + `---- + + x SubclassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^ + `---- + + x ClassSelector + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^^ + `---- + + x Ident + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^^ + `---- + + x SimpleBlock + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^^ + `---- + + x LBrace + ,-[$DIR/tests/fixture/issue-8461/2/input.css:1:1] + 1 | .foo :global(.bar).baz {} + : ^ + `---- diff --git a/crates/swc_css_parser/tests/fixture/issue-8461/2/trailing-comments.json b/crates/swc_css_parser/tests/fixture/issue-8461/2/trailing-comments.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/crates/swc_css_parser/tests/fixture/issue-8461/2/trailing-comments.json @@ -0,0 +1 @@ +{}