summaryrefslogtreecommitdiffstats
path: root/generator
diff options
context:
space:
mode:
authorCyborus <cyborus@cyborus.xyz>2024-02-10 04:39:32 +0100
committerCyborus <cyborus@cyborus.xyz>2024-02-10 04:39:32 +0100
commit3f1458e1be318cf3389ad8cff604bd3cf690c3fd (patch)
tree0e379072b8248c7215f1f461d146b849172b9bb4 /generator
parentderef more params (diff)
downloadforgejo-api-3f1458e1be318cf3389ad8cff604bd3cf690c3fd.tar.xz
forgejo-api-3f1458e1be318cf3389ad8cff604bd3cf690c3fd.zip
even more strongly typed returns
Diffstat (limited to 'generator')
-rw-r--r--generator/src/main.rs87
-rw-r--r--generator/src/methods.rs15
-rw-r--r--generator/src/structs.rs110
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)
+}