diff options
author | Cyborus <cyborus@cyborus.xyz> | 2024-02-10 04:39:32 +0100 |
---|---|---|
committer | Cyborus <cyborus@cyborus.xyz> | 2024-02-10 04:39:32 +0100 |
commit | 3f1458e1be318cf3389ad8cff604bd3cf690c3fd (patch) | |
tree | 0e379072b8248c7215f1f461d146b849172b9bb4 /generator | |
parent | deref more params (diff) | |
download | forgejo-api-3f1458e1be318cf3389ad8cff604bd3cf690c3fd.tar.xz forgejo-api-3f1458e1be318cf3389ad8cff604bd3cf690c3fd.zip |
even more strongly typed returns
Diffstat (limited to 'generator')
-rw-r--r-- | generator/src/main.rs | 87 | ||||
-rw-r--r-- | generator/src/methods.rs | 15 | ||||
-rw-r--r-- | generator/src/structs.rs | 110 |
3 files changed, 154 insertions, 58 deletions
diff --git a/generator/src/main.rs b/generator/src/main.rs index 6e43f2c..3aece4f 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -4,7 +4,7 @@ mod methods; mod openapi; mod structs; -use heck::ToSnakeCase; +use heck::{ToSnakeCase, ToPascalCase}; use openapi::*; fn main() -> eyre::Result<()> { @@ -51,6 +51,9 @@ fn schema_ref_type_name(spec: &OpenApiV2, schema: &MaybeRef<Schema>) -> eyre::Re } else { None }; + if name == Some("LanguageStatistics") { + eprintln!("lang stats found"); + } let schema = schema.deref(spec)?; schema_type_name(spec, name, schema) } @@ -184,3 +187,85 @@ fn sanitize_ident(s: &str) -> String { } s } + +fn schema_subtype_name( + spec: &OpenApiV2, + parent_name: &str, + name: &str, + schema: &Schema, + ty: &mut String, +) -> eyre::Result<bool> { + let b = match schema { + Schema { + _type: Some(SchemaType::One(Primitive::Object)), + .. + } => { + *ty = format!("{parent_name}{}", name.to_pascal_case()); + true + } + Schema { + _type: Some(SchemaType::One(Primitive::String)), + _enum: Some(_enum), + .. + } => { + *ty = format!("{parent_name}{}", name.to_pascal_case()); + true + } + Schema { + _type: Some(SchemaType::One(Primitive::Array)), + items: Some(items), + .. + } => { + if let MaybeRef::Value { value } = &**items { + if schema_subtype_name(spec, parent_name, name, value, ty)? { + *ty = format!("Vec<{ty}>"); + true + } else { + false + } + } else { + false + } + } + _ => false, + }; + Ok(b) +} +fn schema_subtypes( + spec: &OpenApiV2, + parent_name: &str, + name: &str, + schema: &Schema, + subtypes: &mut Vec<String>, +) -> eyre::Result<()> { + let b = match schema { + Schema { + _type: Some(SchemaType::One(Primitive::Object)), + .. + } => { + let name = format!("{parent_name}{}", name.to_pascal_case()); + let subtype = structs::create_struct_for_definition(spec, &name, schema)?; + subtypes.push(subtype); + } + Schema { + _type: Some(SchemaType::One(Primitive::String)), + _enum: Some(_enum), + .. + } => { + let name = format!("{parent_name}{}", name.to_pascal_case()); + let subtype = structs::create_enum(&name, schema.description.as_deref(), _enum)?; + subtypes.push(subtype); + } + Schema { + _type: Some(SchemaType::One(Primitive::Array)), + items: Some(items), + .. + } => { + if let MaybeRef::Value { value } = &**items { + schema_subtypes(spec, parent_name, name, value, subtypes)?; + } + } + _ => (), + }; + Ok(()) +} diff --git a/generator/src/methods.rs b/generator/src/methods.rs index 28f9c73..23df8c9 100644 --- a/generator/src/methods.rs +++ b/generator/src/methods.rs @@ -1,6 +1,6 @@ use crate::{openapi::*, schema_ref_type_name}; use eyre::{OptionExt, WrapErr}; -use heck::ToSnakeCase; +use heck::{ToPascalCase, ToSnakeCase}; use std::fmt::Write; pub fn create_methods(spec: &OpenApiV2) -> eyre::Result<String> { @@ -270,13 +270,13 @@ fn fn_return_from_op(spec: &OpenApiV2, op: &Operation) -> eyre::Result<ResponseT fn response_ref_type_name( spec: &OpenApiV2, - schema: &MaybeRef<Response>, + response_ref: &MaybeRef<Response>, op: &Operation, ) -> eyre::Result<ResponseType> { - let response = schema.deref(spec)?; + let response = response_ref.deref(spec)?; let mut ty = ResponseType::default(); if response.headers.is_some() { - let parent_name = match &schema { + let parent_name = match &response_ref { MaybeRef::Ref { _ref } => _ref .rsplit_once("/") .ok_or_else(|| eyre::eyre!("invalid ref"))? @@ -303,7 +303,12 @@ fn response_ref_type_name( (true, false, false) => { if let Some(schema) = &response.schema { ty.kind = Some(ResponseKind::Json); - ty.body = Some(crate::schema_ref_type_name(spec, schema)?); + let mut body = crate::schema_ref_type_name(spec, schema)?; + if let MaybeRef::Value { value } = schema { + let op_name = op.operation_id.as_deref().ok_or_else(|| eyre::eyre!("no operation id"))?.to_pascal_case(); + crate::schema_subtype_name(spec, &op_name, "Response", value, &mut body)?; + } + ty.body = Some(body); }; } (false, _, true) => { diff --git a/generator/src/structs.rs b/generator/src/structs.rs index ef61a8f..7b7672a 100644 --- a/generator/src/structs.rs +++ b/generator/src/structs.rs @@ -20,11 +20,17 @@ pub fn create_structs(spec: &OpenApiV2) -> eyre::Result<String> { let strukt = create_header_struct(name, headers)?; s.push_str(&strukt); } + + let tys = create_response_struct(spec, name, response)?; + s.push_str(&tys); } } for (_, item) in &spec.paths { let strukt = create_query_structs_for_path(spec, item)?; s.push_str(&strukt); + + let strukt = create_response_structs(spec, item)?; + s.push_str(&strukt); } s.push_str("\n}"); Ok(s) @@ -56,57 +62,8 @@ pub fn create_struct_for_definition( let field_name = crate::sanitize_ident(prop_name); let mut field_ty = prop_ty.clone(); if let MaybeRef::Value { value } = &prop_schema { - fn schema_subtypes( - spec: &OpenApiV2, - ty_name: &str, - name: &str, - schema: &Schema, - subtypes: &mut Vec<String>, - ty: &mut String, - ) -> eyre::Result<bool> { - let b = match schema { - Schema { - _type: Some(SchemaType::One(Primitive::Object)), - .. - } => { - let name = format!("{ty_name}{}", name.to_pascal_case()); - let subtype = create_struct_for_definition(spec, &name, schema)?; - subtypes.push(subtype); - *ty = name; - true - } - Schema { - _type: Some(SchemaType::One(Primitive::String)), - _enum: Some(_enum), - .. - } => { - let name = format!("{ty_name}{}", name.to_pascal_case()); - let subtype = create_enum(&name, schema.description.as_deref(), _enum)?; - subtypes.push(subtype); - *ty = name; - true - } - Schema { - _type: Some(SchemaType::One(Primitive::Array)), - items: Some(items), - .. - } => { - if let MaybeRef::Value { value } = &**items { - if schema_subtypes(spec, ty_name, name, value, subtypes, ty)? { - *ty = format!("Vec<{ty}>"); - true - } else { - false - } - } else { - false - } - } - _ => false, - }; - Ok(b) - } - schema_subtypes(spec, name, prop_name, value, &mut subtypes, &mut field_ty)?; + crate::schema_subtype_name(spec, name, prop_name, value, &mut field_ty)?; + crate::schema_subtypes(spec, name, prop_name, value, &mut subtypes)?; } if field_name.ends_with("url") && field_name != "ssh_url" && field_ty == "String" { field_ty = "url::Url".into() @@ -163,7 +120,7 @@ pub fn create_struct_for_definition( Ok(out) } -fn create_enum( +pub fn create_enum( name: &str, desc: Option<&str>, _enum: &[serde_json::Value], @@ -621,3 +578,52 @@ pub fn header_type(header: &Header) -> eyre::Result<String> { true, ) } + +pub fn create_response_structs(spec: &OpenApiV2, item: &PathItem) -> eyre::Result<String> { + let mut s = String::new(); + if let Some(op) = &item.get { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("GET")?); + } + if let Some(op) = &item.put { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("PUT")?); + } + if let Some(op) = &item.post { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("POST")?); + } + if let Some(op) = &item.delete { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("DELETE")?); + } + if let Some(op) = &item.options { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("OPTIONS")?); + } + if let Some(op) = &item.head { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("HEAD")?); + } + if let Some(op) = &item.patch { + s.push_str(&create_response_structs_for_op(spec, op).wrap_err("PATCH")?); + } + Ok(s) +} + +pub fn create_response_structs_for_op(spec: &OpenApiV2, op: &Operation) -> eyre::Result<String> { + let mut out = String::new(); + let op_name = op.operation_id.as_deref().ok_or_else(|| eyre::eyre!("no operation id"))?.to_pascal_case(); + for (_, response) in &op.responses.http_codes { + let response = response.deref(spec)?; + let tys = create_response_struct(spec, &op_name, response)?; + out.push_str(&tys); + } + Ok(out) +} + +pub fn create_response_struct(spec: &OpenApiV2, name: &str, res: &Response) -> eyre::Result<String> { + let mut types = Vec::new(); + if let Some(MaybeRef::Value { value }) = &res.schema { + crate::schema_subtypes(spec, name, "Response", value, &mut types)?; + } + let mut out = String::new(); + for ty in types { + out.push_str(&ty); + } + Ok(out) +} |