Skip to content

Commit e6acb6e

Browse files
committed
Suppressed invalid directives validation (#353)
1 parent b43d3b6 commit e6acb6e

File tree

1 file changed

+105
-91
lines changed

1 file changed

+105
-91
lines changed

src/main/com/intellij/lang/jsgraphql/ide/GraphQLValidationAnnotator.java

Lines changed: 105 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
public class GraphQLValidationAnnotator implements Annotator {
6767

6868
private static final Key<List<? extends GraphQLError>> ERRORS = Key.create(GraphQLValidationAnnotator.class.getName() + ".errors");
69-
private static final Key<Editor> EDITOR = Key.create(GraphQLValidationAnnotator.class.getName() + ".editor");
7069

7170
@Override
7271
public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder annotationHolder) {
@@ -245,108 +244,123 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
245244
session.putUserData(ERRORS, Collections.emptyList());
246245
}
247246

248-
if (userData != null) {
249-
for (GraphQLError userDatum : userData) {
250-
if (userDatum instanceof ValidationError) {
251-
final ValidationError validationError = (ValidationError) userDatum;
252-
final ValidationErrorType validationErrorType = validationError.getValidationErrorType();
253-
if (validationErrorType != null) {
254-
switch (validationErrorType) {
255-
case DefaultForNonNullArgument:
256-
case WrongType:
257-
case SubSelectionRequired:
258-
case SubSelectionNotAllowed:
259-
case BadValueForDefaultArg:
260-
case InlineFragmentTypeConditionInvalid:
261-
case FragmentTypeConditionInvalid:
262-
case UnknownArgument:
263-
case NonInputTypeOnVariable:
264-
case MissingFieldArgument:
265-
case MissingDirectiveArgument:
266-
case VariableTypeMismatch:
267-
case MisplacedDirective:
268-
case UndefinedVariable:
269-
case UnusedVariable:
270-
case FragmentCycle:
271-
case FieldsConflict:
272-
case InvalidFragmentType:
273-
case LoneAnonymousOperationViolation:
274-
for (SourceLocation location : validationError.getLocations()) {
275-
final int positionToOffset = getOffsetFromSourceLocation(containingFile, location);
276-
if (positionToOffset == -1) {
277-
continue;
278-
}
279-
int injectionOffset = 0;
280-
if (containingFile.getContext() != null) {
281-
injectionOffset = containingFile.getContext().getTextOffset();
247+
if (userData == null) {
248+
return;
249+
}
250+
251+
for (GraphQLError userDatum : userData) {
252+
if (!(userDatum instanceof ValidationError)) {
253+
continue;
254+
}
255+
256+
final ValidationError validationError = (ValidationError) userDatum;
257+
final ValidationErrorType validationErrorType = validationError.getValidationErrorType();
258+
if (validationErrorType == null) {
259+
continue;
260+
}
261+
262+
switch (validationErrorType) {
263+
case DefaultForNonNullArgument:
264+
case WrongType:
265+
case SubSelectionRequired:
266+
case SubSelectionNotAllowed:
267+
case BadValueForDefaultArg:
268+
case InlineFragmentTypeConditionInvalid:
269+
case FragmentTypeConditionInvalid:
270+
case UnknownArgument:
271+
case NonInputTypeOnVariable:
272+
case MissingFieldArgument:
273+
case MissingDirectiveArgument:
274+
case VariableTypeMismatch:
275+
case MisplacedDirective:
276+
case UndefinedVariable:
277+
case UnusedVariable:
278+
case FragmentCycle:
279+
case FieldsConflict:
280+
case InvalidFragmentType:
281+
case LoneAnonymousOperationViolation:
282+
for (SourceLocation location : validationError.getLocations()) {
283+
final int positionToOffset = getOffsetFromSourceLocation(containingFile, location);
284+
if (positionToOffset == -1) {
285+
continue;
286+
}
287+
int injectionOffset = 0;
288+
if (containingFile.getContext() != null) {
289+
injectionOffset = containingFile.getContext().getTextOffset();
290+
}
291+
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset - injectionOffset);
292+
if (errorPsiElement == null) {
293+
continue;
294+
}
295+
296+
if (isIgnored(validationErrorType, errorPsiElement)) {
297+
continue;
298+
}
299+
300+
final IElementType elementType = errorPsiElement.getNode().getElementType();
301+
if (elementType == GraphQLElementTypes.SPREAD) {
302+
// graphql-java uses the '...' as source location on fragments, so find the fragment name or type condition
303+
final GraphQLFragmentSelection fragmentSelection = PsiTreeUtil.getParentOfType(errorPsiElement, GraphQLFragmentSelection.class);
304+
if (fragmentSelection != null) {
305+
if (fragmentSelection.getFragmentSpread() != null) {
306+
errorPsiElement = fragmentSelection.getFragmentSpread().getNameIdentifier();
307+
} else if (fragmentSelection.getInlineFragment() != null) {
308+
final GraphQLTypeCondition typeCondition = fragmentSelection.getInlineFragment().getTypeCondition();
309+
if (typeCondition != null) {
310+
errorPsiElement = typeCondition.getTypeName();
282311
}
283-
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset - injectionOffset);
284-
if (errorPsiElement != null) {
285-
final IElementType elementType = errorPsiElement.getNode().getElementType();
286-
if (elementType == GraphQLElementTypes.SPREAD) {
287-
// graphql-java uses the '...' as source location on fragments, so find the fragment name or type condition
288-
final GraphQLFragmentSelection fragmentSelection = PsiTreeUtil.getParentOfType(errorPsiElement, GraphQLFragmentSelection.class);
289-
if (fragmentSelection != null) {
290-
if (fragmentSelection.getFragmentSpread() != null) {
291-
errorPsiElement = fragmentSelection.getFragmentSpread().getNameIdentifier();
292-
} else if (fragmentSelection.getInlineFragment() != null) {
293-
final GraphQLTypeCondition typeCondition = fragmentSelection.getInlineFragment().getTypeCondition();
294-
if (typeCondition != null) {
295-
errorPsiElement = typeCondition.getTypeName();
296-
}
297-
}
298-
}
299-
} else if (elementType == GraphQLElementTypes.AT) {
300-
// mark the directive and not only the '@'
301-
if (validationErrorType == ValidationErrorType.MisplacedDirective) {
302-
// graphql-java KnownDirectives rule only recognizes executable directive locations, so ignore
303-
// the error if we're inside a type definition
304-
if (PsiTreeUtil.getTopmostParentOfType(errorPsiElement, GraphQLTypeSystemDefinition.class) != null) {
305-
continue;
306-
}
307-
}
308-
errorPsiElement = errorPsiElement.getParent();
309-
}
310-
if (errorPsiElement != null) {
311-
if (isInsideTemplateElement(errorPsiElement)) {
312-
// error due to template placeholder replacement, so we can ignore it for '___' replacement variables
313-
if (validationErrorType == ValidationErrorType.UndefinedVariable) {
314-
continue;
315-
}
316-
}
317-
if (validationErrorType == ValidationErrorType.SubSelectionRequired) {
318-
// apollo client 2.5 doesn't require sub selections for client fields
319-
final GraphQLDirectivesAware directivesAware = PsiTreeUtil.getParentOfType(errorPsiElement, GraphQLDirectivesAware.class);
320-
if (directivesAware != null) {
321-
boolean ignoreError = false;
322-
for (GraphQLDirective directive : directivesAware.getDirectives()) {
323-
if ("client".equals(directive.getName())) {
324-
ignoreError = true;
325-
}
326-
}
327-
if (ignoreError) {
328-
continue;
329-
}
330-
}
331-
}
332-
final String message = Optional.ofNullable(validationError.getDescription()).orElse(validationError.getMessage());
333-
createErrorAnnotation(annotationHolder, errorPsiElement, message);
312+
}
313+
}
314+
} else if (elementType == GraphQLElementTypes.AT) {
315+
// mark the directive and not only the '@'
316+
errorPsiElement = errorPsiElement.getParent();
317+
}
318+
if (errorPsiElement != null) {
319+
if (isInsideTemplateElement(errorPsiElement)) {
320+
// error due to template placeholder replacement, so we can ignore it for '___' replacement variables
321+
if (validationErrorType == ValidationErrorType.UndefinedVariable) {
322+
continue;
323+
}
324+
}
325+
if (validationErrorType == ValidationErrorType.SubSelectionRequired) {
326+
// apollo client 2.5 doesn't require sub selections for client fields
327+
final GraphQLDirectivesAware directivesAware = PsiTreeUtil.getParentOfType(errorPsiElement, GraphQLDirectivesAware.class);
328+
if (directivesAware != null) {
329+
boolean ignoreError = false;
330+
for (GraphQLDirective directive : directivesAware.getDirectives()) {
331+
if ("client".equals(directive.getName())) {
332+
ignoreError = true;
334333
}
335334
}
335+
if (ignoreError) {
336+
continue;
337+
}
336338
}
337-
break;
338-
default:
339-
// remaining rules are handled above using psi references
340-
break;
339+
}
340+
final String message = Optional.ofNullable(validationError.getDescription()).orElse(validationError.getMessage());
341+
createErrorAnnotation(annotationHolder, errorPsiElement, message);
341342
}
342343
}
343-
}
344+
break;
345+
default:
346+
// remaining rules are handled above using psi references
347+
break;
344348
}
345349
}
346350

347351
}
348352
}
349353

354+
private static boolean isIgnored(@NotNull ValidationErrorType errorType, @NotNull PsiElement element) {
355+
if (errorType == ValidationErrorType.MisplacedDirective) {
356+
// graphql-java KnownDirectives rule only recognizes executable directive locations, so ignore
357+
// the error if we're inside a type definition
358+
return PsiTreeUtil.getParentOfType(element, GraphQLTypeSystemDefinition.class) != null;
359+
}
360+
361+
return false;
362+
}
363+
350364
/**
351365
* Gets whether the specified element is inside a placeholder in a template
352366
*/

0 commit comments

Comments
 (0)