Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/validation/__tests__/FieldsOnCorrectType.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ describe('Validate: Fields on correct type', () => {
`);
});

it('reports errors when type is known again', () => {
expectFailsRule(FieldsOnCorrectType, `
fragment typeKnownAgain on Pet {
unknown_pet_field {
... on Cat {
unknown_cat_field
}
}
}`,
[ undefinedField('unknown_pet_field', 'Pet', 3, 9),
undefinedField('unknown_cat_field', 'Cat', 5, 13) ]
);
});

it('Field not defined on fragment', () => {
expectFailsRule(FieldsOnCorrectType, `
fragment fieldNotDefined on Dog {
Expand All @@ -84,7 +98,7 @@ describe('Validate: Fields on correct type', () => {
);
});

it('Field not defined deeply, only reports first', () => {
it('Ignores deeply unknown field', () => {
expectFailsRule(FieldsOnCorrectType, `
fragment deepFieldNotDefined on Dog {
unknown_field {
Expand Down
4 changes: 3 additions & 1 deletion src/validation/__tests__/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ describe('Validate: Supports full validation', () => {
);

expect(errors).to.deep.equal([
{ message: 'Cannot query field "catOrDog" on "QueryRoot".' }
{ message: 'Cannot query field "catOrDog" on "QueryRoot".' },
{ message: 'Cannot query field "furColor" on "Cat".' },
{ message: 'Cannot query field "isHousetrained" on "Dog".' }
]);
});

Expand Down
4 changes: 2 additions & 2 deletions src/validation/rules/ArgumentsOfCorrectType.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ export function ArgumentsOfCorrectType(context: ValidationContext): any {
Argument(argAST) {
var argDef = context.getArgument();
if (argDef && !isValidLiteralValue(argDef.type, argAST.value)) {
return new GraphQLError(
context.reportError(new GraphQLError(
badValueMessage(
argAST.name.value,
argDef.type,
print(argAST.value)
),
[ argAST.value ]
);
));
}
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions src/validation/rules/DefaultValuesOfCorrectType.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ export function DefaultValuesOfCorrectType(context: ValidationContext): any {
var defaultValue = varDefAST.defaultValue;
var type = context.getInputType();
if (type instanceof GraphQLNonNull && defaultValue) {
return new GraphQLError(
context.reportError(new GraphQLError(
defaultForNonNullArgMessage(name, type, type.ofType),
[ defaultValue ]
);
));
}
if (type && defaultValue && !isValidLiteralValue(type, defaultValue)) {
return new GraphQLError(
context.reportError(new GraphQLError(
badValueForDefaultArgMessage(name, type, print(defaultValue)),
[ defaultValue ]
);
));
}
return false;
},
Expand Down
4 changes: 2 additions & 2 deletions src/validation/rules/FieldsOnCorrectType.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ export function FieldsOnCorrectType(context: ValidationContext): any {
if (type) {
var fieldDef = context.getFieldDef();
if (!fieldDef) {
return new GraphQLError(
context.reportError(new GraphQLError(
undefinedFieldMessage(node.name.value, type.name),
[ node ]
);
));
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/validation/rules/FragmentsOnCompositeTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,22 @@ export function FragmentsOnCompositeTypes(context: ValidationContext): any {
InlineFragment(node) {
var type = context.getType();
if (node.typeCondition && type && !isCompositeType(type)) {
return new GraphQLError(
context.reportError(new GraphQLError(
inlineFragmentOnNonCompositeErrorMessage(print(node.typeCondition)),
[ node.typeCondition ]
);
));
}
},
FragmentDefinition(node) {
var type = context.getType();
if (type && !isCompositeType(type)) {
return new GraphQLError(
context.reportError(new GraphQLError(
fragmentOnNonCompositeErrorMessage(
node.name.value,
print(node.typeCondition)
),
[ node.typeCondition ]
);
));
}
}
};
Expand Down
8 changes: 4 additions & 4 deletions src/validation/rules/KnownArgumentNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ export function KnownArgumentNames(context: ValidationContext): any {
if (!fieldArgDef) {
var parentType = context.getParentType();
invariant(parentType);
return new GraphQLError(
context.reportError(new GraphQLError(
unknownArgMessage(
node.name.value,
fieldDef.name,
parentType.name
),
[ node ]
);
));
}
}
} else if (argumentOf.kind === DIRECTIVE) {
Expand All @@ -72,10 +72,10 @@ export function KnownArgumentNames(context: ValidationContext): any {
arg => arg.name === node.name.value
);
if (!directiveArgDef) {
return new GraphQLError(
context.reportError(new GraphQLError(
unknownDirectiveArgMessage(node.name.value, directive.name),
[ node ]
);
));
}
}
}
Expand Down
55 changes: 31 additions & 24 deletions src/validation/rules/KnownDirectives.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,33 +45,40 @@ export function KnownDirectives(context: ValidationContext): any {
def => def.name === node.name.value
);
if (!directiveDef) {
return new GraphQLError(
context.reportError(new GraphQLError(
unknownDirectiveMessage(node.name.value),
[ node ]
);
));
return;
}
var appliedTo = ancestors[ancestors.length - 1];
if (appliedTo.kind === OPERATION_DEFINITION &&
!directiveDef.onOperation) {
return new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'operation'),
[ node ]
);
}
if (appliedTo.kind === FIELD && !directiveDef.onField) {
return new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'field'),
[ node ]
);
}
if ((appliedTo.kind === FRAGMENT_SPREAD ||
appliedTo.kind === INLINE_FRAGMENT ||
appliedTo.kind === FRAGMENT_DEFINITION) &&
!directiveDef.onFragment) {
return new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'fragment'),
[ node ]
);
const appliedTo = ancestors[ancestors.length - 1];
switch (appliedTo.kind) {
case OPERATION_DEFINITION:
if (!directiveDef.onOperation) {
context.reportError(new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'operation'),
[ node ]
));
}
break;
case FIELD:
if (!directiveDef.onField) {
context.reportError(new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'field'),
[ node ]
));
}
break;
case FRAGMENT_SPREAD:
case INLINE_FRAGMENT:
case FRAGMENT_DEFINITION:
if (!directiveDef.onFragment) {
context.reportError(new GraphQLError(
misplacedDirectiveMessage(node.name.value, 'fragment'),
[ node ]
));
}
break;
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/validation/rules/KnownFragmentNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export function KnownFragmentNames(context: ValidationContext): any {
var fragmentName = node.name.value;
var fragment = context.getFragment(fragmentName);
if (!fragment) {
return new GraphQLError(
context.reportError(new GraphQLError(
unknownFragmentMessage(fragmentName),
[ node.name ]
);
));
}
}
};
Expand Down
4 changes: 3 additions & 1 deletion src/validation/rules/KnownTypeNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export function KnownTypeNames(context: ValidationContext): any {
var typeName = node.name.value;
var type = context.getSchema().getType(typeName);
if (!type) {
return new GraphQLError(unknownTypeMessage(typeName), [ node ]);
context.reportError(
new GraphQLError(unknownTypeMessage(typeName), [ node ])
);
}
}
};
Expand Down
7 changes: 5 additions & 2 deletions src/validation/rules/LoneAnonymousOperation.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

import type { ValidationContext } from '../index';
import { GraphQLError } from '../../error';
import { OPERATION_DEFINITION } from '../../language/kinds';

Expand All @@ -22,7 +23,7 @@ export function anonOperationNotAloneMessage(): string {
* A GraphQL document is only valid if when it contains an anonymous operation
* (the query short-hand) that it contains only that one operation definition.
*/
export function LoneAnonymousOperation(): any {
export function LoneAnonymousOperation(context: ValidationContext): any {
var operationCount = 0;
return {
Document(node) {
Expand All @@ -32,7 +33,9 @@ export function LoneAnonymousOperation(): any {
},
OperationDefinition(node) {
if (!node.name && operationCount > 1) {
return new GraphQLError(anonOperationNotAloneMessage(), [ node ]);
context.reportError(
new GraphQLError(anonOperationNotAloneMessage(), [ node ])
);
}
}
};
Expand Down
11 changes: 1 addition & 10 deletions src/validation/rules/NoFragmentCycles.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ export function cycleErrorMessage(
}

export function NoFragmentCycles(context: ValidationContext): any {
var errors = [];

// Tracks already visited fragments to maintain O(N) and to ensure that cycles
// are not redundantly reported.
var visitedFrags = Object.create(null);
Expand All @@ -35,13 +33,6 @@ export function NoFragmentCycles(context: ValidationContext): any {
var spreadPathIndexByName = Object.create(null);

return {
Document: {
leave() {
if (errors.length) {
return errors;
}
}
},
OperationDefinition: () => false,
FragmentDefinition(node) {
if (!visitedFrags[node.name.value]) {
Expand Down Expand Up @@ -81,7 +72,7 @@ export function NoFragmentCycles(context: ValidationContext): any {
spreadPath.pop();
} else {
const cyclePath = spreadPath.slice(cycleIndex);
errors.push(new GraphQLError(
context.reportError(new GraphQLError(
cycleErrorMessage(
spreadName,
cyclePath.map(s => s.name.value)
Expand Down
21 changes: 7 additions & 14 deletions src/validation/rules/NoUndefinedVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,19 @@ export function NoUndefinedVariables(context: ValidationContext): any {
},
leave(operation) {
const usages = context.getRecursiveVariableUsages(operation);
const errors = [];

usages.forEach(({ node }) => {
var varName = node.name.value;
if (variableNameDefined[varName] !== true) {
errors.push(
new GraphQLError(
undefinedVarMessage(
varName,
operation.name && operation.name.value
),
[ node, operation ]
)
);
context.reportError(new GraphQLError(
undefinedVarMessage(
varName,
operation.name && operation.name.value
),
[ node, operation ]
));
}
});

if (errors.length > 0) {
return errors;
}
}
},
VariableDefinition(varDefAST) {
Expand Down
18 changes: 9 additions & 9 deletions src/validation/rules/NoUnusedFragments.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ export function NoUnusedFragments(context: ValidationContext): any {
);
});

var errors = fragmentDefs
.filter(def => fragmentNameUsed[def.name.value] !== true)
.map(def => new GraphQLError(
unusedFragMessage(def.name.value),
[ def ]
));
if (errors.length > 0) {
return errors;
}
fragmentDefs.forEach(fragmentDef => {
const fragName = fragmentDef.name.value;
if (fragmentNameUsed[fragName] !== true) {
context.reportError(new GraphQLError(
unusedFragMessage(fragName),
[ fragmentDef ]
));
}
});
}
}
};
Expand Down
19 changes: 9 additions & 10 deletions src/validation/rules/NoUnusedVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,22 @@ export function NoUnusedVariables(context: ValidationContext): any {
variableDefs = [];
},
leave(operation) {

const variableNameUsed = Object.create(null);
const usages = context.getRecursiveVariableUsages(operation);

usages.forEach(({ node }) => {
variableNameUsed[node.name.value] = true;
});

var errors = variableDefs
.filter(def => variableNameUsed[def.variable.name.value] !== true)
.map(def => new GraphQLError(
unusedVariableMessage(def.variable.name.value),
[ def ]
));
if (errors.length > 0) {
return errors;
}
variableDefs.forEach(variableDef => {
const variableName = variableDef.variable.name.value;
if (variableNameUsed[variableName] !== true) {
context.reportError(new GraphQLError(
unusedVariableMessage(variableName),
[ variableDef ]
));
}
});
}
},
VariableDefinition(def) {
Expand Down
Loading