gesha_core/
error.rs

1use crate::conversions::Error::FormatFailed;
2use crate::{conversions, io};
3use console::{Style, StyledObject};
4use gesha_collections::partial_result::PartialResult;
5use std::path::PathBuf;
6
7pub type Result<A> = std::result::Result<A, Error>;
8
9pub type Output<A> = PartialResult<A, Error>;
10
11#[derive(Debug)]
12pub enum Error {
13    OpenApiTypes {
14        path: PathBuf,
15        cause: openapi_types::Error,
16    },
17
18    Conversion {
19        path: PathBuf,
20        cause: conversions::Error,
21    },
22
23    Io(io::Error),
24
25    Multiple(Vec<Self>),
26
27    #[cfg(feature = "testing")]
28    Testing(crate::testing::Error),
29}
30
31impl Error {
32    pub fn detail(&self, theme: ErrorTheme) -> String {
33        match self {
34            Error::Conversion {
35                cause: FormatFailed { detail },
36                ..
37            } => {
38                format!("rustfmt>\n{}", detail)
39            }
40            Error::Conversion {
41                path,
42                cause: conversions::Error::TransformBroken { detail },
43            } => {
44                format!(
45                    "internal error: transform broken.\n{}\n{}",
46                    path.display(),
47                    detail,
48                )
49            }
50            Error::Multiple(errors) => errors
51                .iter()
52                .map(|e| e.detail(theme))
53                .collect::<Vec<_>>()
54                .join("\n"),
55
56            #[cfg(feature = "testing")]
57            Error::Testing(crate::testing::Error::DiffDetected {
58                output,
59                actual,
60                expected,
61            }) => {
62                let style = theme.diff_style();
63                format!(
64                    "\n {: <10} : {}\n {} : {}\n\n{}",
65                    style.src_lines,
66                    actual.to_string_lossy(),
67                    style.dst_lines,
68                    expected.to_string_lossy(),
69                    output
70                )
71            }
72            _ => {
73                format!("{:#?}", self)
74            }
75        }
76    }
77    pub fn conversion<A: Into<PathBuf>>(path: A) -> impl Fn(conversions::Error) -> Self {
78        let path = path.into();
79        move |cause| Self::Conversion {
80            path: path.clone(),
81            cause,
82        }
83    }
84    pub fn openapi<A: Into<PathBuf>>(path: A) -> impl Fn(openapi_types::Error) -> Self {
85        let path = path.into();
86        move |cause| Self::OpenApiTypes {
87            path: path.clone(),
88            cause,
89        }
90    }
91    pub fn dump(&self) -> String {
92        self.detail(ErrorTheme::Test)
93    }
94}
95
96#[derive(Copy, Clone)]
97pub enum ErrorTheme {
98    Test,
99    Overwrite,
100}
101
102pub struct DiffStyle {
103    src_lines: StyledObject<&'static str>,
104    dst_lines: StyledObject<&'static str>,
105}
106
107impl ErrorTheme {
108    pub fn diff_style(&self) -> DiffStyle {
109        match self {
110            ErrorTheme::Test => DiffStyle {
111                src_lines: Style::new().red().apply_to("- actual"),
112                dst_lines: Style::new().green().apply_to("+ expected"),
113            },
114            ErrorTheme::Overwrite => DiffStyle {
115                src_lines: Style::new().red().apply_to("- current"),
116                dst_lines: Style::new().green().apply_to("+ modified"),
117            },
118        }
119    }
120}