Skip to main content

spikard_cli/codegen/
mod.rs

1//! Code generation from `OpenAPI` and `AsyncAPI` schemas
2
3mod asyncapi;
4mod base;
5pub mod common;
6mod elixir;
7mod engine;
8pub mod formatters;
9mod graphql;
10mod openapi;
11mod openrpc;
12mod php;
13mod php_dto;
14mod protobuf;
15mod python;
16pub mod quality;
17mod ruby;
18mod rust;
19mod schema_index;
20pub mod sql;
21pub mod ts_schema;
22mod typescript;
23
24pub use asyncapi::{
25    Protocol, detect_primary_protocol, generate_fixtures, generate_nodejs_handler_app, generate_nodejs_test_app,
26    generate_php_handler_app, generate_python_handler_app, generate_python_test_app, generate_ruby_handler_app,
27    generate_ruby_test_app, generate_rust_handler_app, parse_asyncapi_schema,
28};
29pub use base::OpenApiGenerator;
30pub use elixir::ElixirGenerator;
31pub use engine::{CodegenEngine, CodegenOutcome, CodegenRequest, CodegenTargetKind, GeneratedAsset, SchemaKind};
32pub use formatters::{Formatter, HeaderMetadata, Import, PythonFormatter, RubyFormatter, Section, TypeScriptFormatter};
33pub use graphql::{
34    GraphQLArgument, GraphQLDirective, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLSchema, GraphQLType,
35    TypeKind, generate_elixir_graphql, generate_php_graphql, generate_python_graphql, generate_ruby_graphql,
36    generate_rust_graphql, generate_typescript_graphql, parse_graphql_schema, parse_graphql_sdl,
37    parse_graphql_sdl_string,
38};
39pub use openapi::parse_openapi_schema;
40pub use openrpc::{
41    generate_php_handler_app as generate_openrpc_php_handler_app,
42    generate_python_handler_app as generate_openrpc_python_handler_app,
43    generate_ruby_handler_app as generate_openrpc_ruby_handler_app,
44    generate_rust_handler_app as generate_openrpc_rust_handler_app,
45    generate_typescript_handler_app as generate_openrpc_typescript_handler_app, parse_openrpc_schema,
46};
47pub use php::PhpGenerator;
48pub use php_dto::PhpDtoGenerator;
49pub use protobuf::{
50    EnumDef, EnumValue, FieldDef, FieldLabel, MessageDef, MethodDef, ProtoType, ProtobufGenerator, ProtobufSchema,
51    ProtobufTarget, generate_elixir_protobuf, generate_php_protobuf, generate_python_protobuf, generate_ruby_protobuf,
52    generate_typescript_protobuf, parse_proto_schema, parse_proto_schema_string,
53};
54pub use python::PythonGenerator;
55pub use ruby::RubyGenerator;
56pub use rust::RustGenerator;
57pub use schema_index::SchemaRegistry;
58pub use typescript::TypeScriptGenerator;
59
60use anyhow::Result;
61use std::path::Path;
62
63/// Supported target languages for code generation
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum TargetLanguage {
66    Python,
67    TypeScript,
68    Rust,
69    Ruby,
70    Php,
71    Elixir,
72}
73
74/// DTO configuration per language.
75#[derive(Debug, Clone)]
76pub struct DtoConfig {
77    pub python: PythonDtoStyle,
78    pub node: NodeDtoStyle,
79    pub ruby: RubyDtoStyle,
80    pub rust: RustDtoStyle,
81    pub php: PhpDtoStyle,
82    pub elixir: ElixirDtoStyle,
83}
84
85impl Default for DtoConfig {
86    fn default() -> Self {
87        Self {
88            python: PythonDtoStyle::Dataclass,
89            node: NodeDtoStyle::Zod,
90            ruby: RubyDtoStyle::DrySchema,
91            rust: RustDtoStyle::SerdeStruct,
92            php: PhpDtoStyle::ReadonlyClass,
93            elixir: ElixirDtoStyle::Typespecs,
94        }
95    }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub enum PythonDtoStyle {
100    Dataclass,
101    Msgspec,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum NodeDtoStyle {
106    Zod,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub enum RubyDtoStyle {
111    DrySchema,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum RustDtoStyle {
116    SerdeStruct,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum PhpDtoStyle {
121    ReadonlyClass,
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub enum ElixirDtoStyle {
126    Typespecs,
127}
128
129/// Generate server code from an `OpenAPI` schema file
130pub fn generate_from_openapi(schema_path: &Path, target_lang: TargetLanguage, dto: &DtoConfig) -> Result<String> {
131    let spec = parse_openapi_schema(schema_path)?;
132
133    let code = match target_lang {
134        TargetLanguage::Python => {
135            let generator = PythonGenerator::new(spec, dto.python);
136            generator.generate()?
137        }
138        TargetLanguage::TypeScript => {
139            let generator = TypeScriptGenerator::new(spec, dto.node);
140            generator.generate()?
141        }
142        TargetLanguage::Rust => {
143            let generator = RustGenerator::new(spec, dto.rust);
144            generator.generate()?
145        }
146        TargetLanguage::Ruby => {
147            let generator = RubyGenerator::new(spec, dto.ruby);
148            generator.generate()?
149        }
150        TargetLanguage::Php => {
151            let generator = PhpGenerator::new(spec, dto.php);
152            generator.generate()?
153        }
154        TargetLanguage::Elixir => {
155            let generator = ElixirGenerator::new(spec, dto.elixir);
156            generator.generate()?
157        }
158    };
159
160    Ok(code)
161}