Skip to content

Commit

Permalink
Merge pull request #1121 from phpDocumentor/task/menu-automatic
Browse files Browse the repository at this point in the history
[FEATURE] Add option to create an automatic menu
  • Loading branch information
jaapio authored Oct 8, 2024
2 parents 5d2bbf1 + 9978ef1 commit 96d5f59
Show file tree
Hide file tree
Showing 52 changed files with 1,652 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/guides-cli/resources/schema/guides.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<xsd:attribute name="theme" type="xsd:string"/>
<xsd:attribute name="default-code-language" type="xsd:string"/>
<xsd:attribute name="links-are-relative" type="xsd:string"/>
<xsd:attribute name="automatic-menu" type="xsd:string"/>
<xsd:attribute name="max-menu-depth" type="xsd:int"/>

</xsd:complexType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\ParserContext;
use phpDocumentor\Guides\Settings\ProjectSettings;
use phpDocumentor\Guides\Settings\SettingsManager;
use Psr\Log\LoggerInterface;
use RuntimeException;

Expand All @@ -40,16 +42,21 @@ final class MarkupLanguageParser implements MarkupLanguageParserInterface

private DocumentNode|null $document = null;

private SettingsManager $settingsManager;

/** @param iterable<ParserInterface<Node>> $parsers */
public function __construct(
private readonly LoggerInterface $logger,
private readonly iterable $parsers,
SettingsManager|null $settingsManager,
) {
$cmEnvironment = new CommonMarkEnvironment(['html_input' => 'strip']);
$cmEnvironment->addExtension(new CommonMarkCoreExtension());
$cmEnvironment->addExtension(new TableExtension());
$cmEnvironment->addExtension(new AutolinkExtension());
$this->markdownParser = new MarkdownParser($cmEnvironment);
// if for backward compatibility reasons no settings manager was passed, use the defaults
$this->settingsManager = $settingsManager ?? new SettingsManager(new ProjectSettings());
}

public function supports(string $inputFormat): bool
Expand All @@ -69,7 +76,7 @@ public function parse(ParserContext $parserContext, string $contents): DocumentN
private function parseDocument(NodeWalker $walker, string $hash): DocumentNode
{
$document = new DocumentNode($hash, ltrim($this->getParserContext()->getCurrentAbsolutePath(), '/'));
$document->setOrphan(true);
$document->setOrphan(!$this->settingsManager->getProjectSettings()->isAutomaticMenu());
$this->document = $document;

while ($event = $walker->next()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Compiler\NodeTransformers\MenuNodeTransformers;

use phpDocumentor\Guides\Compiler\CompilerContextInterface;
use phpDocumentor\Guides\Compiler\NodeTransformer;
use phpDocumentor\Guides\Nodes\Menu\MenuNode;
use phpDocumentor\Guides\Nodes\Menu\NavMenuNode;
use phpDocumentor\Guides\Nodes\Menu\TocNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Settings\SettingsManager;
use Psr\Log\LoggerInterface;

/** @implements NodeTransformer<MenuNode> */
final class TocNodeReplacementTransformer implements NodeTransformer
{
public function __construct(
private readonly LoggerInterface $logger,
private readonly SettingsManager $settingsManager,
) {
}

public function enterNode(Node $node, CompilerContextInterface $compilerContext): Node
{
return $node;
}

public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null
{
if (!$node instanceof TocNode) {
return $node;
}

if (!$this->settingsManager->getProjectSettings()->isAutomaticMenu()) {
return $node;
}

if ($node->hasOption('hidden')) {
$this->logger->warning('The `.. toctree::` directive with option `:hidden:` is not supported in automatic-menu mode. ', $compilerContext->getLoggerInformation());

return null;
}

$this->logger->warning('The `.. toctree::` directive is not supported in automatic-menu mode. Use `.. menu::` instead. ', $compilerContext->getLoggerInformation());
$menuNode = new NavMenuNode($node->getMenuEntries());
$menuNode = $menuNode->withOptions($node->getOptions());
$menuNode = $menuNode->withCaption($node->getCaption());

return $menuNode;
}

public function supports(Node $node): bool
{
return $node instanceof TocNode;
}

public function getPriority(): int
{
return 20_000;
}
}
63 changes: 63 additions & 0 deletions packages/guides/src/Compiler/Passes/AutomaticMenuPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Compiler\Passes;

use phpDocumentor\Guides\Compiler\CompilerContextInterface;
use phpDocumentor\Guides\Compiler\CompilerPass;
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Settings\SettingsManager;

final class AutomaticMenuPass implements CompilerPass
{
public function __construct(
private readonly SettingsManager $settingsManager,
) {
}

public function getPriority(): int
{
return 20; // must be run very late
}

/**
* @param DocumentNode[] $documents
*
* @return DocumentNode[]
*/
public function run(array $documents, CompilerContextInterface $compilerContext): array
{
if (!$this->settingsManager->getProjectSettings()->isAutomaticMenu()) {
return $documents;
}

$projectNode = $compilerContext->getProjectNode();
$rootDocumentEntry = $projectNode->getRootDocumentEntry();
foreach ($documents as $documentNode) {
if ($documentNode->isOrphan()) {
// Do not add orphans to the automatic menu
continue;
}

if ($documentNode->isRoot()) {
continue;
}

$documentEntry = $projectNode->getDocumentEntry($documentNode->getFilePath());
$documentEntry->setParent($rootDocumentEntry);
$rootDocumentEntry->addChild($documentEntry);
}

return $documents;
}
}
19 changes: 18 additions & 1 deletion packages/guides/src/Compiler/Passes/GlobalMenuPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

use function array_map;
use function assert;
use function count;

use const PHP_INT_MAX;

Expand All @@ -56,7 +57,7 @@ public function run(array $documents, CompilerContextInterface $compilerContext)
try {
$rootDocumentEntry = $projectNode->getRootDocumentEntry();
} catch (Throwable) {
// Todo: Functional tests have not root document entry
// Todo: Functional tests have no root document entry
return $documents;
}

Expand All @@ -78,11 +79,27 @@ public function run(array $documents, CompilerContextInterface $compilerContext)
$menuNodes[] = $menuNode->withCaption($tocNode->getCaption());
}

if ($this->settingsManager->getProjectSettings()->isAutomaticMenu() && count($menuNodes) === 0) {
$menuNodes[] = $this->getNavMenuNodeFromDocumentEntries($compilerContext);
}

$projectNode->setGlobalMenues($menuNodes);

return $documents;
}

private function getNavMenuNodeFromDocumentEntries(CompilerContextInterface $compilerContext): NavMenuNode
{
$menuEntries = [];
$rootDocumentEntry = $compilerContext->getProjectNode()->getRootDocumentEntry();
foreach ($rootDocumentEntry->getChildren() as $documentEntryNode) {
$newMenuEntry = new InternalMenuEntryNode($documentEntryNode->getFile(), $documentEntryNode->getTitle(), [], false, 1);
$menuEntries[] = $newMenuEntry;
}

return new NavMenuNode($menuEntries);
}

private function getNavMenuNodefromTocNode(CompilerContextInterface $compilerContext, TocNode $tocNode, string|null $menuType = null): NavMenuNode
{
$self = $this;
Expand Down
11 changes: 11 additions & 0 deletions packages/guides/src/Compiler/Passes/ToctreeValidationPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
use phpDocumentor\Guides\Nodes\ProjectNode;
use phpDocumentor\Guides\Settings\ProjectSettings;
use phpDocumentor\Guides\Settings\SettingsManager;
use Psr\Log\LoggerInterface;

final class ToctreeValidationPass implements CompilerPass
{
private SettingsManager $settingsManager;

public function __construct(
private readonly LoggerInterface $logger,
SettingsManager|null $settingsManager = null,
) {
// if for backward compatibility reasons no settings manager was passed, use the defaults
$this->settingsManager = $settingsManager ?? new SettingsManager(new ProjectSettings());
}

public function getPriority(): int
Expand All @@ -39,6 +46,10 @@ public function getPriority(): int
*/
public function run(array $documents, CompilerContextInterface $compilerContext): array
{
if ($this->settingsManager->getProjectSettings()->isAutomaticMenu()) {
return $documents;
}

$projectNode = $compilerContext->getProjectNode();

foreach ($documents as $document) {
Expand Down
5 changes: 5 additions & 0 deletions packages/guides/src/DependencyInjection/GuidesExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ static function ($value) {
->scalarNode('show_progress')->end()
->scalarNode('links_are_relative')->end()
->scalarNode('max_menu_depth')->end()
->scalarNode('automatic_menu')->end()
->arrayNode('base_template_paths')
->defaultValue([])
->scalarPrototype()->end()
Expand Down Expand Up @@ -278,6 +279,10 @@ public function load(array $configs, ContainerBuilder $container): void
$projectSettings->setMaxMenuDepth((int) $config['max_menu_depth']);
}

if (isset($config['automatic_menu'])) {
$projectSettings->setAutomaticMenu((bool) $config['automatic_menu']);
}

if (isset($config['default_code_language'])) {
$projectSettings->setDefaultCodeLanguage((string) $config['default_code_language']);
}
Expand Down
13 changes: 13 additions & 0 deletions packages/guides/src/Settings/ProjectSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ final class ProjectSettings
private bool $linksRelative = false;
private string $defaultCodeLanguage = '';
private int $maxMenuDepth = 0;
private bool $automaticMenu = false;

/** @var string[] */
private array $ignoredDomains = [];
Expand Down Expand Up @@ -243,4 +244,16 @@ public function setIndexName(string $indexName): ProjectSettings

return $this;
}

public function isAutomaticMenu(): bool
{
return $this->automaticMenu;
}

public function setAutomaticMenu(bool $automaticMenu): ProjectSettings
{
$this->automaticMenu = $automaticMenu;

return $this;
}
}
Loading

0 comments on commit 96d5f59

Please sign in to comment.