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);
}