diff --git a/sphinx_js/directives.py b/sphinx_js/directives.py index d5d161c..6915687 100644 --- a/sphinx_js/directives.py +++ b/sphinx_js/directives.py @@ -373,7 +373,7 @@ def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str] class JSTypeAlias(JSObject): doc_field_types = [ - GroupedField( + JSGroupedField( "typeparam", label="Type parameters", names=("typeparam",), diff --git a/tests/test_build_ts/source/module.ts b/tests/test_build_ts/source/module.ts index b8344df..86bc22e 100644 --- a/tests/test_build_ts/source/module.ts +++ b/tests/test_build_ts/source/module.ts @@ -57,6 +57,16 @@ export interface I {} */ export let interfaceInstance: I = {}; +/** + * A super special type alias + * @typeParam T The whatsit + */ +export type TestTypeAlias = { a: T }; +export type TestTypeAlias2 = { a: number }; + +export let t: TestTypeAlias; +export let t2: TestTypeAlias2; + /** * A function with a type parameter! * diff --git a/tests/test_build_ts/test_build_ts.py b/tests/test_build_ts/test_build_ts.py index 264c227..8abd391 100644 --- a/tests/test_build_ts/test_build_ts.py +++ b/tests/test_build_ts/test_build_ts.py @@ -273,6 +273,14 @@ def test_automodule(self): Another thing. +module.t + + type: "TestTypeAlias"<"A"> + +module.t2 + + type: "TestTypeAlias2" + module.zInstance type: "Z"<"A"> @@ -353,6 +361,19 @@ class module.Z(a, b) Documentation for the interface I *exported from* "module" + +module.TestTypeAlias + + type: { a: T; } + + A super special type alias + + Type parameters: + **T** -- The whatsit (extends "A") + +module.TestTypeAlias2 + + type: { a: number; } """ ), ) @@ -434,7 +455,7 @@ def test_autosummary(self): soup = BeautifulSoup(self._file_contents("autosummary"), "html.parser") attrs = soup.find(class_="attributes") rows = list(attrs.find_all("tr")) - assert len(rows) == 5 + assert len(rows) == 7 href = rows[0].find("a") assert href.get_text() == "a" diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 6c16fb6..b234ca6 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -14,6 +14,7 @@ Interface, Param, Return, + TypeAlias, TypeParam, TypeXRefExternal, TypeXRefInternal, @@ -133,6 +134,18 @@ def attribute_render(partial_path=None, use_short_name=False, **args): return attribute_render +@pytest.fixture() +def type_alias_render(attribute_renderer) -> Any: + def type_alias_render(partial_path=None, use_short_name=False, **args): + if not partial_path: + partial_path = ["blah"] + return attribute_renderer.rst( + partial_path, make_type_alias(**args), use_short_name + ) + + return type_alias_render + + top_level_dict = dict( name="", path=[], @@ -173,6 +186,7 @@ def attribute_render(partial_path=None, use_short_name=False, **args): ) ) attribute_dict = top_level_dict | member_dict | dict(type="") +type_alias_dict = top_level_dict | dict(type="", type_params=[]) def make_class(**args): @@ -191,6 +205,10 @@ def make_attribute(**args): return Attribute(**(attribute_dict | args)) +def make_type_alias(**args): + return TypeAlias(**(type_alias_dict | args)) + + DEFAULT_RESULT = ".. js:function:: blah()\n" @@ -301,6 +319,11 @@ def test_render_xref(function_renderer: AutoFunctionRenderer): function_renderer.render_type([TypeXRefInternal(name="A", path=["a.", "A"])]) == ":js:class:`A`" ) + function_renderer.objects["A"] = make_type_alias() + assert ( + function_renderer.render_type([TypeXRefInternal(name="A", path=["a.", "A"])]) + == ":js:typealias:`A`" + ) function_renderer.objects["A"] = make_interface() assert ( function_renderer.render_type([TypeXRefInternal(name="A", path=["a.", "A"])]) @@ -341,7 +364,7 @@ def test_func_render_param_type(function_render): """ ) assert function_render( - objects={"A": make_interface()}, + objects={"A": make_type_alias()}, params=[ Param( "a", @@ -354,7 +377,7 @@ def test_func_render_param_type(function_render): .. js:function:: blah(a) :param a: a description - :type a: :js:interface:`A` + :type a: :js:typealias:`A` """ ) @@ -501,3 +524,37 @@ def test_examples(function_render): Something python """ ) + + +def test_type_alias(type_alias_render): + assert type_alias_render() == ".. js:typealias:: blah\n" + assert type_alias_render( + type="number", description="my great type alias!" + ) == dedent( + """\ + .. js:typealias:: blah + + .. rst-class:: js attribute type + + type: **number** + + my great type alias! + """ + ) + assert type_alias_render( + type="string | T", + type_params=[TypeParam("T", extends="number", description="ABC")], + description="With a type parameter", + ) == dedent( + """\ + .. js:typealias:: blah + + .. rst-class:: js attribute type + + type: **string | T** + + With a type parameter + + :typeparam T: ABC (extends **number**) + """ + ) diff --git a/tests/test_typedoc_analysis/source/nodes.ts b/tests/test_typedoc_analysis/source/nodes.ts index a040a25..946fe33 100644 --- a/tests/test_typedoc_analysis/source/nodes.ts +++ b/tests/test_typedoc_analysis/source/nodes.ts @@ -54,3 +54,9 @@ export class Indexable { // Test that we don't fail on a reexport export { Blah } from "./exports"; + +/** + * A super special type alias + * @typeparam T The whatsit + */ +export type TestTypeAlias = 1 | 2 | T; diff --git a/tests/test_typedoc_analysis/test_typedoc_analysis.py b/tests/test_typedoc_analysis/test_typedoc_analysis.py index acc7a36..a15e7a1 100644 --- a/tests/test_typedoc_analysis/test_typedoc_analysis.py +++ b/tests/test_typedoc_analysis/test_typedoc_analysis.py @@ -5,6 +5,7 @@ from sphinx_js.ir import ( Attribute, Class, + Description, DescriptionCode, DescriptionText, Function, @@ -12,6 +13,7 @@ Pathname, Return, Type, + TypeAlias, TypeParam, TypeXRef, TypeXRefExternal, @@ -30,12 +32,12 @@ def join_type(t: Type) -> str: return "".join(e.name if isinstance(e, TypeXRef) else e for e in t) -def join_descri(t: Type) -> str: +def join_description(t: Description) -> str: if not t: return "" if isinstance(t, str): return t - return "".join(e.name if isinstance(e, TypeXRef) else e for e in t) + return "".join(e.code if isinstance(e, DescriptionCode) else e.text for e in t) class TestPathSegments(TypeDocTestCase): @@ -356,6 +358,13 @@ def test_setter(self): assert isinstance(setter, Attribute) assert setter.type == [TypeXRefIntrinsic("string")] + def test_type_alias(self): + alias = self.analyzer.get_object(["TestTypeAlias"]) + assert isinstance(alias, TypeAlias) + assert join_description(alias.description) == "A super special type alias" + assert join_type(alias.type) == "1 | 2 | T" + assert alias.type_params == [TypeParam(name="T", extends=None, description=[])] + class TestTypeName(TypeDocAnalyzerTestCase): """Make sure our rendering of TypeScript types into text works.""" diff --git a/tests/test_typedoc_analysis/typedoc.json b/tests/test_typedoc_analysis/typedoc.json new file mode 100644 index 0000000..e69de29 diff --git a/tests/testing.py b/tests/testing.py index 2bc6dd1..52c3b43 100644 --- a/tests/testing.py +++ b/tests/testing.py @@ -55,6 +55,7 @@ def _file_contents(self, filename): def _file_contents_eq(self, filename, contents): __tracebackhide__ = True + print(self._file_contents(filename)) assert self._file_contents(filename) == contents