Skip to content

Commit ea130b1

Browse files
committed
[BUGFIX] Make links to special objects prefixable
If we have both an anchor like '.. _demo:' and a confval of the same name we would get duplicate id's and the links to those two elements could not be distinguished. Sphinx solves this by prefixing all confval links with "confval-". Therefore I introduces the possibility of prefixing links to destinguished linkable objects. related #924 releases: main, 1.0
1 parent 3896e4f commit ea130b1

File tree

13 files changed

+81
-11
lines changed

13 files changed

+81
-11
lines changed

packages/guides-restructured-text/resources/template/html/body/directive/confval.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<dl class="confval">
2-
<dt id="{{ node.id }}">
2+
<dt id="{{ node.anchor }}">
33
<code class="sig-name descname"><span class="pre">{{ node.plainContent }}</span></code></dt>
44
<dd>
55
<div class="line-block">

packages/guides-restructured-text/src/RestructuredText/Directives/ConfvalDirective.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(
4444
) {
4545
parent::__construct($startingRule);
4646

47-
$genericLinkProvider->addGenericLink(self::NAME, ConfvalNode::LINK_TYPE);
47+
$genericLinkProvider->addGenericLink(self::NAME, ConfvalNode::LINK_TYPE, ConfvalNode::LINK_PREFIX);
4848
}
4949

5050
public function getName(): string

packages/guides-restructured-text/src/RestructuredText/Nodes/ConfvalNode.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
use phpDocumentor\Guides\Nodes\CompoundNode;
1717
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
18-
use phpDocumentor\Guides\Nodes\LinkTargetNode;
1918
use phpDocumentor\Guides\Nodes\Node;
19+
use phpDocumentor\Guides\Nodes\PrefixedLinkTargetNode;
2020

2121
/**
2222
* The confval directive configuration values.
@@ -25,9 +25,10 @@
2525
*
2626
* @extends CompoundNode<Node>
2727
*/
28-
final class ConfvalNode extends CompoundNode implements LinkTargetNode
28+
final class ConfvalNode extends CompoundNode implements PrefixedLinkTargetNode
2929
{
3030
public const LINK_TYPE = 'std:confval';
31+
public const LINK_PREFIX = 'confval-';
3132

3233
/**
3334
* @param list<Node> $value
@@ -60,6 +61,11 @@ public function getId(): string
6061
return $this->id;
6162
}
6263

64+
public function getAnchor(): string
65+
{
66+
return self::LINK_PREFIX . $this->id;
67+
}
68+
6369
public function getLinkText(): string
6470
{
6571
return $this->plainContent;
@@ -85,4 +91,9 @@ public function getAdditionalOptions(): array
8591
{
8692
return $this->additionalOptions;
8793
}
94+
95+
public function getPrefix(): string
96+
{
97+
return self::LINK_PREFIX;
98+
}
8899
}

packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericLinkProvider.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ final class GenericLinkProvider
3030
private array $textRoleLinkTypeMapping = [
3131
'ref' => SectionNode::STD_LABEL,
3232
];
33+
/** @var array<string, string> */
34+
private array $prefixLinkTypeMapping = ['ref' => ''];
3335

34-
public function addGenericLink(string $textRole, string $linkType): void
36+
public function addGenericLink(string $textRole, string $linkType, string $prefix = ''): void
3537
{
3638
$this->textRoleLinkTypeMapping[$textRole] = $linkType;
39+
$this->prefixLinkTypeMapping[$textRole] = $prefix;
3740
}
3841

3942
/** @return string[] */
@@ -46,4 +49,9 @@ public function getLinkType(string $textRole): string
4649
{
4750
return $this->textRoleLinkTypeMapping[$textRole] ?? SectionNode::STD_LABEL;
4851
}
52+
53+
public function getLinkPrefix(string $textRole): string
54+
{
55+
return $this->prefixLinkTypeMapping[$textRole] ?? '';
56+
}
4957
}

packages/guides-restructured-text/src/RestructuredText/TextRoles/GenericReferenceTextRole.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ protected function createNode(string $referenceTarget, string|null $referenceNam
4646
$linkType = $this->genericLinkProvider->getLinkType($role);
4747
$interlinkData = $this->interlinkParser->extractInterlink($referenceTarget);
4848
$reference = $this->anchorReducer->reduceAnchor($interlinkData->reference);
49+
$prefix = $this->genericLinkProvider->getLinkPrefix($role);
4950

50-
return new ReferenceNode($reference, $referenceName ?? '', $interlinkData->interlink, $linkType);
51+
return new ReferenceNode($reference, $referenceName ?? '', $interlinkData->interlink, $linkType, $prefix);
5152
}
5253
}

packages/guides/src/Compiler/NodeTransformers/CollectLinkTargetsTransformer.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use phpDocumentor\Guides\Nodes\LinkTargetNode;
2222
use phpDocumentor\Guides\Nodes\MultipleLinkTargetsNode;
2323
use phpDocumentor\Guides\Nodes\Node;
24+
use phpDocumentor\Guides\Nodes\PrefixedLinkTargetNode;
2425
use phpDocumentor\Guides\Nodes\SectionNode;
2526
use phpDocumentor\Guides\ReferenceResolvers\AnchorNormalizer;
2627
use SplStack;
@@ -68,13 +69,19 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
6869
$currentDocument = $this->documentStack->top();
6970
Assert::notNull($currentDocument);
7071
$anchor = $node->getId();
72+
$prefix = '';
73+
if ($node instanceof PrefixedLinkTargetNode) {
74+
$prefix = $node->getPrefix();
75+
}
76+
7177
$compilerContext->getProjectNode()->addLinkTarget(
7278
$anchor,
7379
new InternalTarget(
7480
$currentDocument->getFilePath(),
7581
$anchor,
7682
$node->getLinkText(),
7783
$node->getLinkType(),
84+
$prefix,
7885
),
7986
);
8087
if ($node instanceof MultipleLinkTargetsNode) {

packages/guides/src/Meta/InternalTarget.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public function __construct(
2424
protected string $anchorName,
2525
private readonly string|null $title = null,
2626
private readonly string $linkType = SectionNode::STD_LABEL,
27+
private readonly string $prefix = '',
2728
) {
2829
}
2930

@@ -63,4 +64,9 @@ public function getLinkType(): string
6364
{
6465
return $this->linkType;
6566
}
67+
68+
public function getPrefix(): string
69+
{
70+
return $this->prefix;
71+
}
6672
}

packages/guides/src/Nodes/Inline/ReferenceNode.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public function __construct(
3737
string $value = '',
3838
private readonly string $interlinkDomain = '',
3939
private readonly string $linkType = SectionNode::STD_LABEL,
40+
private readonly string $prefix = '',
4041
) {
4142
parent::__construct(self::TYPE, $targetReference, $value);
4243
}
@@ -62,6 +63,11 @@ public function getDebugInformation(): array
6263

6364
public function getInterlinkGroup(): string
6465
{
65-
return 'std:label';
66+
return $this->linkType;
67+
}
68+
69+
public function getPrefix(): string
70+
{
71+
return $this->prefix;
6672
}
6773
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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 phpDocumentor\Guides\Nodes;
15+
16+
interface PrefixedLinkTargetNode extends LinkTargetNode
17+
{
18+
public function getPrefix(): string;
19+
}

packages/guides/src/ReferenceResolvers/AnchorReferenceResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function resolve(LinkInlineNode $node, RenderContext $renderContext, Mess
4646
return false;
4747
}
4848

49-
$node->setUrl($this->urlGenerator->generateCanonicalOutputUrl($renderContext, $target->getDocumentPath(), $target->getAnchor()));
49+
$node->setUrl($this->urlGenerator->generateCanonicalOutputUrl($renderContext, $target->getDocumentPath(), $target->getPrefix() . $target->getAnchor()));
5050
if ($node->getValue() === '') {
5151
$node->setValue($target->getTitle() ?? '');
5252
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<!-- content start -->
22
<div class="section" id="confval-directive">
3+
<a id="demo"></a>
34
<h1>Confval directive</h1>
45

56
<dl class="confval">
6-
<dt id="demo">
7+
<dt id="confval-demo">
78
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
89
<dd>
910
<div class="line-block">
@@ -17,7 +18,8 @@ <h1>Confval directive</h1>
1718
</div>
1819
</dd>
1920
</dl>
20-
<p>See option <a href="/index.html#demo">demo</a>.</p>
21+
<p>See option <a href="/index.html#confval-demo">demo</a>. We can also link the
22+
headline: <a href="/index.html#demo">Confval directive</a>.</p>
2123
</div>
2224

2325
<!-- content end -->

tests/Integration/tests/confval/expected/objects.inv.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
"-",
1414
"index.html#confval-directive",
1515
"Confval directive"
16+
],
17+
"demo": [
18+
"-",
19+
"-",
20+
"index.html#demo",
21+
"Confval directive"
1622
]
1723
},
1824
"std:confval": {

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2+
.. _demo:
3+
14
Confval directive
25
=================
36

@@ -11,4 +14,5 @@ Confval directive
1114

1215
Another paragraph.
1316

14-
See option :confval:`demo`.
17+
See option :confval:`demo`. We can also link the
18+
headline: :ref:`demo`.

0 commit comments

Comments
 (0)