1use crate::error::DerefError;
2use crate::reference::ReferenceOrExt;
3use alloc::boxed::Box;
4use alloc::string::String;
5use alloc::string::ToString;
6use alloc::vec::Vec;
7use indexmap::IndexMap;
8use openapiv3::*;
9
10pub trait SpecExt {
12 fn deref_all(self) -> OpenAPI;
32}
33
34impl SpecExt for OpenAPI {
35 fn deref_all(mut self) -> OpenAPI {
38 if let Some(comp) = self.components.as_ref() {
39 for (_, path_item) in &mut self.paths.paths {
40 deref_everything_in_path(path_item, comp);
41 }
42 }
43 self
45 }
46}
47
48fn deref_everything_in_path(path_item: &mut ReferenceOr<PathItem>, components: &Components) {
49 let p_item = path_item.to_item_mut(); set_deref_all_params(&mut p_item.parameters, components);
51
52 let p_item2 = p_item.clone(); for operation in operation_list(p_item) {
55 set_deref_all_params(&mut operation.parameters, components);
57 for param in &p_item2.parameters {
59 operation.parameters.push(param.clone());
60 }
61
62 if operation.request_body.is_some() {
64 let req_body = operation.request_body.as_mut().unwrap();
65 set_deref(req_body, &components.request_bodies, &mut Vec::new());
66 let body: &mut RequestBody = req_body.to_item_mut();
67 for (_, media) in &mut body.content {
68 if media.schema.is_none() {
69 continue;
70 }
71 let schema = media.schema.as_mut().unwrap();
72 let mut referred = Vec::new();
73 set_deref(schema, &components.schemas, &mut referred);
74 set_defer_schema_contents(schema.to_item_mut(), components, 10, &mut referred);
75 }
76 }
77
78 for (_status_code, response) in &mut operation.responses.responses {
80 set_deref(response, &components.responses, &mut Vec::new());
81 for (_name, header) in &mut response.to_item_mut().headers {
82 set_deref(header, &components.headers, &mut Vec::new());
83 }
84 for (_, media) in &mut response.to_item_mut().content {
85 if media.schema.is_none() {
86 continue;
87 }
88 let schema = media.schema.as_mut().unwrap();
89 let mut referred = Vec::new();
90 set_deref(schema, &components.schemas, &mut referred);
91 set_defer_schema_contents(schema.to_item_mut(), components, 10, &mut referred);
92 }
93 }
94 }
95}
96
97fn set_defer_schema_contents(
98 schema: &mut Schema,
99 components: &Components,
100 recursion: i32,
101 referred: &mut Vec<String>,
102) {
103 if recursion == 0 {
104 return;
105 }
106 match &mut schema.schema_kind {
107 SchemaKind::Type(schema_type) => match schema_type {
108 Type::Object(object) => {
109 for (_name, property) in &mut object.properties {
110 set_deref_box(property, &components.schemas, referred);
111 set_defer_schema_contents(
112 property.to_item_mut(),
113 components,
114 recursion - 1,
115 referred,
116 );
117 }
118 }
119 Type::Array(array) => match &mut array.items {
120 None => {}
121 Some(items) => {
122 set_deref_box(items, &components.schemas, referred);
123 set_defer_schema_contents(
124 items.to_item_mut(),
125 components,
126 recursion - 1,
127 referred,
128 );
129 }
130 },
131 _ => {}
132 },
133
134 SchemaKind::OneOf { ref mut one_of } => {
135 for sch in &mut one_of.iter_mut() {
136 set_deref(sch, &components.schemas, referred);
137 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
138 }
139 }
140 SchemaKind::AnyOf { ref mut any_of } => {
141 for sch in &mut any_of.iter_mut() {
142 set_deref(sch, &components.schemas, referred);
143 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
144 }
145 }
146 SchemaKind::AllOf { ref mut all_of } => {
147 for sch in &mut all_of.iter_mut() {
148 set_deref(sch, &components.schemas, referred);
149 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
150 }
151 }
152 SchemaKind::Not { ref mut not } => {
153 let sch = not;
154 set_deref(sch, &components.schemas, referred);
155 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
156 }
157 SchemaKind::Any(schema) => {
158 for (_name, property) in &mut schema.properties {
159 set_deref_box(property, &components.schemas, referred);
160 set_defer_schema_contents(property.to_item_mut(), components, recursion - 1, referred);
161 }
162 if schema.items.is_some() {
163 let the_items = schema.items.as_mut().unwrap();
164 set_deref_box(the_items, &components.schemas, referred);
165 set_defer_schema_contents(the_items.to_item_mut(), components, recursion - 1, referred);
166 }
167 for sch in &mut schema.one_of.iter_mut() {
168 set_deref(sch, &components.schemas, referred);
169 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
170 }
171 for sch in &mut schema.any_of.iter_mut() {
172 set_deref(sch, &components.schemas, referred);
173 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
174 }
175 for sch in &mut schema.all_of.iter_mut() {
176 set_deref(sch, &components.schemas, referred);
177 set_defer_schema_contents(sch.to_item_mut(), components, recursion - 1, referred);
178 }
179 }
180 }
181}
182
183fn set_deref_all_params(parameters: &mut [ReferenceOr<Parameter>], components: &Components) {
184 for parameter in parameters.iter_mut() {
185 set_deref(parameter, &components.parameters, &mut Vec::new());
186 }
187}
188
189fn set_deref<T>(
190 item: &mut ReferenceOr<T>,
191 component_type: &IndexMap<String, ReferenceOr<T>>,
192 referred: &mut Vec<String>,
193) where
194 T: Clone,
195{
196 match item {
197 ReferenceOr::Reference { reference } => {
198 let p = find_reference(reference, component_type, referred)
199 .expect("No Reference found!");
200 *item = ReferenceOr::Item(p);
201 }
202 ReferenceOr::Item(_) => {}
203 }
204}
205
206fn set_deref_box<T>(
207 item: &mut ReferenceOr<Box<T>>,
208 component_type: &IndexMap<String, ReferenceOr<T>>,
209 referred: &mut Vec<String>,
210) where
211 T: Clone,
212{
213 match item {
214 ReferenceOr::Reference { reference } => {
215 let p = find_reference(reference, component_type, referred)
216 .expect("No Reference found!");
217 *item = ReferenceOr::Item(Box::new(p));
218 }
219 ReferenceOr::Item(_) => {}
220 }
221}
222
223fn find_reference<T>(
224 reference: &str,
225 component_type: &IndexMap<String, ReferenceOr<T>>,
226 referred: &mut Vec<String>,
227) -> Result<T, DerefError>
228where
229 T: Clone,
230{
231 let reference_name: &str = reference.rsplit('/').next().unwrap();
232
233 let ref_item = component_type
234 .get(reference_name)
235 .ok_or(DerefError::ReferenceError {
236 name: reference_name.to_string(),
237 })?;
238
239 match ref_item {
240 ReferenceOr::Reference { reference } => {
241 if referred.iter().any(|v| v == reference_name) {
242 unimplemented!("Circular references are not supported")
243 } else {
244 referred.push(reference_name.to_string());
245 let p = find_reference(reference, component_type, referred)
246 .expect("No Reference found!");
247 Ok(p)
248 }
249 }
250 ReferenceOr::Item(item) => Ok(item.clone()),
251 }
252}
253
254fn operation_list<'a>(item: &'a mut PathItem) -> Vec<&'a mut Operation> {
255 let mut result = Vec::new();
256 let mut pusher = |operation: &'a mut Option<Operation>| {
257 if operation.is_some() {
258 result.push(operation.as_mut().unwrap());
259 }
260 };
261 pusher(&mut item.delete);
262 pusher(&mut item.get);
263 pusher(&mut item.head);
264 pusher(&mut item.options);
265 pusher(&mut item.patch);
266 pusher(&mut item.post);
267 pusher(&mut item.put);
268 pusher(&mut item.trace);
269 result
270}