Skip to content

Commit 62b77b8

Browse files
committed
feat(graphql_analyze): implement useUniqueInputFieldNames
1 parent 958e24b commit 62b77b8

File tree

11 files changed

+212
-26
lines changed

11 files changed

+212
-26
lines changed

.changeset/cold-ravens-show.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Added the nursery rule [`useUniqueInputFieldNames`](https://biomejs.dev/linter/rules/use-unique-input-field-names/). Require fields within an input object to be unique.
6+
7+
**Invalid:**
8+
9+
```graphql
10+
query A($x: Int, $x: Int) {
11+
field
12+
}
13+
```

crates/biome_configuration/src/analyzer/linter/rules.rs

Lines changed: 46 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_diagnostics_categories/src/categories.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ define_categories! {
230230
"lint/nursery/useSortedClasses": "https://biomejs.dev/linter/rules/use-sorted-classes",
231231
"lint/nursery/useSpread": "https://biomejs.dev/linter/rules/no-spread",
232232
"lint/nursery/useUniqueGraphqlOperationName": "https://biomejs.dev/linter/rules/use-unique-graphql-operation-name",
233+
"lint/nursery/useUniqueInputFieldNames": "https://biomejs.dev/linter/rules/use-unique-input-field-names",
233234
"lint/nursery/useUniqueVariableNames": "https://biomejs.dev/linter/rules/use-unique-variable-names",
234235
"lint/nursery/useVueConsistentDefinePropsDeclaration": "https://biomejs.dev/linter/rules/use-vue-consistent-define-props-declaration",
235236
"lint/nursery/useVueDefineMacrosOrder": "https://biomejs.dev/linter/rules/use-vue-define-macros-order",

crates/biome_graphql_analyze/src/lint/nursery.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ pub mod no_empty_source;
77
pub mod use_consistent_graphql_descriptions;
88
pub mod use_deprecated_date;
99
pub mod use_unique_graphql_operation_name;
10+
pub mod use_unique_input_field_names;
1011
pub mod use_unique_variable_names;
11-
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_empty_source :: NoEmptySource , self :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptions , self :: use_deprecated_date :: UseDeprecatedDate , self :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationName , self :: use_unique_variable_names :: UseUniqueVariableNames ,] } }
12+
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_empty_source :: NoEmptySource , self :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptions , self :: use_deprecated_date :: UseDeprecatedDate , self :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationName , self :: use_unique_input_field_names :: UseUniqueInputFieldNames , self :: use_unique_variable_names :: UseUniqueVariableNames ,] } }
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use biome_analyze::{
2+
Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
3+
};
4+
use biome_console::markup;
5+
use biome_graphql_syntax::GraphqlRoot;
6+
use biome_rowan::AstNode;
7+
use biome_rule_options::use_unique_input_field_names::UseUniqueInputFieldNamesOptions;
8+
9+
declare_lint_rule! {
10+
/// Require fields within an input object to be unique.
11+
///
12+
/// A GraphQL input object value is only valid if all supplied fields are uniquely named.
13+
///
14+
/// ## Examples
15+
///
16+
/// ### Invalid
17+
///
18+
/// ```graphql,expect_diagnostic
19+
/// query {
20+
/// field(arg: { f1: "value", f1: "value" })
21+
/// }
22+
/// ```
23+
///
24+
/// ### Valid
25+
///
26+
/// ```graphql
27+
/// query {
28+
/// field(arg: { f1: "value", f2: "value" })
29+
/// }
30+
/// ```
31+
///
32+
pub UseUniqueInputFieldNames {
33+
version: "next",
34+
name: "useUniqueInputFieldNames",
35+
language: "graphql",
36+
recommended: false,
37+
sources: &[RuleSource::EslintGraphql("unique-input-field-names").same()],
38+
}
39+
}
40+
41+
impl Rule for UseUniqueInputFieldNames {
42+
type Query = Ast<GraphqlRoot>;
43+
type State = ();
44+
type Signals = Option<Self::State>;
45+
type Options = UseUniqueInputFieldNamesOptions;
46+
47+
fn run(ctx: &RuleContext<Self>) -> Self::Signals {
48+
let _node = ctx.query();
49+
None
50+
}
51+
52+
fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
53+
let span = ctx.query().range();
54+
Some(
55+
RuleDiagnostic::new(
56+
rule_category!(),
57+
span,
58+
markup! {
59+
"Duplicate input field name."
60+
},
61+
)
62+
.note(markup! {
63+
"A GraphQL input object value is only valid if all supplied fields are uniquely named. Make sure to name every input field differently."
64+
}),
65+
)
66+
}
67+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# should generate diagnostics
2+
query A {
3+
field(arg: { f1: "value", f1: "value" })
4+
}
5+
6+
query B {
7+
field(arg: { f1: "value", f1: "value", f1: "value" })
8+
}
9+
10+
query C {
11+
field(arg: { f1: {f2: "value", f2: "value" }})
12+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# should not generate diagnostics
2+
query A {
3+
field(arg: { f: true })
4+
}
5+
6+
query B {
7+
field(arg1: { f: true }, arg2: { f: true })
8+
}
9+
10+
query C {
11+
field(arg: { f1: "value", f2: "value", f3: "value" })
12+
}
13+
14+
query D{
15+
field(arg: {
16+
deep: {
17+
deep: {
18+
id: 1
19+
}
20+
id: 1
21+
}
22+
id: 1
23+
})
24+
}

crates/biome_rule_options/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ pub mod use_trim_start_end;
384384
pub mod use_unified_type_signatures;
385385
pub mod use_unique_element_ids;
386386
pub mod use_unique_graphql_operation_name;
387+
pub mod use_unique_input_field_names;
387388
pub mod use_unique_variable_names;
388389
pub mod use_valid_anchor;
389390
pub mod use_valid_aria_props;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use biome_deserialize_macros::{Deserializable, Merge};
2+
use serde::{Deserialize, Serialize};
3+
#[derive(Default, Clone, Debug, Deserialize, Deserializable, Merge, Eq, PartialEq, Serialize)]
4+
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
5+
#[serde(rename_all = "camelCase", deny_unknown_fields, default)]
6+
pub struct UseUniqueInputFieldNamesOptions {}

packages/@biomejs/backend-jsonrpc/src/workspace.ts

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)