providedRequiredArgumentsOnDirectivesRule function
TypedVisitor
providedRequiredArgumentsOnDirectivesRule(
- SDLValidationCtx context
@internal
Implementation
TypedVisitor providedRequiredArgumentsOnDirectivesRule(
SDLValidationCtx context,
) {
final visitor = TypedVisitor();
final requiredArgsMap = <String, Map<String, Object>>{};
final schema = context.schema;
final definedDirectives =
schema?.directives ?? GraphQLDirective.specifiedDirectives;
for (final directive in definedDirectives) {
requiredArgsMap[directive.name] =
directive.inputs.where((arg) => arg.isRequired).groupFoldBy(
(element) => element.name,
(previous, element) => previous ?? element,
);
}
final astDefinitions =
context.document.definitions.whereType<DirectiveDefinitionNode>();
for (final def in astDefinitions) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
final argNodes = def.args;
requiredArgsMap[def.name.value] = argNodes
.where(_isRequiredArgumentNode)
.groupFoldBy((a) => a.name.value, (p, e) => p ?? e);
}
visitor.add<DirectiveNode>((_) {},
// Validate on leave to allow for deeper errors to appear first.
leave: (directiveNode) {
final directiveName = directiveNode.name.value;
final requiredArgs = requiredArgsMap[directiveName];
if (requiredArgs != null) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
final argNodes = directiveNode.arguments;
final argNodeMap = argNodes.map((arg) => arg.name.value).toSet();
for (final entry in requiredArgs.entries) {
if (!argNodeMap.contains(entry.key)) {
final arg = entry.value;
final argType = arg is GraphQLFieldInput
? inspect(arg.type)
: printNode((arg as InputValueDefinitionNode).type);
context.reportError(
GraphQLError(
'Directive "@${directiveName}" argument "${entry.key}" of'
' type "${argType}" is required, but it was not provided.',
locations: GraphQLErrorLocation.firstFromNodes(
[directiveNode, directiveNode.name]),
extensions:
_providedRequiredArgumentsOnDirectivesSpec.extensions(),
),
);
}
}
}
});
return visitor;
}