1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::collections::HashMap;
use std::{env, io};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::io::Write;
use regex::Regex;
use crate::GeneratorError::InvalidGeneratorArguments;
pub struct ProcessorParams {
pub function_name: String,
pub config: HashMap<String, String>,
}
#[derive(Debug, Eq, PartialEq)]
pub enum GeneratorError {
InvalidGeneratorArguments {
args: Vec<String>,
description: String,
},
RequiredConfigNotFound {
function_name: String,
field_name: String,
description: Option<String>,
},
OtherError {
description: String,
},
}
impl GeneratorError {
pub fn new_from<E: Error>(err: E) -> GeneratorError {
GeneratorError::OtherError {
description: format!("{err}")
}
}
}
impl Display for GeneratorError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
InvalidGeneratorArguments { args, description } =>
write!(f, "{description} \nProvided arguments:{args:?}"),
GeneratorError::RequiredConfigNotFound { function_name, field_name, description } =>
write!(f, "Processor required config that was missing in template. Function: {}, missing field: {}. Description: {}",
function_name, field_name, description.clone().unwrap_or_else(|| "N/A".to_string())
),
GeneratorError::OtherError { description } =>
write!(f, "{description}"),
}
}
}
impl Error for GeneratorError {}
pub fn read_params() -> Result<ProcessorParams, GeneratorError> {
let args: Vec<String> = env::args().collect();
if args.is_empty() {
return Err(InvalidGeneratorArguments {
args,
description: "No processor generator arguments specified. Specify at least 1 argument (function_name).".to_string(),
});
}
if args.len() % 2 == 1 {
return Err(InvalidGeneratorArguments {
args,
description: "Processor arguments are invalid. Cannot construct the config map (wrong number of arguments).".to_string(),
});
}
let function_name = args[1].clone();
let config: HashMap<String, String> = args.into_iter()
.skip(2)
.collect::<Vec<String>>()
.chunks_exact(2)
.into_iter()
.map(|chunk| (chunk[0].clone(), chunk[1].clone()))
.collect();
Ok(ProcessorParams {
function_name,
config,
})
}
pub fn return_generated<F>(generate_function: F)
where F: FnOnce(ProcessorParams) -> Result<String, GeneratorError> {
let result = read_params()
.and_then(generate_function);
let mut output = String::new();
match result {
Ok(string) => {
output.push_str("OK\n");
output.push_str(&string);
},
Err(e) => {
output.push_str("ERR\n");
output.push_str(&format!("{e}"));
},
}
{
let mut lock = io::stdout().lock();
lock.write_all(output.as_bytes()).unwrap();
lock.flush().unwrap();
}
}
pub fn json_path_to_object_key(jsonpath: &str) -> String {
if !jsonpath.starts_with('$') {
return format!("&[Key(\"{}\".to_string())]", jsonpath.escape_for_json())
}
let result: Vec<String> = Regex::new(r"[.\[\]]")
.unwrap()
.split(jsonpath)
.skip(1)
.filter(|s| !s.is_empty())
.map(|s| match s.parse::<i64>() {
Ok(num) => format!("Index({num})"),
Err(_) => format!("Key(\"{}\".to_string())", s.escape_for_json()),
})
.collect();
format!("&[{}]", result.join(", "))
}
pub trait JsonFieldName {
fn escape_for_json(&self) -> String;
}
impl JsonFieldName for String {
fn escape_for_json(&self) -> String {
self.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
}
}
impl JsonFieldName for &str {
fn escape_for_json(&self) -> String {
self.to_string()
.escape_for_json()
}
}