Skip to content

Commit 60cc7d9

Browse files
committed
[TASK] Warn about duplicate anchors
Sphinx also warns about these
1 parent bd86cd1 commit 60cc7d9

File tree

7 files changed

+126
-23
lines changed

7 files changed

+126
-23
lines changed

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

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use phpDocumentor\Guides\Compiler\CompilerContextInterface;
1717
use phpDocumentor\Guides\Compiler\NodeTransformer;
18+
use phpDocumentor\Guides\Exception\DuplicateLinkAnchorException;
1819
use phpDocumentor\Guides\Meta\InternalTarget;
1920
use phpDocumentor\Guides\Nodes\AnchorNode;
2021
use phpDocumentor\Guides\Nodes\DocumentNode;
@@ -66,14 +67,18 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext)
6667
}
6768

6869
$anchorName = $this->anchorReducer->reduceAnchor($node->toString());
69-
$compilerContext->getProjectNode()->addLinkTarget(
70-
$anchorName,
71-
new InternalTarget(
72-
$currentDocument->getFilePath(),
73-
$node->toString(),
74-
$title,
75-
),
76-
);
70+
try {
71+
$compilerContext->getProjectNode()->addLinkTarget(
72+
$anchorName,
73+
new InternalTarget(
74+
$currentDocument->getFilePath(),
75+
$node->toString(),
76+
$title,
77+
),
78+
);
79+
} catch (DuplicateLinkAnchorException $exception) {
80+
$this->logger?->warning($exception->getMessage(), $compilerContext->getLoggerInformation());
81+
}
7782

7883
return $node;
7984
}
@@ -82,15 +87,19 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext)
8287
$currentDocument = $this->documentStack->top();
8388
Assert::notNull($currentDocument);
8489
$anchorName = $node->getId();
85-
$compilerContext->getProjectNode()->addLinkTarget(
86-
$anchorName,
87-
new InternalTarget(
88-
$currentDocument->getFilePath(),
90+
try {
91+
$compilerContext->getProjectNode()->addLinkTarget(
8992
$anchorName,
90-
$node->getLinkText(),
91-
SectionNode::STD_TITLE,
92-
),
93-
);
93+
new InternalTarget(
94+
$currentDocument->getFilePath(),
95+
$anchorName,
96+
$node->getLinkText(),
97+
SectionNode::STD_TITLE,
98+
),
99+
);
100+
} catch (DuplicateLinkAnchorException $exception) {
101+
$this->logger?->warning($exception->getMessage(), $compilerContext->getLoggerInformation());
102+
}
94103

95104
return $node;
96105
}
@@ -175,9 +184,13 @@ private function addLinkTargetToProject(CompilerContextInterface $compilerContex
175184
return;
176185
}
177186

178-
$compilerContext->getProjectNode()->addLinkTarget(
179-
$internalTarget->getAnchor(),
180-
$internalTarget,
181-
);
187+
try {
188+
$compilerContext->getProjectNode()->addLinkTarget(
189+
$internalTarget->getAnchor(),
190+
$internalTarget,
191+
);
192+
} catch (DuplicateLinkAnchorException $exception) {
193+
$this->logger?->warning($exception->getMessage(), $compilerContext->getLoggerInformation());
194+
}
182195
}
183196
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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\Exception;
15+
16+
use Exception;
17+
18+
final class DuplicateLinkAnchorException extends Exception
19+
{
20+
}

packages/guides/src/Nodes/ProjectNode.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use DateTimeImmutable;
1717
use Exception;
1818
use phpDocumentor\Guides\Exception\DocumentEntryNotFound;
19+
use phpDocumentor\Guides\Exception\DuplicateLinkAnchorException;
1920
use phpDocumentor\Guides\Meta\CitationTarget;
2021
use phpDocumentor\Guides\Meta\InternalTarget;
2122
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
@@ -24,6 +25,7 @@
2425

2526
use function array_merge;
2627
use function array_unique;
28+
use function sprintf;
2729

2830
use const DATE_RFC2822;
2931

@@ -143,13 +145,19 @@ public function getCitationTarget(string $name): CitationTarget|null
143145
return $this->citationTargets[$name] ?? null;
144146
}
145147

148+
/** @throws DuplicateLinkAnchorException */
146149
public function addLinkTarget(string $anchorName, InternalTarget $target): void
147150
{
148-
if (!isset($this->internalLinkTargets[$target->getLinkType()])) {
149-
$this->internalLinkTargets[$target->getLinkType()] = [];
151+
$linkType = $target->getLinkType();
152+
if (!isset($this->internalLinkTargets[$linkType])) {
153+
$this->internalLinkTargets[$linkType] = [];
150154
}
151155

152-
$this->internalLinkTargets[$target->getLinkType()][$anchorName] = $target;
156+
if (isset($this->internalLinkTargets[$linkType][$anchorName]) && $linkType !== 'std:title') {
157+
throw new DuplicateLinkAnchorException(sprintf('Duplicate anchor "%s". There is already another anchor of that name in document "%s"', $anchorName, $this->internalLinkTargets[$linkType][$anchorName]->getDocumentPath()));
158+
}
159+
160+
$this->internalLinkTargets[$linkType][$anchorName] = $target;
153161
}
154162

155163
public function hasInternalTarget(string $anchorName, string $linkType = SectionNode::STD_LABEL): bool
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!-- content start -->
2+
<div class="section" id="overview">
3+
<a id="rst-overview"></a>
4+
<h1>Overview</h1>
5+
6+
<p>RST Overview content</p>
7+
8+
</div>
9+
<div class="section" id="overview-1">
10+
<a id="sphinx-overview"></a>
11+
<h1>Overview</h1>
12+
13+
<p>Sphinx Overview content</p>
14+
15+
<div class="section" id="somewhere-else">
16+
<h2>Somewhere else</h2>
17+
18+
<p>This is a link to the RST Overview: <a href="/index.html#rst-overview">Overview</a></p>
19+
20+
<div class="toc">
21+
<ul class="menu-level">
22+
<li class="toc-item">
23+
<a href="/page.html#page">Page</a>
24+
25+
26+
</li>
27+
</ul>
28+
</div>
29+
</div>
30+
</div>
31+
<!-- content end -->
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.WARNING: Duplicate anchor "rst-overview". There is already another anchor of that name in document "index" {"rst-file":"page.rst"} []
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.. _rst-overview:
2+
3+
Overview
4+
**********
5+
6+
RST Overview content
7+
8+
.. _sphinx-overview:
9+
10+
Overview
11+
*********
12+
13+
Sphinx Overview content
14+
15+
Somewhere else
16+
=============
17+
18+
This is a link to the RST Overview: :ref:`rst-overview`
19+
20+
.. toctree::
21+
:glob:
22+
23+
*
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. _rst-overview:
2+
3+
====
4+
Page
5+
====
6+
7+
RST Overview content

0 commit comments

Comments
 (0)