1use std::error::Error;
4use std::fmt::Display;
5use std::io::Error as IoError;
6use std::path::PathBuf;
7
8use wdl_analysis::AnalysisResult;
9
10pub type DocResult<T> = Result<T, DocError>;
12
13pub(crate) trait ResultContextExt {
15 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#[derive(Debug)]
34pub enum NpmError {
35 Build(IoError),
37 Install(IoError),
39 SearchIndex(IoError),
41 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#[derive(Debug)]
58pub enum DocErrorKind {
59 WorkspaceNotFound(PathBuf),
61 NoDocuments,
63 Analyzer(anyhow::Error),
65 AnalysisFailed(Vec<AnalysisResult>),
69 Npm(NpmError),
71 Io(IoError),
73 Manifest(wdl_modules::manifest::ManifestError),
75}
76
77#[derive(Debug)]
79pub struct DocError {
80 context: Option<String>,
82 kind: DocErrorKind,
84}
85
86impl DocError {
87 pub fn new(kind: DocErrorKind) -> Self {
89 Self {
90 kind,
91 context: None,
92 }
93 }
94
95 pub fn kind(&self) -> &DocErrorKind {
97 &self.kind
98 }
99
100 pub fn with_context(self, context: impl Display) -> Self {
102 Self {
103 context: Some(context.to_string()),
104 kind: self.kind,
105 }
106 }
107}
108
109impl Display for DocError {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 if let Some(ref ctx) = self.context {
112 write!(f, "{ctx}: ")?;
113 }
114
115 match &self.kind {
116 DocErrorKind::WorkspaceNotFound(root) => {
117 write!(
118 f,
119 "workspace root `{}` not found in analysis results",
120 root.display()
121 )
122 }
123 DocErrorKind::NoDocuments => write!(f, "no WDL documents found in analysis"),
124 DocErrorKind::Analyzer(e) => write!(f, "{e}"),
125 DocErrorKind::AnalysisFailed(_) => {
126 write!(f, "a WDL document in the workspace has analysis errors")
127 }
128 DocErrorKind::Npm(e) => write!(f, "{e}"),
129 DocErrorKind::Io(e) => write!(f, "{e}"),
130 DocErrorKind::Manifest(e) => write!(f, "failed to load WDL module manifest: {e}"),
131 }
132 }
133}
134
135impl Error for DocError {
136 fn source(&self) -> Option<&(dyn Error + 'static)> {
137 match &self.kind {
138 DocErrorKind::Manifest(e) => Some(e),
139 _ => None,
140 }
141 }
142}
143
144impl From<NpmError> for DocError {
145 fn from(e: NpmError) -> Self {
146 DocError::new(DocErrorKind::Npm(e))
147 }
148}
149
150impl From<IoError> for DocError {
151 fn from(e: IoError) -> Self {
152 DocError::new(DocErrorKind::Io(e))
153 }
154}
155
156impl From<wdl_modules::manifest::ManifestError> for DocError {
157 fn from(e: wdl_modules::manifest::ManifestError) -> Self {
158 DocError::new(DocErrorKind::Manifest(e))
159 }
160}
161
162impl From<DocErrorKind> for DocError {
163 fn from(e: DocErrorKind) -> Self {
164 DocError::new(e)
165 }
166}