diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/EmbeddedUriParser.php b/packages/guides-restructured-text/src/RestructuredText/Parser/EmbeddedUriParser.php
new file mode 100644
index 000000000..4c7cc6b90
--- /dev/null
+++ b/packages/guides-restructured-text/src/RestructuredText/Parser/EmbeddedUriParser.php
@@ -0,0 +1,28 @@
+)?$/s', $text, $matches);
+
+ $text = $matches[1] === '' ? null : $matches[1];
+ $uri = $matches[1];
+
+ if (isset($matches[2])) {
+ // there is an embedded URI, text and URI are different
+ $uri = $matches[2];
+ } else {
+ $text = null;
+ }
+
+ return ['text' => $text, 'uri' => $uri];
+ }
+}
diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/InlineLexer.php b/packages/guides-restructured-text/src/RestructuredText/Parser/InlineLexer.php
index 42b253f2f..992625026 100644
--- a/packages/guides-restructured-text/src/RestructuredText/Parser/InlineLexer.php
+++ b/packages/guides-restructured-text/src/RestructuredText/Parser/InlineLexer.php
@@ -23,8 +23,6 @@ final class InlineLexer extends AbstractLexer
public const ANONYMOUS_END = 3;
public const LITERAL = 5;
public const BACKTICK = 6;
- public const EMBEDED_URL_START = 9;
- public const EMBEDED_URL_END = 10;
public const NAMED_REFERENCE = 11;
public const ANONYMOUSE_REFERENCE = 12;
public const COLON = 13;
@@ -62,8 +60,6 @@ protected function getCatchablePatterns(): array
'``.+?``(?!`)',
'_{2}',
'_',
- '<',
- '>',
'`',
':',
'|',
@@ -138,8 +134,6 @@ protected function getType(string &$value)
'**' => self::STRONG_DELIMITER,
'*' => self::EMPHASIS_DELIMITER,
'|' => self::VARIABLE_DELIMITER,
- '<' => self::EMBEDED_URL_START,
- '>' => self::EMBEDED_URL_END,
'_' => self::UNDERSCORE,
'__' => self::ANONYMOUS_END,
':' => self::COLON,
diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/AnonymousPhraseRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/AnonymousPhraseRule.php
index d0b3d0c9f..ddc721c86 100644
--- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/AnonymousPhraseRule.php
+++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/AnonymousPhraseRule.php
@@ -6,6 +6,7 @@
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
+use phpDocumentor\Guides\RestructuredText\Parser\EmbeddedUriParser;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
/**
@@ -20,6 +21,8 @@
*/
class AnonymousPhraseRule extends ReferenceRule
{
+ use EmbeddedUriParser;
+
public function applies(InlineLexer $lexer): bool
{
return $lexer->token?->type === InlineLexer::BACKTICK;
@@ -27,8 +30,7 @@ public function applies(InlineLexer $lexer): bool
public function apply(BlockContext $blockContext, InlineLexer $lexer): AbstractLinkInlineNode|null
{
- $text = '';
- $embeddedUrl = null;
+ $value = '';
$initialPosition = $lexer->token?->position;
$lexer->moveNext();
while ($lexer->token !== null) {
@@ -43,17 +45,10 @@ public function apply(BlockContext $blockContext, InlineLexer $lexer): AbstractL
$lexer->moveNext();
- return $this->createAnonymousReference($blockContext, $text, $embeddedUrl);
-
- case InlineLexer::EMBEDED_URL_START:
- $embeddedUrl = $this->parseEmbeddedUrl($lexer);
- if ($embeddedUrl === null) {
- $text .= '<';
- }
+ return $this->createAnonymousReference($blockContext, $value);
- break;
default:
- $text .= $lexer->token->value;
+ $value .= $lexer->token->value;
}
$lexer->moveNext();
@@ -64,9 +59,17 @@ public function apply(BlockContext $blockContext, InlineLexer $lexer): AbstractL
return null;
}
- private function createAnonymousReference(BlockContext $blockContext, string $link, string|null $embeddedUrl): AbstractLinkInlineNode
+ private function createAnonymousReference(BlockContext $blockContext, string $value): AbstractLinkInlineNode
{
- $node = $this->createReference($blockContext, $link, $embeddedUrl, false);
+ $parsed = $this->extractEmbeddedUri($value);
+ $link = $parsed['text'];
+ $uri = $parsed['uri'];
+ if ($link === null) {
+ $link = $uri;
+ $uri = null;
+ }
+
+ $node = $this->createReference($blockContext, $link, $uri, false);
$blockContext->getDocumentParserContext()->pushAnonymous($link);
return $node;
diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedPhraseRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedPhraseRule.php
index 98fb5555d..dcadf66aa 100644
--- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedPhraseRule.php
+++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedPhraseRule.php
@@ -6,6 +6,7 @@
use phpDocumentor\Guides\Nodes\Inline\InlineNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
+use phpDocumentor\Guides\RestructuredText\Parser\EmbeddedUriParser;
use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
/**
@@ -20,6 +21,8 @@
*/
class NamedPhraseRule extends ReferenceRule
{
+ use EmbeddedUriParser;
+
public function applies(InlineLexer $lexer): bool
{
return $lexer->token?->type === InlineLexer::BACKTICK;
@@ -27,8 +30,7 @@ public function applies(InlineLexer $lexer): bool
public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null
{
- $text = '';
- $embeddedUrl = null;
+ $value = '';
$initialPosition = $lexer->token?->position;
$lexer->moveNext();
while ($lexer->token !== null) {
@@ -42,25 +44,23 @@ public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNod
}
$lexer->moveNext();
- if ($text === '') {
- $text = $embeddedUrl ?? '';
- }
-
- return $this->createReference($blockContext, $text, $embeddedUrl);
- case InlineLexer::EMBEDED_URL_START:
- $embeddedUrl = $this->parseEmbeddedUrl($lexer);
- if ($embeddedUrl === null) {
- $text .= '<';
+ $parsed = $this->extractEmbeddedUri($value);
+ $text = $parsed['text'];
+ $uri = $parsed['uri'];
+ if ($text === null) {
+ $text = $uri;
+ $uri = null;
}
- break;
+ return $this->createReference($blockContext, $text, $uri);
+
case InlineLexer::WHITESPACE:
- $text .= ' ';
+ $value .= ' ';
break;
default:
- $text .= $lexer->token->value;
+ $value .= $lexer->token->value;
}
$lexer->moveNext();
diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/ReferenceRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/ReferenceRule.php
index 2c1bfc013..7398ba614 100644
--- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/ReferenceRule.php
+++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/ReferenceRule.php
@@ -8,7 +8,6 @@
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
use phpDocumentor\Guides\Nodes\Inline\HyperLinkNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
-use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
use function filter_var;
use function preg_replace;
@@ -41,35 +40,4 @@ protected function createReference(BlockContext $blockContext, string $link, str
return new HyperLinkNode($link, $targetLink);
}
-
- protected function parseEmbeddedUrl(InlineLexer $lexer): string|null
- {
- if ($lexer->token === null) {
- return null;
- }
-
- $startPosition = $lexer->token->position;
- $text = '';
-
- while ($lexer->moveNext()) {
- $token = $lexer->token;
- switch ($token->type) {
- case InlineLexer::BACKTICK:
- //We did not find the expected SpanLexer::EMBEDED_URL_END
- $this->rollback($lexer, $startPosition);
-
- return null;
-
- case InlineLexer::EMBEDED_URL_END:
- return $text;
-
- default:
- $text .= $token->value;
- }
- }
-
- $this->rollback($lexer, $startPosition);
-
- return null;
- }
}
diff --git a/packages/guides-restructured-text/src/RestructuredText/TextRoles/AbstractReferenceTextRole.php b/packages/guides-restructured-text/src/RestructuredText/TextRoles/AbstractReferenceTextRole.php
index e43890cbb..3b7e2a2f5 100644
--- a/packages/guides-restructured-text/src/RestructuredText/TextRoles/AbstractReferenceTextRole.php
+++ b/packages/guides-restructured-text/src/RestructuredText/TextRoles/AbstractReferenceTextRole.php
@@ -6,25 +6,15 @@
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext;
-use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer;
-use Psr\Log\LoggerInterface;
-
-use function sprintf;
-use function trim;
+use phpDocumentor\Guides\RestructuredText\Parser\EmbeddedUriParser;
/** @see https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#embedded-uris-and-aliases */
abstract class AbstractReferenceTextRole implements TextRole
{
+ use EmbeddedUriParser;
+
/** @see https://regex101.com/r/htMn5p/1 */
public const INTERLINK_REGEX = '/^([a-zA-Z0-9-_]+):(.*$)/';
- private readonly InlineLexer $lexer;
-
- public function __construct(
- private readonly LoggerInterface $logger,
- ) {
- // Do not inject the $lexer. It contains a state.
- $this->lexer = new InlineLexer();
- }
public function processNode(
DocumentParserContext $documentParserContext,
@@ -32,60 +22,9 @@ public function processNode(
string $content,
string $rawContent,
): AbstractLinkInlineNode {
- $referenceTarget = null;
- $value = null;
-
- $part = '';
- $this->lexer->setInput($content);
- $this->lexer->moveNext();
- $this->lexer->moveNext();
- while ($this->lexer->token !== null) {
- $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->debug(
- sprintf(
- 'Reference contains unexpected content after closing `>`, treating it as text like sphinx does: "%s"',
- $rawContent,
- ),
- $documentParserContext->getLoggerInformation(),
- );
- $part = $value . '<' . $part . '>';
- $value = null;
- break;
- }
-
- $referenceTarget = $part;
- $part = '';
-
- break 2;
- default:
- $part .= $token->value;
- }
-
- $this->lexer->moveNext();
- }
-
- $value .= trim($part);
-
- if ($referenceTarget === null) {
- $referenceTarget = $value;
- $value = null;
- }
+ $parsed = $this->extractEmbeddedUri($content);
- return $this->createNode($referenceTarget, $value, $role);
+ return $this->createNode($parsed['uri'], $parsed['text'], $role);
}
abstract protected function createNode(string $referenceTarget, string|null $referenceName, string $role): AbstractLinkInlineNode;
diff --git a/packages/guides-restructured-text/src/RestructuredText/TextRoles/DocReferenceTextRole.php b/packages/guides-restructured-text/src/RestructuredText/TextRoles/DocReferenceTextRole.php
index 4cf9c9e0d..25f1f1612 100644
--- a/packages/guides-restructured-text/src/RestructuredText/TextRoles/DocReferenceTextRole.php
+++ b/packages/guides-restructured-text/src/RestructuredText/TextRoles/DocReferenceTextRole.php
@@ -6,18 +6,11 @@
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
-use Psr\Log\LoggerInterface;
use function preg_match;
class DocReferenceTextRole extends AbstractReferenceTextRole
{
- public function __construct(
- protected readonly LoggerInterface $logger,
- ) {
- parent::__construct($this->logger);
- }
-
final public const NAME = 'doc';
public function getName(): string
diff --git a/packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericReferenceTextRole.php b/packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericReferenceTextRole.php
index 05db85099..43f9c47f0 100644
--- a/packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericReferenceTextRole.php
+++ b/packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericReferenceTextRole.php
@@ -7,7 +7,6 @@
use phpDocumentor\Guides\Nodes\Inline\AbstractLinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorReducer;
-use Psr\Log\LoggerInterface;
use function array_keys;
use function preg_match;
@@ -15,11 +14,9 @@
class GenericReferenceTextRole extends AbstractReferenceTextRole
{
public function __construct(
- protected readonly LoggerInterface $logger,
private readonly GenericLinkProvider $genericLinkProvider,
private readonly AnchorReducer $anchorReducer,
) {
- parent::__construct($this->logger);
}
public function getName(): string
diff --git a/packages/guides-restructured-text/tests/unit/Parser/InlineTokenParserTest.php b/packages/guides-restructured-text/tests/unit/Parser/InlineTokenParserTest.php
index fde2e723b..9516dde2c 100644
--- a/packages/guides-restructured-text/tests/unit/Parser/InlineTokenParserTest.php
+++ b/packages/guides-restructured-text/tests/unit/Parser/InlineTokenParserTest.php
@@ -4,7 +4,6 @@
namespace phpDocumentor\Guides\RestructuredText\Parser;
-use Monolog\Logger;
use phpDocumentor\Guides\Nodes\Inline\CitationInlineNode;
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
use phpDocumentor\Guides\Nodes\Inline\EmphasisInlineNode;
@@ -43,20 +42,18 @@
final class InlineTokenParserTest extends TestCase
{
- public Logger $logger;
private DocumentParserContext $documentParserContext;
private InlineParser $inlineTokenParser;
private DefaultTextRoleFactory $textRoleFactory;
public function setUp(): void
{
- $this->logger = new Logger('test');
$this->textRoleFactory = new DefaultTextRoleFactory(
new GenericTextRole(),
new LiteralTextRole(),
[
- new ReferenceTextRole($this->logger),
- new DocReferenceTextRole($this->logger),
+ new ReferenceTextRole(),
+ new DocReferenceTextRole(),
],
);
$this->documentParserContext = new DocumentParserContext(
@@ -167,19 +164,19 @@ public static function inlineNodeProvider(): array
new InlineCompoundNode([new HyperLinkNode('myref', 'myref')]),
],
'Named Reference, Phrased, With URL' => [
- '`myref
You can read more on the features of Embeddables objects in the documentation.
Doctrine has a few links that are between brackets (such as here)
+Links may use reserved characters as name like this one linking to the <head> element.
+But this <
is not a link >
.