1use quote::ToTokens;
2use syn::Attribute;
3
4pub fn update_openapi_macro_attributes(
5 macro_attibutes: &mut Vec<Attribute>,
6 uto_paths: &String,
7 uto_models: &String,
8 uto_responses: &String,
9) {
10 let mut is_ok = false;
11 for attr in macro_attibutes {
12 if !attr.path().is_ident("openapi") {
13 continue;
14 }
15 is_ok = true;
16 let mut src_uto_macro = attr.to_token_stream().to_string();
17
18 src_uto_macro = src_uto_macro.replace("#[openapi()]", "");
19 src_uto_macro = src_uto_macro.replace("#[openapi(", "");
20 src_uto_macro = src_uto_macro.replace(")]", "");
21 *attr = build_new_openapi_attributes(src_uto_macro, uto_paths, uto_models, uto_responses);
22 }
23 if !is_ok {
24 panic!("No utoipa::openapi Macro found !");
25 }
26}
27
28pub fn build_new_openapi_attributes(
30 src_uto_macro: String,
31 uto_paths: &String,
32 uto_models: &String,
33 uto_responses: &String,
34) -> Attribute {
35 let paths = extract_paths(src_uto_macro.clone());
36 let schemas = extract_schemas(src_uto_macro.clone());
37 let responses = extract_responses(src_uto_macro.clone());
38 let src_uto_macro = remove_paths(src_uto_macro);
39 let src_uto_macro = remove_schemas(src_uto_macro);
40 let src_uto_macro = remove_responses(src_uto_macro);
41 let src_uto_macro = remove_components(src_uto_macro);
42
43 let paths = format!("{}{}", uto_paths, paths);
44 let schemas = format!("{}{}", uto_models, schemas);
45 let responses = format!("{}{}", uto_responses, responses);
46 let src_uto_macro = format!(
47 "paths({}),components(schemas({}),responses({})),{}",
48 paths, schemas, responses, src_uto_macro
49 )
50 .replace(",,", ",");
51
52 let stream: proc_macro2::TokenStream = src_uto_macro.parse().unwrap();
53
54 syn::parse_quote! { #[openapi( #stream )] }
55}
56
57fn remove_paths(src_uto_macro: String) -> String {
58 if src_uto_macro.contains("paths(") {
59 let paths = src_uto_macro.split("paths(").collect::<Vec<&str>>()[1];
60 let paths = paths.split(')').collect::<Vec<&str>>()[0];
61 src_uto_macro
62 .replace(format!("paths({})", paths).as_str(), "")
63 .replace(",,", ",")
64 } else {
65 src_uto_macro
66 }
67}
68
69fn remove_schemas(src_uto_macro: String) -> String {
70 if src_uto_macro.contains("schemas(") {
71 let schemas = src_uto_macro.split("schemas(").collect::<Vec<&str>>()[1];
72 let schemas = schemas.split(')').collect::<Vec<&str>>()[0];
73 src_uto_macro
74 .replace(format!("schemas({})", schemas).as_str(), "")
75 .replace(",,", ",")
76 } else {
77 src_uto_macro
78 }
79}
80
81fn remove_components(src_uto_macro: String) -> String {
82 if src_uto_macro.contains("components(") {
83 let components = src_uto_macro.split("components(").collect::<Vec<&str>>()[1];
84 let components = components.split(')').collect::<Vec<&str>>()[0];
85 src_uto_macro
86 .replace(format!("components({})", components).as_str(), "")
87 .replace(",,", ",")
88 } else {
89 src_uto_macro
90 }
91}
92
93fn remove_responses(src_uto_macro: String) -> String {
94 if src_uto_macro.contains("responses(") {
95 let responses = src_uto_macro.split("responses(").collect::<Vec<&str>>()[1];
96 let responses = responses.split(')').collect::<Vec<&str>>()[0];
97 src_uto_macro
98 .replace(format!("responses({})", responses).as_str(), "")
99 .replace(",,", ",")
100 } else {
101 src_uto_macro
102 }
103}
104
105fn extract_paths(src_uto_macro: String) -> String {
106 if src_uto_macro.contains("paths(") {
107 let paths = src_uto_macro.split("paths(").collect::<Vec<&str>>()[1];
108 let paths = paths.split(')').collect::<Vec<&str>>()[0];
109 paths.to_string()
110 } else {
111 "".to_string()
112 }
113}
114
115fn extract_schemas(src_uto_macro: String) -> String {
116 if src_uto_macro.contains("schemas(") {
117 let schemas = src_uto_macro.split("schemas(").collect::<Vec<&str>>()[1];
118 let schemas = schemas.split(')').collect::<Vec<&str>>()[0];
119 schemas.to_string()
120 } else {
121 "".to_string()
122 }
123}
124
125fn extract_responses(src_uto_macro: String) -> String {
126 if src_uto_macro.contains("responses(") {
127 let responses = src_uto_macro.split("responses(").collect::<Vec<&str>>()[1];
128 let responses = responses.split(')').collect::<Vec<&str>>()[0];
129 responses.to_string()
130 } else {
131 "".to_string()
132 }
133}
134#[cfg(test)]
135mod test {
136 use quote::ToTokens;
137
138 #[test]
139 fn test_remove_paths() {
140 assert_eq!(
141 super::remove_paths("description(test),paths(p1),info(test)".to_string()),
142 "description(test),info(test)".to_string()
143 );
144 }
145
146 #[test]
147 fn test_extract_paths() {
148 assert_eq!(super::extract_paths("paths(p1)".to_string()), "p1".to_string());
149 }
150
151 #[test]
152 fn test_extract_paths_empty() {
153 assert_eq!(super::extract_paths("".to_string()), "".to_string());
154 }
155
156 #[test]
157 fn test_build_new_openapi_attributes() {
158 assert_eq!(
159 super::build_new_openapi_attributes(
160 "".to_string(),
161 &"./src".to_string(),
162 &"".to_string(),
163 &"".to_string(),
164 )
165 .to_token_stream()
166 .to_string()
167 .replace(' ', ""),
168 "#[openapi(paths(./src),components(schemas(),responses()),)]".to_string()
169 );
170 }
171
172 #[test]
173 fn test_build_new_openapi_attributes_path_replace() {
174 assert_eq!(
175 super::build_new_openapi_attributes(
176 "paths(p1)".to_string(),
177 &"./src,".to_string(),
178 &"".to_string(),
179 &"".to_string(),
180 )
181 .to_token_stream()
182 .to_string()
183 .replace(' ', ""),
184 "#[openapi(paths(./src,p1),components(schemas(),responses()),)]".to_string()
185 );
186 }
187
188 #[test]
189 fn test_build_new_openapi_attributes_components() {
190 assert_eq!(
191 super::build_new_openapi_attributes(
192 "paths(p1)".to_string(),
193 &"./src,".to_string(),
194 &"model".to_string(),
195 &"".to_string()
196 )
197 .to_token_stream()
198 .to_string()
199 .replace(' ', ""),
200 "#[openapi(paths(./src,p1),components(schemas(model),responses()),)]".to_string()
201 );
202 }
203
204 #[test]
205 fn test_build_new_openapi_attributes_components_schemas_replace() {
206 assert_eq!(
207 super::build_new_openapi_attributes(
208 "paths(p1), components(schemas(m1))".to_string(),
209 &"./src,".to_string(),
210 &"model,".to_string(),
211 &"".to_string(),
212 )
213 .to_token_stream()
214 .to_string()
215 .replace(' ', ""),
216 "#[openapi(paths(./src,p1),components(schemas(model,m1),responses()),)]".to_string()
217 );
218 }
219
220 #[test]
221 fn test_build_new_openapi_attributes_components_responses_replace() {
222 assert_eq!(
223 super::build_new_openapi_attributes(
224 "paths(p1), components(responses(r1))".to_string(),
225 &"./src,".to_string(),
226 &"".to_string(),
227 &"response,".to_string(),
228 )
229 .to_token_stream()
230 .to_string()
231 .replace(' ', ""),
232 "#[openapi(paths(./src,p1),components(schemas(),responses(response,r1)),)]".to_string()
233 );
234 }
235
236 #[test]
237 fn test_build_new_openapi_attributes_components_responses_schemas_replace() {
238 assert_eq!(
239 super::build_new_openapi_attributes(
240 "paths(p1), components(responses(r1), schemas(m1))".to_string(),
241 &"./src,".to_string(),
242 &"model,".to_string(),
243 &"response,".to_string(),
244 )
245 .to_token_stream()
246 .to_string()
247 .replace(' ', ""),
248 "#[openapi(paths(./src,p1),components(schemas(model,m1),responses(response,r1)),)]".to_string()
249 );
250 }
251
252 #[test]
253 fn test_build_new_openapi_attributes_components_responses_schemas() {
254 assert_eq!(
255 super::build_new_openapi_attributes(
256 "paths(p1), components(responses(r1), schemas(m1))".to_string(),
257 &"./src,".to_string(),
258 &"".to_string(),
259 &"response,".to_string(),
260 )
261 .to_token_stream()
262 .to_string()
263 .replace(' ', ""),
264 "#[openapi(paths(./src,p1),components(schemas(m1),responses(response,r1)),)]".to_string()
265 );
266 }
267
268 #[test]
269 fn test_build_new_openapi_attributes_components_schemas_reponses() {
270 assert_eq!(
271 super::build_new_openapi_attributes(
272 "paths(p1), components(schemas(m1), responses(r1))".to_string(),
273 &"./src,".to_string(),
274 &"model,".to_string(),
275 &"".to_string(),
276 )
277 .to_token_stream()
278 .to_string()
279 .replace(' ', ""),
280 "#[openapi(paths(./src,p1),components(schemas(model,m1),responses(r1)),)]".to_string()
281 );
282 }
283}