Skip to content

Commit c7fb009

Browse files
authored
[BUGFIX] Skip erroneous } when parsing CSSList (#1426)
This allows parsing of the next item, if valid, rather than dropping it.
1 parent dada8f8 commit c7fb009

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Please also have a look at our
2424

2525
### Fixed
2626

27-
- Improve recovery parsing when a rogue `}` is encountered (#1425)
27+
- Improve recovery parsing when a rogue `}` is encountered (#1425, #1426)
2828
- Parse comment(s) immediately preceding a selector (#1421)
2929
- Parse consecutive comments (#1421)
3030
- Support attribute selectors with values containing commas in

src/CSSList/CSSList.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ private static function parseListItem(ParserState $parserState, CSSList $list)
133133
} elseif ($parserState->comes('}')) {
134134
if ($isRoot) {
135135
if ($parserState->getSettings()->usesLenientParsing()) {
136-
return DeclarationBlock::parse($parserState) ?? false;
136+
$parserState->consume(1);
137+
return self::parseListItem($parserState, $list);
137138
} else {
138139
throw new SourceException('Unopened {', $parserState->currentLine());
139140
}

tests/Unit/CSSList/CSSListTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@
77
use PHPUnit\Framework\TestCase;
88
use Sabberworm\CSS\Comment\Commentable;
99
use Sabberworm\CSS\CSSElement;
10+
use Sabberworm\CSS\CSSList\CSSList;
1011
use Sabberworm\CSS\CSSList\CSSListItem;
12+
use Sabberworm\CSS\CSSList\Document;
13+
use Sabberworm\CSS\OutputFormat;
14+
use Sabberworm\CSS\Parsing\ParserState;
1115
use Sabberworm\CSS\Property\Selector;
1216
use Sabberworm\CSS\Renderable;
1317
use Sabberworm\CSS\RuleSet\DeclarationBlock;
18+
use Sabberworm\CSS\Settings;
1419
use Sabberworm\CSS\Tests\Unit\CSSList\Fixtures\ConcreteCSSList;
1520

1621
/**
@@ -342,4 +347,37 @@ public function removeDeclarationBlockBySelectorRemovesMultipleBlocksWithStringS
342347

343348
self::assertSame([], $subject->getContents());
344349
}
350+
351+
/**
352+
* The content provided must (currently) be in the same format as the expected rendering.
353+
*
354+
* @return array<non-empty-string, array{0: non-empty-string}>
355+
*/
356+
public function provideValidContentForParsing(): array
357+
{
358+
return [
359+
'at-import rule' => ['@import url("foo.css");'],
360+
'rule with declaration block' => ['a {color: green;}'],
361+
];
362+
}
363+
364+
/**
365+
* @test
366+
*
367+
* @param non-empty-string $followingContent
368+
*
369+
* @dataProvider provideValidContentForParsing
370+
*/
371+
public function parseListAtRootLevelSkipsErroneousClosingBraceAndParsesFollowingContent(
372+
string $followingContent
373+
): void {
374+
$parserState = new ParserState('}' . $followingContent, Settings::create());
375+
// The subject needs to be a `Document`, as that is currently the test for 'root level'.
376+
// Otherwise `}` will be treated as 'end of list'.
377+
$subject = new Document();
378+
379+
CSSList::parseList($parserState, $subject);
380+
381+
self::assertSame($followingContent, $subject->render(new OutputFormat()));
382+
}
345383
}

0 commit comments

Comments
 (0)