even more strongly typed returns
This commit is contained in:
parent
8cf3213267
commit
3f1458e1be
|
@ -4,7 +4,7 @@ mod methods;
|
||||||
mod openapi;
|
mod openapi;
|
||||||
mod structs;
|
mod structs;
|
||||||
|
|
||||||
use heck::ToSnakeCase;
|
use heck::{ToSnakeCase, ToPascalCase};
|
||||||
use openapi::*;
|
use openapi::*;
|
||||||
|
|
||||||
fn main() -> eyre::Result<()> {
|
fn main() -> eyre::Result<()> {
|
||||||
|
@ -51,6 +51,9 @@ fn schema_ref_type_name(spec: &OpenApiV2, schema: &MaybeRef<Schema>) -> eyre::Re
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
if name == Some("LanguageStatistics") {
|
||||||
|
eprintln!("lang stats found");
|
||||||
|
}
|
||||||
let schema = schema.deref(spec)?;
|
let schema = schema.deref(spec)?;
|
||||||
schema_type_name(spec, name, schema)
|
schema_type_name(spec, name, schema)
|
||||||
}
|
}
|
||||||
|
@ -184,3 +187,85 @@ fn sanitize_ident(s: &str) -> String {
|
||||||
}
|
}
|
||||||
s
|
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(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{openapi::*, schema_ref_type_name};
|
use crate::{openapi::*, schema_ref_type_name};
|
||||||
use eyre::{OptionExt, WrapErr};
|
use eyre::{OptionExt, WrapErr};
|
||||||
use heck::ToSnakeCase;
|
use heck::{ToPascalCase, ToSnakeCase};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub fn create_methods(spec: &OpenApiV2) -> eyre::Result<String> {
|
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(
|
fn response_ref_type_name(
|
||||||
spec: &OpenApiV2,
|
spec: &OpenApiV2,
|
||||||
schema: &MaybeRef<Response>,
|
response_ref: &MaybeRef<Response>,
|
||||||
op: &Operation,
|
op: &Operation,
|
||||||
) -> eyre::Result<ResponseType> {
|
) -> eyre::Result<ResponseType> {
|
||||||
let response = schema.deref(spec)?;
|
let response = response_ref.deref(spec)?;
|
||||||
let mut ty = ResponseType::default();
|
let mut ty = ResponseType::default();
|
||||||
if response.headers.is_some() {
|
if response.headers.is_some() {
|
||||||
let parent_name = match &schema {
|
let parent_name = match &response_ref {
|
||||||
MaybeRef::Ref { _ref } => _ref
|
MaybeRef::Ref { _ref } => _ref
|
||||||
.rsplit_once("/")
|
.rsplit_once("/")
|
||||||
.ok_or_else(|| eyre::eyre!("invalid ref"))?
|
.ok_or_else(|| eyre::eyre!("invalid ref"))?
|
||||||
|
@ -303,7 +303,12 @@ fn response_ref_type_name(
|
||||||
(true, false, false) => {
|
(true, false, false) => {
|
||||||
if let Some(schema) = &response.schema {
|
if let Some(schema) = &response.schema {
|
||||||
ty.kind = Some(ResponseKind::Json);
|
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) => {
|
(false, _, true) => {
|
||||||
|
|
|
@ -20,11 +20,17 @@ pub fn create_structs(spec: &OpenApiV2) -> eyre::Result<String> {
|
||||||
let strukt = create_header_struct(name, headers)?;
|
let strukt = create_header_struct(name, headers)?;
|
||||||
s.push_str(&strukt);
|
s.push_str(&strukt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tys = create_response_struct(spec, name, response)?;
|
||||||
|
s.push_str(&tys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, item) in &spec.paths {
|
for (_, item) in &spec.paths {
|
||||||
let strukt = create_query_structs_for_path(spec, item)?;
|
let strukt = create_query_structs_for_path(spec, item)?;
|
||||||
s.push_str(&strukt);
|
s.push_str(&strukt);
|
||||||
|
|
||||||
|
let strukt = create_response_structs(spec, item)?;
|
||||||
|
s.push_str(&strukt);
|
||||||
}
|
}
|
||||||
s.push_str("\n}");
|
s.push_str("\n}");
|
||||||
Ok(s)
|
Ok(s)
|
||||||
|
@ -56,57 +62,8 @@ pub fn create_struct_for_definition(
|
||||||
let field_name = crate::sanitize_ident(prop_name);
|
let field_name = crate::sanitize_ident(prop_name);
|
||||||
let mut field_ty = prop_ty.clone();
|
let mut field_ty = prop_ty.clone();
|
||||||
if let MaybeRef::Value { value } = &prop_schema {
|
if let MaybeRef::Value { value } = &prop_schema {
|
||||||
fn schema_subtypes(
|
crate::schema_subtype_name(spec, name, prop_name, value, &mut field_ty)?;
|
||||||
spec: &OpenApiV2,
|
crate::schema_subtypes(spec, name, prop_name, value, &mut subtypes)?;
|
||||||
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)?;
|
|
||||||
}
|
}
|
||||||
if field_name.ends_with("url") && field_name != "ssh_url" && field_ty == "String" {
|
if field_name.ends_with("url") && field_name != "ssh_url" && field_ty == "String" {
|
||||||
field_ty = "url::Url".into()
|
field_ty = "url::Url".into()
|
||||||
|
@ -163,7 +120,7 @@ pub fn create_struct_for_definition(
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_enum(
|
pub fn create_enum(
|
||||||
name: &str,
|
name: &str,
|
||||||
desc: Option<&str>,
|
desc: Option<&str>,
|
||||||
_enum: &[serde_json::Value],
|
_enum: &[serde_json::Value],
|
||||||
|
@ -621,3 +578,52 @@ pub fn header_type(header: &Header) -> eyre::Result<String> {
|
||||||
true,
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -1162,7 +1162,7 @@ impl crate::Forgejo {
|
||||||
&self,
|
&self,
|
||||||
org: &str,
|
org: &str,
|
||||||
query: TeamSearchQuery,
|
query: TeamSearchQuery,
|
||||||
) -> Result<serde_json::Map<String, serde_json::Value>, ForgejoError> {
|
) -> Result<TeamSearchResponse, ForgejoError> {
|
||||||
let request = self
|
let request = self
|
||||||
.get(&format!("orgs/{org}/teams/search?{query}"))
|
.get(&format!("orgs/{org}/teams/search?{query}"))
|
||||||
.build()?;
|
.build()?;
|
||||||
|
@ -4117,7 +4117,7 @@ impl crate::Forgejo {
|
||||||
&self,
|
&self,
|
||||||
owner: &str,
|
owner: &str,
|
||||||
repo: &str,
|
repo: &str,
|
||||||
) -> Result<serde_json::Map<String, serde_json::Value>, ForgejoError> {
|
) -> Result<RepoGetLanguagesResponse, ForgejoError> {
|
||||||
let request = self
|
let request = self
|
||||||
.get(&format!("repos/{owner}/{repo}/languages"))
|
.get(&format!("repos/{owner}/{repo}/languages"))
|
||||||
.build()?;
|
.build()?;
|
||||||
|
@ -6918,7 +6918,7 @@ impl crate::Forgejo {
|
||||||
pub async fn user_search(
|
pub async fn user_search(
|
||||||
&self,
|
&self,
|
||||||
query: UserSearchQuery,
|
query: UserSearchQuery,
|
||||||
) -> Result<serde_json::Map<String, serde_json::Value>, ForgejoError> {
|
) -> Result<UserSearchResponse, ForgejoError> {
|
||||||
let request = self.get(&format!("users/search?{query}")).build()?;
|
let request = self.get(&format!("users/search?{query}")).build()?;
|
||||||
let response = self.execute(request).await?;
|
let response = self.execute(request).await?;
|
||||||
match response.status().as_u16() {
|
match response.status().as_u16() {
|
||||||
|
@ -10392,6 +10392,11 @@ pub mod structs {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct LanguageStatisticsResponse {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub additional: std::collections::BTreeMap<String, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ErrorHeaders {
|
pub struct ErrorHeaders {
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
|
@ -11119,6 +11124,11 @@ pub mod structs {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct TeamSearchResponse {
|
||||||
|
pub data: Option<Vec<Team>>,
|
||||||
|
pub ok: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ListPackagesQuery {
|
pub struct ListPackagesQuery {
|
||||||
/// page number of results to return (1-based)
|
/// page number of results to return (1-based)
|
||||||
|
@ -12363,6 +12373,11 @@ pub mod structs {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct RepoGetLanguagesResponse {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub additional: std::collections::BTreeMap<String, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RepoGetRawFileOrLfsQuery {
|
pub struct RepoGetRawFileOrLfsQuery {
|
||||||
/// The name of the commit/branch/tag. Default the repository’s default branch (usually master)
|
/// The name of the commit/branch/tag. Default the repository’s default branch (usually master)
|
||||||
|
@ -13622,6 +13637,11 @@ pub mod structs {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct UserSearchResponse {
|
||||||
|
pub data: Option<Vec<User>>,
|
||||||
|
pub ok: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UserListActivityFeedsQuery {
|
pub struct UserListActivityFeedsQuery {
|
||||||
/// if true, only show actions performed by the requested user
|
/// if true, only show actions performed by the requested user
|
||||||
|
|
Loading…
Reference in a new issue