Skip to content

Commit

Permalink
Merge pull request #93 from piercefreeman/feature/recursive-model-def…
Browse files Browse the repository at this point in the history
…initions

Handle recursive schema definitions
  • Loading branch information
piercefreeman authored Apr 12, 2024
2 parents a3ed791 + d582aad commit 2d3b595
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 224 deletions.
21 changes: 21 additions & 0 deletions mountaineer/__tests__/client_builder/test_build_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,24 @@ def test_get_typescript_interface_name(model_title: str, expected_interface: str
)
== expected_interface
)


class ChildNode(BaseModel):
siblings: list["ChildNode"]


def test_gather_all_models_recursive():
"""
Ensure that schemas can be specified recursively for nested elements.
"""
converter = OpenAPIToTypescriptSchemaConverter()
openapi_spec = OpenAPISchema(**converter.get_model_json_schema(ChildNode))

found_models = converter.gather_all_models(openapi_spec)
assert len(found_models) == 1

js_interfaces = converter.convert_schema_to_typescript(openapi_spec)
assert js_interfaces == {
"ChildNode": "interface ChildNode {\n siblings: Array<ChildNode>;\n}"
}
14 changes: 12 additions & 2 deletions mountaineer/client_builder/build_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,20 @@ def gather_all_models(self, base: OpenAPISchema):
:param base: The core OpenAPI Schema
"""

seen_models: set[str] = set()

def walk_models(
property: OpenAPIProperty | EmptyAPIProperty,
) -> Iterator[OpenAPIProperty]:
if isinstance(property, EmptyAPIProperty):
return

if property.title in seen_models:
# We've already parsed this model
return
elif property.title:
seen_models.add(property.title)

if (
property.variable_type == OpenAPISchemaType.OBJECT
or property.enum is not None
Expand Down Expand Up @@ -194,10 +202,12 @@ def walk_array_types(prop: OpenAPIProperty | EmptyAPIProperty) -> Iterator[str]:
sorted(set(walk_array_types(prop.additionalProperties)))
)
yield f"Record<{map_openapi_type_to_ts(OpenAPISchemaType.STRING)}, {sub_types}>"
elif prop.variable_type:
yield map_openapi_type_to_ts(prop.variable_type)
elif prop.const:
yield python_payload_to_typescript(prop.const)
elif prop.variable_type:
# Should be the very last type to parsed, since all the other switch
# statements are more specific than a simple variable type
yield map_openapi_type_to_ts(prop.variable_type)
else:
LOGGER.warning(f"Unknown property type: {prop}")

Expand Down
Loading

0 comments on commit 2d3b595

Please sign in to comment.