From f6d9f85be51593abc7cc8119ec020440e4762101 Mon Sep 17 00:00:00 2001 From: Kurt Wolf Date: Sun, 17 Dec 2023 18:32:19 -0500 Subject: [PATCH] update --- core/src/extractor.rs | 86 ++++++++++++++++++++---------------- core/src/extractor/record.rs | 12 +++-- hir/src/lib.rs | 2 +- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/core/src/extractor.rs b/core/src/extractor.rs index a9cac8a..a353e02 100644 --- a/core/src/extractor.rs +++ b/core/src/extractor.rs @@ -17,22 +17,19 @@ mod record; /// You might need to call add_operation_models after this pub fn extract_spec(spec: &OpenAPI) -> Result { - let operations = extract_api_operations(spec)?; - let schemas = extract_records(spec)?; + let mut result = HirSpec::default(); + extract_api_operations(spec, &mut result)?; + extract_records(spec, &mut result)?; let servers = extract_servers(spec)?; let security = extract_security_strategies(spec); let api_docs_url = extract_api_docs_link(spec); - let mut s = HirSpec { - operations, - schemas, - servers, - security, - api_docs_url, - }; - sanitize_spec(&mut s); - Ok(s) + result.servers = servers; + result.security = security; + result.api_docs_url = api_docs_url; + sanitize_spec(&mut result); + Ok(result) } pub fn is_optional(name: &str, param: &Schema, parent: &Schema) -> bool { @@ -149,7 +146,7 @@ pub fn extract_inputs<'a>( pub fn extract_response_success<'a>( operation: &'a oa::Operation, spec: &'a OpenAPI, -) -> Option<&'a ReferenceOr> { +) -> Option<&'a ReferenceOr> { use openapiv3::StatusCode; let response = operation @@ -232,31 +229,46 @@ pub fn make_name_from_method_and_url(method: &str, url: &str) -> String { format!("{method}{name}{last_group}") } -pub fn extract_api_operations(spec: &OpenAPI) -> Result> { - spec.operations() - .map(|(path, method, operation, item)| { - let name = match &operation.operation_id { - None => make_name_from_method_and_url(method, path), - Some(name) => name.clone(), - }; - let doc = extract_operation_doc(operation, DocFormat::Markdown); - let mut parameters = extract_inputs(operation, item, spec)?; - parameters.sort_by(|a, b| a.name.cmp(&b.name)); - let response_success = extract_response_success(operation, spec); - let ret = match response_success { - None => Ty::Unit, - Some(r) => schema_ref_to_ty(r, spec), - }; - Ok(Operation { - name, - doc, - parameters, - ret, - path: path.to_string(), - method: method.to_string(), - }) - }) - .collect() +pub fn extract_api_operations(spec: &OpenAPI, result: &mut HirSpec) -> Result<()> { + for (path, method, operation, item) in spec.operations() { + let name = match &operation.operation_id { + None => make_name_from_method_and_url(method, path), + Some(name) => name.clone(), + }; + let doc = extract_operation_doc(operation, DocFormat::Markdown); + let mut parameters = extract_inputs(operation, item, spec)?; + parameters.sort_by(|a, b| a.name.cmp(&b.name)); + let response_success = extract_response_success(operation, spec); + let mut needs_response_model = None; + let ret = match response_success { + None => Ty::Unit, + Some(ReferenceOr::Item(s)) => { + if matches!(s.schema_kind, oa::SchemaKind::Type(oa::Type::Object(_))) { + needs_response_model = Some(s); + Ty::model(&format!("{}Response", name)) + } else { + schema_to_ty(s, spec) + } + }, + Some(x @ ReferenceOr::Reference { .. }) => { + schema_ref_to_ty(x, spec) + } + }; + + if let Some(s) = needs_response_model { + let response_name = format!("{}Response", name); + result.schemas.insert(response_name.clone(), create_record(&response_name, s, spec)); + } + result.operations.push(Operation { + name, + doc, + parameters, + ret, + path: path.to_string(), + method: method.to_string(), + }); + } + Ok(()) } diff --git a/core/src/extractor/record.rs b/core/src/extractor/record.rs index cbd53d1..cfc7adb 100644 --- a/core/src/extractor/record.rs +++ b/core/src/extractor/record.rs @@ -7,7 +7,7 @@ use indexmap::IndexMap; use openapiv3::{ObjectType, OpenAPI, ReferenceOr, Schema, SchemaData, SchemaKind, SchemaReference, StringType, Type}; use tracing::warn; -use hir::{Doc, HirField, Record, StrEnum, Struct, NewType}; +use hir::{Doc, HirField, Record, StrEnum, Struct, NewType, HirSpec}; use crate::extractor; use crate::child_schemas::ChildSchemas; @@ -144,23 +144,21 @@ fn create_record_from_all_of(name: &str, all_of: &[ReferenceOr], schema_ } // records are data types: structs, newtypes -pub fn extract_records(spec: &OpenAPI) -> Result> { - let mut result: BTreeMap = BTreeMap::new(); +pub fn extract_records(spec: &OpenAPI, result: &mut HirSpec) -> Result<()> { let mut schema_lookup = HashMap::new(); spec.add_child_schemas(&mut schema_lookup); for (mut name, schema) in schema_lookup { let rec = create_record(&name, schema, spec); let name = rec.name().to_string(); - result.insert(name, rec); + result.schemas.insert(name, rec); } for (name, schema_ref) in spec.schemas() { let Some(reference) = schema_ref.as_ref_str() else { continue; }; - result.insert(name.clone(), Record::TypeAlias(name.clone(), create_field(&schema_ref, spec))); + result.schemas.insert(name.clone(), Record::TypeAlias(name.clone(), create_field(&schema_ref, spec))); } - - Ok(result) + Ok(()) } #[cfg(test)] diff --git a/hir/src/lib.rs b/hir/src/lib.rs index 3ed193d..76a79a6 100644 --- a/hir/src/lib.rs +++ b/hir/src/lib.rs @@ -306,7 +306,7 @@ impl Record { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct HirSpec { pub operations: Vec, pub schemas: BTreeMap,