ddex_parser/
error.rs

1//! Parser-specific error handling
2
3use ddex_core::error::DDEXError;
4use ddex_core::ffi::{FFIError, FFIErrorSeverity, FFIErrorCategory};
5use thiserror::Error;
6
7// Re-export ErrorLocation for use in this crate
8pub use ddex_core::error::ErrorLocation;
9
10// Define Result type alias
11pub type Result<T> = std::result::Result<T, ParseError>;
12
13/// Parser-specific errors
14#[derive(Debug, Error)]
15pub enum ParseError {
16    #[error("XML parsing error: {message}")]
17    XmlError {
18        message: String,
19        location: ErrorLocation,
20    },
21    
22    #[error("Unsupported DDEX version: {version}")]
23    UnsupportedVersion {
24        version: String,
25    },
26    
27    #[error("Security violation: {message}")]
28    SecurityViolation {
29        message: String,
30    },
31    
32    #[error("Parse timeout after {seconds} seconds")]
33    Timeout {
34        seconds: u64,
35    },
36    
37    #[error("Core error: {0}")]
38    Core(#[from] DDEXError),
39    
40    #[error("IO error: {0}")]
41    Io(#[from] std::io::Error),
42}
43
44impl From<ParseError> for FFIError {
45    fn from(err: ParseError) -> Self {
46        match err {
47            ParseError::Core(core_err) => core_err.into(),
48            ParseError::XmlError { message, location } => FFIError {
49                code: "PARSE_XML_ERROR".to_string(),
50                message,
51                location: Some(ddex_core::ffi::FFIErrorLocation {
52                    line: location.line,
53                    column: location.column,
54                    path: location.path,
55                }),
56                severity: FFIErrorSeverity::Error,
57                hint: Some("Check XML syntax".to_string()),
58                category: FFIErrorCategory::XmlParsing,
59            },
60            ParseError::UnsupportedVersion { version } => FFIError {
61                code: "UNSUPPORTED_VERSION".to_string(),
62                message: format!("Unsupported DDEX version: {}", version),
63                location: None,
64                severity: FFIErrorSeverity::Error,
65                hint: Some("Use ERN 3.8.2, 4.2, or 4.3".to_string()),
66                category: FFIErrorCategory::Version,
67            },
68            ParseError::SecurityViolation { message } => FFIError {
69                code: "SECURITY_VIOLATION".to_string(),
70                message,
71                location: None,
72                severity: FFIErrorSeverity::Error,
73                hint: Some("Check for XXE or entity expansion attacks".to_string()),
74                category: FFIErrorCategory::Validation,
75            },
76            ParseError::Timeout { seconds } => FFIError {
77                code: "PARSE_TIMEOUT".to_string(),
78                message: format!("Parse timeout after {} seconds", seconds),
79                location: None,
80                severity: FFIErrorSeverity::Error,
81                hint: Some("File may be too large or complex".to_string()),
82                category: FFIErrorCategory::Io,
83            },
84            ParseError::Io(io_err) => FFIError {
85                code: "IO_ERROR".to_string(),
86                message: io_err.to_string(),
87                location: None,
88                severity: FFIErrorSeverity::Error,
89                hint: None,
90                category: FFIErrorCategory::Io,
91            },
92        }
93    }
94}