Skip to content

Commit 031d6c3

Browse files
feature: Adds ProvidedRequiredArgumentsRuleTests
1 parent 958cbea commit 031d6c3

File tree

5 files changed

+364
-66
lines changed

5 files changed

+364
-66
lines changed

Sources/GraphQL/Validation/Rules/ProvidedNonNullArgumentsRule.swift

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import Foundation
2+
3+
/**
4+
* Provided required arguments
5+
*
6+
* A field or directive is only valid if all required (non-null without a
7+
* default value) field arguments have been provided.
8+
*/
9+
func ProvidedRequiredArgumentsRule(context: ValidationContext) -> Visitor {
10+
var requiredArgsMap = [String: [String: String]]()
11+
12+
let schema = context.schema
13+
let definedDirectives = schema.directives
14+
for directive in definedDirectives {
15+
var requiredArgMap = [String: String]()
16+
directive.args.filter { arg in
17+
isRequiredArgument(arg)
18+
}.forEach { arg in
19+
requiredArgMap[arg.name] = "\(arg.type)"
20+
}
21+
requiredArgsMap[directive.name] = requiredArgMap
22+
}
23+
24+
let astDefinitions = context.ast.definitions
25+
for def in astDefinitions {
26+
if let directive = def as? DirectiveDefinition {
27+
var requiredArgMap = [String: String]()
28+
directive.arguments.filter { arg in
29+
isRequiredArgumentNode(arg)
30+
}.forEach { arg in
31+
requiredArgMap[arg.name.value] = "\(arg.type)"
32+
}
33+
34+
requiredArgsMap[directive.name.value] = requiredArgMap
35+
}
36+
}
37+
38+
return Visitor(
39+
leave: { node, _, _, _, _ in
40+
if let fieldNode = node as? Field {
41+
guard let fieldDef = context.fieldDef else {
42+
return .continue
43+
}
44+
45+
let providedArguments = Set(fieldNode.arguments.map { $0.name.value })
46+
47+
for argDef in fieldDef.args {
48+
if !providedArguments.contains(argDef.name), isRequiredArgument(argDef) {
49+
context.report(error: GraphQLError(
50+
message: "Field \"\(fieldDef.name)\" argument \"\(argDef.name)\" of type \"\(argDef.type)\" is required, but it was not provided.",
51+
nodes: [fieldNode]
52+
))
53+
}
54+
}
55+
}
56+
57+
if let directiveNode = node as? Directive {
58+
let directiveName = directiveNode.name.value
59+
60+
if let requiredArgs = requiredArgsMap[directiveName] {
61+
let argNodes = directiveNode.arguments
62+
let argNodeMap = Set(argNodes.map { $0.name.value })
63+
for (argName, argType) in requiredArgs {
64+
if !argNodeMap.contains(argName) {
65+
context.report(error: GraphQLError(
66+
message: "Directive \"@\(directiveName)\" argument \"\(argName)\" of type \"\(argType)\" is required, but it was not provided.",
67+
nodes: [directiveNode]
68+
))
69+
}
70+
}
71+
}
72+
}
73+
return .continue
74+
}
75+
)
76+
}
77+
78+
func isRequiredArgumentNode(_ arg: InputValueDefinition) -> Bool {
79+
return arg.type.kind == .nonNullType && arg.defaultValue == nil
80+
}

Sources/GraphQL/Validation/SpecifiedRules.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ public let specifiedRules: [(ValidationContext) -> Visitor] = [
2727
KnownArgumentNamesRule,
2828
UniqueArgumentNamesRule,
2929
ValuesOfCorrectTypeRule,
30-
// ProvidedRequiredArgumentsRule,
31-
ProvidedNonNullArgumentsRule,
30+
ProvidedRequiredArgumentsRule,
3231
VariablesInAllowedPositionRule,
3332
// OverlappingFieldsCanBeMergedRule,
3433
UniqueInputFieldNamesRule,

Tests/GraphQLTests/ValidationTests/ProvidedNonNullArgumentsTests.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)