in compiler-rs/clients_schema_to_openapi/src/schemas.rs [272:367]
fn convert_interface_definition(&mut self, itf: &Interface) -> anyhow::Result<Schema> {
if !itf.generics.is_empty() {
bail!(
"Interface definition {} has generic parameters. Expand generics before conversion",
itf.base.name
);
}
let mut schema = if let Some(container) = &itf.variants {
// TODO: interface definition container.non_exhaustive
let _non_exhaustive = container.non_exhaustive;
// Split container properties and variants
let container_props = itf
.properties
.iter()
.filter(|p| p.container_property)
.collect::<Vec<_>>();
let variant_props = itf
.properties
.iter()
.filter(|p| !p.container_property)
.collect::<Vec<_>>();
// A container is represented by an object will all optional properties and exactly one that
// needs to be set.
let mut schema = ObjectType {
properties: self.convert_properties(variant_props.iter().copied())?,
required: vec![],
additional_properties: None,
min_properties: Some(1),
max_properties: Some(1),
}
.into_schema();
if !container_props.is_empty() {
// Create a schema for the container property, and group it in an "allOf" with variants
let container_props_schema = ObjectType {
properties: self.convert_properties(container_props.iter().copied())?,
required: self.required_properties(container_props.iter().copied()),
additional_properties: None,
min_properties: None,
max_properties: None,
}
.into_schema_ref();
schema = SchemaKind::AllOf {
all_of: vec![container_props_schema, schema.into_schema_ref()],
}
.into_schema();
}
self.fill_schema_with_base(&mut schema, &itf.base);
schema
} else {
let schema = ObjectType {
properties: self.convert_properties(itf.properties.iter())?,
required: self.required_properties(itf.properties.iter()),
additional_properties: None,
min_properties: None,
max_properties: None,
}
.into_schema();
schema
};
// Inheritance
if let Some(inherit) = &itf.inherits {
schema = SchemaKind::AllOf {
all_of: vec![self.for_type_name(&inherit.typ)?, schema.into_schema_ref()],
}
.into_schema();
}
// Behaviors
for bh in &itf.implements {
match bh.typ.name.as_str() {
name @ ("AdditionalProperty" | "AdditionalProperties") => {
let single = name == "AdditionalProperty";
let value_schema = self.convert_value_of(&bh.generics[1])?;
schema = ObjectType {
properties: Default::default(),
required: vec![],
additional_properties: Some(AdditionalProperties::Schema(Box::new(value_schema))),
min_properties: if single { Some(1) } else { None },
max_properties: if single { Some(1) } else { None },
}
.into_schema();
}
_ => bail!("Unknown behavior {}", &bh.typ),
}
}
Ok(schema)
}