Skip to content

Commit 3253a1b

Browse files
committed
[TASK] Warn about duplicate anchors in LinkTargetNode
Exclude section for now as this is a bit more tricky. releases: main, 1.0 (cherry picked from commit 17c3a07)
1 parent 098b439 commit 3253a1b

File tree

13 files changed

+290
-44
lines changed

13 files changed

+290
-44
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ protected function processSub(
6161
CollectionNode $collectionNode,
6262
Directive $directive,
6363
): Node|null {
64-
$id = $this->anchorReducer->reduceAnchor($directive->getData());
64+
$id = $directive->getData();
65+
if ($directive->hasOption('name')) {
66+
$id = (string) $directive->getOption('name')->getValue();
67+
}
68+
69+
$id = $this->anchorReducer->reduceAnchor($id);
6570
$type = null;
6671
$required = false;
6772
$default = null;
@@ -79,7 +84,7 @@ protected function processSub(
7984
}
8085

8186
foreach ($directive->getOptions() as $option) {
82-
if (in_array($option->getName(), ['type', 'required', 'default', 'noindex'], true)) {
87+
if (in_array($option->getName(), ['type', 'required', 'default', 'noindex', 'name'], true)) {
8388
continue;
8489
}
8590

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

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
5151
{
5252
if ($node instanceof DocumentNode) {
5353
$this->documentStack->push($node);
54-
} elseif ($node instanceof AnchorNode) {
54+
55+
return $node;
56+
}
57+
58+
if ($node instanceof AnchorNode) {
5559
$currentDocument = $compilerContext->getDocumentNode();
5660
$parentSection = $compilerContext->getShadowTree()->getParent()?->getNode();
5761
$title = null;
@@ -68,52 +72,48 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
6872
$title,
6973
),
7074
);
71-
} elseif ($node instanceof LinkTargetNode) {
75+
76+
return $node;
77+
}
78+
79+
if ($node instanceof SectionNode) {
80+
$currentDocument = $this->documentStack->top();
81+
Assert::notNull($currentDocument);
82+
$anchorName = $node->getId();
83+
$compilerContext->getProjectNode()->addLinkTarget(
84+
$anchorName,
85+
new InternalTarget(
86+
$currentDocument->getFilePath(),
87+
$anchorName,
88+
$node->getLinkText(),
89+
$node->getLinkType(),
90+
),
91+
);
92+
93+
return $node;
94+
}
95+
96+
if ($node instanceof LinkTargetNode) {
7297
$currentDocument = $this->documentStack->top();
7398
Assert::notNull($currentDocument);
74-
$anchor = $node->getId();
75-
if ($compilerContext->getProjectNode()->hasInternalTarget($anchor, $node->getLinkType())) {
76-
$this->logger?->warning(
77-
sprintf(
78-
'Duplicate anchor "%s" for link type "%s" in document "%s". The anchor is already used at "%s"',
79-
$anchor,
80-
$node->getLinkType(),
81-
$compilerContext->getDocumentNode()->getFilePath(),
82-
$compilerContext->getProjectNode()->getInternalTarget($anchor, $node->getLinkType())?->getDocumentPath(),
83-
),
84-
$compilerContext->getLoggerInformation(),
85-
);
86-
} else {
87-
$compilerContext->getProjectNode()->addLinkTarget(
99+
$anchor = $this->anchorReducer->reduceAnchor($node->getId());
100+
$this->addLinkTargetToProject(
101+
$compilerContext,
102+
new InternalTarget(
103+
$currentDocument->getFilePath(),
88104
$anchor,
89-
new InternalTarget(
90-
$currentDocument->getFilePath(),
91-
$anchor,
92-
$node->getLinkText(),
93-
$node->getLinkType(),
94-
),
95-
);
96-
}
105+
$node->getLinkText(),
106+
$node->getLinkType(),
107+
),
108+
);
97109
if ($node instanceof MultipleLinkTargetsNode) {
98110
foreach ($node->getAdditionalIds() as $id) {
99-
if ($compilerContext->getProjectNode()->hasInternalTarget($id, $node->getLinkType())) {
100-
$this->logger?->warning(
101-
sprintf(
102-
'Duplicate anchor "%s" for link type "%s" in document "%s". The anchor is already used at "%s"',
103-
$anchor,
104-
$node->getLinkType(),
105-
$compilerContext->getDocumentNode()->getFilePath(),
106-
$compilerContext->getProjectNode()->getInternalTarget($anchor, $node->getLinkType())?->getDocumentPath(),
107-
),
108-
$compilerContext->getLoggerInformation(),
109-
);
110-
}
111-
112-
$compilerContext->getProjectNode()->addLinkTarget(
113-
$id,
111+
$anchor = $this->anchorReducer->reduceAnchor($id);
112+
$this->addLinkTargetToProject(
113+
$compilerContext,
114114
new InternalTarget(
115115
$currentDocument->getFilePath(),
116-
$id,
116+
$anchor,
117117
$node->getLinkText(),
118118
$node->getLinkType(),
119119
),
@@ -144,4 +144,28 @@ public function getPriority(): int
144144
// After MetasPass
145145
return 5000;
146146
}
147+
148+
private function addLinkTargetToProject(CompilerContext $compilerContext, InternalTarget $internalTarget): void
149+
{
150+
if ($compilerContext->getProjectNode()->hasInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType())) {
151+
$otherLink = $compilerContext->getProjectNode()->getInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType());
152+
$this->logger?->warning(
153+
sprintf(
154+
'Duplicate anchor "%s" for link type "%s" in document "%s". The anchor is already used at "%s"',
155+
$internalTarget->getAnchor(),
156+
$internalTarget->getLinkType(),
157+
$compilerContext->getDocumentNode()->getFilePath(),
158+
$otherLink?->getDocumentPath(),
159+
),
160+
$compilerContext->getLoggerInformation(),
161+
);
162+
163+
return;
164+
}
165+
166+
$compilerContext->getProjectNode()->addLinkTarget(
167+
$internalTarget->getAnchor(),
168+
$internalTarget,
169+
);
170+
}
147171
}

tests/Integration/tests/confval/expected/index.html renamed to tests/Integration/tests/confval/confval-name/expected/another.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
18
<!-- content start -->
29
<div class="section" id="confval-directive">
310
<h1>Confval directive</h1>
411

512
<dl class="confval">
6-
<dt id="demo">
13+
<dt id="another-demo">
714
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
815
<dd>
916
<div class="line-block">
@@ -21,3 +28,5 @@ <h1>Confval directive</h1>
2128
</div>
2229

2330
<!-- content end -->
31+
</body>
32+
</html>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
8+
<!-- content start -->
9+
<div class="section" id="confval-directive">
10+
<h1>Confval directive</h1>
11+
12+
<dl class="confval">
13+
<dt id="demo">
14+
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
15+
<dd>
16+
<div class="line-block">
17+
<div class="line"><strong>Type:</strong> <code>&quot;Hello World&quot;</code></div>
18+
<div class="line"><strong>Required:</strong> true</div>
19+
<div class="line"><strong>Custom Info:</strong> <strong>custom</strong></div>
20+
21+
</div>
22+
<div class="confval-description">
23+
<p>This is the confval <code>demo</code> content!</p><p>Another paragraph.</p>
24+
</div>
25+
</dd>
26+
</dl>
27+
<p>See option <a href="/index.html#demo">demo</a>.</p>
28+
<div class="toc">
29+
<ul class="menu-level">
30+
<li class="toc-item"><a href="/another.html#confval-directive">Confval directive</a></li>
31+
32+
</ul>
33+
</div>
34+
35+
</div>
36+
37+
<!-- content end -->
38+
</body>
39+
</html>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"std:doc": {
3+
"another": [
4+
"-",
5+
"-",
6+
"another.html",
7+
"Confval directive"
8+
],
9+
"index": [
10+
"-",
11+
"-",
12+
"index.html",
13+
"Confval directive"
14+
]
15+
},
16+
"std:label": {
17+
"confval-directive": [
18+
"-",
19+
"-",
20+
"index.html#confval-directive",
21+
"Confval directive"
22+
]
23+
},
24+
"std:confval": {
25+
"another-demo": [
26+
"-",
27+
"-",
28+
"another.html#another-demo",
29+
"demo"
30+
],
31+
"demo": [
32+
"-",
33+
"-",
34+
"index.html#demo",
35+
"demo"
36+
]
37+
}
38+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Confval directive
2+
=================
3+
4+
.. confval:: demo
5+
:name: another-demo
6+
:type: :php:`string`
7+
:default: ``"Hello World"``
8+
:required: true
9+
:Custom Info: **custom**
10+
11+
This is the confval ``demo`` content!
12+
13+
Another paragraph.
14+
15+
See option :confval:`demo`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Confval directive
2+
=================
3+
4+
.. confval:: demo
5+
:type: :php:`string`
6+
:default: ``"Hello World"``
7+
:required: true
8+
:Custom Info: **custom**
9+
10+
This is the confval ``demo`` content!
11+
12+
Another paragraph.
13+
14+
See option :confval:`demo`.
15+
16+
.. toctree::
17+
:glob:
18+
19+
*
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
8+
<!-- content start -->
9+
<div class="section" id="confval-directive">
10+
<h1>Confval directive</h1>
11+
12+
<dl class="confval">
13+
<dt id="demo">
14+
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
15+
<dd>
16+
<div class="line-block">
17+
<div class="line"><strong>Type:</strong> <code>&quot;Hello World&quot;</code></div>
18+
<div class="line"><strong>Required:</strong> true</div>
19+
<div class="line"><strong>Custom Info:</strong> <strong>custom</strong></div>
20+
21+
</div>
22+
<div class="confval-description">
23+
<p>This is the confval <code>demo</code> content!</p><p>Another paragraph.</p>
24+
</div>
25+
</dd>
26+
</dl>
27+
<p>See option <a href="/another.html#demo">demo</a>.</p>
28+
</div>
29+
30+
<!-- content end -->
31+
</body>
32+
</html>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
8+
<!-- content start -->
9+
<div class="section" id="confval-directive">
10+
<h1>Confval directive</h1>
11+
12+
<dl class="confval">
13+
<dt id="demo">
14+
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
15+
<dd>
16+
<div class="line-block">
17+
<div class="line"><strong>Type:</strong> <code>&quot;Hello World&quot;</code></div>
18+
<div class="line"><strong>Required:</strong> true</div>
19+
<div class="line"><strong>Custom Info:</strong> <strong>custom</strong></div>
20+
21+
</div>
22+
<div class="confval-description">
23+
<p>This is the confval <code>demo</code> content!</p><p>Another paragraph.</p>
24+
</div>
25+
</dd>
26+
</dl>
27+
<p>See option <a href="/another.html#demo">demo</a>.</p>
28+
<div class="toc">
29+
<ul class="menu-level">
30+
<li class="toc-item"><a href="/another.html#confval-directive">Confval directive</a></li>
31+
32+
</ul>
33+
</div>
34+
35+
</div>
36+
37+
<!-- content end -->
38+
</body>
39+
</html>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.WARNING: Duplicate anchor "demo" for link type "std:confval" in document "index". The anchor is already used at "another"

tests/Integration/tests/confval/expected/objects.inv.json renamed to tests/Integration/tests/confval/confval-warning/expected/objects.inv.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
{
22
"std:doc": {
3+
"another": [
4+
"-",
5+
"-",
6+
"another.html",
7+
"Confval directive"
8+
],
39
"index": [
410
"-",
511
"-",
@@ -19,7 +25,7 @@
1925
"demo": [
2026
"-",
2127
"-",
22-
"index.html#demo",
28+
"another.html#demo",
2329
"demo"
2430
]
2531
}

0 commit comments

Comments
 (0)