Skip to content

Commit 5f6cd7d

Browse files
committed
Move Menu Entry Creation to TocNodeWithDocumentEntryTransformer
1 parent 991e017 commit 5f6cd7d

File tree

19 files changed

+506
-66
lines changed

19 files changed

+506
-66
lines changed

packages/guides-restructured-text/src/RestructuredText/Toc/ToctreeBuilder.php

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,12 @@
66

77
use phpDocumentor\Guides\ParserContext;
88
use phpDocumentor\Guides\RestructuredText\Parser\LinesIterator;
9-
use phpDocumentor\Guides\UrlGeneratorInterface;
109

1110
use function array_filter;
1211
use function array_map;
13-
use function in_array;
14-
use function str_contains;
1512

1613
class ToctreeBuilder
1714
{
18-
public function __construct(private readonly GlobSearcher $globSearcher, private readonly UrlGeneratorInterface $urlGenerator)
19-
{
20-
}
21-
2215
/**
2316
* @param mixed[] $options
2417
*
@@ -46,10 +39,4 @@ private function parseToctreeFiles(LinesIterator $lines): array
4639
static fn (string $file): bool => $file !== '',
4740
);
4841
}
49-
50-
/** @param mixed[] $options */
51-
private function isGlob(array $options, string $file): bool
52-
{
53-
return isset($options['glob']) && str_contains($file, '*');
54-
}
5542
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<ul class="phpdocumentor-list">
2-
{% for entry in node.entries -%}
2+
{% for entry in node.menuEntries -%}
33
{{ renderNode(entry) }}
44
{% endfor %}
55
</ul>

packages/guides/src/Compiler/NodeTransformers/DocumentEntryRegistrationTransformer.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
use phpDocumentor\Guides\Nodes\TitleNode;
1313
use Psr\Log\LoggerInterface;
1414

15-
/**
16-
* @implements NodeTransformer<Node>
17-
*
18-
*/
15+
/** @implements NodeTransformer<Node> */
1916
class DocumentEntryRegistrationTransformer implements NodeTransformer
2017
{
2118
public function __construct(
@@ -38,7 +35,7 @@ public function leaveNode(Node $node, CompilerContext $compilerContext): Node|nu
3835
$this->logger->warning('Document has not title', $node->getLoggerInformation());
3936
}
4037

41-
$entry = new DocumentEntryNode($node->getFilePath(), $node->getTitle()??TitleNode::emptyNode());
38+
$entry = new DocumentEntryNode($node->getFilePath(), $node->getTitle() ?? TitleNode::emptyNode());
4239
$compilerContext->getProjectNode()->addDocumentEntry($entry);
4340

4441
return $node->withDocumentEntry($entry);

packages/guides/src/Compiler/NodeTransformers/MenuNodeTransformer.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
<?php
32

43
declare(strict_types=1);
@@ -12,7 +11,7 @@
1211
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
1312
use phpDocumentor\Guides\Nodes\DocumentTree\Entry as MetaEntry;
1413
use phpDocumentor\Guides\Nodes\DocumentTree\SectionEntryNode;
15-
use phpDocumentor\Guides\Nodes\Menu\Entry;
14+
use phpDocumentor\Guides\Nodes\Menu\MenuEntry;
1615
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
1716
use phpDocumentor\Guides\Nodes\Node;
1817
use Traversable;
@@ -38,14 +37,14 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
3837
foreach ($this->buildFromDocumentEntry($metaEntry, 1, $node, $compilerContext) as $entry) {
3938
if ($entry->getUrl() === $compilerContext->getDocumentNode()->getFilePath()) {
4039
$entry = $entry->withOptions(array_merge($entry->getOptions(), ['active' => true]));
41-
assert($entry instanceof Entry);
40+
assert($entry instanceof MenuEntry);
4241
}
4342

4443
$entries[] = $entry;
4544
}
4645
}
4746

48-
return $node->withEntries($entries);
47+
return $node->withMenuEntries($entries);
4948
}
5049

5150
public function leaveNode(Node $node, CompilerContext $compilerContext): Node|null
@@ -58,7 +57,7 @@ public function supports(Node $node): bool
5857
return $node instanceof MenuNode;
5958
}
6059

61-
/** @return iterable<Entry> */
60+
/** @return iterable<MenuEntry> */
6261
private function buildFromDocumentEntry(DocumentEntryNode $document, int $depth, MenuNode $node, CompilerContext $compilerContext): iterable
6362
{
6463
if ($depth > $node->getDepth()) {
@@ -74,7 +73,7 @@ private function buildFromDocumentEntry(DocumentEntryNode $document, int $depth,
7473
}
7574
}
7675

77-
/** @return Traversable<Entry> */
76+
/** @return Traversable<MenuEntry> */
7877
private function buildFromSection(
7978
DocumentEntryNode $document,
8079
SectionEntryNode $entry,
@@ -91,7 +90,7 @@ private function buildFromSection(
9190
}
9291
}
9392

94-
/** @return Traversable<Entry> */
93+
/** @return Traversable<MenuEntry> */
9594
private function buildLevel(
9695
MetaEntry $child,
9796
DocumentEntryNode $document,
@@ -101,7 +100,7 @@ private function buildLevel(
101100
): Traversable {
102101
if ($child instanceof SectionEntryNode) {
103102
if (!$node->isPageLevelOnly() || $depth === 1) {
104-
yield new Entry(
103+
yield new MenuEntry(
105104
$document->getFile(),
106105
$child->getTitle(),
107106
iterator_to_array($this->buildFromSection($document, $child, ++$depth, $node, $compilerContext), false),
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Guides\Compiler\NodeTransformers;
6+
7+
use phpDocumentor\Guides\Compiler\CompilerContext;
8+
use phpDocumentor\Guides\Compiler\NodeTransformer;
9+
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
10+
use phpDocumentor\Guides\Nodes\Menu\MenuEntry;
11+
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
12+
use phpDocumentor\Guides\Nodes\Menu\TocNode;
13+
use phpDocumentor\Guides\Nodes\Node;
14+
15+
use function array_pop;
16+
use function explode;
17+
use function implode;
18+
use function preg_match;
19+
use function str_replace;
20+
use function str_starts_with;
21+
22+
/** @implements NodeTransformer<MenuNode> */
23+
class TocNodeWithDocumentEntryTransformer implements NodeTransformer
24+
{
25+
public function enterNode(Node $node, CompilerContext $compilerContext): Node
26+
{
27+
return $node;
28+
}
29+
30+
public function leaveNode(Node $node, CompilerContext $compilerContext): Node|null
31+
{
32+
if (!$node instanceof TocNode) {
33+
return $node;
34+
}
35+
36+
$files = $node->getFiles();
37+
$glob = $node->hasOption('glob');
38+
39+
$documentEntries = $compilerContext->getProjectNode()->getAllDocumentEntries();
40+
$currentPath = $compilerContext->getDocumentNode()->getFilePath();
41+
$documentEntriesInTree = [];
42+
$menuEntries = [];
43+
44+
foreach ($files as $file) {
45+
foreach ($documentEntries as $documentEntry) {
46+
if ($this->isEqualAbsolutePath($documentEntry, $file, $currentPath, $glob)) {
47+
$documentEntriesInTree[] = $documentEntry;
48+
$menuEntry = new MenuEntry($documentEntry->getFile(), $documentEntry->getTitle(), [], false);
49+
$menuEntries[] = $menuEntry;
50+
if (!$glob) {
51+
// If blob is not set, there may only be one result per listed file
52+
break;
53+
}
54+
} elseif ($this->isEqualRelativePath($documentEntry, $file, $currentPath, $glob)) {
55+
$documentEntriesInTree[] = $documentEntry;
56+
$menuEntry = new MenuEntry($documentEntry->getFile(), $documentEntry->getTitle(), [], false, 1);
57+
$menuEntries[] = $menuEntry;
58+
if (!$glob) {
59+
// If blob is not set, there may only be one result per listed file
60+
break;
61+
}
62+
}
63+
}
64+
}
65+
66+
$node = $node->withMenuEntries($menuEntries);
67+
68+
return $node;
69+
}
70+
71+
public function supports(Node $node): bool
72+
{
73+
return $node instanceof MenuNode;
74+
}
75+
76+
public function getPriority(): int
77+
{
78+
// After DocumentEntryTransformer
79+
return 4500;
80+
}
81+
82+
private function isEqualAbsolutePath(DocumentEntryNode $documentEntry, string $file, string $currentPath, bool $glob): bool
83+
{
84+
if ($file === '/' . $documentEntry->getFile()) {
85+
return true;
86+
}
87+
88+
if ($glob && $documentEntry->getFile() !== $currentPath) {
89+
$file = str_replace('*', '[a-zA-Z0-9]*', $file);
90+
$pattern = '`^' . $file . '$`';
91+
92+
return preg_match($pattern, '/' . $documentEntry->getFile()) > 0;
93+
}
94+
95+
return false;
96+
}
97+
98+
private function isEqualRelativePath(DocumentEntryNode $documentEntry, string $file, string $currentPath, bool $glob): bool
99+
{
100+
if (str_starts_with($file, '/')) {
101+
return false;
102+
}
103+
104+
$current = explode('/', $currentPath);
105+
array_pop($current);
106+
$current[] = $file;
107+
$absolute = implode('/', $current);
108+
109+
if ($absolute === $documentEntry->getFile()) {
110+
return true;
111+
}
112+
113+
if ($glob && $documentEntry->getFile() !== $currentPath) {
114+
$file = str_replace('*', '[a-zA-Z0-9]*', $file);
115+
$pattern = '`^' . $file . '$`';
116+
117+
return preg_match($pattern, $documentEntry->getFile()) > 0;
118+
}
119+
120+
return false;
121+
}
122+
}

packages/guides/src/NodeRenderers/Html/MenuEntryRenderer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
namespace phpDocumentor\Guides\NodeRenderers\Html;
66

77
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
8-
use phpDocumentor\Guides\Nodes\Menu\Entry;
8+
use phpDocumentor\Guides\Nodes\Menu\MenuEntry;
99
use phpDocumentor\Guides\Nodes\Node;
1010
use phpDocumentor\Guides\RenderContext;
1111
use phpDocumentor\Guides\TemplateRenderer;
1212

13-
/** @implements NodeRenderer<Entry> */
13+
/** @implements NodeRenderer<MenuEntry> */
1414
final class MenuEntryRenderer implements NodeRenderer
1515
{
1616
public function __construct(private readonly TemplateRenderer $renderer)
@@ -19,7 +19,7 @@ public function __construct(private readonly TemplateRenderer $renderer)
1919

2020
public function supports(Node $node): bool
2121
{
22-
return $node instanceof Entry;
22+
return $node instanceof MenuEntry;
2323
}
2424

2525
public function render(Node $node, RenderContext $renderContext): string

packages/guides/src/Nodes/DocumentNode.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,29 +244,27 @@ public function getFootnoteTargetAnonymous(): FootnoteTarget|null
244244

245245
return null;
246246
}
247+
247248
public function getDocumentEntry(): DocumentEntryNode|null
248249
{
249250
return $this->documentEntry;
250251
}
251252

252253
public function withDocumentEntry(DocumentEntryNode $documentEntry): DocumentNode
253254
{
254-
$node = clone($this);
255+
$node = clone$this;
255256
$node->documentEntry = $documentEntry;
257+
256258
return $node;
257259
}
258260

259-
/**
260-
* @return SectionEntryNode|null
261-
*/
262-
public function getRootSectionEntry(): ?SectionEntryNode
261+
public function getRootSectionEntry(): SectionEntryNode|null
263262
{
264263
return $this->rootSectionEntry;
265264
}
266265

267-
public function setRootSectionEntry(?SectionEntryNode $rootSectionEntry): void
266+
public function setRootSectionEntry(SectionEntryNode|null $rootSectionEntry): void
268267
{
269268
$this->rootSectionEntry = $rootSectionEntry;
270269
}
271-
272270
}

packages/guides/src/Nodes/DocumentTree/DocumentEntryNode.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class DocumentEntryNode extends AbstractNode implements Entry
1313
{
1414
/** @var Entry[] */
1515
private array $entries = [];
16+
private DocumentEntryNode|null $parent = null;
1617

1718
public function __construct(private readonly string $file, private readonly TitleNode $titleNode)
1819
{
@@ -34,6 +35,16 @@ public function getChildren(): array
3435
return $this->entries;
3536
}
3637

38+
public function getParent(): DocumentEntryNode|null
39+
{
40+
return $this->parent;
41+
}
42+
43+
public function setParent(DocumentEntryNode|null $parent): void
44+
{
45+
$this->parent = $parent;
46+
}
47+
3748
public function getFile(): string
3849
{
3950
return $this->file;

packages/guides/src/Nodes/Menu/Entry.php renamed to packages/guides/src/Nodes/Menu/MenuEntry.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
use phpDocumentor\Guides\Nodes\TitleNode;
99

1010
/** @extends AbstractNode<TitleNode> */
11-
final class Entry extends AbstractNode
11+
final class MenuEntry extends AbstractNode
1212
{
13-
/** @param Entry[] $children */
14-
public function __construct(private readonly string $url, TitleNode $title, private readonly array $children = [], private readonly bool $isDocumentRoot = false)
15-
{
13+
/** @param MenuEntry[] $children */
14+
public function __construct(
15+
private readonly string $url,
16+
TitleNode $title,
17+
private readonly array $children = [],
18+
private readonly bool $isDocumentRoot = false,
19+
private readonly int $level = 1,
20+
) {
1621
$this->value = $title;
1722
}
1823

@@ -21,13 +26,13 @@ public function getUrl(): string
2126
return $this->url;
2227
}
2328

24-
/** @return Entry[] */
29+
/** @return MenuEntry[] */
2530
public function getChildren(): array
2631
{
2732
return $this->children;
2833
}
2934

30-
/** @return Entry[] */
35+
/** @return MenuEntry[] */
3136
public function getEntries(): array
3237
{
3338
return $this->children;
@@ -37,4 +42,9 @@ public function isDocumentRoot(): bool
3742
{
3843
return $this->isDocumentRoot;
3944
}
45+
46+
public function getLevel(): int
47+
{
48+
return $this->level;
49+
}
4050
}

0 commit comments

Comments
 (0)