1use num::Zero;
2
3use crate::public::{
4 parse_json_string::parse_json_string,
5 parse_stringified_json_string::parse_stringified_json_string,
6};
7
8pub(crate) fn json_context(trimmed_str: &str) -> JsonContext {
9 let json_context = match trimmed_str {
10 trimmed_str if trimmed_str.starts_with('{') && trimmed_str.ends_with('}') => {
11 JsonContext::Object
12 }
13 trimmed_str if trimmed_str.starts_with('[') && trimmed_str.ends_with(']') => {
14 JsonContext::Array
15 }
16 _ => JsonContext::Value,
17 };
18
19 json_context
20}
21
22pub(crate) fn ensure_array_wrapper(string: &str) -> String {
23 let array_string = if string.starts_with('[') && string.ends_with(']') {
24 string.to_string()
25 } else {
26 format!("[{string}]")
27 };
28 array_string
29}
30
31#[allow(clippy::needless_pass_by_value)]
32pub(crate) fn content_str(json_context: JsonContext, trimmed_str: &str) -> String {
33 let content_str = match json_context {
34 JsonContext::Array | JsonContext::Object => {
35 let mut content_str = trimmed_str[1..].to_string();
36 content_str.pop();
37
38 let trimmed_content_str = content_str
39 .trim_matches([' ', '\n', '\t', ',', ';', ':'])
40 .trim_start_matches("\\n")
41 .trim_end_matches("\\n")
42 .trim_start_matches("\\\\n")
43 .trim_end_matches("\\\\n")
44 .to_string();
45
46 trimmed_content_str
47 }
48 JsonContext::Value => trimmed_str.to_string(),
49 };
50
51 content_str
52}
53
54#[allow(clippy::needless_pass_by_value)]
55pub(crate) fn rewrap_string(parsed_json_string: &str, json_context: JsonContext) -> String {
56 let rewrapped_string = match json_context {
57 JsonContext::Array => {
58 let rewrapped_string = format!("[{parsed_json_string}]");
59
60 rewrapped_string
61 }
62 JsonContext::Object => {
63 let rewrapped_string = format!("{{{parsed_json_string}}}");
64
65 rewrapped_string
66 }
67 JsonContext::Value => parsed_json_string.to_string(),
68 };
69
70 rewrapped_string
71}
72
73#[derive(Clone, Debug, PartialEq, Eq)]
74pub(crate) enum JsonContext {
75 Array,
76 Object,
77 Value,
78}
79
80pub(crate) fn handle_object_w_wrapper(string: &str) -> String {
81 let mut content_string = string[1..].to_string();
82 content_string.pop();
83 let content_string = content_string
84 .trim_matches([' ', '\n', '\t', ','])
85 .trim_start_matches("\\\\n")
86 .trim_end_matches("\\\\n")
87 .trim_start_matches("\\n")
88 .trim_end_matches("\\n");
89
90 let object_context = JsonContext::Object;
91
92 let new_object_substance = parse_json_string(content_string, object_context);
93
94 let new_with_braces = format!("{{{new_object_substance}}}");
95
96 new_with_braces
97}
98
99pub(crate) fn handle_stringified_object_w_wrapper(string: &str) -> String {
100 let mut content_string = string[1..].to_string();
101 content_string.pop();
102 let content_string = content_string
103 .trim_matches([' ', '\n', '\t', ','])
104 .trim_start_matches("\\\\n")
105 .trim_end_matches("\\\\n")
106 .trim_start_matches("\\n")
107 .trim_end_matches("\\n");
108
109 let object_context = JsonContext::Object;
110
111 let new_object_substance = parse_stringified_json_string(content_string, object_context);
112
113 let new_with_braces = format!("{{{new_object_substance}}}");
114
115 new_with_braces
116}
117
118pub(crate) fn handle_stringified_array_content(string: &str) -> String {
119 let mut array_elements = split_array_elements(string)
120 .iter()
121 .map(|element| {
122 let value_context = JsonContext::Value;
123
124 let new_element = parse_stringified_json_string(element, value_context);
125 let formatted_element = format!("{new_element}, ");
126 formatted_element
127 })
128 .collect::<String>();
129 array_elements.pop();
130 array_elements.pop();
131
132 array_elements
133}
134
135pub(crate) fn handle_array_content(string: &str) -> String {
136 let mut array_elements = split_array_elements(string)
137 .iter()
138 .map(|element| {
139 let value_context = JsonContext::Value;
140
141 let new_element = parse_json_string(element, value_context);
142 let formatted_element = format!("{new_element}, ");
143 formatted_element
144 })
145 .collect::<String>();
146 array_elements.pop();
147 array_elements.pop();
148
149 array_elements
150}
151
152pub(crate) fn handle_stringified_array_w_wrapper(string: &str) -> String {
153 let mut content_str = string[1..].to_string();
154 content_str.pop();
155 let content_str = content_str.trim();
156
157 let mut array_str = split_array_elements(content_str)
158 .iter()
159 .map(|element| {
160 let value_context = JsonContext::Value;
161
162 let new_element = parse_stringified_json_string(element, value_context);
163 let formatted_element = format!("{new_element}, ");
164 formatted_element
165 })
166 .collect::<String>();
167 array_str.pop();
168 array_str.pop();
169
170 let add_the_brackets_back = format!("[{array_str}]");
171
172 add_the_brackets_back
173}
174
175pub(crate) fn handle_array_w_wrapper(string: &str) -> String {
176 let mut content_str = string[1..].to_string();
177 content_str.pop();
178 let content_str = content_str.trim();
179
180 let mut array_str = split_array_elements(content_str)
181 .iter()
182 .map(|element| {
183 let value_context = JsonContext::Value;
184
185 let new_element = parse_json_string(element, value_context);
186 let formatted_element = format!("{new_element}, ");
187 formatted_element
188 })
189 .collect::<String>();
190 array_str.pop();
191 array_str.pop();
192
193 let add_the_brackets_back = format!("[{array_str}]");
194
195 add_the_brackets_back
196}
197
198pub(crate) fn handle_stringified_object_content(string: &str) -> String {
199 let mut key_value_pairs = split_object_elements(string)
200 .iter()
201 .filter_map(|kv_pair| {
202 let (key, value) = kv_pair.split_once(':')?;
203
204 let trimmed_key = key.trim();
205
206 let new_key = if trimmed_key.starts_with('\"') && trimmed_key.ends_with('\"') {
207 trimmed_key.to_string()
208 } else {
209 format!("\"{trimmed_key}\"")
210 };
211
212 let trimmed_value = value
213 .trim_matches([' ', '\n', '\t', ','])
214 .trim_start_matches("\\\\n")
215 .trim_end_matches("\\\\n")
216 .trim_start_matches("\\n")
217 .trim_end_matches("\\n");
218
219 let value_context = JsonContext::Value;
220
221 let new_value = parse_stringified_json_string(trimmed_value, value_context);
222
223 let new_kv_pair = format!("{new_key}: {new_value}, ");
224
225 Some(new_kv_pair)
226 })
227 .collect::<String>();
228 key_value_pairs.pop();
229 key_value_pairs.pop();
230
231 key_value_pairs
232}
233
234pub(crate) fn handle_object_content(string: &str) -> String {
235 let mut key_value_pairs = split_object_elements(string)
236 .iter()
237 .filter_map(|kv_pair| {
238 let (key, value) = kv_pair.split_once(':')?;
239
240 let trimmed_key = key.trim();
241
242 let new_key = if trimmed_key.starts_with('\"') && trimmed_key.ends_with('\"') {
243 trimmed_key.to_string()
244 } else {
245 format!("\"{trimmed_key}\"")
246 };
247
248 let trimmed_value = value
249 .trim_matches([' ', '\n', '\t', ','])
250 .trim_start_matches("\\\\n")
251 .trim_end_matches("\\\\n")
252 .trim_start_matches("\\n")
253 .trim_end_matches("\\n");
254
255 let value_context = JsonContext::Value;
256
257 let new_value = parse_json_string(trimmed_value, value_context);
258
259 let new_kv_pair = format!("{new_key}: {new_value}, ");
260
261 Some(new_kv_pair)
262 })
263 .collect::<String>();
264 key_value_pairs.pop();
265 key_value_pairs.pop();
266
267 key_value_pairs
268}
269
270pub(crate) fn split_array_elements(string: &str) -> Vec<String> {
271 let mut all_elements = Vec::new();
272 let mut current_element = String::default();
273 let mut array_lefts = 0;
274 let mut object_lefts = 0;
275
276 for ch in string.chars() {
277 let is_separator = ch == ',' || ch == ';';
278
279 if is_separator && array_lefts.is_zero() && object_lefts.is_zero() {
280 let trimmed_current_element = current_element
281 .trim_matches([' ', '\n', '\t', ',', ';'])
282 .trim_start_matches("\\\\n")
283 .trim_end_matches("\\\\n")
284 .trim_start_matches("\\n")
285 .trim_end_matches("\\n")
286 .to_string();
287 all_elements.push(trimmed_current_element.clone());
288 current_element.clear();
289 }
290
291 if ch == '{' && array_lefts.is_zero() {
292 object_lefts += 1;
293 }
294
295 if ch == '[' && object_lefts.is_zero() {
296 array_lefts += 1;
297 }
298
299 if ch == ']' && !array_lefts.is_zero() {
300 array_lefts -= 1;
301 }
302
303 if ch == '}' && !object_lefts.is_zero() {
304 object_lefts -= 1;
305 }
306 current_element.push(ch);
307 }
308
309 let trimmed_current_element = current_element
310 .trim_matches([' ', '\n', '\t', ',', ';'])
311 .trim_start_matches("\\\\n")
312 .trim_end_matches("\\\\n")
313 .trim_start_matches("\\n")
314 .trim_end_matches("\\n")
315 .to_string();
316 all_elements.push(trimmed_current_element.clone());
317 current_element.clear();
318
319 all_elements
320}
321
322pub(crate) fn split_object_elements(object_str: &str) -> Vec<String> {
323 let mut all_elements = Vec::new();
324 let mut current_element = String::default();
325 let mut array_lefts = 0;
326 let mut object_lefts = 0;
327 let mut double_quote_lefts = 0;
328
329 for ch in object_str.chars() {
330 let is_separator = ch == ',' || ch == ';';
331 if is_separator
332 && array_lefts.is_zero()
333 && object_lefts.is_zero()
334 && double_quote_lefts.is_zero()
335 {
336 let trimmed_element = current_element
337 .trim_matches([' ', '\n', '\t', ','])
338 .trim_start_matches("\\\\n")
339 .trim_end_matches("\\\\n")
340 .trim_start_matches("\\n")
341 .trim_end_matches("\\n")
342 .to_string();
343 all_elements.push(trimmed_element);
344 current_element.clear();
345 }
346
347 if ch == '{' && array_lefts.is_zero() && double_quote_lefts.is_zero() {
348 object_lefts += 1;
349 }
350
351 if ch == '[' && object_lefts.is_zero() && double_quote_lefts.is_zero() {
352 array_lefts += 1;
353 }
354
355 if ch == '\"' && object_lefts.is_zero() && array_lefts.is_zero() {
356 if double_quote_lefts.is_zero() {
357 double_quote_lefts += 1;
358 } else {
359 double_quote_lefts -= 1;
360 };
361 }
362
363 if ch == ']' && !array_lefts.is_zero() && double_quote_lefts.is_zero() {
364 array_lefts -= 1;
365 }
366
367 if ch == '}' && !object_lefts.is_zero() && double_quote_lefts.is_zero() {
368 object_lefts -= 1;
369 }
370
371 current_element.push(ch);
372 }
373
374 let trimmed_element = current_element
375 .trim_matches([' ', '\n', '\t', ','])
376 .trim_start_matches("\\\\n")
377 .trim_end_matches("\\\\n")
378 .trim_start_matches("\\n")
379 .trim_end_matches("\\n")
380 .to_string();
381 all_elements.push(trimmed_element);
382 current_element.clear();
383
384 all_elements
385}
386
387pub(crate) fn format_stringified_value(value_str: &str) -> String {
388 if value_str.is_empty() {
389 return String::default();
390 }
391
392 let without_quotes = value_str
393 .trim_matches('\"')
394 .trim_start_matches("\\\\n")
395 .trim_end_matches("\\\\n")
396 .trim_start_matches("\\n")
397 .trim_end_matches("\\n");
398 let formatted_value = format!("\"{without_quotes}\"");
399
400 formatted_value
401}
402
403pub(crate) fn format_value(value_str: &str) -> String {
404 let formatted_value = match value_str.to_lowercase().as_str() {
405 value_str
406 if value_str.parse::<bool>().is_ok()
407 || value_str.parse::<f64>().is_ok()
408 || value_str.parse::<u64>().is_ok()
409 || value_str.parse::<i64>().is_ok()
410 || value_str.starts_with('[') && value_str.ends_with(']')
411 || value_str.starts_with('{') && value_str.ends_with('}')
412 || value_str.is_empty() =>
413 {
414 value_str.to_string()
415 }
416 "none" => "None".to_string(),
417 _ => {
418 let without_quotes = value_str
419 .trim_matches('\"')
420 .trim_start_matches("\\\\n")
421 .trim_end_matches("\\\\n")
422 .trim_start_matches("\\n")
423 .trim_end_matches("\\n");
424
425 let with_quotes = format!("\"{without_quotes}\"");
426 with_quotes
427 }
428 };
429
430 formatted_value
431}