Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/utilities/TypeInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export class TypeInfo {
const listType: unknown = getNullableType(this.getInputType());
const itemType: unknown = isListType(listType)
? listType.ofType
: listType;
: undefined;
// List positions never have a default value.
this._defaultValueStack.push(undefined);
this._inputTypeStack.push(isInputType(itemType) ? itemType : undefined);
Expand Down
104 changes: 102 additions & 2 deletions src/utilities/__tests__/TypeInfo-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,10 @@ describe('visitWithTypeInfo', () => {
['enter', 'ObjectField', null, '[String]'],
['enter', 'Name', 'stringListField', '[String]'],
['leave', 'Name', 'stringListField', '[String]'],
['enter', 'ListValue', null, 'String'],
['enter', 'ListValue', null, 'String' /* the item type, not list type */],
['enter', 'StringValue', null, 'String'],
['leave', 'StringValue', null, 'String'],
['leave', 'ListValue', null, 'String'],
['leave', 'ListValue', null, 'String' /* the item type, not list type */],
['leave', 'ObjectField', null, '[String]'],
['leave', 'ObjectValue', null, 'ComplexInput'],
]);
Expand Down Expand Up @@ -457,4 +457,104 @@ describe('visitWithTypeInfo', () => {
['leave', 'SelectionSet', null, 'Human', 'Human'],
]);
});

it('supports traversals of object literals of custom scalars', () => {
const schema = buildSchema(`
scalar GeoPoint
`);
const ast = parseValue('{x: 4.0, y: 2.0}');
const scalarType = schema.getType('GeoPoint');
invariant(scalarType != null);

const typeInfo = new TypeInfo(schema, scalarType);

const visited: Array<any> = [];
visit(
ast,
visitWithTypeInfo(typeInfo, {
enter(node) {
const type = typeInfo.getInputType();
visited.push([
'enter',
node.kind,
node.kind === 'Name' ? node.value : null,
String(type),
]);
},
leave(node) {
const type = typeInfo.getInputType();
visited.push([
'leave',
node.kind,
node.kind === 'Name' ? node.value : null,
String(type),
]);
},
}),
);

expect(visited).to.deep.equal([
// Everything within ObjectValue should have type: undefined since the
// contents of custom scalars aren't part of GraphQL schema definitions.
['enter', 'ObjectValue', null, 'GeoPoint'],
['enter', 'ObjectField', null, 'undefined'],
['enter', 'Name', 'x', 'undefined'],
['leave', 'Name', 'x', 'undefined'],
['enter', 'FloatValue', null, 'undefined'],
['leave', 'FloatValue', null, 'undefined'],
['leave', 'ObjectField', null, 'undefined'],
['enter', 'ObjectField', null, 'undefined'],
['enter', 'Name', 'y', 'undefined'],
['leave', 'Name', 'y', 'undefined'],
['enter', 'FloatValue', null, 'undefined'],
['leave', 'FloatValue', null, 'undefined'],
['leave', 'ObjectField', null, 'undefined'],
['leave', 'ObjectValue', null, 'GeoPoint'],
]);
});

it('supports traversals of list literals of custom scalars', () => {
const schema = buildSchema(`
scalar GeoPoint
`);
const ast = parseValue('[4.0, 2.0]');
const scalarType = schema.getType('GeoPoint');
invariant(scalarType != null);

const typeInfo = new TypeInfo(schema, scalarType);

const visited: Array<any> = [];
visit(
ast,
visitWithTypeInfo(typeInfo, {
enter(node) {
const type = typeInfo.getInputType();
visited.push([
'enter',
node.kind,
node.kind === 'Name' ? node.value : null,
String(type),
]);
},
leave(node) {
const type = typeInfo.getInputType();
visited.push([
'leave',
node.kind,
node.kind === 'Name' ? node.value : null,
String(type),
]);
},
}),
);

expect(visited).to.deep.equal([
['enter', 'ListValue', null, 'undefined'],
['enter', 'FloatValue', null, 'undefined'],
['leave', 'FloatValue', null, 'undefined'],
['enter', 'FloatValue', null, 'undefined'],
['leave', 'FloatValue', null, 'undefined'],
['leave', 'ListValue', null, 'undefined'],
]);
});
});
77 changes: 77 additions & 0 deletions src/validation/__tests__/VariablesInAllowedPositionRule-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,81 @@ describe('Validates OneOf Input Objects', () => {
},
]);
});

it('Custom scalars as arg', () => {
expectValid(`
query Query($point: GeoPoint) {
dog {
distanceFrom(loc: $point)
}
}`);
});

it('Forbids using custom scalar as builtin arg', () => {
expectErrors(`
query Query($point: GeoPoint) {
dog {
isAtLocation(x: $point, y: 10)
}
}
`).toDeepEqual([
{
locations: [
{
column: 19,
line: 2,
},
{
column: 27,
line: 4,
},
],
message:
'Variable "$point" of type "GeoPoint" used in position expecting type "Int".',
},
]);
});

it('Forbids using builtin scalar as custom scalar arg', () => {
expectErrors(`
query Query($x: Float) {
dog {
distanceFrom(loc: $x)
}
}
`).toDeepEqual([
{
locations: [
{
column: 19,
line: 2,
},
{
column: 29,
line: 4,
},
],
message:
'Variable "$x" of type "Float" used in position expecting type "GeoPoint".',
},
]);
});

it('Allows using variables inside object literal in custom scalar', () => {
expectValid(`
query Query($x: Float) {
dog {
distanceFrom(loc: {x: $x, y: 10.0})
}
}`);
});

it('Allows using variables inside list literal in custom scalar', () => {
expectValid(`
query Query($x: Float) {
dog {
distanceFrom(loc: [$x, 10.0])
}
}`);
});
});
3 changes: 3 additions & 0 deletions src/validation/__tests__/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const testSchema: GraphQLSchema = buildSchema(`
DOWN
}

scalar GeoPoint

type Dog implements Pet & Mammal & Canine {
name(surname: Boolean): String
nickname: String
Expand All @@ -41,6 +43,7 @@ export const testSchema: GraphQLSchema = buildSchema(`
doesKnowCommand(dogCommand: DogCommand): Boolean
isHouseTrained(atOtherHomes: Boolean = true): Boolean
isAtLocation(x: Int, y: Int): Boolean
distanceFrom(loc: GeoPoint): Float
mother: Dog
father: Dog
}
Expand Down
Loading