noUnusedFragmentsRule function

Visitor noUnusedFragmentsRule(
  1. SDLValidationCtx context
)

No unused fragments

A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.

See https://spec.graphql.org/draft/#sec-Fragments-Must-Be-Used

Implementation

Visitor noUnusedFragmentsRule(
  SDLValidationCtx context, // ASTValidationContext
) {
  final visitor = TypedVisitor();
  final operationDefs = <OperationDefinitionNode>[];
  final fragmentDefs = <FragmentDefinitionNode>[];

  visitor.add<OperationDefinitionNode>((node) {
    operationDefs.add(node);
    return VisitBehavior.skipTree;
  });

  visitor.add<FragmentDefinitionNode>((node) {
    fragmentDefs.add(node);
    return VisitBehavior.skipTree;
  });
  visitor.add<DocumentNode>(
    (_) {},
    leave: (_) {
      final fragmentNameUsed = <String>{};
      for (final operation in operationDefs) {
        for (final fragment in context.getRecursivelyReferencedFragments(
          operation,
        )) {
          fragmentNameUsed.add(fragment.name.value);
        }
      }

      for (final fragmentDef in fragmentDefs) {
        final fragName = fragmentDef.name.value;
        if (!fragmentNameUsed.contains(fragName)) {
          context.reportError(
            GraphQLError(
              'Fragment "${fragName}" is never used.',
              locations: GraphQLErrorLocation.firstFromNodes(
                  [fragmentDef, fragmentDef.name]),
              extensions: _noUnusedFragmentsSpec.extensions(),
            ),
          );
        }
      }
    },
  );

  return visitor;
}