Skip to content

Commit df8a948

Browse files
committed
[BUGFIX] Parse comment(s) immediately preceding selector - part 2
1 parent c7fb009 commit df8a948

3 files changed

Lines changed: 16 additions & 7 deletions

File tree

src/CSSList/CSSList.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,15 @@ public static function parseList(ParserState $parserState, CSSList $list): void
7272
$listItem = null;
7373
if ($usesLenientParsing) {
7474
try {
75+
$positionBeforeParse = $parserState->currentColumn();
7576
$listItem = self::parseListItem($parserState, $list);
7677
} catch (UnexpectedTokenException $e) {
7778
$listItem = false;
79+
// If the failed parsing did not consume anything ...
80+
if ($parserState->currentColumn() === $positionBeforeParse) {
81+
// ... the unexpected token needs to be skipped, otherwise there'll be an infinite loop.
82+
$parserState->consume(1);
83+
}
7884
}
7985
} else {
8086
$listItem = self::parseListItem($parserState, $list);

src/RuleSet/DeclarationBlock.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
7575
} catch (UnexpectedTokenException $e) {
7676
if ($parserState->getSettings()->usesLenientParsing()) {
7777
if (!$parserState->consumeIfComes('}')) {
78-
$parserState->consumeUntil('}', false, true);
78+
$parserState->consumeUntil(['}', ParserState::EOF], false, true);
7979
}
8080
return null;
8181
} else {
@@ -307,7 +307,6 @@ private static function parseSelector(ParserState $parserState, array &$comments
307307
static $stopCharacters = ['{', '}', '\'', '"', '(', ')', ','];
308308

309309
while (true) {
310-
$selectorParts[] = $parserState->consume(1);
311310
$selectorParts[] = $parserState->consumeUntil($stopCharacters, false, false, $comments);
312311
$nextCharacter = $parserState->peek();
313312
switch ($nextCharacter) {
@@ -348,12 +347,18 @@ private static function parseSelector(ParserState $parserState, array &$comments
348347
}
349348
break;
350349
}
350+
$selectorParts[] = $parserState->consume(1);
351351
}
352352

353353
if ($functionNestingLevel !== 0) {
354354
throw new UnexpectedTokenException(')', $nextCharacter);
355355
}
356356

357-
return \implode('', $selectorParts);
357+
$selector = \implode('', $selectorParts);
358+
if ($selector === '') {
359+
throw new UnexpectedTokenException('selector', $nextCharacter, 'literal', $parserState->currentLine());
360+
}
361+
362+
return $selector;
358363
}
359364
}

tests/Unit/RuleSet/DeclarationBlockTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,9 @@ public function parsesTwoCommaSeparatedSelectors(string $firstSelector, string $
163163
*/
164164
public static function provideInvalidSelector(): array
165165
{
166-
// TODO: the `parse` method consumes the first character without inspection,
167-
// so the 'lone' test strings are prefixed with a space.
168166
return [
169-
'lone `(`' => [' ('],
170-
'lone `)`' => [' )'],
167+
'lone `(`' => ['('],
168+
'lone `)`' => [')'],
171169
'unclosed `(`' => [':not(#your-mug'],
172170
'extra `)`' => [':not(#your-mug))'],
173171
];

0 commit comments

Comments
 (0)