From 64a84a644923bd6bdee0c0f89f876f4c43e3ffb9 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Mon, 7 Oct 2024 09:27:25 +0100 Subject: [PATCH] refactor(cli): use command runner to run predictable logic (#4176) --- crates/biome_cli/src/changed.rs | 4 +- crates/biome_cli/src/commands/check.rs | 9 +- crates/biome_cli/src/commands/ci.rs | 2 +- crates/biome_cli/src/commands/format.rs | 380 +++++++++++------------- crates/biome_cli/src/commands/lint.rs | 9 +- crates/biome_cli/src/commands/mod.rs | 147 ++++++++- crates/biome_cli/src/lib.rs | 16 +- 7 files changed, 342 insertions(+), 225 deletions(-) diff --git a/crates/biome_cli/src/changed.rs b/crates/biome_cli/src/changed.rs index b3eae9f37621..7b101ae841f1 100644 --- a/crates/biome_cli/src/changed.rs +++ b/crates/biome_cli/src/changed.rs @@ -7,14 +7,14 @@ use std::ffi::OsString; pub(crate) fn get_changed_files( fs: &DynRef<'_, dyn FileSystem>, configuration: &PartialConfiguration, - since: Option, + since: Option<&str>, ) -> Result, CliDiagnostic> { let default_branch = configuration .vcs .as_ref() .and_then(|v| v.default_branch.as_ref()); - let base = match (since.as_ref(), default_branch) { + let base = match (since, default_branch) { (Some(since), Some(_)) => since, (Some(since), None) => since, (None, Some(branch)) => branch, diff --git a/crates/biome_cli/src/commands/check.rs b/crates/biome_cli/src/commands/check.rs index d0584dd2e26f..b8cc90369ab1 100644 --- a/crates/biome_cli/src/commands/check.rs +++ b/crates/biome_cli/src/commands/check.rs @@ -168,8 +168,13 @@ pub(crate) fn check( let stdin = get_stdin(stdin_file_path, &mut *session.app.console, "check")?; - let vcs_targeted_paths = - get_files_to_process(since, changed, staged, &session.app.fs, &fs_configuration)?; + let vcs_targeted_paths = get_files_to_process( + since.as_deref(), + changed, + staged, + &session.app.fs, + &fs_configuration, + )?; session .app diff --git a/crates/biome_cli/src/commands/ci.rs b/crates/biome_cli/src/commands/ci.rs index 29b909276813..34ac322ed075 100644 --- a/crates/biome_cli/src/commands/ci.rs +++ b/crates/biome_cli/src/commands/ci.rs @@ -142,7 +142,7 @@ pub(crate) fn ci(session: CliSession, payload: CiCommandPayload) -> Result<(), C } if changed { - paths = get_changed_files(&session.app.fs, &fs_configuration, since)?; + paths = get_changed_files(&session.app.fs, &fs_configuration, since.as_deref())?; } session diff --git a/crates/biome_cli/src/commands/format.rs b/crates/biome_cli/src/commands/format.rs index 0438e60f5706..1d7c2072761e 100644 --- a/crates/biome_cli/src/commands/format.rs +++ b/crates/biome_cli/src/commands/format.rs @@ -1,28 +1,22 @@ use crate::cli_options::CliOptions; -use crate::commands::{ - get_files_to_process, get_stdin, resolve_manifest, validate_configuration_diagnostics, -}; +use crate::commands::{get_files_to_process, CommandRunner}; use crate::diagnostics::DeprecatedArgument; use crate::execute::VcsTargeted; -use crate::{ - execute_mode, setup_cli_subscriber, CliDiagnostic, CliSession, Execution, TraversalMode, -}; +use crate::{CliDiagnostic, Execution, TraversalMode}; use biome_configuration::vcs::PartialVcsConfiguration; use biome_configuration::{ - PartialCssFormatter, PartialFilesConfiguration, PartialFormatterConfiguration, - PartialGraphqlFormatter, PartialJavascriptFormatter, PartialJsonFormatter, + PartialConfiguration, PartialCssFormatter, PartialFilesConfiguration, + PartialFormatterConfiguration, PartialGraphqlFormatter, PartialJavascriptFormatter, + PartialJsonFormatter, }; -use biome_console::{markup, ConsoleExt}; +use biome_console::{markup, Console, ConsoleExt}; use biome_deserialize::Merge; use biome_diagnostics::PrintDiagnostic; -use biome_service::configuration::{ - load_configuration, load_editorconfig, LoadedConfiguration, PartialConfigurationExt, -}; -use biome_service::workspace::{RegisterProjectFolderParams, UpdateSettingsParams}; +use biome_fs::FileSystem; +use biome_service::configuration::{load_editorconfig, LoadedConfiguration}; +use biome_service::{DynRef, WorkspaceError}; use std::ffi::OsString; -use super::check_fix_incompatible_arguments; - pub(crate) struct FormatCommandPayload { pub(crate) javascript_formatter: Option, pub(crate) json_formatter: Option, @@ -34,227 +28,193 @@ pub(crate) struct FormatCommandPayload { pub(crate) stdin_file_path: Option, pub(crate) write: bool, pub(crate) fix: bool, - pub(crate) cli_options: CliOptions, pub(crate) paths: Vec, pub(crate) staged: bool, pub(crate) changed: bool, pub(crate) since: Option, } -/// Handler for the "format" command of the Biome CLI -pub(crate) fn format( - session: CliSession, - payload: FormatCommandPayload, -) -> Result<(), CliDiagnostic> { - let FormatCommandPayload { - mut javascript_formatter, - mut formatter_configuration, - vcs_configuration, - mut paths, - cli_options, - stdin_file_path, - files_configuration, - write, - fix, - mut json_formatter, - css_formatter, - graphql_formatter, - since, - staged, - changed, - } = payload; - setup_cli_subscriber(cli_options.log_level, cli_options.log_kind); - - check_fix_incompatible_arguments(super::FixFileModeOptions { - apply: false, - apply_unsafe: false, - write, - fix, - unsafe_: false, - })?; - - let loaded_configuration = - load_configuration(&session.app.fs, cli_options.as_configuration_path_hint())?; - validate_configuration_diagnostics( - &loaded_configuration, - session.app.console, - cli_options.verbose, - )?; - - let editorconfig_search_path = loaded_configuration.directory_path.clone(); - let LoadedConfiguration { - configuration: biome_configuration, - directory_path: configuration_path, - .. - } = loaded_configuration; - - let should_use_editorconfig = formatter_configuration - .as_ref() - .and_then(|c| c.use_editorconfig) - .unwrap_or(biome_configuration.use_editorconfig().unwrap_or_default()); - let mut fs_configuration = if should_use_editorconfig { - let (editorconfig, editorconfig_diagnostics) = { - let search_path = editorconfig_search_path.unwrap_or_else(|| { - let fs = &session.app.fs; - fs.working_directory().unwrap_or_default() - }); - load_editorconfig(&session.app.fs, search_path)? +impl CommandRunner for FormatCommandPayload { + const COMMAND_NAME: &'static str = "format"; + + fn merge_configuration( + &mut self, + loaded_configuration: LoadedConfiguration, + fs: &DynRef<'_, dyn FileSystem>, + console: &mut dyn Console, + ) -> Result { + let LoadedConfiguration { + configuration: biome_configuration, + directory_path: configuration_path, + .. + } = loaded_configuration; + let editorconfig_search_path = configuration_path.clone(); + let should_use_editorconfig = self + .formatter_configuration + .as_ref() + .and_then(|c| c.use_editorconfig) + .unwrap_or(biome_configuration.use_editorconfig().unwrap_or_default()); + let mut fs_configuration = if should_use_editorconfig { + let (editorconfig, editorconfig_diagnostics) = { + let search_path = editorconfig_search_path + .unwrap_or_else(|| fs.working_directory().unwrap_or_default()); + load_editorconfig(fs, search_path)? + }; + for diagnostic in editorconfig_diagnostics { + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }) + } + editorconfig.unwrap_or_default() + } else { + Default::default() }; - for diagnostic in editorconfig_diagnostics { - session.app.console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }) - } - editorconfig.unwrap_or_default() - } else { - Default::default() - }; - // this makes biome configuration take precedence over editorconfig configuration - fs_configuration.merge_with(biome_configuration); - let mut configuration = fs_configuration; - - // TODO: remove in biome 2.0 - let console = &mut *session.app.console; - if let Some(config) = formatter_configuration.as_mut() { - if let Some(indent_size) = config.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--indent-size"" is deprecated, it will be removed in the next major release. Use ""--indent-width"" instead." - }); - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if config.indent_width.is_none() { - config.indent_width = Some(indent_size); + // this makes biome configuration take precedence over editorconfig configuration + fs_configuration.merge_with(biome_configuration); + let mut configuration = fs_configuration; + + // TODO: remove in biome 2.0 + if let Some(config) = self.formatter_configuration.as_mut() { + if let Some(indent_size) = config.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--indent-size"" is deprecated, it will be removed in the next major release. Use ""--indent-width"" instead." + }); + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if config.indent_width.is_none() { + config.indent_width = Some(indent_size); + } } } - } - // TODO: remove in biome 2.0 - if let Some(js_formatter) = javascript_formatter.as_mut() { - if let Some(indent_size) = js_formatter.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--javascript-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--javascript-formatter-indent-width"" instead." - }); - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); + // TODO: remove in biome 2.0 + if let Some(js_formatter) = self.javascript_formatter.as_mut() { + if let Some(indent_size) = js_formatter.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--javascript-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--javascript-formatter-indent-width"" instead." + }); + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if js_formatter.indent_width.is_none() { + js_formatter.indent_width = Some(indent_size); + } + } - if js_formatter.indent_width.is_none() { - js_formatter.indent_width = Some(indent_size); + if let Some(trailing_comma) = js_formatter.trailing_comma { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--trailing-comma"" is deprecated, it will be removed in the next major release. Use ""--trailing-commas"" instead." + }); + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if js_formatter.trailing_commas.is_none() { + js_formatter.trailing_commas = Some(trailing_comma); + } } } - - if let Some(trailing_comma) = js_formatter.trailing_comma { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--trailing-comma"" is deprecated, it will be removed in the next major release. Use ""--trailing-commas"" instead." - }); - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if js_formatter.trailing_commas.is_none() { - js_formatter.trailing_commas = Some(trailing_comma); + // TODO: remove in biome 2.0 + if let Some(json_formatter) = self.json_formatter.as_mut() { + if let Some(indent_size) = json_formatter.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--json-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--json-formatter-indent-width"" instead." + }); + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if json_formatter.indent_width.is_none() { + json_formatter.indent_width = Some(indent_size); + } } } - } - // TODO: remove in biome 2.0 - if let Some(json_formatter) = json_formatter.as_mut() { - if let Some(indent_size) = json_formatter.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--json-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--json-formatter-indent-width"" instead." - }); - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - if json_formatter.indent_width.is_none() { - json_formatter.indent_width = Some(indent_size); + // merge formatter options + if !configuration + .formatter + .as_ref() + .is_some_and(PartialFormatterConfiguration::is_disabled) + { + let formatter = configuration.formatter.get_or_insert_with(Default::default); + if let Some(formatter_configuration) = self.formatter_configuration.clone() { + formatter.merge_with(formatter_configuration); } + + formatter.enabled = Some(true); + } + if self.css_formatter.is_some() { + let css = configuration.css.get_or_insert_with(Default::default); + css.formatter.merge_with(self.css_formatter.clone()); + } + if self.graphql_formatter.is_some() { + let graphql = configuration.graphql.get_or_insert_with(Default::default); + graphql.formatter.merge_with(self.graphql_formatter.clone()); } - } - // merge formatter options - if !configuration - .formatter - .as_ref() - .is_some_and(PartialFormatterConfiguration::is_disabled) - { - let formatter = configuration.formatter.get_or_insert_with(Default::default); - if let Some(formatter_configuration) = formatter_configuration { - formatter.merge_with(formatter_configuration); + if self.javascript_formatter.is_some() { + let javascript = configuration + .javascript + .get_or_insert_with(Default::default); + javascript + .formatter + .merge_with(self.javascript_formatter.clone()); + } + if self.json_formatter.is_some() { + let json = configuration.json.get_or_insert_with(Default::default); + json.formatter.merge_with(self.json_formatter.clone()); } - formatter.enabled = Some(true); - } - if css_formatter.is_some() { - let css = configuration.css.get_or_insert_with(Default::default); - css.formatter.merge_with(css_formatter); - } - if graphql_formatter.is_some() { - let graphql = configuration.graphql.get_or_insert_with(Default::default); - graphql.formatter.merge_with(graphql_formatter); - } + configuration + .files + .merge_with(self.files_configuration.clone()); + configuration.vcs.merge_with(self.vcs_configuration.clone()); - if javascript_formatter.is_some() { - let javascript = configuration - .javascript - .get_or_insert_with(Default::default); - javascript.formatter.merge_with(javascript_formatter); + Ok(configuration) } - if json_formatter.is_some() { - let json = configuration.json.get_or_insert_with(Default::default); - json.formatter.merge_with(json_formatter); - } - - configuration.files.merge_with(files_configuration); - configuration.vcs.merge_with(vcs_configuration); - // check if support of git ignore files is enabled - let vcs_base_path = configuration_path.or(session.app.fs.working_directory()); - let (vcs_base_path, gitignore_matches) = - configuration.retrieve_gitignore_matches(&session.app.fs, vcs_base_path.as_deref())?; - - if let Some(_paths) = - get_files_to_process(since, changed, staged, &session.app.fs, &configuration)? - { - paths = _paths; + fn get_files_to_process( + &self, + fs: &DynRef<'_, dyn FileSystem>, + configuration: &PartialConfiguration, + ) -> Result, CliDiagnostic> { + if let Some(paths) = get_files_to_process( + self.since.as_deref(), + self.changed, + self.staged, + fs, + configuration, + )? { + Ok(paths) + } else { + Ok(self.paths.clone()) + } } - session - .app - .workspace - .register_project_folder(RegisterProjectFolderParams { - path: session.app.fs.working_directory(), - set_as_current_workspace: true, - })?; - - let manifest_data = resolve_manifest(&session.app.fs)?; - - if let Some(manifest_data) = manifest_data { - session - .app - .workspace - .set_manifest_for_project(manifest_data.into())?; + fn get_stdin_file_path(&self) -> Option<&String> { + self.stdin_file_path.as_ref() } - session - .app - .workspace - .update_settings(UpdateSettingsParams { - workspace_directory: session.app.fs.working_directory(), - configuration, - vcs_base_path, - gitignore_matches, - })?; - - let stdin = get_stdin(stdin_file_path, console, "format")?; - let execution = Execution::new(TraversalMode::Format { - ignore_errors: cli_options.skip_errors, - write: write || fix, - stdin, - vcs_targeted: VcsTargeted { staged, changed }, - }) - .set_report(&cli_options); + fn should_write(&self) -> bool { + self.write || self.fix + } - execute_mode(execution, session, &cli_options, paths) + fn get_execution( + &self, + cli_options: &CliOptions, + console: &mut dyn Console, + ) -> Result { + Ok(Execution::new(TraversalMode::Format { + ignore_errors: cli_options.skip_errors, + write: self.should_write(), + stdin: self.get_stdin(console)?, + vcs_targeted: VcsTargeted { + staged: self.staged, + changed: self.changed, + }, + }) + .set_report(cli_options)) + } } diff --git a/crates/biome_cli/src/commands/lint.rs b/crates/biome_cli/src/commands/lint.rs index 84ab59f0f440..6f4deec7861a 100644 --- a/crates/biome_cli/src/commands/lint.rs +++ b/crates/biome_cli/src/commands/lint.rs @@ -138,8 +138,13 @@ pub(crate) fn lint(session: CliSession, payload: LintCommandPayload) -> Result<( json.linter.merge_with(json_linter); } - let vcs_targeted_paths = - get_files_to_process(since, changed, staged, &session.app.fs, &fs_configuration)?; + let vcs_targeted_paths = get_files_to_process( + since.as_deref(), + changed, + staged, + &session.app.fs, + &fs_configuration, + )?; // check if support of git ignore files is enabled let vcs_base_path = configuration_path.or(session.app.fs.working_directory()); diff --git a/crates/biome_cli/src/commands/mod.rs b/crates/biome_cli/src/commands/mod.rs index 5e68992a2456..188bf7820769 100644 --- a/crates/biome_cli/src/commands/mod.rs +++ b/crates/biome_cli/src/commands/mod.rs @@ -3,7 +3,9 @@ use crate::cli_options::{cli_options, CliOptions, CliReporter, ColorsArg}; use crate::diagnostics::{DeprecatedArgument, DeprecatedConfigurationFile}; use crate::execute::Stdin; use crate::logging::LoggingKind; -use crate::{CliDiagnostic, LoggingLevel, VERSION}; +use crate::{ + execute_mode, setup_cli_subscriber, CliDiagnostic, CliSession, Execution, LoggingLevel, VERSION, +}; use biome_configuration::analyzer::RuleSelector; use biome_configuration::css::PartialCssLinter; use biome_configuration::javascript::PartialJavascriptLinter; @@ -22,10 +24,12 @@ use biome_configuration::{BiomeDiagnostic, PartialConfiguration}; use biome_console::{markup, Console, ConsoleExt}; use biome_diagnostics::{Diagnostic, PrintDiagnostic}; use biome_fs::{BiomePath, FileSystem}; -use biome_service::configuration::LoadedConfiguration; +use biome_service::configuration::{ + load_configuration, LoadedConfiguration, PartialConfigurationExt, +}; use biome_service::documentation::Doc; -use biome_service::workspace::FixFileMode; -use biome_service::{DynRef, WorkspaceError}; +use biome_service::workspace::{FixFileMode, RegisterProjectFolderParams, UpdateSettingsParams}; +use biome_service::{DynRef, Workspace, WorkspaceError}; use bpaf::Bpaf; use std::ffi::OsString; use std::path::PathBuf; @@ -692,7 +696,7 @@ pub(crate) fn get_stdin( } fn get_files_to_process( - since: Option, + since: Option<&str>, changed: bool, staged: bool, fs: &DynRef<'_, dyn FileSystem>, @@ -804,6 +808,139 @@ fn check_fix_incompatible_arguments(options: FixFileModeOptions) -> Result<(), C Ok(()) } +/// Generic interface for executing commands. +/// +/// Consumers must implement the following methods: +/// +/// - [CommandRunner::merge_configuration] +/// - [CommandRunner::get_files_to_process] +/// - [CommandRunner::get_stdin_file_path] +/// - [CommandRunner::should_write] +/// - [CommandRunner::get_execution] +/// +/// Optional methods: +/// - [CommandRunner::check_incompatible_arguments] +pub(crate) trait CommandRunner: Sized { + const COMMAND_NAME: &'static str; + + /// The main command to use. + fn run(&mut self, session: CliSession, cli_options: &CliOptions) -> Result<(), CliDiagnostic> { + setup_cli_subscriber(cli_options.log_level, cli_options.log_kind); + let fs = &session.app.fs; + let console = &mut *session.app.console; + let workspace = &*session.app.workspace; + self.check_incompatible_arguments()?; + let (execution, paths) = self.configure_workspace(fs, console, workspace, cli_options)?; + execute_mode(execution, session, cli_options, paths) + } + + /// This function prepares the workspace with the following: + /// - Loading the configuration file. + /// - Configure the VCS integration + /// - Computes the paths to traverse/handle. This changes based on the VCS arguments that were passed. + /// - Register a project folder using the working directory. + /// - Resolves the closets manifest AKA `package.json` and registers it. + /// - Updates the settings that belong to the project registered + fn configure_workspace( + &mut self, + fs: &DynRef<'_, dyn FileSystem>, + console: &mut dyn Console, + workspace: &dyn Workspace, + cli_options: &CliOptions, + ) -> Result<(Execution, Vec), CliDiagnostic> { + let loaded_configuration = + load_configuration(fs, cli_options.as_configuration_path_hint())?; + validate_configuration_diagnostics(&loaded_configuration, console, cli_options.verbose)?; + let configuration_path = loaded_configuration.directory_path.clone(); + let configuration = self.merge_configuration(loaded_configuration, fs, console)?; + let vcs_base_path = configuration_path.or(fs.working_directory()); + let (vcs_base_path, gitignore_matches) = + configuration.retrieve_gitignore_matches(fs, vcs_base_path.as_deref())?; + let paths = self.get_files_to_process(fs, &configuration)?; + workspace.register_project_folder(RegisterProjectFolderParams { + path: fs.working_directory(), + set_as_current_workspace: true, + })?; + + let manifest_data = resolve_manifest(fs)?; + + if let Some(manifest_data) = manifest_data { + workspace.set_manifest_for_project(manifest_data.into())?; + } + workspace.update_settings(UpdateSettingsParams { + workspace_directory: fs.working_directory(), + configuration, + vcs_base_path, + gitignore_matches, + })?; + + let execution = self.get_execution(cli_options, console)?; + Ok((execution, paths)) + } + + /// Computes [Stdin] if the CLI has the necessary information. + /// + /// ## Errors + /// - If the user didn't provide anything via `stdin` but the option `--stdin-file-path` is passed. + fn get_stdin(&self, console: &mut dyn Console) -> Result, CliDiagnostic> { + let stdin = if let Some(stdin_file_path) = self.get_stdin_file_path() { + let input_code = console.read(); + if let Some(input_code) = input_code { + let path = PathBuf::from(stdin_file_path); + Some((path, input_code).into()) + } else { + // we provided the argument without a piped stdin, we bail + return Err(CliDiagnostic::missing_argument("stdin", Self::COMMAND_NAME)); + } + } else { + None + }; + + Ok(stdin) + } + + // Below, the methods that consumers must implement. + + /// Implements this method if you need to merge CLI arguments to the loaded configuration. + /// + /// The CLI arguments take precedence over the option configured in the configuration file. + fn merge_configuration( + &mut self, + loaded_configuration: LoadedConfiguration, + fs: &DynRef<'_, dyn FileSystem>, + console: &mut dyn Console, + ) -> Result; + + /// It returns the paths that need to be handled/traversed. + fn get_files_to_process( + &self, + fs: &DynRef<'_, dyn FileSystem>, + configuration: &PartialConfiguration, + ) -> Result, CliDiagnostic>; + + /// It returns the file path to use in `stdin` mode. + fn get_stdin_file_path(&self) -> Option<&String>; + + /// Whether the command should write the files. + fn should_write(&self) -> bool; + + /// Returns the [Execution] mode. + fn get_execution( + &self, + cli_options: &CliOptions, + console: &mut dyn Console, + ) -> Result; + + // Below, methods that consumers can implement + + /// Optional method that can be implemented to check if some CLI arguments aren't compatible. + /// + /// The method is called before loading the configuration from disk. + fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { + Ok(()) + } +} + #[cfg(test)] mod tests { use biome_console::BufferConsole; diff --git a/crates/biome_cli/src/lib.rs b/crates/biome_cli/src/lib.rs index 653ebdc1d32f..88ebd8d09463 100644 --- a/crates/biome_cli/src/lib.rs +++ b/crates/biome_cli/src/lib.rs @@ -23,11 +23,12 @@ mod panic; mod reporter; mod service; -use crate::cli_options::ColorsArg; +use crate::cli_options::{CliOptions, ColorsArg}; use crate::commands::check::CheckCommandPayload; use crate::commands::ci::CiCommandPayload; use crate::commands::format::FormatCommandPayload; use crate::commands::lint::LintCommandPayload; +use crate::commands::CommandRunner; pub use crate::commands::{biome_command, BiomeCommand}; pub use crate::logging::{setup_cli_subscriber, LoggingLevel}; pub use diagnostics::CliDiagnostic; @@ -210,15 +211,15 @@ impl<'app> CliSession<'app> { staged, changed, since, - } => commands::format::format( + } => run_command( self, + &cli_options, FormatCommandPayload { javascript_formatter, formatter_configuration, stdin_file_path, write, fix, - cli_options, paths, vcs_configuration, files_configuration, @@ -291,3 +292,12 @@ pub fn to_color_mode(color: Option<&ColorsArg>) -> ColorMode { None => ColorMode::Auto, } } + +pub(crate) fn run_command( + session: CliSession, + cli_options: &CliOptions, + mut command: impl CommandRunner, +) -> Result<(), CliDiagnostic> { + let command = &mut command; + command.run(session, cli_options) +}