diff --git a/CHANGELOG.md b/CHANGELOG.md index 64381784d5da..ee2337259c7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b ### CLI +#### New features + +- Add `--graphql-linter-enabled` option, to control whether the linter should enabled or not for GraphQL files. Contributed by @ematipico + ### Configuration - Add support for loading configuration from `.editorconfig` files ([#1724](https://github.com/biomejs/biome/issues/1724)). Contributed by @dyc3 @@ -69,6 +73,10 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b Contributed by @Conaclos +#### New features + +- Add support for GraphQL linting. Contributed by @ematipico + #### Bug fixes - Don't request alt text for elements hidden from assistive technologies ([#3316](https://github.com/biomejs/biome/issues/3316)). Contributed by @robintown diff --git a/crates/biome_cli/src/commands/format.rs b/crates/biome_cli/src/commands/format.rs index c90b466f8464..f865f712c378 100644 --- a/crates/biome_cli/src/commands/format.rs +++ b/crates/biome_cli/src/commands/format.rs @@ -10,7 +10,7 @@ use crate::{ use biome_configuration::vcs::PartialVcsConfiguration; use biome_configuration::{ PartialCssFormatter, PartialFilesConfiguration, PartialFormatterConfiguration, - PartialJavascriptFormatter, PartialJsonFormatter, + PartialGraphqlFormatter, PartialJavascriptFormatter, PartialJsonFormatter, }; use biome_console::{markup, ConsoleExt}; use biome_deserialize::Merge; @@ -27,6 +27,7 @@ pub(crate) struct FormatCommandPayload { pub(crate) javascript_formatter: Option, pub(crate) json_formatter: Option, pub(crate) css_formatter: Option, + pub(crate) graphql_formatter: Option, pub(crate) formatter_configuration: Option, pub(crate) vcs_configuration: Option, pub(crate) files_configuration: Option, @@ -57,6 +58,7 @@ pub(crate) fn format( fix, mut json_formatter, css_formatter, + graphql_formatter, since, staged, changed, @@ -196,6 +198,11 @@ pub(crate) fn format( let css = configuration.css.get_or_insert_with(Default::default); css.formatter.merge_with(css_formatter); } + if graphql_formatter.is_some() { + let graphql = configuration.graphql.get_or_insert_with(Default::default); + graphql.formatter.merge_with(graphql_formatter); + } + if javascript_formatter.is_some() { let javascript = configuration .javascript diff --git a/crates/biome_cli/src/commands/lint.rs b/crates/biome_cli/src/commands/lint.rs index e00631f89e1a..07dfdb14283b 100644 --- a/crates/biome_cli/src/commands/lint.rs +++ b/crates/biome_cli/src/commands/lint.rs @@ -12,7 +12,8 @@ use biome_configuration::json::PartialJsonLinter; use biome_configuration::linter::RuleSelector; use biome_configuration::vcs::PartialVcsConfiguration; use biome_configuration::{ - PartialConfiguration, PartialFilesConfiguration, PartialLinterConfiguration, + PartialConfiguration, PartialFilesConfiguration, PartialGraphqlLinter, + PartialLinterConfiguration, }; use biome_deserialize::Merge; use biome_service::configuration::{ @@ -43,6 +44,7 @@ pub(crate) struct LintCommandPayload { pub(crate) javascript_linter: Option, pub(crate) json_linter: Option, pub(crate) css_linter: Option, + pub(crate) graphql_linter: Option, } /// Handler for the "lint" command of the Biome CLI @@ -67,6 +69,7 @@ pub(crate) fn lint(session: CliSession, payload: LintCommandPayload) -> Result<( javascript_linter, css_linter, json_linter, + graphql_linter, } = payload; setup_cli_subscriber(cli_options.log_level, cli_options.log_kind); @@ -118,6 +121,13 @@ pub(crate) fn lint(session: CliSession, payload: LintCommandPayload) -> Result<( let css = fs_configuration.css.get_or_insert_with(Default::default); css.linter.merge_with(css_linter); } + + if graphql_linter.is_some() { + let graphql = fs_configuration + .graphql + .get_or_insert_with(Default::default); + graphql.linter.merge_with(graphql_linter); + } if javascript_linter.is_some() { let javascript = fs_configuration .javascript diff --git a/crates/biome_cli/src/commands/mod.rs b/crates/biome_cli/src/commands/mod.rs index 0b49de90d539..5323782b6bbd 100644 --- a/crates/biome_cli/src/commands/mod.rs +++ b/crates/biome_cli/src/commands/mod.rs @@ -9,12 +9,14 @@ use biome_configuration::javascript::PartialJavascriptLinter; use biome_configuration::json::PartialJsonLinter; use biome_configuration::linter::RuleSelector; use biome_configuration::{ - css::partial_css_formatter, css::partial_css_linter, javascript::partial_javascript_formatter, + css::partial_css_formatter, css::partial_css_linter, graphql::partial_graphql_formatter, + graphql::partial_graphql_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, + PartialGraphqlFormatter, PartialGraphqlLinter, PartialJavascriptFormatter, + PartialJsonFormatter, PartialLinterConfiguration, }; use biome_configuration::{BiomeDiagnostic, PartialConfiguration}; use biome_console::{markup, Console, ConsoleExt}; @@ -190,6 +192,9 @@ pub enum BiomeCommand { #[bpaf(external(partial_css_linter), optional, hide_usage, hide)] css_linter: Option, + #[bpaf(external(partial_graphql_linter), optional, hide_usage, hide)] + graphql_linter: Option, + #[bpaf(external, hide_usage)] cli_options: CliOptions, @@ -246,6 +251,9 @@ pub enum BiomeCommand { #[bpaf(external(partial_css_formatter), optional, hide_usage, hide)] css_formatter: Option, + #[bpaf(external(partial_graphql_formatter), optional, hide_usage, hide)] + graphql_formatter: Option, + #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] vcs_configuration: Option, diff --git a/crates/biome_cli/src/commands/rage.rs b/crates/biome_cli/src/commands/rage.rs index 057c6ec1fec3..86a46b16b3ec 100644 --- a/crates/biome_cli/src/commands/rage.rs +++ b/crates/biome_cli/src/commands/rage.rs @@ -271,7 +271,7 @@ impl Display for RageConfiguration<'_, '_> { configuration.get_graphql_formatter_configuration(); markup! ( {Section("GraphQL Formatter")} - {KeyValuePair("Enabled", markup!({DebugDisplay(graphql_formatter_configuration.enabled)}))} + {KeyValuePair("Enabled", markup!({DebugDisplayOption(graphql_formatter_configuration.enabled)}))} {KeyValuePair("Indent style", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_style)}))} {KeyValuePair("Indent width", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_width)}))} {KeyValuePair("Line ending", markup!({DebugDisplayOption(graphql_formatter_configuration.line_ending)}))} @@ -288,11 +288,13 @@ impl Display for RageConfiguration<'_, '_> { let javascript_linter = configuration.get_javascript_linter_configuration(); let json_linter = configuration.get_json_linter_configuration(); let css_linter = configuration.get_css_linter_configuration(); + let graphq_linter = configuration.get_graphql_linter_configuration(); markup! ( {Section("Linter")} {KeyValuePair("JavaScript enabled", markup!({DebugDisplay(javascript_linter.enabled)}))} {KeyValuePair("JSON enabled", markup!({DebugDisplay(json_linter.enabled)}))} {KeyValuePair("CSS enabled", markup!({DebugDisplay(css_linter.enabled)}))} + {KeyValuePair("GraphQL enabled", markup!({DebugDisplayOption(graphq_linter.enabled)}))} {KeyValuePair("Recommended", markup!({DebugDisplay(linter_configuration.recommended.unwrap_or_default())}))} {KeyValuePair("All", markup!({DebugDisplay(linter_configuration.all.unwrap_or_default())}))} {RageConfigurationLintRules("Enabled rules",linter_configuration)} diff --git a/crates/biome_cli/src/lib.rs b/crates/biome_cli/src/lib.rs index 9ab166f67b38..490fd738399b 100644 --- a/crates/biome_cli/src/lib.rs +++ b/crates/biome_cli/src/lib.rs @@ -135,6 +135,7 @@ impl<'app> CliSession<'app> { css_linter, javascript_linter, json_linter, + graphql_linter, } => commands::lint::lint( self, LintCommandPayload { @@ -157,6 +158,7 @@ impl<'app> CliSession<'app> { css_linter, javascript_linter, json_linter, + graphql_linter, }, ), BiomeCommand::Ci { @@ -193,6 +195,7 @@ impl<'app> CliSession<'app> { files_configuration, json_formatter, css_formatter, + graphql_formatter, staged, changed, since, @@ -210,6 +213,7 @@ impl<'app> CliSession<'app> { files_configuration, json_formatter, css_formatter, + graphql_formatter, staged, changed, since, diff --git a/crates/biome_cli/tests/cases/graphql.rs b/crates/biome_cli/tests/cases/graphql.rs new file mode 100644 index 000000000000..7e8dee54a6c3 --- /dev/null +++ b/crates/biome_cli/tests/cases/graphql.rs @@ -0,0 +1,115 @@ +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 = r#"type Query { + me: User +} + +type User { id: ID name: String +}"#; + +const FORMATTED: &str = "type Query {\n\tme: User\n}\n\ntype User {\n\tid: ID\n\tname: String\n}\n"; + +const MISSING_REASON: &str = r#"query { + member @deprecated { + id + } +}"#; + +#[test] +fn format_graphql_files() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("file.graphql"); + fs.insert(file_path.into(), UNFORMATTED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("format"), file_path.as_os_str().to_str().unwrap()].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_graphql_files", + fs, + console, + result, + )); +} + +#[test] +fn format_and_write_graphql_files() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("file.graphql"); + fs.insert(file_path.into(), UNFORMATTED.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("format"), + "--write", + file_path.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_file_contents(&fs, file_path, FORMATTED); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "format_and_write_graphql_files", + fs, + console, + result, + )); +} + +#[test] +fn lint_single_rule() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let file_path = Path::new("file.graphql"); + fs.insert(file_path.into(), MISSING_REASON.as_bytes()); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from( + [ + ("lint"), + "--only=nursery/useDeprecatedReason", + file_path.as_os_str().to_str().unwrap(), + ] + .as_slice(), + ), + ); + + assert!(result.is_ok(), "run_cli returned {result:?}"); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "lint_single_rule", + fs, + console, + result, + )); +} diff --git a/crates/biome_cli/tests/cases/mod.rs b/crates/biome_cli/tests/cases/mod.rs index fc3e960808d8..8c76695ba529 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 editorconfig; +mod graphql; mod handle_astro_files; mod handle_css_files; mod handle_svelte_files; diff --git a/crates/biome_cli/tests/snapshots/main_cases_graphql/format_and_write_graphql_files.snap b/crates/biome_cli/tests/snapshots/main_cases_graphql/format_and_write_graphql_files.snap new file mode 100644 index 000000000000..21ef37915e23 --- /dev/null +++ b/crates/biome_cli/tests/snapshots/main_cases_graphql/format_and_write_graphql_files.snap @@ -0,0 +1,23 @@ +--- +source: crates/biome_cli/tests/snap_test.rs +expression: content +--- +## `file.graphql` + +```graphql +type Query { + me: User +} + +type User { + id: ID + name: String +} + +``` + +# Emitted Messages + +```block +Formatted 1 file in