use std::error::Error;
use std::fmt::Display;
use std::io::Error as IoError;
use std::path::PathBuf;
use wdl_analysis::AnalysisResult;
pub type DocResult<T> = Result<T, DocError>;
pub(crate) trait ResultContextExt {
fn with_context<F, C>(self, context: F) -> Self
where
F: FnOnce() -> C,
C: Display;
}
impl<T> ResultContextExt for DocResult<T> {
fn with_context<F, C>(self, context: F) -> Self
where
F: FnOnce() -> C,
C: Display,
{
self.map_err(|e| e.with_context(context()))
}
}
#[derive(Debug)]
pub enum NpmError {
Build(IoError),
Install(IoError),
Tailwind(IoError),
}
impl Display for NpmError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NpmError::Build(e) => write!(f, "failed to run `npm run build`: {e}"),
NpmError::Install(e) => write!(f, "failed to run `npm install`: {e}"),
NpmError::Tailwind(e) => write!(f, "failed to run `npx @tailwindcss/cli`: {e}"),
}
}
}
#[derive(Debug)]
pub enum DocErrorKind {
WorkspaceNotFound(PathBuf),
NoDocuments,
Analyzer(anyhow::Error),
AnalysisFailed(Vec<AnalysisResult>),
Npm(NpmError),
Io(IoError),
}
#[derive(Debug)]
pub struct DocError {
context: Option<String>,
kind: DocErrorKind,
}
impl DocError {
pub fn new(kind: DocErrorKind) -> Self {
Self {
kind,
context: None,
}
}
pub fn kind(&self) -> &DocErrorKind {
&self.kind
}
pub fn with_context(self, context: impl Display) -> Self {
Self {
context: Some(context.to_string()),
kind: self.kind,
}
}
}
impl Display for DocError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(ref ctx) = self.context {
write!(f, "{ctx}: ")?;
}
match &self.kind {
DocErrorKind::WorkspaceNotFound(root) => {
write!(
f,
"workspace root `{}` not found in analysis results",
root.display()
)
}
DocErrorKind::NoDocuments => write!(f, "no WDL documents found in analysis"),
DocErrorKind::Analyzer(e) => write!(f, "{e}"),
DocErrorKind::AnalysisFailed(_) => {
write!(f, "a WDL document in the workspace has analysis errors")
}
DocErrorKind::Npm(e) => write!(f, "{e}"),
DocErrorKind::Io(e) => write!(f, "{e}"),
}
}
}
impl Error for DocError {}
impl From<NpmError> for DocError {
fn from(e: NpmError) -> Self {
DocError::new(DocErrorKind::Npm(e))
}
}
impl From<IoError> for DocError {
fn from(e: IoError) -> Self {
DocError::new(DocErrorKind::Io(e))
}
}
impl From<DocErrorKind> for DocError {
fn from(e: DocErrorKind) -> Self {
DocError::new(e)
}
}