Skip to content

Commit

Permalink
feat(linter): add hyperlinks to diagnostic messages
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac committed Aug 29, 2024
1 parent 524b7ca commit be6076d
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 15 deletions.
22 changes: 17 additions & 5 deletions crates/oxc_diagnostics/src/graphic_reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,24 @@ impl GraphicalReportHandler {
opts = opts.word_splitter(word_splitter);
}

let title = if let Some(code) = diagnostic.code() {
format!("{code}: {diagnostic}")
} else {
diagnostic.to_string()
let title = match (self.links, diagnostic.url(), diagnostic.code()) {
(LinkStyle::Link, Some(url), Some(code)) => {
// magic unicode escape sequences to make the terminal print a hyperlink
const CTL: &str = "\u{1b}]8;;";
const END: &str = "\u{1b}]8;;\u{1b}\\";
let code = code.style(severity_style);
let message = diagnostic.to_string();
let title = message.style(severity_style);
format!("{CTL}{url}\u{1b}\\{code}{END}: {title}",)
}
(_, _, Some(code)) => {
let title = format!("{code}: {}", diagnostic);
format!("{}", title.style(severity_style))
}
_ => {
format!("{}", diagnostic.to_string().style(severity_style))
}
};
let title = format!("{}", title.style(severity_style));
let title = textwrap::fill(&title, opts);
writeln!(f, "{}", title)?;

Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub struct OxcDiagnosticInner {
pub help: Option<Cow<'static, str>>,
pub severity: Severity,
pub code: OxcCode,
pub url: Option<Cow<'static, str>>,
}

impl fmt::Display for OxcDiagnostic {
Expand Down Expand Up @@ -101,6 +102,9 @@ impl Diagnostic for OxcDiagnostic {
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.code.is_some().then(|| Box::new(&self.code) as Box<dyn Display>)
}
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.url.as_ref().map(Box::new).map(|c| c as Box<dyn Display>)
}
}

impl OxcDiagnostic {
Expand All @@ -112,6 +116,7 @@ impl OxcDiagnostic {
help: None,
severity: Severity::Error,
code: OxcCode::default(),
url: None,
}),
}
}
Expand All @@ -124,6 +129,7 @@ impl OxcDiagnostic {
help: None,
severity: Severity::Warning,
code: OxcCode::default(),
url: None,
}),
}
}
Expand Down Expand Up @@ -205,6 +211,11 @@ impl OxcDiagnostic {
self
}

pub fn with_url<S: Into<Cow<'static, str>>>(mut self, url: S) -> Self {
self.inner.url = Some(url.into());
self
}

pub fn with_source_code<T: SourceCode + Send + Sync + 'static>(self, code: T) -> Error {
Error::from(self).with_source_code(code)
}
Expand Down
30 changes: 21 additions & 9 deletions crates/oxc_linter/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub struct LintContext<'a> {
eslint_config: Arc<OxlintConfig>,

// states
current_plugin_name: &'static str,
current_plugin_prefix: &'static str,
current_rule_name: &'static str,
#[cfg(debug_assertions)]
Expand All @@ -60,6 +61,7 @@ pub struct LintContext<'a> {
}

impl<'a> LintContext<'a> {
const WEBSITE_BASE_URL: &'static str = "https://oxc.rs/docs/guide/usage/linter/rules";
/// # Panics
/// If `semantic.cfg()` is `None`.
pub fn new(file_path: Box<Path>, semantic: Rc<Semantic<'a>>) -> Self {
Expand All @@ -81,6 +83,7 @@ impl<'a> LintContext<'a> {
fix: FixKind::None,
file_path: file_path.into(),
eslint_config: Arc::new(OxlintConfig::default()),
current_plugin_name: "eslint",
current_plugin_prefix: "eslint",
current_rule_name: "",
#[cfg(debug_assertions)]
Expand All @@ -102,6 +105,7 @@ impl<'a> LintContext<'a> {
}

pub fn with_plugin_name(mut self, plugin: &'static str) -> Self {
self.current_plugin_name = plugin;
self.current_plugin_prefix = plugin_name_to_prefix(plugin);
self
}
Expand Down Expand Up @@ -209,16 +213,24 @@ impl<'a> LintContext<'a> {
self.diagnostics.borrow().iter().cloned().collect::<Vec<_>>()
}

fn add_diagnostic(&self, message: Message<'a>) {
if !self.disable_directives.contains(self.current_rule_name, message.span()) {
let mut message = message;
message.error =
message.error.with_error_code(self.current_plugin_prefix, self.current_rule_name);
if message.error.severity != self.severity {
message.error = message.error.with_severity(self.severity);
}
self.diagnostics.borrow_mut().push(message);
fn add_diagnostic(&self, mut message: Message<'a>) {
if self.disable_directives.contains(self.current_rule_name, message.span()) {
return;
}
message.error = message
.error
.with_error_code(self.current_plugin_prefix, self.current_rule_name)
.with_url(format!(
"{}/{}/{}.html",
Self::WEBSITE_BASE_URL,
self.current_plugin_name,
self.current_rule_name
));
if message.error.severity != self.severity {
message.error = message.error.with_severity(self.severity);
}

self.diagnostics.borrow_mut().push(message);
}

/// Report a lint rule violation.
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_linter/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,9 @@ impl Tester {
}
.to_string_lossy();

let handler = GraphicalReportHandler::new().with_theme(GraphicalTheme::unicode_nocolor());
let handler = GraphicalReportHandler::new()
.with_links(false)
.with_theme(GraphicalTheme::unicode_nocolor());
for diagnostic in result {
let diagnostic = diagnostic.error.with_source_code(NamedSource::new(
diagnostic_path.clone(),
Expand Down

0 comments on commit be6076d

Please sign in to comment.