crud_api_endpoint/
config.rs

1use crate::VecStringWrapper;
2use darling::FromMeta;
3use proc_macro_error::abort;
4use serde::{Deserialize, Serialize};
5/// Arguments configuration.
6/// We want to avoid argumnent clash. The proposed solution is to reconfigure the standard argmunents.
7use std::collections::HashMap;
8
9#[derive(Debug, Default, FromMeta, Clone, Serialize, Deserialize)]
10#[darling(default)]
11pub struct ApiInputConfig {
12  pub arg_name: Option<String>,
13  pub ty: Option<String>,
14  pub long: Option<String>,
15  pub short: Option<char>,
16  pub no_short: Option<bool>,
17  pub heading: Option<String>,
18  pub help: Option<String>,
19  pub long_help: Option<String>,
20  pub possible_values: Option<VecStringWrapper>,
21  /// Force the requirement of this field else use the Option to determine id this field is required or not.
22  pub required: Option<bool>,
23  /// By default `num_args` is set automatically. You can override the automatism with this arg.
24  pub num_args: Option<String>,
25}
26
27lazy_static! {
28  static ref CONFIGMAP: HashMap<String, ApiInputConfig> = {
29    let mut m = HashMap::new();
30    m.insert(
31      "output_file".into(),
32      ApiInputConfig {
33        arg_name: Some("output_file".into()),
34        ty: Some("String".into()),
35        long: Some("output".into()),
36        short:Some( 'o'),
37        help:Some( "Output file. (default: stdout)".into()),
38        long_help: Some( "Output file to save the result in. (default: stdout)".into()),
39        heading: Some("Options".into()),
40        required:Some(false),
41        ..Default::default()
42      },
43    );
44    m.insert(
45      "input_file".into(),
46      ApiInputConfig {
47        arg_name: Some("input_file".into()),
48        ty: Some("String".into()),
49        long: Some("input".into()),
50        short: Some('i'),
51        help: Some("Read the data from file ('-' for stdin)".into()),
52        long_help: Some("Read the data from a JSON file ('-' for stdin)".into()),
53        heading: Some("Options".into()),
54        possible_values: None,
55        required:Some(false),
56        ..Default::default()
57      },
58    );
59    m.insert(
60      "input_template".into(),
61      ApiInputConfig {
62        arg_name: Some("input_template".into()),
63        ty: Some("Option<bool>".into()),
64        num_args:None,
65        long: Some("template".into()),
66        short: Some('t'),
67        help: Some("Generate an input template".into()),
68        long_help: Some("Generate an input template to use with the --input option".into()),
69        heading: Some("Options".into()),
70        possible_values: None,
71        required:Some(false),
72        ..Default::default()
73      },
74    );
75    m.insert(
76      "output_format".into(),
77      ApiInputConfig {
78        arg_name: Some( "output_format".into()),
79        long: Some("format".into()),
80        short: Some('f'),
81        // help: "Display result as JSON".into(),
82           heading: Some("Formatting".into()),
83        // possible_values: vec![],
84        ..Default::default()
85      },
86    );
87      m
88  };
89}
90
91pub fn arg_config(k: &str, local_config: &[ApiInputConfig]) -> ApiInputConfig {
92  let global = CONFIGMAP.get(k);
93  let local = local_config
94    .iter()
95    .find(|&c| k == c.arg_name.as_ref().unwrap());
96
97  match (global, local) {
98    (None, None) => abort!(k, format!("Can't find '{k}' configuration")),
99    (None, Some(l)) => l.to_owned(),
100    (Some(g), None) => g.to_owned(),
101    (Some(g), Some(l)) => ApiInputConfig {
102      arg_name: l.arg_name.to_owned().or_else(|| g.arg_name.to_owned()),
103      ty: l.ty.to_owned().or_else(|| g.ty.to_owned()),
104      long: l.long.to_owned().or_else(|| g.long.to_owned()),
105      short: l.short.to_owned().or_else(|| g.short.to_owned()),
106      no_short: l.no_short.to_owned().or_else(|| g.no_short.to_owned()),
107      heading: l.heading.to_owned().or_else(|| g.heading.to_owned()),
108      help: l.help.to_owned().or_else(|| g.help.to_owned()),
109      long_help: l.long_help.to_owned().or_else(|| g.long_help.to_owned()),
110      possible_values: l
111        .possible_values
112        .to_owned()
113        .or_else(|| g.possible_values.to_owned()),
114      required: l.required.to_owned().or_else(|| g.required.to_owned()),
115      num_args: l.num_args.to_owned().or_else(|| g.num_args.to_owned()),
116    },
117  }
118}
119
120// #[allow(dead_code)]
121// pub(crate) fn arg_config_quote(k: &str) -> TokenStream {
122//   let ac = arg_config(k);
123//   field_quote(&ac.into(), None)
124// }
125
126// pub(crate) fn parse_arg_config(meta: &MetaList) {
127//   let parsed_arg = parse_arg_config_internal(meta);
128//   let k = parsed_arg.name.to_owned();
129//   let mut arg = arg_config(&k);
130//   if !parsed_arg.long.is_empty() {
131//     arg.long = parsed_arg.long;
132//   }
133//   if parsed_arg.short != char::default() {
134//     arg.short = parsed_arg.short;
135//   }
136//   if !parsed_arg.help.is_empty() {
137//     arg.help = parsed_arg.help;
138//   }
139//   if !parsed_arg.heading.is_empty() {
140//     arg.heading = parsed_arg.heading;
141//   }
142//   if !parsed_arg.possible_values.is_empty() {
143//     arg.possible_values = parsed_arg.possible_values;
144//   }
145//   CONFIGMAP // .lock().unwrap()
146//     .insert(k, arg);
147// }
148
149// #[cfg(test)]
150// mod tests {
151//   use super::arg_config_quote;
152
153//   #[test]
154//   fn test_arg_config_quote() {
155//     assert_eq!(arg_config_quote("output").to_string(), "Arg :: new (\"output\") . long (\"output\") . short ('o') . help (\"Output file. (default: stdout)\")");
156//   }
157
158//   #[test]
159//   #[should_panic]
160//   fn test_arg_config_quote_not_exist() {
161//     arg_config_quote("no_exist");
162//   }
163// }