possibleTypeExtensionsRule function

Visitor possibleTypeExtensionsRule(
  1. SDLValidationCtx context
)

Possible type extension

A type extension is only valid if the type is defined and has the same kind.

See https://spec.graphql.org/draft/#sec-Schema

Implementation

Visitor possibleTypeExtensionsRule(
  SDLValidationCtx context,
) {
  final schema = context.schema;
  final definedTypes = <String, DefinitionNode>{};

  for (final def
      in context.document.definitions.whereType<TypeDefinitionNode>()) {
    definedTypes[def.name.value] = def;
  }

  VisitBehavior? checkExtension(TypeExtensionNode node) {
    final typeName = node.name.value;
    final defNode = definedTypes[typeName];
    final existingType = schema?.getType(typeName);

    Kind? expectedKind;
    if (defNode != null) {
      expectedKind = defKindToExtKind[defNode.kind];
    } else if (existingType != null) {
      expectedKind = typeToExtKind(existingType);
    }

    if (expectedKind != null) {
      if (expectedKind != node.kind) {
        final kindStr = extensionKindToTypeName(node.kind);
        context.reportError(
          GraphQLError(
            'Cannot extend non-${kindStr} type "${typeName}".',
            locations: [
              ...GraphQLErrorLocation.firstFromNodes([defNode]),
              GraphQLErrorLocation.fromSourceLocation(node.name.span!.start),
            ],
            extensions: _possibleTypeExtensionsSpec.extensions(),
          ),
        );
      }
    } else {
      // final allTypeNames = {
      //   ...definedTypes,
      //   if (schema != null) ...schema.typeMap,
      // };

      // final suggestedTypes = suggestionList(typeName, allTypeNames);
      context.reportError(
        GraphQLError(
          'Cannot extend type "${typeName}" because it is not defined.'
          // + didYouMean(suggestedTypes)
          ,
          locations: GraphQLErrorLocation.firstFromNodes([node.name]),
          extensions: _possibleTypeExtensionsSpec.extensions(),
        ),
      );
    }
  }

  final visitor = TypedVisitor();

  visitor.add<ScalarTypeExtensionNode>(checkExtension);
  visitor.add<ObjectTypeExtensionNode>(checkExtension);
  visitor.add<InterfaceTypeExtensionNode>(checkExtension);
  visitor.add<UnionTypeExtensionNode>(checkExtension);
  visitor.add<EnumTypeExtensionNode>(checkExtension);
  visitor.add<InputObjectTypeExtensionNode>(checkExtension);

  return visitor;
}