From 664ea8ba30ca84d05a115d24518f3efd5532358c Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Fri, 6 May 2016 15:08:06 -0700 Subject: [PATCH] RFC: Directive location: schema definition This allows directives to be defined on schema definitions. --- src/language/ast.js | 1 + src/language/parser.js | 4 +++- src/language/printer.js | 8 ++++++-- src/language/visitor.js | 2 +- src/type/directives.js | 1 + src/type/introspection.js | 4 ++++ src/utilities/__tests__/schemaPrinter-test.js | 1 + src/validation/__tests__/KnownDirectives-test.js | 9 +++++++++ src/validation/__tests__/harness.js | 4 ++++ src/validation/rules/KnownDirectives.js | 12 +++++++----- 10 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/language/ast.js b/src/language/ast.js index 0f45446588..6c0056f12a 100644 --- a/src/language/ast.js +++ b/src/language/ast.js @@ -268,6 +268,7 @@ export type TypeSystemDefinition = SchemaDefinition export type SchemaDefinition = { kind: 'SchemaDefinition'; loc?: ?Location; + directives: Array; operationTypes: Array; } diff --git a/src/language/parser.js b/src/language/parser.js index 6195b9bfe1..11faabb4b0 100644 --- a/src/language/parser.js +++ b/src/language/parser.js @@ -701,13 +701,14 @@ function parseTypeSystemDefinition(parser: Parser): TypeSystemDefinition { } /** - * SchemaDefinition : schema { OperationTypeDefinition+ } + * SchemaDefinition : schema Directives? { OperationTypeDefinition+ } * * OperationTypeDefinition : OperationType : NamedType */ function parseSchemaDefinition(parser: Parser): SchemaDefinition { const start = parser.token.start; expectKeyword(parser, 'schema'); + const directives = parseDirectives(parser); const operationTypes = many( parser, TokenKind.BRACE_L, @@ -716,6 +717,7 @@ function parseSchemaDefinition(parser: Parser): SchemaDefinition { ); return { kind: SCHEMA_DEFINITION, + directives, operationTypes, loc: loc(parser, start), }; diff --git a/src/language/printer.js b/src/language/printer.js index 356d7c29bd..b908162f1f 100644 --- a/src/language/printer.js +++ b/src/language/printer.js @@ -94,8 +94,12 @@ const printDocASTReducer = { // Type System Definitions - SchemaDefinition: ({ operationTypes }) => - 'schema ' + block(operationTypes), + SchemaDefinition: ({ directives, operationTypes }) => + join([ + 'schema', + join(directives, ' '), + block(operationTypes), + ], ' '), OperationTypeDefinition: ({ operation, type }) => operation + ': ' + type, diff --git a/src/language/visitor.js b/src/language/visitor.js index 87661ff26e..4ed7b11640 100644 --- a/src/language/visitor.js +++ b/src/language/visitor.js @@ -38,7 +38,7 @@ export const QueryDocumentKeys = { ListType: [ 'type' ], NonNullType: [ 'type' ], - SchemaDefinition: [ 'operationTypes' ], + SchemaDefinition: [ 'directives', 'operationTypes' ], OperationTypeDefinition: [ 'type' ], ScalarTypeDefinition: [ 'name', 'directives' ], diff --git a/src/type/directives.js b/src/type/directives.js index 72a2ec7075..ff36829b9c 100644 --- a/src/type/directives.js +++ b/src/type/directives.js @@ -28,6 +28,7 @@ export const DirectiveLocation = { FRAGMENT_SPREAD: 'FRAGMENT_SPREAD', INLINE_FRAGMENT: 'INLINE_FRAGMENT', // Schema Definitions + SCHEMA: 'SCHEMA', SCALAR: 'SCALAR', OBJECT: 'OBJECT', FIELD_DEFINITION: 'FIELD_DEFINITION', diff --git a/src/type/introspection.js b/src/type/introspection.js index 383d9ac9db..fa509d604d 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -149,6 +149,10 @@ export const __DirectiveLocation = new GraphQLEnumType({ value: DirectiveLocation.INLINE_FRAGMENT, description: 'Location adjacent to an inline fragment.' }, + SCHEMA: { + value: DirectiveLocation.SCHEMA, + description: 'Location adjacent to a schema definition.' + }, SCALAR: { value: DirectiveLocation.SCALAR, description: 'Location adjacent to a scalar definition.' diff --git a/src/utilities/__tests__/schemaPrinter-test.js b/src/utilities/__tests__/schemaPrinter-test.js index 0e055edcef..bf8395196b 100644 --- a/src/utilities/__tests__/schemaPrinter-test.js +++ b/src/utilities/__tests__/schemaPrinter-test.js @@ -620,6 +620,7 @@ enum __DirectiveLocation { FRAGMENT_DEFINITION FRAGMENT_SPREAD INLINE_FRAGMENT + SCHEMA SCALAR OBJECT FIELD_DEFINITION diff --git a/src/validation/__tests__/KnownDirectives-test.js b/src/validation/__tests__/KnownDirectives-test.js index 91e9f063ce..179bf4dc29 100644 --- a/src/validation/__tests__/KnownDirectives-test.js +++ b/src/validation/__tests__/KnownDirectives-test.js @@ -149,6 +149,10 @@ describe('Validate: Known directives', () => { input MyInput @onInputObject { myField: Int @onInputFieldDefinition } + + schema @onSchema { + query: MyQuery + } `); }); @@ -173,6 +177,10 @@ describe('Validate: Known directives', () => { input MyInput @onEnum { myField: Int @onArgumentDefinition } + + schema @onObject { + query: MyQuery + } `, [ misplacedDirective('onInterface', 'OBJECT', 2, 43), misplacedDirective('onInputFieldDefinition', 'ARGUMENT_DEFINITION', 3, 30), @@ -186,6 +194,7 @@ describe('Validate: Known directives', () => { misplacedDirective('onUnion', 'ENUM_VALUE', 15, 20), misplacedDirective('onEnum', 'INPUT_OBJECT', 18, 23), misplacedDirective('onArgumentDefinition', 'INPUT_FIELD_DEFINITION', 19, 24), + misplacedDirective('onObject', 'SCHEMA', 22, 16), ]); }); diff --git a/src/validation/__tests__/harness.js b/src/validation/__tests__/harness.js index 3c30bcd603..ab26c915cd 100644 --- a/src/validation/__tests__/harness.js +++ b/src/validation/__tests__/harness.js @@ -336,6 +336,10 @@ export const testSchema = new GraphQLSchema({ name: 'onInlineFragment', locations: [ 'INLINE_FRAGMENT' ], }), + new GraphQLDirective({ + name: 'onSchema', + locations: [ 'SCHEMA' ], + }), new GraphQLDirective({ name: 'onScalar', locations: [ 'SCALAR' ], diff --git a/src/validation/rules/KnownDirectives.js b/src/validation/rules/KnownDirectives.js index fdef4a1db4..1528df3c96 100644 --- a/src/validation/rules/KnownDirectives.js +++ b/src/validation/rules/KnownDirectives.js @@ -17,15 +17,16 @@ import { FRAGMENT_SPREAD, INLINE_FRAGMENT, OPERATION_DEFINITION, - ENUM_TYPE_DEFINITION, - ENUM_VALUE_DEFINITION, + SCHEMA_DEFINITION, + SCALAR_TYPE_DEFINITION, + OBJECT_TYPE_DEFINITION, FIELD_DEFINITION, - INPUT_OBJECT_TYPE_DEFINITION, INPUT_VALUE_DEFINITION, INTERFACE_TYPE_DEFINITION, - OBJECT_TYPE_DEFINITION, - SCALAR_TYPE_DEFINITION, UNION_TYPE_DEFINITION, + ENUM_TYPE_DEFINITION, + ENUM_VALUE_DEFINITION, + INPUT_OBJECT_TYPE_DEFINITION, } from '../../language/kinds'; import { DirectiveLocation } from '../../type/directives'; @@ -91,6 +92,7 @@ function getDirectiveLocationForASTPath(ancestors) { case FRAGMENT_SPREAD: return DirectiveLocation.FRAGMENT_SPREAD; case INLINE_FRAGMENT: return DirectiveLocation.INLINE_FRAGMENT; case FRAGMENT_DEFINITION: return DirectiveLocation.FRAGMENT_DEFINITION; + case SCHEMA_DEFINITION: return DirectiveLocation.SCHEMA; case SCALAR_TYPE_DEFINITION: return DirectiveLocation.SCALAR; case OBJECT_TYPE_DEFINITION: return DirectiveLocation.OBJECT; case FIELD_DEFINITION: return DirectiveLocation.FIELD_DEFINITION;