Skip to main content

cc_audit/parser/
json.rs

1//! JSON content parser.
2
3use super::traits::{ContentParser, ContentType, ParsedContent};
4use crate::error::Result;
5
6/// Parser for JSON files (mcp.json, package.json, settings.json, etc.).
7pub struct JsonParser;
8
9impl JsonParser {
10    /// Create a new JSON parser.
11    pub fn new() -> Self {
12        Self
13    }
14
15    /// Parse JSON content to a Value.
16    pub fn parse_value(content: &str) -> Option<serde_json::Value> {
17        serde_json::from_str(content).ok()
18    }
19}
20
21impl Default for JsonParser {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl ContentParser for JsonParser {
28    fn parse(&self, content: &str, path: &str) -> Result<ParsedContent> {
29        let mut parsed =
30            ParsedContent::new(ContentType::Json, content.to_string(), path.to_string());
31
32        // Try to parse as structured JSON
33        if let Some(value) = Self::parse_value(content) {
34            parsed = parsed.with_structured_data(value);
35        }
36
37        Ok(parsed)
38    }
39
40    fn supported_extensions(&self) -> &[&str] {
41        &[".json"]
42    }
43
44    fn can_parse(&self, path: &str) -> bool {
45        let path_lower = path.to_lowercase();
46        path_lower.ends_with(".json")
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_parse_valid_json() {
56        let parser = JsonParser::new();
57        let content = r#"{"name": "test", "version": "1.0"}"#;
58        let result = parser.parse(content, "config.json").unwrap();
59
60        assert_eq!(result.content_type, ContentType::Json);
61        assert!(result.structured_data.is_some());
62        let data = result.structured_data.unwrap();
63        assert_eq!(data["name"].as_str(), Some("test"));
64    }
65
66    #[test]
67    fn test_parse_invalid_json() {
68        let parser = JsonParser::new();
69        let content = "not valid json";
70        let result = parser.parse(content, "config.json").unwrap();
71
72        assert_eq!(result.content_type, ContentType::Json);
73        assert!(result.structured_data.is_none());
74    }
75
76    #[test]
77    fn test_supported_extensions() {
78        let parser = JsonParser::new();
79        assert!(parser.can_parse("mcp.json"));
80        assert!(parser.can_parse("package.json"));
81        assert!(!parser.can_parse("config.yaml"));
82    }
83
84    #[test]
85    fn test_parse_complex_json() {
86        let parser = JsonParser::new();
87        let content = r#"{
88            "mcpServers": {
89                "example": {
90                    "command": "npx",
91                    "args": ["-y", "@example/mcp-server"]
92                }
93            }
94        }"#;
95        let result = parser.parse(content, "mcp.json").unwrap();
96
97        assert!(result.structured_data.is_some());
98        let data = result.structured_data.unwrap();
99        assert!(data["mcpServers"]["example"]["command"].is_string());
100    }
101}