providedRequiredArgumentsOnDirectivesRule function

TypedVisitor providedRequiredArgumentsOnDirectivesRule(
  1. 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;
}