|
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