Skip to content

Commit c1599a4

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

File tree

4 files changed

+23
-18
lines changed

4 files changed

+23
-18
lines changed

src/CSSList/CSSList.php

Lines changed: 8 additions & 1 deletion
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);
@@ -133,7 +139,8 @@ private static function parseListItem(ParserState $parserState, CSSList $list)
133139
} elseif ($parserState->comes('}')) {
134140
if ($isRoot) {
135141
if ($parserState->getSettings()->usesLenientParsing()) {
136-
return DeclarationBlock::parse($parserState) ?? false;
142+
$parserState->consume(1);
143+
return self::parseListItem($parserState, $list);
137144
} else {
138145
throw new SourceException('Unopened {', $parserState->currentLine());
139146
}

src/RuleSet/DeclarationBlock.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
7474
}
7575
} catch (UnexpectedTokenException $e) {
7676
if ($parserState->getSettings()->usesLenientParsing()) {
77-
if (!$parserState->comes('}')) {
78-
$parserState->consumeUntil('}', false, true);
77+
if ($parserState->comes('}')) {
78+
$parserState->consume(1);
79+
} else {
80+
$parserState->consumeUntil(['}', ParserState::EOF], false, true);
7981
}
8082
return null;
8183
} else {
@@ -307,7 +309,6 @@ private static function parseSelector(ParserState $parserState, array &$comments
307309
static $stopCharacters = ['{', '}', '\'', '"', '(', ')', ','];
308310

309311
while (true) {
310-
$selectorParts[] = $parserState->consume(1);
311312
$selectorParts[] = $parserState->consumeUntil($stopCharacters, false, false, $comments);
312313
$nextCharacter = $parserState->peek();
313314
switch ($nextCharacter) {
@@ -348,12 +349,18 @@ private static function parseSelector(ParserState $parserState, array &$comments
348349
}
349350
break;
350351
}
352+
$selectorParts[] = $parserState->consume(1);
351353
}
352354

353355
if ($functionNestingLevel !== 0) {
354356
throw new UnexpectedTokenException(')', $nextCharacter);
355357
}
356358

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

tests/ParserTest.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ public function invalidSelectorsInFile(): void
718718
$document = self::parsedStructureForFile('invalid-selectors', Settings::create()->withMultibyteSupport(true));
719719
$expected = '@keyframes mymove {from {top: 0px;}}
720720
#test {color: white;background: green;}
721+
#test {display: block;background: red;color: white;}
721722
#test {display: block;background: white;color: black;}';
722723
self::assertSame($expected, $document->render());
723724

@@ -727,6 +728,7 @@ public function invalidSelectorsInFile(): void
727728
.super-menu > li:last-of-type {border-right-width: 0;}
728729
html[dir="rtl"] .super-menu > li:first-of-type {border-left-width: 1px;border-right-width: 0;}
729730
html[dir="rtl"] .super-menu > li:last-of-type {border-left-width: 0;}}
731+
.super-menu.menu-floated {border-right-width: 1px;border-left-width: 1px;border-color: #5a4242;border-style: dotted;}
730732
body {background-color: red;}';
731733
self::assertSame($expected, $document->render());
732734
}
@@ -740,15 +742,6 @@ public function selectorEscapesInFile(): void
740742
$expected = '#\\# {color: red;}
741743
.col-sm-1\\/5 {width: 20%;}';
742744
self::assertSame($expected, $document->render());
743-
744-
$document = self::parsedStructureForFile('invalid-selectors-2', Settings::create()->withMultibyteSupport(true));
745-
$expected = '@media only screen and (max-width: 1215px) {.breadcrumb {padding-left: 10px;}
746-
.super-menu > li:first-of-type {border-left-width: 0;}
747-
.super-menu > li:last-of-type {border-right-width: 0;}
748-
html[dir="rtl"] .super-menu > li:first-of-type {border-left-width: 1px;border-right-width: 0;}
749-
html[dir="rtl"] .super-menu > li:last-of-type {border-left-width: 0;}}
750-
body {background-color: red;}';
751-
self::assertSame($expected, $document->render());
752745
}
753746

754747
/**

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)