fn generate_type_for_schema()

in compiler-rs/openapi_to_clients_schema/src/types.rs [99:177]


fn generate_type_for_schema(
    open_api: &OpenAPI,
    id: &str,
    schema: &Schema,
    types: &mut Types,
) -> anyhow::Result<TypeName> {
    if let Some(typedef) = types.get(id) {
        // info!("Type '{id}' already generated");
        return Ok(typedef.name().clone());
    }

    types.track(id);

    // Build the common "base" fields from the OpenApi schema_data
    let type_name = id_to_typename(id);
    let data = &schema.schema_data;
    let mut base = BaseType::new(type_name.clone());
    base.description = data.description.clone();
    if data.deprecated {
        base.deprecation = Some(Deprecation {
            version: "".into(),
            description: "".into(),
        })
    }
    if let Some(ref docs) = data.external_docs {
        base.ext_doc_url = Some(docs.url.clone())
    }

    // TODO: data.readonly/writeonly -> OverloadOf?
    // TODO: data.default -> serverDefault
    // TODO: data.extensions -> see what's there, fail on unknown ones
    for (k, v) in &data.extensions {
        info!("{id} - extension {k} = {v}");
    }

    if data.discriminator.is_some() {
        // FIXME: data.discriminator -> internally tagged variant

        bail!(
            "Discriminator in schema {} has to become an internally tagged variant",
            id
        );
    }

    use openapiv3::SchemaKind::*;
    match &schema.schema_kind {
        Type(t) => {
            // Type alias to a primitive type or enum
            generate_schema_kind_type(open_api, id, t, base, types)?;
        }
        Not { .. } => {
            bail!("Unsupported schema kind for '{}' - {:?}", id, schema.schema_kind);
        }
        Any(any) => {
            let not_any = Schema {
                schema_data: data.clone(),
                schema_kind: openapi::any_to_schema(any.clone())?,
            };
            generate_type_for_schema(open_api, id, &not_any, types)?;
        }
        // Definitions:
        // - oneOf: validates the value against exactly one of the subschemas
        // - anyOf: validates the value against any (one or more) of the subschemas
        // - allOf – validates the value against all the subschemas
        //
        // AnyOf sits in between oneOf and allOf and doesn't have a direct equivalence in schema.json
        // We choose to handle it like a oneOf, even if oneOf is more constrained, as allOf is used for
        // composition/inheritance.
        AllOf { all_of } => {
            let merged = open_api.merge_schemas(all_of, data)?;
            generate_type_for_schema(open_api, id, &merged, types)?;
        }
        AnyOf { any_of: one_of } | OneOf { one_of } => {
            generate_schema_kind_one_of(open_api, id, one_of, &data.discriminator, base, types)?;
        }
    }

    Ok(type_name)
}