Skip to content

Commit

Permalink
[FEATURE] Introduce textroles for component (#28)
Browse files Browse the repository at this point in the history
* [TASK] Move shared functionality of textroles to common abstract class

* [Feature] Introduce :php:class: TextRole

* [Feature] Introduce :php:enum: TextRole

* [Feature] Introduce :php:trait: TextRole

* [Feature] Introduce :php:exception: TextRole

* Update src/TextRoles/PhpComponentTextRole.php

Co-authored-by: Chris Müller <2566282+brotkrueml@users.noreply.github.com>

---------

Co-authored-by: Chris Müller <2566282+brotkrueml@users.noreply.github.com>
  • Loading branch information
linawolf and brotkrueml authored Dec 12, 2023
1 parent 55fba46 commit e92c96e
Show file tree
Hide file tree
Showing 18 changed files with 486 additions and 94 deletions.
12 changes: 12 additions & 0 deletions resources/config/php-domain.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
use T3Docs\GuidesPhpDomain\Directives\Php\GlobalDirective;
use T3Docs\GuidesPhpDomain\Directives\Php\TraitDirective;
use T3Docs\GuidesPhpDomain\PhpDomain\ModifierService;
use T3Docs\GuidesPhpDomain\TextRoles\ClassTextRole;
use T3Docs\GuidesPhpDomain\TextRoles\EnumTextRole;
use T3Docs\GuidesPhpDomain\TextRoles\ExceptionTextRole;
use T3Docs\GuidesPhpDomain\TextRoles\TraitTextRole;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

use T3Docs\GuidesPhpDomain\Directives\Php\EnumDirective;
Expand Down Expand Up @@ -53,7 +57,15 @@
->set(ModifierService::class)
->set(NamespaceRepository::class)

->set(ClassTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role', ['domain' => 'php'])
->set(EnumTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role', ['domain' => 'php'])
->set(ExceptionTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role', ['domain' => 'php'])
->set(InterfaceTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role', ['domain' => 'php'])
->set(TraitTextRole::class)
->tag('phpdoc.guides.parser.rst.text_role', ['domain' => 'php'])
;
};
24 changes: 24 additions & 0 deletions src/TextRoles/ClassTextRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace T3Docs\GuidesPhpDomain\TextRoles;

use Doctrine\Common\Lexer\Token;
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

final class ClassTextRole extends PhpComponentTextRole
{
private const TYPE = 'class';

public function getName(): string
{
return self::TYPE;
}
}
24 changes: 24 additions & 0 deletions src/TextRoles/EnumTextRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace T3Docs\GuidesPhpDomain\TextRoles;

use Doctrine\Common\Lexer\Token;
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

final class EnumTextRole extends PhpComponentTextRole
{
private const TYPE = 'enum';

public function getName(): string
{
return self::TYPE;
}
}
41 changes: 41 additions & 0 deletions src/TextRoles/ExceptionTextRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace T3Docs\GuidesPhpDomain\TextRoles;

use Doctrine\Common\Lexer\Token;
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

final class ExceptionTextRole extends PhpComponentTextRole
{
private const TYPE = 'exception';

public function getAliases(): array
{
return ['exc'];
}

public function getName(): string
{
return self::TYPE;
}

public function processNode(
DocumentParserContext $documentParserContext,
string $role,
string $content,
string $rawContent,
): AbstractLinkInlineNode {
if ($role !== 'php:exception') {
$this->logger->warning(sprintf('Text role :%s: is deprecated. Use :php:exception: instead. ', $role), $documentParserContext->getLoggerInformation());
}
return parent::processNode($documentParserContext, $role, $content, $rawContent);
}
}
97 changes: 3 additions & 94 deletions src/TextRoles/InterfaceTextRole.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,103 +13,12 @@
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

final class InterfaceTextRole implements TextRole
final class InterfaceTextRole extends PhpComponentTextRole
{
/**
* @see https://regex101.com/r/OyN05v/1
*/
private const INTERLINK_NAME_REGEX = '/^([a-zA-Z0-9]+):(.*$)/';

private readonly InlineLexer $lexer;

public function __construct(
private readonly LoggerInterface $logger,
private readonly AnchorReducer $anchorReducer,
) {
// Do not inject the $lexer. It contains a state.
$this->lexer = new InlineLexer();
}
final public const NAME = 'interface';
private const TYPE = 'interface';

public function getName(): string
{
return self::NAME;
}
public function getAliases(): array
{
return [];
}

public function processNode(
DocumentParserContext $documentParserContext,
string $role,
string $content,
string $rawContent,
): AbstractLinkInlineNode {
$referenceTarget = null;
$value = null;

$part = '';
$this->lexer->setInput($rawContent);
$this->lexer->moveNext();
$this->lexer->moveNext();
while ($this->lexer->token instanceof Token) {
$token = $this->lexer->token;
switch ($token->type) {
case InlineLexer::EMBEDED_URL_START:
$value = trim($part);
$part = '';

break;
case InlineLexer::EMBEDED_URL_END:
if ($value === null) {
// not inside the embedded URL
$part .= $token->value;
break;
}

if ($this->lexer->peek() !== null) {
$this->logger->warning(
sprintf(
'Reference contains unexpected content after closing `>`: "%s"',
$content,
),
$documentParserContext->getLoggerInformation(),
);
}

$referenceTarget = $part;
$part = '';

break 2;
default:
$part .= $token->value;
}

$this->lexer->moveNext();
}

$value .= trim($part);

if ($referenceTarget === null) {
$referenceTarget = $value;
$value = null;
}

return $this->createNode($referenceTarget, $value, $role);
}

/** @return ReferenceNode */
protected function createNode(string $referenceTarget, string|null $referenceName, string $role): AbstractLinkInlineNode
{
if (preg_match(self::INTERLINK_NAME_REGEX, $referenceTarget, $matches)) {
$interlinkDomain = $matches[1];
$id = $this->anchorReducer->reduceAnchor($matches[2]);
} else {
$interlinkDomain = '';
$id = $this->anchorReducer->reduceAnchor($referenceTarget);
}

return new ReferenceNode($id, $referenceName ?? '', $interlinkDomain, 'php:interface');
return self::TYPE;
}
}
113 changes: 113 additions & 0 deletions src/TextRoles/PhpComponentTextRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

declare(strict_types=1);

namespace T3Docs\GuidesPhpDomain\TextRoles;

use Doctrine\Common\Lexer\Token;
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

abstract class PhpComponentTextRole implements TextRole
{
/**
* @see https://regex101.com/r/OyN05v/1
*/
private const INTERLINK_NAME_REGEX = '/^([a-zA-Z0-9]+):(.*$)/';

private readonly InlineLexer $lexer;

public function __construct(
protected readonly LoggerInterface $logger,
private readonly AnchorReducer $anchorReducer,
) {
// Do not inject the $lexer. It contains a state.
$this->lexer = new InlineLexer();
}

/**
* @return list<string>
*/
public function getAliases(): array
{
return [];
}

public function processNode(
DocumentParserContext $documentParserContext,
string $role,
string $content,
string $rawContent,
): AbstractLinkInlineNode {
$referenceTarget = null;
$value = null;

$part = '';
$this->lexer->setInput($rawContent);
$this->lexer->moveNext();
$this->lexer->moveNext();
while ($this->lexer->token instanceof Token) {
$token = $this->lexer->token;
switch ($token->type) {
case InlineLexer::EMBEDED_URL_START:
$value = trim($part);
$part = '';

break;
case InlineLexer::EMBEDED_URL_END:
if ($value === null) {
// not inside the embedded URL
$part .= $token->value;
break;
}

if ($this->lexer->peek() !== null) {
$this->logger->warning(
sprintf(
'Reference contains unexpected content after closing `>`: "%s"',
$content,
),
$documentParserContext->getLoggerInformation(),
);
}

$referenceTarget = $part;
$part = '';

break 2;
default:
$part .= $token->value;
}

$this->lexer->moveNext();
}

$value .= trim($part);

if ($referenceTarget === null) {
$referenceTarget = $value;
$value = null;
}

return $this->createNode($referenceTarget, $value, $role);
}

/** @return ReferenceNode */
protected function createNode(string $referenceTarget, string|null $referenceName, string $role): AbstractLinkInlineNode
{
if (preg_match(self::INTERLINK_NAME_REGEX, $referenceTarget, $matches)) {
$interlinkDomain = $matches[1];
$id = $this->anchorReducer->reduceAnchor($matches[2]);
} else {
$interlinkDomain = '';
$id = $this->anchorReducer->reduceAnchor($referenceTarget);
}

return new ReferenceNode($id, $referenceName ?? '', $interlinkDomain, 'php:' . $this->getName());
}
}
24 changes: 24 additions & 0 deletions src/TextRoles/TraitTextRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace T3Docs\GuidesPhpDomain\TextRoles;

use Doctrine\Common\Lexer\Token;
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use phpDocumentor\Guides\RestructuredText\TextRoles\TextRole;
use Psr\Log\LoggerInterface;

final class TraitTextRole extends PhpComponentTextRole
{
private const TYPE = 'trait';

public function getName(): string
{
return self::TYPE;
}
}
Loading

0 comments on commit e92c96e

Please sign in to comment.