diff --git a/Cargo.lock b/Cargo.lock index 422b21cd..5e66e4bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -474,6 +474,7 @@ dependencies = [ "serde", "serde_json", "syn 1.0.109", + "thiserror 2.0.11", ] [[package]] diff --git a/graphql_client_cli/src/error.rs b/graphql_client_cli/src/error.rs index feb682c2..3c597d3a 100644 --- a/graphql_client_cli/src/error.rs +++ b/graphql_client_cli/src/error.rs @@ -1,5 +1,3 @@ -use std::fmt::{Debug, Display}; - pub struct Error { source: Option>, message: Option, @@ -28,25 +26,16 @@ impl Error { } // This is the impl that shows up when the error bubbles up to `main()`. -impl Debug for Error { +impl std::fmt::Debug for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(msg) = &self.message { - f.write_str(msg)?; - f.write_str("\n")?; - } - - if self.source.is_some() && self.message.is_some() { - f.write_str("Cause: ")?; + match (&self.message, &self.source) { + (Some(msg), Some(source)) => { + write!(f, "{msg}\nCause: {source}\nLocation: {}", self.location) + } + (Some(msg), None) => write!(f, "{msg}\nLocation: {}", self.location), + (None, Some(source)) => write!(f, "{source}\nLocation: {}", self.location), + (None, None) => write!(f, "\nLocation: {}", self.location), } - - if let Some(source) = self.source.as_ref() { - Display::fmt(source, f)?; - } - - f.write_str("\nLocation: ")?; - Display::fmt(self.location, f)?; - - Ok(()) } } diff --git a/graphql_client_codegen/Cargo.toml b/graphql_client_codegen/Cargo.toml index 5a20e1f7..9c1392a4 100644 --- a/graphql_client_codegen/Cargo.toml +++ b/graphql_client_codegen/Cargo.toml @@ -17,3 +17,4 @@ quote = "^1.0" serde_json = "1.0" serde = { version = "^1.0", features = ["derive"] } syn = "^1.0" +thiserror = "2.0.11" diff --git a/graphql_client_codegen/src/generated_module.rs b/graphql_client_codegen/src/generated_module.rs index b225d001..0913d520 100644 --- a/graphql_client_codegen/src/generated_module.rs +++ b/graphql_client_codegen/src/generated_module.rs @@ -6,23 +6,13 @@ use crate::{ use heck::*; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use std::{error::Error, fmt::Display}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("Could not find an operation named {operation_name} in the query document.")] struct OperationNotFound { operation_name: String, } -impl Display for OperationNotFound { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Could not find an operation named ")?; - f.write_str(&self.operation_name)?; - f.write_str(" in the query document.") - } -} - -impl Error for OperationNotFound {} - /// This struct contains the parameters necessary to generate code for a given operation. pub(crate) struct GeneratedModule<'a> { pub operation: &'a str, diff --git a/graphql_client_codegen/src/lib.rs b/graphql_client_codegen/src/lib.rs index 8d087057..bfee221f 100644 --- a/graphql_client_codegen/src/lib.rs +++ b/graphql_client_codegen/src/lib.rs @@ -28,19 +28,12 @@ mod tests; pub use crate::codegen_options::{CodegenMode, GraphQLClientCodegenOptions}; -use std::{collections::BTreeMap, fmt::Display, io}; +use std::{collections::BTreeMap, io}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("{0}")] struct GeneralError(String); -impl Display for GeneralError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.0) - } -} - -impl std::error::Error for GeneralError {} - type BoxError = Box; type CacheMap = std::sync::Mutex>; type QueryDocument = graphql_parser::query::Document<'static, String>; @@ -169,34 +162,20 @@ fn generate_module_token_stream_inner( Ok(modules) } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] enum ReadFileError { - FileNotFound { path: String, io_error: io::Error }, - ReadError { path: String, io_error: io::Error }, -} - -impl Display for ReadFileError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ReadFileError::FileNotFound { path, .. } => { - write!(f, "Could not find file with path: {}\n - Hint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".", path) - } - ReadFileError::ReadError { path, .. } => { - f.write_str("Error reading file at: ")?; - f.write_str(path) - } - } - } -} - -impl std::error::Error for ReadFileError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - ReadFileError::FileNotFound { io_error, .. } - | ReadFileError::ReadError { io_error, .. } => Some(io_error), - } - } + #[error("Could not find file with path: {path}\nHint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".")] + FileNotFound { + path: String, + #[source] + io_error: io::Error, + }, + #[error("Error reading file at: {path}")] + ReadError { + path: String, + #[source] + io_error: io::Error, + }, } fn read_file(path: &std::path::Path) -> Result { diff --git a/graphql_client_codegen/src/query.rs b/graphql_client_codegen/src/query.rs index bb2b6318..1593a64c 100644 --- a/graphql_client_codegen/src/query.rs +++ b/graphql_client_codegen/src/query.rs @@ -18,24 +18,14 @@ use crate::{ StoredInputType, StoredScalar, TypeId, UnionId, }, }; -use std::{ - collections::{BTreeMap, BTreeSet}, - fmt::Display, -}; +use std::collections::{BTreeMap, BTreeSet}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("{message}")] pub(crate) struct QueryValidationError { message: String, } -impl Display for QueryValidationError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) - } -} - -impl std::error::Error for QueryValidationError {} - impl QueryValidationError { pub(crate) fn new(message: String) -> Self { QueryValidationError { message }