Skip to content

Commit e1da711

Browse files
committed
Merge pull request #325 from graphql/schema-def
[RFC] Add Schema Definition to IDL.
2 parents 942f84e + 8379e71 commit e1da711

12 files changed

+509
-89
lines changed

src/language/__tests__/schema-kitchen-sink.graphql

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
# LICENSE file in the root directory of this source tree. An additional grant
66
# of patent rights can be found in the PATENTS file in the same directory.
77

8+
schema {
9+
query: QueryType
10+
mutation: MutationType
11+
}
12+
813
type Foo implements Bar {
914
one: Type
1015
two(argument: InputType!): Type

src/language/__tests__/schema-printer.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ describe('Printer', () => {
5151

5252
/* eslint-disable max-len */
5353
expect(printed).to.equal(
54-
`type Foo implements Bar {
54+
`schema {
55+
query: QueryType
56+
mutation: MutationType
57+
}
58+
59+
type Foo implements Bar {
5560
one: Type
5661
two(argument: InputType!): Type
5762
three(argument: InputType, other: String): Int

src/language/ast.js

+23-5
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ export type Node = Name
4747
| NamedType
4848
| ListType
4949
| NonNullType
50+
| SchemaDefinition
51+
| OperationTypeDefinition
52+
| ScalarTypeDefinition
5053
| ObjectTypeDefinition
5154
| FieldDefinition
5255
| InputValueDefinition
5356
| InterfaceTypeDefinition
5457
| UnionTypeDefinition
55-
| ScalarTypeDefinition
5658
| EnumTypeDefinition
5759
| EnumValueDefinition
5860
| InputObjectTypeDefinition
@@ -77,19 +79,21 @@ export type Document = {
7779

7880
export type Definition = OperationDefinition
7981
| FragmentDefinition
80-
| TypeSystemDefinition
82+
| TypeSystemDefinition // experimental non-spec addition.
8183

8284
export type OperationDefinition = {
8385
kind: 'OperationDefinition';
8486
loc?: ?Location;
85-
// Note: subscription is an experimental non-spec addition.
86-
operation: 'query' | 'mutation' | 'subscription';
87+
operation: OperationType;
8788
name?: ?Name;
8889
variableDefinitions?: ?Array<VariableDefinition>;
8990
directives?: ?Array<Directive>;
9091
selectionSet: SelectionSet;
9192
}
9293

94+
// Note: subscription is an experimental non-spec addition.
95+
export type OperationType = 'query' | 'mutation' | 'subscription';
96+
9397
export type VariableDefinition = {
9498
kind: 'VariableDefinition';
9599
loc?: ?Location;
@@ -256,10 +260,24 @@ export type NonNullType = {
256260

257261
// Type System Definition
258262

259-
export type TypeSystemDefinition = TypeDefinition
263+
export type TypeSystemDefinition = SchemaDefinition
264+
| TypeDefinition
260265
| TypeExtensionDefinition
261266
| DirectiveDefinition
262267

268+
export type SchemaDefinition = {
269+
kind: 'SchemaDefinition';
270+
loc?: ?Location;
271+
operationTypes: Array<OperationTypeDefinition>;
272+
}
273+
274+
export type OperationTypeDefinition = {
275+
kind: 'OperationTypeDefinition';
276+
loc?: ?Location;
277+
operation: OperationType;
278+
type: NamedType;
279+
}
280+
263281
export type TypeDefinition = ScalarTypeDefinition
264282
| ObjectTypeDefinition
265283
| InterfaceTypeDefinition

src/language/kinds.js

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ export const NON_NULL_TYPE = 'NonNullType';
5050

5151
// Type System Definitions
5252

53+
export const SCHEMA_DEFINITION = 'SchemaDefinition';
54+
export const OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition';
55+
5356
// Type Definitions
5457

5558
export const SCALAR_TYPE_DEFINITION = 'ScalarTypeDefinition';

src/language/parser.js

+59-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
Document,
2020
Definition,
2121
OperationDefinition,
22+
OperationType,
2223
VariableDefinition,
2324
SelectionSet,
2425
Selection,
@@ -41,6 +42,9 @@ import type {
4142

4243
TypeSystemDefinition,
4344

45+
SchemaDefinition,
46+
OperationTypeDefinition,
47+
4448
ScalarTypeDefinition,
4549
ObjectTypeDefinition,
4650
FieldDefinition,
@@ -86,6 +90,9 @@ import {
8690
LIST_TYPE,
8791
NON_NULL_TYPE,
8892

93+
SCHEMA_DEFINITION,
94+
OPERATION_TYPE_DEFINITION,
95+
8996
SCALAR_TYPE_DEFINITION,
9097
OBJECT_TYPE_DEFINITION,
9198
FIELD_DEFINITION,
@@ -203,6 +210,7 @@ function parseDefinition(parser: Parser): Definition {
203210
case 'fragment': return parseFragmentDefinition(parser);
204211

205212
// Note: the Type System IDL is an experimental non-spec addition.
213+
case 'schema':
206214
case 'scalar':
207215
case 'type':
208216
case 'interface':
@@ -224,8 +232,6 @@ function parseDefinition(parser: Parser): Definition {
224232
* OperationDefinition :
225233
* - SelectionSet
226234
* - OperationType Name? VariableDefinitions? Directives? SelectionSet
227-
*
228-
* OperationType : one of query mutation
229235
*/
230236
function parseOperationDefinition(parser: Parser): OperationDefinition {
231237
const start = parser.token.start;
@@ -240,12 +246,7 @@ function parseOperationDefinition(parser: Parser): OperationDefinition {
240246
loc: loc(parser, start)
241247
};
242248
}
243-
const operationToken = expect(parser, TokenKind.NAME);
244-
const operation =
245-
operationToken.value === 'mutation' ? 'mutation' :
246-
operationToken.value === 'subscription' ? 'subscription' :
247-
operationToken.value === 'query' ? 'query' :
248-
(() => { throw unexpected(parser, operationToken); })();
249+
const operation = parseOperationType(parser);
249250
let name;
250251
if (peek(parser, TokenKind.NAME)) {
251252
name = parseName(parser);
@@ -261,6 +262,21 @@ function parseOperationDefinition(parser: Parser): OperationDefinition {
261262
};
262263
}
263264

265+
/**
266+
* OperationType : one of query mutation subscription
267+
*/
268+
function parseOperationType(parser: Parser): OperationType {
269+
const operationToken = expect(parser, TokenKind.NAME);
270+
switch (operationToken.value) {
271+
case 'query': return 'query';
272+
case 'mutation': return 'mutation';
273+
// Note: subscription is an experimental non-spec addition.
274+
case 'subscription': return 'subscription';
275+
}
276+
277+
throw unexpected(parser, operationToken);
278+
}
279+
264280
/**
265281
* VariableDefinitions : ( VariableDefinition+ )
266282
*/
@@ -666,6 +682,7 @@ export function parseNamedType(parser: Parser): NamedType {
666682
function parseTypeSystemDefinition(parser: Parser): TypeSystemDefinition {
667683
if (peek(parser, TokenKind.NAME)) {
668684
switch (parser.token.value) {
685+
case 'schema': return parseSchemaDefinition(parser);
669686
case 'scalar': return parseScalarTypeDefinition(parser);
670687
case 'type': return parseObjectTypeDefinition(parser);
671688
case 'interface': return parseInterfaceTypeDefinition(parser);
@@ -680,6 +697,40 @@ function parseTypeSystemDefinition(parser: Parser): TypeSystemDefinition {
680697
throw unexpected(parser);
681698
}
682699

700+
/**
701+
* SchemaDefinition : schema { OperationTypeDefinition+ }
702+
*
703+
* OperationTypeDefinition : OperationType : NamedType
704+
*/
705+
function parseSchemaDefinition(parser: Parser): SchemaDefinition {
706+
const start = parser.token.start;
707+
expectKeyword(parser, 'schema');
708+
const operationTypes = many(
709+
parser,
710+
TokenKind.BRACE_L,
711+
parseOperationTypeDefinition,
712+
TokenKind.BRACE_R
713+
);
714+
return {
715+
kind: SCHEMA_DEFINITION,
716+
operationTypes,
717+
loc: loc(parser, start),
718+
};
719+
}
720+
721+
function parseOperationTypeDefinition(parser: Parser): OperationTypeDefinition {
722+
const start = parser.token.start;
723+
const operation = parseOperationType(parser);
724+
expect(parser, TokenKind.COLON);
725+
const type = parseNamedType(parser);
726+
return {
727+
kind: OPERATION_TYPE_DEFINITION,
728+
operation,
729+
type,
730+
loc: loc(parser, start),
731+
};
732+
}
733+
683734
/**
684735
* ScalarTypeDefinition : scalar Name
685736
*/

src/language/printer.js

+6
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ const printDocASTReducer = {
9494

9595
// Type System Definitions
9696

97+
SchemaDefinition: ({ operationTypes }) =>
98+
'schema ' + block(operationTypes),
99+
100+
OperationTypeDefinition: ({ operation, type }) =>
101+
operation + ': ' + type,
102+
97103
ScalarTypeDefinition: ({ name }) =>
98104
`scalar ${name}`,
99105

src/language/visitor.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,21 @@ export const QueryDocumentKeys = {
3838
ListType: [ 'type' ],
3939
NonNullType: [ 'type' ],
4040

41+
SchemaDefinition: [ 'operationTypes' ],
42+
OperationTypeDefinition: [ 'type' ],
43+
44+
ScalarTypeDefinition: [ 'name' ],
4145
ObjectTypeDefinition: [ 'name', 'interfaces', 'fields' ],
4246
FieldDefinition: [ 'name', 'arguments', 'type' ],
4347
InputValueDefinition: [ 'name', 'type', 'defaultValue' ],
4448
InterfaceTypeDefinition: [ 'name', 'fields' ],
4549
UnionTypeDefinition: [ 'name', 'types' ],
46-
ScalarTypeDefinition: [ 'name' ],
4750
EnumTypeDefinition: [ 'name', 'values' ],
4851
EnumValueDefinition: [ 'name' ],
4952
InputObjectTypeDefinition: [ 'name', 'fields' ],
53+
5054
TypeExtensionDefinition: [ 'definition' ],
55+
5156
DirectiveDefinition: [ 'name', 'arguments', 'locations' ],
5257
};
5358

0 commit comments

Comments
 (0)