Skip to content

Commit 5379e65

Browse files
authored
feat: diagnostic with labels (#6001)
1 parent 549825a commit 5379e65

File tree

4 files changed

+107
-13
lines changed

4 files changed

+107
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rspack_error/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ version = "0.1.0"
99

1010
[dependencies]
1111
anyhow = { workspace = true, features = ["backtrace"] }
12+
derivative = { workspace = true }
1213
futures = { workspace = true }
1314
miette = { version = "5", features = ["fancy"] }
1415
once_cell = { workspace = true }

crates/rspack_error/src/ext.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use std::error::Error;
1+
use std::{borrow::Cow, error::Error};
22

33
use miette::Diagnostic;
44

5-
use crate::miette_helpers::WithHelp;
5+
use crate::miette_helpers::{WithHelp, WithLabel};
66

77
/// Useful to convert [std::error::Error] to [crate::DiagnosticError]
88
pub trait ErrorExt {
@@ -26,19 +26,37 @@ impl<T: Diagnostic + Send + Sync + 'static> DiagnosticExt for T {
2626
}
2727

2828
pub trait MietteExt {
29-
fn with_help(self, message: impl Into<String>) -> Box<dyn Diagnostic + Send + Sync>;
29+
fn with_help(self, message: impl Into<Cow<'static, str>>) -> Box<dyn Diagnostic + Send + Sync>;
30+
fn with_labels(
31+
self,
32+
labels: impl Iterator<Item = miette::LabeledSpan>,
33+
) -> Box<dyn Diagnostic + Send + Sync>;
3034
}
3135

3236
impl MietteExt for Box<dyn Diagnostic + Send + Sync> {
33-
fn with_help(self, message: impl Into<String>) -> Box<dyn Diagnostic + Send + Sync> {
37+
fn with_help(self, message: impl Into<Cow<'static, str>>) -> Box<dyn Diagnostic + Send + Sync> {
3438
let h = WithHelp::from(self).with_help(message);
3539
<WithHelp as DiagnosticExt>::boxed(h)
3640
}
41+
fn with_labels(
42+
self,
43+
labels: impl Iterator<Item = miette::LabeledSpan>,
44+
) -> Box<dyn Diagnostic + Send + Sync> {
45+
let l = WithLabel::from(self).with_label(labels);
46+
<WithLabel as DiagnosticExt>::boxed(l)
47+
}
3748
}
3849

3950
impl MietteExt for miette::Error {
40-
fn with_help(self, message: impl Into<String>) -> Box<dyn Diagnostic + Send + Sync> {
51+
fn with_help(self, message: impl Into<Cow<'static, str>>) -> Box<dyn Diagnostic + Send + Sync> {
4152
let h = WithHelp::from(self).with_help(message);
4253
<WithHelp as DiagnosticExt>::boxed(h)
4354
}
55+
fn with_labels(
56+
self,
57+
labels: impl Iterator<Item = miette::LabeledSpan>,
58+
) -> Box<dyn Diagnostic + Send + Sync> {
59+
let l = WithLabel::from(self).with_label(labels);
60+
<WithLabel as DiagnosticExt>::boxed(l)
61+
}
4462
}

crates/rspack_error/src/miette_helpers.rs

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use std::fmt::Display;
1+
use std::{borrow::Cow, fmt::Display};
22

3+
use derivative::Derivative;
34
use miette::Diagnostic;
45
use once_cell::sync::OnceCell;
56
use thiserror::Error;
@@ -11,12 +12,12 @@ use crate::Error;
1112
#[error("{err}")]
1213
pub(crate) struct WithHelp {
1314
err: Error,
14-
help: Option<String>,
15-
wrap_help: OnceCell<Option<String>>,
15+
help: Option<Cow<'static, str>>,
16+
wrap_help: OnceCell<Option<Cow<'static, str>>>,
1617
}
1718

1819
impl WithHelp {
19-
pub(crate) fn with_help(mut self, help: impl Into<String>) -> Self {
20+
pub(crate) fn with_help(mut self, help: impl Into<Cow<'static, str>>) -> Self {
2021
self.help = Some(help.into());
2122
self
2223
}
@@ -54,12 +55,12 @@ impl miette::Diagnostic for WithHelp {
5455
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
5556
let help = self.wrap_help.get_or_init(|| {
5657
let prev = self.err.help().map(|h| h.to_string());
57-
let help = self.help.as_ref().map(|h| h.to_string());
58+
let help = self.help.as_ref().cloned();
5859
if let Some(prev) = prev {
59-
if let Some(help) = help {
60-
Some(format!("{prev}\n{help}"))
60+
if let Some(help) = &help {
61+
Some(format!("{prev}\n{help}").into())
6162
} else {
62-
Some(prev)
63+
Some(prev.into())
6364
}
6465
} else if help.is_some() {
6566
help
@@ -91,3 +92,76 @@ impl miette::Diagnostic for WithHelp {
9192
self.err.diagnostic_source()
9293
}
9394
}
95+
96+
/// Wrap diagnostic with label.
97+
#[derive(Error, Derivative)]
98+
#[derivative(Debug)]
99+
#[error("{err}")]
100+
pub(crate) struct WithLabel {
101+
err: Error,
102+
#[derivative(Debug = "ignore")]
103+
labels: Option<Vec<miette::LabeledSpan>>,
104+
}
105+
106+
impl WithLabel {
107+
pub(crate) fn with_label(mut self, labels: impl Iterator<Item = miette::LabeledSpan>) -> Self {
108+
self.labels = Some(labels.collect());
109+
self
110+
}
111+
}
112+
113+
impl From<Box<dyn Diagnostic + Send + Sync>> for WithLabel {
114+
fn from(value: Box<dyn Diagnostic + Send + Sync>) -> Self {
115+
Self {
116+
err: Error::new_boxed(value),
117+
labels: None,
118+
}
119+
}
120+
}
121+
122+
impl From<Error> for WithLabel {
123+
fn from(value: Error) -> Self {
124+
Self {
125+
err: value,
126+
labels: None,
127+
}
128+
}
129+
}
130+
131+
impl miette::Diagnostic for WithLabel {
132+
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
133+
self.err.code()
134+
}
135+
136+
fn severity(&self) -> Option<miette::Severity> {
137+
self.err.severity()
138+
}
139+
140+
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
141+
self.err.help()
142+
}
143+
144+
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
145+
self.err.url()
146+
}
147+
148+
fn source_code(&self) -> Option<&dyn miette::SourceCode> {
149+
self.err.source_code()
150+
}
151+
152+
fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
153+
self
154+
.labels
155+
.as_ref()
156+
.cloned()
157+
.map(|l| Box::new(l.into_iter()) as Box<dyn Iterator<Item = miette::LabeledSpan>>)
158+
}
159+
160+
fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
161+
self.err.related()
162+
}
163+
164+
fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
165+
self.err.diagnostic_source()
166+
}
167+
}

0 commit comments

Comments
 (0)