diff --git a/CHANGELOG.md b/CHANGELOG.md index 912d5dba..08dfef29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -110,6 +110,7 @@ Please also have a look at our ### Fixed +- Parse quoted attribute selector value containing comma (#1323) - Allow comma in selectors (e.g. `:not(html, body)`) (#1293) - Insert `Rule` before sibling even with different property name (in `RuleSet::addRule()`) (#1270) diff --git a/src/RuleSet/DeclarationBlock.php b/src/RuleSet/DeclarationBlock.php index bd295dd2..d0b9654c 100644 --- a/src/RuleSet/DeclarationBlock.php +++ b/src/RuleSet/DeclarationBlock.php @@ -40,13 +40,18 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ? $comments = []; $result = new DeclarationBlock($parserState->currentLine()); try { + $selectors = []; $selectorParts = []; $stringWrapperCharacter = null; - static $stopCharacters = ['{', '}', '\'', '"']; + $consumedNextCharacter = false; + static $stopCharacters = ['{', '}', '\'', '"', ',']; do { - $selectorParts[] = $parserState->consume(1) - . $parserState->consumeUntil($stopCharacters, false, false, $comments); + if (!$consumedNextCharacter) { + $selectorParts[] = $parserState->consume(1); + } + $selectorParts[] = $parserState->consumeUntil($stopCharacters, false, false, $comments); $nextCharacter = $parserState->peek(); + $consumedNextCharacter = false; switch ($nextCharacter) { case '\'': // The fallthrough is intentional. @@ -59,9 +64,18 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ? } } break; + case ',': + if (!\is_string($stringWrapperCharacter)) { + $selectors[] = \implode('', $selectorParts); + $selectorParts = []; + $parserState->consume(1); + $consumedNextCharacter = true; + } + break; } } while (!\in_array($nextCharacter, ['{', '}'], true) || \is_string($stringWrapperCharacter)); - $result->setSelectors(\implode('', $selectorParts), $list); + $selectors[] = \implode('', $selectorParts); // add final or only selector + $result->setSelectors($selectors, $list); if ($parserState->comes('{')) { $parserState->consume(1); } diff --git a/tests/Unit/RuleSet/DeclarationBlockTest.php b/tests/Unit/RuleSet/DeclarationBlockTest.php index 697b15aa..468a8515 100644 --- a/tests/Unit/RuleSet/DeclarationBlockTest.php +++ b/tests/Unit/RuleSet/DeclarationBlockTest.php @@ -68,8 +68,8 @@ public static function provideSelector(): array 'type & pseudo-class' => ['a:hover'], '`not`' => [':not(#your-mug)'], 'pseudo-element' => ['::before'], - 'attribute with `"`' => ['[alt="{}()[]\\"\'"]'], - 'attribute with `\'`' => ['[alt=\'{}()[]"\\\'\']'], + 'attribute with `"`' => ['[alt="{}()[]\\"\',"]'], + 'attribute with `\'`' => ['[alt=\'{}()[]"\\\',\']'], ]; }