diff --git a/crates/rome_cli/src/commands/format.rs b/crates/rome_cli/src/commands/format.rs index 26508e99dea..03b4ecfb206 100644 --- a/crates/rome_cli/src/commands/format.rs +++ b/crates/rome_cli/src/commands/format.rs @@ -71,15 +71,11 @@ pub(crate) fn apply_format_settings_from_cli( let mut configuration = if let Some(configuration) = configuration { configuration } else { - Configuration { - formatter: Some(FormatterConfiguration::default()), - javascript: Some(JavascriptConfiguration { - formatter: Some(JavascriptFormatter::default()), - globals: None, - }), - ..Configuration::default() - } + Configuration::default() }; + let formatter = configuration + .formatter + .get_or_insert_with(FormatterConfiguration::default); let size = session .args @@ -105,21 +101,19 @@ pub(crate) fn apply_format_settings_from_cli( source, })?; - if let Some(formatter) = configuration.formatter.as_mut() { - match indent_style { - Some(IndentStyle::Tab) => { - formatter.indent_style = PlainIndentStyle::Tab; - } - Some(IndentStyle::Space(default_size)) => { - formatter.indent_style = PlainIndentStyle::Space; - formatter.indent_size = size.unwrap_or(default_size); - } - None => {} + match indent_style { + Some(IndentStyle::Tab) => { + formatter.indent_style = PlainIndentStyle::Tab; } - - if let Some(line_width) = line_width { - formatter.line_width = line_width; + Some(IndentStyle::Space(default_size)) => { + formatter.indent_style = PlainIndentStyle::Space; + formatter.indent_size = size.unwrap_or(default_size); } + None => {} + } + + if let Some(line_width) = line_width { + formatter.line_width = line_width; } let quote_properties = session @@ -137,18 +131,20 @@ pub(crate) fn apply_format_settings_from_cli( argument: "--quote-style", source, })?; - if let Some(javascript) = configuration + + let javascript = configuration .javascript - .as_mut() - .and_then(|j| j.formatter.as_mut()) - { - if let Some(quote_properties) = quote_properties { - javascript.quote_properties = quote_properties; - } + .get_or_insert_with(JavascriptConfiguration::default); + let javascript_formatter = javascript + .formatter + .get_or_insert_with(JavascriptFormatter::default); - if let Some(quote_style) = quote_style { - javascript.quote_style = quote_style; - } + if let Some(quote_properties) = quote_properties { + javascript_formatter.quote_properties = quote_properties; + } + + if let Some(quote_style) = quote_style { + javascript_formatter.quote_style = quote_style; } Ok(configuration) diff --git a/crates/rome_cli/tests/configs.rs b/crates/rome_cli/tests/configs.rs index d4fc35b3b42..cd14e368269 100644 --- a/crates/rome_cli/tests/configs.rs +++ b/crates/rome_cli/tests/configs.rs @@ -144,3 +144,19 @@ pub const CONFIG_INCORRECT_GLOBALS_V2: &str = r#"{ } } }"#; + +pub const CONFIG_ISSUE_3175_1: &str = r#"{ + "formatter": { + "indentStyle": "space", + "indentSize": 2, + "lineWidth": 120 + } +}"#; + +pub const CONFIG_ISSUE_3175_2: &str = r#"{ + "javascript": { + "formatter": { + "quoteStyle": "single" + } + } +}"#; diff --git a/crates/rome_cli/tests/main.rs b/crates/rome_cli/tests/main.rs index 309ade47aa9..592b1606a8e 100644 --- a/crates/rome_cli/tests/main.rs +++ b/crates/rome_cli/tests/main.rs @@ -734,7 +734,9 @@ mod ci { mod format { use super::*; - use crate::configs::{CONFIG_DISABLED_FORMATTER, CONFIG_FORMAT}; + use crate::configs::{ + CONFIG_DISABLED_FORMATTER, CONFIG_FORMAT, CONFIG_ISSUE_3175_1, CONFIG_ISSUE_3175_2, + }; use crate::snap_test::markup_to_string; use rome_console::markup; use rome_fs::FileSystemExt; @@ -934,6 +936,97 @@ mod format { ); } + #[test] + fn applies_custom_configuration_over_config_file_issue_3175_v1() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("rome.json"); + fs.insert(file_path.into(), CONFIG_ISSUE_3175_1.as_bytes()); + + let file_path = Path::new("file.js"); + fs.insert(file_path.into(), "import React from 'react';\n".as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + DynRef::Borrowed(&mut console), + Arguments::from_vec(vec![ + OsString::from("format"), + OsString::from("--quote-style"), + OsString::from("single"), + file_path.as_os_str().into(), + ]), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + let mut file = fs + .open(file_path) + .expect("formatting target file was removed by the CLI"); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("failed to read file from memory FS"); + + assert_eq!(content, "import React from 'react';\n"); + + drop(file); + assert_cli_snapshot( + module_path!(), + "applies_custom_configuration_over_config_file_issue_3175_v1", + fs, + console, + ); + } + + #[test] + fn applies_custom_configuration_over_config_file_issue_3175_v2() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let source = r#"function f() { + return 'hey'; +} +"#; + + let file_path = Path::new("rome.json"); + fs.insert(file_path.into(), CONFIG_ISSUE_3175_2.as_bytes()); + + let file_path = Path::new("file.js"); + fs.insert(file_path.into(), source.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + DynRef::Borrowed(&mut console), + Arguments::from_vec(vec![ + OsString::from("format"), + OsString::from("--indent-style"), + OsString::from("space"), + file_path.as_os_str().into(), + ]), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + let mut file = fs + .open(file_path) + .expect("formatting target file was removed by the CLI"); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("failed to read file from memory FS"); + + assert_eq!(content, source); + + drop(file); + assert_cli_snapshot( + module_path!(), + "applies_custom_configuration_over_config_file_issue_3175_v2", + fs, + console, + ); + } + #[test] fn applies_custom_quote_style() { let mut fs = MemoryFileSystem::default(); diff --git a/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v1.snap b/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v1.snap new file mode 100644 index 00000000000..4819d371e9f --- /dev/null +++ b/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v1.snap @@ -0,0 +1,26 @@ +--- +source: crates/rome_cli/tests/snap_test.rs +expression: content +--- +## `rome.json` + +```json +{ + "formatter": { + "indentStyle": "space", + "indentSize": 2, + "lineWidth": 120 + } +} +``` + +## `file.js` + +```js +import React from 'react'; + +``` + +# Emitted Messages + + diff --git a/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap b/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap new file mode 100644 index 00000000000..cdf17b21be4 --- /dev/null +++ b/crates/rome_cli/tests/snapshots/main_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap @@ -0,0 +1,28 @@ +--- +source: crates/rome_cli/tests/snap_test.rs +expression: content +--- +## `rome.json` + +```json +{ + "javascript": { + "formatter": { + "quoteStyle": "single" + } + } +} +``` + +## `file.js` + +```js +function f() { + return 'hey'; +} + +``` + +# Emitted Messages + + diff --git a/crates/rome_service/src/configuration/javascript.rs b/crates/rome_service/src/configuration/javascript.rs index 0fcecf0d344..de2e197fa17 100644 --- a/crates/rome_service/src/configuration/javascript.rs +++ b/crates/rome_service/src/configuration/javascript.rs @@ -23,6 +23,15 @@ pub struct JavascriptConfiguration { pub globals: Option>, } +impl JavascriptConfiguration { + pub fn with_formatter() -> Self { + Self { + formatter: Some(JavascriptFormatter::default()), + ..JavascriptConfiguration::default() + } + } +} + pub(crate) fn deserialize_globals<'de, D>( deserializer: D, ) -> Result>, D::Error> diff --git a/npm/rome/tests/__snapshots__/wasm.test.mjs.snap b/npm/rome/tests/__snapshots__/wasm.test.mjs.snap deleted file mode 100644 index b8187942d45..00000000000 --- a/npm/rome/tests/__snapshots__/wasm.test.mjs.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Vitest Snapshot v1 - -exports[`Rome WebAssembly formatter > should not format and have diagnostics > syntax error 1`] = ` -[ - { - "children": [], - "code": "SyntaxError", - "code_link": null, - "file_id": 0, - "footers": [], - "primary": { - "msg": [ - { - "content": "", - "elements": [], - }, - ], - "severity": "Error", - "span": { - "file": 0, - "range": [ - 11, - 12, - ], - }, - }, - "severity": "Error", - "suggestions": [], - "summary": null, - "tag": null, - "title": [ - { - "content": "expected a name for the function in a function declaration, but found none", - "elements": [], - }, - ], - }, -] -`; diff --git a/npm/rome/tests/__snapshots__/daemon.test.mjs.snap b/npm/rome/tests/daemon/__snapshots__/formatContent.test.mjs.snap similarity index 100% rename from npm/rome/tests/__snapshots__/daemon.test.mjs.snap rename to npm/rome/tests/daemon/__snapshots__/formatContent.test.mjs.snap diff --git a/npm/rome/tests/daemon.test.mjs b/npm/rome/tests/daemon/formatContent.test.mjs similarity index 76% rename from npm/rome/tests/daemon.test.mjs rename to npm/rome/tests/daemon/formatContent.test.mjs index 787bfca123e..8e27eab2ca8 100644 --- a/npm/rome/tests/daemon.test.mjs +++ b/npm/rome/tests/daemon/formatContent.test.mjs @@ -1,54 +1,15 @@ import { describe, expect, it } from "vitest"; -import { BackendKind, Rome } from "../dist"; +import { BackendKind, Rome } from "../../dist"; import { resolve } from "path"; import { fileURLToPath } from "url"; const target = process.env.CI ? "target/release/rome" : "target/debug/rome"; describe("Rome Deamon formatter", () => { - it("should not format files", async () => { - const pathToBinary = resolve( - fileURLToPath(import.meta.url), - "../../../..", - target, - ); - - const rome = await Rome.create({ - backendKind: BackendKind.DAEMON, - pathToBinary, - }); - - let result = await rome.formatFiles(["./path/to/file.js"]); - - expect(result.content).toEqual(""); - expect(result.diagnostics).toEqual([]); - }); - - it("should not format files in debug mode", async () => { - const pathToBinary = resolve( - fileURLToPath(import.meta.url), - "../../../..", - target, - ); - - const rome = await Rome.create({ - backendKind: BackendKind.DAEMON, - pathToBinary, - }); - - let result = await rome.formatFiles(["./path/to/file.js"], { - debug: true, - }); - - expect(result.content).toEqual(""); - expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual(""); - }); - it("should format content", async () => { const command = resolve( fileURLToPath(import.meta.url), - "../../../..", + "../../../../..", target, ); @@ -67,7 +28,7 @@ describe("Rome Deamon formatter", () => { it("should not format and have diagnostics", async () => { const command = resolve( fileURLToPath(import.meta.url), - "../../../..", + "../../../../..", target, ); @@ -92,7 +53,7 @@ describe("Rome Deamon formatter", () => { it("should format content in debug mode", async () => { const command = resolve( fileURLToPath(import.meta.url), - "../../../..", + "../../../../..", target, ); @@ -116,7 +77,7 @@ describe("Rome Deamon formatter", () => { it("should not format content with range", async () => { const command = resolve( fileURLToPath(import.meta.url), - "../../../..", + "../../../../..", target, ); @@ -136,7 +97,7 @@ describe("Rome Deamon formatter", () => { it("should not format content with range in debug mode", async () => { const command = resolve( fileURLToPath(import.meta.url), - "../../../..", + "../../../../..", target, ); @@ -170,4 +131,4 @@ describe("Rome Deamon formatter", () => { `, ); }); -}); +}, 1500); diff --git a/npm/rome/tests/daemon/formatFiles.test.mjs b/npm/rome/tests/daemon/formatFiles.test.mjs new file mode 100644 index 00000000000..d55376807ff --- /dev/null +++ b/npm/rome/tests/daemon/formatFiles.test.mjs @@ -0,0 +1,49 @@ +import { describe, expect, it } from "vitest"; +import { BackendKind, Rome } from "../../dist"; +import { resolve } from "path"; +import { fileURLToPath } from "url"; + +const target = process.env.CI ? "target/release/rome" : "target/debug/rome"; + +describe("Rome Deamon formatter", () => { + it("should not format files", async () => { + const pathToBinary = resolve( + fileURLToPath(import.meta.url), + "../../../../..", + target, + ); + + console.log(pathToBinary); + + const rome = await Rome.create({ + backendKind: BackendKind.DAEMON, + pathToBinary, + }); + + let result = await rome.formatFiles(["./path/to/file.js"]); + + expect(result.content).toEqual(""); + expect(result.diagnostics).toEqual([]); + }); + + it("should not format files in debug mode", async () => { + const pathToBinary = resolve( + fileURLToPath(import.meta.url), + "../../../../..", + target, + ); + + const rome = await Rome.create({ + backendKind: BackendKind.DAEMON, + pathToBinary, + }); + + let result = await rome.formatFiles(["./path/to/file.js"], { + debug: true, + }); + + expect(result.content).toEqual(""); + expect(result.diagnostics).toEqual([]); + expect(result.ir).toEqual(""); + }); +}); diff --git a/npm/rome/tests/wasm.test.mjs b/npm/rome/tests/wasm.test.mjs deleted file mode 100644 index 73308e16d6e..00000000000 --- a/npm/rome/tests/wasm.test.mjs +++ /dev/null @@ -1,139 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { BackendKind, Rome } from "../dist"; - -describe("Rome WebAssembly formatter", () => { - it("should not format files", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatFiles(["./path/to/file.js"]); - - expect(result.content).toEqual(""); - expect(result.diagnostics).toEqual([]); - }); - - it("should not format files in debug mode", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatFiles(["./path/to/file.js"], { - debug: true, - }); - - expect(result.content).toEqual(""); - expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual(""); - }); - - it("should format content", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatContent("function f () { }", { - filePath: "example.js", - }); - - expect(result.content).toEqual("function f() {}\n"); - expect(result.diagnostics).toEqual([]); - }); - - it("should not format and have diagnostics", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let content = "function () { }"; - let result = await rome.formatContent(content, { - filePath: "example.js", - }); - - expect(result.content).toEqual(content); - expect(result.diagnostics).toHaveLength(1); - expect(result.diagnostics[0].title[0].content).toContain( - "expected a name for the function in a function declaration, but found none", - ); - expect(result.diagnostics).toMatchSnapshot("syntax error"); - }); - - it("should format content in debug mode", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatContent("function f() {}", { - filePath: "example.js", - debug: true, - }); - - expect(result.content).toEqual("function f() {}\n"); - expect(result.diagnostics).toEqual([]); - expect(result.ir).toMatchInlineSnapshot( - '"[\\"function\\", \\" \\", \\"f\\", group([\\"(\\", \\")\\"]), \\" \\", \\"{\\", \\"}\\", hard_line_break]"', - ); - }); - - it("should not format content with range", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatContent("let a ; function g () { }", { - filePath: "file.js", - range: [20, 25], - }); - - expect(result.content).toEqual("function g() {}"); - expect(result.diagnostics).toEqual([]); - }); - - it("should not format content with range in debug mode", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.formatContent("let a ; function g () { }", { - filePath: "file.js", - range: [20, 25], - debug: true, - }); - - expect(result.content).toEqual("function g() {}"); - expect(result.diagnostics).toEqual([]); - expect(result.ir).toMatchInlineSnapshot( - ` - "[ - group([\\"let\\", \\" \\", \\"a\\"]), - \\";\\", - hard_line_break, - \\"function\\", - \\" \\", - \\"g\\", - group([\\"(\\", \\")\\"]), - \\" \\", - \\"{\\", - \\"}\\", - hard_line_break - ]" - `, - ); - }); -}); - -describe("Rome parser", () => { - it("should not parse content", async () => { - const rome = await Rome.create({ - backendKind: BackendKind.NODE, - }); - - let result = await rome.parseContent("function f() {}", { - filePath: "example.js", - }); - - expect(result.ast).toEqual(""); - expect(result.cst).toEqual(""); - expect(result.diagnostics).toEqual([]); - }); -});