Skip to content

Commit

Permalink
Add Type XRefs to IR
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hoodmane committed Sep 23, 2023
1 parent ec3277c commit 984bcbb
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 105 deletions.
22 changes: 20 additions & 2 deletions sphinx_js/ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,25 @@

from .analyzer_utils import dotted_path


@dataclass
class TypeXRef:
name: str


@dataclass
class TypeXRefInternal(TypeXRef):
path: list[str]


@dataclass
class TypeXRefExternal(TypeXRef):
sourcefilename: str
qualifiedName: str


#: Human-readable type of a value. None if we don't know the type.
Type = str | None
Type = str | list[str | TypeXRef] | None
# In the far future, we may take full control of our RST templates rather than
# using the js-domain directives provided by Sphinx. This would give us the
# freedom to link type names in formal param lists and param description lists
Expand All @@ -38,6 +55,7 @@
# (simple for JS, fancy for TS) and can, on request, render it out as either
# text or link-having RST.


#: Pathname, full or not, to an object:
ReStructuredText = str

Expand Down Expand Up @@ -98,7 +116,7 @@ class or interface"""
@dataclass
class TypeParam:
name: str
extends: str | None
extends: Type
description: ReStructuredText = ReStructuredText("")


Expand Down
50 changes: 44 additions & 6 deletions sphinx_js/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
Pathname,
Return,
TopLevel,
Type,
TypeParam,
TypeXRef,
)
from .jsdoc import Analyzer as JsAnalyzer
from .parsers import PathVisitor
Expand Down Expand Up @@ -205,16 +207,51 @@ def _formal_params(self, obj: Function | Class) -> str:

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

def format_type(self, type: Type, escape: bool = False) -> str:
if not type:
return ""
if isinstance(type, str):
return self.format_type([type])
it = iter(type)

def strs() -> Iterator[str]:
for elem in it:
if isinstance(elem, str):
yield elem
else:
xref.append(elem)
return

res = []
while True:
xref: list[TypeXRef] = []
s = "".join(strs())
if escape:
s = rst.escape(s)
res.append(s)
if not xref:
break
res.append(self.render_xref(xref[0], escape))

return "".join(res)

def render_xref(self, s: TypeXRef, escape: bool = False) -> str:
if escape:
return rst.escape(s.name)
return s.name

def _return_formatter(self, return_: Return) -> tuple[list[str], str]:
"""Derive heads and tail from ``@returns`` blocks."""
tail = ("**%s** -- " % rst.escape(return_.type)) if return_.type else ""
tail = ""
if return_.type:
tail += "**%s** -- " % self.format_type(return_.type, escape=True)
tail += return_.description
return ["returns"], tail

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

Expand All @@ -225,8 +262,9 @@ def _param_formatter(self, param: Param) -> tuple[list[str], str] | None:
return None
heads = ["param"]
if param.type:
heads.append(param.type)
heads.append(self.format_type(param.type))
heads.append(param.name)

tail = param.description
return heads, tail

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

def _exception_formatter(self, exception: Exc) -> tuple[list[str], str]:
"""Derive heads and tail from ``@throws`` blocks."""
heads = ["throws"]
if exception.type:
heads.append(exception.type)
heads.append(self.format_type(exception.type))
tail = exception.description
return heads, tail

Expand Down Expand Up @@ -453,7 +491,7 @@ def _template_vars(self, name: str, obj: Attribute) -> dict[str, Any]: # type:
is_optional=obj.is_optional,
see_also=obj.see_alsos,
examples=obj.examples,
type=obj.type,
type=self.format_type(obj.type),
content="\n".join(self._content),
)

Expand Down
Loading

0 comments on commit 984bcbb

Please sign in to comment.