1use crate::error::{Result, SearchError};
2use serde_json::Value;
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use super::translation::TranslationEntry;
7
8pub struct JsonParser;
10
11impl JsonParser {
12 pub fn parse_file(path: &Path) -> Result<Vec<TranslationEntry>> {
13 let content = fs::read_to_string(path).map_err(|e| {
14 SearchError::json_parse_error(path, format!("Failed to read file: {}", e))
15 })?;
16
17 let root: Value = serde_json::from_str(&content).map_err(|e| {
18 SearchError::json_parse_error(path, format!("Invalid JSON syntax: {}", e))
19 })?;
20
21 let mut entries = Vec::new();
22 Self::flatten_json(&root, String::new(), path, &mut entries);
23
24 Ok(entries)
25 }
26
27 fn flatten_json(
28 value: &Value,
29 prefix: String,
30 file_path: &Path,
31 entries: &mut Vec<TranslationEntry>,
32 ) {
33 match value {
34 Value::Object(map) => {
35 for (key, val) in map {
36 let new_prefix = if prefix.is_empty() {
37 key.clone()
38 } else {
39 format!("{}.{}", prefix, key)
40 };
41
42 Self::flatten_json(val, new_prefix, file_path, entries);
43 }
44 }
45 Value::String(s) => {
46 entries.push(TranslationEntry {
54 key: prefix,
55 value: s.clone(),
56 line: 0, file: PathBuf::from(file_path),
58 });
59 }
60 Value::Number(n) => {
61 entries.push(TranslationEntry {
62 key: prefix,
63 value: n.to_string(),
64 line: 0,
65 file: PathBuf::from(file_path),
66 });
67 }
68 Value::Bool(b) => {
69 entries.push(TranslationEntry {
70 key: prefix,
71 value: b.to_string(),
72 line: 0,
73 file: PathBuf::from(file_path),
74 });
75 }
76 _ => {
77 }
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use std::io::Write;
87 use tempfile::NamedTempFile;
88
89 #[test]
90 fn test_parse_simple_json() {
91 let mut file = NamedTempFile::new().unwrap();
92 write!(file, r#"{{"key": "value"}}"#).unwrap();
93
94 let entries = JsonParser::parse_file(file.path()).unwrap();
95 assert_eq!(entries.len(), 1);
96 assert_eq!(entries[0].key, "key");
97 assert_eq!(entries[0].value, "value");
98 }
99
100 #[test]
101 fn test_parse_nested_json() {
102 let mut file = NamedTempFile::new().unwrap();
103 write!(file, r#"{{"parent": {{"child": "value"}}}}"#).unwrap();
104
105 let entries = JsonParser::parse_file(file.path()).unwrap();
106 assert_eq!(entries.len(), 1);
107 assert_eq!(entries[0].key, "parent.child");
108 assert_eq!(entries[0].value, "value");
109 }
110}