Skip to content

Commit 16e4839

Browse files
committed
[FEATURE] Use :ref: Textrole to link to confvals and viewhelpers
1 parent e280832 commit 16e4839

File tree

20 files changed

+379
-169
lines changed

20 files changed

+379
-169
lines changed

packages/typo3-docs-theme/resources/config/typo3-docs-theme.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use phpDocumentor\Guides\RestructuredText\Parser\Productions\DocumentRule;
1919
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
2020
use T3Docs\Typo3DocsTheme\Api\Typo3ApiService;
21+
use T3Docs\Typo3DocsTheme\Compiler\NodeTransformers\CollectPrefixLinkTargetsTransformer;
2122
use T3Docs\Typo3DocsTheme\Compiler\NodeTransformers\ConfvalMenuNodeTransformer;
2223
use T3Docs\Typo3DocsTheme\Compiler\NodeTransformers\RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer;
2324
use T3Docs\Typo3DocsTheme\Directives\ConfvalMenuDirective;
@@ -82,6 +83,8 @@
8283
->bind('$startingRule', service(DirectiveContentRule::class))
8384
->instanceof(BaseDirective::class)
8485
->tag('phpdoc.guides.directive')
86+
->set(CollectPrefixLinkTargetsTransformer::class)
87+
->tag('phpdoc.guides.compiler.nodeTransformers')
8588
->set(ConfvalMenuNodeTransformer::class)
8689
->tag('phpdoc.guides.compiler.nodeTransformers')
8790
->set(RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer::class)
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace T3Docs\Typo3DocsTheme\Compiler\NodeTransformers;
15+
16+
use phpDocumentor\Guides\Compiler\CompilerContextInterface;
17+
use phpDocumentor\Guides\Compiler\NodeTransformer;
18+
use phpDocumentor\Guides\Exception\DuplicateLinkAnchorException;
19+
use phpDocumentor\Guides\Meta\InternalTarget;
20+
use phpDocumentor\Guides\Nodes\AnchorNode;
21+
use phpDocumentor\Guides\Nodes\DocumentNode;
22+
use phpDocumentor\Guides\Nodes\LinkTargetNode;
23+
use phpDocumentor\Guides\Nodes\MultipleLinkTargetsNode;
24+
use phpDocumentor\Guides\Nodes\Node;
25+
use phpDocumentor\Guides\Nodes\OptionalLinkTargetsNode;
26+
use phpDocumentor\Guides\Nodes\PrefixedLinkTargetNode;
27+
use phpDocumentor\Guides\Nodes\SectionNode;
28+
use phpDocumentor\Guides\ReferenceResolvers\AnchorNormalizer;
29+
use Psr\Log\LoggerInterface;
30+
use SplStack;
31+
use Webmozart\Assert\Assert;
32+
33+
use function sprintf;
34+
35+
/** @implements NodeTransformer<DocumentNode|AnchorNode|SectionNode> */
36+
final class CollectPrefixLinkTargetsTransformer implements NodeTransformer
37+
{
38+
/** @var SplStack<DocumentNode> */
39+
private readonly SplStack $documentStack;
40+
41+
public function __construct(
42+
private readonly AnchorNormalizer $anchorReducer,
43+
private LoggerInterface|null $logger = null,
44+
) {
45+
/*
46+
* TODO: remove stack here, as we should not have sub documents in this way, sub documents are
47+
* now produced by the {@see \phpDocumentor\Guides\RestructuredText\MarkupLanguageParser::getSubParser}
48+
* as this works right now in isolation includes do not work as they should.
49+
*/
50+
$this->documentStack = new SplStack();
51+
}
52+
53+
public function enterNode(Node $node, CompilerContextInterface $compilerContext): Node
54+
{
55+
if ($node instanceof DocumentNode) {
56+
$this->documentStack->push($node);
57+
return $node;
58+
}
59+
if ($node instanceof SectionNode) {
60+
return $node;
61+
}
62+
63+
if ($node instanceof LinkTargetNode) {
64+
if ($node instanceof OptionalLinkTargetsNode && $node->isNoindex()) {
65+
return $node;
66+
}
67+
if ($node->getLinkText() === SectionNode::STD_LABEL) {
68+
return $node;
69+
}
70+
71+
$currentDocument = $this->documentStack->top();
72+
Assert::notNull($currentDocument);
73+
$anchor = $this->anchorReducer->reduceAnchor($node->getId());
74+
$prefix = '';
75+
if ($node instanceof PrefixedLinkTargetNode) {
76+
$prefix = $node->getPrefix();
77+
}
78+
79+
$this->addLinkTargetToProject(
80+
$compilerContext,
81+
new InternalTarget(
82+
$currentDocument->getFilePath(),
83+
$prefix . $anchor,
84+
$node->getLinkText(),
85+
SectionNode::STD_LABEL,
86+
),
87+
);
88+
if ($node instanceof MultipleLinkTargetsNode) {
89+
foreach ($node->getAdditionalIds() as $id) {
90+
$anchor = $this->anchorReducer->reduceAnchor($id);
91+
$this->addLinkTargetToProject(
92+
$compilerContext,
93+
new InternalTarget(
94+
$currentDocument->getFilePath(),
95+
$prefix . $anchor,
96+
$node->getLinkText(),
97+
SectionNode::STD_LABEL,
98+
),
99+
);
100+
}
101+
}
102+
}
103+
104+
return $node;
105+
}
106+
107+
public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null
108+
{
109+
if ($node instanceof DocumentNode) {
110+
$this->documentStack->pop();
111+
}
112+
113+
return $node;
114+
}
115+
116+
public function supports(Node $node): bool
117+
{
118+
return $node instanceof DocumentNode || $node instanceof LinkTargetNode;
119+
}
120+
121+
public function getPriority(): int
122+
{
123+
// After CollectLinkTargetsTransformer
124+
return 4000;
125+
}
126+
127+
private function addLinkTargetToProject(CompilerContextInterface $compilerContext, InternalTarget $internalTarget): void
128+
{
129+
if ($compilerContext->getProjectNode()->hasInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType())) {
130+
$otherLink = $compilerContext->getProjectNode()->getInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType());
131+
$this->logger?->warning(
132+
sprintf(
133+
'Duplicate anchor "%s" for link type "%s" in document "%s". The anchor is already used at "%s"',
134+
$internalTarget->getAnchor(),
135+
$internalTarget->getLinkType(),
136+
$compilerContext->getDocumentNode()->getFilePath(),
137+
$otherLink?->getDocumentPath(),
138+
),
139+
$compilerContext->getLoggerInformation(),
140+
);
141+
142+
return;
143+
}
144+
145+
try {
146+
$compilerContext->getProjectNode()->addLinkTarget(
147+
$internalTarget->getAnchor(),
148+
$internalTarget,
149+
);
150+
} catch (DuplicateLinkAnchorException $exception) {
151+
$this->logger?->warning($exception->getMessage(), $compilerContext->getLoggerInformation());
152+
}
153+
}
154+
}

packages/typo3-docs-theme/src/Twig/TwigExtension.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use phpDocumentor\Guides\Nodes\Metadata\NoSearchNode;
1313
use phpDocumentor\Guides\Nodes\Metadata\OrphanNode;
1414
use phpDocumentor\Guides\Nodes\Node;
15+
use phpDocumentor\Guides\Nodes\PrefixedLinkTargetNode;
1516
use phpDocumentor\Guides\Nodes\SectionNode;
1617
use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface;
1718
use phpDocumentor\Guides\RenderContext;
@@ -201,27 +202,30 @@ public function isNoSearch(array $context): bool
201202
public function getRstCodeForLink(array $context, LinkTargetNode $linkTargetNode): string
202203
{
203204
$interlink = $this->themeSettings->getSettings('interlink_shortcode') !== '' ? $this->themeSettings->getSettings('interlink_shortcode') : 'somemanual';
204-
if ($linkTargetNode->getLinkType() === ConfvalNode::LINK_TYPE) {
205+
if ($linkTargetNode instanceof PrefixedLinkTargetNode && $linkTargetNode->getLinkType() === ConfvalNode::LINK_TYPE) {
205206
return sprintf(
206-
':confval:`%s <%s:%s>`',
207+
':ref:`%s <%s:%s%s>`',
207208
$linkTargetNode->getLinkText(),
208209
$interlink,
210+
$linkTargetNode->getPrefix(),
209211
$linkTargetNode->getId()
210212
);
211213
}
212-
if ($linkTargetNode->getLinkType() === ViewHelperNode::LINK_TYPE) {
214+
if ($linkTargetNode instanceof PrefixedLinkTargetNode && $linkTargetNode->getLinkType() === ViewHelperNode::LINK_TYPE) {
213215
return sprintf(
214-
':typo3:viewhelper:`%s <%s:%s>`',
216+
':ref:`%s <%s:%s%s>`',
215217
$linkTargetNode->getLinkText(),
216218
$interlink,
219+
$linkTargetNode->getPrefix(),
217220
$linkTargetNode->getId()
218221
);
219222
}
220-
if ($linkTargetNode->getLinkType() === ViewHelperArgumentNode::LINK_TYPE) {
223+
if ($linkTargetNode instanceof PrefixedLinkTargetNode && $linkTargetNode->getLinkType() === ViewHelperArgumentNode::LINK_TYPE) {
221224
return sprintf(
222-
':typo3:viewhelper-argument:`%s <%s:%s>`',
225+
':ref:`%s <%s:%s%s>`',
223226
$linkTargetNode->getLinkText(),
224227
$interlink,
228+
$linkTargetNode->getPrefix(),
225229
$linkTargetNode->getId()
226230
);
227231
}

tests/Integration/tests/confval/confval-basic/expected/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="sr-only">demo</h3>
1616
data-bs-toggle="modal"
1717
data-bs-target="#linkReferenceModal"
1818
data-id="confval-demo"
19-
data-rstCode=":confval:`demo &lt;somemanual:demo&gt;`"
19+
data-rstCode=":ref:`demo &lt;somemanual:confval-demo&gt;`"
2020
title="Reference this configuration value"><i
2121
class="fa-solid fa-paragraph"></i></a>
2222
</div>
@@ -41,7 +41,7 @@ <h3 class="sr-only">demo</h3>
4141
</dl>
4242
</section>
4343

44-
<p>See also <a href="#confval-demo">demo</a>.</p>
44+
<p>See also <a href="#confval-demo">demo</a> or <a href="#confval-demo">demo</a>.</p>
4545

4646
</section>
4747
<!-- content end -->

tests/Integration/tests/confval/confval-basic/input/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ Confval
99

1010
Some Text
1111

12-
See also :confval:`demo`.
12+
See also :confval:`demo` or :ref:`demo <confval-demo>`.

tests/Integration/tests/confval/confval-duplicate-with-name/expected/anotherDomain.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="sr-only">demo</h3>
1616
data-bs-toggle="modal"
1717
data-bs-target="#linkReferenceModal"
1818
data-id="confval-another-demo"
19-
data-rstCode=":confval:`demo &lt;somemanual:another-demo&gt;`"
19+
data-rstCode=":ref:`demo &lt;somemanual:confval-another-demo&gt;`"
2020
title="Reference this configuration value"><i
2121
class="fa-solid fa-paragraph"></i></a>
2222
</div>

tests/Integration/tests/confval/confval-duplicate-with-name/expected/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="sr-only">demo</h3>
1616
data-bs-toggle="modal"
1717
data-bs-target="#linkReferenceModal"
1818
data-id="confval-demo"
19-
data-rstCode=":confval:`demo &lt;somemanual:demo&gt;`"
19+
data-rstCode=":ref:`demo &lt;somemanual:confval-demo&gt;`"
2020
title="Reference this configuration value"><i
2121
class="fa-solid fa-paragraph"></i></a>
2222
</div>

tests/Integration/tests/confval/confval-duplicate/expected/anotherDomain.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="sr-only">demo</h3>
1616
data-bs-toggle="modal"
1717
data-bs-target="#linkReferenceModal"
1818
data-id="confval-demo"
19-
data-rstCode=":confval:`demo &lt;somemanual:demo&gt;`"
19+
data-rstCode=":ref:`demo &lt;somemanual:confval-demo&gt;`"
2020
title="Reference this configuration value"><i
2121
class="fa-solid fa-paragraph"></i></a>
2222
</div>

tests/Integration/tests/confval/confval-duplicate/expected/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="sr-only">demo</h3>
1616
data-bs-toggle="modal"
1717
data-bs-target="#linkReferenceModal"
1818
data-id="confval-demo"
19-
data-rstCode=":confval:`demo &lt;somemanual:demo&gt;`"
19+
data-rstCode=":ref:`demo &lt;somemanual:confval-demo&gt;`"
2020
title="Reference this configuration value"><i
2121
class="fa-solid fa-paragraph"></i></a>
2222
</div>

tests/Integration/tests/confval/confval-menu-tree-anchor/expected/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ <h3 class="sr-only">array of cObjects</h3>
6060
data-bs-toggle="modal"
6161
data-bs-target="#linkReferenceModal"
6262
data-id="confval-case-array"
63-
data-rstCode=":confval:`array of cObjects &lt;somemanual:case-array&gt;`"
63+
data-rstCode=":ref:`array of cObjects &lt;somemanual:confval-case-array&gt;`"
6464
title="Reference this configuration value"><i
6565
class="fa-solid fa-paragraph"></i></a>
6666
</div>
@@ -100,7 +100,7 @@ <h3 class="sr-only">cache</h3>
100100
data-bs-toggle="modal"
101101
data-bs-target="#linkReferenceModal"
102102
data-id="confval-case-cache"
103-
data-rstCode=":confval:`cache &lt;somemanual:case-cache&gt;`"
103+
data-rstCode=":ref:`cache &lt;somemanual:confval-case-cache&gt;`"
104104
title="Reference this configuration value"><i
105105
class="fa-solid fa-paragraph"></i></a>
106106
</div>
@@ -137,7 +137,7 @@ <h3 class="sr-only">default</h3>
137137
data-bs-toggle="modal"
138138
data-bs-target="#linkReferenceModal"
139139
data-id="confval-case-default"
140-
data-rstCode=":confval:`default &lt;somemanual:case-default&gt;`"
140+
data-rstCode=":ref:`default &lt;somemanual:confval-case-default&gt;`"
141141
title="Reference this configuration value"><i
142142
class="fa-solid fa-paragraph"></i></a>
143143
</div>
@@ -178,7 +178,7 @@ <h3 class="sr-only">if</h3>
178178
data-bs-toggle="modal"
179179
data-bs-target="#linkReferenceModal"
180180
data-id="confval-case-if"
181-
data-rstCode=":confval:`if &lt;somemanual:case-if&gt;`"
181+
data-rstCode=":ref:`if &lt;somemanual:confval-case-if&gt;`"
182182
title="Reference this configuration value"><i
183183
class="fa-solid fa-paragraph"></i></a>
184184
</div>

tests/Integration/tests/confval/confval-menu-tree-multiple/expected/index.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ <h3 class="sr-only">array of cObjects</h3>
6464
data-bs-toggle="modal"
6565
data-bs-target="#linkReferenceModal"
6666
data-id="confval-case-array"
67-
data-rstCode=":confval:`array of cObjects &lt;somemanual:case-array&gt;`"
67+
data-rstCode=":ref:`array of cObjects &lt;somemanual:confval-case-array&gt;`"
6868
title="Reference this configuration value"><i
6969
class="fa-solid fa-paragraph"></i></a>
7070
</div>
@@ -103,7 +103,7 @@ <h3 class="sr-only">cache</h3>
103103
data-bs-toggle="modal"
104104
data-bs-target="#linkReferenceModal"
105105
data-id="confval-case-cache"
106-
data-rstCode=":confval:`cache &lt;somemanual:case-cache&gt;`"
106+
data-rstCode=":ref:`cache &lt;somemanual:confval-case-cache&gt;`"
107107
title="Reference this configuration value"><i
108108
class="fa-solid fa-paragraph"></i></a>
109109
</div>
@@ -139,7 +139,7 @@ <h3 class="sr-only">default</h3>
139139
data-bs-toggle="modal"
140140
data-bs-target="#linkReferenceModal"
141141
data-id="confval-case-default"
142-
data-rstCode=":confval:`default &lt;somemanual:case-default&gt;`"
142+
data-rstCode=":ref:`default &lt;somemanual:confval-case-default&gt;`"
143143
title="Reference this configuration value"><i
144144
class="fa-solid fa-paragraph"></i></a>
145145
</div>
@@ -178,7 +178,7 @@ <h3 class="sr-only">if</h3>
178178
data-bs-toggle="modal"
179179
data-bs-target="#linkReferenceModal"
180180
data-id="confval-case-if"
181-
data-rstCode=":confval:`if &lt;somemanual:case-if&gt;`"
181+
data-rstCode=":ref:`if &lt;somemanual:confval-case-if&gt;`"
182182
title="Reference this configuration value"><i
183183
class="fa-solid fa-paragraph"></i></a>
184184
</div>
@@ -254,7 +254,7 @@ <h3 class="sr-only">1,2,3,4...</h3>
254254
data-bs-toggle="modal"
255255
data-bs-target="#linkReferenceModal"
256256
data-id="confval-coa-array"
257-
data-rstCode=":confval:`1,2,3,4... &lt;somemanual:coa-array&gt;`"
257+
data-rstCode=":ref:`1,2,3,4... &lt;somemanual:confval-coa-array&gt;`"
258258
title="Reference this configuration value"><i
259259
class="fa-solid fa-paragraph"></i></a>
260260
</div>
@@ -291,7 +291,7 @@ <h3 class="sr-only">cache</h3>
291291
data-bs-toggle="modal"
292292
data-bs-target="#linkReferenceModal"
293293
data-id="confval-coa-cache"
294-
data-rstCode=":confval:`cache &lt;somemanual:coa-cache&gt;`"
294+
data-rstCode=":ref:`cache &lt;somemanual:confval-coa-cache&gt;`"
295295
title="Reference this configuration value"><i
296296
class="fa-solid fa-paragraph"></i></a>
297297
</div>
@@ -327,7 +327,7 @@ <h3 class="sr-only">if</h3>
327327
data-bs-toggle="modal"
328328
data-bs-target="#linkReferenceModal"
329329
data-id="confval-coa-if"
330-
data-rstCode=":confval:`if &lt;somemanual:coa-if&gt;`"
330+
data-rstCode=":ref:`if &lt;somemanual:confval-coa-if&gt;`"
331331
title="Reference this configuration value"><i
332332
class="fa-solid fa-paragraph"></i></a>
333333
</div>

0 commit comments

Comments
 (0)