fjson_core/
lib.rs

1use std::collections::HashMap;
2
3/// Parses a JSON string and automatically corrects
4/// common issues (e.g., missing brackets, invalid numbers, incomplete literals).
5///
6/// Also deserializes everything by default (root and nested).
7///
8/// Returns a formatted, valid JSON string.
9pub fn fix(input: impl Into<String>) -> String {
10    let json = Parser::new(input).parse_and_fix();
11    json.deserialize_all().stringify(0)
12}
13
14struct Parser {
15    chars: Vec<char>,
16    i: usize,
17}
18
19impl Parser {
20    pub fn new(input: impl Into<String>) -> Self {
21        Self {
22            chars: input.into().trim().chars().collect(),
23            i: 0,
24        }
25    }
26
27    fn peek(&mut self) -> Option<char> {
28        self.chars.get(self.i).copied()
29    }
30
31    fn next(&mut self) -> Option<char> {
32        let c = self.peek();
33        if c.is_some() {
34            self.i += 1;
35        }
36        c
37    }
38
39    fn skip_whitespace(&mut self) {
40        while let Some(c) = self.peek()
41            && c.is_whitespace()
42        {
43            self.next();
44        }
45    }
46
47    pub fn parse_and_fix(&mut self) -> Json {
48        self.parse_value()
49    }
50
51    fn parse_value(&mut self) -> Json {
52        self.skip_whitespace();
53
54        if let Some(c) = self.peek() {
55            match c {
56                'n' | 'N' | 't' | 'T' | 'f' | 'F' => self.parse_static(),
57
58                val if val.is_ascii_digit() || val == '-' || val == '.' => self.parse_number(),
59
60                '"' => self.parse_string(),
61
62                '[' => self.parse_array(),
63
64                '{' => self.parse_object(),
65
66                _ => {
67                    self.next();
68                    Json::Null
69                }
70            }
71        } else {
72            Json::Null
73        }
74    }
75
76    fn parse_static(&mut self) -> Json {
77        match self.next().unwrap().to_ascii_lowercase() {
78            'n' => Json::Null,
79            't' => Json::True,
80            _ => Json::False,
81        }
82    }
83
84    fn parse_number(&mut self) -> Json {
85        let mut lex = String::new();
86
87        if let Some('-') = self.peek() {
88            lex.push('-');
89            self.next();
90
91            while let Some('-') = self.peek() {
92                self.next();
93            }
94        }
95
96        if let Some('.') = self.peek() {
97            lex.push('0');
98        }
99
100        // trailing 0
101        if let Some('0') = self.peek() {
102            lex.push('0');
103            self.next();
104
105            while let Some(c) = self.peek() {
106                if c == '0' {
107                    self.next();
108                } else {
109                    if c.is_ascii_digit() {
110                        lex.pop();
111                    }
112                    break;
113                }
114            }
115        }
116
117        // integer
118        while let Some(c) = self.peek()
119            && c.is_ascii_digit()
120        {
121            lex.push(c);
122            self.next();
123        }
124
125        // float
126        if let Some('.') = self.peek() {
127            lex.push('.');
128            self.next();
129
130            let mut count = 0;
131            while let Some(c) = self.peek()
132                && c.is_ascii_digit()
133            {
134                lex.push(c);
135                self.next();
136                count += 1;
137            }
138
139            if count == 0 {
140                lex.push('0');
141            }
142        }
143
144        // expoent
145        if let Some(c) = self.peek()
146            && (c == 'e' || c == 'E')
147        {
148            lex.push(c);
149            self.next();
150
151            if let Some(sign) = self.peek()
152                && (sign == '-' || sign == '+')
153            {
154                lex.push(sign);
155                self.next();
156            }
157
158            let mut count = 0;
159            while let Some(c) = self.peek()
160                && c.is_ascii_digit()
161            {
162                lex.push(c);
163                self.next();
164                count += 1;
165            }
166
167            if count == 0 {
168                if lex.ends_with('-') || lex.ends_with('+') {
169                    lex.pop();
170                }
171                lex.pop();
172            }
173        }
174
175        if lex == "-" {
176            lex.push('0');
177        }
178
179        Json::Number(lex)
180    }
181
182    fn parse_string(&mut self) -> Json {
183        let mut lex = String::new();
184
185        self.next();
186        while let Some(c) = self.next() {
187            match c {
188                '"' => {
189                    break;
190                }
191
192                '\\' => {
193                    if let Some(esc) = self.next() {
194                        match esc {
195                            '"' => lex.push('"'),
196                            '\\' => lex.push('\\'),
197                            '/' => lex.push('/'),
198                            'b' => lex.push('\u{0008}'),
199                            'f' => lex.push('\u{000C}'),
200                            'n' => lex.push('\n'),
201                            'r' => lex.push('\r'),
202                            't' => lex.push('\t'),
203
204                            'u' => {
205                                if let Some(c) = self.parse_unicode_escape() {
206                                    lex.push(c);
207                                }
208                            }
209
210                            ch => {
211                                lex.push(ch);
212                            }
213                        }
214                    }
215                }
216
217                _ => {
218                    lex.push(c);
219                }
220            }
221        }
222
223        Json::String(lex)
224    }
225
226    fn parse_unicode_escape(&mut self) -> Option<char> {
227        let mut hex = String::new();
228        for _ in 0..4 {
229            if let Some(c) = self.next() {
230                hex.push(c);
231            } else {
232                return None;
233            }
234        }
235
236        let code = u32::from_str_radix(&hex, 16).ok()?;
237
238        if let Some(ch) = char::from_u32(code) {
239            Some(ch)
240        } else if (0xD800..=0xDBFF).contains(&code) {
241            if let (Some('\\'), Some('u')) = (self.next(), self.next()) {
242                let mut low_hex = String::new();
243                for _ in 0..4 {
244                    if let Some(c) = self.next() {
245                        low_hex.push(c);
246                    } else {
247                        return None;
248                    }
249                }
250
251                let low_code = u32::from_str_radix(&low_hex, 16).ok()?;
252
253                if (0xDC00..=0xDFFF).contains(&low_code) {
254                    let full_code = 0x10000 + ((code - 0xD800) << 10) + (low_code - 0xDC00);
255
256                    char::from_u32(full_code)
257                } else {
258                    None
259                }
260            } else {
261                None
262            }
263        } else {
264            None
265        }
266    }
267
268    fn parse_array(&mut self) -> Json {
269        let mut arr = Vec::new();
270
271        self.next();
272
273        loop {
274            self.skip_whitespace();
275
276            match self.peek() {
277                Some(']') => {
278                    self.next();
279                    break;
280                }
281
282                Some(',') => {
283                    self.next();
284                    continue;
285                }
286
287                Some(_) => {
288                    arr.push(self.parse_value());
289
290                    self.skip_whitespace();
291
292                    while let Some(c) = self.peek() {
293                        match c {
294                            ']' | ',' => {
295                                break;
296                            }
297
298                            _ => {
299                                self.next();
300                            }
301                        }
302                    }
303                }
304
305                None => {
306                    break;
307                }
308            }
309        }
310
311        Json::Array(arr)
312    }
313
314    fn parse_object(&mut self) -> Json {
315        let mut obj = HashMap::new();
316        let mut order = Vec::new();
317
318        self.next();
319
320        loop {
321            self.skip_whitespace();
322
323            match self.peek() {
324                Some('}') => {
325                    self.next();
326                    break;
327                }
328
329                Some('"') => {
330                    let key = match self.parse_string() {
331                        Json::String(s) => s,
332                        _ => unreachable!(),
333                    };
334
335                    self.skip_whitespace();
336
337                    if self.peek() == Some(':') {
338                        self.next();
339                    }
340
341                    if obj.contains_key(&key)
342                        && let Some(pos) = order.iter().position(|k| k == &key)
343                    {
344                        order.remove(pos);
345                    }
346
347                    obj.insert(key.clone(), self.parse_value());
348                    order.push(key);
349                }
350
351                None => {
352                    break;
353                }
354
355                _ => {
356                    self.next();
357                }
358            }
359        }
360
361        Json::Object((obj, order))
362    }
363}
364
365enum Json {
366    Null,
367    True,
368    False,
369    Number(String),
370    String(String),
371    Array(Vec<Json>),
372    Object((HashMap<String, Json>, Vec<String>)),
373}
374
375impl Json {
376    pub fn deserialize_all(self) -> Json {
377        match self {
378            Self::String(val) => {
379                let trimmed = val.trim();
380
381                if trimmed.starts_with('{') || trimmed.starts_with('[') {
382                    Parser::new(trimmed).parse_and_fix().deserialize_all()
383                } else {
384                    Json::String(val)
385                }
386            }
387
388            Json::Array(arr) => Json::Array(arr.into_iter().map(|v| v.deserialize_all()).collect()),
389
390            Json::Object((obj, order)) => Json::Object((
391                obj.into_iter()
392                    .map(|(k, v)| (k, v.deserialize_all()))
393                    .collect(),
394                order,
395            )),
396
397            other => other,
398        }
399    }
400
401    pub fn stringify(&self, tabs: usize) -> String {
402        const TAB: &str = "   ";
403
404        match self {
405            Self::Null => "null".to_string(),
406            Self::True => "true".to_string(),
407            Self::False => "false".to_string(),
408
409            Self::Number(val) => val.clone(),
410            Self::String(val) => format!("\"{}\"", val),
411
412            Self::Array(arr) => {
413                if arr.is_empty() {
414                    return "[]".to_string();
415                }
416
417                let mut result = String::from("[\n");
418                let tab_str = TAB.repeat(tabs + 1);
419
420                for val in arr {
421                    result.push_str(&format!("{}{},\n", tab_str, val.stringify(tabs + 1)));
422                }
423
424                result.truncate(result.len() - 2);
425
426                result.push('\n');
427                result.push_str(&TAB.repeat(tabs));
428                result.push(']');
429                result
430            }
431
432            Self::Object((obj, order)) => {
433                if obj.is_empty() {
434                    return "{}".to_string();
435                }
436
437                let mut result = String::from("{\n");
438                let tab_str = TAB.repeat(tabs + 1);
439
440                for key in order {
441                    if let Some(val) = obj.get(key) {
442                        result.push_str(&format!(
443                            "{}\"{}\": {},\n",
444                            tab_str,
445                            key,
446                            val.stringify(tabs + 1)
447                        ));
448                    }
449                }
450
451                result.truncate(result.len() - 2);
452
453                result.push('\n');
454                result.push_str(&TAB.repeat(tabs));
455                result.push('}');
456                result
457            }
458        }
459    }
460
461    fn _stringify_without_formatting(&self) -> String {
462        match self {
463            Self::Null => "null".to_string(),
464            Self::True => "true".to_string(),
465            Self::False => "false".to_string(),
466
467            Self::Number(val) => val.clone(),
468            Self::String(val) => format!("\"{}\"", val),
469
470            Self::Array(arr) => {
471                let mut result = String::from('[');
472
473                for val in arr {
474                    result.push_str(&format!("{},", val._stringify_without_formatting()));
475                }
476
477                if result.ends_with(',') {
478                    result.pop();
479                }
480
481                result.push(']');
482                result
483            }
484
485            Self::Object((obj, order)) => {
486                let mut result = String::from('{');
487
488                for key in order {
489                    if let Some(val) = obj.get(key) {
490                        result.push_str(&format!(
491                            "\"{}\":{},",
492                            key,
493                            val._stringify_without_formatting()
494                        ));
495                    }
496                }
497
498                if result.ends_with(',') {
499                    result.pop();
500                }
501
502                result.push('}');
503                result
504            }
505        }
506    }
507}
508
509fn _fix_without_formatting(input: impl Into<String>) -> String {
510    let json = Parser::new(input).parse_and_fix();
511    json.deserialize_all()._stringify_without_formatting()
512}
513
514#[cfg(test)]
515mod tests;