From 87f3bfb18fe877d50d064c9acf0035560d60d508 Mon Sep 17 00:00:00 2001 From: Jaapio Date: Fri, 25 Oct 2024 17:25:10 +0200 Subject: [PATCH] Markdown supports more nesting on nodes than RST does. To support this we needed to add support for compound nodes. We tried to be backward compatible for people building their own template. This layer will be removed in v2 and therfor we do trigger deprecations. See #1161 Fixes: #1160 --- .../InlineParsers/AbstractInlineParser.php | 6 +-- .../AbstractInlineTextDecoratorParser.php | 14 +++--- .../Parsers/InlineParsers/EmphasisParser.php | 6 ++- .../InlineParsers/InlineCodeParser.php | 3 +- .../InlineParsers/InlineImageParser.php | 3 +- .../Parsers/InlineParsers/LinkParser.php | 6 ++- .../Parsers/InlineParsers/NewLineParser.php | 4 +- .../Parsers/InlineParsers/StrongParser.php | 6 ++- .../InlineRules/DefaultTextRoleRule.php | 4 +- .../Productions/InlineRules/EmphasisRule.php | 4 +- .../Productions/InlineRules/InlineRule.php | 4 +- .../InlineRules/InternalReferenceRule.php | 4 +- .../InlineRules/NamedPhraseRule.php | 4 +- .../InlineRules/NamedReferenceRule.php | 4 +- .../Productions/InlineRules/StrongRule.php | 4 +- .../Productions/InlineRules/TextRoleRule.php | 4 +- .../Parser/Productions/LineBlockRule.php | 4 +- .../RestructuredText/TextRoles/TextRole.php | 4 +- .../resources/template/rst/template.php | 2 +- .../template/html/inline/emphasis.html.twig | 6 ++- .../template/html/inline/link.html.twig | 8 ++- .../template/html/inline/strong.html.twig | 6 ++- .../resources/template/html/template.php | 3 +- .../Nodes/Inline/AbstractLinkInlineNode.php | 32 ++++++++++-- .../src/Nodes/Inline/BCInlineNodeBehavior.php | 50 +++++++++++++++++++ .../src/Nodes/Inline/EmphasisInlineNode.php | 26 ++++++++-- .../guides/src/Nodes/Inline/HyperLinkNode.php | 5 +- .../guides/src/Nodes/Inline/InlineNode.php | 2 +- .../src/Nodes/Inline/InlineNodeInterface.php | 23 +++++++++ .../src/Nodes/Inline/StrongInlineNode.php | 26 ++++++++-- .../guides/src/Nodes/InlineCompoundNode.php | 11 ++-- phpstan-baseline.neon | 35 +++++++++++++ psalm.xml | 2 + .../markdown/emphasis-md/expected/index.html | 4 +- .../tests/markdown/emphasis-md/input/index.md | 8 ++- 35 files changed, 270 insertions(+), 67 deletions(-) create mode 100644 packages/guides/src/Nodes/Inline/BCInlineNodeBehavior.php create mode 100644 packages/guides/src/Nodes/Inline/InlineNodeInterface.php diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineParser.php index fcef8c743..f87006f12 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineParser.php @@ -17,13 +17,13 @@ use League\CommonMark\Node\NodeWalker; use phpDocumentor\Guides\Markdown\ParserInterface; use phpDocumentor\Guides\MarkupLanguageParser; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; /** - * @template TValue as InlineNode + * @template TValue as InlineNodeInterface * @implements ParserInterface */ abstract class AbstractInlineParser implements ParserInterface { - abstract public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNode; + abstract public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNodeInterface; } diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineTextDecoratorParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineTextDecoratorParser.php index 3c9923c9e..a8abf2d59 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineTextDecoratorParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineTextDecoratorParser.php @@ -18,16 +18,16 @@ use League\CommonMark\Node\NodeWalkerEvent; use phpDocumentor\Guides\MarkupLanguageParser; use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\PlainTextInlineNode; use Psr\Log\LoggerInterface; use RuntimeException; use function count; use function sprintf; -use function var_export; /** - * @template TValue as InlineNode + * @template TValue as InlineNodeInterface * @extends AbstractInlineParser */ abstract class AbstractInlineTextDecoratorParser extends AbstractInlineParser @@ -40,7 +40,7 @@ public function __construct( } /** @return TValue */ - public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNode + public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNodeInterface { $content = []; @@ -66,12 +66,10 @@ public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMa if ($this->supportsCommonMarkNode($commonMarkNode)) { if (count($content) === 1 && $content[0] instanceof PlainTextInlineNode) { - return $this->createInlineNode($commonMarkNode, $content[0]->getValue()); + return $this->createInlineNode($commonMarkNode, $content[0]->getValue(), $content); } - $this->logger->warning(sprintf('%s CONTEXT: Content of emphasis could not be interpreted: %s', $this->getType(), var_export($content, true))); - - return $this->createInlineNode($commonMarkNode, null); + return $this->createInlineNode($commonMarkNode, null, $content); } $this->logger->warning(sprintf('%s context does not allow a %s node', $this->getType(), $commonMarkNode::class)); @@ -83,7 +81,7 @@ public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMa abstract protected function getType(): string; /** @return TValue */ - abstract protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNode; + abstract protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNodeInterface; abstract protected function supportsCommonMarkNode(CommonMarkNode $commonMarkNode): bool; diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/EmphasisParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/EmphasisParser.php index 6e047ce9b..7525b3abe 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/EmphasisParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/EmphasisParser.php @@ -17,6 +17,7 @@ use League\CommonMark\Node\Node as CommonMarkNode; use phpDocumentor\Guides\Nodes\Inline\EmphasisInlineNode; use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use Psr\Log\LoggerInterface; /** @extends AbstractInlineTextDecoratorParser */ @@ -35,9 +36,10 @@ protected function getType(): string return 'Emphasis'; } - protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNode + /** @param InlineNodeInterface[] $children */ + protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content, array $children = []): InlineNodeInterface { - return new EmphasisInlineNode($content ?? ''); + return new EmphasisInlineNode($content ?? '', $children); } protected function supportsCommonMarkNode(CommonMarkNode $commonMarkNode): bool diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineCodeParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineCodeParser.php index a06500ae1..a28e92275 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineCodeParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineCodeParser.php @@ -18,6 +18,7 @@ use League\CommonMark\Node\NodeWalker; use League\CommonMark\Node\NodeWalkerEvent; use phpDocumentor\Guides\MarkupLanguageParser; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\LiteralInlineNode; use function assert; @@ -25,7 +26,7 @@ /** @extends AbstractInlineParser */ final class InlineCodeParser extends AbstractInlineParser { - public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): LiteralInlineNode + public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNodeInterface { assert($current instanceof Code); diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineImageParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineImageParser.php index cc1815454..e9679f926 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineImageParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/InlineImageParser.php @@ -17,6 +17,7 @@ use League\CommonMark\Node\Node as CommonMarkNode; use phpDocumentor\Guides\Nodes\Inline\ImageInlineNode; use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use Psr\Log\LoggerInterface; use function assert; @@ -38,7 +39,7 @@ protected function getType(): string return 'Image'; } - protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNode + protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNodeInterface { assert($commonMarkNode instanceof Image); diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/LinkParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/LinkParser.php index 1a2a622ea..d4b640c9b 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/LinkParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/LinkParser.php @@ -17,6 +17,7 @@ use League\CommonMark\Node\Node as CommonMarkNode; use phpDocumentor\Guides\Nodes\Inline\HyperLinkNode; use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use Psr\Log\LoggerInterface; use function assert; @@ -42,7 +43,8 @@ protected function getType(): string return 'Link'; } - protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNode + /** @param InlineNodeInterface[] $children */ + protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content, array $children = []): InlineNodeInterface { assert($commonMarkNode instanceof Link); @@ -52,7 +54,7 @@ protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $url = substr($url, 0, -3); } - return new HyperLinkNode($content, $url); + return new HyperLinkNode($content, $url, $children); } protected function supportsCommonMarkNode(CommonMarkNode $commonMarkNode): bool diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/NewLineParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/NewLineParser.php index 86e30c7a5..f1a4a7101 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/NewLineParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/NewLineParser.php @@ -18,7 +18,7 @@ use League\CommonMark\Node\NodeWalker; use League\CommonMark\Node\NodeWalkerEvent; use phpDocumentor\Guides\MarkupLanguageParser; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\PlainTextInlineNode; /** @extends AbstractInlineParser */ @@ -28,7 +28,7 @@ public function __construct() { } - public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNode + public function parse(MarkupLanguageParser $parser, NodeWalker $walker, CommonMarkNode $current): InlineNodeInterface { return new PlainTextInlineNode(' '); } diff --git a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/StrongParser.php b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/StrongParser.php index 9c9cd1fda..bb31d6175 100644 --- a/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/StrongParser.php +++ b/packages/guides-markdown/src/Markdown/Parsers/InlineParsers/StrongParser.php @@ -16,6 +16,7 @@ use League\CommonMark\Extension\CommonMark\Node\Inline\Strong; use League\CommonMark\Node\Node as CommonMarkNode; use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\StrongInlineNode; use Psr\Log\LoggerInterface; @@ -35,9 +36,10 @@ protected function getType(): string return 'StrongDecorator'; } - protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content): InlineNode + /** @param InlineNodeInterface[] $children */ + protected function createInlineNode(CommonMarkNode $commonMarkNode, string|null $content, array $children = []): InlineNodeInterface { - return new StrongInlineNode($content ?? ''); + return new StrongInlineNode($content ?? '', $children); } protected function supportsCommonMarkNode(CommonMarkNode $commonMarkNode): bool diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/DefaultTextRoleRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/DefaultTextRoleRule.php index f54680da4..b02d6f7ce 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/DefaultTextRoleRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/DefaultTextRoleRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -27,7 +27,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::BACKTICK; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $text = ''; diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/EmphasisRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/EmphasisRule.php index ab8f06449..b4c4e3545 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/EmphasisRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/EmphasisRule.php @@ -14,7 +14,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; use phpDocumentor\Guides\Nodes\Inline\EmphasisInlineNode; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -28,7 +28,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::EMPHASIS_DELIMITER; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $text = ''; diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InlineRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InlineRule.php index 057862846..e569546a2 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InlineRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InlineRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -21,7 +21,7 @@ interface InlineRule { public function applies(InlineLexer $lexer): bool; - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null; + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null; public function getPriority(): int; } diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InternalReferenceRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InternalReferenceRule.php index 13dc4e4ad..646a7f737 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InternalReferenceRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/InternalReferenceRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -24,7 +24,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::UNDERSCORE; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $text = ''; $initialPosition = $lexer->token?->position; 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 c3243064e..508cc5b15 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 @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; use phpDocumentor\Guides\RestructuredText\Parser\References\EmbeddedReferenceParser; @@ -37,7 +37,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::BACKTICK; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $value = ''; $initialPosition = $lexer->token?->position; diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedReferenceRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedReferenceRule.php index 66d7bf133..d5736a878 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedReferenceRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedReferenceRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -35,7 +35,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::NAMED_REFERENCE; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $value = rtrim($lexer->token?->value ?? '', '_'); $node = $this->createReference($blockContext, $value); diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/StrongRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/StrongRule.php index be51e2d37..b9475a104 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/StrongRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/StrongRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\StrongInlineNode; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -28,7 +28,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::STRONG_DELIMITER; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $text = ''; diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/TextRoleRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/TextRoleRule.php index 75180b154..62d6c4218 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/TextRoleRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/TextRoleRule.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\InlineLexer; @@ -29,7 +29,7 @@ public function applies(InlineLexer $lexer): bool return $lexer->token?->type === InlineLexer::COLON; } - public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNode|null + public function apply(BlockContext $blockContext, InlineLexer $lexer): InlineNodeInterface|null { $domain = null; $role = null; diff --git a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/LineBlockRule.php b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/LineBlockRule.php index 38639317c..364625b06 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/LineBlockRule.php +++ b/packages/guides-restructured-text/src/RestructuredText/Parser/Productions/LineBlockRule.php @@ -14,7 +14,7 @@ namespace phpDocumentor\Guides\RestructuredText\Parser\Productions; use phpDocumentor\Guides\Nodes\CompoundNode; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\Nodes\Inline\NewlineInlineNode; use phpDocumentor\Guides\Nodes\Node; use phpDocumentor\Guides\RestructuredText\Nodes\ContainerNode; @@ -71,7 +71,7 @@ private function collectContentLines(BlockContext $blockContext): Buffer return $buffer; } - /** @return CompoundNode */ + /** @return CompoundNode */ private function createLine(BlockContext $blockContext, Buffer $buffer): CompoundNode { $line = $this->inlineMarkupRule->apply(new BlockContext( diff --git a/packages/guides-restructured-text/src/RestructuredText/TextRoles/TextRole.php b/packages/guides-restructured-text/src/RestructuredText/TextRoles/TextRole.php index 473cc00b7..1469c7c0b 100644 --- a/packages/guides-restructured-text/src/RestructuredText/TextRoles/TextRole.php +++ b/packages/guides-restructured-text/src/RestructuredText/TextRoles/TextRole.php @@ -13,7 +13,7 @@ namespace phpDocumentor\Guides\RestructuredText\TextRoles; -use phpDocumentor\Guides\Nodes\Inline\InlineNode; +use phpDocumentor\Guides\Nodes\Inline\InlineNodeInterface; use phpDocumentor\Guides\RestructuredText\Parser\DocumentParserContext; interface TextRole @@ -32,5 +32,5 @@ public function processNode( string $role, string $content, string $rawContent, - ): InlineNode; + ): InlineNodeInterface; } diff --git a/packages/guides-theme-rst/resources/template/rst/template.php b/packages/guides-theme-rst/resources/template/rst/template.php index 14bd87902..4b150dd8a 100644 --- a/packages/guides-theme-rst/resources/template/rst/template.php +++ b/packages/guides-theme-rst/resources/template/rst/template.php @@ -76,7 +76,6 @@ AnnotationListNode::class => 'body/annotation-list.rst.twig', // Inline ImageInlineNode::class => 'inline/image.rst.twig', - InlineCompoundNode::class => 'inline/inline-node.rst.twig', AbbreviationInlineNode::class => 'inline/textroles/abbreviation.rst.twig', CitationInlineNode::class => 'inline/citation.rst.twig', DocReferenceNode::class => 'inline/doc.rst.twig', @@ -91,6 +90,7 @@ StrongInlineNode::class => 'inline/strong.rst.twig', VariableInlineNode::class => 'inline/variable.rst.twig', GenericTextRoleInlineNode::class => 'inline/textroles/generic.rst.twig', + InlineCompoundNode::class => 'inline/inline-node.rst.twig', // Output as Metatags AuthorNode::class => 'structure/header/author.rst.twig', CopyrightNode::class => 'structure/header/copyright.rst.twig', diff --git a/packages/guides/resources/template/html/inline/emphasis.html.twig b/packages/guides/resources/template/html/inline/emphasis.html.twig index eca92aa7c..1708213e5 100644 --- a/packages/guides/resources/template/html/inline/emphasis.html.twig +++ b/packages/guides/resources/template/html/inline/emphasis.html.twig @@ -1 +1,5 @@ -{{- node.value -}} + + {%- for child in node.children -%} + {{- renderNode(child) -}} + {%- endfor -%} + diff --git a/packages/guides/resources/template/html/inline/link.html.twig b/packages/guides/resources/template/html/inline/link.html.twig index f92d44f61..a6db95ca3 100644 --- a/packages/guides/resources/template/html/inline/link.html.twig +++ b/packages/guides/resources/template/html/inline/link.html.twig @@ -3,8 +3,12 @@ {%- for key, value in attributes %} {{- key -}}="{{- value -}}"{% endfor -%} {%- if node.classes %} class="{{ node.classesString }}"{% endif -%} > - {{- node.value -}} + {%- for child in node.children -%} + {{- renderNode(child) -}} + {%- endfor -%} {%- else -%} - {{- node.value -}} + {%- for child in node.children -%} + {{- renderNode(child) -}} + {%- endfor -%} {%- endif -%} diff --git a/packages/guides/resources/template/html/inline/strong.html.twig b/packages/guides/resources/template/html/inline/strong.html.twig index 936f48e8d..77a6bc008 100644 --- a/packages/guides/resources/template/html/inline/strong.html.twig +++ b/packages/guides/resources/template/html/inline/strong.html.twig @@ -1 +1,5 @@ -{{- node.value -}} + +{%- for child in node.children -%} + {{- renderNode(child) -}} +{%- endfor -%} + diff --git a/packages/guides/resources/template/html/template.php b/packages/guides/resources/template/html/template.php index 21f5e1c62..89da801e1 100644 --- a/packages/guides/resources/template/html/template.php +++ b/packages/guides/resources/template/html/template.php @@ -83,7 +83,6 @@ EmbeddedFrame::class => 'body/embedded-frame.html.twig', // Inline ImageInlineNode::class => 'inline/image.html.twig', - InlineCompoundNode::class => 'inline/inline-node.html.twig', AbbreviationInlineNode::class => 'inline/textroles/abbreviation.html.twig', CitationInlineNode::class => 'inline/citation.html.twig', DocReferenceNode::class => 'inline/doc.html.twig', @@ -98,6 +97,8 @@ StrongInlineNode::class => 'inline/strong.html.twig', VariableInlineNode::class => 'inline/variable.html.twig', GenericTextRoleInlineNode::class => 'inline/textroles/generic.html.twig', + InlineCompoundNode::class => 'inline/inline-node.html.twig', + // Output as Metatags AuthorNode::class => 'structure/header/author.html.twig', CopyrightNode::class => 'structure/header/copyright.html.twig', diff --git a/packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php b/packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php index 3e1aa3dd0..5732d4ecc 100644 --- a/packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php +++ b/packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php @@ -13,13 +13,32 @@ namespace phpDocumentor\Guides\Nodes\Inline; -abstract class AbstractLinkInlineNode extends InlineNode implements LinkInlineNode +use Doctrine\Deprecations\Deprecation; +use phpDocumentor\Guides\Nodes\InlineCompoundNode; + +abstract class AbstractLinkInlineNode extends InlineCompoundNode implements LinkInlineNode { + use BCInlineNodeBehavior; + private string $url = ''; - public function __construct(string $type, private readonly string $targetReference, string $value = '') - { - parent::__construct($type, $value); + /** @param InlineNodeInterface[] $children */ + public function __construct( + private readonly string $type, + private readonly string $targetReference, + string $value = '', + array $children = [], + ) { + if (empty($children)) { + Deprecation::trigger( + 'phpdocumentor/guides', + 'https://github.com/phpDocumentor/guides/issues/1161', + 'Please provide the children as an array of InlineNodeInterface instances instead of a string.', + ); + $children = [new PlainTextInlineNode($value)]; + } + + parent::__construct($children); } public function getTargetReference(): string @@ -46,4 +65,9 @@ public function getDebugInformation(): array 'value' => $this->getValue(), ]; } + + public function getType(): string + { + return $this->type; + } } diff --git a/packages/guides/src/Nodes/Inline/BCInlineNodeBehavior.php b/packages/guides/src/Nodes/Inline/BCInlineNodeBehavior.php new file mode 100644 index 000000000..e34ca8538 --- /dev/null +++ b/packages/guides/src/Nodes/Inline/BCInlineNodeBehavior.php @@ -0,0 +1,50 @@ +toString(); + } + + /** @param InlineNodeInterface[]|string $value */ + public function setValue(mixed $value): void + { + if (is_string($value)) { + $value = [new PlainTextInlineNode($value)]; + + Deprecation::trigger( + 'phpdocumentor/guides', + 'https://github.com/phpDocumentor/guides/issues/1161', + 'Please provide the children as an array of InlineNodeInterface instances instead of a string.', + ); + } + + parent::setValue($value); + } + + abstract public function toString(): string; +} diff --git a/packages/guides/src/Nodes/Inline/EmphasisInlineNode.php b/packages/guides/src/Nodes/Inline/EmphasisInlineNode.php index ecb809008..1d4371aab 100644 --- a/packages/guides/src/Nodes/Inline/EmphasisInlineNode.php +++ b/packages/guides/src/Nodes/Inline/EmphasisInlineNode.php @@ -13,12 +13,32 @@ namespace phpDocumentor\Guides\Nodes\Inline; -final class EmphasisInlineNode extends InlineNode +use Doctrine\Deprecations\Deprecation; +use phpDocumentor\Guides\Nodes\InlineCompoundNode; + +final class EmphasisInlineNode extends InlineCompoundNode { + use BCInlineNodeBehavior; + public const TYPE = 'emphasis'; - public function __construct(string $value) + /** @param InlineNodeInterface[] $children */ + public function __construct(string $value, array $children = []) + { + if (empty($children)) { + $children = [new PlainTextInlineNode($value)]; + Deprecation::trigger( + 'phpdocumentor/guides', + 'https://github.com/phpDocumentor/guides/issues/1161', + 'Please provide the children as an array of InlineNodeInterface instances instead of a string.', + ); + } + + parent::__construct($children); + } + + public function getType(): string { - parent::__construct(self::TYPE, $value); + return self::TYPE; } } diff --git a/packages/guides/src/Nodes/Inline/HyperLinkNode.php b/packages/guides/src/Nodes/Inline/HyperLinkNode.php index 5ea04e8fe..89eef6f56 100644 --- a/packages/guides/src/Nodes/Inline/HyperLinkNode.php +++ b/packages/guides/src/Nodes/Inline/HyperLinkNode.php @@ -18,8 +18,9 @@ */ final class HyperLinkNode extends AbstractLinkInlineNode { - public function __construct(string $value, string $targetReference) + /** @param InlineNodeInterface[] $children */ + public function __construct(string $value, string $targetReference, array $children = []) { - parent::__construct('link', $targetReference, $value); + parent::__construct('link', $targetReference, $value, $children); } } diff --git a/packages/guides/src/Nodes/Inline/InlineNode.php b/packages/guides/src/Nodes/Inline/InlineNode.php index 3f8414d6c..59bc5f156 100644 --- a/packages/guides/src/Nodes/Inline/InlineNode.php +++ b/packages/guides/src/Nodes/Inline/InlineNode.php @@ -16,7 +16,7 @@ use phpDocumentor\Guides\Nodes\AbstractNode; /** @extends AbstractNode */ -abstract class InlineNode extends AbstractNode +abstract class InlineNode extends AbstractNode implements InlineNodeInterface { public function __construct(private readonly string $type, string $value = '') { diff --git a/packages/guides/src/Nodes/Inline/InlineNodeInterface.php b/packages/guides/src/Nodes/Inline/InlineNodeInterface.php new file mode 100644 index 000000000..50e67be65 --- /dev/null +++ b/packages/guides/src/Nodes/Inline/InlineNodeInterface.php @@ -0,0 +1,23 @@ + */ -final class InlineCompoundNode extends CompoundNode +/** @extends CompoundNode */ +class InlineCompoundNode extends CompoundNode implements InlineNodeInterface { public function toString(): string { @@ -33,4 +33,9 @@ public static function getPlainTextInlineNode(string $content): self { return new InlineCompoundNode([new PlainTextInlineNode($content)]); } + + public function getType(): string + { + return 'compound'; + } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0407e6f12..374965cf7 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -90,6 +90,11 @@ parameters: count: 1 path: packages/guides-graphs/src/Graphs/Renderer/PlantumlRenderer.php + - + message: "#^Method phpDocumentor\\\\Guides\\\\Markdown\\\\Parsers\\\\InlineParsers\\\\AbstractInlineTextDecoratorParser\\\\:\\:createInlineNode\\(\\) invoked with 3 parameters, 2 required\\.$#" + count: 2 + path: packages/guides-markdown/src/Markdown/Parsers/InlineParsers/AbstractInlineTextDecoratorParser.php + - message: "#^Cannot call method scalarNode\\(\\) on Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface\\|null\\.$#" count: 1 @@ -145,6 +150,36 @@ parameters: count: 1 path: packages/guides/src/DependencyInjection/GuidesExtension.php + - + message: "#^Parameter \\#1 \\$value \\(array\\\\|string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\AbstractLinkInlineNode\\:\\:setValue\\(\\) should be contravariant with parameter \\$value \\(mixed\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Node\\:\\:setValue\\(\\)$#" + count: 3 + path: packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php + + - + message: "#^Return type \\(string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\AbstractLinkInlineNode\\:\\:getValue\\(\\) should be compatible with return type \\(array\\\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\AbstractNode\\\\>\\:\\:getValue\\(\\)$#" + count: 1 + path: packages/guides/src/Nodes/Inline/AbstractLinkInlineNode.php + + - + message: "#^Parameter \\#1 \\$value \\(array\\\\|string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\EmphasisInlineNode\\:\\:setValue\\(\\) should be contravariant with parameter \\$value \\(mixed\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Node\\:\\:setValue\\(\\)$#" + count: 2 + path: packages/guides/src/Nodes/Inline/EmphasisInlineNode.php + + - + message: "#^Return type \\(string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\EmphasisInlineNode\\:\\:getValue\\(\\) should be compatible with return type \\(array\\\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\AbstractNode\\\\>\\:\\:getValue\\(\\)$#" + count: 1 + path: packages/guides/src/Nodes/Inline/EmphasisInlineNode.php + + - + message: "#^Parameter \\#1 \\$value \\(array\\\\|string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\StrongInlineNode\\:\\:setValue\\(\\) should be contravariant with parameter \\$value \\(mixed\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Node\\:\\:setValue\\(\\)$#" + count: 2 + path: packages/guides/src/Nodes/Inline/StrongInlineNode.php + + - + message: "#^Return type \\(string\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\Inline\\\\StrongInlineNode\\:\\:getValue\\(\\) should be compatible with return type \\(array\\\\) of method phpDocumentor\\\\Guides\\\\Nodes\\\\AbstractNode\\\\>\\:\\:getValue\\(\\)$#" + count: 1 + path: packages/guides/src/Nodes/Inline/StrongInlineNode.php + - message: "#^Property phpDocumentor\\\\Guides\\\\Renderer\\\\DocumentListIterator\\:\\:\\$currentDocument \\(WeakReference\\\\|null\\) does not accept WeakReference\\\\.$#" count: 1 diff --git a/psalm.xml b/psalm.xml index 29e1aefb7..d0cdb7cbf 100644 --- a/psalm.xml +++ b/psalm.xml @@ -19,6 +19,8 @@ + + diff --git a/tests/Integration/tests/markdown/emphasis-md/expected/index.html b/tests/Integration/tests/markdown/emphasis-md/expected/index.html index aa82e3c2b..e4ad4ab4a 100644 --- a/tests/Integration/tests/markdown/emphasis-md/expected/index.html +++ b/tests/Integration/tests/markdown/emphasis-md/expected/index.html @@ -2,7 +2,7 @@

Markdown with emphasis

-

Italic or Italic Bold or Bold

- +

Italic or Italic, Bold or Bold, Bold and Italic, Italic and Bold

+

test

diff --git a/tests/Integration/tests/markdown/emphasis-md/input/index.md b/tests/Integration/tests/markdown/emphasis-md/input/index.md index fc8f1bd97..2c3e78aea 100644 --- a/tests/Integration/tests/markdown/emphasis-md/input/index.md +++ b/tests/Integration/tests/markdown/emphasis-md/input/index.md @@ -1,4 +1,8 @@ # Markdown with emphasis -*Italic* or _Italic_ -**Bold** or __Bold__ +*Italic* or _Italic_, +**Bold** or __Bold__, +**Bold and _Italic_**, +_Italic and **Bold**_ + +[_test_](https://phpdoc.org)