1use std::{collections::{HashMap, VecDeque}, error::Error, fs, path::{Path, PathBuf}, sync::Arc};
2use anyhow::{bail, Result};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct RawSchemaEnumItem {
7 pub name: String,
8 pub value: Option<i32>,
9}
10
11
12#[derive(Debug, Serialize, Deserialize)]
13#[serde(deny_unknown_fields)]
14pub struct GlobalOption {
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub generator: Option<GeneratorOption>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub usecase_suffix: Option<String>,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub usecase_request_suffix: Option<String>,
25
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub usecase_response_suffix: Option<String>,
29
30 pub skip_types: Option<Vec<String>>
32}
33
34
35#[derive(Debug, Serialize, Deserialize)]
36#[serde(deny_unknown_fields)]
37pub struct GeneratorOption {
38 pub rust: Option<RustGeneratorOption>,
39 pub golang: Option<GolangGeneratorOption>,
40 pub golang_gin: Option<GolangGinGeneratorOption>,
41 pub python: Option<PythonGeneratorOption>,
42 pub python_fastapi: Option<PythonFastApiGeneratorOption>,
43 pub python_redis: Option<PythonRedisGeneratorOption>,
44 pub rust_axum: Option<RustAxumGeneratorOption>,
45 pub openapi: Option<OpenapiGeneratorOption>,
46 pub typescript: Option<TypescriptGeneratorOption>,
47 pub typescript_nestjs: Option<TypescriptNestjsGeneratorOption>
48}
49
50#[derive(Debug, Serialize, Deserialize)]
51#[serde(deny_unknown_fields)]
52pub struct GolangGinGeneratorOption {
53 #[serde(skip)]
54 pub def_loc: Arc<DefLoc>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub file: Option<String>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub package: Option<String>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub domain_package: Option<String>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub domain_import: Option<String>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub extra_request_fields: Option<Vec<String>>
74}
75
76#[derive(Debug, Serialize, Deserialize)]
77#[serde(deny_unknown_fields)]
78pub struct PythonRedisGeneratorOption {
79 #[serde(skip)]
80 pub def_loc: Arc<DefLoc>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub file: Option<String>,
85
86 #[serde(rename = "async", skip_serializing_if = "Option::is_none")]
87 pub async_flag: Option<bool>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub usecase_from: Option<String>,
91
92}
93
94#[derive(Debug, Serialize, Deserialize)]
95#[serde(deny_unknown_fields)]
96pub struct GolangGeneratorOption {
97 #[serde(skip)]
98 pub def_loc: Arc<DefLoc>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub file: Option<String>,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub package: Option<String>,
107}
108
109#[derive(Debug, Serialize, Deserialize)]
110#[serde(deny_unknown_fields)]
111pub struct PythonFastApiGeneratorOption {
112 #[serde(skip)]
113 pub def_loc: Arc<DefLoc>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub file: Option<String>,
118
119 #[serde(rename = "async", skip_serializing_if = "Option::is_none")]
120 pub async_flag: Option<bool>,
121
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub get_ctx_from: Option<String>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub usecase_from: Option<String>,
128
129 pub extra_imports: Option<Vec<String>>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub extra_method_args: Option<Vec<String>>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub extra_request_fields: Option<Vec<String>>
136}
137
138
139
140
141
142#[derive(Debug, Serialize, Deserialize)]
143#[serde(deny_unknown_fields)]
144pub struct TypescriptNestjsGeneratorOption {
145 #[serde(skip)]
146 pub def_loc: Arc<DefLoc>,
147
148 pub file: Option<String>
150}
151
152#[derive(Debug, Serialize, Deserialize)]
153#[serde(deny_unknown_fields)]
154pub struct TypescriptGeneratorOption {
155 #[serde(skip)]
156 pub def_loc: Arc<DefLoc>,
157
158 pub file: Option<String>,
160
161}
162
163#[derive(Debug, Serialize, Deserialize)]
164#[serde(deny_unknown_fields)]
165pub struct PythonGeneratorOption {
166 #[serde(skip)]
167 pub def_loc: Arc<DefLoc>,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub file: Option<String>,
172
173 #[serde(rename = "async", skip_serializing_if = "Option::is_none")]
174 pub async_flag: Option<bool>,
175
176
177}
178
179#[derive(Debug, Serialize, Deserialize)]
180#[serde(deny_unknown_fields)]
181pub struct RustGeneratorOption {
182 #[serde(skip)]
183 pub def_loc: Arc<DefLoc>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub file: Option<String>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub no_default_derive: Option<bool>,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub default_derive: Option<Vec<String>>,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub uses: Option<Vec<String>>,
200
201
202
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub no_error_type: Option<bool>,
205
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub error_type: Option<String>,
208
209 #[serde(rename = "async", skip_serializing_if = "Option::is_none")]
210 pub async_flag: Option<bool>,
211
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub async_trait: Option<bool>,
214}
215
216#[derive(Debug, Serialize, Deserialize)]
217#[serde(deny_unknown_fields)]
218pub struct RustAxumGeneratorOption {
219 #[serde(skip)]
220 pub def_loc: Arc<DefLoc>,
221
222 pub file: Option<String>
224}
225
226
227#[derive(Debug, Serialize, Deserialize)]
228pub struct OpenapiGeneratorOption {
229 #[serde(skip)]
230 pub def_loc: Arc<DefLoc>,
231
232 pub file: Option<String>
234}
235
236
237#[derive(Debug)]
238pub struct DefLoc {
239 pub file: PathBuf
240}
241
242impl DefLoc {
243 pub fn new(file: PathBuf) -> Self {
244 Self {
245 file
246 }
247 }
248}
249
250impl Default for DefLoc {
251 fn default() -> Self {
252 Self {
253 file: PathBuf::new()
254 }
255 }
256}
257
258
259
260#[derive(Debug, Serialize, Deserialize, Clone)]
261pub struct RawSchema {
262 #[serde(skip)]
263 pub def_loc: Arc<DefLoc>,
264
265 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
266 pub ty: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
269 pub items: Option<Box<RawSchema>>,
270
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub properties: Option<HashMap<String, RawSchema>>,
273
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub required: Option<bool>,
276
277 #[serde(skip_serializing_if = "Option::is_none")]
278 pub namespace: Option<String>,
279
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub enum_items: Option<Vec<RawSchemaEnumItem>>,
282
283 #[serde(skip_serializing_if = "Option::is_none")]
284 pub option: Option<RawSchemaPropertyOption>,
285
286 #[serde(skip_serializing_if = "Option::is_none")]
287 pub extends: Option<HashMap<String, String>>,
288
289 #[serde(skip_serializing_if = "Option::is_none")]
290 pub flat_extends: Option<Vec<String>>,
291}
292
293impl RawSchema {
294 pub fn new(def_loc: Arc<DefLoc>, ty: String) -> Self {
295 Self {
296 def_loc,
297 ty: Some(ty),
298 items: None,
299 properties: None,
300 required: None,
301 namespace: None,
302 enum_items: None,
303 option: None,
304 extends: None,
305 flat_extends: None,
306 }
307 }
308
309 pub fn new_array_ty(def_loc: Arc<DefLoc>, items_ty: String) -> Self {
310 Self {
311 def_loc: def_loc.clone(),
312 ty: None,
313 items: Some(Box::new(RawSchema::new(def_loc, items_ty))),
314 properties: None,
315 required: None,
316 namespace: None,
317 enum_items: None,
318 option: None,
319 extends: None,
320 flat_extends: None,
321 }
322 }
323}
324
325#[derive(Debug, Serialize, Deserialize, Clone)]
326#[serde(deny_unknown_fields)]
327pub struct RawSchemaPropertyOption {
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub rest: Option<RawSchemaPropertyRestOption>,
330
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub python: Option<RawSchemaPropertyPythonOption>,
333
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub rust: Option<RawSchemaPropertyRustOption>,
336
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub openapi: Option<RawSchemaPropertyOpenApiOption>,
339
340 #[serde(skip_serializing_if = "Option::is_none")]
341 pub python_fastapi: Option<RawSchemaPropertyPythonFastApiOption>,
342
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub golang_gin: Option<RawSchemaPropertyGolangGinOption>,
345
346 #[serde(skip_serializing_if = "Option::is_none")]
347 pub description: Option<String>
348
349}
350
351#[derive(Debug, Serialize, Deserialize, Clone)]
352#[serde(deny_unknown_fields)]
353pub struct RawSchemaPropertyPythonOption {
354
355}
356
357#[derive(Debug, Serialize, Deserialize, Clone)]
358#[serde(deny_unknown_fields)]
359pub struct RawSchemaPropertyOpenApiOption {
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub exclude: Option<bool>
362}
363
364#[derive(Debug, Serialize, Deserialize, Clone)]
365#[serde(deny_unknown_fields)]
366pub struct RawSchemaPropertyGolangGinOption {
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub exclude: Option<bool>
369}
370
371#[derive(Debug, Serialize, Deserialize, Clone)]
372#[serde(deny_unknown_fields)]
373pub struct RawSchemaPropertyPythonFastApiOption {
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub exclude: Option<bool>
376}
377
378
379#[derive(Debug, Serialize, Deserialize, Clone)]
380#[serde(deny_unknown_fields)]
381pub struct RawSchemaPropertyRestOption {
382 #[serde(skip_serializing_if = "Option::is_none")]
383 pub query: Option<bool>
384}
385
386#[derive(Debug, Serialize, Deserialize, Clone)]
387#[serde(deny_unknown_fields)]
388pub struct RawSchemaPropertyRustOption {
389 #[serde(skip_serializing_if = "Option::is_none")]
390 pub attrs: Option<Vec<String>>
391}
392#[derive(Debug, Serialize, Deserialize)]
393pub struct RawUsecaseMethod {
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub req: Option<RawSchema>,
396 #[serde(skip_serializing_if = "Option::is_none")]
397 pub res: Option<RawSchema>,
398
399 #[serde(skip_serializing_if = "Option::is_none")]
400 pub option: Option<RawUsecaseMethodOption>
401}
402
403
404#[derive(Debug, Serialize, Deserialize)]
405pub struct RawUsecase {
406 #[serde(skip)]
407 pub def_loc: Arc<DefLoc>,
408
409 pub methods: HashMap<String, RawUsecaseMethod>,
410
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub option: Option<RawUsecaseOption>
413}
414
415#[derive(Debug, Serialize, Deserialize)]
416#[serde(deny_unknown_fields)]
417pub struct RawUsecaseOption {
418
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub rest: Option<RawUsecaseRestOption>
421}
422
423#[derive(Debug, Serialize, Deserialize)]
424#[serde(deny_unknown_fields)]
425pub struct RawUsecaseRestOption {
426 #[serde(skip_serializing_if = "Option::is_none")]
428 pub path: Option<String>
429}
430
431
432#[derive(Debug, Serialize, Deserialize)]
433#[serde(deny_unknown_fields)]
434pub struct RawUsecaseMethodOption {
435 #[serde(skip_serializing_if = "Option::is_none")]
436 pub rest: Option<RawUsecaseMethodRestOption>,
437
438 #[serde(skip_serializing_if = "Option::is_none")]
439 pub redis: Option<RawUsecaseMethodRedisOption>,
440
441 #[serde(skip_serializing_if = "Option::is_none")]
442 pub python_fastapi: Option<RawUsecaseMethodPythonFastApiOption>,
443
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub golang_gin: Option<RawUsecaseMethodGolangGinOption>,
446
447 #[serde(skip_serializing_if = "Option::is_none")]
448 pub description: Option<String>
449}
450
451#[derive(Debug, Serialize, Deserialize)]
452#[serde(deny_unknown_fields)]
453pub struct RawUsecaseMethodRedisOption {
454
455 #[serde(skip_serializing_if = "Option::is_none")]
456 pub queue_name: Option<String>,
457
458 #[serde(skip_serializing_if = "Option::is_none")]
459 pub ack_queue_name: Option<String>
460}
461
462#[derive(Debug, Serialize, Deserialize)]
463pub struct RawUsecaseMethodGolangGinOption {
464
465 #[serde(skip_serializing_if = "Option::is_none")]
466 pub extra_request_fields: Option<Vec<String>>
467}
468
469#[derive(Debug, Serialize, Deserialize)]
470pub struct RawUsecaseMethodPythonFastApiOption {
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub extra_method_args: Option<Vec<String>>,
473
474 #[serde(skip_serializing_if = "Option::is_none")]
475 pub extra_request_fields: Option<Vec<String>>
476}
477
478#[derive(Clone, Debug, Serialize, Deserialize)]
479pub struct RawUsecaseMethodRestOption {
480 pub method: String,
481 pub path: Option<String>
482}
483
484#[derive(Debug, Serialize, Deserialize)]
487#[serde(deny_unknown_fields)]
488pub struct RawSpec {
489
490
491 #[serde(rename = "types", skip_serializing_if = "Option::is_none")]
492 pub ty: Option<HashMap<String, RawSchema>>,
493
494 #[serde(skip_serializing_if = "Option::is_none")]
495 pub usecases: Option<HashMap<String, RawUsecase>>,
496
497
498 #[serde(skip_serializing_if = "Option::is_none")]
499 pub option: Option<GlobalOption>,
500
501
502 #[serde(skip_serializing_if = "Option::is_none")]
503 pub imports: Option<Vec<String>>,
504
505}
506
507
508impl RawSpec {
509
510
511 pub fn merge(&mut self, to_merge: RawSpec)-> Result<()> {
512 if let Some(to_merge_ty) = to_merge.ty {
513 let ty_map = self.ty.get_or_insert_with(HashMap::new);
514 for (key, value) in to_merge_ty {
515 if ty_map.contains_key(&key) {
516 bail!("Conflict for key '{}' in 'ty' hashmap", key);
517 }
518 ty_map.insert(key, value);
519 }
520 }
521
522 if let Some(to_merge_usecase) = to_merge.usecases {
524 let usecase_map = self.usecases.get_or_insert_with(HashMap::new);
525 for (key, value) in to_merge_usecase {
526 if usecase_map.contains_key(&key) {
527 bail!("Conflict for key '{}' in 'usecase' hashmap", key)
528 }
529 usecase_map.insert(key, value);
530 }
531 }
532
533 if let Some(to_merge_imports) = to_merge.imports {
537 if let Some(imports) = &mut self.imports {
538 for import in &to_merge_imports {
539 if imports.contains(import) {
540 continue;
541 }
542 }
543 imports.extend(to_merge_imports);
544 } else {
545 self.imports = Some(to_merge_imports);
546 }
547 }
548
549 Ok(())
550 }
551
552 pub fn new() -> Self {
553 Self {
554 ty: Default::default(),
555 usecases: Default::default(),
556 option: Default::default(),
557 imports: Default::default()
558 }
559 }
560}
561