2323use phpDocumentor \Guides \Nodes \Node ;
2424use phpDocumentor \Guides \Nodes \SectionNode ;
2525use phpDocumentor \Guides \ReferenceResolvers \AnchorNormalizer ;
26+ use Psr \Log \LoggerInterface ;
2627use SplStack ;
2728use Webmozart \Assert \Assert ;
2829
30+ use function sprintf ;
31+
2932/** @implements NodeTransformer<DocumentNode|AnchorNode|SectionNode> */
3033final class CollectLinkTargetsTransformer implements NodeTransformer
3134{
@@ -34,6 +37,7 @@ final class CollectLinkTargetsTransformer implements NodeTransformer
3437
3538 public function __construct (
3639 private readonly AnchorNormalizer $ anchorReducer ,
40+ private LoggerInterface |null $ logger = null ,
3741 ) {
3842 /*
3943 * TODO: remove stack here, as we should not have sub documents in this way, sub documents are
@@ -68,17 +72,43 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
6872 $ currentDocument = $ this ->documentStack ->top ();
6973 Assert::notNull ($ currentDocument );
7074 $ anchor = $ node ->getId ();
71- $ compilerContext ->getProjectNode ()->addLinkTarget (
72- $ anchor ,
73- new InternalTarget (
74- $ currentDocument ->getFilePath (),
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 (
7588 $ anchor ,
76- $ node ->getLinkText (),
77- $ node ->getLinkType (),
78- ),
79- );
89+ new InternalTarget (
90+ $ currentDocument ->getFilePath (),
91+ $ anchor ,
92+ $ node ->getLinkText (),
93+ $ node ->getLinkType (),
94+ ),
95+ );
96+ }
8097 if ($ node instanceof MultipleLinkTargetsNode) {
8198 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+
82112 $ compilerContext ->getProjectNode ()->addLinkTarget (
83113 $ id ,
84114 new InternalTarget (
0 commit comments