Skip to content

Commit

Permalink
feat(reporting): add support for different targets and formats
Browse files Browse the repository at this point in the history
closes #1

Signed-off-by: azjezz <[email protected]>
  • Loading branch information
azjezz committed Dec 15, 2024
1 parent 4dd9847 commit 60ba66d
Show file tree
Hide file tree
Showing 25 changed files with 897 additions and 267 deletions.
6 changes: 5 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ bitflags = "2.6.0"
wasm-bindgen = "0.2.97"
serde-wasm-bindgen = "0.4"
diffy = "0.4.0"
termcolor = "1.4.1"

[dependencies]
mago-cli = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ clap = { workspace = true }
ahash = { workspace = true }
termtree = { workspace = true }
serde_json = { workspace = true }
strum = { workspace = true }
15 changes: 14 additions & 1 deletion crates/cli/src/commands/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use mago_ast::node::NodeKind;
use mago_ast::Node;
use mago_interner::ThreadedInterner;
use mago_reporting::reporter::Reporter;
use mago_reporting::reporter::ReportingFormat;
use mago_reporting::reporter::ReportingTarget;
use mago_reporting::Issue;
use mago_service::ast::AstService;
use mago_source::SourceManager;

use crate::enum_variants;
use crate::utils::bail;

#[derive(Parser, Debug)]
Expand All @@ -24,6 +27,12 @@ pub struct AstCommand {

#[arg(long, help = "Outputs the result in JSON format.")]
pub json: bool,

#[arg(long, default_value_t, help = "The issue reporting target to use.", ignore_case = true, value_parser = enum_variants!(ReportingTarget))]
pub reporting_target: ReportingTarget,

#[arg(long, default_value_t, help = "The issue reporting format to use.", ignore_case = true, value_parser = enum_variants!(ReportingFormat))]
pub reporting_format: ReportingFormat,
}

pub async fn execute(command: AstCommand) -> i32 {
Expand All @@ -32,11 +41,13 @@ pub async fn execute(command: AstCommand) -> i32 {
// Check if the file exists and is readable
if !file_path.exists() {
mago_feedback::error!("file '{}' does not exist.", command.file);

return 1;
}

if !file_path.is_file() {
mago_feedback::error!("'{}' is not a valid file.", command.file);

return 1;
}

Expand Down Expand Up @@ -68,7 +79,9 @@ pub async fn execute(command: AstCommand) -> i32 {
if let Some(error) = &error {
let issue = Into::<Issue>::into(error);

Reporter::new(source_manager).report(issue);
Reporter::new(interner, source_manager, command.reporting_target)
.report([issue], command.reporting_format)
.unwrap_or_else(bail);
}
}

Expand Down
15 changes: 13 additions & 2 deletions crates/cli/src/commands/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use clap::Parser;

use mago_interner::ThreadedInterner;
use mago_reporting::reporter::Reporter;
use mago_reporting::reporter::ReportingFormat;
use mago_reporting::reporter::ReportingTarget;
use mago_reporting::Level;
use mago_service::config::Configuration;
use mago_service::linter::LintService;
use mago_service::source::SourceService;

use crate::enum_variants;
use crate::utils::bail;

#[derive(Parser, Debug)]
Expand All @@ -24,6 +27,12 @@ If `mago.toml` is not found, the default configuration is used. The command outp
pub struct LintCommand {
#[arg(long, short, help = "Only show fixable issues", default_value_t = false)]
pub only_fixable: bool,

#[arg(long, default_value_t, help = "The issue reporting target to use.", ignore_case = true, value_parser = enum_variants!(ReportingTarget))]
pub reporting_target: ReportingTarget,

#[arg(long, default_value_t, help = "The issue reporting format to use.", ignore_case = true, value_parser = enum_variants!(ReportingFormat))]
pub reporting_format: ReportingFormat,
}

pub async fn execute(command: LintCommand, configuration: Configuration) -> i32 {
Expand All @@ -36,10 +45,12 @@ pub async fn execute(command: LintCommand, configuration: Configuration) -> i32
let issues = lint_service.run().await.unwrap_or_else(bail);
let issues_contain_errors = issues.get_highest_level().is_some_and(|level| level >= Level::Error);

let reporter = Reporter::new(interner, source_manager, command.reporting_target);

if command.only_fixable {
Reporter::new(source_manager).report_all(issues.only_fixable());
reporter.report(issues.only_fixable(), command.reporting_format).unwrap_or_else(bail);
} else {
Reporter::new(source_manager).report_all(issues);
reporter.report(issues, command.reporting_format).unwrap_or_else(bail);
}

if issues_contain_errors {
Expand Down
9 changes: 9 additions & 0 deletions crates/cli/src/utils/clap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[macro_export]
macro_rules! enum_variants {
($e: ty) => {{
use clap::builder::TypedValueParser;
use strum::VariantNames;

clap::builder::PossibleValuesParser::new(<$e>::VARIANTS).map(|s| s.parse::<$e>().unwrap())
}};
}
2 changes: 2 additions & 0 deletions crates/cli/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::error::Error;

pub mod clap;

pub fn print(error: impl Error) {
mago_feedback::error!(target = "mago", "{}", error);
mago_feedback::debug!(target = "mago", "{:#?}", error);
Expand Down
6 changes: 4 additions & 2 deletions crates/parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ impl From<SyntaxError> for ParseError {
}

impl From<&ParseError> for Issue {
fn from(val: &ParseError) -> Self {
Issue::error(val.to_string()).with_annotation(Annotation::primary(val.span()))
fn from(error: &ParseError) -> Self {
let span = error.span();

Issue::error(error.to_string()).with_annotation(Annotation::primary(span))
}
}
4 changes: 4 additions & 0 deletions crates/reporting/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ rust-version.workspace = true
workspace = true

[dependencies]
mago-interner = { workspace = true }
mago-span = { workspace = true }
mago-source = { workspace = true }
mago-fixer = { workspace = true }
ahash = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
codespan-reporting = { workspace = true }
termcolor = { workspace = true }
strum = { workspace = true }
65 changes: 65 additions & 0 deletions crates/reporting/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use codespan_reporting::files::Error as FilesError;
use serde_json::Error as JsonError;
use std::io::Error as IoError;

use mago_source::error::SourceError;

#[derive(Debug)]
pub enum ReportingError {
SourceError(SourceError),
JsonError(JsonError),
FilesError(FilesError),
IoError(IoError),
InvalidTarget(String),
InvalidFormat(String),
}

impl std::fmt::Display for ReportingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SourceError(error) => write!(f, "source error: {}", error),
Self::JsonError(error) => write!(f, "json error: {}", error),
Self::FilesError(error) => write!(f, "files error: {}", error),
Self::IoError(error) => write!(f, "io error: {}", error),
Self::InvalidTarget(target) => write!(f, "invalid target: {}", target),
Self::InvalidFormat(format) => write!(f, "invalid format: {}", format),
}
}
}

impl std::error::Error for ReportingError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::SourceError(error) => Some(error),
Self::JsonError(error) => Some(error),
Self::FilesError(error) => Some(error),
Self::IoError(error) => Some(error),
Self::InvalidTarget(_) => None,
Self::InvalidFormat(_) => None,
}
}
}

impl From<SourceError> for ReportingError {
fn from(error: SourceError) -> Self {
Self::SourceError(error)
}
}

impl From<JsonError> for ReportingError {
fn from(error: JsonError) -> Self {
Self::JsonError(error)
}
}

impl From<FilesError> for ReportingError {
fn from(error: FilesError) -> Self {
Self::FilesError(error)
}
}

impl From<IoError> for ReportingError {
fn from(error: IoError) -> Self {
Self::IoError(error)
}
}
Loading

0 comments on commit 60ba66d

Please sign in to comment.