Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/CSSList/CSSList.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static function parseList(ParserState $parserState, CSSList $list): void
$usesLenientParsing = $parserState->getSettings()->usesLenientParsing();
$comments = [];
while (!$parserState->isEnd()) {
$comments = \array_merge($comments, $parserState->consumeWhiteSpace());
$parserState->consumeWhiteSpace($comments);
$listItem = null;
if ($usesLenientParsing) {
try {
Expand All @@ -93,7 +93,8 @@ public static function parseList(ParserState $parserState, CSSList $list): void
$listItem->addComments($comments);
$list->append($listItem);
}
$comments = $parserState->consumeWhiteSpace();
$comments = [];
$parserState->consumeWhiteSpace($comments);
}
$list->addComments($comments);
if (!$isRoot && !$usesLenientParsing) {
Expand Down
14 changes: 9 additions & 5 deletions src/Parsing/ParserState.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ public function parseCharacter(bool $isForIdentifier): ?string
}

/**
* @return list<Comment>
* Consumes whitespace and/or comments until the next non-whitespace character that isn't a slash opening a comment.
*
* @param list<Comment> $comments Any comments consumed will be appended to this array.
*
* @return string the whitespace consumed, without the comments
*
* @throws UnexpectedEOFException
* @throws UnexpectedTokenException
Expand All @@ -197,12 +201,12 @@ public function parseCharacter(bool $isForIdentifier): ?string
* This method may change the state of the object by advancing the internal position;
* it does not simply 'get' a value.
*/
Comment thread
oliverklee marked this conversation as resolved.
public function consumeWhiteSpace(): array
public function consumeWhiteSpace(array &$comments = []): string
{
$comments = [];
$consumed = '';
do {
while (preg_match('/\\s/isSu', $this->peek()) === 1) {
$this->consume(1);
$consumed .= $this->consume(1);
}
if ($this->parserSettings->usesLenientParsing()) {
try {
Expand All @@ -219,7 +223,7 @@ public function consumeWhiteSpace(): array
}
} while ($comment instanceof Comment);

return $comments;
return $consumed;
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/Rule/Rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ public function __construct(string $rule, ?int $lineNumber = null, ?int $columnN
*/
public static function parse(ParserState $parserState, array $commentsBeforeRule = []): Rule
{
$comments = \array_merge($commentsBeforeRule, $parserState->consumeWhiteSpace());
$comments = $commentsBeforeRule;
$parserState->consumeWhiteSpace($comments);
$rule = new Rule(
$parserState->parseIdentifier(!$parserState->comes('--')),
$parserState->currentLine(),
$parserState->currentColumn()
);
$parserState->consumeWhiteSpace($comments);
$rule->setComments($comments);
$rule->addComments($parserState->consumeWhiteSpace());
$parserState->consume(':');
$value = Value::parseValue($parserState, self::listDelimiterForRule($rule->getRule()));
$rule->setValue($value);
Expand Down
3 changes: 2 additions & 1 deletion src/RuleSet/RuleSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public static function parseRuleSet(ParserState $parserState, RuleSet $ruleSet):
$parserState->consume(';');
}
while (true) {
$commentsBeforeRule = $parserState->consumeWhiteSpace();
$commentsBeforeRule = [];
$parserState->consumeWhiteSpace($commentsBeforeRule);
if ($parserState->comes('}')) {
break;
}
Expand Down
146 changes: 146 additions & 0 deletions tests/Unit/Parsing/ParserStateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Sabberworm\CSS\Comment\Comment;
use Sabberworm\CSS\Parsing\ParserState;
use Sabberworm\CSS\Settings;
use TRegx\PhpUnit\DataProviders\DataProvider;

/**
* @covers \Sabberworm\CSS\Parsing\ParserState
Expand Down Expand Up @@ -157,4 +158,149 @@ public function consumeIfComesUpdatesLineNumber(): void

self::assertSame(2, $subject->currentLine());
}

/**
* @return array<non-empty-string, array{0: string, 1: string}>
*/
public static function provideContentWhichMayHaveWhitespaceOrCommentsAndExpectedConsumption(): array
{
return [
'nothing' => ['', ''],
'space' => [' ', ' '],
'tab' => ["\t", "\t"],
'line feed' => ["\n", "\n"],
'carriage return' => ["\r", "\r"],
'two spaces' => [' ', ' '],
'comment' => ['/*hello*/', ''],
'comment with space to the left' => [' /*hello*/', ' '],
'comment with space to the right' => ['/*hello*/ ', ' '],
'two comments' => ['/*hello*//*bye*/', ''],
'two comments with space between' => ['/*hello*/ /*bye*/', ' '],
'two comments with line feed between' => ["/*hello*/\n/*bye*/", "\n"],
];
}

/**
* @test
*
* @dataProvider provideContentWhichMayHaveWhitespaceOrCommentsAndExpectedConsumption
*/
public function consumeWhiteSpaceReturnsTheConsumed(
string $whitespaceMaybeWithComments,
string $expectedConsumption
): void {
$subject = new ParserState($whitespaceMaybeWithComments, Settings::create());

$result = $subject->consumeWhiteSpace();

self::assertSame($expectedConsumption, $result);
}

/**
* @test
*/
public function consumeWhiteSpaceExtractsComment(): void
{
$commentText = 'Did they get you to trade your heroes for ghosts?';
$subject = new ParserState('/*' . $commentText . '*/', Settings::create());

$result = [];
$subject->consumeWhiteSpace($result);

self::assertInstanceOf(Comment::class, $result[0]);
self::assertSame($commentText, $result[0]->getComment());
}

/**
* @test
*/
public function consumeWhiteSpaceExtractsTwoComments(): void
{
$commentText1 = 'Hot ashes for trees? Hot air for a cool breeze?';
$commentText2 = 'Cold comfort for change? Did you exchange';
$subject = new ParserState('/*' . $commentText1 . '*//*' . $commentText2 . '*/', Settings::create());

$result = [];
$subject->consumeWhiteSpace($result);

self::assertInstanceOf(Comment::class, $result[0]);
self::assertSame($commentText1, $result[0]->getComment());
self::assertInstanceOf(Comment::class, $result[1]);
self::assertSame($commentText2, $result[1]->getComment());
}

/**
* @return array<non-empty-string, array{0: non-empty-string}>
*/
public static function provideWhitespace(): array
{
return [
'space' => [' '],
'tab' => ["\t"],
'line feed' => ["\n"],
'carriage return' => ["\r"],
'two spaces' => [' '],
];
}

/**
* @test
*
* @param non-empty-string $whitespace
*
* @dataProvider provideWhitespace
*/
public function consumeWhiteSpaceExtractsCommentWithSurroundingWhitespace(string $whitespace): void
{
$commentText = 'A walk-on part in the war for a lead role in a cage?';
Comment thread
oliverklee marked this conversation as resolved.
$subject = new ParserState($whitespace . '/*' . $commentText . '*/' . $whitespace, Settings::create());

$result = [];
$subject->consumeWhiteSpace($result);

self::assertInstanceOf(Comment::class, $result[0]);
self::assertSame($commentText, $result[0]->getComment());
}

/**
* @return array<non-empty-string, array{0: non-empty-string}>
*/
public static function provideNonWhitespace(): array
{
return [
'number' => ['7'],
'uppercase letter' => ['B'],
'lowercase letter' => ['c'],
'symbol' => ['@'],
'sequence of non-whitespace characters' => ['Hello!'],
'sequence of characters including space which isn\'t first' => ['Oh no!'],
];
}

/**
* @return DataProvider<non-empty-string, array{0: non-empty-string, 1: string}>
*/
public function provideNonWhitespaceAndContentWithPossibleWhitespaceOrComments(): DataProvider
{
return DataProvider::cross(
self::provideNonWhitespace(),
self::provideContentWhichMayHaveWhitespaceOrCommentsAndExpectedConsumption()
);
}

/**
* @test
*
* @param non-empty-string $nonWhitespace
*
* @dataProvider provideNonWhitespaceAndContentWithPossibleWhitespaceOrComments
*/
public function consumeWhiteSpaceStopsAtNonWhitespace(string $nonWhitespace, string $whitespace): void
{
$subject = new ParserState($whitespace . $nonWhitespace, Settings::create());

$subject->consumeWhiteSpace();

self::assertTrue($subject->comes($nonWhitespace));
}
}