rupring_macro/
lib.rs

1mod attribute;
2mod parse;
3mod rule;
4use std::str::FromStr;
5
6use attribute::AttributeValue;
7use proc_macro::TokenStream;
8use quote::ToTokens;
9use syn::Expr;
10
11const SHARP: &str = "#";
12
13#[proc_macro_attribute]
14#[allow(non_snake_case)]
15pub fn Module(attr: TokenStream, mut item: TokenStream) -> TokenStream {
16    let _item = item.clone();
17    let ast = syn::parse_macro_input!(_item as syn::ItemStruct);
18
19    let struct_name = parse::find_struct_name(&ast);
20
21    let attribute_map: std::collections::HashMap<String, attribute::AttributeValue> =
22        attribute::parse_attribute(attr.clone(), false);
23
24    let controllers = match attribute_map.get("controllers") {
25        Some(controllers) => match controllers {
26            attribute::AttributeValue::ListOfString(controllers) => controllers.to_owned(),
27            attribute::AttributeValue::String(controller) => vec![controller.to_owned()],
28        },
29        None => vec![],
30    };
31
32    let modules = match attribute_map.get("modules") {
33        Some(modules) => match modules {
34            attribute::AttributeValue::ListOfString(modules) => modules.to_owned(),
35            AttributeValue::String(module) => vec![module.to_owned()],
36        },
37        None => vec![],
38    };
39
40    let providers = match attribute_map.get("providers") {
41        Some(providers) => match providers {
42            attribute::AttributeValue::ListOfString(providers) => providers.to_owned(),
43            AttributeValue::String(provider) => vec![provider.to_owned()],
44        },
45        None => vec![],
46    };
47
48    let middlewares = match attribute_map.get("middlewares") {
49        Some(middlewares) => match middlewares {
50            AttributeValue::ListOfString(middlewares) => middlewares.to_owned(),
51            AttributeValue::String(middleware) => vec![middleware.to_owned()],
52        },
53        None => vec![],
54    };
55
56    let controllers = controllers
57        .iter()
58        .map(|controller| format!("Box::new({})", controller.to_owned()))
59        .collect::<Vec<String>>()
60        .join(", ");
61
62    let modules = modules
63        .iter()
64        .map(|module| format!("Box::new({})", module.to_owned()))
65        .collect::<Vec<String>>()
66        .join(", ");
67
68    let providers = providers
69        .iter()
70        .map(|provider| format!("Box::new({})", provider.to_owned()))
71        .collect::<Vec<String>>()
72        .join(", ");
73
74    let middlewares = middlewares
75        .iter()
76        .map(|middleware| format!("Box::new({})", middleware.to_owned()))
77        .collect::<Vec<String>>()
78        .join(", ");
79
80    let new_code = format!(
81        r#"impl rupring::IModule for {struct_name} {{
82    fn child_modules(&self) -> Vec<Box<dyn rupring::IModule>> {{
83        vec![{modules}]
84    }}
85
86    fn controllers(&self) -> Vec<Box<dyn rupring::IController>> {{
87        vec![{controllers}]
88    }}
89
90    fn providers(&self) -> Vec<Box<dyn rupring::IProvider>> {{
91        vec![{providers}]
92    }}
93
94    fn middlewares(&self) -> Vec<rupring::MiddlewareFunction> {{
95        vec![{middlewares}]
96    }}
97}}
98"#
99    );
100
101    item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
102
103    return item;
104}
105
106#[proc_macro_attribute]
107#[allow(non_snake_case)]
108pub fn Controller(attr: TokenStream, mut item: TokenStream) -> TokenStream {
109    let _item = item.clone();
110    let ast = syn::parse_macro_input!(_item as syn::ItemStruct);
111
112    let struct_name = parse::find_struct_name(&ast);
113
114    let attribute_map = attribute::parse_attribute(attr.clone(), false);
115
116    let prefix = match attribute_map.get("prefix") {
117        Some(prefix) => match prefix {
118            AttributeValue::String(prefix) => prefix.to_owned(),
119            _ => "".to_string(),
120        },
121        None => "".to_string(),
122    };
123
124    let routes = match attribute_map.get("routes") {
125        Some(routes) => match routes {
126            AttributeValue::ListOfString(routes) => routes.to_owned(),
127            AttributeValue::String(route) => vec![route.to_owned()],
128        },
129        None => vec![],
130    };
131
132    let routes = routes
133        .iter()
134        .map(|route| {
135            let mut scopes = route.split("::").map(|e| e.trim()).collect::<Vec<&str>>();
136
137            let route = scopes.pop().unwrap();
138
139            let route_name = rule::make_route_name(route);
140
141            let scopes = scopes.join("::");
142
143            if scopes.len() > 0 {
144                format!("Box::new({scopes}::{route_name}{{}})")
145            } else {
146                format!("Box::new({route_name}{{}})")
147            }
148        })
149        .collect::<Vec<String>>()
150        .join(", ");
151
152    let middlewares = match attribute_map.get("middlewares") {
153        Some(middlewares) => match middlewares {
154            AttributeValue::ListOfString(middlewares) => middlewares.to_owned(),
155            AttributeValue::String(middleware) => vec![middleware.to_owned()],
156        },
157        None => vec![],
158    };
159
160    let middlewares = middlewares
161        .iter()
162        .map(|middleware| format!("Box::new({})", middleware.to_owned()))
163        .collect::<Vec<String>>()
164        .join(", ");
165
166    let new_code = format!(
167        r#"impl rupring::IController for {struct_name} {{
168            fn prefix(&self) -> String {{
169                "{prefix}".to_string()
170            }}
171        
172            fn routes(&self) -> Vec<Box<dyn rupring::IRoute + Send + 'static>> {{
173                vec![{routes}]
174            }}
175
176            fn middlewares(&self) -> Vec<rupring::MiddlewareFunction> {{
177                vec![{middlewares}]
178            }}
179        }}"#
180    );
181
182    item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
183
184    return item;
185}
186
187#[proc_macro_attribute]
188#[allow(non_snake_case)]
189pub fn Service(attr: TokenStream, item: TokenStream) -> TokenStream {
190    return Injectable(attr, item);
191}
192
193#[proc_macro_attribute]
194#[allow(non_snake_case)]
195pub fn Repository(attr: TokenStream, item: TokenStream) -> TokenStream {
196    return Injectable(attr, item);
197}
198
199#[proc_macro_attribute]
200#[allow(non_snake_case)]
201pub fn Component(attr: TokenStream, item: TokenStream) -> TokenStream {
202    return Injectable(attr, item);
203}
204
205#[proc_macro_attribute]
206#[allow(non_snake_case)]
207pub fn Bean(attr: TokenStream, item: TokenStream) -> TokenStream {
208    return Injectable(attr, item);
209}
210
211#[proc_macro_attribute]
212#[allow(non_snake_case)]
213pub fn Injectable(attr: TokenStream, mut item: TokenStream) -> TokenStream {
214    let _item = item.clone();
215    let function_ast = syn::parse_macro_input!(_item as syn::ItemFn);
216
217    let _provider_type = parse::find_function_return_type(&function_ast);
218    let parameters_types = parse::find_function_parameter_types(&function_ast);
219    let function_name = parse::find_function_name(&function_ast);
220
221    let mut dependencies = vec![];
222    let mut arguments = vec![];
223    for parameter_type in parameters_types {
224        dependencies.push(format!("std::any::TypeId::of::<{parameter_type}>()",));
225
226        if parameter_type.contains("&") {
227            arguments.push(format!("di_context.get::<{parameter_type}>().unwrap()",));
228        } else {
229            arguments.push(format!(
230                "di_context.get::<{parameter_type}>().unwrap().to_owned()"
231            ));
232        }
233    }
234
235    let struct_name = if attr.is_empty() {
236        function_name.clone()
237    } else if attr.clone().into_iter().count() == 1 {
238        attr.into_iter().next().unwrap().to_string()
239    } else {
240        let attribute_map = attribute::parse_attribute(attr.clone(), false);
241
242        match attribute_map.get("name") {
243            Some(name) => match name {
244                AttributeValue::String(name) => name.to_owned(),
245                _ => function_name.clone(),
246            },
247            None => function_name.clone(),
248        }
249    };
250
251    let function_call = format!("{function_name}({})", arguments.join(", "));
252    let dependencies = dependencies.join(", ");
253
254    let new_code = format!(
255        r#"
256#[allow(non_camel_case_types)]
257pub struct {struct_name}{{}}
258impl rupring::IProvider for {struct_name} {{
259    fn dependencies(&self) -> Vec<std::any::TypeId> {{
260        vec![{dependencies}]
261    }}
262
263    fn provide(&self, di_context: &rupring::DIContext) -> Box<dyn std::any::Any> {{
264        Box::new({function_call})
265    }}
266}}"#
267    );
268
269    item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
270
271    return item;
272}
273
274fn convert_rust_type_to_js_type(rust_type: &str) -> String {
275    match rust_type {
276        "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64" | "u128" => {
277            "integer".to_string()
278        }
279        "Option<i8>" | "Option<i16>" | "Option<i32>" | "Option<i64>" | "Option<i128>"
280        | "Option<isize>" | "Option<u8>" | "Option<u16>" | "Option<u32>" | "Option<u64>"
281        | "Option<u128>" => "integer".to_string(),
282        "f32" | "f64" => "number".to_string(),
283        "Option<f32>" | "Option<f64>" => "number".to_string(),
284        "bool" => "boolean".to_string(),
285        "Option<bool>" => "boolean".to_string(),
286        _ => "string".to_string(),
287    }
288}
289
290#[allow(non_snake_case)]
291fn MapRoute(method: String, attr: TokenStream, item: TokenStream) -> TokenStream {
292    let _item = item.clone();
293    let function_ast = syn::parse_macro_input!(_item as syn::ItemFn);
294
295    let (item, additional_attributes) = attribute::extract_additional_attributes(item);
296    let summary = additional_attributes
297        .get("summary")
298        .map(|e| e.as_string())
299        .unwrap_or_default()
300        .trim_start_matches("\"")
301        .trim_end_matches("\"")
302        .to_owned();
303
304    let description = additional_attributes
305        .get("Description")
306        .map(|e| e.as_string())
307        .unwrap_or_default()
308        .trim_start_matches("\"")
309        .trim_end_matches("\"")
310        .to_owned();
311
312    let tags = additional_attributes
313        .get("tags")
314        .map(|e| match e {
315            AttributeValue::ListOfString(tags) => tags.to_owned(),
316            AttributeValue::String(tag) => vec![tag.to_owned()],
317        })
318        .map(|e| {
319            e.iter()
320                .map(|e| e.trim_start_matches("\"").trim_end_matches("\"").to_owned())
321                .collect::<Vec<_>>()
322        })
323        .unwrap_or_default();
324
325    let tags = format!(
326        "vec![{}]",
327        tags.iter()
328            .map(|e| format!("\"{}\".to_string()", e))
329            .collect::<Vec<_>>()
330            .join(", ")
331    );
332
333    let request_body = additional_attributes
334        .get("parameters")
335        .or(additional_attributes.get("params"))
336        .map(|e| e.as_string())
337        .unwrap_or_default()
338        .trim_start_matches("\"")
339        .trim_end_matches("\"")
340        .to_owned();
341
342    let response = additional_attributes
343        .get("response")
344        .map(|e| e.as_string())
345        .unwrap_or_default()
346        .trim_start_matches("\"")
347        .trim_end_matches("\"")
348        .to_owned();
349
350    let auth = additional_attributes.get("auth").map(|e| {
351        let mut auth_value = e
352            .as_string()
353            .trim_start_matches("\"")
354            .trim_end_matches("\"")
355            .to_owned();
356
357        if auth_value.len() == 0 {
358            auth_value = "BearerAuth".to_string();
359        }
360
361        auth_value
362    });
363
364    let (item, annotated_parameters) = parse::manipulate_route_function_parameters(item);
365
366    let mut swagger_code = "".to_string();
367    let mut variables_code = "".to_string();
368
369    // 함수 최상단에 코드를 주입합니다.
370
371    for anotated_parameter in annotated_parameters {
372        if anotated_parameter.attributes.contains_key("PathVariable") {
373            let parameter_name = anotated_parameter.name;
374            let parameter_type = anotated_parameter.type_;
375            let path_name = anotated_parameter.attributes["PathVariable"].as_string();
376            let path_name = path_name.trim_start_matches("\"").trim_end_matches("\"");
377            let required = !parameter_type.starts_with("Option<");
378            let type_ = convert_rust_type_to_js_type(parameter_type.as_str());
379
380            let description = anotated_parameter
381                .attributes
382                .get("Description")
383                .map(|e| {
384                    e.as_string()
385                        .trim_start_matches("\"")
386                        .trim_end_matches("\"")
387                        .to_string()
388                })
389                .unwrap_or_default();
390
391            let variable_expression = format!(
392                r###"
393                use rupring::ParamStringDeserializer;
394                let ___{parameter_name} = rupring::ParamString(request.path_parameters["{path_name}"].clone());
395                let {parameter_name}: {parameter_type} = match ___{parameter_name}.deserialize() {{
396                    Ok(v) => v,
397                    Err(_) => return rupring::Response::new().status(400).text("Invalid parameter: {parameter_name}"),
398                }};
399                "###
400            );
401
402            variables_code.push_str(&variable_expression);
403
404            swagger_code.push_str(
405                format!(
406                    r##"
407                swagger.parameters.push(
408                    rupring::swagger::SwaggerParameter {{
409                        name: "{parameter_name}".to_string(),
410                        in_: rupring::swagger::SwaggerParameterCategory::Path,
411                        description: "{description}".to_string(),
412                        required: {required},
413                        schema: Some(rupring::swagger::SwaggerTypeOrReference::Type(
414                            rupring::swagger::SwaggerType {{
415                                type_: "{type_}".to_string(),
416                            }} 
417                        )),
418                        type_: None,
419                    }}
420                );
421            "##
422                )
423                .as_str(),
424            );
425
426            continue;
427        }
428    }
429
430    let mut item = parse::prepend_code_to_function_body(
431        item,
432        TokenStream::from_str(variables_code.as_str()).unwrap(),
433    );
434
435    let function_name = parse::find_function_name(&function_ast);
436    let attribute_map = attribute::parse_attribute(attr.clone(), false);
437
438    let path = match attribute_map.get("path") {
439        Some(path) => match path {
440            AttributeValue::String(path) => path.to_owned(),
441            _ => "".to_string(),
442        },
443        None => "".to_string(),
444    };
445
446    let route_name = rule::make_route_name(function_name.as_str());
447    let handler_name = rule::make_handler_name(function_name.as_str());
448
449    let mut swagger_request_body_code = "".to_string();
450    if request_body.len() > 0 {
451        swagger_request_body_code = format!(
452            r#"
453            fn swagger_request_info(&self) -> Option<rupring::swagger::macros::SwaggerRequestBody> {{
454                rupring::swagger::macros::generate_swagger_request_info::<{request_body}>()
455            }}
456            "#
457        );
458    }
459
460    let mut swagger_response_body_code = "".to_string();
461    if response.len() > 0 {
462        swagger_response_body_code = format!(
463            r#"
464            fn swagger_response_info(&self) -> Option<rupring::swagger::macros::SwaggerRequestBody> {{
465                rupring::swagger::macros::generate_swagger_request_info::<{response}>()
466            }}
467            "#
468        );
469    }
470
471    let mut swagger_security_code = "".to_string();
472    if let Some(auth) = auth {
473        swagger_security_code = format!(
474            r#"
475            fn swagger_security_info(&self) -> Vec<rupring::swagger::json::SwaggerSecurity> {{
476                vec![
477                    std::collections::HashMap::from_iter(vec![("{auth}".to_string(), vec![])])
478                ]
479            }}
480            "#
481        );
482    }
483
484    swagger_code.push_str(format!("swagger.summary = \"{summary}\".to_string();").as_str());
485    swagger_code.push_str(format!("swagger.description = \"{description}\".to_string();").as_str());
486    swagger_code.push_str(format!("swagger.tags = {tags};", tags = tags).as_str());
487
488    let new_code = format!(
489        r#"
490#[allow(non_camel_case_types)]
491#[derive(Debug, Clone)]
492pub(crate) struct {route_name} {{}}
493
494impl rupring::IRoute for {route_name} {{
495    fn method(&self) -> rupring::Method {{
496        rupring::Method::{method}
497    }}
498
499    fn path(&self) -> String {{
500        "{path}".to_string()
501    }}
502
503    fn handler(&self) -> Box<dyn rupring::IHandler + Send + 'static> {{
504        Box::new({handler_name}{{}})
505    }}
506
507    fn swagger(&self) -> rupring::swagger::SwaggerOperation {{
508        let mut swagger = rupring::swagger::SwaggerOperation::default();
509        {swagger_code}
510        swagger
511    }}
512
513    {swagger_request_body_code}
514
515    {swagger_response_body_code}
516
517    {swagger_security_code}
518}}
519
520#[allow(non_camel_case_types)]
521#[derive(Debug, Clone)]
522pub(crate) struct {handler_name}{{}}
523
524impl rupring::IHandler for {handler_name} {{
525    fn handle(&self, request: rupring::Request, response: rupring::Response) -> rupring::Response {{
526        {function_name}(request, response)
527    }}
528}}
529"#,
530    );
531
532    item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
533
534    return item;
535}
536
537#[proc_macro_attribute]
538#[allow(non_snake_case)]
539pub fn Get(attr: TokenStream, item: TokenStream) -> TokenStream {
540    return MapRoute("GET".to_string(), attr, item);
541}
542
543#[proc_macro_attribute]
544#[allow(non_snake_case)]
545pub fn GetMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
546    return Get(attr, item);
547}
548
549#[proc_macro_attribute]
550#[allow(non_snake_case)]
551pub fn Post(attr: TokenStream, item: TokenStream) -> TokenStream {
552    return MapRoute("POST".to_string(), attr, item);
553}
554
555#[proc_macro_attribute]
556#[allow(non_snake_case)]
557pub fn PostMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
558    return Post(attr, item);
559}
560
561#[proc_macro_attribute]
562#[allow(non_snake_case)]
563pub fn Put(attr: TokenStream, item: TokenStream) -> TokenStream {
564    return MapRoute("PUT".to_string(), attr, item);
565}
566
567#[proc_macro_attribute]
568#[allow(non_snake_case)]
569pub fn PutMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
570    return Put(attr, item);
571}
572
573#[proc_macro_attribute]
574#[allow(non_snake_case)]
575pub fn Delete(attr: TokenStream, item: TokenStream) -> TokenStream {
576    return MapRoute("DELETE".to_string(), attr, item);
577}
578
579#[proc_macro_attribute]
580#[allow(non_snake_case)]
581pub fn DeleteMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
582    return Delete(attr, item);
583}
584
585#[proc_macro_attribute]
586#[allow(non_snake_case)]
587pub fn Patch(attr: TokenStream, item: TokenStream) -> TokenStream {
588    return MapRoute("PATCH".to_string(), attr, item);
589}
590
591#[proc_macro_attribute]
592#[allow(non_snake_case)]
593pub fn PatchMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
594    return Patch(attr, item);
595}
596
597/**
598## What is RupringDto?
599- This is a macro used to automatically generate Swagger documents.
600- It also provides functions such as Request Validation.
601
602## Attribute
6031. example: Example of the field value.
6042. description: Description of the field.
6053. required: Whether the field is required.
6064. name: Name of the field.
6075. path_param: Path parameter.
6086. param: Parameter.
6097. query: Query parameter.
6108. body: Body parameter.
6119. ignore: Ignore the field.
612 */
613#[proc_macro_derive(
614    RupringDto,
615    attributes(
616        example,
617        description,
618        desc,
619        required,
620        name,
621        path_param,
622        param,
623        query,
624        body,
625        ignore,
626    )
627)]
628pub fn derive_rupring_dto(item: TokenStream) -> TokenStream {
629    let ast = syn::parse_macro_input!(item as syn::ItemStruct);
630    let struct_name = parse::find_struct_name(&ast);
631
632    let mut code = "".to_string();
633
634    code +=
635        format!(r#"impl rupring::swagger::macros::ToSwaggerDefinitionNode for {struct_name} {{"#)
636            .as_str();
637
638    code += "fn get_definition_name() -> String {";
639    code += r#"let current_module_name = module_path!().to_string();"#;
640    code += format!(r#"let definition_name = format!("{{current_module_name}}::{struct_name}");"#)
641        .as_str();
642    code += "definition_name";
643    code += "}";
644
645    code += "fn to_swagger_definition(context: &mut rupring::swagger::macros::SwaggerDefinitionContext) -> rupring::swagger::macros::SwaggerDefinitionNode {";
646    code += format!(r#"let mut swagger_definition = rupring::swagger::json::SwaggerDefinition {{"#)
647        .as_str();
648    code += format!(r#"type_: "object".to_string(),"#).as_str();
649    code += format!(r#"properties: std::collections::HashMap::new(),"#).as_str();
650    code += format!(r#"required: vec![],"#).as_str();
651    code += format!(r#"path_parameters: vec![],"#).as_str();
652    code += format!(r#"query_parameters: vec![],"#).as_str();
653    code += "};";
654
655    let mut define_struct_for_json = "".to_string();
656    define_struct_for_json += format!("#[allow(non_camel_case_types)]").as_str();
657    define_struct_for_json +=
658        format!(r#"#[derive(serde::Serialize, serde::Deserialize)]"#).as_str();
659    define_struct_for_json += format!(r#"pub struct {struct_name}__JSON {{"#).as_str();
660
661    let mut json_field_names = vec![];
662    let mut path_field_names = vec![];
663    let mut query_field_names = vec![];
664
665    for field in ast.fields.iter() {
666        let mut description = "".to_string();
667        let mut example = r#""""#.to_string();
668
669        let field_name = field.ident.as_ref().unwrap().to_string();
670        let mut field_type = field.ty.to_token_stream().to_string().replace(" ", "");
671
672        let struct_field_name = field_name.clone();
673        let mut param_name = field_name.clone();
674
675        let attributes = field.attrs.clone();
676
677        let mut is_required = true;
678        let mut is_ignore = false;
679
680        let mut is_path_parameter = false;
681        let mut is_query_parameter = false;
682
683        if field_type.starts_with("Option<") {
684            is_required = false;
685        }
686
687        for attribute in attributes {
688            let metadata = attribute.meta;
689
690            let path = metadata.path().to_token_stream().to_string();
691
692            let meta_value = metadata.require_name_value().ok().map(|e| e.value.clone());
693
694            match path.to_lowercase().as_str() {
695                "example" => {
696                    if let Some(Expr::Lit(lit)) = &meta_value {
697                        example = format!("{:?}", lit.to_token_stream().to_string());
698                    }
699                }
700                "required" => {
701                    if let Some(Expr::Lit(lit)) = &meta_value {
702                        is_required = lit.to_token_stream().to_string().parse().unwrap();
703                    } else {
704                        is_required = true;
705                    }
706                }
707                "description" | "desc" => {
708                    if let Some(Expr::Lit(lit)) = &meta_value {
709                        let mut text = lit.to_token_stream().to_string();
710
711                        if text.starts_with("\"") {
712                            text = text
713                                .trim_start_matches("\"")
714                                .trim_end_matches("\"")
715                                .to_string();
716                        }
717
718                        description = text;
719                    }
720                }
721                "name" => {
722                    if let Some(Expr::Lit(lit)) = &meta_value {
723                        let mut text = lit.to_token_stream().to_string();
724
725                        if text.starts_with("\"") {
726                            text = text
727                                .trim_start_matches("\"")
728                                .trim_end_matches("\"")
729                                .to_string();
730                        }
731
732                        param_name = text;
733                    }
734                }
735                "path_param" | "param" => {
736                    if let Some(Expr::Lit(lit)) = &meta_value {
737                        let mut text = lit.to_token_stream().to_string();
738
739                        if text.starts_with("\"") {
740                            text = text
741                                .trim_start_matches("\"")
742                                .trim_end_matches("\"")
743                                .to_string();
744                        }
745
746                        param_name = text;
747                    }
748
749                    is_path_parameter = true;
750                }
751                "query" => {
752                    is_query_parameter = true;
753
754                    if let Some(Expr::Lit(lit)) = &meta_value {
755                        let mut text = lit.to_token_stream().to_string();
756
757                        if text.starts_with("\"") {
758                            text = text
759                                .trim_start_matches("\"")
760                                .trim_end_matches("\"")
761                                .to_string();
762                        }
763
764                        param_name = text;
765                    }
766                }
767                "ignore" => {
768                    is_ignore = true;
769                }
770                _ => {}
771            }
772        }
773
774        if is_ignore {
775            continue;
776        }
777
778        if is_required {
779            code += format!(r#"swagger_definition.required.push("{field_name}".to_string());"#)
780                .as_str();
781        }
782
783        // T<A> 형태를 T::<A> 형태로 변환
784        if field_type.contains("<") {
785            field_type = field_type.replace("<", "::<")
786        }
787
788        if is_path_parameter {
789            path_field_names.push((
790                struct_field_name.clone(),
791                param_name.clone(),
792                field_type.clone(),
793            ));
794
795            code += format!(
796                r#"swagger_definition.path_parameters.push(rupring::swagger::json::SwaggerParameter {{
797                name: "{field_name}".to_string(),
798                in_: rupring::swagger::json::SwaggerParameterCategory::Path,
799                description: "{description}".to_string(),
800                required: {is_required},
801                schema: Some(rupring::swagger::json::SwaggerTypeOrReference::Type(
802                    rupring::swagger::json::SwaggerType {{
803                        type_: "{field_type}".to_string(),
804                    }}
805                )),
806                type_: None,
807            }});"#
808            ).as_str();
809
810            continue;
811        }
812
813        if is_query_parameter {
814            query_field_names.push((
815                struct_field_name.clone(),
816                param_name.clone(),
817                field_type.clone(),
818            ));
819
820            code += format!(
821                r#"swagger_definition.query_parameters.push(rupring::swagger::json::SwaggerParameter {{
822                name: "{field_name}".to_string(),
823                in_: rupring::swagger::json::SwaggerParameterCategory::Query,
824                description: "{description}".to_string(),
825                required: {is_required},
826                schema: Some(rupring::swagger::json::SwaggerTypeOrReference::Type(
827                    rupring::swagger::json::SwaggerType {{
828                        type_: "{field_type}".to_string(),
829                    }}
830                )),
831                type_: None,
832            }});"#
833            ).as_str();
834
835            continue;
836        }
837
838        json_field_names.push((
839            struct_field_name.clone(),
840            param_name.clone(),
841            field_type.clone(),
842        ));
843
844        define_struct_for_json += format!(
845            r#"
846            pub {struct_field_name}: {field_type}, 
847        "#
848        )
849        .as_str();
850
851        // Body 파라미터 생성 구현
852        code += format!(r#"let property_of_type = {field_type}::to_swagger_definition(context);"#)
853            .as_str();
854
855        code += format!(
856            r#"let property_value = match property_of_type {{
857            rupring::swagger::macros::SwaggerDefinitionNode::Single(leaf) => {{
858                rupring::swagger::json::SwaggerProperty::Single(rupring::swagger::json::SwaggerSingleProperty {{
859                    type_: leaf.type_,
860                    description: "{description}".to_string(),
861                    example: Some({example}.into()),
862                }})
863            }},
864            rupring::swagger::macros::SwaggerDefinitionNode::Array(array) => {{
865                rupring::swagger::json::SwaggerProperty::Array(rupring::swagger::json::SwaggerArrayProperty {{
866                    type_: array.type_,
867                    items: array.items,
868                    description: "{description}".to_string(),
869                }})
870            }},
871            rupring::swagger::macros::SwaggerDefinitionNode::Object(object) => {{
872                let definition_name = {field_type}::get_definition_name();
873
874                context.definitions.insert(definition_name.clone(), object);
875
876                rupring::swagger::json::SwaggerProperty::Reference(rupring::swagger::json::SwaggerReferenceProperty {{
877                    reference: "{SHARP}/definitions/".to_string() + definition_name.as_str(),
878                    description: "{description}".to_string(),
879                }})
880            }},
881        }};"#
882        )
883        .as_str();
884
885        code += format!(
886            r#"swagger_definition.properties.insert("{field_name}".to_string(), property_value);"#
887        )
888        .as_str();
889    }
890
891    define_struct_for_json += format!(r#"}}"#).as_str();
892
893    code += "rupring::swagger::macros::SwaggerDefinitionNode::Object(swagger_definition)";
894
895    code += "}";
896
897    code += "}";
898
899    code += define_struct_for_json.as_str();
900
901    let mut request_bind_code = "".to_string();
902    request_bind_code +=
903        format!(r#"impl rupring::request::BindFromRequest for {struct_name} {{"#).as_str();
904
905    request_bind_code +=
906        "fn bind(request: rupring::request::Request) -> rupring::anyhow::Result<Self> {";
907    request_bind_code += "use rupring::request::ParamStringDeserializer;";
908    request_bind_code += "use rupring::request::QueryStringDeserializer;";
909
910    request_bind_code += format!("let mut json_bound = rupring::serde_json::from_str::<{struct_name}__JSON>(request.body.as_str())?;").as_str();
911
912    request_bind_code += format!("let bound = {struct_name} {{").as_str();
913
914    for (struct_field_name, _, _) in json_field_names {
915        request_bind_code +=
916            format!("{struct_field_name}: json_bound.{struct_field_name},").as_str();
917    }
918
919    for (struct_field_name, param_name, field_type) in path_field_names {
920        request_bind_code += format!(
921            r#"{struct_field_name}: {{
922                let param = rupring::request::ParamString(
923                    request.path_parameters["{param_name}"].clone()
924                );
925
926                let deserialized: {field_type} = match param.deserialize() {{
927                    Ok(v) => v,
928                    Err(_) => return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}")),
929                }};
930
931                deserialized
932            }}
933            "#
934        )
935        .as_str();
936    }
937
938    for (struct_field_name, param_name, field_type) in query_field_names {
939        let mut code_if_field_type_is_none =
940            format!(r#"return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}"));"#);
941
942        if field_type.starts_with("Option<") || field_type.starts_with("Option::<") {
943            code_if_field_type_is_none = r#"
944                rupring::request::QueryString(vec![])
945            "#
946            .to_string();
947        }
948
949        request_bind_code += format!(
950            r#"{struct_field_name}: {{
951                let query = if let Some(query) = request.query_parameters.get("{param_name}") {{
952                    rupring::request::QueryString(query.to_owned())
953                }} else {{
954                    {code_if_field_type_is_none}
955                }};
956
957                let deserialized: {field_type} = match query.deserialize_query_string() {{
958                    Ok(v) => v,
959                    Err(_) => return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}")),
960                }};
961
962                deserialized
963            }},
964            "#
965        )
966        .as_str();
967    }
968
969    request_bind_code += format!("}};").as_str();
970
971    request_bind_code += "Ok(bound)";
972    request_bind_code += "}";
973
974    request_bind_code += format!(r#"}}"#).as_str();
975
976    code += request_bind_code.as_str();
977
978    return TokenStream::from_str(code.as_str()).unwrap();
979}