Allow conversion overrides by specifying a schema (#280)
This commit is contained in:
parent
df5f513083
commit
57031d77d3
|
@ -1158,6 +1158,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"progenitor-impl",
|
||||
"quote",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_tokenstream",
|
||||
|
@ -1928,7 +1929,7 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
|||
[[package]]
|
||||
name = "typify"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#1aefa41396d0aefa1a9dbb32320445ab02a5cbc3"
|
||||
source = "git+https://github.com/oxidecomputer/typify#da0505b0b43180ee85d8df2a7c2504acb7ce01e0"
|
||||
dependencies = [
|
||||
"typify-impl",
|
||||
"typify-macro",
|
||||
|
@ -1937,7 +1938,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "typify-impl"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#1aefa41396d0aefa1a9dbb32320445ab02a5cbc3"
|
||||
source = "git+https://github.com/oxidecomputer/typify#da0505b0b43180ee85d8df2a7c2504acb7ce01e0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"log",
|
||||
|
@ -1955,7 +1956,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "typify-macro"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#1aefa41396d0aefa1a9dbb32320445ab02a5cbc3"
|
||||
source = "git+https://github.com/oxidecomputer/typify#da0505b0b43180ee85d8df2a7c2504acb7ce01e0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -15,5 +15,6 @@ members = [
|
|||
#typify = { path = "../typify/typify" }
|
||||
|
||||
#[patch.crates-io]
|
||||
#serde_tokenstream = { path = "../serde_tokenstream" }
|
||||
#typify = { path = "../typify/typify" }
|
||||
#rustfmt-wrapper = { path = "../rustfmt-wrapper" }
|
||||
|
|
|
@ -3,8 +3,9 @@ name = "progenitor-impl"
|
|||
version = "0.2.1-dev"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator - core implementation"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
readme = "../README.md"
|
||||
|
||||
[dependencies]
|
||||
heck = "0.4.0"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pre-release-replacements = []
|
|
@ -52,6 +52,7 @@ pub struct GenerationSettings {
|
|||
post_hook: Option<TokenStream>,
|
||||
extra_derives: Vec<String>,
|
||||
patch: HashMap<String, TypePatch>,
|
||||
convert: Vec<(schemars::schema::SchemaObject, String, Vec<String>)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, PartialEq, Eq)]
|
||||
|
@ -122,6 +123,20 @@ impl GenerationSettings {
|
|||
.insert(type_name.as_ref().to_string(), patch.clone());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_conversion<S: ToString, I: Iterator<Item = impl ToString>>(
|
||||
&mut self,
|
||||
schema: schemars::schema::SchemaObject,
|
||||
type_name: S,
|
||||
impls: I,
|
||||
) -> &mut Self {
|
||||
self.convert.push((
|
||||
schema,
|
||||
type_name.to_string(),
|
||||
impls.map(|x| x.to_string()).collect(),
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Generator {
|
||||
|
@ -149,6 +164,16 @@ impl Generator {
|
|||
settings.patch.iter().for_each(|(type_name, patch)| {
|
||||
type_settings.with_patch(type_name, patch);
|
||||
});
|
||||
settings
|
||||
.convert
|
||||
.iter()
|
||||
.for_each(|(schema, type_name, impls)| {
|
||||
type_settings.with_conversion(
|
||||
schema.clone(),
|
||||
type_name,
|
||||
impls.iter(),
|
||||
);
|
||||
});
|
||||
Self {
|
||||
type_space: TypeSpace::new(&type_settings),
|
||||
settings: settings.clone(),
|
||||
|
|
|
@ -55,9 +55,9 @@ pub mod types {
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
|
||||
pub struct ReportFinishBody {
|
||||
pub duration_millis: i32,
|
||||
pub duration_millis: usize,
|
||||
pub end_time: chrono::DateTime<chrono::offset::Utc>,
|
||||
pub exit_status: i32,
|
||||
pub exit_status: usize,
|
||||
pub id: ReportId,
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,11 @@ pub mod types {
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
|
||||
pub struct ReportSummary {
|
||||
pub age_seconds: i32,
|
||||
pub duration_seconds: i32,
|
||||
pub age_seconds: usize,
|
||||
pub duration_seconds: usize,
|
||||
pub host: String,
|
||||
pub job: String,
|
||||
pub status: i32,
|
||||
pub status: usize,
|
||||
pub when: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
|
||||
|
@ -324,9 +324,9 @@ pub mod types {
|
|||
}
|
||||
|
||||
pub struct ReportFinishBody {
|
||||
duration_millis: Result<i32, String>,
|
||||
duration_millis: Result<usize, String>,
|
||||
end_time: Result<chrono::DateTime<chrono::offset::Utc>, String>,
|
||||
exit_status: Result<i32, String>,
|
||||
exit_status: Result<usize, String>,
|
||||
id: Result<super::ReportId, String>,
|
||||
}
|
||||
|
||||
|
@ -344,7 +344,7 @@ pub mod types {
|
|||
impl ReportFinishBody {
|
||||
pub fn duration_millis<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: std::convert::TryInto<i32>,
|
||||
T: std::convert::TryInto<usize>,
|
||||
T::Error: std::fmt::Display,
|
||||
{
|
||||
self.duration_millis = value.try_into().map_err(|e| {
|
||||
|
@ -364,7 +364,7 @@ pub mod types {
|
|||
}
|
||||
pub fn exit_status<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: std::convert::TryInto<i32>,
|
||||
T: std::convert::TryInto<usize>,
|
||||
T::Error: std::fmt::Display,
|
||||
{
|
||||
self.exit_status = value
|
||||
|
@ -624,11 +624,11 @@ pub mod types {
|
|||
}
|
||||
|
||||
pub struct ReportSummary {
|
||||
age_seconds: Result<i32, String>,
|
||||
duration_seconds: Result<i32, String>,
|
||||
age_seconds: Result<usize, String>,
|
||||
duration_seconds: Result<usize, String>,
|
||||
host: Result<String, String>,
|
||||
job: Result<String, String>,
|
||||
status: Result<i32, String>,
|
||||
status: Result<usize, String>,
|
||||
when: Result<chrono::DateTime<chrono::offset::Utc>, String>,
|
||||
}
|
||||
|
||||
|
@ -648,7 +648,7 @@ pub mod types {
|
|||
impl ReportSummary {
|
||||
pub fn age_seconds<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: std::convert::TryInto<i32>,
|
||||
T: std::convert::TryInto<usize>,
|
||||
T::Error: std::fmt::Display,
|
||||
{
|
||||
self.age_seconds = value
|
||||
|
@ -658,7 +658,7 @@ pub mod types {
|
|||
}
|
||||
pub fn duration_seconds<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: std::convert::TryInto<i32>,
|
||||
T: std::convert::TryInto<usize>,
|
||||
T::Error: std::fmt::Display,
|
||||
{
|
||||
self.duration_seconds = value.try_into().map_err(|e| {
|
||||
|
@ -691,7 +691,7 @@ pub mod types {
|
|||
}
|
||||
pub fn status<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: std::convert::TryInto<i32>,
|
||||
T: std::convert::TryInto<usize>,
|
||||
T::Error: std::fmt::Display,
|
||||
{
|
||||
self.status = value
|
||||
|
|
|
@ -26,7 +26,18 @@ fn verify_apis(openapi_file: &str) {
|
|||
.with_interface(InterfaceStyle::Builder)
|
||||
.with_tag(TagStyle::Merged)
|
||||
.with_derive("JsonSchema")
|
||||
.with_patch("Name", TypePatch::default().with_derive("Hash")),
|
||||
.with_patch("Name", TypePatch::default().with_derive("Hash"))
|
||||
.with_conversion(
|
||||
schemars::schema::SchemaObject {
|
||||
instance_type: Some(
|
||||
schemars::schema::InstanceType::Integer.into(),
|
||||
),
|
||||
format: Some("int32".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
"usize",
|
||||
["Display"].into_iter(),
|
||||
),
|
||||
);
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
|
|
|
@ -3,18 +3,20 @@ name = "progenitor-macro"
|
|||
version = "0.2.1-dev"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator - macros"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
readme = "../README.md"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
openapiv3 = "1.0.0"
|
||||
proc-macro2 = "1.0"
|
||||
progenitor-impl = { version = "0.2.1-dev", path = "../progenitor-impl" }
|
||||
quote = "1.0"
|
||||
schemars = "0.8.11"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_tokenstream = "0.1.6"
|
||||
syn = "1.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pre-release-replacements = []
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2022 Oxide Computer Company
|
||||
|
||||
use std::{collections::HashMap, path::Path};
|
||||
use std::{collections::HashMap, fmt::Display, path::Path};
|
||||
|
||||
use openapiv3::OpenAPI;
|
||||
use proc_macro::TokenStream;
|
||||
|
@ -8,8 +8,9 @@ use progenitor_impl::{
|
|||
GenerationSettings, Generator, InterfaceStyle, TagStyle, TypePatch,
|
||||
};
|
||||
use quote::{quote, ToTokens};
|
||||
use schemars::schema::SchemaObject;
|
||||
use serde::Deserialize;
|
||||
use serde_tokenstream::ParseWrapper;
|
||||
use serde_tokenstream::{OrderedMap, ParseWrapper};
|
||||
use syn::LitStr;
|
||||
|
||||
/// Generates a client from the given OpenAPI document
|
||||
|
@ -82,6 +83,24 @@ struct MacroSettings {
|
|||
derives: Vec<ParseWrapper<syn::Path>>,
|
||||
#[serde(default)]
|
||||
patch: HashMap<ParseWrapper<syn::Type>, MacroPatch>,
|
||||
#[serde(default)]
|
||||
convert: OrderedMap<
|
||||
SchemaObject,
|
||||
(ParseWrapper<syn::Path>, Vec<MacroSettingsImpl>),
|
||||
>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum MacroSettingsImpl {
|
||||
Display,
|
||||
}
|
||||
|
||||
impl Display for MacroSettingsImpl {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MacroSettingsImpl::Display => f.write_str("Display"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -153,6 +172,7 @@ fn do_generate_api(item: TokenStream) -> Result<TokenStream, syn::Error> {
|
|||
post_hook,
|
||||
derives,
|
||||
patch,
|
||||
convert,
|
||||
} = serde_tokenstream::from_tokenstream(&item.into())?;
|
||||
let mut settings = GenerationSettings::default();
|
||||
settings.with_interface(interface);
|
||||
|
@ -174,6 +194,15 @@ fn do_generate_api(item: TokenStream) -> Result<TokenStream, syn::Error> {
|
|||
&patch.into(),
|
||||
);
|
||||
});
|
||||
convert
|
||||
.into_iter()
|
||||
.for_each(|(schema, (type_name, impls))| {
|
||||
settings.with_conversion(
|
||||
schema,
|
||||
type_name.to_token_stream(),
|
||||
impls.into_iter(),
|
||||
);
|
||||
});
|
||||
(spec.into_inner(), settings)
|
||||
};
|
||||
|
||||
|
|
|
@ -3,8 +3,11 @@ name = "progenitor"
|
|||
version = "0.2.1-dev"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
readme = "../README.md"
|
||||
keywords = ["openapi", "openapiv3", "sdk", "generator", "proc_macro"]
|
||||
categories = ["api-bindings", "compilers"]
|
||||
|
||||
[dependencies]
|
||||
progenitor-client = { version = "0.2.1-dev", path = "../progenitor-client" }
|
||||
|
|
Loading…
Reference in New Issue