diff --git a/CHANGELOG.md b/CHANGELOG.md index ccaab2474814..86ae800f3363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,15 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b ### CLI +#### Enhancements + +- Biome now executes commands (lint, format, check and ci) on the working directory by default. [#2266](https://github.com/biomejs/biome/issues/2266) Contributed by @unvalley + + ```diff + - biome check . + + biome check # You can run the command without the path + ``` + ### Configuration ### Editors diff --git a/crates/biome_cli/src/execute/traverse.rs b/crates/biome_cli/src/execute/traverse.rs index 6db15bff0649..f4e78e2ac30e 100644 --- a/crates/biome_cli/src/execute/traverse.rs +++ b/crates/biome_cli/src/execute/traverse.rs @@ -17,6 +17,7 @@ use crossbeam::channel::{unbounded, Receiver, Sender}; use rustc_hash::FxHashSet; use std::sync::atomic::AtomicU32; use std::{ + env::current_dir, ffi::OsString, panic::catch_unwind, path::{Path, PathBuf}, @@ -32,17 +33,28 @@ pub(crate) fn traverse( execution: &Execution, session: &mut CliSession, cli_options: &CliOptions, - inputs: Vec, + mut inputs: Vec, ) -> Result<(TraversalSummary, Vec), CliDiagnostic> { init_thread_pool(); - if inputs.is_empty() - && execution.as_stdin_file().is_none() - && !cli_options.no_errors_on_unmatched - { - return Err(CliDiagnostic::missing_argument( - "", - format!("{}", execution.traversal_mode), - )); + + if inputs.is_empty() { + match execution.traversal_mode { + TraversalMode::Check { .. } + | TraversalMode::Lint { .. } + | TraversalMode::Format { .. } + | TraversalMode::CI { .. } => match current_dir() { + Ok(current_dir) => inputs.push(current_dir.into_os_string()), + Err(err) => return Err(CliDiagnostic::io_error(err)), + }, + _ => { + if execution.as_stdin_file().is_none() && !cli_options.no_errors_on_unmatched { + return Err(CliDiagnostic::missing_argument( + "", + format!("{}", execution.traversal_mode), + )); + } + } + } } let (interner, recv_files) = PathInterner::new(); diff --git a/crates/biome_cli/tests/commands/check.rs b/crates/biome_cli/tests/commands/check.rs index 42c80ed85f0e..b59a6dcfcb39 100644 --- a/crates/biome_cli/tests/commands/check.rs +++ b/crates/biome_cli/tests/commands/check.rs @@ -2897,3 +2897,28 @@ fn print_json_pretty() { result, )); } + +#[test] +fn lint_error_without_file_paths() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("check.js"); + fs.insert(file_path.into(), LINT_ERROR.as_bytes()); + + let result: Result<(), biome_cli::CliDiagnostic> = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("check"), ""].as_slice()), + ); + + assert!(result.is_err(), "run_cli returned {result:?}"); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "lint_error_without_file_paths", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/commands/ci.rs b/crates/biome_cli/tests/commands/ci.rs index aea7cc6f96ea..f41bca32dcb8 100644 --- a/crates/biome_cli/tests/commands/ci.rs +++ b/crates/biome_cli/tests/commands/ci.rs @@ -1025,3 +1025,28 @@ A = 0; result, )); } + +#[test] +fn does_formatting_error_without_file_paths() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("ci.js"); + fs.insert(file_path.into(), UNFORMATTED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("ci"), ""].as_slice()), + ); + + assert!(result.is_err(), "run_cli returned {result:?}"); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_formatting_error_without_file_paths", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/commands/format.rs b/crates/biome_cli/tests/commands/format.rs index ef0e1dcbd5a2..1decf72ded5e 100644 --- a/crates/biome_cli/tests/commands/format.rs +++ b/crates/biome_cli/tests/commands/format.rs @@ -3585,3 +3585,30 @@ fn print_json_pretty() { result, )); } + +#[test] +fn format_without_file_paths() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("format.js"); + fs.insert(file_path.into(), UNFORMATTED.as_bytes()); + + let result: Result<(), biome_cli::CliDiagnostic> = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("format"), ""].as_slice()), + ); + + assert!(result.is_err(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, file_path, UNFORMATTED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "format_without_file_paths", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/commands/lint.rs b/crates/biome_cli/tests/commands/lint.rs index ba5253458dbe..e15a4b66e5ce 100644 --- a/crates/biome_cli/tests/commands/lint.rs +++ b/crates/biome_cli/tests/commands/lint.rs @@ -1966,7 +1966,7 @@ fn group_level_recommended_false_enable_specific() { let code = r#" function SubmitButton() { return ; - } + } "#; let file_path = Path::new("fix.jsx"); @@ -3246,3 +3246,28 @@ import "lodash"; result, )); } + +#[test] +fn should_lint_error_without_file_paths() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("check.js"); + fs.insert(file_path.into(), LINT_ERROR.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("lint"), ""].as_slice()), + ); + + assert!(result.is_err(), "run_cli returned {result:?}"); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "lint_error_without_file_paths", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/snapshots/main_commands_check/lint_error_without_file_paths.snap b/crates/biome_cli/tests/snapshots/main_commands_check/lint_error_without_file_paths.snap new file mode 100644 index 000000000000..2d4b249e7ddd --- /dev/null +++ b/crates/biome_cli/tests/snapshots/main_commands_check/lint_error_without_file_paths.snap @@ -0,0 +1,70 @@ +--- +source: crates/biome_cli/tests/snap_test.rs +expression: content +--- +## `check.js` + +```js +for(;true;); + +``` + +# Termination Message + +```block +check ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Some errors were emitted while running checks. + + + +``` + +# Emitted Messages + +```block +check.js:1:1 lint/style/useWhile FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Use a while loop instead of a for loop. + + > 1 │ for(;true;); + │ ^^^^^^^^^^^ + 2 │ + + i Prefer a while loop over a for loop without initialization and update. + + i Safe fix: Use a while loop. + + 1 │ - for(;true;); + 1 │ + while(true); + 2 2 │ + + +``` + +```block +check.js:1:6 lint/correctness/noConstantCondition ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected constant condition. + + > 1 │ for(;true;); + │ ^^^^ + 2 │ + + +``` + +```block +check.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Formatter would have printed the following content: + + 1 │ for·(;·true;·); + │ + + + + +``` + +```block +Checked 1 file in