mago_cli/commands/
lint.rs

1use clap::Parser;
2
3use mago_interner::ThreadedInterner;
4use mago_reporting::reporter::Reporter;
5use mago_reporting::reporter::ReportingFormat;
6use mago_reporting::reporter::ReportingTarget;
7use mago_reporting::Level;
8use mago_service::config::Configuration;
9use mago_service::linter::LintService;
10use mago_service::source::SourceService;
11
12use crate::enum_variants;
13use crate::utils::bail;
14
15#[derive(Parser, Debug)]
16#[command(
17    name = "lint",
18    about = "Lint the project according to the `mago.toml` configuration or default settings",
19    long_about = r#"
20Lint the project according to the `mago.toml` configuration or default settings.
21
22This command analyzes the project's source code and highlights issues based on the defined linting rules.
23
24If `mago.toml` is not found, the default configuration is used. The command outputs the issues found in the project."
25    "#
26)]
27pub struct LintCommand {
28    #[arg(long, short, help = "Only show fixable issues", default_value_t = false)]
29    pub only_fixable: bool,
30
31    #[arg(long, default_value_t, help = "The issue reporting target to use.", ignore_case = true, value_parser = enum_variants!(ReportingTarget))]
32    pub reporting_target: ReportingTarget,
33
34    #[arg(long, default_value_t, help = "The issue reporting format to use.", ignore_case = true, value_parser = enum_variants!(ReportingFormat))]
35    pub reporting_format: ReportingFormat,
36}
37
38pub async fn execute(command: LintCommand, configuration: Configuration) -> i32 {
39    let interner = ThreadedInterner::new();
40
41    let source_service = SourceService::new(interner.clone(), configuration.source);
42    let source_manager = source_service.load().await.unwrap_or_else(bail);
43
44    let lint_service = LintService::new(configuration.linter, interner.clone(), source_manager.clone());
45    let issues = lint_service.run().await.unwrap_or_else(bail);
46    let issues_contain_errors = issues.get_highest_level().is_some_and(|level| level >= Level::Error);
47
48    let reporter = Reporter::new(interner, source_manager, command.reporting_target);
49
50    if command.only_fixable {
51        reporter.report(issues.only_fixable(), command.reporting_format).unwrap_or_else(bail);
52    } else {
53        reporter.report(issues, command.reporting_format).unwrap_or_else(bail);
54    }
55
56    if issues_contain_errors {
57        1
58    } else {
59        0
60    }
61}