Compare commits

..

No commits in common. "485c2ea176aa6910736c846d330490dc0784ebc5" and "a90bcb00c4a13ad50199b7092985a002b749d2db" have entirely different histories.

11 changed files with 143 additions and 2784 deletions

4
Cargo.lock generated
View file

@ -2294,7 +2294,7 @@ dependencies = [
[[package]] [[package]]
name = "torn-api" name = "torn-api"
version = "1.7.0" version = "1.6.6"
dependencies = [ dependencies = [
"bon", "bon",
"bytes", "bytes",
@ -2316,7 +2316,7 @@ dependencies = [
[[package]] [[package]]
name = "torn-api-codegen" name = "torn-api-codegen"
version = "0.7.0" version = "0.6.2"
dependencies = [ dependencies = [
"heck", "heck",
"indexmap", "indexmap",

View file

@ -4,8 +4,8 @@ members = ["torn-api", "torn-api-codegen", "torn-key-pool"]
[workspace.package] [workspace.package]
license-file = "./LICENSE" license-file = "./LICENSE"
repository = "https://git.elimination.me/pyrite/torn-api.rs.git" repository = "https://github.com/TotallyNot/torn-api.rs.git"
homepage = "https://git.elimination.me/pyrite/torn-api.rs" homepage = "https://github.com/TotallyNot/torn-api.rs.git"
[workspace.dependencies] [workspace.dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -1,7 +1,7 @@
[package] [package]
name = "torn-api-codegen" name = "torn-api-codegen"
authors = ["Pyrit [2111649]"] authors = ["Pyrit [2111649]"]
version = "0.7.0" version = "0.6.2"
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-file = { workspace = true } license-file = { workspace = true }

View file

@ -77,11 +77,6 @@ impl EnumVariantTupleValue {
format: Some("int32"), format: Some("int32"),
.. ..
} => Some(Self::Primitive(PrimitiveType::I32)), } => Some(Self::Primitive(PrimitiveType::I32)),
OpenApiType {
r#type: Some("number"),
format: Some("float") | None,
..
} => Some(Self::Primitive(PrimitiveType::Float)),
_ => None, _ => None,
} }
} }
@ -151,7 +146,6 @@ impl EnumVariantTupleValue {
pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool { pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool {
match self { match self {
Self::Primitive(PrimitiveType::Float) => false,
Self::Primitive(_) => true, Self::Primitive(_) => true,
Self::Enum { inner, .. } => inner.is_comparable(resolved), Self::Enum { inner, .. } => inner.is_comparable(resolved),
Self::Ref { ty_name } | Self::ArrayOfRefs { ty_name } => resolved Self::Ref { ty_name } | Self::ArrayOfRefs { ty_name } => resolved

View file

@ -1,10 +1,8 @@
use std::{cell::RefCell, rc::Rc};
use indexmap::IndexMap; use indexmap::IndexMap;
use newtype::Newtype; use newtype::Newtype;
use object::Object; use object::Object;
use parameter::Parameter; use parameter::Parameter;
use path::{Path, PrettySegments}; use path::Path;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use r#enum::Enum; use r#enum::Enum;
use scope::Scope; use scope::Scope;
@ -37,73 +35,11 @@ impl Model {
} }
} }
#[derive(Default)] #[derive(Debug, Default)]
pub struct ResolvedSchema { pub struct ResolvedSchema {
pub models: IndexMap<String, Model>, pub models: IndexMap<String, Model>,
pub paths: IndexMap<String, Path>, pub paths: IndexMap<String, Path>,
pub parameters: Vec<Parameter>, pub parameters: Vec<Parameter>,
pub warnings: WarningReporter,
}
#[derive(Clone)]
pub struct Warning {
pub message: String,
pub path: Vec<String>,
}
impl std::fmt::Display for Warning {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "in {}: {}", self.path.join("."), self.message)
}
}
#[derive(Default)]
struct WarningReporterState {
warnings: Vec<Warning>,
path: Vec<String>,
}
#[derive(Clone, Default)]
pub struct WarningReporter {
state: Rc<RefCell<WarningReporterState>>,
}
impl WarningReporter {
pub fn new() -> Self {
Self::default()
}
fn push(&self, message: impl ToString) {
let mut state = self.state.borrow_mut();
let path = state.path.iter().map(ToString::to_string).collect();
state.warnings.push(Warning {
message: message.to_string(),
path,
});
}
fn child(&self, name: impl ToString) -> WarningReporter {
self.state.borrow_mut().path.push(name.to_string());
Self {
state: self.state.clone(),
}
}
pub fn is_empty(&self) -> bool {
self.state.borrow().warnings.is_empty()
}
pub fn get_warnings(&self) -> Vec<Warning> {
self.state.borrow().warnings.clone()
}
}
impl Drop for WarningReporter {
fn drop(&mut self) {
self.state.borrow_mut().path.pop();
}
} }
impl ResolvedSchema { impl ResolvedSchema {
@ -113,20 +49,14 @@ impl ResolvedSchema {
for (name, r#type) in &schema.components.schemas { for (name, r#type) in &schema.components.schemas {
result.models.insert( result.models.insert(
name.to_string(), name.to_string(),
resolve(r#type, name, &schema.components.schemas, &result.warnings), resolve(r#type, name, &schema.components.schemas),
); );
} }
for (path, body) in &schema.paths { for (path, body) in &schema.paths {
result.paths.insert( result.paths.insert(
path.to_string(), path.to_string(),
Path::from_schema( Path::from_schema(path, body, &schema.components.parameters).unwrap(),
path,
body,
&schema.components.parameters,
result.warnings.child(path),
)
.unwrap(),
); );
} }
@ -153,9 +83,7 @@ impl ResolvedSchema {
let mut output = TokenStream::default(); let mut output = TokenStream::default();
for path in self.paths.values() { for path in self.paths.values() {
output.extend( output.extend(path.codegen_request(self));
path.codegen_request(self, self.warnings.child(PrettySegments(&path.segments))),
);
} }
output output
@ -184,12 +112,7 @@ impl ResolvedSchema {
} }
} }
pub fn resolve( pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenApiType>) -> Model {
r#type: &OpenApiType,
name: &str,
schemas: &IndexMap<&str, OpenApiType>,
warnings: &WarningReporter,
) -> Model {
match r#type { match r#type {
OpenApiType { OpenApiType {
r#enum: Some(_), .. r#enum: Some(_), ..
@ -197,12 +120,8 @@ pub fn resolve(
OpenApiType { OpenApiType {
r#type: Some("object"), r#type: Some("object"),
.. ..
} => Model::Object(Object::from_schema_object( } => Object::from_schema_object(name, r#type, schemas)
name, .map_or(Model::Unresolved, Model::Object),
r#type,
schemas,
warnings.child(name),
)),
OpenApiType { OpenApiType {
r#type: Some(_), .. r#type: Some(_), ..
} => Newtype::from_schema(name, r#type).map_or(Model::Unresolved, Model::Newtype), } => Newtype::from_schema(name, r#type).map_or(Model::Unresolved, Model::Newtype),
@ -213,12 +132,7 @@ pub fn resolve(
OpenApiType { OpenApiType {
all_of: Some(types), all_of: Some(types),
.. ..
} => Model::Object(Object::from_all_of( } => Object::from_all_of(name, types, schemas).map_or(Model::Unresolved, Model::Object),
name,
types,
schemas,
warnings.child(name),
)),
_ => Model::Unresolved, _ => Model::Unresolved,
} }
} }
@ -245,14 +159,7 @@ mod test {
let user_id_schema = schema.components.schemas.get("UserId").unwrap(); let user_id_schema = schema.components.schemas.get("UserId").unwrap();
let reporter = WarningReporter::new(); let user_id = resolve(user_id_schema, "UserId", &schema.components.schemas);
let user_id = resolve(
user_id_schema,
"UserId",
&schema.components.schemas,
&reporter,
);
assert!(reporter.is_empty());
assert_eq!( assert_eq!(
user_id, user_id,
@ -267,13 +174,7 @@ mod test {
let attack_code_schema = schema.components.schemas.get("AttackCode").unwrap(); let attack_code_schema = schema.components.schemas.get("AttackCode").unwrap();
let attack_code = resolve( let attack_code = resolve(attack_code_schema, "AttackCode", &schema.components.schemas);
attack_code_schema,
"AttackCode",
&schema.components.schemas,
&reporter,
);
assert!(reporter.is_empty());
assert_eq!( assert_eq!(
attack_code, attack_code,
@ -295,10 +196,7 @@ mod test {
let total = schema.components.schemas.len(); let total = schema.components.schemas.len();
for (name, desc) in &schema.components.schemas { for (name, desc) in &schema.components.schemas {
let reporter = WarningReporter::new(); if resolve(desc, name, &schema.components.schemas) == Model::Unresolved {
if resolve(desc, name, &schema.components.schemas, &reporter) == Model::Unresolved
|| !reporter.is_empty()
{
unresolved.push(name); unresolved.push(name);
} }
} }

View file

@ -1,12 +1,12 @@
use heck::{ToSnakeCase, ToUpperCamelCase}; use heck::{ToSnakeCase, ToUpperCamelCase};
use indexmap::{map::Entry, IndexMap}; use indexmap::IndexMap;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::Ident; use syn::Ident;
use crate::openapi::r#type::OpenApiType; use crate::openapi::r#type::OpenApiType;
use super::{r#enum::Enum, ResolvedSchema, WarningReporter}; use super::{r#enum::Enum, ResolvedSchema};
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveType { pub enum PrimitiveType {
@ -85,7 +85,6 @@ impl PropertyType {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Property { pub struct Property {
pub field_name: String,
pub name: String, pub name: String,
pub description: Option<String>, pub description: Option<String>,
pub required: bool, pub required: bool,
@ -100,31 +99,24 @@ impl Property {
required: bool, required: bool,
schema: &OpenApiType, schema: &OpenApiType,
schemas: &IndexMap<&str, OpenApiType>, schemas: &IndexMap<&str, OpenApiType>,
warnings: WarningReporter,
) -> Option<Self> { ) -> Option<Self> {
let name = name.to_owned(); let name = name.to_owned();
let field_name = name.to_snake_case();
let description = schema.description.as_deref().map(ToOwned::to_owned); let description = schema.description.as_deref().map(ToOwned::to_owned);
match schema { match schema {
OpenApiType { OpenApiType {
r#enum: Some(_), .. r#enum: Some(_), ..
} => { } => Some(Self {
let Some(r#enum) = Enum::from_schema(&name.clone().to_upper_camel_case(), schema) r#type: PropertyType::Enum(Enum::from_schema(
else { &name.clone().to_upper_camel_case(),
warnings.push("Failed to create enum"); schema,
return None; )?),
}; name,
Some(Self { description,
r#type: PropertyType::Enum(r#enum), required,
name, deprecated: schema.deprecated,
field_name, nullable: false,
description, }),
required,
deprecated: schema.deprecated,
nullable: false,
})
}
OpenApiType { OpenApiType {
one_of: Some(types), one_of: Some(types),
.. ..
@ -133,7 +125,7 @@ impl Property {
r#type: Some("null"), r#type: Some("null"),
.. ..
}] => { }] => {
let mut inner = Self::from_schema(&name, required, left, schemas, warnings)?; let mut inner = Self::from_schema(&name, required, left, schemas)?;
inner.nullable = true; inner.nullable = true;
Some(inner) Some(inner)
} }
@ -145,19 +137,14 @@ impl Property {
one_of: Some(left.to_owned()), one_of: Some(left.to_owned()),
..schema.clone() ..schema.clone()
}; };
let mut inner = Self::from_schema(&name, required, &rest, schemas, warnings)?; let mut inner = Self::from_schema(&name, required, &rest, schemas)?;
inner.nullable = true; inner.nullable = true;
Some(inner) Some(inner)
} }
cases => { cases => {
let Some(r#enum) = Enum::from_one_of(&name.to_upper_camel_case(), cases) else { let r#enum = Enum::from_one_of(&name.to_upper_camel_case(), cases)?;
warnings.push("Failed to create oneOf enum");
return None;
};
Some(Self { Some(Self {
name, name,
field_name,
description, description,
required, required,
nullable: false, nullable: false,
@ -170,12 +157,9 @@ impl Property {
all_of: Some(types), all_of: Some(types),
.. ..
} => { } => {
let obj_name = name.to_upper_camel_case(); let composite = Object::from_all_of(&name.to_upper_camel_case(), types, schemas)?;
let composite =
Object::from_all_of(&obj_name, types, schemas, warnings.child(&obj_name));
Some(Self { Some(Self {
name, name,
field_name,
description, description,
required, required,
nullable: false, nullable: false,
@ -186,29 +170,23 @@ impl Property {
OpenApiType { OpenApiType {
r#type: Some("object"), r#type: Some("object"),
.. ..
} => { } => Some(Self {
let obj_name = name.to_upper_camel_case(); r#type: PropertyType::Nested(Box::new(Object::from_schema_object(
Some(Self { &name.clone().to_upper_camel_case(),
r#type: PropertyType::Nested(Box::new(Object::from_schema_object( schema,
&obj_name, schemas,
schema, )?)),
schemas, name,
warnings.child(&obj_name), description,
))), required,
name, deprecated: schema.deprecated,
field_name, nullable: false,
description, }),
required,
deprecated: schema.deprecated,
nullable: false,
})
}
OpenApiType { OpenApiType {
ref_path: Some(path), ref_path: Some(path),
.. ..
} => Some(Self { } => Some(Self {
name, name,
field_name,
description, description,
r#type: PropertyType::Ref((*path).to_owned()), r#type: PropertyType::Ref((*path).to_owned()),
required, required,
@ -220,11 +198,10 @@ impl Property {
items: Some(items), items: Some(items),
.. ..
} => { } => {
let inner = Self::from_schema(&name, required, items, schemas, warnings)?; let inner = Self::from_schema(&name, required, items, schemas)?;
Some(Self { Some(Self {
name, name,
field_name,
description, description,
required, required,
nullable: false, nullable: false,
@ -249,7 +226,6 @@ impl Property {
Some(Self { Some(Self {
name, name,
field_name,
description, description,
required, required,
nullable: false, nullable: false,
@ -257,10 +233,7 @@ impl Property {
r#type: PropertyType::Primitive(prim), r#type: PropertyType::Primitive(prim),
}) })
} }
_ => { _ => None,
warnings.push("Could not resolve property type");
None
}
} }
} }
@ -274,11 +247,11 @@ impl Property {
let name = &self.name; let name = &self.name;
let (name, serde_attr) = match name.as_str() { let (name, serde_attr) = match name.as_str() {
"type" => (format_ident!("r#type"), None), "type" => (format_ident!("r#type"), None),
name if name != self.field_name => ( name if name != name.to_snake_case() => (
format_ident!("{}", self.field_name), format_ident!("{}", name.to_snake_case()),
Some(quote! { #[serde(rename = #name)]}), Some(quote! { #[serde(rename = #name)]}),
), ),
_ => (format_ident!("{}", self.field_name), None), _ => (format_ident!("{name}"), None),
}; };
let ty_inner = self.r#type.codegen(namespace, resolved)?; let ty_inner = self.r#type.codegen(namespace, resolved)?;
@ -310,7 +283,7 @@ impl Property {
pub struct Object { pub struct Object {
pub name: String, pub name: String,
pub description: Option<String>, pub description: Option<String>,
pub properties: IndexMap<String, Property>, pub properties: Vec<Property>,
} }
impl Object { impl Object {
@ -318,8 +291,7 @@ impl Object {
name: &str, name: &str,
schema: &OpenApiType, schema: &OpenApiType,
schemas: &IndexMap<&str, OpenApiType>, schemas: &IndexMap<&str, OpenApiType>,
warnings: WarningReporter, ) -> Option<Self> {
) -> Self {
let mut result = Object { let mut result = Object {
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),
@ -327,54 +299,39 @@ impl Object {
}; };
let Some(props) = &schema.properties else { let Some(props) = &schema.properties else {
warnings.push("Missing properties"); return None;
return result;
}; };
let required = schema.required.clone().unwrap_or_default(); let required = schema.required.clone().unwrap_or_default();
for (prop_name, prop) in props { for (prop_name, prop) in props {
let Some(prop) = Property::from_schema( // HACK: This will cause a duplicate key otherwise
if ["itemDetails", "sci-fi", "non-attackers", "co-leader_id"].contains(prop_name) {
continue;
}
// TODO: implement custom enum for this (depends on overrides being added)
// Maybe this is an issue with the schema instead?
if *prop_name == "value" && name == "TornHof" {
continue;
}
result.properties.push(Property::from_schema(
prop_name, prop_name,
required.contains(prop_name), required.contains(prop_name),
prop, prop,
schemas, schemas,
warnings.child(prop_name), )?);
) else {
continue;
};
let field_name = prop.field_name.clone();
let entry = result.properties.entry(field_name.clone());
if let Entry::Occupied(mut entry) = entry {
let other_name = entry.get().name.clone();
warnings.push(format!(
"Property name collision: {other_name} and {field_name}"
));
// deprioritise kebab and camelcase
if other_name.contains('-')
|| other_name
.chars()
.filter(|c| c.is_alphabetic())
.all(|c| c.is_ascii_lowercase())
{
entry.insert(prop);
}
} else {
entry.insert_entry(prop);
}
} }
result Some(result)
} }
pub fn from_all_of( pub fn from_all_of(
name: &str, name: &str,
types: &[OpenApiType], types: &[OpenApiType],
schemas: &IndexMap<&str, OpenApiType>, schemas: &IndexMap<&str, OpenApiType>,
warnings: WarningReporter, ) -> Option<Self> {
) -> Self {
let mut result = Self { let mut result = Self {
name: name.to_owned(), name: name.to_owned(),
..Default::default() ..Default::default()
@ -382,29 +339,22 @@ impl Object {
for r#type in types { for r#type in types {
let r#type = if let OpenApiType { let r#type = if let OpenApiType {
ref_path: Some(ref_path), ref_path: Some(path),
.. ..
} = r#type } = r#type
{ {
let Some(name) = ref_path.strip_prefix("#/components/schemas/") else { let name = path.strip_prefix("#/components/schemas/")?;
warnings.push(format!("Malformed ref {ref_path}")); schemas.get(name)?
continue;
};
let Some(schema) = schemas.get(name) else {
warnings.push(format!("Missing schema for ref {name}"));
continue;
};
schema
} else { } else {
r#type r#type
}; };
let obj = Self::from_schema_object(name, r#type, schemas, warnings.child("variant")); let obj = Self::from_schema_object(name, r#type, schemas)?;
result.description = result.description.or(obj.description); result.description = result.description.or(obj.description);
result.properties.extend(obj.properties); result.properties.extend(obj.properties);
} }
result Some(result)
} }
pub fn codegen(&self, resolved: &ResolvedSchema) -> Option<TokenStream> { pub fn codegen(&self, resolved: &ResolvedSchema) -> Option<TokenStream> {
@ -421,7 +371,7 @@ impl Object {
}; };
let mut props = Vec::with_capacity(self.properties.len()); let mut props = Vec::with_capacity(self.properties.len());
for (_, prop) in &self.properties { for prop in &self.properties {
props.push(prop.codegen(&mut namespace, resolved)?); props.push(prop.codegen(&mut namespace, resolved)?);
} }
@ -491,14 +441,7 @@ mod test {
for (name, desc) in &schema.components.schemas { for (name, desc) in &schema.components.schemas {
if desc.r#type == Some("object") { if desc.r#type == Some("object") {
objects += 1; objects += 1;
let reporter = WarningReporter::new(); if Object::from_schema_object(name, desc, &schema.components.schemas).is_none() {
Object::from_schema_object(
name,
desc,
&schema.components.schemas,
reporter.clone(),
);
if !reporter.is_empty() {
unresolved.push(name); unresolved.push(name);
} }
} }

View file

@ -14,7 +14,7 @@ use crate::openapi::{
use super::{ use super::{
parameter::{Parameter, ParameterLocation, ParameterType}, parameter::{Parameter, ParameterLocation, ParameterType},
union::Union, union::Union,
ResolvedSchema, WarningReporter, ResolvedSchema,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -23,21 +23,6 @@ pub enum PathSegment {
Parameter { name: String }, Parameter { name: String },
} }
pub struct PrettySegments<'a>(pub &'a [PathSegment]);
impl std::fmt::Display for PrettySegments<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for segment in self.0 {
match segment {
PathSegment::Constant(c) => write!(f, "/{c}")?,
PathSegment::Parameter { name } => write!(f, "/{{{name}}}")?,
}
}
Ok(())
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PathParameter { pub enum PathParameter {
Inline(Parameter), Inline(Parameter),
@ -66,7 +51,6 @@ impl Path {
path: &str, path: &str,
schema: &OpenApiPath, schema: &OpenApiPath,
parameters: &IndexMap<&str, OpenApiParameter>, parameters: &IndexMap<&str, OpenApiParameter>,
warnings: WarningReporter,
) -> Option<Self> { ) -> Option<Self> {
let mut segments = Vec::new(); let mut segments = Vec::new();
for segment in path.strip_prefix('/')?.split('/') { for segment in path.strip_prefix('/')?.split('/') {
@ -127,13 +111,9 @@ impl Path {
.strip_prefix("#/components/schemas/")? .strip_prefix("#/components/schemas/")?
.to_owned(), .to_owned(),
}, },
OpenApiResponseBody::Union { any_of: _ } => { OpenApiResponseBody::Union { any_of: _ } => PathResponse::ArbitraryUnion(
PathResponse::ArbitraryUnion(Union::from_schema( Union::from_schema("Response", &schema.get.response_content)?,
"Response", ),
&schema.get.response_content,
warnings.child("response"),
)?)
}
}; };
Some(Self { Some(Self {
@ -146,11 +126,7 @@ impl Path {
}) })
} }
pub fn codegen_request( pub fn codegen_request(&self, resolved: &ResolvedSchema) -> Option<TokenStream> {
&self,
resolved: &ResolvedSchema,
warnings: WarningReporter,
) -> Option<TokenStream> {
let name = if self.segments.len() == 1 { let name = if self.segments.len() == 1 {
let Some(PathSegment::Constant(first)) = self.segments.first() else { let Some(PathSegment::Constant(first)) = self.segments.first() else {
return None; return None;
@ -231,30 +207,17 @@ impl Path {
let query_val = &param.value; let query_val = &param.value;
if param.location == ParameterLocation::Path { if param.location == ParameterLocation::Path {
if self.segments.iter().any(|s| { discriminant.push(ty.clone());
if let PathSegment::Parameter { name } = s { discriminant_val.push(quote! { self.#name });
name == &param.value let path_name = format_ident!("{}", param.value);
} else { start_fields.push(quote! {
false #[cfg_attr(feature = "builder", builder(start_fn))]
} #builder_param
}) { pub #name: #ty
discriminant.push(ty.clone()); });
discriminant_val.push(quote! { self.#name }); fmt_val.push(quote! {
let path_name = format_ident!("{}", param.value); #path_name=self.#name
start_fields.push(quote! { });
#[cfg_attr(feature = "builder", builder(start_fn))]
#builder_param
pub #name: #ty
});
fmt_val.push(quote! {
#path_name=self.#name
});
} else {
warnings.push(format!(
"Provided path parameter is not present in the url: {}",
param.value
));
}
} else { } else {
let ty = if param.required { let ty = if param.required {
convert_field.push(quote! { convert_field.push(quote! {
@ -366,15 +329,7 @@ impl Path {
PathParameter::Component(param) => (param, false), PathParameter::Component(param) => (param, false),
}; };
if param.location == ParameterLocation::Path if param.location == ParameterLocation::Path {
&& self.segments.iter().any(|s| {
if let PathSegment::Parameter { name } = s {
name == &param.value
} else {
false
}
})
{
let ty = match &param.r#type { let ty = match &param.r#type {
ParameterType::I32 { .. } | ParameterType::Enum { .. } => { ParameterType::I32 { .. } | ParameterType::Enum { .. } => {
let ty_name = format_ident!("{}", param.name); let ty_name = format_ident!("{}", param.name);
@ -489,15 +444,8 @@ impl Path {
PathParameter::Inline(param) => (param, true), PathParameter::Inline(param) => (param, true),
PathParameter::Component(param) => (param, false), PathParameter::Component(param) => (param, false),
}; };
if param.location == ParameterLocation::Path
&& self.segments.iter().any(|s| { if param.location == ParameterLocation::Path {
if let PathSegment::Parameter { name } = s {
name == &param.value
} else {
false
}
})
{
let ty = match &param.r#type { let ty = match &param.r#type {
ParameterType::I32 { .. } | ParameterType::Enum { .. } => { ParameterType::I32 { .. } | ParameterType::Enum { .. } => {
let ty_name = format_ident!("{}", param.name); let ty_name = format_ident!("{}", param.name);
@ -656,14 +604,7 @@ mod test {
for (name, desc) in &schema.paths { for (name, desc) in &schema.paths {
paths += 1; paths += 1;
if Path::from_schema( if Path::from_schema(name, desc, &schema.components.parameters).is_none() {
name,
desc,
&schema.components.parameters,
WarningReporter::new(),
)
.is_none()
{
unresolved.push(name); unresolved.push(name);
} }
} }
@ -686,23 +627,18 @@ mod test {
fn codegen_paths() { fn codegen_paths() {
let schema = get_schema(); let schema = get_schema();
let resolved = ResolvedSchema::from_open_api(&schema); let resolved = ResolvedSchema::from_open_api(&schema);
let reporter = WarningReporter::new();
let mut paths = 0; let mut paths = 0;
let mut unresolved = vec![]; let mut unresolved = vec![];
for (name, desc) in &schema.paths { for (name, desc) in &schema.paths {
paths += 1; paths += 1;
let Some(path) = let Some(path) = Path::from_schema(name, desc, &schema.components.parameters) else {
Path::from_schema(name, desc, &schema.components.parameters, reporter.clone())
else {
unresolved.push(name); unresolved.push(name);
continue; continue;
}; };
if path.codegen_scope_call().is_none() if path.codegen_scope_call().is_none() || path.codegen_request(&resolved).is_none() {
|| path.codegen_request(&resolved, reporter.clone()).is_none()
{
unresolved.push(name); unresolved.push(name);
} }
} }

View file

@ -4,8 +4,6 @@ use quote::{format_ident, quote};
use crate::openapi::path::OpenApiResponseBody; use crate::openapi::path::OpenApiResponseBody;
use super::WarningReporter;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Union { pub struct Union {
pub name: String, pub name: String,
@ -13,23 +11,10 @@ pub struct Union {
} }
impl Union { impl Union {
pub fn from_schema( pub fn from_schema(name: &str, schema: &OpenApiResponseBody) -> Option<Self> {
name: &str,
schema: &OpenApiResponseBody,
warnings: WarningReporter,
) -> Option<Self> {
let members = match schema { let members = match schema {
OpenApiResponseBody::Union { any_of } => { OpenApiResponseBody::Union { any_of } => {
let mut members = Vec::with_capacity(any_of.len()); any_of.iter().map(|l| l.ref_path.to_owned()).collect()
for l in any_of {
let path = l.ref_path.to_owned();
if members.contains(&path) {
warnings.push(format!("Duplicate member: {path}"));
} else {
members.push(path);
}
}
members
} }
_ => return None, _ => return None,
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "torn-api" name = "torn-api"
version = "1.7.0" version = "1.6.6"
edition = "2021" edition = "2021"
description = "Auto-generated bindings for the v2 torn api" description = "Auto-generated bindings for the v2 torn api"
license-file = { workspace = true } license-file = { workspace = true }
@ -39,7 +39,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.0" } torn-api-codegen = { path = "../torn-api-codegen", version = "0.6.2" }
syn = { workspace = true, features = ["parsing"] } syn = { workspace = true, features = ["parsing"] }
proc-macro2 = { workspace = true } proc-macro2 = { workspace = true }
prettyplease = "0.2" prettyplease = "0.2"

View file

@ -28,8 +28,4 @@ fn main() {
let scopes_file = syn::parse2(resolved.codegen_scopes()).unwrap(); let scopes_file = syn::parse2(resolved.codegen_scopes()).unwrap();
let scopes_pretty = prettyplease::unparse(&scopes_file); let scopes_pretty = prettyplease::unparse(&scopes_file);
fs::write(&scopes_dest, scopes_pretty).unwrap(); fs::write(&scopes_dest, scopes_pretty).unwrap();
for warning in resolved.warnings.get_warnings() {
println!("cargo:warning={}", warning);
}
} }

File diff suppressed because it is too large Load diff