diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4787d789..30778b6925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi ### Fixed - Fixed attribute parsing incorrectly parsing mustache-like syntax (#1035) +- Fixed incorrect `Table` start line numbers (#1037) ## [2.5.0] - 2024-07-22 diff --git a/src/Parser/MarkdownParser.php b/src/Parser/MarkdownParser.php index 9d684dd215..a5fea7d396 100644 --- a/src/Parser/MarkdownParser.php +++ b/src/Parser/MarkdownParser.php @@ -158,14 +158,17 @@ private function parseLine(string $line): void $unmatchedBlocks = 0; } + $oldBlockLineStart = null; if ($blockStart->isReplaceActiveBlockParser()) { - $this->prepareActiveBlockParserForReplacement(); + $oldBlockLineStart = $this->prepareActiveBlockParserForReplacement(); } foreach ($blockStart->getBlockParsers() as $newBlockParser) { - $blockParser = $this->addChild($newBlockParser); + $blockParser = $this->addChild($newBlockParser, $oldBlockLineStart); $tryBlockStarts = $newBlockParser->isContainer(); } + + unset($oldBlockLineStart); } // What remains at the offset is a text line. Add the text to the appropriate block. @@ -275,12 +278,12 @@ private function processInlines(): void * Add block of type tag as a child of the tip. If the tip can't accept children, close and finalize it and try * its parent, and so on til we find a block that can accept children. */ - private function addChild(BlockContinueParserInterface $blockParser): BlockContinueParserInterface + private function addChild(BlockContinueParserInterface $blockParser, ?int $startLineNumber = null): BlockContinueParserInterface { - $blockParser->getBlock()->setStartLine($this->lineNumber); + $blockParser->getBlock()->setStartLine($startLineNumber ?? $this->lineNumber); while (! $this->getActiveBlockParser()->canContain($blockParser->getBlock())) { - $this->closeBlockParsers(1, $this->lineNumber - 1); + $this->closeBlockParsers(1, ($startLineNumber ?? $this->lineNumber) - 1); } $this->getActiveBlockParser()->getBlock()->appendChild($blockParser->getBlock()); @@ -307,7 +310,10 @@ private function deactivateBlockParser(): BlockContinueParserInterface return $popped; } - private function prepareActiveBlockParserForReplacement(): void + /** + * @return int|null The line number where the old block started + */ + private function prepareActiveBlockParserForReplacement(): ?int { // Note that we don't want to parse inlines or finalize this block, as it's getting replaced. $old = $this->deactivateBlockParser(); @@ -317,6 +323,8 @@ private function prepareActiveBlockParserForReplacement(): void } $old->getBlock()->detach(); + + return $old->getBlock()->getStartLine(); } /** diff --git a/tests/functional/Extension/Table/TableMarkdownTest.php b/tests/functional/Extension/Table/TableMarkdownTest.php index c38ef0ce8c..ec5c00f8f6 100644 --- a/tests/functional/Extension/Table/TableMarkdownTest.php +++ b/tests/functional/Extension/Table/TableMarkdownTest.php @@ -18,8 +18,10 @@ use League\CommonMark\ConverterInterface; use League\CommonMark\Environment\Environment; use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; +use League\CommonMark\Extension\Table\Table; use League\CommonMark\Extension\Table\TableExtension; use League\CommonMark\MarkdownConverter; +use League\CommonMark\Parser\MarkdownParser; use League\CommonMark\Tests\Functional\AbstractLocalDataTestCase; /** @@ -46,4 +48,29 @@ public static function dataProvider(): iterable { yield from self::loadTests(__DIR__ . '/md'); } + + public function testStartEndLinesProperlySet(): void + { + $markdown = <<addExtension(new CommonMarkCoreExtension()); + $environment->addExtension(new TableExtension()); + + $parser = new MarkdownParser($environment); + $doc = $parser->parse($markdown); + + $table = $doc->lastChild(); + $this->assertInstanceOf(Table::class, $table); + $this->assertSame(4, $table->getStartLine()); + $this->assertSame(7, $table->getEndLine()); + } }