mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
parent
ae1f15ac1e
commit
4425b961cd
4 changed files with 81 additions and 19 deletions
|
|
@ -144,6 +144,7 @@ pub struct OutputOptions {
|
||||||
pub enum OutputFormat {
|
pub enum OutputFormat {
|
||||||
Default,
|
Default,
|
||||||
Json,
|
Json,
|
||||||
|
Unix,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for OutputFormat {
|
impl FromStr for OutputFormat {
|
||||||
|
|
@ -152,6 +153,7 @@ impl FromStr for OutputFormat {
|
||||||
match s {
|
match s {
|
||||||
"json" => Ok(Self::Json),
|
"json" => Ok(Self::Json),
|
||||||
"default" => Ok(Self::Default),
|
"default" => Ok(Self::Default),
|
||||||
|
"unix" => Ok(Self::Unix),
|
||||||
_ => Err(format!("'{s}' is not a known format")),
|
_ => Err(format!("'{s}' is not a known format")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ impl LintRunner {
|
||||||
match output_options.format {
|
match output_options.format {
|
||||||
OutputFormat::Default => {}
|
OutputFormat::Default => {}
|
||||||
OutputFormat::Json => diagnostic_service.set_json_reporter(),
|
OutputFormat::Json => diagnostic_service.set_json_reporter(),
|
||||||
|
OutputFormat::Unix => diagnostic_service.set_unix_reporter(),
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostic_service
|
diagnostic_service
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,37 @@ use std::io::{BufWriter, Stdout, Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
miette::{Error, JSONReportHandler},
|
miette::{Error, JSONReportHandler},
|
||||||
GraphicalReportHandler,
|
GraphicalReportHandler, Severity,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// stdio is blocked by LineWriter, use a BufWriter to reduce syscalls.
|
||||||
|
/// See `https://github.com/rust-lang/rust/issues/60673`.
|
||||||
|
fn writer() -> BufWriter<Stdout> {
|
||||||
|
BufWriter::new(std::io::stdout())
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)] // Lerge size is fine because this is a singleton
|
#[allow(clippy::large_enum_variant)] // Lerge size is fine because this is a singleton
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum DiagnosticReporter {
|
pub enum DiagnosticReporter {
|
||||||
// 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> },
|
Graphical { handler: GraphicalReportHandler, writer: BufWriter<Stdout> },
|
||||||
Json { diagnostics: Vec<Error> },
|
Json { diagnostics: Vec<Error> },
|
||||||
|
Unix { total: usize, writer: BufWriter<Stdout> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticReporter {
|
impl DiagnosticReporter {
|
||||||
pub fn new_graphical() -> Self {
|
pub fn new_graphical() -> Self {
|
||||||
Self::Graphical {
|
Self::Graphical { handler: GraphicalReportHandler::new(), writer: writer() }
|
||||||
handler: GraphicalReportHandler::new(),
|
|
||||||
writer: BufWriter::new(std::io::stdout()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_json() -> Self {
|
pub fn new_json() -> Self {
|
||||||
Self::Json { diagnostics: vec![] }
|
Self::Json { diagnostics: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_unix() -> Self {
|
||||||
|
Self::Unix { total: 0, writer: writer() }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn finish(&mut self) {
|
pub fn finish(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
Self::Graphical { writer, .. } => {
|
Self::Graphical { writer, .. } => {
|
||||||
|
|
@ -35,24 +41,21 @@ impl DiagnosticReporter {
|
||||||
// NOTE: this output does not conform to eslint json format yet
|
// NOTE: this output does not conform to eslint json format yet
|
||||||
// https://eslint.org/docs/latest/use/formatters/#json
|
// https://eslint.org/docs/latest/use/formatters/#json
|
||||||
Self::Json { diagnostics } => {
|
Self::Json { diagnostics } => {
|
||||||
let handler = JSONReportHandler::new();
|
format_json(diagnostics);
|
||||||
let messages = diagnostics
|
}
|
||||||
.drain(..)
|
Self::Unix { total, writer } => {
|
||||||
.map(|error| {
|
if *total > 0 {
|
||||||
let mut output = String::from("\t");
|
let line = format!("\n{total} problem{}\n", if *total > 1 { "s" } else { "" });
|
||||||
handler.render_report(&mut output, error.as_ref()).unwrap();
|
writer.write_all(line.as_bytes()).unwrap();
|
||||||
output
|
}
|
||||||
})
|
writer.flush().unwrap();
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(",\n");
|
|
||||||
println!("[\n{messages}\n]");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_diagnostics(&mut self, s: &[u8]) {
|
pub fn render_diagnostics(&mut self, s: &[u8]) {
|
||||||
match self {
|
match self {
|
||||||
Self::Graphical { writer, .. } => {
|
Self::Graphical { writer, .. } | Self::Unix { writer, .. } => {
|
||||||
writer.write_all(s).unwrap();
|
writer.write_all(s).unwrap();
|
||||||
}
|
}
|
||||||
Self::Json { .. } => {}
|
Self::Json { .. } => {}
|
||||||
|
|
@ -70,6 +73,58 @@ impl DiagnosticReporter {
|
||||||
diagnostics.push(error);
|
diagnostics.push(error);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
Self::Unix { total: count, .. } => {
|
||||||
|
*count += 1;
|
||||||
|
Some(format_unix(&error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://github.com/fregante/eslint-formatters/tree/main/packages/eslint-formatter-json>
|
||||||
|
fn format_json(diagnostics: &mut Vec<Error>) {
|
||||||
|
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]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://github.com/fregante/eslint-formatters/tree/main/packages/eslint-formatter-unix>
|
||||||
|
fn format_unix(diagnostic: &Error) -> String {
|
||||||
|
let mut line = 0;
|
||||||
|
let mut column = 0;
|
||||||
|
let mut filename = String::new();
|
||||||
|
let mut message = String::new();
|
||||||
|
let mut severity = "Warning";
|
||||||
|
let mut rule_id = String::new();
|
||||||
|
if let Some(mut labels) = diagnostic.labels() {
|
||||||
|
if let Some(source) = diagnostic.source_code() {
|
||||||
|
if let Some(label) = labels.next() {
|
||||||
|
if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
|
||||||
|
line = span_content.line() + 1;
|
||||||
|
column = span_content.column() + 1;
|
||||||
|
if let Some(name) = span_content.name() {
|
||||||
|
filename = name.to_string();
|
||||||
|
};
|
||||||
|
if matches!(diagnostic.severity(), Some(Severity::Error)) {
|
||||||
|
severity = "Warning";
|
||||||
|
}
|
||||||
|
let msg = diagnostic.to_string();
|
||||||
|
// Our messages usually comes with `eslint(rule): message`
|
||||||
|
(rule_id, message) = msg.split_once(':').map_or_else(
|
||||||
|
|| (String::new(), msg.to_string()),
|
||||||
|
|(id, msg)| (id.to_string(), msg.trim().to_string()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format!("{filename}:{line}:{column}: {message} [{severity}/{rule_id}]\n")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ impl DiagnosticService {
|
||||||
self.reporter = DiagnosticReporter::new_json();
|
self.reporter = DiagnosticReporter::new_json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_unix_reporter(&mut self) {
|
||||||
|
self.reporter = DiagnosticReporter::new_unix();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_graphical_output(&self) -> bool {
|
pub fn is_graphical_output(&self) -> bool {
|
||||||
matches!(self.reporter, DiagnosticReporter::Graphical { .. })
|
matches!(self.reporter, DiagnosticReporter::Graphical { .. })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue