fn convert_interface_definition()

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)
    }