feat: handle duplicate enum cases
This commit is contained in:
parent
12cfcf7f11
commit
2e60e0a24f
10 changed files with 1462 additions and 658 deletions
988
Cargo.lock
generated
988
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "torn-api-codegen"
|
||||
authors = ["Pyrit [2111649]"]
|
||||
version = "0.7.5"
|
||||
version = "0.8.0"
|
||||
edition = "2021"
|
||||
description = "Contains the v2 torn API model descriptions and codegen for the bindings"
|
||||
license = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use heck::{ToSnakeCase, ToUpperCamelCase};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::Ident;
|
||||
|
||||
use crate::openapi::{
|
||||
use crate::{
|
||||
model::WarningReporter,
|
||||
openapi::{
|
||||
parameter::OpenApiParameterSchema,
|
||||
r#type::{OpenApiType, OpenApiVariants},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{object::PrimitiveType, Model, ResolvedSchema};
|
||||
|
|
@ -25,7 +30,11 @@ pub enum EnumVariantTupleValue {
|
|||
}
|
||||
|
||||
impl EnumVariantTupleValue {
|
||||
pub fn from_schema(name: &str, schema: &OpenApiType) -> Option<Self> {
|
||||
pub fn from_schema(
|
||||
name: &str,
|
||||
schema: &OpenApiType,
|
||||
warnings: WarningReporter,
|
||||
) -> Option<Self> {
|
||||
match schema {
|
||||
OpenApiType {
|
||||
ref_path: Some(path),
|
||||
|
|
@ -63,7 +72,7 @@ impl EnumVariantTupleValue {
|
|||
} => {
|
||||
let name = format!("{name}Variant");
|
||||
Some(Self::Enum {
|
||||
inner: Enum::from_schema(&name, schema)?,
|
||||
inner: Enum::from_schema(&name, schema, warnings.child(name.clone()))?,
|
||||
name,
|
||||
})
|
||||
}
|
||||
|
|
@ -353,7 +362,11 @@ pub struct Enum {
|
|||
}
|
||||
|
||||
impl Enum {
|
||||
pub fn from_schema(name: &str, schema: &OpenApiType) -> Option<Self> {
|
||||
pub fn from_schema(
|
||||
name: &str,
|
||||
schema: &OpenApiType,
|
||||
warnings: WarningReporter,
|
||||
) -> Option<Self> {
|
||||
let mut result = Enum {
|
||||
name: name.to_owned(),
|
||||
description: schema.description.as_deref().map(ToOwned::to_owned),
|
||||
|
|
@ -389,6 +402,19 @@ impl Enum {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut visited = HashSet::with_capacity(result.variants.len());
|
||||
let mut new_variants = Vec::with_capacity(result.variants.len());
|
||||
for variant in result.variants {
|
||||
if visited.contains(&variant.name) {
|
||||
warnings.push(format!("Duplicate case `{}`", variant.name));
|
||||
} else {
|
||||
visited.insert(variant.name.clone());
|
||||
new_variants.push(variant);
|
||||
}
|
||||
}
|
||||
|
||||
result.variants = new_variants;
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
|
|
@ -417,7 +443,11 @@ impl Enum {
|
|||
Some(result)
|
||||
}
|
||||
|
||||
pub fn from_one_of(name: &str, schemas: &[OpenApiType]) -> Option<Self> {
|
||||
pub fn from_one_of(
|
||||
name: &str,
|
||||
schemas: &[OpenApiType],
|
||||
warnings: WarningReporter,
|
||||
) -> Option<Self> {
|
||||
let mut result = Self {
|
||||
name: name.to_owned(),
|
||||
untagged: true,
|
||||
|
|
@ -425,7 +455,8 @@ impl Enum {
|
|||
};
|
||||
|
||||
for schema in schemas {
|
||||
let value = EnumVariantTupleValue::from_schema(name, schema)?;
|
||||
let value =
|
||||
EnumVariantTupleValue::from_schema(name, schema, warnings.child(name.to_owned()))?;
|
||||
let name = value.name();
|
||||
|
||||
result.variants.push(EnumVariant {
|
||||
|
|
|
|||
|
|
@ -131,9 +131,10 @@ impl ResolvedSchema {
|
|||
}
|
||||
|
||||
for (name, param) in &schema.components.parameters {
|
||||
result
|
||||
.parameters
|
||||
.push(Parameter::from_schema(name, param).unwrap());
|
||||
result.parameters.push(
|
||||
Parameter::from_schema(name, param, result.warnings.child(name.to_owned()))
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
result
|
||||
|
|
@ -193,7 +194,8 @@ pub fn resolve(
|
|||
match r#type {
|
||||
OpenApiType {
|
||||
r#enum: Some(_), ..
|
||||
} => Enum::from_schema(name, r#type).map_or(Model::Unresolved, Model::Enum),
|
||||
} => Enum::from_schema(name, r#type, warnings.child(name))
|
||||
.map_or(Model::Unresolved, Model::Enum),
|
||||
OpenApiType {
|
||||
r#type: Some("object"),
|
||||
..
|
||||
|
|
@ -209,7 +211,8 @@ pub fn resolve(
|
|||
OpenApiType {
|
||||
one_of: Some(types),
|
||||
..
|
||||
} => Enum::from_one_of(name, types).map_or(Model::Unresolved, Model::Enum),
|
||||
} => Enum::from_one_of(name, types, warnings.child(name))
|
||||
.map_or(Model::Unresolved, Model::Enum),
|
||||
OpenApiType {
|
||||
all_of: Some(types),
|
||||
..
|
||||
|
|
|
|||
|
|
@ -114,8 +114,11 @@ impl Property {
|
|||
OpenApiType {
|
||||
r#enum: Some(_), ..
|
||||
} => {
|
||||
let Some(r#enum) = Enum::from_schema(&name.clone().to_upper_camel_case(), schema)
|
||||
else {
|
||||
let Some(r#enum) = Enum::from_schema(
|
||||
&name.clone().to_upper_camel_case(),
|
||||
schema,
|
||||
warnings.clone(),
|
||||
) else {
|
||||
warnings.push("Failed to create enum");
|
||||
return None;
|
||||
};
|
||||
|
|
@ -154,7 +157,9 @@ impl Property {
|
|||
Some(inner)
|
||||
}
|
||||
cases => {
|
||||
let Some(r#enum) = Enum::from_one_of(&name.to_upper_camel_case(), cases) else {
|
||||
let Some(r#enum) =
|
||||
Enum::from_one_of(&name.to_upper_camel_case(), cases, warnings.clone())
|
||||
else {
|
||||
warnings.push("Failed to create oneOf enum");
|
||||
return None;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@ use heck::ToUpperCamelCase;
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
|
||||
use crate::openapi::parameter::{
|
||||
use crate::{
|
||||
model::WarningReporter,
|
||||
openapi::parameter::{
|
||||
OpenApiParameter, OpenApiParameterDefault, OpenApiParameterSchema,
|
||||
ParameterLocation as SchemaLocation,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{r#enum::Enum, ResolvedSchema};
|
||||
|
|
@ -38,7 +41,11 @@ pub enum ParameterType {
|
|||
}
|
||||
|
||||
impl ParameterType {
|
||||
pub fn from_schema(name: &str, schema: &OpenApiParameterSchema) -> Option<Self> {
|
||||
pub fn from_schema(
|
||||
name: &str,
|
||||
schema: &OpenApiParameterSchema,
|
||||
warnings: WarningReporter,
|
||||
) -> Option<Self> {
|
||||
match schema {
|
||||
OpenApiParameterSchema {
|
||||
r#type: Some("integer"),
|
||||
|
|
@ -97,7 +104,7 @@ impl ParameterType {
|
|||
minimum: None,
|
||||
maximum: None,
|
||||
},
|
||||
r#type: Enum::from_one_of(name, schemas)?,
|
||||
r#type: Enum::from_one_of(name, schemas, warnings.child(name.to_owned()))?,
|
||||
}),
|
||||
OpenApiParameterSchema {
|
||||
r#type: Some("string"),
|
||||
|
|
@ -116,7 +123,11 @@ impl ParameterType {
|
|||
items: Some(items),
|
||||
..
|
||||
} => Some(Self::Array {
|
||||
items: Box::new(Self::from_schema(name, items)?),
|
||||
items: Box::new(Self::from_schema(
|
||||
name,
|
||||
items,
|
||||
warnings.child(name.to_owned()),
|
||||
)?),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -153,7 +164,11 @@ pub struct Parameter {
|
|||
}
|
||||
|
||||
impl Parameter {
|
||||
pub fn from_schema(name: &str, schema: &OpenApiParameter) -> Option<Self> {
|
||||
pub fn from_schema(
|
||||
name: &str,
|
||||
schema: &OpenApiParameter,
|
||||
warnings: WarningReporter,
|
||||
) -> Option<Self> {
|
||||
let name = match name {
|
||||
"From" => "FromTimestamp".to_owned(),
|
||||
"To" => "ToTimestamp".to_owned(),
|
||||
|
|
@ -167,7 +182,7 @@ impl Parameter {
|
|||
SchemaLocation::Path => ParameterLocation::Path,
|
||||
};
|
||||
|
||||
let r#type = ParameterType::from_schema(&name, &schema.schema)?;
|
||||
let r#type = ParameterType::from_schema(&name, &schema.schema, warnings)?;
|
||||
|
||||
Some(Self {
|
||||
name,
|
||||
|
|
@ -364,7 +379,7 @@ mod test {
|
|||
|
||||
for (name, desc) in &schema.components.parameters {
|
||||
parameters += 1;
|
||||
if Parameter::from_schema(name, desc).is_none() {
|
||||
if Parameter::from_schema(name, desc, WarningReporter::new()).is_none() {
|
||||
unresolved.push(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -394,7 +409,8 @@ mod test {
|
|||
for param in &body.get.parameters {
|
||||
if let OpenApiPathParameter::Inline(inline) = param {
|
||||
params += 1;
|
||||
if Parameter::from_schema(inline.name, inline).is_none() {
|
||||
if Parameter::from_schema(inline.name, inline, WarningReporter::new()).is_none()
|
||||
{
|
||||
unresolved.push(format!("`{}.{}`", path, inline.name));
|
||||
}
|
||||
}
|
||||
|
|
@ -423,7 +439,9 @@ mod test {
|
|||
for param in &body.get.parameters {
|
||||
if let OpenApiPathParameter::Inline(inline) = param {
|
||||
if inline.r#in == SchemaLocation::Query {
|
||||
let Some(param) = Parameter::from_schema(inline.name, inline) else {
|
||||
let Some(param) =
|
||||
Parameter::from_schema(inline.name, inline, WarningReporter::new())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if matches!(
|
||||
|
|
|
|||
|
|
@ -91,12 +91,14 @@ impl Path {
|
|||
.to_owned();
|
||||
let param = parameters.get(&name.as_str())?;
|
||||
params.push(PathParameter::Component(Parameter::from_schema(
|
||||
&name, param,
|
||||
&name,
|
||||
param,
|
||||
warnings.child(&name),
|
||||
)?));
|
||||
}
|
||||
OpenApiPathParameter::Inline(schema) => {
|
||||
let name = schema.name.to_upper_camel_case();
|
||||
let parameter = Parameter::from_schema(&name, schema)?;
|
||||
let parameter = Parameter::from_schema(&name, schema, warnings.clone())?;
|
||||
params.push(PathParameter::Inline(parameter));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "torn-api"
|
||||
version = "4.2.0"
|
||||
version = "4.7.0"
|
||||
edition = "2021"
|
||||
description = "Auto-generated bindings for the v2 torn api"
|
||||
license = { workspace = true }
|
||||
|
|
@ -43,7 +43,7 @@ strum = { version = "0.27.1", features = ["derive"], optional = true }
|
|||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[build-dependencies]
|
||||
torn-api-codegen = { path = "../torn-api-codegen", version = "0.7.4" }
|
||||
torn-api-codegen = { path = "../torn-api-codegen", version = "0.8" }
|
||||
syn = { workspace = true, features = ["parsing"] }
|
||||
proc-macro2 = { workspace = true }
|
||||
prettyplease = "0.2"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@ pub(super) mod test {
|
|||
executor::{ExecutorExt, ReqwestClient},
|
||||
models::{
|
||||
faction_selection_name::FactionSelectionNameVariant, AttackCode,
|
||||
PersonalStatsCategoryEnum, PersonalStatsStatName, UserListEnum,
|
||||
PersonalStatsCategoryEnum, PersonalStatsStatName, UserId, UserListEnum,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -743,7 +743,7 @@ pub(super) mod test {
|
|||
|
||||
client
|
||||
.user()
|
||||
.bounties_for_id(986228.into(), |b| b)
|
||||
.bounties_for_id(UserId(986228).into(), |b| b)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -807,7 +807,7 @@ pub(super) mod test {
|
|||
|
||||
client
|
||||
.user()
|
||||
.forumposts_for_id(1.into(), |b| b)
|
||||
.forumposts_for_id(UserId(1).into(), |b| b)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -832,7 +832,7 @@ pub(super) mod test {
|
|||
|
||||
client
|
||||
.user()
|
||||
.forumthreads_for_id(1.into(), |b| b)
|
||||
.forumthreads_for_id(UserId(1).into(), |b| b)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -848,7 +848,11 @@ pub(super) mod test {
|
|||
async fn user_hof_for_id() {
|
||||
let client = test_client().await;
|
||||
|
||||
client.user().hof_for_id(1.into(), |b| b).await.unwrap();
|
||||
client
|
||||
.user()
|
||||
.hof_for_id(UserId(1).into(), |b| b)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1094,7 +1098,7 @@ pub(super) mod test {
|
|||
|
||||
client
|
||||
.user()
|
||||
.personalstats_for_id(1.into(), |b| b.cat(PersonalStatsCategoryEnum::All))
|
||||
.personalstats_for_id(UserId(1).into(), |b| b.cat(PersonalStatsCategoryEnum::All))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -1147,7 +1151,11 @@ pub(super) mod test {
|
|||
|
||||
client.user().profile(|b| b).await.unwrap();
|
||||
|
||||
client.user().profile_for_id(4.into(), |b| b).await.unwrap();
|
||||
client
|
||||
.user()
|
||||
.profile_for_id(UserId(4).into(), |b| b)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue