Skip to main content

wdl_doc/
error.rs

1//! Error type definitions.
2
3use std::error::Error;
4use std::fmt::Display;
5use std::io::Error as IoError;
6use std::path::PathBuf;
7
8use wdl_analysis::AnalysisResult;
9
10/// Result type for documentation operations.
11pub type DocResult<T> = Result<T, DocError>;
12
13/// Extensions for documentation results.
14pub(crate) trait ResultContextExt {
15    /// Apply additional context to a [`DocResult`] if it contains an error.
16    fn with_context<F, C>(self, context: F) -> Self
17    where
18        F: FnOnce() -> C,
19        C: Display;
20}
21
22impl<T> ResultContextExt for DocResult<T> {
23    fn with_context<F, C>(self, context: F) -> Self
24    where
25        F: FnOnce() -> C,
26        C: Display,
27    {
28        self.map_err(|e| e.with_context(context()))
29    }
30}
31
32/// Errors that can occur while running `npm` commands.
33#[derive(Debug)]
34pub enum NpmError {
35    /// Failed to run `npm run build` in the theme directory.
36    Build(IoError),
37    /// Failed to run `npm install` in the theme directory.
38    Install(IoError),
39    /// Failed to run `npx pagefind` in the output directory.
40    SearchIndex(IoError),
41    /// Failed to run `npx @tailwindcss/cli`.
42    Tailwind(IoError),
43}
44
45impl Display for NpmError {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            NpmError::Build(e) => write!(f, "failed to run `npm run build`: {e}"),
49            NpmError::Install(e) => write!(f, "failed to run `npm install`: {e}"),
50            NpmError::SearchIndex(e) => write!(f, "failed to run `npx pagefind`: {e}"),
51            NpmError::Tailwind(e) => write!(f, "failed to run `npx @tailwindcss/cli`: {e}"),
52        }
53    }
54}
55
56/// The kinds of errors that can occur.
57#[derive(Debug)]
58pub enum DocErrorKind {
59    /// The expected workspace was not found.
60    WorkspaceNotFound(PathBuf),
61    /// No WDL documents were found in the workspace.
62    NoDocuments,
63    /// Failed to run analysis on the workspace.
64    Analyzer(anyhow::Error),
65    /// One or more documents failed analysis.
66    ///
67    /// This contains the analysis results of all failed documents.
68    AnalysisFailed(Vec<AnalysisResult>),
69    /// Failed to run an `npm` command.
70    Npm(NpmError),
71    /// An I/O operation failed.
72    Io(IoError),
73}
74
75/// Errors that can occur while generating documentation.
76#[derive(Debug)]
77pub struct DocError {
78    /// An additional context message, if applicable.
79    context: Option<String>,
80    /// The kind of error that occurred.
81    kind: DocErrorKind,
82}
83
84impl DocError {
85    /// Create a new `DocError`.
86    pub fn new(kind: DocErrorKind) -> Self {
87        Self {
88            kind,
89            context: None,
90        }
91    }
92
93    /// The kind of error that occurred.
94    pub fn kind(&self) -> &DocErrorKind {
95        &self.kind
96    }
97
98    /// Add a context message to this error.
99    pub fn with_context(self, context: impl Display) -> Self {
100        Self {
101            context: Some(context.to_string()),
102            kind: self.kind,
103        }
104    }
105}
106
107impl Display for DocError {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        if let Some(ref ctx) = self.context {
110            write!(f, "{ctx}: ")?;
111        }
112
113        match &self.kind {
114            DocErrorKind::WorkspaceNotFound(root) => {
115                write!(
116                    f,
117                    "workspace root `{}` not found in analysis results",
118                    root.display()
119                )
120            }
121            DocErrorKind::NoDocuments => write!(f, "no WDL documents found in analysis"),
122            DocErrorKind::Analyzer(e) => write!(f, "{e}"),
123            DocErrorKind::AnalysisFailed(_) => {
124                write!(f, "a WDL document in the workspace has analysis errors")
125            }
126            DocErrorKind::Npm(e) => write!(f, "{e}"),
127            DocErrorKind::Io(e) => write!(f, "{e}"),
128        }
129    }
130}
131
132impl Error for DocError {}
133
134impl From<NpmError> for DocError {
135    fn from(e: NpmError) -> Self {
136        DocError::new(DocErrorKind::Npm(e))
137    }
138}
139
140impl From<IoError> for DocError {
141    fn from(e: IoError) -> Self {
142        DocError::new(DocErrorKind::Io(e))
143    }
144}
145
146impl From<DocErrorKind> for DocError {
147    fn from(e: DocErrorKind) -> Self {
148        DocError::new(e)
149    }
150}