feat(cli,diagnostics): add json reporter (#2451)

This commit is contained in:
Boshen 2024-02-20 15:28:27 +08:00 committed by GitHub
parent 399c3a6234
commit 195d76e6a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 11 deletions

View file

@ -7,7 +7,7 @@ use bpaf::Bpaf;
pub use self::{
format::{format_command, FormatOptions},
ignore::IgnoreOptions,
lint::{lint_command, LintOptions},
lint::{lint_command, LintOptions, OutputFormat, OutputOptions, WarningOptions},
};
use self::{format::format_options, lint::lint_options};

View file

@ -6,7 +6,7 @@ use oxc_linter::{partial_loader::LINT_PARTIAL_LOADER_EXT, LintOptions, LintServi
use oxc_span::VALID_EXTENSIONS;
use crate::{
command::LintOptions as CliLintOptions,
command::{LintOptions as CliLintOptions, OutputFormat, OutputOptions, WarningOptions},
walk::{Extensions, Walk},
CliRunResult, LintResult, Runner,
};
@ -37,6 +37,7 @@ impl Runner for LintRunner {
fix_options,
enable_plugins,
config,
output_options,
..
} = self.options;
@ -110,10 +111,7 @@ impl Runner for LintRunner {
};
let lint_service = LintService::new(cwd, &paths, linter);
let diagnostic_service = DiagnosticService::default()
.with_quiet(warning_options.quiet)
.with_max_warnings(warning_options.max_warnings);
let 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({
@ -137,6 +135,24 @@ impl Runner for LintRunner {
}
}
impl LintRunner {
fn get_diagnostic_service(
warning_options: &WarningOptions,
output_options: &OutputOptions,
) -> DiagnosticService {
let mut diagnostic_service = DiagnosticService::default()
.with_quiet(warning_options.quiet)
.with_max_warnings(warning_options.max_warnings);
match output_options.format {
OutputFormat::Default => {}
OutputFormat::Json => diagnostic_service.set_json_reporter(),
}
diagnostic_service
}
}
#[cfg(all(test, not(target_os = "windows")))]
mod test {
use super::LintRunner;

View file

@ -3,6 +3,7 @@
mod graphic_reporter;
mod graphical_theme;
mod reporter;
mod service;
use std::path::PathBuf;

View file

@ -0,0 +1,26 @@
use std::fmt;
use crate::{miette::JSONReportHandler, Diagnostic, 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())
}
}
impl DiagnosticReporter {
pub fn render_report<T: fmt::Write>(&self, f: &mut T, diagnostic: &(dyn Diagnostic)) {
match self {
Self::Graphical(handler) => handler.render_report(f, diagnostic).unwrap(),
Self::Json(handler) => handler.render_report(f, diagnostic).unwrap(),
}
}
}

View file

@ -2,17 +2,22 @@ use std::{
cell::Cell,
io::{BufWriter, Write},
path::{Path, PathBuf},
sync::mpsc,
sync::Arc,
sync::{mpsc, Arc},
};
use crate::{miette::NamedSource, Error, GraphicalReportHandler, MinifiedFileError, Severity};
use crate::{
miette::{JSONReportHandler, NamedSource},
reporter::DiagnosticReporter,
Error, MinifiedFileError, Severity,
};
pub type DiagnosticTuple = (PathBuf, Vec<Error>);
pub type DiagnosticSender = mpsc::Sender<Option<DiagnosticTuple>>;
pub type DiagnosticReceiver = mpsc::Receiver<Option<DiagnosticTuple>>;
pub struct DiagnosticService {
reporter: DiagnosticReporter,
/// Disable reporting on warnings, only errors are reported
quiet: bool,
@ -34,6 +39,7 @@ impl Default for DiagnosticService {
fn default() -> Self {
let (sender, receiver) = mpsc::channel();
Self {
reporter: DiagnosticReporter::default(),
quiet: false,
max_warnings: None,
warnings_count: Cell::new(0),
@ -45,6 +51,10 @@ impl Default for DiagnosticService {
}
impl DiagnosticService {
pub fn set_json_reporter(&mut self) {
self.reporter = DiagnosticReporter::Json(JSONReportHandler::new());
}
#[must_use]
pub fn with_quiet(mut self, yes: bool) -> Self {
self.quiet = yes;
@ -91,7 +101,6 @@ impl DiagnosticService {
/// * When the writer fails to write
pub fn run(&self) {
let mut buf_writer = BufWriter::new(std::io::stdout());
let handler = GraphicalReportHandler::new();
while let Ok(Some((path, diagnostics))) = self.receiver.recv() {
let mut output = String::new();
@ -116,7 +125,7 @@ impl DiagnosticService {
}
let mut err = String::new();
handler.render_report(&mut err, diagnostic.as_ref()).unwrap();
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()));