Skip to content

Commit a1871c6

Browse files
committed
Add Type XRefs to IR
This updates the IR representation of types to a possible list of strings or xref objects. The xrefs can be internal xrefs to types in the project or external ones to types defined in dependencies. I don't currently add xrefs to intrinsic types but that would be a natural thing to do. The renderer currently throws this information away. Rendering it is left to a followup.
1 parent e0faba2 commit a1871c6

File tree

5 files changed

+276
-105
lines changed

5 files changed

+276
-105
lines changed

sphinx_js/ir.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,25 @@
2828

2929
from .analyzer_utils import dotted_path
3030

31+
32+
@dataclass
33+
class TypeXRef:
34+
name: str
35+
36+
37+
@dataclass
38+
class TypeXRefInternal(TypeXRef):
39+
path: list[str]
40+
41+
42+
@dataclass
43+
class TypeXRefExternal(TypeXRef):
44+
sourcefilename: str
45+
qualifiedName: str
46+
47+
3148
#: Human-readable type of a value. None if we don't know the type.
32-
Type = str | None
49+
Type = str | list[str | TypeXRef] | None
3350
# In the far future, we may take full control of our RST templates rather than
3451
# using the js-domain directives provided by Sphinx. This would give us the
3552
# freedom to link type names in formal param lists and param description lists
@@ -38,6 +55,7 @@
3855
# (simple for JS, fancy for TS) and can, on request, render it out as either
3956
# text or link-having RST.
4057

58+
4159
#: Pathname, full or not, to an object:
4260
ReStructuredText = str
4361

@@ -98,7 +116,7 @@ class or interface"""
98116
@dataclass
99117
class TypeParam:
100118
name: str
101-
extends: str | None
119+
extends: Type
102120
description: ReStructuredText = ReStructuredText("")
103121

104122

sphinx_js/renderers.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
Pathname,
2424
Return,
2525
TopLevel,
26+
Type,
2627
TypeParam,
28+
TypeXRef,
2729
)
2830
from .jsdoc import Analyzer as JsAnalyzer
2931
from .parsers import PathVisitor
@@ -205,16 +207,51 @@ def _formal_params(self, obj: Function | Class) -> str:
205207

206208
return "({})".format(", ".join(formals))
207209

210+
def format_type(self, type: Type, escape: bool = False) -> str:
211+
if not type:
212+
return ""
213+
if isinstance(type, str):
214+
return self.format_type([type])
215+
it = iter(type)
216+
217+
def strs() -> Iterator[str]:
218+
for elem in it:
219+
if isinstance(elem, str):
220+
yield elem
221+
else:
222+
xref.append(elem)
223+
return
224+
225+
res = []
226+
while True:
227+
xref: list[TypeXRef] = []
228+
s = "".join(strs())
229+
if escape:
230+
s = rst.escape(s)
231+
res.append(s)
232+
if not xref:
233+
break
234+
res.append(self.render_xref(xref[0], escape))
235+
236+
return "".join(res)
237+
238+
def render_xref(self, s: TypeXRef, escape: bool = False) -> str:
239+
if escape:
240+
return rst.escape(s.name)
241+
return s.name
242+
208243
def _return_formatter(self, return_: Return) -> tuple[list[str], str]:
209244
"""Derive heads and tail from ``@returns`` blocks."""
210-
tail = ("**%s** -- " % rst.escape(return_.type)) if return_.type else ""
245+
tail = ""
246+
if return_.type:
247+
tail += "**%s** -- " % self.format_type(return_.type, escape=True)
211248
tail += return_.description
212249
return ["returns"], tail
213250

214251
def _type_param_formatter(self, tparam: TypeParam) -> tuple[list[str], str] | None:
215252
v = tparam.name
216253
if tparam.extends:
217-
v += f" extends {tparam.extends}"
254+
v += " extends " + self.format_type(tparam.extends)
218255
heads = ["typeparam", v]
219256
return heads, tparam.description
220257

@@ -225,8 +262,9 @@ def _param_formatter(self, param: Param) -> tuple[list[str], str] | None:
225262
return None
226263
heads = ["param"]
227264
if param.type:
228-
heads.append(param.type)
265+
heads.append(self.format_type(param.type))
229266
heads.append(param.name)
267+
230268
tail = param.description
231269
return heads, tail
232270

@@ -235,14 +273,14 @@ def _param_type_formatter(self, param: Param) -> tuple[list[str], str] | None:
235273
if not param.type:
236274
return None
237275
heads = ["type", param.name]
238-
tail = rst.escape(param.type)
276+
tail = self.format_type(param.type)
239277
return heads, tail
240278

241279
def _exception_formatter(self, exception: Exc) -> tuple[list[str], str]:
242280
"""Derive heads and tail from ``@throws`` blocks."""
243281
heads = ["throws"]
244282
if exception.type:
245-
heads.append(exception.type)
283+
heads.append(self.format_type(exception.type))
246284
tail = exception.description
247285
return heads, tail
248286

@@ -453,7 +491,7 @@ def _template_vars(self, name: str, obj: Attribute) -> dict[str, Any]: # type:
453491
is_optional=obj.is_optional,
454492
see_also=obj.see_alsos,
455493
examples=obj.examples,
456-
type=obj.type,
494+
type=self.format_type(obj.type),
457495
content="\n".join(self._content),
458496
)
459497

0 commit comments

Comments
 (0)