Skip to main content

probar_js_gen/
error.rs

1//! Error types for `probar-js-gen`.
2//!
3//! # References
4//! - DO-178C (2011) Section 6.3.4: Error handling requirements
5//! - Leveson (2012) "Engineering a Safer World" - Fault tolerance patterns
6
7use thiserror::Error;
8
9/// Result type alias for js-gen operations.
10pub type Result<T> = std::result::Result<T, JsGenError>;
11
12/// Errors that can occur during JavaScript generation.
13///
14/// Each variant includes context for debugging while maintaining
15/// type safety per DO-178C requirements.
16#[derive(Debug, Error)]
17pub enum JsGenError {
18    /// Invalid identifier name (reserved word, invalid characters, etc.)
19    #[error("Invalid identifier '{name}': {reason}")]
20    InvalidIdentifier {
21        /// The invalid identifier
22        name: String,
23        /// Why it's invalid
24        reason: String,
25    },
26
27    /// Invalid string literal (unterminated, invalid escapes, etc.)
28    #[error("Invalid string literal: {0}")]
29    InvalidString(String),
30
31    /// Code generation failed
32    #[error("Code generation failed: {0}")]
33    GenerationError(String),
34
35    /// Validation failed
36    #[error("Validation failed: {message}")]
37    ValidationError {
38        /// What validation failed
39        message: String,
40        /// Location in generated code (if available)
41        location: Option<CodeLocation>,
42    },
43
44    /// Manifest verification failed (file was manually modified)
45    #[error("Manifest verification failed for '{path}': {reason}")]
46    ManifestError {
47        /// Path to the file
48        path: String,
49        /// Why verification failed
50        reason: String,
51    },
52
53    /// Hash mismatch (generated file was modified)
54    #[error("Hash mismatch for '{path}': expected {expected}, got {actual}")]
55    HashMismatch {
56        /// Path to the file
57        path: String,
58        /// Expected hash
59        expected: String,
60        /// Actual hash
61        actual: String,
62    },
63
64    /// IO error during file operations
65    #[error("IO error: {0}")]
66    Io(#[from] std::io::Error),
67
68    /// JSON serialization/deserialization error
69    #[error("JSON error: {0}")]
70    Json(#[from] serde_json::Error),
71}
72
73/// Location in generated code for error reporting.
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct CodeLocation {
76    /// Line number (1-indexed)
77    pub line: usize,
78    /// Column number (1-indexed)
79    pub column: usize,
80}
81
82impl std::fmt::Display for CodeLocation {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        write!(f, "line {}, column {}", self.line, self.column)
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn error_display_invalid_identifier() {
94        let err = JsGenError::InvalidIdentifier {
95            name: "class".to_string(),
96            reason: "reserved word".to_string(),
97        };
98        assert_eq!(err.to_string(), "Invalid identifier 'class': reserved word");
99    }
100
101    #[test]
102    fn error_display_hash_mismatch() {
103        let err = JsGenError::HashMismatch {
104            path: "worker.js".to_string(),
105            expected: "abc123".to_string(),
106            actual: "def456".to_string(),
107        };
108        assert!(err.to_string().contains("Hash mismatch"));
109        assert!(err.to_string().contains("worker.js"));
110    }
111
112    #[test]
113    fn code_location_display() {
114        let loc = CodeLocation {
115            line: 42,
116            column: 10,
117        };
118        assert_eq!(loc.to_string(), "line 42, column 10");
119    }
120}