|  | 
| 1 | 1 | use crate::cli_options::CliOptions; | 
| 2 |  | -use crate::{CliDiagnostic, Execution, TraversalMode}; | 
| 3 |  | -use biome_deserialize::Merge; | 
|  | 2 | +use crate::commands::get_files_to_process_with_cli_options; | 
|  | 3 | +use crate::execute::{StdinPayload, run_files, run_stdin}; | 
|  | 4 | +use crate::reporter::Report; | 
|  | 5 | +use crate::{CliDiagnostic, CliSession, VcsIntegration}; | 
|  | 6 | +use crate::{ExecutionConfig, ExecutionMode, VcsTargeting}; | 
| 4 | 7 | use pgt_configuration::PartialConfiguration; | 
| 5 | 8 | use pgt_console::Console; | 
|  | 9 | +use pgt_diagnostics::category; | 
| 6 | 10 | use pgt_fs::FileSystem; | 
| 7 |  | -use pgt_workspace::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; | 
|  | 11 | +use pgt_workspace::DynRef; | 
| 8 | 12 | use std::ffi::OsString; | 
| 9 | 13 | 
 | 
| 10 |  | -use super::{CommandRunner, get_files_to_process_with_cli_options}; | 
|  | 14 | +pub struct CheckArgs { | 
|  | 15 | + pub configuration: Option<PartialConfiguration>, | 
|  | 16 | + pub paths: Vec<OsString>, | 
|  | 17 | + pub stdin_file_path: Option<String>, | 
|  | 18 | + pub staged: bool, | 
|  | 19 | + pub changed: bool, | 
|  | 20 | + pub since: Option<String>, | 
|  | 21 | +} | 
|  | 22 | + | 
|  | 23 | +pub fn check( | 
|  | 24 | + mut session: CliSession, | 
|  | 25 | + cli_options: &CliOptions, | 
|  | 26 | + args: CheckArgs, | 
|  | 27 | +) -> Result<(), CliDiagnostic> { | 
|  | 28 | + validate_args(&args)?; | 
|  | 29 | + | 
|  | 30 | + let configuration = session.prepare_with_config(cli_options, args.configuration.clone())?; | 
|  | 31 | + session.setup_workspace(configuration.clone(), VcsIntegration::Enabled)?; | 
|  | 32 | + | 
|  | 33 | + let paths = resolve_paths(session.fs(), &configuration, &args)?; | 
|  | 34 | + | 
|  | 35 | + let vcs = VcsTargeting { | 
|  | 36 | + staged: args.staged, | 
|  | 37 | + changed: args.changed, | 
|  | 38 | + }; | 
|  | 39 | + | 
|  | 40 | + let max_diagnostics = if cli_options.reporter.is_default() { | 
|  | 41 | + cli_options.max_diagnostics.into() | 
|  | 42 | + } else { | 
|  | 43 | + u32::MAX | 
|  | 44 | + }; | 
|  | 45 | + | 
|  | 46 | + let mode = ExecutionMode::Check { vcs }; | 
|  | 47 | + let execution = ExecutionConfig::new(mode, max_diagnostics); | 
| 11 | 48 | 
 | 
| 12 |  | -pub(crate) struct CheckCommandPayload { | 
| 13 |  | - pub(crate) configuration: Option<PartialConfiguration>, | 
| 14 |  | - pub(crate) paths: Vec<OsString>, | 
| 15 |  | - pub(crate) stdin_file_path: Option<String>, | 
| 16 |  | - pub(crate) staged: bool, | 
| 17 |  | - pub(crate) changed: bool, | 
| 18 |  | - pub(crate) since: Option<String>, | 
|  | 49 | + if let Some(stdin_path) = args.stdin_file_path.as_deref() { | 
|  | 50 | + let payload = read_stdin_payload(stdin_path, session.console())?; | 
|  | 51 | + run_stdin(&mut session, &execution, payload) | 
|  | 52 | + } else { | 
|  | 53 | + let report: Report = run_files(&mut session, &execution, paths)?; | 
|  | 54 | + | 
|  | 55 | + let exit_result = enforce_exit_codes(cli_options, &report); | 
|  | 56 | + session.report("check", cli_options, &report)?; | 
|  | 57 | + exit_result | 
|  | 58 | + } | 
| 19 | 59 | } | 
| 20 | 60 | 
 | 
| 21 |  | -impl CommandRunner for CheckCommandPayload { | 
| 22 |  | - const COMMAND_NAME: &'static str = "check"; | 
| 23 |  | - | 
| 24 |  | - fn merge_configuration( | 
| 25 |  | - &mut self, | 
| 26 |  | -  loaded_configuration: LoadedConfiguration, | 
| 27 |  | - _fs: &DynRef<'_, dyn FileSystem>, | 
| 28 |  | - _console: &mut dyn Console, | 
| 29 |  | - ) -> Result<PartialConfiguration, WorkspaceError> { | 
| 30 |  | - let LoadedConfiguration { | 
| 31 |  | -  configuration: mut fs_configuration, | 
| 32 |  | -  .. | 
| 33 |  | -  } = loaded_configuration; | 
| 34 |  | - | 
| 35 |  | -  if let Some(configuration) = self.configuration.clone() { | 
| 36 |  | -  // overwrite fs config with cli args | 
| 37 |  | - fs_configuration.merge_with(configuration); | 
|  | 61 | +fn resolve_paths( | 
|  | 62 | + fs: &DynRef<'_, dyn FileSystem>, | 
|  | 63 | + configuration: &PartialConfiguration, | 
|  | 64 | + args: &CheckArgs, | 
|  | 65 | +) -> Result<Vec<OsString>, CliDiagnostic> { | 
|  | 66 | + let mut paths = get_files_to_process_with_cli_options( | 
|  | 67 | + args.since.as_deref(), | 
|  | 68 | + args.changed, | 
|  | 69 | +  args.staged, | 
|  | 70 | + fs, | 
|  | 71 | + configuration, | 
|  | 72 | + )? | 
|  | 73 | + .unwrap_or_else(|| args.paths.clone()); | 
|  | 74 | + | 
|  | 75 | + if paths.is_empty() && args.stdin_file_path.is_none() { | 
|  | 76 | + if let Some(current_dir) = fs.working_directory() { | 
|  | 77 | + paths.push(current_dir.into_os_string()); | 
| 38 | 78 |  } | 
|  | 79 | + } | 
| 39 | 80 | 
 | 
| 40 |  | - Ok(fs_configuration) | 
|  | 81 | + Ok(paths) | 
|  | 82 | +} | 
|  | 83 | + | 
|  | 84 | +fn read_stdin_payload( | 
|  | 85 | + path: &str, | 
|  | 86 | + console: &mut dyn Console, | 
|  | 87 | +) -> Result<StdinPayload, CliDiagnostic> { | 
|  | 88 | + let input_code = console.read(); | 
|  | 89 | + if let Some(input_code) = input_code { | 
|  | 90 | + Ok(StdinPayload { | 
|  | 91 | + path: path.into(), | 
|  | 92 | + content: input_code, | 
|  | 93 | + }) | 
|  | 94 | + } else { | 
|  | 95 | + Err(CliDiagnostic::missing_argument("stdin", "check")) | 
| 41 | 96 |  } | 
|  | 97 | +} | 
|  | 98 | + | 
|  | 99 | +fn enforce_exit_codes(cli_options: &CliOptions, payload: &Report) -> Result<(), CliDiagnostic> { | 
|  | 100 | + let traversal = payload.traversal.as_ref(); | 
|  | 101 | + let processed = traversal.map_or(0, |t| t.changed + t.unchanged); | 
|  | 102 | + let skipped = traversal.map_or(0, |t| t.skipped); | 
| 42 | 103 | 
 | 
| 43 |  | - fn get_files_to_process( | 
| 44 |  | - &self, | 
| 45 |  | - fs: &DynRef<'_, dyn FileSystem>, | 
| 46 |  | - configuration: &PartialConfiguration, | 
| 47 |  | - ) -> Result<Vec<OsString>, CliDiagnostic> { | 
| 48 |  | - let paths = get_files_to_process_with_cli_options( | 
| 49 |  | - self.since.as_deref(), | 
| 50 |  | - self.changed, | 
| 51 |  | - self.staged, | 
| 52 |  | - fs, | 
| 53 |  | - configuration, | 
| 54 |  | - )? | 
| 55 |  | - .unwrap_or(self.paths.clone()); | 
| 56 |  | - | 
| 57 |  | - Ok(paths) | 
|  | 104 | + if processed.saturating_sub(skipped) == 0 && !cli_options.no_errors_on_unmatched { | 
|  | 105 | + return Err(CliDiagnostic::no_files_processed()); | 
| 58 | 106 |  } | 
| 59 | 107 | 
 | 
| 60 |  | - fn get_stdin_file_path(&self) -> Option<&str> { | 
| 61 |  | - self.stdin_file_path.as_deref() | 
|  | 108 | + let warnings = payload.warnings; | 
|  | 109 | + let errors = payload.errors; | 
|  | 110 | + let category = category!("check"); | 
|  | 111 | + | 
|  | 112 | + if errors > 0 { | 
|  | 113 | + return Err(CliDiagnostic::check_error(category)); | 
| 62 | 114 |  } | 
| 63 | 115 | 
 | 
| 64 |  | - fn get_execution( | 
| 65 |  | - &self, | 
| 66 |  | - cli_options: &CliOptions, | 
| 67 |  | - console: &mut dyn Console, | 
| 68 |  | - _workspace: &dyn Workspace, | 
| 69 |  | - ) -> Result<Execution, CliDiagnostic> { | 
| 70 |  | - Ok(Execution::new(TraversalMode::Check { | 
| 71 |  | - stdin: self.get_stdin(console)?, | 
| 72 |  | - vcs_targeted: (self.staged, self.changed).into(), | 
| 73 |  | - }) | 
| 74 |  | - .set_report(cli_options)) | 
|  | 116 | + if warnings > 0 && cli_options.error_on_warnings { | 
|  | 117 | + return Err(CliDiagnostic::check_warnings(category)); | 
| 75 | 118 |  } | 
|  | 119 | + | 
|  | 120 | + Ok(()) | 
|  | 121 | +} | 
|  | 122 | + | 
|  | 123 | +fn validate_args(args: &CheckArgs) -> Result<(), CliDiagnostic> { | 
|  | 124 | + if args.since.is_some() { | 
|  | 125 | + if !args.changed { | 
|  | 126 | + return Err(CliDiagnostic::incompatible_arguments("since", "changed")); | 
|  | 127 | + } | 
|  | 128 | + if args.staged { | 
|  | 129 | + return Err(CliDiagnostic::incompatible_arguments("since", "staged")); | 
|  | 130 | + } | 
|  | 131 | + } | 
|  | 132 | + | 
|  | 133 | + if args.changed && args.staged { | 
|  | 134 | + return Err(CliDiagnostic::incompatible_arguments("changed", "staged")); | 
|  | 135 | + } | 
|  | 136 | + | 
|  | 137 | + Ok(()) | 
| 76 | 138 | } | 
0 commit comments