private void completeFragmentOnTypeName()

in src/main/com/intellij/lang/jsgraphql/ide/completion/GraphQLCompletionContributor.java [795:891]


  private void completeFragmentOnTypeName() {
    CompletionProvider<CompletionParameters> provider = new CompletionProvider<>() {
      @Override
      protected void addCompletions(final @NotNull CompletionParameters parameters,
                                    @NotNull ProcessingContext context,
                                    @NotNull CompletionResultSet result) {

        final PsiElement completionElement = parameters.getPosition();

        // the type condition that the 'on' keyword belongs to
        GraphQLTypeCondition typeCondition = PsiTreeUtil.getParentOfType(completionElement, GraphQLTypeCondition.class);
        if (typeCondition == null) {
          // typeCondition is on the left if the selection set follows
          typeCondition = PsiTreeUtil.getPrevSiblingOfType(completionElement, GraphQLTypeCondition.class);
        }
        final boolean fragmentDefinition = typeCondition != null && typeCondition.getParent() instanceof GraphQLFragmentDefinition;

        final GraphQLRegistryProvider schemaProvider = GraphQLRegistryProvider.getInstance(completionElement.getProject());
        final TypeDefinitionRegistry typeDefinitionRegistry = schemaProvider
          .getRegistryInfo(parameters.getOriginalFile()).getTypeDefinitionRegistry();

        Set<TypeDefinition> fragmentTypes = new HashSet<>();

        if (fragmentDefinition) {
          // completion in a top-level fragment definition, so add all known types, interfaces, unions
          typeDefinitionRegistry.types().forEach((key, value) -> {
            final boolean isTypeCondition = value instanceof ObjectTypeDefinition ||
                                            value instanceof UnionTypeDefinition ||
                                            value instanceof InterfaceTypeDefinition;
            if (isTypeCondition) {
              fragmentTypes.add(value);
            }
          });
        }
        else {
          // inline fragment, so get type scope
          GraphQLTypeScopeProvider typeScopeProvider =
            PsiTreeUtil.getParentOfType(completionElement, GraphQLTypeScopeProvider.class);

          if (typeScopeProvider instanceof GraphQLInlineFragment &&
              ((GraphQLInlineFragment)typeScopeProvider).getTypeCondition() == typeCondition) {
            // if the type condition belongs to the type scope provider, we want the parent scope since that
            // is the real source of what we can fragment on
            typeScopeProvider = PsiTreeUtil.getParentOfType(typeScopeProvider, GraphQLTypeScopeProvider.class);
          }

          GraphQLType rawTypeScope = typeScopeProvider != null ? typeScopeProvider.getTypeScope() : null;
          if (rawTypeScope != null) {
            GraphQLUnmodifiedType typeScope = GraphQLSchemaUtil.getUnmodified(rawTypeScope);
            final TypeDefinition fragmentType = typeScope != null
                                                ? typeDefinitionRegistry.getType(typeScope.getName()).orElse(null)
                                                : null;
            if (fragmentType != null) {
              final Ref<Consumer<TypeDefinition<?>>> addTypesRecursive = new Ref<>();
              final Consumer<TypeDefinition<?>> addTypes = (typeToFragmentOn) -> {
                if (typeToFragmentOn instanceof ObjectTypeDefinition) {
                  fragmentTypes.add(typeToFragmentOn);
                  final List<Type> anImplements = ((ObjectTypeDefinition)typeToFragmentOn).getImplements();
                  if (anImplements != null) {
                    anImplements.forEach(type -> {
                      final TypeDefinition typeDefinition = typeDefinitionRegistry.getType(type).orElse(null);
                      if (typeDefinition instanceof InterfaceTypeDefinition) {
                        fragmentTypes.add(typeDefinition);
                      }
                    });
                  }
                }
                else if (typeToFragmentOn instanceof InterfaceTypeDefinition) {
                  fragmentTypes.add(typeToFragmentOn);
                  final List<ObjectTypeDefinition> implementationsOf = typeDefinitionRegistry
                    .getImplementationsOf((InterfaceTypeDefinition)typeToFragmentOn);
                  fragmentTypes.addAll(implementationsOf);
                }
                else if (typeToFragmentOn instanceof UnionTypeDefinition) {
                  final List<Type> memberTypes = ((UnionTypeDefinition)typeToFragmentOn).getMemberTypes();
                  if (memberTypes != null) {
                    memberTypes.forEach(memberType -> typeDefinitionRegistry.getType(memberType).ifPresent(
                      memberTypeDefinition -> addTypesRecursive.get().consume(memberTypeDefinition)));
                  }
                }
              };
              addTypesRecursive.set(addTypes);
              addTypes.consume(fragmentType);
            }
          }
        }

        fragmentTypes.forEach(fragmentType -> {
          String typeName = fragmentType.getName();
          if (isIgnoredType(typeName)) return;

          result.addElement(GraphQLCompletionUtil.createTypeNameLookupElement(typeName));
        });
      }
    };
    extend(CompletionType.BASIC, psiElement().afterLeaf(psiElement(GraphQLElementTypes.ON_KEYWORD)), provider);
  }