Skip to content

Commit

Permalink
Merge pull request #1131 from phpDocumentor/feature/md-admonitions
Browse files Browse the repository at this point in the history
[FEATURE] Support GitHub like Markdown Admonitions
  • Loading branch information
jaapio authored Oct 12, 2024
2 parents f7aeefe + 17a3997 commit c32f534
Show file tree
Hide file tree
Showing 18 changed files with 256 additions and 104 deletions.
63 changes: 61 additions & 2 deletions packages/guides-markdown/src/Markdown/Parsers/BlockQuoteParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@
use League\CommonMark\Node\NodeWalker;
use League\CommonMark\Node\NodeWalkerEvent;
use phpDocumentor\Guides\MarkupLanguageParser;
use phpDocumentor\Guides\Nodes\AdmonitionNode;
use phpDocumentor\Guides\Nodes\Inline\PlainTextInlineNode;
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\ParagraphNode;
use phpDocumentor\Guides\Nodes\QuoteNode;
use Psr\Log\LoggerInterface;
use RuntimeException;

use function array_shift;
use function count;
use function sprintf;
use function trim;

/** @extends AbstractBlockParser<QuoteNode> */
/** @extends AbstractBlockParser<Node> */
final class BlockQuoteParser extends AbstractBlockParser
{
/** @param iterable<AbstractBlockParser<Node>> $subParsers */
Expand All @@ -35,7 +42,7 @@ public function __construct(
) {
}

public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): QuoteNode
public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): Node
{
$content = [];

Expand All @@ -55,6 +62,58 @@ public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMa

// leaving the heading node
if ($commonMarkNode instanceof BlockQuote) {
if (count($content) > 0 && $content[0] instanceof ParagraphNode && ($content[0]->getValue()[0]) instanceof InlineCompoundNode) {
$paragraphContent = $content[0]->getValue()[0]->getValue();
if (count($paragraphContent) > 0 && $paragraphContent[0] instanceof PlainTextInlineNode) {
$text = trim($paragraphContent[0]->getValue());
$newParagraphContent = $paragraphContent;
array_shift($newParagraphContent);
switch ($text) {
case '[!NOTE]':
return new AdmonitionNode(
'note',
new InlineCompoundNode([new PlainTextInlineNode('Note')]),
'Note',
$newParagraphContent,
);

case '[!TIP]':
return new AdmonitionNode(
'tip',
new InlineCompoundNode([new PlainTextInlineNode('Tip')]),
'Tip',
$newParagraphContent,
);

case '[!IMPORTANT]':
return new AdmonitionNode(
'important',
new InlineCompoundNode([new PlainTextInlineNode('Important')]),
'Important',
$newParagraphContent,
);

case '[!WARNING]':
return new AdmonitionNode(
'warning',
new InlineCompoundNode([new PlainTextInlineNode('Warning')]),
'Warning',
$newParagraphContent,
);

case '[!CAUTION]':
return new AdmonitionNode(
'caution',
new InlineCompoundNode([new PlainTextInlineNode('Caution')]),
'Caution',
$newParagraphContent,
);
}
}

$content[0] = new ParagraphNode([new InlineCompoundNode($paragraphContent)]);
}

return new QuoteNode($content);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

namespace phpDocumentor\Guides\RestructuredText\Directives;

use phpDocumentor\Guides\Nodes\AdmonitionNode;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Nodes\AdmonitionNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

namespace phpDocumentor\Guides\RestructuredText\Directives;

use phpDocumentor\Guides\Nodes\AdmonitionNode;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Nodes\AdmonitionNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,6 @@

namespace phpDocumentor\Guides\RestructuredText\NodeRenderers\Html;

use InvalidArgumentException;
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RenderContext;
use phpDocumentor\Guides\RestructuredText\Nodes\AdmonitionNode;
use phpDocumentor\Guides\TemplateRenderer;

use function implode;
use function is_a;

/** @implements NodeRenderer<AdmonitionNode> */
final class AdmonitionNodeRenderer implements NodeRenderer
final class AdmonitionNodeRenderer extends \phpDocumentor\Guides\NodeRenderers\Html\AdmonitionNodeRenderer
{
public function __construct(private readonly TemplateRenderer $renderer)
{
}

public function supports(string $nodeFqcn): bool
{
return $nodeFqcn === AdmonitionNode::class || is_a($nodeFqcn, AdmonitionNode::class, true);
}

public function render(Node $node, RenderContext $renderContext): string
{
if ($node instanceof AdmonitionNode === false) {
throw new InvalidArgumentException('Node must be an instance of ' . AdmonitionNode::class);
}

$classes = $node->getClasses();

return $this->renderer->renderTemplate(
$renderContext,
'body/admonition.html.twig',
[
'name' => $node->getName(),
'text' => $node->getText(),
'title' => $node->getTitle(),
'isTitled' => $node->isTitled(),
'class' => implode(' ', $classes),
'node' => $node->getValue(),
],
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,6 @@

namespace phpDocumentor\Guides\RestructuredText\Nodes;

use phpDocumentor\Guides\Nodes\CompoundNode;
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;

/** @extends CompoundNode<Node> */
final class AdmonitionNode extends CompoundNode
class AdmonitionNode extends \phpDocumentor\Guides\Nodes\AdmonitionNode
{
/** @param Node[] $value */
public function __construct(private readonly string $name, private readonly InlineCompoundNode|null $title, private readonly string $text, array $value, private readonly bool $isTitled = false)
{
parent::__construct($value);
}

public function getName(): string
{
return $this->name;
}

public function getTitle(): InlineCompoundNode|null
{
return $this->title;
}

public function getText(): string
{
return $this->text;
}

public function isTitled(): bool
{
return $this->isTitled;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@

{% if name == 'caution' %}
{% include "body/admonitions/caution.html.twig" %}
{% endif %}
{% if name == 'important' %}
{% include "body/admonitions/important.html.twig" %}
{% endif %}
{% if name == 'note' %}
{% include "body/admonitions/note.html.twig" %}
{% endif %}
{% if name == 'warning' or name == 'caution' %}
{% if name == 'warning' %}
{% include "body/admonitions/warning.html.twig" %}
{% endif %}
{% if name == 'tip' or name == 'hint' %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="alert alert-danger {{ class ? (' '~class) }}{% if node.classes %} {{ node.classesString }}{% endif %}" role="alert">
<h4 class="alert-heading">Caution</h4>
{{ renderNode(node) }}
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="alert alert-danger {{ class ? (' '~class) }}{% if node.classes %} {{ node.classesString }}{% endif %}" role="alert">
<h4 class="alert-heading">Tip</h4>
<div class="alert alert-warning {{ class ? (' '~class) }}{% if node.classes %} {{ node.classesString }}{% endif %}" role="alert">
<h4 class="alert-heading">Imortant</h4>
{{ renderNode(node) }}
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="alert alert-danger {{ class ? (' '~class) }}{% if node.classes %} {{ node.classesString }}{% endif %}" role="alert">
<h4 class="alert-heading">Tip</h4>
<h4 class="alert-heading">Warning</h4>
{{ renderNode(node) }}
</div>
59 changes: 59 additions & 0 deletions packages/guides/src/NodeRenderers/Html/AdmonitionNodeRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?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\NodeRenderers\Html;

use InvalidArgumentException;
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
use phpDocumentor\Guides\Nodes\AdmonitionNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RenderContext;
use phpDocumentor\Guides\TemplateRenderer;

use function implode;
use function is_a;

/** @implements NodeRenderer<AdmonitionNode> */
class AdmonitionNodeRenderer implements NodeRenderer
{
public function __construct(private readonly TemplateRenderer $renderer)
{
}

public function supports(string $nodeFqcn): bool
{
return $nodeFqcn === AdmonitionNode::class || is_a($nodeFqcn, AdmonitionNode::class, true);
}

public function render(Node $node, RenderContext $renderContext): string
{
if ($node instanceof AdmonitionNode === false) {
throw new InvalidArgumentException('Node must be an instance of ' . AdmonitionNode::class);
}

$classes = $node->getClasses();

return $this->renderer->renderTemplate(
$renderContext,
'body/admonition.html.twig',
[
'name' => $node->getName(),
'text' => $node->getText(),
'title' => $node->getTitle(),
'isTitled' => $node->isTitled(),
'class' => implode(' ', $classes),
'node' => $node->getValue(),
],
);
}
}
44 changes: 44 additions & 0 deletions packages/guides/src/Nodes/AdmonitionNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?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\Nodes;

/** @extends CompoundNode<Node> */
class AdmonitionNode extends CompoundNode
{
/** @param Node[] $value */
public function __construct(private readonly string $name, private readonly InlineCompoundNode|null $title, private readonly string $text, array $value, private readonly bool $isTitled = false)
{
parent::__construct($value);
}

public function getName(): string
{
return $this->name;
}

public function getTitle(): InlineCompoundNode|null
{
return $this->title;
}

public function getText(): string
{
return $this->text;
}

public function isTitled(): bool
{
return $this->isTitled;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<!-- content start -->
<div class="section" id="document-title">
<h1>Document Title</h1>

<div class="alert alert-info " role="alert">
<div class="alert alert-info " role="alert">
<h4 class="alert-heading">Tip</h4>

<p>Lorem Ipsum Dolor.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<!-- content start -->
<div class="section" id="directive-tests">
<h1>Directive tests</h1>
<p>Lorem Ipsum Dolor</p>
<p>Dolor sit!</p>
</div>
<div class="section" id="directive-tests">
<h1>Directive tests</h1>


<p>Lorem Ipsum Dolor</p>

<p>Dolor sit!</p>

</div>
<!-- content end -->
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<!-- content start -->
<div class="section" id="directive-tests">
<h1>Directive tests</h1>
<div>
<p>Lorem Ipsum Dolor</p>
<h2>Some Rubric</h2>
<p>Dolor sit!</p>
</div>
<div class="section" id="directive-tests">
<h1>Directive tests</h1>
<div>

<p>Lorem Ipsum Dolor</p>
<h2>Some Rubric</h2>
<p>Dolor sit!</p>
</div>
</div>
<!-- content end -->
Loading

0 comments on commit c32f534

Please sign in to comment.