Skip to content

Commit 04b229f

Browse files
jdknightAA-Turner
andauthored
linkcheck: add HyperlinkCollector.find_url() (#12213)
Signed-off-by: James Knight <[email protected]> Co-authored-by: Adam Turner <[email protected]>
1 parent 208f4bc commit 04b229f

File tree

1 file changed

+49
-23
lines changed

1 file changed

+49
-23
lines changed

sphinx/builders/linkcheck.py

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -178,41 +178,67 @@ class HyperlinkCollector(SphinxPostTransform):
178178
default_priority = 800
179179

180180
def run(self, **kwargs: Any) -> None:
181-
builder = cast(CheckExternalLinksBuilder, self.app.builder)
182-
hyperlinks = builder.hyperlinks
183-
docname = self.env.docname
181+
for node in self.document.findall():
182+
if uri := self.find_uri(node):
183+
self._add_uri(uri, node)
184+
185+
def find_uri(self, node: nodes.Element) -> str | None:
186+
"""Find a URI for a given node.
184187
188+
This call can be used to retrieve a URI from a provided node. If no
189+
URI exists for a provided node, this call will return ``None``.
190+
191+
This method can be useful for extension developers who wish to
192+
easily inject hyperlinks into a builder by only needing to override
193+
this method.
194+
195+
:param node: A node class
196+
:returns: URI of the node
197+
"""
185198
# reference nodes
186-
for refnode in self.document.findall(nodes.reference):
187-
if 'refuri' in refnode:
188-
uri = refnode['refuri']
189-
_add_uri(self.app, uri, refnode, hyperlinks, docname)
199+
if isinstance(node, nodes.reference):
200+
if 'refuri' in node:
201+
return node['refuri']
190202

191203
# image nodes
192-
for imgnode in self.document.findall(nodes.image):
193-
uri = imgnode['candidates'].get('?')
204+
if isinstance(node, nodes.image):
205+
uri = node['candidates'].get('?')
194206
if uri and '://' in uri:
195-
_add_uri(self.app, uri, imgnode, hyperlinks, docname)
207+
return uri
196208

197209
# raw nodes
198-
for rawnode in self.document.findall(nodes.raw):
199-
uri = rawnode.get('source')
210+
if isinstance(node, nodes.raw):
211+
uri = node.get('source')
200212
if uri and '://' in uri:
201-
_add_uri(self.app, uri, rawnode, hyperlinks, docname)
213+
return uri
214+
215+
return None
202216

217+
def _add_uri(self, uri: str, node: nodes.Element) -> None:
218+
"""Registers a node's URI into a builder's collection of hyperlinks.
203219
204-
def _add_uri(app: Sphinx, uri: str, node: nodes.Element,
205-
hyperlinks: dict[str, Hyperlink], docname: str) -> None:
206-
if newuri := app.emit_firstresult('linkcheck-process-uri', uri):
207-
uri = newuri
220+
Provides the ability to register a URI value determined from a node
221+
into the linkcheck's builder. URI's processed through this call can
222+
be manipulated through a ``linkcheck-process-uri`` event before the
223+
builder attempts to validate.
208224
209-
try:
210-
lineno = get_node_line(node)
211-
except ValueError:
212-
lineno = -1
225+
:param uri: URI to add
226+
:param node: A node class where the URI was found
227+
"""
228+
builder = cast(CheckExternalLinksBuilder, self.app.builder)
229+
hyperlinks = builder.hyperlinks
230+
docname = self.env.docname
231+
232+
if newuri := self.app.emit_firstresult('linkcheck-process-uri', uri):
233+
uri = newuri
234+
235+
try:
236+
lineno = get_node_line(node)
237+
except ValueError:
238+
lineno = -1
213239

214-
if uri not in hyperlinks:
215-
hyperlinks[uri] = Hyperlink(uri, docname, app.env.doc2path(docname), lineno)
240+
if uri not in hyperlinks:
241+
hyperlinks[uri] = Hyperlink(uri, docname, self.env.doc2path(docname), lineno)
216242

217243

218244
class Hyperlink(NamedTuple):

0 commit comments

Comments
 (0)