use thiserror::Error;
#[derive(Debug, Error)]
pub enum ConvexTypeGeneratorError
{
#[error("Schema file not found")]
MissingSchemaFile,
#[error("Failed to parse file '{file}': {details}")]
ParsingFailed
{
file: String,
details: String,
},
#[error("Schema file '{file}' is empty")]
EmptySchemaFile
{
file: String,
},
#[error("Invalid path: {0}")]
InvalidPath(String),
#[error("Path contains invalid Unicode: {0}")]
InvalidUnicode(String),
#[error("Failed to parse AST as JSON: {0}")]
SerializationFailed(#[from] serde_json::Error),
#[error("IO error while reading '{file}': {error}")]
IOError
{
file: String,
#[source]
error: std::io::Error,
},
#[error("Invalid schema at {context}: {details}")]
InvalidSchema
{
context: String,
details: String,
},
#[error("Circular type reference detected: {}", .path.join(" -> "))]
CircularReference
{
path: Vec<String>,
},
#[error("Invalid type '{found}'. Valid types are: {}", .valid_types.join(", "))]
InvalidType
{
found: String,
valid_types: Vec<String>,
},
}
impl From<std::io::Error> for ConvexTypeGeneratorError
{
fn from(error: std::io::Error) -> Self
{
ConvexTypeGeneratorError::IOError {
file: String::new(),
error,
}
}
}
impl ConvexTypeGeneratorError
{
pub fn with_file_context(self, file: impl Into<String>) -> Self
{
match self {
Self::IOError { error, .. } => Self::IOError {
file: file.into(),
error,
},
other => other,
}
}
}
#[cfg(test)]
mod with_file_context_tests
{
use std::io::Error as IoError;
use super::*;
#[test]
fn attaches_path_to_io_error()
{
let err = ConvexTypeGeneratorError::IOError {
file: String::new(),
error: IoError::other("boom"),
};
let wrapped = err.with_file_context("/tmp/x.ts");
assert!(matches!(wrapped, ConvexTypeGeneratorError::IOError { ref file, .. } if file == "/tmp/x.ts"));
}
#[test]
fn leaves_non_io_variants_unchanged()
{
let err = ConvexTypeGeneratorError::MissingSchemaFile;
assert!(matches!(
err.with_file_context("nope"),
ConvexTypeGeneratorError::MissingSchemaFile
));
}
}
#[cfg(test)]
mod from_io_error_tests
{
use std::io::Error as IoError;
use super::*;
#[test]
fn maps_std_io_to_io_error_with_empty_file()
{
let e: ConvexTypeGeneratorError = IoError::other("read fail").into();
match e {
ConvexTypeGeneratorError::IOError { file, .. } => assert!(file.is_empty()),
other => panic!("expected IOError, got {other:?}"),
}
}
}
#[cfg(test)]
mod display_tests
{
use super::*;
#[test]
fn missing_schema_file_message()
{
let s = ConvexTypeGeneratorError::MissingSchemaFile.to_string();
assert!(s.contains("Schema"));
}
#[test]
fn invalid_type_lists_known_validators()
{
let e = ConvexTypeGeneratorError::InvalidType {
found: "bogus".into(),
valid_types: vec!["string".into()],
};
let s = e.to_string();
assert!(s.contains("bogus") && s.contains("string"));
}
}