Skip to content

Commit

Permalink
refactor(linter): add output formatter (#8436)
Browse files Browse the repository at this point in the history
I want to start grouping all the different Formats for action X, Y and Z
into own place.
This is the first step and probably not the best one to be honest :)

~~I prefer that the `OutputFormatter` is a part of `oxlint` and not
`oxc_linter`~~
~~but all `use create::rules::RULES` is not public from outside.~~
EDIT: I pushed a commit with this changes can easily be reverted and
move back to `oxc_linter`

Also their is a crate `oxc_diagnostics` which has already the concept
too but only for the lint part of `oxlint` and not for the other parts.
The next goal would be splitting the `DiagnosticService` with its
reporters to `oxlint`.
  • Loading branch information
Sysix authored Jan 12, 2025
1 parent 01722f3 commit 43ed3e1
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 81 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/oxlint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ bpaf = { workspace = true, features = ["autocomplete", "bright-color", "derive"]
ignore = { workspace = true, features = ["simd-accel"] }
miette = { workspace = true }
rayon = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tempfile = { workspace = true }
tracing-subscriber = { workspace = true, features = [] } # Omit the `regex` feature

Expand Down
30 changes: 3 additions & 27 deletions apps/oxlint/src/command/lint.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::{path::PathBuf, str::FromStr};
use std::path::PathBuf;

use bpaf::Bpaf;
use oxc_linter::{AllowWarnDeny, FixKind, LintPlugins};

use crate::output_formatter::OutputFormat;

use super::{
ignore::{ignore_options, IgnoreOptions},
misc_options, validate_paths, MiscOptions, PATHS_ERROR_MESSAGE, VERSION,
Expand Down Expand Up @@ -184,32 +186,6 @@ pub struct OutputOptions {
pub format: OutputFormat,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum OutputFormat {
Default,
/// GitHub Check Annotation
/// <https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message>
Github,
Json,
Unix,
Checkstyle,
}

impl FromStr for OutputFormat {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"json" => Ok(Self::Json),
"default" => Ok(Self::Default),
"unix" => Ok(Self::Unix),
"checkstyle" => Ok(Self::Checkstyle),
"github" => Ok(Self::Github),
_ => Err(format!("'{s}' is not a known format")),
}
}
}

/// Enable Plugins
#[allow(clippy::struct_field_names)]
#[derive(Debug, Default, Clone, Bpaf)]
Expand Down
2 changes: 1 addition & 1 deletion apps/oxlint/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bpaf::Bpaf;

pub use self::{
ignore::IgnoreOptions,
lint::{lint_command, LintCommand, OutputFormat, OutputOptions, WarningOptions},
lint::{lint_command, LintCommand, OutputOptions, WarningOptions},
};

const VERSION: &str = match option_env!("OXC_VERSION") {
Expand Down
1 change: 1 addition & 0 deletions apps/oxlint/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod command;
mod lint;
mod output_formatter;
mod result;
mod runner;
mod walk;
Expand Down
13 changes: 6 additions & 7 deletions apps/oxlint/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ use oxc_span::VALID_EXTENSIONS;

use crate::{
cli::{
CliRunResult, LintCommand, LintResult, MiscOptions, OutputFormat, OutputOptions, Runner,
WarningOptions,
CliRunResult, LintCommand, LintResult, MiscOptions, OutputOptions, Runner, WarningOptions,
},
output_formatter::{OutputFormat, OutputFormatter},
walk::{Extensions, Walk},
};

Expand All @@ -36,13 +36,12 @@ impl Runner for LintRunner {
}

fn run(self) -> CliRunResult {
let format_str = self.options.output_options.format;
let output_formatter = OutputFormatter::new(format_str);

if self.options.list_rules {
let mut stdout = BufWriter::new(std::io::stdout());
if self.options.output_options.format == OutputFormat::Json {
Linter::print_rules_json(&mut stdout);
} else {
Linter::print_rules(&mut stdout);
}
output_formatter.all_rules(&mut stdout);
return CliRunResult::None;
}

Expand Down
29 changes: 29 additions & 0 deletions apps/oxlint/src/output_formatter/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::io::Write;

use oxc_linter::table::RuleTable;

pub struct DefaultOutputFormatter;

impl DefaultOutputFormatter {
pub fn all_rules<T: Write>(writer: &mut T) {
let table = RuleTable::new();
for section in table.sections {
writeln!(writer, "{}", section.render_markdown_table(None)).unwrap();
}
writeln!(writer, "Default: {}", table.turned_on_by_default_count).unwrap();
writeln!(writer, "Total: {}", table.total).unwrap();
}
}

#[cfg(test)]
mod test {
use crate::output_formatter::default::DefaultOutputFormatter;

#[test]
fn all_rules() {
let mut writer = Vec::new();

DefaultOutputFormatter::all_rules(&mut writer);
assert!(!writer.is_empty());
}
}
31 changes: 31 additions & 0 deletions apps/oxlint/src/output_formatter/json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use oxc_linter::rules::RULES;
use oxc_linter::RuleCategory;
use std::io::Write;

#[derive(Debug)]
pub struct JsonOutputFormatter;

impl JsonOutputFormatter {
pub fn all_rules<T: Write>(writer: &mut T) {
#[derive(Debug, serde::Serialize)]
struct RuleInfoJson<'a> {
scope: &'a str,
value: &'a str,
category: RuleCategory,
}

let rules_info = RULES.iter().map(|rule| RuleInfoJson {
scope: rule.plugin_name(),
value: rule.name(),
category: rule.category(),
});

writer
.write_all(
serde_json::to_string_pretty(&rules_info.collect::<Vec<_>>())
.expect("Failed to serialize")
.as_bytes(),
)
.unwrap();
}
}
50 changes: 50 additions & 0 deletions apps/oxlint/src/output_formatter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
mod default;
mod json;

use std::io::Write;
use std::str::FromStr;

use crate::output_formatter::{default::DefaultOutputFormatter, json::JsonOutputFormatter};

pub struct OutputFormatter {
format: OutputFormat,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum OutputFormat {
Default,
/// GitHub Check Annotation
/// <https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message>
Github,
Json,
Unix,
Checkstyle,
}

impl FromStr for OutputFormat {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"json" => Ok(Self::Json),
"default" => Ok(Self::Default),
"unix" => Ok(Self::Unix),
"checkstyle" => Ok(Self::Checkstyle),
"github" => Ok(Self::Github),
_ => Err(format!("'{s}' is not a known format")),
}
}
}

impl OutputFormatter {
pub fn new(format: OutputFormat) -> Self {
Self { format }
}
// print all rules which are currently supported by oxlint
pub fn all_rules<T: Write>(&self, writer: &mut T) {
match self.format {
OutputFormat::Json => JsonOutputFormatter::all_rules(writer),
_ => DefaultOutputFormatter::all_rules(writer),
}
}
}
49 changes: 3 additions & 46 deletions crates/oxc_linter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@ mod module_graph_visitor;
mod module_record;
mod options;
mod rule;
mod rules;
mod service;
mod utils;

pub mod loader;
pub mod rules;
pub mod table;

use std::{io::Write, path::Path, rc::Rc, sync::Arc};
use std::{path::Path, rc::Rc, sync::Arc};

use oxc_semantic::{AstNode, Semantic};
use rules::RULES;

pub use crate::{
config::{
Expand All @@ -45,7 +44,6 @@ use crate::{
context::ContextHost,
fixer::{Fixer, Message},
rules::RuleEnum,
table::RuleTable,
utils::iter_possible_jest_call_node,
};

Expand Down Expand Up @@ -183,52 +181,11 @@ impl Linter {

ctx_host.take_diagnostics()
}

/// # Panics
pub fn print_rules<W: Write>(writer: &mut W) {
let table = RuleTable::new();
for section in table.sections {
writeln!(writer, "{}", section.render_markdown_table(None)).unwrap();
}
writeln!(writer, "Default: {}", table.turned_on_by_default_count).unwrap();
writeln!(writer, "Total: {}", table.total).unwrap();
}

/// # Panics
pub fn print_rules_json<W: Write>(writer: &mut W) {
#[derive(Debug, serde::Serialize)]
struct RuleInfoJson<'a> {
scope: &'a str,
value: &'a str,
category: RuleCategory,
}

let rules_info = RULES.iter().map(|rule| RuleInfoJson {
scope: rule.plugin_name(),
value: rule.name(),
category: rule.category(),
});

writer
.write_all(
serde_json::to_string_pretty(&rules_info.collect::<Vec<_>>())
.expect("Failed to serialize")
.as_bytes(),
)
.unwrap();
}
}

#[cfg(test)]
mod test {
use super::{Linter, Oxlintrc};

#[test]
fn print_rules() {
let mut writer = Vec::new();
Linter::print_rules(&mut writer);
assert!(!writer.is_empty());
}
use super::Oxlintrc;

#[test]
fn test_schema_json() {
Expand Down

0 comments on commit 43ed3e1

Please sign in to comment.