Skip to content

Commit 7a73e85

Browse files
feature: Adds KnownTypeNamesRule
1 parent 787b92d commit 7a73e85

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
/**
3+
* Known type names
4+
*
5+
* A GraphQL document is only valid if referenced types (specifically
6+
* variable definitions and fragment conditions) are defined by the type schema.
7+
*
8+
* See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence
9+
*/
10+
func KnownTypeNamesRule(context: ValidationContext) -> Visitor {
11+
let definitions = context.ast.definitions
12+
let existingTypesMap = context.schema.typeMap
13+
14+
var typeNames = Set<String>()
15+
for typeName in existingTypesMap.keys {
16+
typeNames.insert(typeName)
17+
}
18+
for definition in definitions {
19+
if
20+
let type = definition as? TypeDefinition,
21+
let nameResult = type.get(key: "name"),
22+
case let .node(nameNode) = nameResult,
23+
let name = nameNode as? Name
24+
{
25+
typeNames.insert(name.value)
26+
}
27+
}
28+
29+
return Visitor(
30+
enter: { node, _, _, _, _ in
31+
if let type = node as? NamedType {
32+
let typeName = type.name.value
33+
if !typeNames.contains(typeName) {
34+
// TODO: Add SDL support
35+
36+
let suggestedTypes = suggestionList(
37+
input: typeName,
38+
options: Array(typeNames)
39+
)
40+
context.report(
41+
error: GraphQLError(
42+
message: "Unknown type \"\(typeName)\"." +
43+
didYouMean(suggestions: suggestedTypes),
44+
nodes: [node]
45+
)
46+
)
47+
}
48+
}
49+
return .continue
50+
}
51+
)
52+
}

Sources/GraphQL/Validation/SpecifiedRules.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public let specifiedRules: [(ValidationContext) -> Visitor] = [
66
UniqueOperationNamesRule,
77
LoneAnonymousOperationRule,
88
// SingleFieldSubscriptionsRule,
9-
// KnownTypeNamesRule,
9+
KnownTypeNamesRule,
1010
// FragmentsOnCompositeTypesRule,
1111
// VariablesAreInputTypesRule,
1212
ScalarLeafsRule,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
@testable import GraphQL
2+
import XCTest
3+
4+
class KnownTypeNamesRuleTests: ValidationTestCase {
5+
override func setUp() {
6+
rule = KnownTypeNamesRule
7+
}
8+
9+
func testKnownTypeNamesAreValid() throws {
10+
try assertValid(
11+
"""
12+
query Foo(
13+
$var: String
14+
$required: [Int!]!
15+
$introspectionType: __EnumValue
16+
) {
17+
user(id: 4) {
18+
pets { ... on Pet { name }, ...PetFields, ... { name } }
19+
}
20+
}
21+
22+
fragment PetFields on Pet {
23+
name
24+
}
25+
"""
26+
)
27+
}
28+
29+
func testUnknownTypeNamesAreInvalid() throws {
30+
let errors = try assertInvalid(
31+
errorCount: 3,
32+
query:
33+
"""
34+
query Foo($var: [JumbledUpLetters!]!) {
35+
user(id: 4) {
36+
name
37+
pets { ... on Badger { name }, ...PetFields }
38+
}
39+
}
40+
fragment PetFields on Peat {
41+
name
42+
}
43+
"""
44+
)
45+
try assertValidationError(
46+
error: errors[0],
47+
locations: [(line: 1, column: 18)],
48+
message: "Unknown type \"JumbledUpLetters\"."
49+
)
50+
try assertValidationError(
51+
error: errors[1],
52+
locations: [(line: 4, column: 19)],
53+
message: "Unknown type \"Badger\"."
54+
)
55+
try assertValidationError(
56+
error: errors[2],
57+
locations: [(line: 7, column: 23)],
58+
message: "Unknown type \"Peat\". Did you mean \"Pet\" or \"Cat\"?"
59+
)
60+
}
61+
}

0 commit comments

Comments
 (0)