Skip to content

[FEATURE] add configuration block directive #795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use phpDocumentor\Guides\RestructuredText\Directives\CautionDirective;
use phpDocumentor\Guides\RestructuredText\Directives\ClassDirective;
use phpDocumentor\Guides\RestructuredText\Directives\CodeBlockDirective;
use phpDocumentor\Guides\RestructuredText\Directives\ConfigurationBlockDirective;
use phpDocumentor\Guides\RestructuredText\Directives\ConfvalDirective;
use phpDocumentor\Guides\RestructuredText\Directives\ContainerDirective;
use phpDocumentor\Guides\RestructuredText\Directives\ContentsDirective;
Expand Down Expand Up @@ -115,6 +116,7 @@
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service;
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;

Expand Down Expand Up @@ -175,6 +177,10 @@
),
])
->set(ConfvalDirective::class)
->set(ConfigurationBlockDirective::class)
->args([
'$languageLabels' => param('phpdoc.rst.code_language_labels'),
])
->set(ContainerDirective::class)
->set(ContentsDirective::class)
->arg('$documentNameResolver', service(DocumentNameResolverInterface::class))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,41 @@
use phpDocumentor\Guides\RestructuredText\Nodes\ConfvalNode;
use phpDocumentor\Guides\RestructuredText\Nodes\OptionNode;
use phpDocumentor\Guides\RestructuredText\Nodes\VersionChangeNode;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;

use function assert;
use function dirname;
use function phpDocumentor\Guides\DependencyInjection\template;

class ReStructuredTextExtension extends Extension implements PrependExtensionInterface, CompilerPassInterface
final class ReStructuredTextExtension extends Extension implements
PrependExtensionInterface,
CompilerPassInterface,
ConfigurationInterface
{
/** @param mixed[] $configs */
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$loader = new PhpFileLoader(
$container,
new FileLocator(dirname(__DIR__, 3) . '/resources/config'),
);

$normalizedLanguageLabels = [];
foreach ($config['code_language_labels'] ?? [] as $item) {
$normalizedLanguageLabels[$item['language']] = $item['label'];
}

$container->setParameter('phpdoc.rst.code_language_labels', $normalizedLanguageLabels);
$loader->load('guides-restructured-text.php');
}

Expand Down Expand Up @@ -55,4 +70,36 @@ public function process(ContainerBuilder $container): void
{
(new TextRolePass())->process($container);
}

public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('rst');
$rootNode = $treeBuilder->getRootNode();
assert($rootNode instanceof ArrayNodeDefinition);

$rootNode
->fixXmlConfig('code_language_label', 'code_language_labels')
->children()
->arrayNode('code_language_labels')
->arrayPrototype()
->children()
->scalarNode('language')
->isRequired()
->end()
->scalarNode('label')
->isRequired()
->end()
->end()
->end()
->end()
->end();

return $treeBuilder;
}

/** @param mixed[] $config */
public function getConfiguration(array $config, ContainerBuilder $container): static
{
return $this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Guides\RestructuredText\Directives;

use phpDocumentor\Guides\Nodes\CodeNode;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\Configuration\ConfigurationBlockNode;
use phpDocumentor\Guides\Nodes\Configuration\ConfigurationTab;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
use Psr\Log\LoggerInterface;
use Symfony\Component\String\Slugger\AsciiSlugger;
use Symfony\Component\String\Slugger\SluggerInterface;

use function assert;
use function get_debug_type;

final class ConfigurationBlockDirective extends SubDirective
{
private SluggerInterface $slugger;

/**
* @param Rule<CollectionNode> $startingRule
* @param array<string, string> $languageLabels
*/
public function __construct(
private LoggerInterface $logger,
Rule $startingRule,
private readonly array $languageLabels = [],
) {
parent::__construct($startingRule);

$this->slugger = new AsciiSlugger();
}

public function getName(): string
{
return 'configuration-block';
}

protected function processSub(
BlockContext $blockContext,
CollectionNode $collectionNode,
Directive $directive,
): Node|null {
$tabs = [];
foreach ($collectionNode->getValue() as $child) {
if (!$child instanceof CodeNode) {
$this->logger->warning('The ".. configuration-block::" directive only supports code blocks, "' . get_debug_type($child) . '" given.');

continue;
}

$language = $child->getLanguage();
assert($language !== null);

$label = $this->languageLabels[$language] ?? $this->slugger->slug($language, ' ')->title()->toString();

$tabs[] = new ConfigurationTab(
$label,
$this->slugger->slug($label)->lower()->toString(),
$child,
);
}

return new ConfigurationBlockNode($tabs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div class="configuration-block">
<div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-{{ node.tabs|length }}">
{% for tab in node.tabs %}
<button role="tab" type="button" data-language="{{ tab.slug }}"
aria-controls="{{ 'configuration-block-tabpanel-' ~ tab.hash }}" aria-selected="{{ loop.first ? 'true' : 'false' }}"
{{ loop.first ? 'data-active="true"' }} {{ not loop.first ? 'tabindex="-1"' }}>
<span>{{ tab.label }}</span>
</button>
{% endfor %}
</div>

{% for tab in node.tabs %}
<div role="tabpanel" id="{{ 'configuration-block-tabpanel-' ~ tab.hash }}" aria-label="{{ tab.label }}" class="configuration-codeblock" data-language="{{ tab.slug }}" style="{{ not loop.first ? 'display: none' }}">
{{ renderNode(tab.content) }}
</div>
{% endfor %}
</div>
2 changes: 2 additions & 0 deletions packages/guides/resources/template/html/template.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use phpDocumentor\Guides\Nodes\AnnotationListNode;
use phpDocumentor\Guides\Nodes\CitationNode;
use phpDocumentor\Guides\Nodes\CodeNode;
use phpDocumentor\Guides\Nodes\Configuration\ConfigurationBlockNode;
use phpDocumentor\Guides\Nodes\DefinitionListNode;
use phpDocumentor\Guides\Nodes\DefinitionLists\DefinitionNode;
use phpDocumentor\Guides\Nodes\DocumentNode;
Expand Down Expand Up @@ -65,6 +66,7 @@
DocumentNode::class => 'structure/document.html.twig',
ImageNode::class => 'body/image.html.twig',
CodeNode::class => 'body/code.html.twig',
ConfigurationBlockNode::class => 'body/configuration-block.html.twig',
DefinitionListNode::class => 'body/definition-list.html.twig',
DefinitionNode::class => 'body/definition.html.twig',
FieldListNode::class => 'body/field-list.html.twig',
Expand Down
24 changes: 24 additions & 0 deletions packages/guides/src/Nodes/Configuration/ConfigurationBlockNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Guides\Nodes\Configuration;

use phpDocumentor\Guides\Nodes\AbstractNode;

/** @extends AbstractNode<list<ConfigurationTab>> */
final class ConfigurationBlockNode extends AbstractNode
{
/** @param list<ConfigurationTab> $tabs */
public function __construct(
array $tabs,
) {
$this->value = $tabs;
}

/** @return list<ConfigurationTab> */
public function getTabs(): array
{
return $this->value;
}
}
22 changes: 22 additions & 0 deletions packages/guides/src/Nodes/Configuration/ConfigurationTab.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Guides\Nodes\Configuration;

use phpDocumentor\Guides\Nodes\CodeNode;

use function hash;

final class ConfigurationTab
{
public readonly string $hash;

public function __construct(
public readonly string $label,
public readonly string $slug,
public readonly CodeNode $content,
) {
$this->hash = hash('xxh128', $content->getValue());
}
}
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ parameters:
count: 1
path: packages/guides-graphs/src/Graphs/Renderer/PlantumlRenderer.php

-
message: "#^Cannot call method scalarNode\\(\\) on Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface\\|null\\.$#"
count: 1
path: packages/guides-restructured-text/src/RestructuredText/DependencyInjection/ReStructuredTextExtension.php

-
message: "#^Using nullsafe property access on non\\-nullable type Doctrine\\\\Common\\\\Lexer\\\\Token\\<int, string\\>\\. Use \\-\\> instead\\.$#"
count: 1
Expand Down
5 changes: 5 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
<code>scalarNode</code>
</UndefinedInterfaceMethod>
</file>
<file src="packages/guides-restructured-text/src/RestructuredText/DependencyInjection/ReStructuredTextExtension.php">
<UndefinedInterfaceMethod>
<code>scalarNode</code>
</UndefinedInterfaceMethod>
</file>
<file src="packages/guides-restructured-text/src/RestructuredText/Parser/Productions/EnumeratedListRule.php">
<InvalidArgument>
<code>$listConfig</code>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- content start -->
<div class="section" id="directive-tests">
<h1>Directive tests</h1>

<div class="configuration-block">
<div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-2">
<button role="tab" type="button" data-language="yaml"
aria-controls="configuration-block-tabpanel-523eafc9524d67db5f21ecae2362d532" aria-selected="true"
data-active="true" >
<span>Yaml</span>
</button>
<button role="tab" type="button" data-language="custom"
aria-controls="configuration-block-tabpanel-a51ba27b3c76153f629592baf23834dc" aria-selected="false"
tabindex="-1">
<span>CUSTOM</span>
</button>
</div>

<div role="tabpanel" id="configuration-block-tabpanel-523eafc9524d67db5f21ecae2362d532" aria-label="Yaml" class="configuration-codeblock" data-language="yaml" style="">
<pre><code class="language-yaml"># app/config/services.yml</code></pre>
</div>
<div role="tabpanel" id="configuration-block-tabpanel-a51ba27b3c76153f629592baf23834dc" aria-label="CUSTOM" class="configuration-codeblock" data-language="custom" style="display: none">
<pre><code class="language-php">// config/routes.php</code></pre>
</div>
</div>

</div>


<!-- content end -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<guides xmlns="https://www.phpdoc.org/guides"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.phpdoc.org/guides packages/guides-cli/resources/schema/guides.xsd">
<extension class="\phpDocumentor\Guides\RestructuredText\DependencyInjection\ReStructuredTextExtension">
<code-language-label language="php" label="CUSTOM" />
<code-language-label language="other" label="Other" />
</extension>
</guides>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Directive tests
===============

.. configuration-block::

.. code-block:: yaml

# app/config/services.yml

.. code-block:: php

// config/routes.php