Skip to content

Commit

Permalink
[FEATURE] Render main menu JSON (#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
linawolf committed Sep 22, 2024
1 parent ef87954 commit 5e8aa57
Show file tree
Hide file tree
Showing 13 changed files with 626 additions and 1 deletion.
19 changes: 19 additions & 0 deletions packages/typo3-docs-theme/resources/config/typo3-docs-theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use phpDocumentor\Guides\Event\PostRenderProcess;
use phpDocumentor\Guides\Event\PreParseProcess;
use phpDocumentor\Guides\Graphs\Renderer\PlantumlServerRenderer;
use phpDocumentor\Guides\ReferenceResolvers\DelegatingReferenceResolver;
use phpDocumentor\Guides\ReferenceResolvers\Interlink\InventoryRepository;
use phpDocumentor\Guides\RestructuredText\Directives\BaseDirective;
use phpDocumentor\Guides\RestructuredText\Directives\SubDirective;
Expand All @@ -22,6 +23,7 @@
use T3Docs\Typo3DocsTheme\Directives\GroupTabDirective;
use T3Docs\Typo3DocsTheme\Directives\IncludeDirective;
use T3Docs\Typo3DocsTheme\Directives\LiteralincludeDirective;
use T3Docs\Typo3DocsTheme\Directives\MainMenuJsonDirective;
use T3Docs\Typo3DocsTheme\Directives\RawDirective;
use T3Docs\Typo3DocsTheme\Directives\SiteSetSettingsDirective;
use T3Docs\Typo3DocsTheme\Directives\T3FieldListTableDirective;
Expand All @@ -38,6 +40,8 @@
use T3Docs\Typo3DocsTheme\Parser\Productions\FieldList\EditOnGitHubFieldListItemRule;
use T3Docs\Typo3DocsTheme\Parser\Productions\FieldList\TemplateFieldListItemRule;
use T3Docs\Typo3DocsTheme\Renderer\DecoratingPlantumlRenderer;
use T3Docs\Typo3DocsTheme\Renderer\MainMenuJsonRenderer;
use T3Docs\Typo3DocsTheme\Renderer\NodeRenderer\MainMenuJsonDocumentRenderer;
use T3Docs\Typo3DocsTheme\TextRoles\ApiClassTextRole;
use T3Docs\Typo3DocsTheme\TextRoles\ComposerTextRole;
use T3Docs\Typo3DocsTheme\TextRoles\FluidTextTextRole;
Expand All @@ -63,6 +67,7 @@

use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\tagged_iterator;

return static function (ContainerConfigurator $container): void {
$container->services()
Expand All @@ -79,6 +84,17 @@
->set(TwigExtension::class)
->tag('twig.extension')
->autowire()

->set(MainMenuJsonRenderer::class)
->tag(
'phpdoc.renderer.typerenderer',
[
'noderender_tag' => 'phpdoc.guides.noderenderer.mainmenujson',
'format' => 'mainmenujson',
],
)
->set(MainMenuJsonDocumentRenderer::class)
->tag('phpdoc.guides.noderenderer.mainmenu')
->set(IssueReferenceTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role')
->set(phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryLoader::class)
Expand Down Expand Up @@ -131,6 +147,8 @@
->set(EditOnGitHubFieldListItemRule::class)
->tag('phpdoc.guides.parser.rst.fieldlist')

->set(DelegatingReferenceResolver::class)
->arg('$resolvers', tagged_iterator('phpdoc.guides.reference_resolver', defaultPriorityMethod: 'getPriority'))

->set(DecoratingPlantumlRenderer::class)
->decorate(PlantumlServerRenderer::class)
Expand All @@ -141,6 +159,7 @@
->set(GroupTabDirective::class)
->set(IncludeDirective::class)
->set(LiteralincludeDirective::class)
->set(MainMenuJsonDirective::class)
->set(RawDirective::class)
->set(SiteSetSettingsDirective::class)
->set(T3FieldListTableDirective::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{#-
This directive is only supported in JSON output
-#}
47 changes: 47 additions & 0 deletions packages/typo3-docs-theme/src/Directives/MainMenuJsonDirective.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace T3Docs\Typo3DocsTheme\Directives;

use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Directives\SubDirective;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
use T3Docs\Typo3DocsTheme\Nodes\MainMenuJsonNode;

/**
* Used in the main documentation page docs.typo3.org to configure
* the main menu docs.typo3.org/mainMenu.json.
*
* To be used together with the MainMenuJsonRenderer and the template
* :template: mainMenu.json
*/
class MainMenuJsonDirective extends SubDirective
{
public function __construct(
Rule $startingRule,
) {
parent::__construct($startingRule);
}

public function getName(): string
{
return 'main-menu-json';
}

protected function processSub(
BlockContext $blockContext,
CollectionNode $collectionNode,
Directive $directive,
): Node|null {
return new MainMenuJsonNode(
$directive->getData(),
$directive->getDataNode() ?? new InlineCompoundNode(),
$collectionNode->getChildren(),
);
}
}
22 changes: 22 additions & 0 deletions packages/typo3-docs-theme/src/Nodes/MainMenuJsonNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace T3Docs\Typo3DocsTheme\Nodes;

use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Nodes\GeneralDirectiveNode;

final class MainMenuJsonNode extends GeneralDirectiveNode
{
/**
* @param Node[] $value
*/
public function __construct(
protected readonly string $plainContent,
protected readonly InlineCompoundNode $content,
array $value = [],
) {
parent::__construct('main-menu-json', $plainContent, $content, $value);
}

}
47 changes: 47 additions & 0 deletions packages/typo3-docs-theme/src/Renderer/MainMenuJsonRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace T3Docs\Typo3DocsTheme\Renderer;

use phpDocumentor\Guides\Handlers\RenderCommand;
use phpDocumentor\Guides\RenderContext;
use phpDocumentor\Guides\Renderer\TypeRenderer;
use T3Docs\Typo3DocsTheme\Nodes\Metadata\TemplateNode;
use T3Docs\Typo3DocsTheme\Renderer\NodeRenderer\MainMenuJsonDocumentRenderer;

final class MainMenuJsonRenderer implements TypeRenderer
{
public function __construct(
private readonly MainMenuJsonDocumentRenderer $renderer
) {}

public function render(RenderCommand $renderCommand): void
{
$projectNode = $renderCommand->getProjectNode();

$context = RenderContext::forProject(
$projectNode,
$renderCommand->getDocumentArray(),
$renderCommand->getOrigin(),
$renderCommand->getDestination(),
$renderCommand->getDestinationPath(),
'mainmenujson',
)->withIterator($renderCommand->getDocumentIterator())
->withOutputFilePath('mainmenu.json');

foreach ($renderCommand->getDocumentArray() as $key => $document) {
$headerNodes = $document->getHeaderNodes();
foreach ($headerNodes as $headerNode) {
if ($headerNode instanceof TemplateNode && $headerNode->getValue() === 'mainmenu.json') {
$context = $context->withDocument($document);
$renderCommand->getDestination()->put(
'mainmenu.json',
$this->renderer->render(
$document,
$context,
),
);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace T3Docs\Typo3DocsTheme\Renderer\NodeRenderer;

use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\CompoundNode;
use phpDocumentor\Guides\Nodes\DocumentNode;
use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;
use phpDocumentor\Guides\Nodes\ListItemNode;
use phpDocumentor\Guides\Nodes\ListNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\ReferenceResolvers\DelegatingReferenceResolver;
use phpDocumentor\Guides\ReferenceResolvers\Messages;
use phpDocumentor\Guides\RenderContext;
use T3Docs\Typo3DocsTheme\Nodes\MainMenuJsonNode;

/** @implements NodeRenderer<Node> */
class MainMenuJsonDocumentRenderer implements NodeRenderer
{
public function __construct(
private readonly DelegatingReferenceResolver $delegatingReferenceResolver,
) {}

public function supports(string $nodeFqcn): bool
{
return DocumentNode::class === $nodeFqcn;
}

public function render(Node $node, RenderContext $renderContext): string
{
$result = '';
if ($node instanceof DocumentNode) {
foreach ($node->getChildren() as $childNode) {
$result .= $this->render($childNode, $renderContext);
}
}
if ($node instanceof CollectionNode) {
foreach ($node->getChildren() as $childNode) {
$result .= $this->render($childNode, $renderContext);
}
}
if (!$node instanceof MainMenuJsonNode) {
return $result;
}
return $result . $this->renderMainMenu($node, $renderContext);
}

private function renderMainMenu(MainMenuJsonNode $node, RenderContext $renderContext): string
{
$stringResult = '';
$result = [];
foreach ($node->getChildren() as $listNode) {
$this->renderSubEntry($listNode, $renderContext, $result);
}
return $stringResult . json_encode($result, JSON_PRETTY_PRINT);
}

/**
* @param array<mixed> $result
*/
public function renderSubEntry(Node $node, RenderContext $renderContext, array &$result): void
{
if ($node instanceof ListNode) {
foreach ($node->getChildren() as $listItemNode) {
if (!$listItemNode instanceof ListItemNode) {
continue;
}
$menuEntry = [];
foreach ($listItemNode->getChildren() as $childNode) {
if ($childNode instanceof ListNode) {
$this->renderSubEntryList($menuEntry, $childNode, $renderContext);
} elseif ($childNode instanceof CompoundNode) {
$this->renderMenuEntry($menuEntry, $childNode, $renderContext);
}
}
$result[] = $menuEntry;
}
} elseif ($node instanceof CompoundNode) {
foreach ($node->getChildren() as $childNode) {
$this->renderSubEntry($childNode, $renderContext, $result);
}
}
}

/**
* @param array<mixed> $menuEntry
*/
private function renderMenuEntry(array &$menuEntry, Node $node, RenderContext $renderContext): void
{
if ($node instanceof CompoundNode) {
foreach ($node->getChildren() as $childNode) {
$this->renderMenuEntry($menuEntry, $childNode, $renderContext);
}
return;
}
if ($node instanceof LinkInlineNode) {
$this->delegatingReferenceResolver->resolve($node, $renderContext, new Messages());
$url = $node->getUrl();
$parsedUrl = parse_url($url);
if (!isset($parsedUrl['scheme'])) {
$url = 'https://docs.typo3.org/' . $url;
}
$menuEntry['name'] = $node->getValue();
$menuEntry['href'] = $url;
}
}
/**
* @param array<mixed> $menuEntry
*/
private function renderSubEntryList(array &$menuEntry, ListNode $listNode, RenderContext $renderContext): void
{
$subListItems = [];
$this->renderSubEntry($listNode, $renderContext, $subListItems);
$menuEntry['children'] = $subListItems;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
use phpDocumentor\Guides\Renderer\UrlGenerator\UrlGeneratorInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use T3Docs\GuidesExtension\Command\RunDecorator;
use T3Docs\Typo3DocsTheme\Inventory\Typo3InventoryRepository;
use T3Docs\GuidesExtension\Renderer\UrlGenerator\RenderOutputUrlGenerator;
use T3Docs\GuidesExtension\Renderer\UrlGenerator\SingleHtmlUrlGenerator;
use T3Docs\Typo3DocsTheme\Inventory\Typo3InventoryRepository;

use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
Expand Down
Loading

0 comments on commit 5e8aa57

Please sign in to comment.