From f4cc42bc3c38e7cd4ab5a7edaf275ac32d8e4f87 Mon Sep 17 00:00:00 2001 From: Andrew Frantz Date: Mon, 3 Jun 2024 14:24:57 -0400 Subject: [PATCH] feat: explain command (#4) * feat: explain command * Update explain.rs * feat: pretty print explain * chore: clean * fix: get pretty_print_rule() to work Co-Authored-By: Andrew Thrasher <1165729+adthrasher@users.noreply.github.com> * Update README.md * docs: warning -> rule Co-Authored-By: Andrew Thrasher <1165729+adthrasher@users.noreply.github.com> --------- Co-authored-by: Andrew Thrasher <1165729+adthrasher@users.noreply.github.com> --- Cargo.toml | 3 ++- README.md | 3 ++- src/commands.rs | 1 + src/commands/explain.rs | 51 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 4 ++++ src/report.rs | 19 ++++++++++----- 6 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 src/commands/explain.rs diff --git a/Cargo.toml b/Cargo.toml index b79669d..70176ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,5 +20,6 @@ nonempty = "0.9.0" pest = { version = "2.7.5", features = ["pretty-print"] } tracing = "0.1.40" tracing-subscriber = "0.3.18" -wdl = { version = "0.2.0", features = ["ast", "core", "grammar"] } +wdl = { version = "0.3.0", features = ["ast", "core", "grammar"] } walkdir = "2.4.0" +colored = "2.1.0" diff --git a/README.md b/README.md index 51840c7..9be225d 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ ## 🎨 Features -* **`sprocket lint`.** Lint Workflow Description Language files. +* **`sprocket lint`** Lint Workflow Description Language files. +* **`sprocket explain`** Explain lint rules. ## Guiding Principles diff --git a/src/commands.rs b/src/commands.rs index e7034df..096ee39 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1 +1,2 @@ +pub mod explain; pub mod lint; diff --git a/src/commands/explain.rs b/src/commands/explain.rs new file mode 100644 index 0000000..30f4923 --- /dev/null +++ b/src/commands/explain.rs @@ -0,0 +1,51 @@ +use clap::Parser; +use colored::Colorize; +use wdl::ast::v1::lint as ast_lint; +use wdl::core::concern::lint::Rule; +use wdl::grammar::v1::lint as grammar_lint; + +/// Arguments for the `explain` subcommand. +#[derive(Parser, Debug)] +#[command(author, version, about)] +pub struct Args { + /// The name or code of the rule to explain. + #[arg(required = true)] + pub rule_identifier: String, +} + +pub fn pretty_print_rule(rule: &dyn Rule) { + println!("{}", rule.name().bold().underline()); + println!("{}", format!("{}::{}", rule.code(), rule.tags(),).yellow()); + println!(); + println!("{}", rule.body()); +} + +pub fn explain(args: Args) -> anyhow::Result<()> { + let ident = args.rule_identifier; + + let rule = grammar_lint::rules() + .into_iter() + .find(|rule| rule.name() == ident || rule.code().to_string() == ident); + + match rule { + Some(rule) => { + pretty_print_rule(&*rule); + } + None => { + let rule = ast_lint::rules() + .into_iter() + .find(|rule| rule.name() == ident || rule.code().to_string() == ident); + + match rule { + Some(rule) => { + pretty_print_rule(&*rule); + } + None => { + anyhow::bail!("No rule found with the identifier '{}'", ident); + } + } + } + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index f5ca9db..fef949f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,9 @@ git_testament!(TESTAMENT); enum Commands { /// Lints Workflow Description Language files. Lint(commands::lint::Args), + + /// Explains a lint warning. + Explain(commands::explain::Args), } #[derive(Parser)] @@ -51,6 +54,7 @@ pub fn inner() -> anyhow::Result<()> { match cli.command { Commands::Lint(args) => commands::lint::lint(args), + Commands::Explain(args) => commands::explain::explain(args), } } diff --git a/src/report.rs b/src/report.rs index 621f2c5..7197dc4 100644 --- a/src/report.rs +++ b/src/report.rs @@ -42,9 +42,9 @@ impl<'a> Reporter<'a> { Concern::LintWarning(warning) => { let mut diagnostic = Diagnostic::warning() .with_code(format!( - "{}::{}/{:?}", + "{}::{}::{:?}", warning.code(), - warning.group(), + warning.tags(), warning.level() )) .with_message(warning.subject()); @@ -56,13 +56,20 @@ impl<'a> Reporter<'a> { let byte_range = location.byte_range().unwrap(); diagnostic = diagnostic.with_labels(vec![ - Label::primary(handle, byte_range).with_message(warning.body()), + Label::primary(handle, byte_range).with_message(warning.subject()), ]); } - if let Some(fix) = warning.fix() { - diagnostic = diagnostic.with_notes(vec![format!("fix: {}", fix)]); - } + let mut notes = match warning.fix() { + Some(fix) => vec![format!("fix: {}", fix)], + None => vec![], + }; + notes.extend(vec![format!( + "see `sprocket explain {}` for more information", + warning.code() + )]); + + diagnostic = diagnostic.with_notes(notes); diagnostic }