from pathlib import Path import msgspec from click import Path as ClickPath from click import group, option from yaml import dump as dump_yaml from litestar import Litestar from litestar._openapi.typescript_converter.converter import ( convert_openapi_to_typescript, ) from litestar.cli._utils import JSBEAUTIFIER_INSTALLED, LitestarCLIException, LitestarGroup from litestar.serialization import encode_json, get_serializer __all__ = ("generate_openapi_schema", "generate_typescript_specs", "schema_group") @group(cls=LitestarGroup, name="schema") def schema_group() -> None: """Manage server-side OpenAPI schemas.""" def _generate_openapi_schema(app: Litestar, output: Path) -> None: """Generate an OpenAPI Schema.""" serializer = get_serializer(app.type_encoders) if output.suffix in (".yml", ".yaml"): content = dump_yaml( msgspec.to_builtins(app.openapi_schema.to_schema(), enc_hook=serializer), default_flow_style=False, encoding="utf-8", ) else: content = msgspec.json.format( encode_json(app.openapi_schema.to_schema(), serializer=serializer), indent=4, ) try: output.write_bytes(content) except OSError as e: # pragma: no cover raise LitestarCLIException(f"failed to write schema to path {output}") from e @schema_group.command("openapi") # type: ignore[misc] @option( "--output", help="output file path", type=ClickPath(dir_okay=False, path_type=Path), default=Path("openapi_schema.json"), show_default=True, ) def generate_openapi_schema(app: Litestar, output: Path) -> None: """Generate an OpenAPI Schema.""" _generate_openapi_schema(app, output) @schema_group.command("typescript") # type: ignore[misc] @option( "--output", help="output file path", type=ClickPath(dir_okay=False, path_type=Path), default=Path("api-specs.ts"), show_default=True, ) @option("--namespace", help="namespace to use for the typescript specs", type=str, default="API") def generate_typescript_specs(app: Litestar, output: Path, namespace: str) -> None: """Generate TypeScript specs from the OpenAPI schema.""" if JSBEAUTIFIER_INSTALLED: # pragma: no cover from jsbeautifier import Beautifier beautifier = Beautifier() else: beautifier = None try: specs = convert_openapi_to_typescript(app.openapi_schema, namespace) # beautifier will be defined if JSBEAUTIFIER_INSTALLED is True specs_output = ( beautifier.beautify(specs.write()) if JSBEAUTIFIER_INSTALLED and beautifier else specs.write() # pyright: ignore ) output.write_text(specs_output) except OSError as e: # pragma: no cover raise LitestarCLIException(f"failed to write schema to path {output}") from e