use thiserror::Error;
pub type Result<T> = std::result::Result<T, JsGenError>;
#[derive(Debug, Error)]
pub enum JsGenError {
#[error("Invalid identifier '{name}': {reason}")]
InvalidIdentifier {
name: String,
reason: String,
},
#[error("Invalid string literal: {0}")]
InvalidString(String),
#[error("Code generation failed: {0}")]
GenerationError(String),
#[error("Validation failed: {message}")]
ValidationError {
message: String,
location: Option<CodeLocation>,
},
#[error("Manifest verification failed for '{path}': {reason}")]
ManifestError {
path: String,
reason: String,
},
#[error("Hash mismatch for '{path}': expected {expected}, got {actual}")]
HashMismatch {
path: String,
expected: String,
actual: String,
},
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CodeLocation {
pub line: usize,
pub column: usize,
}
impl std::fmt::Display for CodeLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "line {}, column {}", self.line, self.column)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_display_invalid_identifier() {
let err = JsGenError::InvalidIdentifier {
name: "class".to_string(),
reason: "reserved word".to_string(),
};
assert_eq!(err.to_string(), "Invalid identifier 'class': reserved word");
}
#[test]
fn error_display_hash_mismatch() {
let err = JsGenError::HashMismatch {
path: "worker.js".to_string(),
expected: "abc123".to_string(),
actual: "def456".to_string(),
};
assert!(err.to_string().contains("Hash mismatch"));
assert!(err.to_string().contains("worker.js"));
}
#[test]
fn code_location_display() {
let loc = CodeLocation {
line: 42,
column: 10,
};
assert_eq!(loc.to_string(), "line 42, column 10");
}
}