-
-
Notifications
You must be signed in to change notification settings - Fork 485
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(graphql_analyze): noUnamedOperation
Disallow operations without name, since GraphQL clients usually use operations' name to cache.
- Loading branch information
1 parent
1c60340
commit 0769cd2
Showing
16 changed files
with
263 additions
and
10 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
crates/biome_graphql_analyze/src/lint/nursery/use_named_operation.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use biome_analyze::{ | ||
context::RuleContext, declare_lint_rule, ActionCategory, Ast, FixKind, Rule, RuleDiagnostic, | ||
RuleSource, RuleSourceKind, | ||
}; | ||
use biome_console::markup; | ||
use biome_graphql_factory::make; | ||
use biome_graphql_syntax::{GraphqlOperationDefinition, GraphqlOperationType}; | ||
use biome_rowan::{AstNode, BatchMutationExt}; | ||
use biome_string_case::Case; | ||
|
||
use crate::GraphqlRuleAction; | ||
|
||
declare_lint_rule! { | ||
/// Enforce specifying the name of GraphQL operations. | ||
/// | ||
/// This is useful because most GraphQL client libraries use the operation name for caching purposes. | ||
/// | ||
/// ## Examples | ||
/// | ||
/// ### Invalid | ||
/// | ||
/// ```graphql,expect_diagnostic | ||
/// query {} | ||
/// ``` | ||
/// | ||
/// ### Valid | ||
/// | ||
/// ```graphql | ||
/// query Human { | ||
/// name | ||
/// } | ||
/// ``` | ||
/// | ||
pub UseNamedOperation { | ||
version: "next", | ||
name: "useNamedOperation", | ||
language: "graphql", | ||
sources: &[RuleSource::EslintGraphql("no-anonymous-operations")], | ||
source_kind: RuleSourceKind::SameLogic, | ||
recommended: true, | ||
fix_kind: FixKind::Unsafe, | ||
} | ||
} | ||
|
||
impl Rule for UseNamedOperation { | ||
type Query = Ast<GraphqlOperationDefinition>; | ||
type State = GraphqlOperationType; | ||
type Signals = Option<Self::State>; | ||
type Options = (); | ||
|
||
fn run(ctx: &RuleContext<Self>) -> Option<Self::State> { | ||
let node = ctx.query(); | ||
let operation_type = node.ty().ok()?; | ||
if node.name().is_some() { | ||
None | ||
} else { | ||
Some(operation_type) | ||
} | ||
} | ||
|
||
fn diagnostic( | ||
_ctx: &RuleContext<Self>, | ||
operation_type: &Self::State, | ||
) -> Option<RuleDiagnostic> { | ||
Some( | ||
RuleDiagnostic::new( | ||
rule_category!(), | ||
operation_type.range(), | ||
markup! { | ||
"Anonymous GraphQL operations are forbidden. Make sure to name your " {operation_type.text()}"." | ||
}, | ||
) | ||
.note(markup! { | ||
"Most GraphQL client libraries use the operation name for caching purposes." | ||
}), | ||
) | ||
} | ||
|
||
fn action(ctx: &RuleContext<Self>, operation_type: &Self::State) -> Option<GraphqlRuleAction> { | ||
let mut mutation = ctx.root().begin(); | ||
let node = ctx.query().clone(); | ||
let operation_type = operation_type.text(); | ||
let suggested_name = get_suggested_name(&node, operation_type.clone()); | ||
let new_name = make::graphql_name_binding(make::ident(&suggested_name)); | ||
let new_node = node.clone().with_name(Some(new_name)); | ||
mutation.replace_node(node, new_node); | ||
|
||
Some(GraphqlRuleAction::new( | ||
ActionCategory::QuickFix, | ||
ctx.metadata().applicability(), | ||
markup! { | ||
"Rename this "{operation_type}" to "{suggested_name}"." | ||
}, | ||
mutation, | ||
)) | ||
} | ||
} | ||
|
||
fn get_suggested_name(operation: &GraphqlOperationDefinition, operation_type: String) -> String { | ||
let suggested_name = operation | ||
.selection_set() | ||
.ok() | ||
.and_then(|selection_set| { | ||
selection_set | ||
.selections() | ||
.into_iter() | ||
.find_map(|selection| selection.as_graphql_field().cloned()) | ||
}) | ||
.and_then(|first_field| { | ||
first_field | ||
.alias() | ||
.map(|alias| alias.text()) | ||
.or(first_field.name().ok().map(|name| name.text())) | ||
}) | ||
.unwrap_or(operation_type); | ||
Case::Pascal.convert(&suggested_name) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
3 changes: 3 additions & 0 deletions
3
crates/biome_graphql_analyze/tests/specs/nursery/useNamedOperation/invalid.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
query { human } | ||
mutation { ...Type } | ||
subscription {} |
71 changes: 71 additions & 0 deletions
71
crates/biome_graphql_analyze/tests/specs/nursery/useNamedOperation/invalid.graphql.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
source: crates/biome_graphql_analyze/tests/spec_tests.rs | ||
expression: invalid.graphql | ||
--- | ||
# Input | ||
```graphql | ||
query { human } | ||
mutation { ...Type } | ||
subscription {} | ||
``` | ||
|
||
# Diagnostics | ||
``` | ||
invalid.graphql:1:1 lint/nursery/useNamedOperation FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Anonymous GraphQL operations are forbidden. Make sure to name your query. | ||
> 1 │ query { human } | ||
│ ^^^^^ | ||
2 │ mutation { ...Type } | ||
3 │ subscription {} | ||
i Most GraphQL client libraries use the operation name for caching purposes. | ||
i Unsafe fix: Rename this query to Human. | ||
1 │ query·Human{·human·} | ||
│ +++++ | ||
``` | ||
|
||
``` | ||
invalid.graphql:2:1 lint/nursery/useNamedOperation FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Anonymous GraphQL operations are forbidden. Make sure to name your mutation. | ||
1 │ query { human } | ||
> 2 │ mutation { ...Type } | ||
│ ^^^^^^^^ | ||
3 │ subscription {} | ||
4 │ | ||
i Most GraphQL client libraries use the operation name for caching purposes. | ||
i Unsafe fix: Rename this mutation to Mutation. | ||
2 │ mutation·Mutation{·...Type·} | ||
│ ++++++++ | ||
``` | ||
|
||
``` | ||
invalid.graphql:3:1 lint/nursery/useNamedOperation FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Anonymous GraphQL operations are forbidden. Make sure to name your subscription. | ||
1 │ query { human } | ||
2 │ mutation { ...Type } | ||
> 3 │ subscription {} | ||
│ ^^^^^^^^^^^^ | ||
4 │ | ||
i Most GraphQL client libraries use the operation name for caching purposes. | ||
i Unsafe fix: Rename this subscription to Subscription. | ||
3 │ subscription·Subscription{} | ||
│ ++++++++++++ | ||
``` |
2 changes: 2 additions & 0 deletions
2
crates/biome_graphql_analyze/tests/specs/nursery/useNamedOperation/valid.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/* should not generate diagnostics */ | ||
// var a = 1; |
9 changes: 9 additions & 0 deletions
9
crates/biome_graphql_analyze/tests/specs/nursery/useNamedOperation/valid.graphql.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
source: crates/biome_graphql_analyze/tests/spec_tests.rs | ||
expression: valid.graphql | ||
--- | ||
# Input | ||
```graphql | ||
/* should not generate diagnostics */ | ||
// var a = 1; | ||
``` |
Oops, something went wrong.