Skip to main content

lux_cli/
check.rs

1use clap::{Args, ValueEnum};
2use emmylua_check::OutputDestination;
3use eyre::{eyre, Result};
4use itertools::Itertools;
5use lux_lib::{config::Config, progress::MultiProgress, workspace::Workspace};
6
7use crate::workspace::{sync_dependencies_if_locked, sync_test_dependencies_if_locked};
8
9#[derive(Args)]
10pub struct Check {
11    /// Comma-separated list of ignore patterns.
12    /// Patterns must follow glob syntax.
13    /// Lux will automatically add top-level ignored project files.
14    #[arg(short, long, value_delimiter = ',')]
15    ignore: Option<Vec<String>>,
16
17    /// The output format.
18    #[arg(long, default_value = "text", value_enum, ignore_case = true)]
19    output_format: OutputFormat,
20
21    /// Output destination.{n}
22    /// (stdout or a file path, only used when the output format is json).
23    #[arg(long, default_value = "stdout")]
24    output: OutputDestination,
25
26    /// Treat warnings as errors.
27    #[arg(long)]
28    warnings_as_errors: bool,
29}
30
31#[derive(Debug, Clone, PartialEq, ValueEnum)]
32enum OutputFormat {
33    Json,
34    Text,
35}
36
37impl From<OutputFormat> for emmylua_check::OutputFormat {
38    fn from(value: OutputFormat) -> Self {
39        match value {
40            OutputFormat::Json => emmylua_check::OutputFormat::Json,
41            OutputFormat::Text => emmylua_check::OutputFormat::Text,
42        }
43    }
44}
45
46pub async fn check(args: Check, config: Config) -> Result<()> {
47    let workspace = Workspace::current_or_err()?;
48
49    let progress = MultiProgress::new_arc(&config);
50    sync_dependencies_if_locked(&workspace, progress.clone(), &config).await?;
51    sync_test_dependencies_if_locked(&workspace, progress, &config).await?;
52
53    let workspace_dirs = workspace
54        .members()
55        .iter()
56        .map(|project| project.root())
57        .flat_map(|project_root| {
58            vec![
59                project_root.join("src"),
60                project_root.join("lua"),
61                // For now, we don't include tests
62                // because they require LLS_Addons definitions for busted
63
64                // project_root.join("test"),
65                // project_root.join("tests"),
66                // project_root.join("spec"),
67            ]
68        })
69        .filter(|dir| dir.is_dir())
70        .collect_vec();
71
72    if workspace_dirs.is_empty() {
73        println!("Nothing to check!");
74        return Ok(());
75    }
76
77    let luarc_path = workspace.luarc_path();
78    let rc_files = if luarc_path.is_file() {
79        Some(vec![luarc_path])
80    } else {
81        None
82    };
83    let emmylua_check_args = emmylua_check::CmdArgs {
84        config: rc_files,
85        workspace: workspace_dirs,
86        ignore: args.ignore,
87        output_format: args.output_format.into(),
88        output: args.output,
89        warnings_as_errors: args.warnings_as_errors,
90        verbose: config.verbose(),
91    };
92
93    emmylua_check::run_check(emmylua_check_args)
94        .await
95        .map_err(|err| eyre!(err.to_string()))?;
96    Ok(())
97}