Skip to content

Commit 14949c7

Browse files
feature: Adds UniqueVariableNamesRule
1 parent 062a975 commit 14949c7

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
/**
3+
* Unique variable names
4+
*
5+
* A GraphQL operation is only valid if all its variables are uniquely named.
6+
*/
7+
func UniqueVariableNamesRule(context: ValidationContext) -> Visitor {
8+
return Visitor(
9+
enter: { node, _, _, _, _ in
10+
if let operation = node as? OperationDefinition {
11+
let variableDefinitions = operation.variableDefinitions
12+
13+
let seenVariableDefinitions = Dictionary(grouping: variableDefinitions) { node in
14+
node.variable.name.value
15+
}
16+
17+
for (variableName, variableNodes) in seenVariableDefinitions {
18+
if variableNodes.count > 1 {
19+
context.report(
20+
error: GraphQLError(
21+
message: "There can be only one variable named \"$\(variableName)\".",
22+
nodes: variableNodes.map { $0.variable.name }
23+
)
24+
)
25+
}
26+
}
27+
}
28+
return .continue
29+
}
30+
)
31+
}

Sources/GraphQL/Validation/SpecifiedRules.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public let specifiedRules: [(ValidationContext) -> Visitor] = [
1616
NoUnusedFragmentsRule,
1717
PossibleFragmentSpreadsRule,
1818
NoFragmentCyclesRule,
19-
// UniqueVariableNamesRule,
19+
UniqueVariableNamesRule,
2020
// NoUndefinedVariablesRule,
2121
NoUnusedVariablesRule,
2222
// KnownDirectivesRule,
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
@testable import GraphQL
2+
import XCTest
3+
4+
class UniqueVariableNamesRuleTests: ValidationTestCase {
5+
override func setUp() {
6+
rule = UniqueVariableNamesRule
7+
}
8+
9+
func testUniqueVariableNames() throws {
10+
try assertValid(
11+
"""
12+
query A($x: Int, $y: String) { __typename }
13+
query B($x: String, $y: Int) { __typename }
14+
"""
15+
)
16+
}
17+
18+
func testDuplicateVariableNames() throws {
19+
let errors = try assertInvalid(
20+
errorCount: 3,
21+
query:
22+
"""
23+
query A($x: Int, $x: Int, $x: String) { __typename }
24+
query B($x: String, $x: Int) { __typename }
25+
query C($x: Int, $x: Int) { __typename }
26+
"""
27+
)
28+
try assertValidationError(
29+
error: errors[0],
30+
locations: [
31+
(line: 1, column: 10),
32+
(line: 1, column: 19),
33+
(line: 1, column: 28),
34+
],
35+
message: #"There can be only one variable named "$x"."#
36+
)
37+
try assertValidationError(
38+
error: errors[1],
39+
locations: [
40+
(line: 2, column: 10),
41+
(line: 2, column: 22),
42+
],
43+
message: #"There can be only one variable named "$x"."#
44+
)
45+
try assertValidationError(
46+
error: errors[2],
47+
locations: [
48+
(line: 3, column: 10),
49+
(line: 3, column: 19),
50+
],
51+
message: #"There can be only one variable named "$x"."#
52+
)
53+
}
54+
}

0 commit comments

Comments
 (0)