diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a8b0befc9c..b9d5432d6f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -57,6 +57,20 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
Contributed by @Conaclos
+- Add new command `biome clean`. Use this command to purge all the logs emitted by the Biome daemon. This command is really useful, because the Biome daemon tends
+ log many files and contents during its lifecycle. This means that if your editor is open for hours (or even days), the `biome-logs` folder could become quite heavy. Contributed by @ematipico
+
+- Add support for formatting and linting CSS files from the CLI. These operations are **opt-in** for the time being.
+
+ If you don't have a configuration file, you can enable these features with `--css-formatter-enabled` and `--css-linter-enabled`:
+
+ ```shell
+ biome check --css-formatter-enabled=true --css-linter-enabled=true ./
+ ```
+ Contributed by @ematipico
+
+- Add new CLI options to control the CSS formatting. Check the [CLI reference page](https://biomejs.dev/reference/cli/) for more details. Contributed by @ematipico
+
#### 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
@@ -127,6 +141,11 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
Contributed by @Conaclos
+- Add option `javascript.linter.enabled` to control the linter for JavaScript (and its super languages) files. Contributed by @ematipico
+- Add option `json.linter.enabled` to control the linter for JSON (and its super languages) files. Contributed by @ematipico
+- Add option `css.linter.enabled` to control the linter for CSS (and its super languages) files. Contributed by @ematipico
+- Add option `css.formatter`, to control the formatter options for CSS (and its super languages) files. Contributed by @ematipico
+
#### Enhancements
- The `javascript.formatter.trailingComma` option is deprecated and renamed to `javascript.formatter.trailingCommas`. The corresponding CLI option `--trailing-comma` is also deprecated and renamed to `--trailing-commas`. Details can be checked in [#2492](https://github.com/biomejs/biome/pull/2492). Contributed by @Sec-ant
diff --git a/crates/biome_cli/Cargo.toml b/crates/biome_cli/Cargo.toml
index 7607ad1a707..0037c430ea6 100644
--- a/crates/biome_cli/Cargo.toml
+++ b/crates/biome_cli/Cargo.toml
@@ -74,8 +74,7 @@ regex = { workspace = true }
tokio = { workspace = true, features = ["io-util"] }
[features]
-docgen = ["bpaf/docgen"]
-format_css = ["biome_css_formatter/format_css"]
+docgen = ["bpaf/docgen"]
[lints]
workspace = true
diff --git a/crates/biome_cli/src/commands/format.rs b/crates/biome_cli/src/commands/format.rs
index 61577c7b412..093d1e7c221 100644
--- a/crates/biome_cli/src/commands/format.rs
+++ b/crates/biome_cli/src/commands/format.rs
@@ -51,7 +51,7 @@ pub(crate) fn format(
files_configuration,
write,
mut json_formatter,
- mut css_formatter,
+ css_formatter,
since,
staged,
changed,
@@ -130,27 +130,8 @@ pub(crate) fn format(
}
}
}
- // TODO: remove in biome 2.0
- if let Some(css_formatter) = css_formatter.as_mut() {
- if let Some(indent_size) = css_formatter.indent_size {
- let diagnostic = DeprecatedArgument::new(markup! {
- "The argument ""--css-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--css-formatter-indent-width"" instead."
- });
- console.error(markup! {
- {PrintDiagnostic::simple(&diagnostic)}
- });
- if css_formatter.indent_width.is_none() {
- css_formatter.indent_width = Some(indent_size);
- }
- }
- }
-
- if css_formatter.is_some() {
- let css = configuration.css.get_or_insert_with(Default::default);
- css.formatter.merge_with(css_formatter);
- }
- configuration.files.merge_with(files_configuration);
+ // merge formatter options
if !configuration
.formatter
.as_ref()
@@ -163,6 +144,10 @@ pub(crate) fn format(
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 javascript_formatter.is_some() {
let javascript = configuration
.javascript
@@ -173,6 +158,8 @@ pub(crate) fn format(
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
diff --git a/crates/biome_cli/src/commands/lint.rs b/crates/biome_cli/src/commands/lint.rs
index 035eef8992a..63c01697841 100644
--- a/crates/biome_cli/src/commands/lint.rs
+++ b/crates/biome_cli/src/commands/lint.rs
@@ -5,6 +5,9 @@ use crate::commands::{
use crate::{
execute_mode, setup_cli_subscriber, CliDiagnostic, CliSession, Execution, TraversalMode,
};
+use biome_configuration::css::PartialCssLinter;
+use biome_configuration::javascript::PartialJavascriptLinter;
+use biome_configuration::json::PartialJsonLinter;
use biome_configuration::linter::RuleSelector;
use biome_configuration::vcs::PartialVcsConfiguration;
use biome_configuration::{
@@ -30,6 +33,9 @@ pub(crate) struct LintCommandPayload {
pub(crate) staged: bool,
pub(crate) changed: bool,
pub(crate) since: Option,
+ pub(crate) javascript_linter: Option,
+ pub(crate) json_linter: Option,
+ pub(crate) css_linter: Option,
}
/// Handler for the "lint" command of the Biome CLI
@@ -47,6 +53,9 @@ pub(crate) fn lint(session: CliSession, payload: LintCommandPayload) -> Result<(
staged,
changed,
since,
+ javascript_linter,
+ css_linter,
+ json_linter,
} = payload;
setup_cli_subscriber(cli_options.log_level, cli_options.log_kind);
@@ -96,6 +105,21 @@ pub(crate) fn lint(session: CliSession, payload: LintCommandPayload) -> Result<(
..Default::default()
});
+ if css_linter.is_some() {
+ let css = fs_configuration.css.get_or_insert_with(Default::default);
+ css.linter.merge_with(css_linter);
+ }
+ if javascript_linter.is_some() {
+ let javascript = fs_configuration
+ .javascript
+ .get_or_insert_with(Default::default);
+ javascript.linter.merge_with(javascript_linter);
+ }
+ if json_linter.is_some() {
+ let json = fs_configuration.json.get_or_insert_with(Default::default);
+ json.linter.merge_with(json_linter);
+ }
+
// 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) =
diff --git a/crates/biome_cli/src/commands/mod.rs b/crates/biome_cli/src/commands/mod.rs
index d0d9ad9b33f..87ef0a02e96 100644
--- a/crates/biome_cli/src/commands/mod.rs
+++ b/crates/biome_cli/src/commands/mod.rs
@@ -4,14 +4,17 @@ use crate::diagnostics::DeprecatedConfigurationFile;
use crate::execute::Stdin;
use crate::logging::LoggingKind;
use crate::{CliDiagnostic, CliSession, LoggingLevel, VERSION};
+use biome_configuration::css::PartialCssLinter;
+use biome_configuration::javascript::PartialJavascriptLinter;
+use biome_configuration::json::PartialJsonLinter;
use biome_configuration::linter::RuleSelector;
use biome_configuration::{
- css::partial_css_formatter, javascript::partial_javascript_formatter,
- json::partial_json_formatter, partial_configuration, partial_files_configuration,
- partial_formatter_configuration, partial_linter_configuration, vcs::partial_vcs_configuration,
- vcs::PartialVcsConfiguration, PartialCssFormatter, PartialFilesConfiguration,
- PartialFormatterConfiguration, PartialJavascriptFormatter, PartialJsonFormatter,
- PartialLinterConfiguration,
+ css::partial_css_formatter, css::partial_css_linter, javascript::partial_javascript_formatter,
+ javascript::partial_javascript_linter, json::partial_json_formatter, json::partial_json_linter,
+ partial_configuration, partial_files_configuration, partial_formatter_configuration,
+ partial_linter_configuration, vcs::partial_vcs_configuration, vcs::PartialVcsConfiguration,
+ PartialCssFormatter, PartialFilesConfiguration, PartialFormatterConfiguration,
+ PartialJavascriptFormatter, PartialJsonFormatter, PartialLinterConfiguration,
};
use biome_configuration::{ConfigurationDiagnostic, PartialConfiguration};
use biome_console::{markup, Console, ConsoleExt};
@@ -150,6 +153,15 @@ pub enum BiomeCommand {
#[bpaf(external(partial_files_configuration), optional, hide_usage)]
files_configuration: Option,
+ #[bpaf(external(partial_javascript_linter), optional, hide_usage)]
+ javascript_linter: Option,
+
+ #[bpaf(external(partial_json_linter), optional, hide_usage)]
+ json_linter: Option,
+
+ #[bpaf(external(partial_css_linter), optional, hide_usage, hide)]
+ css_linter: Option,
+
#[bpaf(external, hide_usage)]
cli_options: CliOptions,
diff --git a/crates/biome_cli/src/commands/rage.rs b/crates/biome_cli/src/commands/rage.rs
index 7d3edd44e9c..410c1704710 100644
--- a/crates/biome_cli/src/commands/rage.rs
+++ b/crates/biome_cli/src/commands/rage.rs
@@ -256,6 +256,18 @@ impl Display for RageConfiguration<'_, '_> {
{KeyValuePair("Line width", markup!({DebugDisplayOption(json_formatter_configuration.line_width.map(|lw| lw.get()))}))}
{KeyValuePair("Trailing Commas", markup!({DebugDisplayOption(json_formatter_configuration.trailing_commas)}))}
).fmt(fmt)?;
+
+ let css_formatter_configuration =
+ configuration.get_css_formatter_configuration();
+ markup! (
+ {Section("CSS Formatter")}
+ {KeyValuePair("Enabled", markup!({DebugDisplay(css_formatter_configuration.enabled)}))}
+ {KeyValuePair("Indent style", markup!({DebugDisplay(css_formatter_configuration.indent_style)}))}
+ {KeyValuePair("Indent width", markup!({DebugDisplay(css_formatter_configuration.indent_width)}))}
+ {KeyValuePair("Line ending", markup!({DebugDisplay(css_formatter_configuration.line_ending)}))}
+ {KeyValuePair("Line width", markup!({DebugDisplay(css_formatter_configuration.line_width)}))}
+ {KeyValuePair("Quote style", markup!({DebugDisplay(css_formatter_configuration.quote_style)}))}
+ ).fmt(fmt)?;
}
// Print linter configuration if --linter option is true
@@ -263,8 +275,8 @@ impl Display for RageConfiguration<'_, '_> {
let linter_configuration = configuration.get_linter_rules();
markup! (
{Section("Linter")}
- {KeyValuePair("Recommended", markup!({DebugDisplay(linter_configuration.recommended.unwrap_or(false))}))}
- {KeyValuePair("All", markup!({DebugDisplay(linter_configuration.all.unwrap_or(false))}))}
+ {KeyValuePair("Recommended", markup!({DebugDisplay(linter_configuration.recommended.unwrap_or_default())}))}
+ {KeyValuePair("All", markup!({DebugDisplay(linter_configuration.all.unwrap_or_default())}))}
{RageConfigurationLintRules("Rules",linter_configuration)}
).fmt(fmt)?;
}
diff --git a/crates/biome_cli/src/lib.rs b/crates/biome_cli/src/lib.rs
index 384f93c3bcc..f17171e8b19 100644
--- a/crates/biome_cli/src/lib.rs
+++ b/crates/biome_cli/src/lib.rs
@@ -122,6 +122,9 @@ impl<'app> CliSession<'app> {
staged,
changed,
since,
+ css_linter,
+ javascript_linter,
+ json_linter,
} => commands::lint::lint(
self,
LintCommandPayload {
@@ -137,6 +140,9 @@ impl<'app> CliSession<'app> {
staged,
changed,
since,
+ css_linter,
+ javascript_linter,
+ json_linter,
},
),
BiomeCommand::Ci {
diff --git a/crates/biome_cli/tests/cases/handle_css_files.rs b/crates/biome_cli/tests/cases/handle_css_files.rs
new file mode 100644
index 00000000000..ff0025fc8c5
--- /dev/null
+++ b/crates/biome_cli/tests/cases/handle_css_files.rs
@@ -0,0 +1,183 @@
+use crate::run_cli;
+use crate::snap_test::{assert_cli_snapshot, SnapshotPayload};
+use biome_console::BufferConsole;
+use biome_fs::MemoryFileSystem;
+use biome_service::DynRef;
+use bpaf::Args;
+use std::path::Path;
+
+#[test]
+fn should_not_format_files_by_default() {
+ let mut fs = MemoryFileSystem::default();
+ let mut console = BufferConsole::default();
+
+ let css_file_content = r#"html {}"#;
+ let css_file = Path::new("input.css");
+ fs.insert(css_file.into(), css_file_content.as_bytes());
+
+ let result = run_cli(
+ DynRef::Borrowed(&mut fs),
+ &mut console,
+ Args::from([("format"), css_file.as_os_str().to_str().unwrap()].as_slice()),
+ );
+
+ // no files processed error
+ assert!(result.is_err(), "run_cli returned {result:?}");
+
+ assert_cli_snapshot(SnapshotPayload::new(
+ module_path!(),
+ "should_not_format_files_by_default",
+ fs,
+ console,
+ result,
+ ));
+}
+
+#[test]
+fn should_format_files_by_when_opt_in() {
+ let mut fs = MemoryFileSystem::default();
+ let mut console = BufferConsole::default();
+
+ let css_file_content = r#"html {}"#;
+ let css_file = Path::new("input.css");
+ fs.insert(css_file.into(), css_file_content.as_bytes());
+
+ let result = run_cli(
+ DynRef::Borrowed(&mut fs),
+ &mut console,
+ Args::from(
+ [
+ "format",
+ "--css-formatter-enabled=true",
+ css_file.as_os_str().to_str().unwrap(),
+ ]
+ .as_slice(),
+ ),
+ );
+
+ // not formatted error
+ assert!(result.is_err(), "run_cli returned {result:?}");
+
+ assert_cli_snapshot(SnapshotPayload::new(
+ module_path!(),
+ "should_format_files_by_when_opt_in",
+ fs,
+ console,
+ result,
+ ));
+}
+
+#[test]
+fn should_format_write_files_by_when_opt_in() {
+ let mut fs = MemoryFileSystem::default();
+ let mut console = BufferConsole::default();
+
+ let css_file_content = r#"html {}"#;
+ let css_file = Path::new("input.css");
+ fs.insert(css_file.into(), css_file_content.as_bytes());
+
+ let result = run_cli(
+ DynRef::Borrowed(&mut fs),
+ &mut console,
+ Args::from(
+ [
+ "format",
+ "--write",
+ "--css-formatter-enabled=true",
+ css_file.as_os_str().to_str().unwrap(),
+ ]
+ .as_slice(),
+ ),
+ );
+
+ assert!(result.is_ok(), "run_cli returned {result:?}");
+
+ assert_cli_snapshot(SnapshotPayload::new(
+ module_path!(),
+ "should_format_write_files_by_when_opt_in",
+ fs,
+ console,
+ result,
+ ));
+}
+
+#[test]
+fn should_not_lint_files_by_default() {
+ let mut fs = MemoryFileSystem::default();
+ let mut console = BufferConsole::default();
+
+ let file_path = Path::new("biome.json");
+ fs.insert(
+ file_path.into(),
+ r#"{
+ "linter": { "rules": { "all": true } }
+}
+"#
+ .as_bytes(),
+ );
+
+ let css_file_content = r#"html {}"#;
+ let css_file = Path::new("input.css");
+ fs.insert(css_file.into(), css_file_content.as_bytes());
+
+ let result = run_cli(
+ DynRef::Borrowed(&mut fs),
+ &mut console,
+ Args::from(["lint", css_file.as_os_str().to_str().unwrap()].as_slice()),
+ );
+
+ // no files processed error
+ assert!(result.is_err(), "run_cli returned {result:?}");
+
+ assert_cli_snapshot(SnapshotPayload::new(
+ module_path!(),
+ "should_not_lint_files_by_default",
+ fs,
+ console,
+ result,
+ ));
+}
+
+#[test]
+fn should_lint_files_by_when_enabled() {
+ let mut fs = MemoryFileSystem::default();
+ let mut console = BufferConsole::default();
+
+ let file_path = Path::new("biome.json");
+ fs.insert(
+ file_path.into(),
+ r#"{
+ "linter": { "rules": { "all": true } }
+}
+"#
+ .as_bytes(),
+ );
+
+ let css_file_content = r#"html {}"#;
+ let css_file = Path::new("input.css");
+ fs.insert(css_file.into(), css_file_content.as_bytes());
+
+ let result = run_cli(
+ DynRef::Borrowed(&mut fs),
+ &mut console,
+ Args::from(
+ [
+ "lint",
+ "--css-linter-enabled=true",
+ css_file.as_os_str().to_str().unwrap(),
+ ]
+ .as_slice(),
+ ),
+ );
+
+ // diagnostic
+ assert!(result.is_err(), "run_cli returned {result:?}");
+
+ assert_cli_snapshot(SnapshotPayload::new(
+ module_path!(),
+ "should_lint_files_by_when_enabled",
+ fs,
+ console,
+ result,
+ ));
+}
diff --git a/crates/biome_cli/tests/cases/mod.rs b/crates/biome_cli/tests/cases/mod.rs
index 0c086ce1cc3..7469794861f 100644
--- a/crates/biome_cli/tests/cases/mod.rs
+++ b/crates/biome_cli/tests/cases/mod.rs
@@ -7,6 +7,7 @@ mod config_path;
mod cts_files;
mod diagnostics;
mod handle_astro_files;
+mod handle_css_files;
mod handle_svelte_files;
mod handle_vue_files;
mod included_files;
diff --git a/crates/biome_cli/tests/commands/format.rs b/crates/biome_cli/tests/commands/format.rs
index f0f6b0f0aa7..a1278472aaf 100644
--- a/crates/biome_cli/tests/commands/format.rs
+++ b/crates/biome_cli/tests/commands/format.rs
@@ -2631,8 +2631,9 @@ fn should_apply_different_formatting() {
},
"css": {
"formatter": {
+ "enabled": true,
"lineWidth": 40,
- "indentSize": 6
+ "indentWidth": 6
}
}
}"#,
@@ -2730,7 +2731,8 @@ const a = {
"--json-formatter-line-width=20",
"--json-formatter-indent-size=2",
"--css-formatter-line-width=40",
- "--css-formatter-indent-size=6",
+ "--css-formatter-indent-width=6",
+ "--css-formatter-enabled=true",
json_file.as_os_str().to_str().unwrap(),
js_file.as_os_str().to_str().unwrap(),
css_file.as_os_str().to_str().unwrap(),
diff --git a/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_format_files_by_when_opt_in.snap b/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_format_files_by_when_opt_in.snap
new file mode 100644
index 00000000000..169f83e7f52
--- /dev/null
+++ b/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_format_files_by_when_opt_in.snap
@@ -0,0 +1,40 @@
+---
+source: crates/biome_cli/tests/snap_test.rs
+expression: content
+---
+## `input.css`
+
+```css
+html {}
+```
+
+# Termination Message
+
+```block
+format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+ × Some errors were emitted while running checks.
+
+
+
+```
+
+# Emitted Messages
+
+```block
+input.css format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+ × Formatter would have printed the following content:
+
+ 1 │ - html·{}
+ 1 │ + html·{
+ 2 │ + }
+ 3 │ +
+
+
+```
+
+```block
+Checked 1 file in