def ts_create_dto(self, ctx: CodeSnippetContext, ts_expression: str) -> str: ctx.add("_mapObject", self.MAP_OBJECT_TS_HELPER) sub_expr = self.value_type.ts_create_dto(ctx, "val") if sub_expr == "val": return ts_expression return f"_mapObject({ts_expression}, val => ({sub_expr}))"
def ts_repr(self, ctx: CodeSnippetContext): if self.name: interface_name = to_pascal(self.name) if self.translate_name else self.name if interface_name not in ctx: subctx = ctx.subcontext(interface_name) code = self._render_ts_interface(interface_name, subctx) ctx.add(interface_name, code) return interface_name else: return self._render_ts_interface(None, ctx)
def test_object_ts_repr(self): ctx = CodeSnippetContext() @dataclass() class Foo: my_field: int other_field: str tree = Object.match(Foo) assert tree.ts_repr(ctx) == "Foo" assert ctx.top_level_snippets() == {"Foo"} assert ctx.get_snippet("Foo") == """export interface Foo {
def test_snippet_context_subcontext(): ctx = CodeSnippetContext() ctx.add("foo", "dummy") sub = ctx.subcontext("foo") sub.add("bar", "dummy") ctx.add("baz", "dummy") assert "foo" in ctx assert "bar" in ctx assert ctx.top_level_snippets() == {"foo", "baz"} assert ctx.natural_order() == ["baz", "bar", "foo"]
def test_ts_create_dto_json_compatible(self): ctx = CodeSnippetContext() t = Object("GenObj", lambda: None, { "d1": Primitive(bool), }) parse_expr = t.ts_create_dto(ctx, "*dtoVar*") assert parse_expr == "*dtoVar*"
def test_ts_create_dto_generic(self): ctx = CodeSnippetContext() t = Object("GenObj", lambda: None, { "d1": DummyTypeNode(), }) parse_expr = t.ts_create_dto(ctx, "*dtoVar*") assert parse_expr == "{d1: *makeDummyDto*(*dtoVar*.d1)}"
def test_ts_create_dto_partially_json_compatible(self): ctx = CodeSnippetContext() t = Object("GenObj", lambda: None, { "d1": Primitive(bool), "d2": DummyTypeNode(), }) parse_expr = t.ts_create_dto(ctx, "*dtoVar*") assert parse_expr == "{...*dtoVar*, d2: *makeDummyDto*(*dtoVar*.d2)}"
def test_api_gen(): foo_type_tree = get_type_tree(Foo) ctx = CodeSnippetContext() func_code = build_ts_func("getFoo", foo_type_tree, None, "/api/foo/<my_id>", ["my_id"], "GET", ctx) expected_func_code = """ export const getFoo = async (myId: string): Promise<Foo> => { const response = await fetch(`/api/foo/${myId}`, { method: 'GET' }); if (!response.ok) { throw new ApiError("HTTP status code: " + response.status, response); } return await response.json(); }""" assert func_code == expected_func_code assert ctx.natural_order() == ["ApiError", "Foo"]
def build_ts_func( name: str, return_type_tree: Optional[AbstractNode], payload: Optional[tuple[str, AbstractNode]], url_pattern: str, url_args: list[str], method: str, ctx: CodeSnippetContext ): ts_args = [] for arg in url_args: ts_arg_name = to_camel(arg) url_pattern = url_pattern.replace(f"<{arg}>", f"${{{ts_arg_name}}}") ts_args.append((ts_arg_name, "string")) if return_type_tree is None: ts_return_type = "void" return_expression = None response_dto_type = None else: ts_return_type = return_type_tree.ts_repr(ctx) return_expression = return_type_tree.ts_parse_dto(ctx, "dto") response_dto_type = return_type_tree.dto_tree().ts_repr(ctx) if payload: payload_name, payload_type_tree = payload ts_payload_type = payload_type_tree.ts_repr(ctx) payload_arg_name = to_camel(payload_name) payload_expression = payload_type_tree.ts_create_dto(ctx, payload_arg_name) ts_args.append((payload_arg_name, ts_payload_type)) else: payload_expression = None ctx.add("ApiError", TS_API_ERROR) ts_function_code = jinja2.Template(TS_FUNC_TEMPLATE).render({ "function_name": name, "response_type_name": ts_return_type, "response_dto_type": response_dto_type, "payload_expression": payload_expression, "args": ts_args, "method": method, "url_pattern": url_pattern, "return_expression": return_expression, }) return ts_function_code
def test_deep_nested_tree_ts_repr(self): @dataclass class Baz: nano: int @dataclass class Bar: micro: list[Baz] @dataclass class Foo: my_field: Bar tree = Object.match(Foo) ctx = CodeSnippetContext() assert tree.ts_repr(ctx) == "Foo" assert "Foo" in ctx assert ctx.get_snippet("Foo") == """export interface Foo { myField: Bar; }""" assert "Bar" in ctx assert ctx.get_snippet("Bar") == """export interface Bar { micro: Baz[]; }""" assert "Baz" in ctx assert ctx.get_snippet("Baz") == """export interface Baz { nano: number; }""" assert ctx.topological_dependencies("Foo") == ["Baz", "Bar", "Foo"]
def test_ts_create_dto(self): ctx = CodeSnippetContext() t = List(DummyTypeNode()) assert t.ts_create_dto( ctx, "*listVar*") == "*listVar*.map(item => (*makeDummyDto*(item)))"
def ts_create_dto(self, ctx: CodeSnippetContext, ts_expression: str) -> Optional[str]: prep_function_name = "_formatISODateString" if prep_function_name not in ctx: iso_formatter_ts = f"const {prep_function_name} = (d: Date): string => d.toISOString().split('T')[0];" ctx.add(prep_function_name, iso_formatter_ts) return f"{prep_function_name}({ts_expression})"
def test_ts_repr(): t = OptionalNode(Primitive(str)) assert t.ts_repr(CodeSnippetContext()) == "string | null"
def test_snippet_context_single_snippet(): ctx = CodeSnippetContext() ctx.add("foo", "dummy") assert "foo" in ctx assert ctx.top_level_snippets() == {"foo"} assert ctx.natural_order() == ["foo"]
def test_ts_create_dto_json_compatible(self): ctx = CodeSnippetContext() parse_expr = Dict(Primitive(str)).ts_create_dto(ctx, "*dtoVar*") assert parse_expr == "*dtoVar*"
def test_ts_create_dto_generic(self): ctx = CodeSnippetContext() parse_expr = Dict(DummyTypeNode()).ts_create_dto(ctx, "*dtoVar*") assert parse_expr == "_mapObject(*dtoVar*, val => (*makeDummyDto*(val)))"
def test_ts_repr(self): assert Dict(DummyTypeNode()).ts_repr( CodeSnippetContext()) == "{ [key: string]: *Dummy* }"
def test_tree_parsing(self): assert get_type_tree(dict[str, int]) == Dict(Primitive(int)) t = get_type_tree(dict[int, str]) assert t == UnsupportedTypeNode(dict[int, str]) with pytest.raises(UnsupportedTypeError): t.ts_repr(CodeSnippetContext())
def test_ts_parse_dto_with_json_compatible_element(self): ctx = CodeSnippetContext() t = List(Primitive(int)) parse_expr = t.ts_parse_dto(ctx, "*dtoVar*") assert "*dtoVar*" == parse_expr
def test_ts_parse_dto(self): ctx = CodeSnippetContext() t = List(DummyTypeNode()) parse_expr = t.ts_parse_dto(ctx, "*dtoVar*") assert "*dtoVar*.map(item => (*parseDummyDto*(item)))" == parse_expr
def test_ts_create_dto_with_json_compatible_element(self): ctx = CodeSnippetContext() t = List(Primitive(str)) create_expr = t.ts_create_dto(ctx, "*listVar*") assert "*listVar*" == create_expr
def test_list_ts_repr(self): ctx = CodeSnippetContext() assert List(Primitive(int)).ts_repr(ctx) == "number[]" assert List(Primitive(str)).ts_repr(ctx) == "string[]" assert List(List(Primitive(str))).ts_repr(ctx) == "string[][]"
def test_ts_repr(self): ctx = CodeSnippetContext() t = List(DummyTypeNode()) assert t.ts_repr(ctx) == "*Dummy*[]"