Skip to content

Commit

Permalink
Add support for directives applied on IDL & Schema (#746)
Browse files Browse the repository at this point in the history
* Switch Enum tests to not depend on JSON representation

If we add additional fields (e.g. astNode) into values of enum these test
will be broken.

* Add 'astNode' & 'extensionASTNodes' fields to type definitions

* Make 'buildASTSchema' assign 'astNode' to types

* Make 'extendSchema' assign 'astNode' & 'extensionASTNodes'
  • Loading branch information
IvanGoncharov authored and leebyron committed Jul 5, 2017
1 parent 68b5d22 commit 831598b
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 49 deletions.
5 changes: 4 additions & 1 deletion src/type/__tests__/definition-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ describe('Type System: Example', () => {
description: undefined,
isDeprecated: true,
deprecationReason: 'Just because',
value: 'foo'
value: 'foo',
astNode: undefined,
});
});

Expand All @@ -200,13 +201,15 @@ describe('Type System: Example', () => {
isDeprecated: false,
deprecationReason: undefined,
value: null,
astNode: undefined,
},
{
name: 'UNDEFINED',
description: undefined,
isDeprecated: false,
deprecationReason: undefined,
value: undefined,
astNode: undefined,
},
]);
});
Expand Down
45 changes: 43 additions & 2 deletions src/type/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ import isNullish from '../jsutils/isNullish';
import * as Kind from '../language/kinds';
import { assertValidName } from '../utilities/assertValidName';
import type {
ScalarTypeDefinitionNode,
ObjectTypeDefinitionNode,
FieldDefinitionNode,
InputValueDefinitionNode,
InterfaceTypeDefinitionNode,
UnionTypeDefinitionNode,
EnumTypeDefinitionNode,
EnumValueDefinitionNode,
InputObjectTypeDefinitionNode,
TypeExtensionDefinitionNode,
OperationDefinitionNode,
FieldNode,
FragmentDefinitionNode,
Expand Down Expand Up @@ -294,13 +304,15 @@ function resolveThunk<T>(thunk: Thunk<T>): T {
export class GraphQLScalarType {
name: string;
description: ?string;
astNode: ?ScalarTypeDefinitionNode;

_scalarConfig: GraphQLScalarTypeConfig<*, *>;

constructor(config: GraphQLScalarTypeConfig<*, *>): void {
assertValidName(config.name);
this.name = config.name;
this.description = config.description;
this.astNode = config.astNode;
invariant(
typeof config.serialize === 'function',
`${this.name} must provide "serialize" function. If this custom Scalar ` +
Expand Down Expand Up @@ -364,6 +376,7 @@ GraphQLScalarType.prototype.toJSON =
export type GraphQLScalarTypeConfig<TInternal, TExternal> = {
name: string;
description?: ?string;
astNode?: ?ScalarTypeDefinitionNode;
serialize: (value: mixed) => ?TExternal;
parseValue?: (value: mixed) => ?TInternal;
parseLiteral?: (valueNode: ValueNode) => ?TInternal;
Expand Down Expand Up @@ -411,6 +424,8 @@ export type GraphQLScalarTypeConfig<TInternal, TExternal> = {
export class GraphQLObjectType {
name: string;
description: ?string;
astNode: ?ObjectTypeDefinitionNode;
extensionASTNodes: Array<TypeExtensionDefinitionNode>;
isTypeOf: ?GraphQLIsTypeOfFn<*, *>;

_typeConfig: GraphQLObjectTypeConfig<*, *>;
Expand All @@ -421,6 +436,8 @@ export class GraphQLObjectType {
assertValidName(config.name, config.isIntrospection);
this.name = config.name;
this.description = config.description;
this.astNode = config.astNode;
this.extensionASTNodes = config.extensionASTNodes || [];
if (config.isTypeOf) {
invariant(
typeof config.isTypeOf === 'function',
Expand Down Expand Up @@ -562,7 +579,8 @@ function defineFieldMap<TSource, TContext>(
name: argName,
description: arg.description === undefined ? null : arg.description,
type: arg.type,
defaultValue: arg.defaultValue
defaultValue: arg.defaultValue,
astNode: arg.astNode,
};
});
}
Expand All @@ -587,6 +605,8 @@ export type GraphQLObjectTypeConfig<TSource, TContext> = {
isTypeOf?: ?GraphQLIsTypeOfFn<TSource, TContext>;
description?: ?string;
isIntrospection?: boolean;
astNode?: ?ObjectTypeDefinitionNode;
extensionASTNodes?: ?Array<TypeExtensionDefinitionNode>;
};

export type GraphQLTypeResolver<TSource, TContext> = (
Expand Down Expand Up @@ -630,6 +650,7 @@ export type GraphQLFieldConfig<TSource, TContext> = {
subscribe?: GraphQLFieldResolver<TSource, TContext>;
deprecationReason?: ?string;
description?: ?string;
astNode?: ?FieldDefinitionNode;
};

export type GraphQLFieldConfigArgumentMap = {
Expand All @@ -640,6 +661,7 @@ export type GraphQLArgumentConfig = {
type: GraphQLInputType;
defaultValue?: mixed;
description?: ?string;
astNode?: ?InputValueDefinitionNode;
};

export type GraphQLFieldConfigMap<TSource, TContext> = {
Expand All @@ -655,13 +677,15 @@ export type GraphQLField<TSource, TContext> = {
subscribe?: GraphQLFieldResolver<TSource, TContext>;
isDeprecated?: boolean;
deprecationReason?: ?string;
astNode?: ?FieldDefinitionNode;
};

export type GraphQLArgument = {
name: string;
type: GraphQLInputType;
defaultValue?: mixed;
description?: ?string;
astNode?: ?InputValueDefinitionNode;
};

export type GraphQLFieldMap<TSource, TContext> = {
Expand Down Expand Up @@ -691,6 +715,7 @@ export type GraphQLFieldMap<TSource, TContext> = {
export class GraphQLInterfaceType {
name: string;
description: ?string;
astNode: ?InterfaceTypeDefinitionNode;
resolveType: ?GraphQLTypeResolver<*, *>;

_typeConfig: GraphQLInterfaceTypeConfig<*, *>;
Expand All @@ -700,6 +725,7 @@ export class GraphQLInterfaceType {
assertValidName(config.name);
this.name = config.name;
this.description = config.description;
this.astNode = config.astNode;
if (config.resolveType) {
invariant(
typeof config.resolveType === 'function',
Expand Down Expand Up @@ -737,7 +763,8 @@ export type GraphQLInterfaceTypeConfig<TSource, TContext> = {
* Object type.
*/
resolveType?: ?GraphQLTypeResolver<TSource, TContext>,
description?: ?string
description?: ?string,
astNode?: ?InterfaceTypeDefinitionNode,
};


Expand Down Expand Up @@ -768,6 +795,7 @@ export type GraphQLInterfaceTypeConfig<TSource, TContext> = {
export class GraphQLUnionType {
name: string;
description: ?string;
astNode: ?UnionTypeDefinitionNode;
resolveType: ?GraphQLTypeResolver<*, *>;

_typeConfig: GraphQLUnionTypeConfig<*, *>;
Expand All @@ -778,6 +806,7 @@ export class GraphQLUnionType {
assertValidName(config.name);
this.name = config.name;
this.description = config.description;
this.astNode = config.astNode;
if (config.resolveType) {
invariant(
typeof config.resolveType === 'function',
Expand Down Expand Up @@ -854,6 +883,7 @@ export type GraphQLUnionTypeConfig<TSource, TContext> = {
*/
resolveType?: ?GraphQLTypeResolver<TSource, TContext>;
description?: ?string;
astNode?: ?UnionTypeDefinitionNode;
};


Expand Down Expand Up @@ -882,6 +912,7 @@ export type GraphQLUnionTypeConfig<TSource, TContext> = {
export class GraphQLEnumType/* <T> */ {
name: string;
description: ?string;
astNode: ?EnumTypeDefinitionNode;

_enumConfig: GraphQLEnumTypeConfig/* <T> */;
_values: Array<GraphQLEnumValue/* <T> */>;
Expand All @@ -892,6 +923,7 @@ export class GraphQLEnumType/* <T> */ {
this.name = config.name;
assertValidName(config.name, config.isIntrospection);
this.description = config.description;
this.astNode = config.astNode;
this._values = defineEnumValues(this, config.values);
this._enumConfig = config;
}
Expand Down Expand Up @@ -1008,6 +1040,7 @@ function defineEnumValues(
description: value.description,
isDeprecated: Boolean(value.deprecationReason),
deprecationReason: value.deprecationReason,
astNode: value.astNode,
value: value.hasOwnProperty('value') ? value.value : valueName,
};
});
Expand All @@ -1017,6 +1050,7 @@ export type GraphQLEnumTypeConfig/* <T> */ = {
name: string;
values: GraphQLEnumValueConfigMap/* <T> */;
description?: ?string;
astNode?: ?EnumTypeDefinitionNode;
isIntrospection?: boolean;
};

Expand All @@ -1028,13 +1062,15 @@ export type GraphQLEnumValueConfig/* <T> */ = {
value?: any/* T */;
deprecationReason?: ?string;
description?: ?string;
astNode?: ?EnumValueDefinitionNode;
};

export type GraphQLEnumValue/* <T> */ = {
name: string;
description: ?string;
isDeprecated?: boolean;
deprecationReason: ?string;
astNode?: ?EnumValueDefinitionNode;
value: any/* T */;
};

Expand Down Expand Up @@ -1063,6 +1099,7 @@ export type GraphQLEnumValue/* <T> */ = {
export class GraphQLInputObjectType {
name: string;
description: ?string;
astNode: ?InputObjectTypeDefinitionNode;

_typeConfig: GraphQLInputObjectTypeConfig;
_fields: GraphQLInputFieldMap;
Expand All @@ -1071,6 +1108,7 @@ export class GraphQLInputObjectType {
assertValidName(config.name);
this.name = config.name;
this.description = config.description;
this.astNode = config.astNode;
this._typeConfig = config;
}

Expand Down Expand Up @@ -1130,12 +1168,14 @@ export type GraphQLInputObjectTypeConfig = {
name: string;
fields: Thunk<GraphQLInputFieldConfigMap>;
description?: ?string;
astNode?: ?InputObjectTypeDefinitionNode;
};

export type GraphQLInputFieldConfig = {
type: GraphQLInputType;
defaultValue?: mixed;
description?: ?string;
astNode?: ?InputValueDefinitionNode;
};

export type GraphQLInputFieldConfigMap = {
Expand All @@ -1147,6 +1187,7 @@ export type GraphQLInputField = {
type: GraphQLInputType;
defaultValue?: mixed;
description?: ?string;
astNode?: ?InputValueDefinitionNode;
};

export type GraphQLInputFieldMap = {
Expand Down
8 changes: 7 additions & 1 deletion src/type/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
import { GraphQLString, GraphQLBoolean } from './scalars';
import invariant from '../jsutils/invariant';
import { assertValidName } from '../utilities/assertValidName';
import type { DirectiveDefinitionNode } from '../language/ast';


export const DirectiveLocation = {
Expand Down Expand Up @@ -52,6 +53,7 @@ export class GraphQLDirective {
description: ?string;
locations: Array<DirectiveLocationEnum>;
args: Array<GraphQLArgument>;
astNode: ?DirectiveDefinitionNode;

constructor(config: GraphQLDirectiveConfig): void {
invariant(config.name, 'Directive must be named.');
Expand All @@ -63,6 +65,7 @@ export class GraphQLDirective {
this.name = config.name;
this.description = config.description;
this.locations = config.locations;
this.astNode = config.astNode;

const args = config.args;
if (!args) {
Expand All @@ -84,10 +87,12 @@ export class GraphQLDirective {
name: argName,
description: arg.description === undefined ? null : arg.description,
type: arg.type,
defaultValue: arg.defaultValue
defaultValue: arg.defaultValue,
astNode: arg.astNode,
};
});
}

}
}

Expand All @@ -96,6 +101,7 @@ type GraphQLDirectiveConfig = {
description?: ?string;
locations: Array<DirectiveLocationEnum>;
args?: ?GraphQLFieldConfigArgumentMap;
astNode?: ?DirectiveDefinitionNode;
};

/**
Expand Down
4 changes: 4 additions & 0 deletions src/type/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
GraphQLNamedType,
GraphQLAbstractType
} from './definition';
import type { SchemaDefinitionNode } from '../language/ast';
import { GraphQLDirective, specifiedDirectives } from './directives';
import { __Schema } from './introspection';
import find from '../jsutils/find';
Expand Down Expand Up @@ -55,6 +56,7 @@ import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators';
*
*/
export class GraphQLSchema {
astNode: ?SchemaDefinitionNode;
_queryType: GraphQLObjectType;
_mutationType: ?GraphQLObjectType;
_subscriptionType: ?GraphQLObjectType;
Expand Down Expand Up @@ -107,6 +109,7 @@ export class GraphQLSchema {
);
// Provide specified directives (e.g. @include and @skip) by default.
this._directives = config.directives || specifiedDirectives;
this.astNode = config.astNode || null;

// Build type map now to detect any errors within this schema.
let initialTypes: Array<?GraphQLNamedType> = [
Expand Down Expand Up @@ -227,6 +230,7 @@ type GraphQLSchemaConfig = {
subscription?: ?GraphQLObjectType;
types?: ?Array<GraphQLNamedType>;
directives?: ?Array<GraphQLDirective>;
astNode?: ?SchemaDefinitionNode;
};

function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap {
Expand Down
Loading

0 comments on commit 831598b

Please sign in to comment.