Skip to content

Commit

Permalink
Merge pull request #68 from doctrine/fix-section-nesting
Browse files Browse the repository at this point in the history
Fix issue with sections not being nested properly inside of each other.
  • Loading branch information
jwage authored Nov 21, 2018
2 parents 45cb77c + e1d3842 commit f1f97e1
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 12 deletions.
43 changes: 33 additions & 10 deletions lib/Parser/DocumentParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Doctrine\RST\Nodes\TitleNode;
use Doctrine\RST\Parser;
use Doctrine\RST\Parser\Directive as ParserDirective;
use function array_search;
use function chr;
use function explode;
use function sprintf;
Expand Down Expand Up @@ -91,6 +92,9 @@ class DocumentParser
/** @var TitleNode */
private $lastTitleNode;

/** @var TitleNode[] */
private $openTitleNodes = [];

/**
* @param Directive[] $directives
*/
Expand Down Expand Up @@ -204,13 +208,9 @@ private function parseLines(string $document) : void
$this->flush();
$this->flush();

if ($this->lastTitleNode === null) {
return;
foreach ($this->openTitleNodes as $titleNode) {
$this->endOpenSection($titleNode);
}

$this->document->addNode(
$this->nodeFactory->createSectionEndNode($this->lastTitleNode)
);
}

private function parseLine(string $line) : bool
Expand Down Expand Up @@ -409,17 +409,25 @@ private function flush() : void
);

if ($this->lastTitleNode !== null) {
$this->document->addNode(
$this->nodeFactory->createSectionEndNode($this->lastTitleNode)
);
// current level is less than previous so we need to end all open sections
if ($node->getLevel() < $this->lastTitleNode->getLevel()) {
foreach ($this->openTitleNodes as $titleNode) {
$this->endOpenSection($titleNode);
}
// same level as the last so just close the last open section
} elseif ($node->getLevel() === $this->lastTitleNode->getLevel()) {
$this->endOpenSection($this->lastTitleNode);
}
}

$this->lastTitleNode = $node;

$this->document->addNode(
$this->nodeFactory->createSectionBeginNode($this->lastTitleNode)
$this->nodeFactory->createSectionBeginNode($node)
);

$this->openTitleNodes[] = $node;

break;

case State::SEPARATOR:
Expand Down Expand Up @@ -653,4 +661,19 @@ private function parseListLine(?string $line, bool $flush = false) : bool

return true;
}

private function endOpenSection(TitleNode $titleNode) : void
{
$this->document->addNode(
$this->nodeFactory->createSectionEndNode($titleNode)
);

$key = array_search($titleNode, $this->openTitleNodes, true);

if ($key === false) {
return;
}

unset($this->openTitleNodes[$key]);
}
}
43 changes: 43 additions & 0 deletions tests/HTML/HTMLTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,49 @@ public function testClassDirective() : void
self::assertContains('<table class="special-table">', $rendered);
}

public function testSectionNesting() : void
{
$document = $this->parse('section-nesting.rst');

$rendered = $document->render();

$expected = <<<HTML
<div class="section" id="level-1-test-1">
<h1>Level 1 Test 1</h1>
<div class="section" id="level-2-test-1">
<h2>Level 2 Test 1</h2>
</div>
<div class="section" id="level-2-test-2">
<h2>Level 2 Test 2</h2>
</div>
</div>
<div class="section" id="level-1-test-2">
<h1>Level 1 Test 2</h1>
<div class="section" id="level-2-test-3">
<h2>Level 2 Test 3</h2>
</div>
<div class="section" id="level-2-test-4">
<h2>Level 2 Test 4</h2>
</div>
</div>
<div class="section" id="level-1-test-3">
<h1>Level 1 Test 3</h1>
</div>
<div class="section" id="level-1-test-4">
<h1>Level 1 Test 4</h1>
<div class="section" id="level-2-test-3">
<h2>Level 2 Test 3</h2>
<div class="section" id="level-3-test-1">
<h3>Level 3 Test 1</h3>
</div>
</div>
</div>
HTML;

self::assertSame($expected, $rendered);
}

/**
* Helper function, parses a file and returns the document
* produced by the parser
Expand Down
29 changes: 29 additions & 0 deletions tests/HTML/files/section-nesting.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Level 1 Test 1
==============

Level 2 Test 1
--------------

Level 2 Test 2
--------------

Level 1 Test 2
==============

Level 2 Test 3
--------------

Level 2 Test 4
--------------

Level 1 Test 3
==============

Level 1 Test 4
==============

Level 2 Test 3
--------------

Level 3 Test 1
**************
4 changes: 2 additions & 2 deletions tests/Parser/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,15 @@ public function testSubsequentParsesDontHaveTheSameTitleLevelOrder() : void
self::assertSame(1, $node->getLevel());

/** @var TitleNode $node */
$node = $nodes1[4];
$node = $nodes1[3];
self::assertSame(2, $node->getLevel());

/** @var TitleNode $node */
$node = $nodes2[1];
self::assertSame(1, $node->getLevel(), 'Title level in second parse is influenced by first parse');

/** @var TitleNode $node */
$node = $nodes2[4];
$node = $nodes2[3];
self::assertSame(2, $node->getLevel(), 'Title level in second parse is influenced by first parse');
}

Expand Down

0 comments on commit f1f97e1

Please sign in to comment.