From 9e21f508ae0da058bbf08a62186b443a455c25b1 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 18 Oct 2023 16:29:06 +0100 Subject: [PATCH] feat(project): add overrides (#493) --- Cargo.lock | 15 +- crates/biome_cli/tests/cases/mod.rs | 3 + .../tests/cases/overrides_formatter.rs | 399 ++++++++++++++++ .../biome_cli/tests/cases/overrides_linter.rs | 318 +++++++++++++ .../tests/cases/overrides_organize_imports.rs | 120 +++++ crates/biome_cli/tests/snap_test.rs | 15 +- .../does_handle_included_file.snap | 35 ++ ...nclude_file_with_different_formatting.snap | 36 ++ ..._formatting_and_applies_the_first_one.snap | 39 ++ ...include_file_with_different_languages.snap | 44 ++ ...le_with_different_languages_and_files.snap | 76 +++ ...include_file_with_different_overrides.snap | 45 ++ .../does_not_handle_ignored_file.snap | 35 ++ .../does_handle_included_file.snap | 34 ++ ..._formatting_and_applies_the_first_one.snap | 52 +++ ...include_file_with_different_overrides.snap | 52 +++ ...oes_include_file_with_different_rules.snap | 40 ++ .../does_not_handle_ignored_file.snap | 34 ++ .../does_handle_included_file.snap | 36 ++ .../does_not_handle_ignored_file.snap | 36 ++ .../no_excessive_cognitive_complexity.rs | 2 +- crates/biome_js_analyze/src/options.rs | 2 +- .../use_exhaustive_dependencies.rs | 4 +- .../style/no_restricted_globals.rs | 2 +- crates/biome_json_formatter/src/context.rs | 12 +- crates/biome_json_syntax/src/file_source.rs | 6 +- crates/biome_service/Cargo.toml | 1 + .../src/configuration/formatter.rs | 73 ++- .../src/configuration/linter/mod.rs | 63 +-- .../src/configuration/linter/rules.rs | 18 +- crates/biome_service/src/configuration/mod.rs | 109 ++--- .../src/configuration/organize_imports.rs | 63 +-- .../src/configuration/overrides.rs | 441 ++++++++++++++++++ .../configuration/parse/json/configuration.rs | 6 + .../src/configuration/parse/json/linter.rs | 1 + .../src/configuration/parse/json/mod.rs | 1 + .../src/configuration/parse/json/overrides.rs | 221 +++++++++ .../src/file_handlers/javascript.rs | 104 ++--- .../biome_service/src/file_handlers/json.rs | 61 +-- crates/biome_service/src/file_handlers/mod.rs | 1 + crates/biome_service/src/settings.rs | 398 ++++++++++++---- crates/biome_service/src/workspace/server.rs | 53 ++- .../invalid/overrides/incorrect_key.json | 7 + .../invalid/overrides/incorrect_key.json.snap | 27 ++ .../invalid/overrides/incorrect_type.json | 3 + .../overrides/incorrect_type.json.snap | 16 + .../overrides/incorrect_value_javascript.json | 7 + .../incorrect_value_javascript.json.snap | 17 + .../top_level_extraneous_field.json.snap | 1 + crates/biome_service/tests/spec_tests.rs | 4 +- .../tests/valid/overrides/top_level_keys.json | 10 + crates/biome_service/tests/valid/test.json | 4 + crates/biome_test_utils/src/lib.rs | 10 +- crates/tests_macros/Cargo.toml | 2 +- editors/vscode/configuration_schema.json | 123 +++++ justfile | 1 + .../@biomejs/backend-jsonrpc/src/workspace.ts | 76 +++ .../@biomejs/biome/configuration_schema.json | 123 +++++ xtask/codegen/src/generate_configuration.rs | 4 +- 59 files changed, 3120 insertions(+), 421 deletions(-) create mode 100644 crates/biome_cli/tests/cases/overrides_formatter.rs create mode 100644 crates/biome_cli/tests/cases/overrides_linter.rs create mode 100644 crates/biome_cli/tests/cases/overrides_organize_imports.rs create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_handle_included_file.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_include_file_with_different_formatting.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_include_file_with_different_formatting_and_applies_the_first_one.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_include_file_with_different_languages.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_include_file_with_different_languages_and_files.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_include_file_with_different_overrides.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_not_handle_ignored_file.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_linter/does_handle_included_file.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_linter/does_include_file_with_different_formatting_and_applies_the_first_one.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_linter/does_include_file_with_different_overrides.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_linter/does_include_file_with_different_rules.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_linter/does_not_handle_ignored_file.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_organize_imports/does_handle_included_file.snap create mode 100644 crates/biome_cli/tests/snapshots/main_cases_overrides_organize_imports/does_not_handle_ignored_file.snap create mode 100644 crates/biome_service/src/configuration/overrides.rs create mode 100644 crates/biome_service/src/configuration/parse/json/overrides.rs create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_key.json create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_key.json.snap create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_type.json create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_type.json.snap create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json create mode 100644 crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json.snap create mode 100644 crates/biome_service/tests/valid/overrides/top_level_keys.json create mode 100644 crates/biome_service/tests/valid/test.json diff --git a/Cargo.lock b/Cargo.lock index 0237c55f372d..87f3e7c1b05c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,6 +704,7 @@ dependencies = [ "dashmap", "indexmap", "insta", + "lazy_static", "rustc-hash", "schemars", "serde", @@ -826,7 +827,7 @@ checksum = "22cbaba260bbcbb69b0d54e9f0d83038a4568f3a5d1c95591fed5e8fee964539" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.38", ] [[package]] @@ -2142,9 +2143,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -2589,7 +2590,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.38", ] [[package]] @@ -2744,9 +2745,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -2794,7 +2795,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", ] [[package]] diff --git a/crates/biome_cli/tests/cases/mod.rs b/crates/biome_cli/tests/cases/mod.rs index 6d88fdda6910..b73d611f259b 100644 --- a/crates/biome_cli/tests/cases/mod.rs +++ b/crates/biome_cli/tests/cases/mod.rs @@ -4,3 +4,6 @@ mod biome_json_support; mod config_extends; mod included_files; +mod overrides_formatter; +mod overrides_linter; +mod overrides_organize_imports; diff --git a/crates/biome_cli/tests/cases/overrides_formatter.rs b/crates/biome_cli/tests/cases/overrides_formatter.rs new file mode 100644 index 000000000000..e6ea85f890c1 --- /dev/null +++ b/crates/biome_cli/tests/cases/overrides_formatter.rs @@ -0,0 +1,399 @@ +use crate::run_cli; +use crate::snap_test::{assert_cli_snapshot, assert_file_contents, SnapshotPayload}; +use biome_console::BufferConsole; +use biome_fs::MemoryFileSystem; +use biome_service::DynRef; +use bpaf::Args; +use std::path::Path; + +const UNFORMATTED: &str = " statement( ) "; +const UNFORMATTED_JSON: &str = r#"{ "asta": ["lorem", "ipsum", "first", "second"] }"#; +const FORMATTED_JSON: &str = + "{\n \"asta\": [\n \"lorem\",\n \"ipsum\",\n \"first\",\n \"second\"\n ]\n}\n"; + +const UNFORMATTED_LINE_WIDTH: &str = r#"const a = ["loreum", "ipsum"]"#; +const FORMATTED: &str = "statement();\n"; +const FORMATTED_LINE_WIDTH_OVERRIDDEN: &str = "const a = [\n\t\"loreum\",\n\t\"ipsum\",\n];\n"; + +const FORMATTED_LINE_WITH_SPACES: &str = "const a = [\n \"loreum\",\n \"ipsum\",\n];\n"; + +const FORMATTED_LINE_WIDTH: &str = "const a = [\"loreum\", \"ipsum\"];\n"; + +const FORMATTED_WITH_SINGLE_QUOTES: &str = "const a = ['loreum', 'ipsum'];\n"; +const FORMATTED_WITH_NO_SEMICOLONS: &str = "const a = [\"loreum\", \"ipsum\"]\n"; + +#[test] +fn does_not_handle_ignored_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "include": ["test.js", "special/**"] + }, + "overrides": [{ "ignore": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNFORMATTED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, UNFORMATTED); + assert_file_contents(&fs, test, FORMATTED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_not_handle_ignored_file", + fs, + console, + result, + )); +} + +#[test] +fn does_handle_included_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "ignore": ["test.js", "special/**"] + }, + "overrides": [{ "include": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNFORMATTED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, FORMATTED); + assert_file_contents(&fs, test, UNFORMATTED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_handle_included_file", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_formatting() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [{ "include": ["special/**"], "formatter": { "lineWidth": 20 } }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, FORMATTED_LINE_WIDTH_OVERRIDDEN); + assert_file_contents(&fs, test, FORMATTED_LINE_WIDTH); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_formatting", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_formatting_and_applies_the_first_one() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { "include": ["special/**"], "formatter": { "lineWidth": 20 } }, + { "include": ["special/**"], "formatter": { "lineWidth": 130 } } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, FORMATTED_LINE_WIDTH_OVERRIDDEN); + assert_file_contents(&fs, test, FORMATTED_LINE_WIDTH); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_formatting_and_applies_the_first_one", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_overrides() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { "include": ["test.js"], "formatter": { "lineWidth": 20 } }, + { "include": ["test2.js"], "formatter": { "lineWidth": 20, "indentStyle": "space" } } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let test2 = Path::new("test2.js"); + fs.insert(test2.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test, FORMATTED_LINE_WIDTH_OVERRIDDEN); + assert_file_contents(&fs, test2, FORMATTED_LINE_WITH_SPACES); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_overrides", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_languages() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { "include": ["test.js"], "formatter": { "lineWidth": 120 }, "javascript": { "formatter": { "quoteStyle": "single" } } }, + { "include": ["test2.js"], "formatter": { "lineWidth": 120, "indentStyle": "space" }, "javascript": { "formatter": { "semicolons": "asNeeded" } } } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let test2 = Path::new("test2.js"); + fs.insert(test2.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test, FORMATTED_WITH_SINGLE_QUOTES); + assert_file_contents(&fs, test2, FORMATTED_WITH_NO_SEMICOLONS); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_languages", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_languages_and_files() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { "include": ["test.js"], "formatter": { "lineWidth": 120 }, "javascript": { "formatter": { "quoteStyle": "single" } } }, + { + "include": ["test2.js"], + "formatter": { "lineWidth": 120, "indentStyle": "space" }, + "javascript": { "formatter": { "semicolons": "asNeeded" } }, + "json": { "formatter": { "indentStyle": "space", "lineWidth": 20, "indentWidth": 4 } } + }, + { + "include": ["test3.json"], + "formatter": { "lineWidth": 120, "indentStyle": "space" }, + "json": { "formatter": { "indentStyle": "space", "lineWidth": 20, "indentWidth": 4 } } + } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let test2 = Path::new("test2.js"); + fs.insert(test2.into(), UNFORMATTED_LINE_WIDTH.as_bytes()); + + let json_file = Path::new("test3.json"); + fs.insert(json_file.into(), UNFORMATTED_JSON.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + ("--write"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + json_file.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test, FORMATTED_WITH_SINGLE_QUOTES); + assert_file_contents(&fs, test2, FORMATTED_WITH_NO_SEMICOLONS); + assert_file_contents(&fs, json_file, FORMATTED_JSON); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_languages_and_files", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/cases/overrides_linter.rs b/crates/biome_cli/tests/cases/overrides_linter.rs new file mode 100644 index 000000000000..9cdd6f1dcc0e --- /dev/null +++ b/crates/biome_cli/tests/cases/overrides_linter.rs @@ -0,0 +1,318 @@ +use crate::run_cli; +use crate::snap_test::{assert_cli_snapshot, assert_file_contents, SnapshotPayload}; +use biome_console::BufferConsole; +use biome_fs::MemoryFileSystem; +use biome_service::DynRef; +use bpaf::Args; +use std::path::Path; + +const FIX_BEFORE: &str = "(1 >= -0)"; +const FIX_AFTER: &str = "(1 >= 0)"; + +const DEBUGGER_BEFORE: &str = "debugger"; +const DEBUGGER_AFTER: &str = ""; + +const SIMPLE_NUMBERS_BEFORE: &str = "({ 0x1: 1 });"; +const SIMPLE_NUMBERS_AFTER: &str = "({ 1: 1 });"; +#[test] +fn does_not_handle_ignored_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "include": ["test.js", "special/**"] + }, + "overrides": [{ "ignore": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), FIX_BEFORE.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), FIX_BEFORE.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + ("--apply"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, FIX_BEFORE); + assert_file_contents(&fs, test, FIX_AFTER); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_not_handle_ignored_file", + fs, + console, + result, + )); +} + +#[test] +fn does_handle_included_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "ignore": ["test.js", "special/**"] + }, + "overrides": [{ "include": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), FIX_BEFORE.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), FIX_BEFORE.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + ("--apply"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, FIX_AFTER); + assert_file_contents(&fs, test, FIX_BEFORE); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_handle_included_file", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_rules() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [{ "include": ["special/**"], "linter": { "rules": { + "suspicious": { "noDebugger": "off" } + } } }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), DEBUGGER_BEFORE.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), DEBUGGER_BEFORE.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + ("--apply-unsafe"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, DEBUGGER_BEFORE); + assert_file_contents(&fs, test, DEBUGGER_AFTER); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_rules", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_linting_and_applies_the_first_one() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { + "include": [ + "special/**" + ], + "linter": { + "rules": { + "suspicious": { + "noDebugger": "off" + } + } + } + }, + { + "include": [ + "special/**" + ], + "linter": { + "rules": { + "suspicious": { + "noDebugger": "error" + } + } + } + } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), DEBUGGER_BEFORE.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), DEBUGGER_BEFORE.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + ("--apply-unsafe"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, DEBUGGER_BEFORE); + assert_file_contents(&fs, test, DEBUGGER_AFTER); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_formatting_and_applies_the_first_one", + fs, + console, + result, + )); +} + +#[test] +fn does_include_file_with_different_overrides() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "overrides": [ + { + "include": [ + "test.js" + ], + "linter": { + "rules": { + "suspicious": { + "noDebugger": "off" + } + } + } + }, + { + "include": [ + "test2.js" + ], + "linter": { + "rules": { + "complexity": { + "useSimpleNumberKeys": "error" + } + } + } + } + ] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), DEBUGGER_BEFORE.as_bytes()); + + let test2 = Path::new("test2.js"); + fs.insert(test2.into(), SIMPLE_NUMBERS_BEFORE.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + ("--apply-unsafe"), + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test, DEBUGGER_BEFORE); + assert_file_contents(&fs, test2, SIMPLE_NUMBERS_AFTER); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_include_file_with_different_overrides", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/cases/overrides_organize_imports.rs b/crates/biome_cli/tests/cases/overrides_organize_imports.rs new file mode 100644 index 000000000000..5aba6238ed98 --- /dev/null +++ b/crates/biome_cli/tests/cases/overrides_organize_imports.rs @@ -0,0 +1,120 @@ +use crate::run_cli; +use crate::snap_test::{assert_cli_snapshot, assert_file_contents, SnapshotPayload}; +use biome_console::BufferConsole; +use biome_fs::MemoryFileSystem; +use biome_service::DynRef; +use bpaf::Args; +use std::path::Path; + +const UNORGANIZED: &str = r#"import * as something from "../something"; +import { lorem, foom, bar } from "foo";"#; +const ORGANIZED: &str = r#"import { bar, foom, lorem } from "foo"; +import * as something from "../something";"#; + +#[test] +fn does_not_handle_ignored_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "include": ["test.js", "special/**"] + }, + "overrides": [{ "ignore": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNORGANIZED.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNORGANIZED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("check"), + ("--apply"), + "--formatter-enabled=false", + "--linter-enabled=false", + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, UNORGANIZED); + assert_file_contents(&fs, test, ORGANIZED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_not_handle_ignored_file", + fs, + console, + result, + )); +} + +#[test] +fn does_handle_included_file() { + let mut console = BufferConsole::default(); + let mut fs = MemoryFileSystem::default(); + let file_path = Path::new("biome.json"); + fs.insert( + file_path.into(), + r#"{ + "files": { + "ignore": ["test.js", "special/**"] + }, + "overrides": [{ "include": ["special/**"] }] +} + +"# + .as_bytes(), + ); + + let test = Path::new("test.js"); + fs.insert(test.into(), UNORGANIZED.as_bytes()); + + let test2 = Path::new("special/test2.js"); + fs.insert(test2.into(), UNORGANIZED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("check"), + ("--apply"), + "--formatter-enabled=false", + "--linter-enabled=false", + test.as_os_str().to_str().unwrap(), + test2.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, test2, ORGANIZED); + assert_file_contents(&fs, test, UNORGANIZED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "does_handle_included_file", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/snap_test.rs b/crates/biome_cli/tests/snap_test.rs index cdefd345e197..4ef8fe20ca63 100644 --- a/crates/biome_cli/tests/snap_test.rs +++ b/crates/biome_cli/tests/snap_test.rs @@ -12,7 +12,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::env::{current_exe, temp_dir}; use std::fmt::Write as _; -use std::path::{PathBuf, MAIN_SEPARATOR}; +use std::path::{Path, PathBuf, MAIN_SEPARATOR}; #[derive(Default)] struct InMessages { @@ -352,3 +352,16 @@ pub fn assert_cli_snapshot(payload: SnapshotPayload<'_>) { }); } + +/// It checks if the contents of a file matches the passed `expected_content` +pub fn assert_file_contents(fs: &MemoryFileSystem, file: &Path, expected_content: &str) { + let mut file = fs.open(file).expect("file was removed"); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("failed to read file from memory FS"); + + assert_eq!(content, expected_content); + + // drop(file); +} diff --git a/crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_handle_included_file.snap b/crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_handle_included_file.snap new file mode 100644 index 000000000000..f6c6d1f38e5e --- /dev/null +++ b/crates/biome_cli/tests/snapshots/main_cases_overrides_formatter/does_handle_included_file.snap @@ -0,0 +1,35 @@ +--- +source: crates/biome_cli/tests/snap_test.rs +expression: content +--- +## `biome.json` + +```json +{ + "files": { + "ignore": ["test.js", "special/**"] + }, + "overrides": [{ "include": ["special/**"] }] +} +``` + +## `special/test2.js` + +```js +statement(); + +``` + +## `test.js` + +```js + statement( ) +``` + +# Emitted Messages + +```block +Formatted 1 file(s) in