1use std::process::ExitCode;
8
9use colored::Colorize;
10use fallow_config::OutputFormat;
11
12pub use fallow_api::{
13 CHECK_RULES, DUPES_RULES, FLAGS_RULES, HEALTH_RULES, RuleDef, RuleGuide, SECURITY_RULES,
14 coverage_analyze_meta, coverage_setup_meta, rule_by_id, rule_by_token, rule_docs_url,
15 rule_guide, security_meta, serialize_explain_programmatic_json,
16};
17
18#[must_use]
20pub fn run_explain(issue_type: &str, output: OutputFormat) -> ExitCode {
21 let Some(rule) = rule_by_token(issue_type) else {
22 return crate::error::emit_error(
23 &fallow_api::unknown_explain_error(issue_type).message,
24 2,
25 output,
26 );
27 };
28 let guide = rule_guide(rule);
29 match output {
30 OutputFormat::Json => match serialize_explain_programmatic_json(
31 issue_type,
32 crate::output_runtime::current_root_envelope_mode(),
33 crate::output_runtime::telemetry_analysis_run_id().as_deref(),
34 ) {
35 Ok(value) => crate::report::emit_json(&value, "explain"),
36 Err(error) => crate::error::emit_error(&error.message, error.exit_code, output),
37 },
38 OutputFormat::Human => print_explain_human(rule, &guide),
39 OutputFormat::Compact => print_explain_compact(rule),
40 OutputFormat::Markdown => print_explain_markdown(rule, &guide),
41 OutputFormat::Sarif
42 | OutputFormat::CodeClimate
43 | OutputFormat::PrCommentGithub
44 | OutputFormat::PrCommentGitlab
45 | OutputFormat::ReviewGithub
46 | OutputFormat::ReviewGitlab
47 | OutputFormat::Badge
48 | OutputFormat::GithubAnnotations
49 | OutputFormat::GithubSummary => crate::error::emit_error(
50 "explain supports human, compact, markdown, and json output",
51 2,
52 output,
53 ),
54 }
55}
56
57fn print_explain_human(rule: &RuleDef, guide: &RuleGuide) -> ExitCode {
58 println!("{}", rule.name.bold());
59 println!("{}", rule.id.dimmed());
60 println!();
61 println!("{}", rule.short);
62 println!();
63 println!("{}", "Why it matters".bold());
64 println!("{}", rule.full);
65 println!();
66 println!("{}", "Example".bold());
67 println!("{}", guide.example);
68 println!();
69 println!("{}", "How to fix".bold());
70 println!("{}", guide.how_to_fix);
71 println!();
72 println!("{} {}", "Docs:".dimmed(), rule_docs_url(rule).dimmed());
73 ExitCode::SUCCESS
74}
75
76fn print_explain_compact(rule: &RuleDef) -> ExitCode {
77 println!("explain:{}:{}:{}", rule.id, rule.short, rule_docs_url(rule));
78 ExitCode::SUCCESS
79}
80
81fn print_explain_markdown(rule: &RuleDef, guide: &RuleGuide) -> ExitCode {
82 println!("# {}", rule.name);
83 println!();
84 println!("`{}`", rule.id);
85 println!();
86 println!("{}", rule.short);
87 println!();
88 println!("## Why it matters");
89 println!();
90 println!("{}", rule.full);
91 println!();
92 println!("## Example");
93 println!();
94 println!("{}", guide.example);
95 println!();
96 println!("## How to fix");
97 println!();
98 println!("{}", guide.how_to_fix);
99 println!();
100 println!("[Docs]({})", rule_docs_url(rule));
101 ExitCode::SUCCESS
102}