mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(diagnostics): implement json reporter (#2452)
This commit is contained in:
parent
195d76e6a5
commit
d0d0d9d7bb
3 changed files with 79 additions and 34 deletions
|
|
@ -111,7 +111,8 @@ impl Runner for LintRunner {
|
|||
};
|
||||
|
||||
let lint_service = LintService::new(cwd, &paths, linter);
|
||||
let diagnostic_service = Self::get_diagnostic_service(&warning_options, &output_options);
|
||||
let mut diagnostic_service =
|
||||
Self::get_diagnostic_service(&warning_options, &output_options);
|
||||
|
||||
// Spawn linting in another thread so diagnostics can be printed immediately from diagnostic_service.run.
|
||||
rayon::spawn({
|
||||
|
|
|
|||
|
|
@ -1,26 +1,75 @@
|
|||
use std::fmt;
|
||||
use std::io::{BufWriter, Stdout, Write};
|
||||
|
||||
use crate::{miette::JSONReportHandler, Diagnostic, GraphicalReportHandler};
|
||||
use crate::{
|
||||
miette::{Error, JSONReportHandler},
|
||||
GraphicalReportHandler,
|
||||
};
|
||||
|
||||
#[allow(clippy::large_enum_variant)] // Lerge size is fine because this is a singleton
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum DiagnosticReporter {
|
||||
Graphical(GraphicalReportHandler), // 288 bytes
|
||||
Json(JSONReportHandler),
|
||||
}
|
||||
|
||||
impl Default for DiagnosticReporter {
|
||||
fn default() -> Self {
|
||||
Self::Graphical(GraphicalReportHandler::new())
|
||||
}
|
||||
// stdio is blocked by LineWriter, use a BufWriter to reduce syscalls.
|
||||
// See `https://github.com/rust-lang/rust/issues/60673`.
|
||||
Graphical { handler: GraphicalReportHandler, writer: BufWriter<Stdout> },
|
||||
Json { diagnostics: Vec<Error> },
|
||||
}
|
||||
|
||||
impl DiagnosticReporter {
|
||||
pub fn render_report<T: fmt::Write>(&self, f: &mut T, diagnostic: &(dyn Diagnostic)) {
|
||||
pub fn new_graphical() -> Self {
|
||||
Self::Graphical {
|
||||
handler: GraphicalReportHandler::new(),
|
||||
writer: BufWriter::new(std::io::stdout()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_json() -> Self {
|
||||
Self::Json { diagnostics: vec![] }
|
||||
}
|
||||
|
||||
pub fn finish(&mut self) {
|
||||
match self {
|
||||
Self::Graphical(handler) => handler.render_report(f, diagnostic).unwrap(),
|
||||
Self::Json(handler) => handler.render_report(f, diagnostic).unwrap(),
|
||||
Self::Graphical { writer, .. } => {
|
||||
writer.flush().unwrap();
|
||||
}
|
||||
// NOTE: this output does not conform to eslint json format yet
|
||||
// https://eslint.org/docs/latest/use/formatters/#json
|
||||
Self::Json { diagnostics } => {
|
||||
let handler = JSONReportHandler::new();
|
||||
let messages = diagnostics
|
||||
.drain(..)
|
||||
.map(|error| {
|
||||
let mut output = String::from("\t");
|
||||
handler.render_report(&mut output, error.as_ref()).unwrap();
|
||||
output
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(",\n");
|
||||
println!("[\n{messages}\n]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_diagnostics(&mut self, s: &[u8]) {
|
||||
match self {
|
||||
Self::Graphical { writer, .. } => {
|
||||
writer.write_all(s).unwrap();
|
||||
}
|
||||
Self::Json { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_error(&mut self, error: Error) -> Option<String> {
|
||||
match self {
|
||||
Self::Graphical { handler, .. } => {
|
||||
let mut output = String::new();
|
||||
handler.render_report(&mut output, error.as_ref()).unwrap();
|
||||
Some(output)
|
||||
}
|
||||
Self::Json { diagnostics } => {
|
||||
diagnostics.push(error);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
use std::{
|
||||
cell::Cell,
|
||||
io::{BufWriter, Write},
|
||||
path::{Path, PathBuf},
|
||||
sync::{mpsc, Arc},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
miette::{JSONReportHandler, NamedSource},
|
||||
reporter::DiagnosticReporter,
|
||||
Error, MinifiedFileError, Severity,
|
||||
miette::NamedSource, reporter::DiagnosticReporter, Error, MinifiedFileError, Severity,
|
||||
};
|
||||
|
||||
pub type DiagnosticTuple = (PathBuf, Vec<Error>);
|
||||
|
|
@ -39,7 +36,7 @@ impl Default for DiagnosticService {
|
|||
fn default() -> Self {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
Self {
|
||||
reporter: DiagnosticReporter::default(),
|
||||
reporter: DiagnosticReporter::new_graphical(),
|
||||
quiet: false,
|
||||
max_warnings: None,
|
||||
warnings_count: Cell::new(0),
|
||||
|
|
@ -52,7 +49,7 @@ impl Default for DiagnosticService {
|
|||
|
||||
impl DiagnosticService {
|
||||
pub fn set_json_reporter(&mut self) {
|
||||
self.reporter = DiagnosticReporter::Json(JSONReportHandler::new());
|
||||
self.reporter = DiagnosticReporter::new_json();
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -99,9 +96,7 @@ impl DiagnosticService {
|
|||
/// # Panics
|
||||
///
|
||||
/// * When the writer fails to write
|
||||
pub fn run(&self) {
|
||||
let mut buf_writer = BufWriter::new(std::io::stdout());
|
||||
|
||||
pub fn run(&mut self) {
|
||||
while let Ok(Some((path, diagnostics))) = self.receiver.recv() {
|
||||
let mut output = String::new();
|
||||
for diagnostic in diagnostics {
|
||||
|
|
@ -124,20 +119,20 @@ impl DiagnosticService {
|
|||
}
|
||||
}
|
||||
|
||||
let mut err = String::new();
|
||||
self.reporter.render_report(&mut err, diagnostic.as_ref());
|
||||
// Skip large output and print only once
|
||||
if err.lines().any(|line| line.len() >= 400) {
|
||||
let minified_diagnostic = Error::new(MinifiedFileError(path.clone()));
|
||||
err = format!("{minified_diagnostic:?}");
|
||||
output = err;
|
||||
break;
|
||||
if let Some(mut err_str) = self.reporter.render_error(diagnostic) {
|
||||
// Skip large output and print only once
|
||||
if err_str.lines().any(|line| line.len() >= 400) {
|
||||
let minified_diagnostic = Error::new(MinifiedFileError(path.clone()));
|
||||
err_str = format!("{minified_diagnostic:?}");
|
||||
output = err_str;
|
||||
break;
|
||||
}
|
||||
output.push_str(&err_str);
|
||||
}
|
||||
output.push_str(&err);
|
||||
}
|
||||
buf_writer.write_all(output.as_bytes()).unwrap();
|
||||
self.reporter.render_diagnostics(output.as_bytes());
|
||||
}
|
||||
|
||||
buf_writer.flush().unwrap();
|
||||
self.reporter.finish();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue