use indexmap::IndexMap; use newtype::Newtype; use object::Object; use proc_macro2::TokenStream; use r#enum::Enum; use crate::openapi::r#type::OpenApiType; pub mod r#enum; pub mod newtype; pub mod object; pub mod parameter; pub mod path; pub mod scope; pub mod union; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Model { Newtype(Newtype), Enum(Enum), Object(Object), Unresolved, } pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenApiType>) -> Model { match r#type { OpenApiType { r#enum: Some(_), .. } => Enum::from_schema(name, r#type).map_or(Model::Unresolved, Model::Enum), OpenApiType { r#type: Some("object"), .. } => Object::from_schema_object(name, r#type, schemas) .map_or(Model::Unresolved, Model::Object), OpenApiType { r#type: Some(_), .. } => Newtype::from_schema(name, r#type).map_or(Model::Unresolved, Model::Newtype), OpenApiType { one_of: Some(types), .. } => Enum::from_one_of(name, types).map_or(Model::Unresolved, Model::Enum), OpenApiType { all_of: Some(types), .. } => Object::from_all_of(name, types, schemas).map_or(Model::Unresolved, Model::Object), _ => Model::Unresolved, } } impl Model { pub fn codegen(&self) -> Option { match self { Self::Newtype(newtype) => newtype.codegen(), Self::Enum(r#enum) => r#enum.codegen(), Self::Object(object) => object.codegen(), Self::Unresolved => None, } } } #[cfg(test)] mod test { use super::*; use crate::{ model::r#enum::{EnumRepr, EnumVariant}, openapi::schema::OpenApiSchema, }; #[test] fn resolve_newtypes() { let schema = OpenApiSchema::read().unwrap(); let user_id_schema = schema.components.schemas.get("UserId").unwrap(); let user_id = resolve(user_id_schema, "UserId", &schema.components.schemas); assert_eq!( user_id, Model::Newtype(Newtype { name: "UserId".to_owned(), description: None, inner: newtype::NewtypeInner::I32, copy: true, ord: true }) ); let attack_code_schema = schema.components.schemas.get("AttackCode").unwrap(); let attack_code = resolve(attack_code_schema, "AttackCode", &schema.components.schemas); assert_eq!( attack_code, Model::Newtype(Newtype { name: "AttackCode".to_owned(), description: None, inner: newtype::NewtypeInner::Str, copy: false, ord: false }) ); } #[test] fn resolve_all() { let schema = OpenApiSchema::read().unwrap(); let mut unresolved = vec![]; let total = schema.components.schemas.len(); for (name, desc) in &schema.components.schemas { if resolve(desc, name, &schema.components.schemas) == Model::Unresolved { unresolved.push(name); } } if !unresolved.is_empty() { panic!( "Failed to resolve {}/{} types. Could not resolve [{}]", unresolved.len(), total, unresolved .into_iter() .map(|u| format!("`{u}`")) .collect::>() .join(", ") ) } } }