From e1a0e9b5608cb356b0a98f5060819e412e39df92 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Wed, 11 Feb 2026 01:20:22 +0000 Subject: [PATCH] [TASK] Allow whitepace parsing to be stopped at EOL The whitespace parsing includes extraction of comments to be associated with the content. There are cases where the comment is after the content, but should be associated with the preceding rather than the following. This will help achieve that. --- src/Parsing/ParserState.php | 8 +++- tests/Unit/Parsing/ParserStateTest.php | 63 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/Parsing/ParserState.php b/src/Parsing/ParserState.php index 3451fe0c..f8297d06 100644 --- a/src/Parsing/ParserState.php +++ b/src/Parsing/ParserState.php @@ -201,12 +201,16 @@ 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. */ - public function consumeWhiteSpace(array &$comments = []): string + public function consumeWhiteSpace(array &$comments = [], bool $stopAfterLineFeed = false): string { $consumed = ''; do { while (preg_match('/\\s/isSu', $this->peek()) === 1) { - $consumed .= $this->consume(1); + $characterComsumed = $this->consume(1); + $consumed .= $characterComsumed; + if ($stopAfterLineFeed && $characterComsumed === "\n") { + break 2; + } } if ($this->parserSettings->usesLenientParsing()) { try { diff --git a/tests/Unit/Parsing/ParserStateTest.php b/tests/Unit/Parsing/ParserStateTest.php index ebc3c7fa..0ffaa9a9 100644 --- a/tests/Unit/Parsing/ParserStateTest.php +++ b/tests/Unit/Parsing/ParserStateTest.php @@ -303,4 +303,67 @@ public function consumeWhiteSpaceStopsAtNonWhitespace(string $nonWhitespace, str self::assertTrue($subject->comes($nonWhitespace)); } + + /** + * @return array + */ + public static function providePossibleWhitespaceWithoutLineFeedPossiblyIncludingComments(): array + { + return [ + 'nothing' => [''], + 'space' => [' '], + 'tab' => ["\t"], + 'carriage return' => ["\r"], // inclusion of this is debatable, but Mac line endings are not generally seen + 'two spaces' => [' '], + 'comment' => ['/* Time for bed */'], + 'comment with spacing around' => [' /* I am so tired */ '], + ]; + } + + /** + * @return DataProvider + */ + public function providePossibleWhitespaceWithoutLineFeedPossiblyIncludingCommentsAndTheSameAgain(): DataProvider + { + return DataProvider::cross( + self::providePossibleWhitespaceWithoutLineFeedPossiblyIncludingComments(), + self::providePossibleWhitespaceWithoutLineFeedPossiblyIncludingComments() + ); + } + + /** + * @test + * + * @dataProvider providePossibleWhitespaceWithoutLineFeedPossiblyIncludingCommentsAndTheSameAgain + */ + public function consumeWhiteSpaceStopsAfterLineFeedWhenRequested(string $firstLine, string $secondLine): void + { + $subject = new ParserState($firstLine . "\n" . $secondLine, Settings::create()); + + $comments = []; + $subject->consumeWhiteSpace($comments, true); + + if ($secondLine === '') { + self::assertTrue($subject->isEnd()); + } else { + self::assertTrue($subject->comes($secondLine)); + } + } + + /** + * @test + * + * @dataProvider providePossibleWhitespaceWithoutLineFeedPossiblyIncludingCommentsAndTheSameAgain + */ + public function consumeWhiteSpaceDoesNotStopAfterLineFeedWhenNotRequested( + string $firstLine, + string $secondLine + ): void { + $subject = new ParserState($firstLine . "\n" . $secondLine, Settings::create()); + + $comments = []; + $subject->consumeWhiteSpace($comments, false); + + self::assertTrue($subject->isEnd()); + } }