ddex_parser/
lib.rs

1// core/src/lib.rs
2use ddex_core::models;
3/// DDEX Parser Core Library
4
5pub mod error;
6pub mod parser;
7pub mod transform;
8
9// Re-export commonly used types
10pub use ddex_core::models::versions::ERNVersion;
11
12use serde::{Deserialize, Serialize};
13use parser::security::SecurityConfig;
14
15/// Main DDEX Parser
16#[derive(Debug, Clone)]
17pub struct DDEXParser {
18    config: SecurityConfig,
19}
20
21impl Default for DDEXParser {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl DDEXParser {
28    /// Create a new parser with default security configuration
29    pub fn new() -> Self {
30        Self {
31            config: SecurityConfig::default(),
32        }
33    }
34    
35    /// Create parser with custom security configuration
36    pub fn with_config(config: SecurityConfig) -> Self {
37        Self { config }
38    }
39    
40    /// Parse DDEX XML from a reader
41    pub fn parse<R: std::io::BufRead + std::io::Seek>(
42        &self,
43        reader: R,
44    ) -> Result<ddex_core::models::flat::ParsedERNMessage, error::ParseError> {
45        self.parse_with_options(reader, Default::default())
46    }
47    
48    /// Parse with options
49    pub fn parse_with_options<R: std::io::BufRead + std::io::Seek>(
50        &self,
51        reader: R,
52        options: parser::ParseOptions,
53    ) -> Result<ddex_core::models::flat::ParsedERNMessage, error::ParseError> {
54        // Apply security config
55        if !self.config.disable_external_entities {
56            return Err(error::ParseError::SecurityViolation {
57                message: "External entities are disabled".to_string(),
58            });
59        }
60        
61        parser::parse(reader, options)
62    }
63    
64    /// Stream parse for large files
65    pub fn stream<R: std::io::BufRead>(
66        &self,
67        reader: R,
68    ) -> StreamIterator<R> {
69        // For streaming, we can't detect version from reader without consuming it
70        // So we default to V4_3
71        let version = ddex_core::models::versions::ERNVersion::V4_3;
72        
73        StreamIterator {
74            parser: parser::stream::StreamingParser::new(reader, version),
75            config: self.config.clone(),
76        }
77    }
78    
79    /// Detect DDEX version from XML
80    pub fn detect_version<R: std::io::BufRead>(
81        &self,
82        reader: R,
83    ) -> Result<ddex_core::models::versions::ERNVersion, error::ParseError> {
84        parser::detector::VersionDetector::detect(reader)
85    }
86    
87    /// Perform sanity check on DDEX XML
88    pub fn sanity_check<R: std::io::BufRead>(
89        &self,
90        _reader: R,
91    ) -> Result<SanityCheckResult, error::ParseError> {
92        // Placeholder for sanity check
93        Ok(SanityCheckResult {
94            is_valid: true,
95            version: ddex_core::models::versions::ERNVersion::V4_3,
96            errors: Vec::new(),
97            warnings: Vec::new(),
98        })
99    }
100}
101
102/// Iterator for streaming releases
103pub struct StreamIterator<R: std::io::BufRead> {
104    parser: parser::stream::StreamingParser<R>,
105    #[allow(dead_code)]  // Will be used when implementing Iterator
106    config: SecurityConfig,
107}
108
109impl<R: std::io::BufRead> Iterator for StreamIterator<R> {
110    type Item = Result<models::graph::Release, error::ParseError>;
111    
112    fn next(&mut self) -> Option<Self::Item> {
113        self.parser.stream_releases().next()
114    }
115}
116
117/// Result of sanity check
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct SanityCheckResult {
120    pub is_valid: bool,
121    pub version: ddex_core::models::versions::ERNVersion,
122    pub errors: Vec<String>,
123    pub warnings: Vec<String>,
124}
125
126/// Benchmark report support
127#[cfg(feature = "bench")]
128pub mod bench_report;
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133    
134    #[test]
135    fn test_parser_creation() {
136        let parser = DDEXParser::new();
137        assert!(parser.config.disable_external_entities);
138    }
139}