swc_error_reporters/
lib.rs

1use std::fmt::{Debug, Display};
2
3use anyhow::anyhow;
4use handler::{to_pretty_handler, HandlerOpts, ThreadSafetyDiagnostics};
5pub use miette::{GraphicalReportHandler, GraphicalTheme};
6use swc_common::{
7    errors::{Diagnostic, DiagnosticBuilder, Emitter},
8    sync::Lrc,
9};
10
11mod diagnostic;
12pub mod handler;
13pub use diagnostic::{convert_span, to_pretty_source_code, ToPrettyDiagnostic};
14
15pub struct ErrorEmitter {
16    pub diagnostics: ThreadSafetyDiagnostics,
17    pub cm: Lrc<swc_common::SourceMap>,
18    pub opts: HandlerOpts,
19}
20
21impl Emitter for ErrorEmitter {
22    fn emit(&mut self, db: &mut DiagnosticBuilder<'_>) {
23        let d = db.take();
24        self.diagnostics.push(d);
25    }
26
27    fn take_diagnostics(&mut self) -> Vec<String> {
28        let HandlerOpts {
29            color,
30            skip_filename,
31        } = self.opts;
32
33        self.diagnostics
34            .to_pretty_string(&self.cm, skip_filename, color)
35    }
36}
37
38/// A wrapper around a value that also contains a list of diagnostics.
39/// It helps swc error system migrate to the new error reporting system.
40pub struct TWithDiagnosticArray<T: Debug + Display> {
41    inner: Option<T>,
42    diagnostics: Vec<Diagnostic>,
43    cm: Lrc<swc_common::SourceMap>,
44    report_opts: HandlerOpts,
45}
46
47impl<T: Debug + Display> Debug for TWithDiagnosticArray<T> {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        f.debug_struct("TWithDiagnosticArray")
50            .field("inner", &self.inner)
51            .field("diagnostics", &self.diagnostics)
52            .finish()
53    }
54}
55
56impl<T: Debug + Display> Display for TWithDiagnosticArray<T> {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        match self.inner.as_ref() {
59            Some(inner) => {
60                write!(f, "{}\n{}", self.take_pretty_diagnostics(), inner)
61            }
62            None => write!(f, "{}", self.take_pretty_diagnostics()),
63        }
64    }
65}
66
67impl<T: Debug + Display> TWithDiagnosticArray<T> {
68    /// Creates a new instance of WrapperDiagnostics with the given diagnostics,
69    /// source map, and options.
70    pub fn new(
71        inner: Option<T>,
72        diagnostics: Vec<Diagnostic>,
73        cm: Lrc<swc_common::SourceMap>,
74        opts: HandlerOpts,
75    ) -> Self {
76        Self {
77            inner,
78            diagnostics,
79            cm,
80            report_opts: opts,
81        }
82    }
83
84    /// Returns a reference to the diagnostics vector.
85    pub fn diagnostics(&self) -> &[Diagnostic] {
86        &self.diagnostics
87    }
88
89    /// Consumes the WrapperDiagnostics instance and returns the diagnostics
90    /// vector.
91    pub fn take_diagnostics(self) -> Vec<Diagnostic> {
92        self.diagnostics
93    }
94
95    /// Converts the diagnostics to a pretty string representation.
96    fn take_pretty_diagnostics(&self) -> String {
97        let HandlerOpts {
98            color,
99            skip_filename,
100        } = self.report_opts;
101
102        let report_handler = to_pretty_handler(color);
103
104        self.diagnostics
105            .iter()
106            .map(|d| d.to_pretty_string(&self.cm, skip_filename, &report_handler))
107            .collect::<String>()
108    }
109}
110
111impl TWithDiagnosticArray<anyhow::Error> {
112    /// Converts the diagnostics to a pretty error string and wraps it in an
113    /// anyhow::Error.
114    pub fn to_pretty_error(self) -> anyhow::Error {
115        let pretty_diagnostics = self.take_pretty_diagnostics();
116
117        match self.inner {
118            Some(inner_error) => inner_error.context(pretty_diagnostics),
119            None => {
120                anyhow!(pretty_diagnostics)
121            }
122        }
123    }
124
125    /// Converts the diagnostics to a pretty string representation.
126    pub fn to_pretty_string(self) -> String {
127        let pretty_error = self.to_pretty_error();
128
129        pretty_error.to_string()
130    }
131}