Update website

This commit is contained in:
Guilhem Lavaux 2024-11-19 08:02:04 +01:00
parent 4413528994
commit 1d90fbf296
6865 changed files with 1091082 additions and 0 deletions

View file

@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\SubDirective;
use Doctrine\RST\Environment;
use Doctrine\RST\Nodes\DocumentNode;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
use function array_map;
use function explode;
final class ClassDirective extends SubDirective
{
public function getName(): string
{
return 'class';
}
/** @param string[] $options */
public function processSub(
Parser $parser,
?Node $document,
string $variable,
string $data,
array $options
): ?Node {
if ($document === null) {
return null;
}
$classes = explode(' ', $data);
$normalizedClasses = array_map(static function (string $class): string {
return Environment::slugify($class);
}, $classes);
$document->setClasses($normalizedClasses);
if ($document instanceof DocumentNode) {
$this->setNodesClasses($document->getNodes(), $classes);
}
return $document;
}
public function appliesToNonBlockContent(): bool
{
return true;
}
/**
* @param Node[] $nodes
* @param string[] $classes
*/
private function setNodesClasses(array $nodes, array $classes): void
{
foreach ($nodes as $node) {
$node->setClasses($classes);
if (! ($node instanceof DocumentNode)) {
continue;
}
$this->setNodesClasses($node->getNodes(), $classes);
}
}
}

View file

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\SubDirective;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
/**
* Divs a sub document in a div with a given class
*/
final class Div extends SubDirective
{
public function getName(): string
{
return 'div';
}
/** @param string[] $options */
public function processSub(
Parser $parser,
?Node $document,
string $variable,
string $data,
array $options
): ?Node {
$divOpen = $parser->renderTemplate('div-open.html.twig', ['class' => $data]);
return $parser->getNodeFactory()->createWrapperNode($document, $divOpen, '</div>');
}
}

View file

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\SubDirective;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
use Exception;
use function sprintf;
/**
* Renders an image, example :
*
* .. figure:: image.jpg
* :width: 100
* :title: An image
*
* Here is an awesome caption
*/
final class Figure extends SubDirective
{
public function getName(): string
{
return 'figure';
}
/** @param string[] $options */
public function processSub(
Parser $parser,
?Node $document,
string $variable,
string $data,
array $options
): ?Node {
$environment = $parser->getEnvironment();
$url = $environment->relativeUrl($data);
if ($url === null) {
throw new Exception(sprintf('Could not get relative url for %s', $data));
}
$nodeFactory = $parser->getNodeFactory();
return $parser->getNodeFactory()->createFigureNode(
$nodeFactory->createImageNode($url, $options),
$document
);
}
}

View file

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
use Exception;
use function sprintf;
/**
* Renders an image, example :
*
* .. image:: image.jpg
* :width: 100
* :title: An image
*/
final class Image extends Directive
{
public function getName(): string
{
return 'image';
}
/** @param string[] $options */
public function processNode(
Parser $parser,
string $variable,
string $data,
array $options
): ?Node {
$environment = $parser->getEnvironment();
$url = $environment->relativeUrl($data);
if ($url === null) {
throw new Exception(sprintf('Could not get relative url for %s', $data));
}
return $parser->getNodeFactory()->createImageNode($url, $options);
}
}

View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
/**
* Add a meta information:
*
* .. meta::
* :key: value
*/
final class Meta extends Directive
{
public function getName(): string
{
return 'meta';
}
/** @param string[] $options */
public function process(
Parser $parser,
?Node $node,
string $variable,
string $data,
array $options
): void {
$document = $parser->getDocument();
$nodeFactory = $parser->getNodeFactory();
foreach ($options as $key => $value) {
$meta = $nodeFactory->createMetaNode($key, $value);
$document->addHeaderNode($meta);
}
if ($node === null) {
return;
}
$document->addNode($node);
}
}

View file

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
/**
* Adds a stylesheet to a document, example:
*
* .. stylesheet:: style.css
*/
final class Stylesheet extends Directive
{
public function getName(): string
{
return 'stylesheet';
}
/** @param string[] $options */
public function process(
Parser $parser,
?Node $node,
string $variable,
string $data,
array $options
): void {
$document = $parser->getDocument();
$document->addCss($data);
if ($node === null) {
return;
}
$document->addNode($node);
}
}

View file

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
/**
* Add a meta title to the document
*
* .. title:: Page title
*/
final class Title extends Directive
{
public function getName(): string
{
return 'title';
}
/** @param string[] $options */
public function process(
Parser $parser,
?Node $node,
string $variable,
string $data,
array $options
): void {
$document = $parser->getDocument();
$title = $parser->renderTemplate('title.html.twig', ['title' => $data]);
$document->addHeaderNode(
$parser->getNodeFactory()->createRawNode($title)
);
if ($node === null) {
return;
}
$document->addNode($node);
}
}

View file

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Parser;
use function trim;
/**
* Sets the document URL
*/
final class Url extends Directive
{
public function getName(): string
{
return 'url';
}
/** @param string[] $options */
public function processAction(
Parser $parser,
string $variable,
string $data,
array $options
): void {
$environment = $parser->getEnvironment();
$environment->setUrl(trim($data));
}
}

View file

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Directives;
use Doctrine\RST\Directives\SubDirective;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Parser;
use RuntimeException;
use function uniqid;
/**
* Wraps a sub document in a div with a given class
*/
final class Wrap extends SubDirective
{
/** @var string */
private $class;
/** @var bool */
private $uniqid;
public function __construct(string $class, bool $uniqid = false)
{
$this->class = $class;
$this->uniqid = $uniqid;
}
public function getName(): string
{
return $this->class;
}
/** @param string[] $options */
public function processSub(
Parser $parser,
?Node $document,
string $variable,
string $data,
array $options
): ?Node {
// if there is a "Wrap" directive (e.g. a note::), blank content is unexpected
if ($document === null) {
throw new RuntimeException('Content expected, none found.');
}
if ($this->uniqid) {
$id = uniqid($this->class);
} else {
$id = '';
}
$divOpen = $parser->renderTemplate('div-open.html.twig', [
'id' => $id,
'class' => $this->class,
]);
return $parser->getNodeFactory()->createWrapperNode(
$document,
$divOpen,
'</div>'
);
}
}

View file

@ -0,0 +1,197 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML;
use Doctrine\RST\Directives\Directive;
use Doctrine\RST\Formats\Format;
use Doctrine\RST\HTML;
use Doctrine\RST\Nodes;
use Doctrine\RST\Renderers;
use Doctrine\RST\Renderers\CallableNodeRendererFactory;
use Doctrine\RST\Renderers\NodeRendererFactory;
use Doctrine\RST\Templates\TemplateRenderer;
final class HTMLFormat implements Format
{
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(TemplateRenderer $templateRenderer)
{
$this->templateRenderer = $templateRenderer;
}
public function getFileExtension(): string
{
return Format::HTML;
}
/** @return Directive[] */
public function getDirectives(): array
{
return [
new HTML\Directives\Image(),
new HTML\Directives\Figure(),
new HTML\Directives\Meta(),
new HTML\Directives\Stylesheet(),
new HTML\Directives\Title(),
new HTML\Directives\Url(),
new HTML\Directives\Div(),
new HTML\Directives\Wrap('note'),
new HTML\Directives\ClassDirective(),
];
}
/** @return NodeRendererFactory[] */
public function getNodeRendererFactories(): array
{
return [
Nodes\AnchorNode::class => new CallableNodeRendererFactory(
function (Nodes\AnchorNode $node): HTML\Renderers\AnchorNodeRenderer {
return new HTML\Renderers\AnchorNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\CodeNode::class => new CallableNodeRendererFactory(
function (Nodes\CodeNode $node): HTML\Renderers\CodeNodeRenderer {
return new HTML\Renderers\CodeNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\DefinitionListNode::class => new CallableNodeRendererFactory(
function (Nodes\DefinitionListNode $node): HTML\Renderers\DefinitionListNodeRenderer {
return new HTML\Renderers\DefinitionListNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\FigureNode::class => new CallableNodeRendererFactory(
function (Nodes\FigureNode $node): HTML\Renderers\FigureNodeRenderer {
return new HTML\Renderers\FigureNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\ImageNode::class => new CallableNodeRendererFactory(
function (Nodes\ImageNode $node): HTML\Renderers\ImageNodeRenderer {
return new HTML\Renderers\ImageNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\ListNode::class => new CallableNodeRendererFactory(
function (Nodes\ListNode $node): HTML\Renderers\ListNodeRenderer {
return new HTML\Renderers\ListNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\MetaNode::class => new CallableNodeRendererFactory(
function (Nodes\MetaNode $node): HTML\Renderers\MetaNodeRenderer {
return new HTML\Renderers\MetaNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\ParagraphNode::class => new CallableNodeRendererFactory(
function (Nodes\ParagraphNode $node): HTML\Renderers\ParagraphNodeRenderer {
return new HTML\Renderers\ParagraphNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\QuoteNode::class => new CallableNodeRendererFactory(
function (Nodes\QuoteNode $node): HTML\Renderers\QuoteNodeRenderer {
return new HTML\Renderers\QuoteNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\SeparatorNode::class => new CallableNodeRendererFactory(
function (Nodes\SeparatorNode $node): HTML\Renderers\SeparatorNodeRenderer {
return new HTML\Renderers\SeparatorNodeRenderer(
$this->templateRenderer
);
}
),
Nodes\TableNode::class => new CallableNodeRendererFactory(
function (Nodes\TableNode $node): HTML\Renderers\TableNodeRenderer {
return new HTML\Renderers\TableNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\TitleNode::class => new CallableNodeRendererFactory(
function (Nodes\TitleNode $node): HTML\Renderers\TitleNodeRenderer {
return new HTML\Renderers\TitleNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\TocNode::class => new CallableNodeRendererFactory(
function (Nodes\TocNode $node): HTML\Renderers\TocNodeRenderer {
return new HTML\Renderers\TocNodeRenderer(
$node->getEnvironment(),
$node,
$this->templateRenderer
);
}
),
Nodes\DocumentNode::class => new CallableNodeRendererFactory(
function (Nodes\DocumentNode $node): HTML\Renderers\DocumentNodeRenderer {
return new HTML\Renderers\DocumentNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\SpanNode::class => new CallableNodeRendererFactory(
function (Nodes\SpanNode $node): HTML\Renderers\SpanNodeRenderer {
return new HTML\Renderers\SpanNodeRenderer(
$node->getEnvironment(),
$node,
$this->templateRenderer
);
}
),
Nodes\CallableNode::class => new CallableNodeRendererFactory(
static function (Nodes\CallableNode $node): Renderers\CallableNodeRenderer {
return new Renderers\CallableNodeRenderer(
$node
);
}
),
Nodes\SectionBeginNode::class => new CallableNodeRendererFactory(
function (Nodes\SectionBeginNode $node): HTML\Renderers\SectionBeginNodeRenderer {
return new HTML\Renderers\SectionBeginNodeRenderer(
$node,
$this->templateRenderer
);
}
),
Nodes\SectionEndNode::class => new CallableNodeRendererFactory(
function (Nodes\SectionEndNode $node): HTML\Renderers\SectionEndNodeRenderer {
return new HTML\Renderers\SectionEndNodeRenderer(
$node,
$this->templateRenderer
);
}
),
];
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\AnchorNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class AnchorNodeRenderer implements NodeRenderer
{
/** @var AnchorNode */
private $anchorNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(AnchorNode $anchorNode, TemplateRenderer $templateRenderer)
{
$this->anchorNode = $anchorNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('anchor.html.twig', [
'anchorNode' => $this->anchorNode,
]);
}
}

View file

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\CodeNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class CodeNodeRenderer implements NodeRenderer
{
/** @var CodeNode */
private $codeNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(CodeNode $codeNode, TemplateRenderer $templateRenderer)
{
$this->codeNode = $codeNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
if ($this->codeNode->isRaw()) {
return $this->codeNode->getValue();
}
return $this->templateRenderer->render('code.html.twig', [
'codeNode' => $this->codeNode,
]);
}
}

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\DefinitionListNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class DefinitionListNodeRenderer implements NodeRenderer
{
/** @var DefinitionListNode */
private $definitionListNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(DefinitionListNode $definitionListNode, TemplateRenderer $templateRenderer)
{
$this->definitionListNode = $definitionListNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('definition-list.html.twig', [
'definitionListNode' => $this->definitionListNode,
'definitionList' => $this->definitionListNode->getDefinitionList(),
]);
}
}

View file

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\DocumentNode;
use Doctrine\RST\Renderers\DocumentNodeRenderer as BaseDocumentRender;
use Doctrine\RST\Renderers\FullDocumentNodeRenderer;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
use Gajus\Dindent\Indenter;
final class DocumentNodeRenderer implements NodeRenderer, FullDocumentNodeRenderer
{
/** @var DocumentNode */
private $document;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(DocumentNode $document, TemplateRenderer $templateRenderer)
{
$this->document = $document;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return (new BaseDocumentRender($this->document))->render();
}
public function renderDocument(): string
{
$headerNodes = '';
foreach ($this->document->getHeaderNodes() as $node) {
$headerNodes .= $node->render() . "\n";
}
$html = $this->templateRenderer->render('document.html.twig', [
'headerNodes' => $headerNodes,
'bodyNodes' => $this->render(),
]);
if ($this->document->getConfiguration()->getIndentHTML()) {
return $this->indentHTML($html);
}
return $html;
}
private function indentHTML(string $html): string
{
return (new Indenter())->indent($html);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\FigureNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class FigureNodeRenderer implements NodeRenderer
{
/** @var FigureNode */
private $figureNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(FigureNode $figureNode, TemplateRenderer $templateRenderer)
{
$this->figureNode = $figureNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('figure.html.twig', [
'figureNode' => $this->figureNode,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\ImageNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class ImageNodeRenderer implements NodeRenderer
{
/** @var ImageNode */
private $imageNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(ImageNode $imageNode, TemplateRenderer $templateRenderer)
{
$this->imageNode = $imageNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('image.html.twig', [
'imageNode' => $this->imageNode,
]);
}
}

View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\ListNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class ListNodeRenderer implements NodeRenderer
{
/** @var ListNode */
private $listNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(ListNode $listNode, TemplateRenderer $templateRenderer)
{
$this->listNode = $listNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
$template = 'bullet-list.html.twig';
if ($this->listNode->isOrdered()) {
$template = 'enumerated-list.html.twig';
}
return $this->templateRenderer->render($template, ['listNode' => $this->listNode]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\MetaNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class MetaNodeRenderer implements NodeRenderer
{
/** @var MetaNode */
private $metaNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(MetaNode $metaNode, TemplateRenderer $templateRenderer)
{
$this->metaNode = $metaNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('meta.html.twig', [
'metaNode' => $this->metaNode,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\ParagraphNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class ParagraphNodeRenderer implements NodeRenderer
{
/** @var ParagraphNode */
private $paragraphNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(ParagraphNode $paragraphNode, TemplateRenderer $templateRenderer)
{
$this->paragraphNode = $paragraphNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('paragraph.html.twig', [
'paragraphNode' => $this->paragraphNode,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\QuoteNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class QuoteNodeRenderer implements NodeRenderer
{
/** @var QuoteNode */
private $quoteNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(QuoteNode $quoteNode, TemplateRenderer $templateRenderer)
{
$this->quoteNode = $quoteNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('quote.html.twig', [
'quoteNode' => $this->quoteNode,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\SectionBeginNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class SectionBeginNodeRenderer implements NodeRenderer
{
/** @var SectionBeginNode */
private $sectionBeginNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(SectionBeginNode $sectionBeginNode, TemplateRenderer $templateRenderer)
{
$this->sectionBeginNode = $sectionBeginNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('section-begin.html.twig', [
'sectionBeginNode' => $this->sectionBeginNode,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\SectionEndNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class SectionEndNodeRenderer implements NodeRenderer
{
/** @var SectionEndNode */
private $sectionEndNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(SectionEndNode $sectionEndNode, TemplateRenderer $templateRenderer)
{
$this->sectionEndNode = $sectionEndNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('section-end.html.twig', [
'sectionEndNode' => $this->sectionEndNode,
]);
}
}

View file

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class SeparatorNodeRenderer implements NodeRenderer
{
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(TemplateRenderer $templateRenderer)
{
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('separator.html.twig');
}
}

View file

@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Environment;
use Doctrine\RST\Nodes\SpanNode;
use Doctrine\RST\References\ResolvedReference;
use Doctrine\RST\Renderers\SpanNodeRenderer as BaseSpanNodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
use function htmlspecialchars;
use function trim;
use const ENT_COMPAT;
final class SpanNodeRenderer extends BaseSpanNodeRenderer
{
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(
Environment $environment,
SpanNode $span,
TemplateRenderer $templateRenderer
) {
parent::__construct($environment, $span);
$this->templateRenderer = $templateRenderer;
}
public function emphasis(string $text): string
{
return $this->templateRenderer->render('emphasis.html.twig', ['text' => $text]);
}
public function strongEmphasis(string $text): string
{
return $this->templateRenderer->render('strong-emphasis.html.twig', ['text' => $text]);
}
public function nbsp(): string
{
return $this->templateRenderer->render('nbsp.html.twig');
}
public function br(): string
{
return $this->templateRenderer->render('br.html.twig');
}
public function literal(string $text): string
{
return $this->templateRenderer->render('literal.html.twig', ['text' => $text]);
}
/** @param mixed[] $attributes */
public function link(?string $url, string $title, array $attributes = []): string
{
$url = (string) $url;
return $this->templateRenderer->render('link.html.twig', [
'url' => $this->environment->generateUrl($url),
'title' => $title,
'attributes' => $attributes,
]);
}
public function escape(string $span): string
{
return htmlspecialchars($span, ENT_COMPAT);
}
/** @param mixed[] $value */
public function reference(ResolvedReference $reference, array $value): string
{
$text = (bool) $value['text'] ? $value['text'] : ($reference->getTitle() ?? '');
$text = trim($text);
// reference to another document
if ($reference->getUrl() !== null) {
$url = $reference->getUrl();
if ($value['anchor'] !== null) {
$url .= '#' . $value['anchor'];
}
$link = $this->link($url, $text, $reference->getAttributes());
// reference to anchor in existing document
} elseif ($value['url'] !== null) {
$url = $this->environment->getLink($value['url']);
$link = $this->link($url, $text, $reference->getAttributes());
} else {
$link = $this->link('#', $text . ' (unresolved reference)', $reference->getAttributes());
}
return $link;
}
}

View file

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\TableNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
use LogicException;
use function sprintf;
final class TableNodeRenderer implements NodeRenderer
{
/** @var TableNode */
private $tableNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(TableNode $tableNode, TemplateRenderer $templateRenderer)
{
$this->tableNode = $tableNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
$headers = $this->tableNode->getHeaders();
$rows = $this->tableNode->getData();
$tableHeaderRows = [];
foreach ($headers as $k => $isHeader) {
if ($isHeader === false) {
continue;
}
if (! isset($rows[$k])) {
throw new LogicException(sprintf('Row "%d" should be a header, but that row does not exist.', $k));
}
$tableHeaderRows[] = $rows[$k];
unset($rows[$k]);
}
return $this->templateRenderer->render('table.html.twig', [
'tableNode' => $this->tableNode,
'tableHeaderRows' => $tableHeaderRows,
'tableRows' => $rows,
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Nodes\TitleNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
final class TitleNodeRenderer implements NodeRenderer
{
/** @var TitleNode */
private $titleNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(TitleNode $titleNode, TemplateRenderer $templateRenderer)
{
$this->titleNode = $titleNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
return $this->templateRenderer->render('header-title.html.twig', [
'titleNode' => $this->titleNode,
]);
}
}

View file

@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\HTML\Renderers;
use Doctrine\RST\Environment;
use Doctrine\RST\Nodes\TocNode;
use Doctrine\RST\Renderers\NodeRenderer;
use Doctrine\RST\Templates\TemplateRenderer;
use function count;
use function is_array;
final class TocNodeRenderer implements NodeRenderer
{
/** @var Environment */
private $environment;
/** @var TocNode */
private $tocNode;
/** @var TemplateRenderer */
private $templateRenderer;
public function __construct(Environment $environment, TocNode $tocNode, TemplateRenderer $templateRenderer)
{
$this->environment = $environment;
$this->tocNode = $tocNode;
$this->templateRenderer = $templateRenderer;
}
public function render(): string
{
$options = $this->tocNode->getOptions();
if (isset($options['hidden'])) {
return '';
}
$tocItems = [];
foreach ($this->tocNode->getFiles() as $file) {
$reference = $this->environment->resolve('doc', $file);
if ($reference === null) {
continue;
}
$url = $this->environment->relativeUrl($reference->getUrl());
$this->buildLevel($url, $reference->getTitles(), 1, $tocItems, $file);
}
return $this->templateRenderer->render('toc.html.twig', [
'tocNode' => $this->tocNode,
'tocItems' => $tocItems,
]);
}
/**
* @param mixed[]|array $titles
* @param mixed[] $tocItems
*/
private function buildLevel(
?string $url,
array $titles,
int $level,
array &$tocItems,
string $file
): void {
foreach ($titles as $k => $entry) {
[$title, $children] = $entry;
[$title, $target] = $this->generateTarget(
$url,
$title,
// don't add anchor for first h1 in a different file (link directly to the file)
! ($level === 1 && $k === 0 && $file !== '/' . $this->environment->getCurrentFileName())
);
$tocItem = [
'targetId' => $this->generateTargetId($target),
'targetUrl' => $this->environment->generateUrl($target),
'title' => $title,
'level' => $level,
'children' => [],
];
// render children until we hit the configured maxdepth
if (count($children) > 0 && ! $this->tocNode->isTitlesOnly() && $level < $this->tocNode->getDepth()) {
$this->buildLevel($url, $children, $level + 1, $tocItem['children'], $file);
}
$tocItems[] = $tocItem;
}
}
private function generateTargetId(string $target): string
{
return Environment::slugify($target);
}
/**
* @param string[]|string $title
*
* @return mixed[]
*/
private function generateTarget(?string $url, $title, bool $withAnchor): array
{
$target = $url;
if ($withAnchor) {
$anchor = $this->generateAnchorFromTitle($title);
$target .= '#' . $anchor;
}
if (is_array($title)) {
[$title, $target] = $title;
$reference = $this->environment->resolve('doc', $target);
if ($reference === null) {
return [$title, $target];
}
$target = $this->environment->relativeUrl($reference->getUrl());
}
return [$title, $target];
}
/** @param string[]|string $title */
private function generateAnchorFromTitle($title): string
{
$slug = is_array($title)
? $title[1]
: $title;
return Environment::slugify($slug);
}
}