torn_api_codegen/model/
mod.rs

1use indexmap::IndexMap;
2use newtype::Newtype;
3use object::Object;
4use proc_macro2::TokenStream;
5use r#enum::Enum;
6
7use crate::openapi::r#type::OpenApiType;
8
9pub mod r#enum;
10pub mod newtype;
11pub mod object;
12pub mod parameter;
13pub mod path;
14pub mod scope;
15pub mod union;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum Model {
19    Newtype(Newtype),
20    Enum(Enum),
21    Object(Object),
22    Unresolved,
23}
24
25pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenApiType>) -> Model {
26    match r#type {
27        OpenApiType {
28            r#enum: Some(_), ..
29        } => Enum::from_schema(name, r#type).map_or(Model::Unresolved, Model::Enum),
30        OpenApiType {
31            r#type: Some("object"),
32            ..
33        } => Object::from_schema_object(name, r#type, schemas)
34            .map_or(Model::Unresolved, Model::Object),
35        OpenApiType {
36            r#type: Some(_), ..
37        } => Newtype::from_schema(name, r#type).map_or(Model::Unresolved, Model::Newtype),
38        OpenApiType {
39            one_of: Some(types),
40            ..
41        } => Enum::from_one_of(name, types).map_or(Model::Unresolved, Model::Enum),
42        OpenApiType {
43            all_of: Some(types),
44            ..
45        } => Object::from_all_of(name, types, schemas).map_or(Model::Unresolved, Model::Object),
46        _ => Model::Unresolved,
47    }
48}
49
50impl Model {
51    pub fn codegen(&self) -> Option<TokenStream> {
52        match self {
53            Self::Newtype(newtype) => newtype.codegen(),
54            Self::Enum(r#enum) => r#enum.codegen(),
55            Self::Object(object) => object.codegen(),
56            Self::Unresolved => None,
57        }
58    }
59}
60
61#[cfg(test)]
62mod test {
63    use super::*;
64    use crate::openapi::schema::test::get_schema;
65
66    #[test]
67    fn resolve_newtypes() {
68        let schema = get_schema();
69
70        let user_id_schema = schema.components.schemas.get("UserId").unwrap();
71
72        let user_id = resolve(user_id_schema, "UserId", &schema.components.schemas);
73
74        assert_eq!(
75            user_id,
76            Model::Newtype(Newtype {
77                name: "UserId".to_owned(),
78                description: None,
79                inner: newtype::NewtypeInner::I32,
80                copy: true,
81                ord: true
82            })
83        );
84
85        let attack_code_schema = schema.components.schemas.get("AttackCode").unwrap();
86
87        let attack_code = resolve(attack_code_schema, "AttackCode", &schema.components.schemas);
88
89        assert_eq!(
90            attack_code,
91            Model::Newtype(Newtype {
92                name: "AttackCode".to_owned(),
93                description: None,
94                inner: newtype::NewtypeInner::Str,
95                copy: false,
96                ord: false
97            })
98        );
99    }
100
101    #[test]
102    fn resolve_all() {
103        let schema = get_schema();
104
105        let mut unresolved = vec![];
106        let total = schema.components.schemas.len();
107
108        for (name, desc) in &schema.components.schemas {
109            if resolve(desc, name, &schema.components.schemas) == Model::Unresolved {
110                unresolved.push(name);
111            }
112        }
113
114        if !unresolved.is_empty() {
115            panic!(
116                "Failed to resolve {}/{} types. Could not resolve [{}]",
117                unresolved.len(),
118                total,
119                unresolved
120                    .into_iter()
121                    .map(|u| format!("`{u}`"))
122                    .collect::<Vec<_>>()
123                    .join(", ")
124            )
125        }
126    }
127}