oas3-gen 0.19.0

A rust type generator for OpenAPI v3.1.x specification.
use std::collections::{BTreeMap, BTreeSet};

use crate::generator::ast::{
  DiscriminatedEnumDef, EnumDef, ResponseEnumDef, RustPrimitive, RustType, TypeAliasDef, VariantContent,
};

pub(crate) struct DependencyGraph {
  dependencies: BTreeMap<String, BTreeSet<String>>,
}

impl DependencyGraph {
  pub(crate) fn build(types: &[RustType]) -> Self {
    let mut dependencies = BTreeMap::new();

    for rust_type in types {
      let type_name = rust_type.type_name().to_string();
      let deps = Self::extract_dependencies(rust_type);
      dependencies
        .entry(type_name)
        .and_modify(|existing: &mut BTreeSet<String>| existing.extend(deps.clone()))
        .or_insert(deps);
    }

    Self { dependencies }
  }

  pub(crate) fn get_dependencies(&self, type_name: &str) -> Option<&BTreeSet<String>> {
    self.dependencies.get(type_name)
  }

  fn extract_dependencies(rust_type: &RustType) -> BTreeSet<String> {
    let mut deps = BTreeSet::new();

    match rust_type {
      RustType::Struct(def) => {
        for field in &def.fields {
          Self::extract_from_type_ref(&field.rust_type, &mut deps);
        }
      }
      RustType::Enum(def) => Self::extract_from_enum(def, &mut deps),
      RustType::TypeAlias(def) => Self::extract_from_type_alias(def, &mut deps),
      RustType::DiscriminatedEnum(def) => Self::extract_from_discriminated_enum(def, &mut deps),
      RustType::ResponseEnum(def) => Self::extract_from_response_enum(def, &mut deps),
    }

    deps
  }

  fn extract_from_enum(def: &EnumDef, deps: &mut BTreeSet<String>) {
    for variant in &def.variants {
      if let VariantContent::Tuple(types) = &variant.content {
        for type_ref in types {
          Self::extract_from_type_ref(type_ref, deps);
        }
      }
    }
  }

  fn extract_from_type_alias(def: &TypeAliasDef, deps: &mut BTreeSet<String>) {
    Self::extract_from_type_ref(&def.target, deps);
  }

  fn extract_from_discriminated_enum(def: &DiscriminatedEnumDef, deps: &mut BTreeSet<String>) {
    for variant in &def.variants {
      deps.insert(variant.type_name.clone());
    }
    if let Some(fallback) = &def.fallback {
      deps.insert(fallback.type_name.clone());
    }
  }

  fn extract_from_response_enum(def: &ResponseEnumDef, deps: &mut BTreeSet<String>) {
    deps.insert(def.request_type.clone());
    for variant in &def.variants {
      if let Some(type_ref) = &variant.schema_type {
        Self::extract_from_type_ref(type_ref, deps);
      }
    }
  }

  fn extract_from_type_ref(type_ref: &crate::generator::ast::TypeRef, deps: &mut BTreeSet<String>) {
    if let RustPrimitive::Custom(name) = &type_ref.base_type {
      deps.insert(name.clone());
    }
  }
}