Skip to content

Commit 3f1f9f5

Browse files
committed
[RFC] Type condition optional on inline fragments.
Implements graphql/graphql-spec#100
1 parent 529257b commit 3f1f9f5

File tree

11 files changed

+75
-15
lines changed

11 files changed

+75
-15
lines changed

src/execution/execute.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,11 @@ function doesFragmentConditionMatch(
430430
fragment: FragmentDefinition | InlineFragment,
431431
type: GraphQLObjectType
432432
): boolean {
433-
var conditionalType = typeFromAST(exeContext.schema, fragment.typeCondition);
433+
var typeConditionAST = fragment.typeCondition;
434+
if (!typeConditionAST) {
435+
return true;
436+
}
437+
var conditionalType = typeFromAST(exeContext.schema, typeConditionAST);
434438
if (conditionalType === type) {
435439
return true;
436440
}

src/language/__tests__/kitchen-sink.graphql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ query queryName($foo: ComplexType, $site: Site = MOBILE) {
1717
}
1818
}
1919
}
20+
... @skip(unless: $foo) {
21+
id
22+
}
23+
... {
24+
id
25+
}
2026
}
2127
}
2228

src/language/__tests__/printer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ describe('Printer', () => {
5959
}
6060
}
6161
}
62+
... @skip(unless: $foo) {
63+
id
64+
}
65+
... {
66+
id
67+
}
6268
}
6369
}
6470

src/language/__tests__/visitor.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,34 @@ describe('Visitor', () => {
321321
[ 'leave', 'Field', 0, undefined ],
322322
[ 'leave', 'SelectionSet', 'selectionSet', 'InlineFragment' ],
323323
[ 'leave', 'InlineFragment', 1, undefined ],
324+
[ 'enter', 'InlineFragment', 2, undefined ],
325+
[ 'enter', 'Directive', 0, undefined ],
326+
[ 'enter', 'Name', 'name', 'Directive' ],
327+
[ 'leave', 'Name', 'name', 'Directive' ],
328+
[ 'enter', 'Argument', 0, undefined ],
329+
[ 'enter', 'Name', 'name', 'Argument' ],
330+
[ 'leave', 'Name', 'name', 'Argument' ],
331+
[ 'enter', 'Variable', 'value', 'Argument' ],
332+
[ 'enter', 'Name', 'name', 'Variable' ],
333+
[ 'leave', 'Name', 'name', 'Variable' ],
334+
[ 'leave', 'Variable', 'value', 'Argument' ],
335+
[ 'leave', 'Argument', 0, undefined ],
336+
[ 'leave', 'Directive', 0, undefined ],
337+
[ 'enter', 'SelectionSet', 'selectionSet', 'InlineFragment' ],
338+
[ 'enter', 'Field', 0, undefined ],
339+
[ 'enter', 'Name', 'name', 'Field' ],
340+
[ 'leave', 'Name', 'name', 'Field' ],
341+
[ 'leave', 'Field', 0, undefined ],
342+
[ 'leave', 'SelectionSet', 'selectionSet', 'InlineFragment' ],
343+
[ 'leave', 'InlineFragment', 2, undefined ],
344+
[ 'enter', 'InlineFragment', 3, undefined ],
345+
[ 'enter', 'SelectionSet', 'selectionSet', 'InlineFragment' ],
346+
[ 'enter', 'Field', 0, undefined ],
347+
[ 'enter', 'Name', 'name', 'Field' ],
348+
[ 'leave', 'Name', 'name', 'Field' ],
349+
[ 'leave', 'Field', 0, undefined ],
350+
[ 'leave', 'SelectionSet', 'selectionSet', 'InlineFragment' ],
351+
[ 'leave', 'InlineFragment', 3, undefined ],
324352
[ 'leave', 'SelectionSet', 'selectionSet', 'Field' ],
325353
[ 'leave', 'Field', 0, undefined ],
326354
[ 'leave', 'SelectionSet', 'selectionSet', 'OperationDefinition' ],

src/language/ast.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export type FragmentSpread = {
142142
export type InlineFragment = {
143143
kind: 'InlineFragment';
144144
loc?: ?Location;
145-
typeCondition: NamedType;
145+
typeCondition?: ?NamedType;
146146
directives?: ?Array<Directive>;
147147
selectionSet: SelectionSet;
148148
}

src/language/parser.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,25 +377,29 @@ function parseArgument(parser): Argument {
377377
*
378378
* FragmentSpread : ... FragmentName Directives?
379379
*
380-
* InlineFragment : ... on TypeCondition Directives? SelectionSet
380+
* InlineFragment : ... TypeCondition? Directives? SelectionSet
381381
*/
382382
function parseFragment(parser): FragmentSpread | InlineFragment {
383383
var start = parser.token.start;
384384
expect(parser, TokenKind.SPREAD);
385-
if (parser.token.value === 'on') {
386-
advance(parser);
385+
if (peek(parser, TokenKind.NAME) && parser.token.value !== 'on') {
387386
return {
388-
kind: INLINE_FRAGMENT,
389-
typeCondition: parseNamedType(parser),
387+
kind: FRAGMENT_SPREAD,
388+
name: parseFragmentName(parser),
390389
directives: parseDirectives(parser),
391-
selectionSet: parseSelectionSet(parser),
392390
loc: loc(parser, start)
393391
};
394392
}
393+
var typeCondition = null;
394+
if (parser.token.value === 'on') {
395+
advance(parser);
396+
typeCondition = parseNamedType(parser);
397+
}
395398
return {
396-
kind: FRAGMENT_SPREAD,
397-
name: parseFragmentName(parser),
399+
kind: INLINE_FRAGMENT,
400+
typeCondition,
398401
directives: parseDirectives(parser),
402+
selectionSet: parseSelectionSet(parser),
399403
loc: loc(parser, start)
400404
};
401405
}

src/language/printer.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ var printDocASTReducer = {
5555
'...' + name + wrap(' ', join(directives, ' ')),
5656

5757
InlineFragment: ({ typeCondition, directives, selectionSet }) =>
58-
`... on ${typeCondition} ` +
59-
wrap('', join(directives, ' '), ' ') +
60-
selectionSet,
58+
join([
59+
'...',
60+
wrap('on ', typeCondition),
61+
join(directives, ' '),
62+
selectionSet
63+
], ' '),
6164

6265
FragmentDefinition: ({ name, typeCondition, directives, selectionSet }) =>
6366
`fragment ${name} on ${typeCondition} ` +

src/utilities/TypeInfo.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ export class TypeInfo {
132132
break;
133133
case Kind.INLINE_FRAGMENT:
134134
case Kind.FRAGMENT_DEFINITION:
135-
type = typeFromAST(schema, node.typeCondition);
135+
var typeConditionAST = node.typeCondition;
136+
type = typeConditionAST ?
137+
typeFromAST(schema, typeConditionAST) :
138+
this.getType();
136139
this._typeStack.push(type);
137140
break;
138141
case Kind.VARIABLE_DEFINITION:

src/validation/__tests__/FieldsOnCorrectType.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ describe('Validate: Fields on correct type', () => {
185185
... on Dog {
186186
name
187187
}
188+
... {
189+
name
190+
}
188191
}
189192
`);
190193
});

src/validation/__tests__/KnownFragmentNames.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ describe('Validate: Known fragment names', () => {
3232
... on Human {
3333
...HumanFields2
3434
}
35+
... {
36+
name
37+
}
3538
}
3639
}
3740
fragment HumanFields1 on Human {

src/validation/__tests__/KnownTypeNames.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('Validate: Known type names', () => {
2828
expectPassesRule(KnownTypeNames, `
2929
query Foo($var: String, $required: [String!]!) {
3030
user(id: 4) {
31-
pets { ... on Pet { name }, ...PetFields }
31+
pets { ... on Pet { name }, ...PetFields, ... { name } }
3232
}
3333
}
3434
fragment PetFields on Pet {

0 commit comments

Comments
 (0)