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