diff --git a/.changeset/modern-frogs-roll.md b/.changeset/modern-frogs-roll.md new file mode 100644 index 000000000000..a08739245bc6 --- /dev/null +++ b/.changeset/modern-frogs-roll.md @@ -0,0 +1,24 @@ +--- +"@biomejs/biome": minor +--- + +Rule's `options` is now optional in the Biome configuration files for rules with a `fix` kind. + +Previously, configuring a rule's `fix` required `options` to be set. +Now, `options` is optional. +The following configuration is now valid: + +```json +{ + "linter": { + "rules": { + "correctness": { + "noUnusedImports": { + "level": "on", + "fix": "safe" + } + } + } + } +} +``` diff --git a/crates/biome_cli/src/execute/migrate/eslint_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_to_biome.rs index 4529fa231b42..53af94217d1a 100644 --- a/crates/biome_cli/src/execute/migrate/eslint_to_biome.rs +++ b/crates/biome_cli/src/execute/migrate/eslint_to_biome.rs @@ -487,7 +487,7 @@ fn migrate_eslint_rule( biome_config::RuleWithFixOptions { level: severity.into(), fix: None, - options: *Box::new((*rule_options).into()), + options: Some(*Box::new((*rule_options).into())), }, )); } @@ -534,7 +534,7 @@ fn migrate_eslint_rule( biome_config::RuleWithFixOptions { level: severity.into(), fix: None, - options: *Box::new((*rule_options).into()), + options: Some(*Box::new((*rule_options).into())), }, )); } @@ -551,7 +551,7 @@ fn migrate_eslint_rule( biome_config::RuleWithFixOptions { level: severity.into(), fix: None, - options: rule_options.into(), + options: Some(rule_options.into()), }, )); } @@ -567,7 +567,7 @@ fn migrate_eslint_rule( biome_config::RuleWithFixOptions { level: severity.into(), fix: None, - options: rule_options.into(), + options: Some(rule_options.into()), }, )); } @@ -602,7 +602,7 @@ fn migrate_eslint_rule( biome_config::RuleWithFixOptions { level: severity.into(), fix: None, - options: options.into(), + options: Some(options.into()), }, )); } diff --git a/crates/biome_cli/tests/cases/config_extends.rs b/crates/biome_cli/tests/cases/config_extends.rs index 0688047c5d42..b4b520f6b041 100644 --- a/crates/biome_cli/tests/cases/config_extends.rs +++ b/crates/biome_cli/tests/cases/config_extends.rs @@ -550,3 +550,68 @@ fn extends_config_merge_overrides() { result, )); } + +#[test] +fn extends_config_rule_options_merge() { + let fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let shared = Utf8Path::new("shared.json"); + fs.insert( + shared.into(), + r#"{ + "linter": { + "enabled": true, + "rules": { + "correctness": { + "noUnusedVariables": { + "level": "on", + "options": { + "ignoreRestSiblings": false + } + } + } + } + } + }"#, + ); + + let biome_json = Utf8Path::new("biome.json"); + fs.insert( + biome_json.into(), + r#"{ + "extends": ["shared.json"], + "linter": { + "enabled": true, + "rules": { + "correctness": { + "noUnusedVariables": { + "level": "on", + "fix": "safe" + } + } + } + } + }"#, + ); + + let test_file = Utf8Path::new("test.js"); + fs.insert( + test_file.into(), + "const { a, ...rest } = { a: 1, b: 2}; export { rest }", + ); + + let (fs, result) = run_cli( + fs, + &mut console, + Args::from(["lint", test_file.as_str()].as_slice()), + ); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "extends_config_rule_options_merge", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/snapshots/main_cases_config_extends/extends_config_rule_options_merge.snap b/crates/biome_cli/tests/snapshots/main_cases_config_extends/extends_config_rule_options_merge.snap new file mode 100644 index 000000000000..d0375dc87ed3 --- /dev/null +++ b/crates/biome_cli/tests/snapshots/main_cases_config_extends/extends_config_rule_options_merge.snap @@ -0,0 +1,70 @@ +--- +source: crates/biome_cli/tests/snap_test.rs +expression: redactor(content) +--- +## `biome.json` + +```json +{ + "extends": ["shared.json"], + "linter": { + "enabled": true, + "rules": { + "correctness": { + "noUnusedVariables": { + "level": "on", + "fix": "safe" + } + } + } + } +} +``` + +## `shared.json` + +```json +{ + "linter": { + "enabled": true, + "rules": { + "correctness": { + "noUnusedVariables": { + "level": "on", + "options": { + "ignoreRestSiblings": false + } + } + } + } + } + } +``` + +## `test.js` + +```js +const { a, ...rest } = { a: 1, b: 2}; export { rest } +``` + +# Emitted Messages + +```block +test.js:1:9 lint/correctness/noUnusedVariables ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This variable a is unused. + + > 1 │ const { a, ...rest } = { a: 1, b: 2}; export { rest } + │ ^ + + i Unused variables are often the result of an incomplete refactoring, typos, or other sources of bugs. + + i You can use the ignoreRestSiblings option to ignore unused variables in an object destructuring with a spread. + + +``` + +```block +Checked 1 file in