diff --git a/src/type/__tests__/definition-test.js b/src/type/__tests__/definition-test.js index 1eff90137a8..c47d81299b9 100644 --- a/src/type/__tests__/definition-test.js +++ b/src/type/__tests__/definition-test.js @@ -180,7 +180,8 @@ describe('Type System: Example', () => { description: undefined, isDeprecated: true, deprecationReason: 'Just because', - value: 'foo' + value: 'foo', + astNode: null, }); }); @@ -200,6 +201,7 @@ describe('Type System: Example', () => { isDeprecated: false, deprecationReason: undefined, value: null, + astNode: null, }, { name: 'UNDEFINED', @@ -207,6 +209,7 @@ describe('Type System: Example', () => { isDeprecated: false, deprecationReason: undefined, value: undefined, + astNode: null, }, ]); }); diff --git a/src/type/definition.js b/src/type/definition.js index 434b0c99bee..4867c966eb0 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -13,6 +13,16 @@ import isNullish from '../jsutils/isNullish'; import { ENUM } from '../language/kinds'; import { assertValidName } from '../utilities/assertValidName'; import type { + ScalarTypeDefinitionNode, + ObjectTypeDefinitionNode, + FieldDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + UnionTypeDefinitionNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + InputObjectTypeDefinitionNode, + TypeExtensionDefinitionNode, OperationDefinitionNode, FieldNode, FragmentDefinitionNode, @@ -294,6 +304,7 @@ function resolveThunk(thunk: Thunk): T { export class GraphQLScalarType { name: string; description: ?string; + astNode: ?ScalarTypeDefinitionNode; _scalarConfig: GraphQLScalarTypeConfig<*, *>; @@ -301,6 +312,7 @@ export class GraphQLScalarType { assertValidName(config.name); this.name = config.name; this.description = config.description; + this.astNode = config.astNode || null; invariant( typeof config.serialize === 'function', `${this.name} must provide "serialize" function. If this custom Scalar ` + @@ -364,6 +376,7 @@ GraphQLScalarType.prototype.toJSON = export type GraphQLScalarTypeConfig = { name: string; description?: ?string; + astNode?: ?ScalarTypeDefinitionNode; serialize: (value: mixed) => ?TExternal; parseValue?: (value: mixed) => ?TInternal; parseLiteral?: (valueNode: ValueNode) => ?TInternal; @@ -411,6 +424,8 @@ export type GraphQLScalarTypeConfig = { export class GraphQLObjectType { name: string; description: ?string; + astNode: ?ObjectTypeDefinitionNode; + extensionASTNodes: Array; isTypeOf: ?GraphQLIsTypeOfFn<*, *>; _typeConfig: GraphQLObjectTypeConfig<*, *>; @@ -421,6 +436,8 @@ export class GraphQLObjectType { assertValidName(config.name, config.isIntrospection); this.name = config.name; this.description = config.description; + this.astNode = config.astNode || null; + this.extensionASTNodes = config.extensionASTNodes || []; if (config.isTypeOf) { invariant( typeof config.isTypeOf === 'function', @@ -562,7 +579,8 @@ function defineFieldMap( name: argName, description: arg.description === undefined ? null : arg.description, type: arg.type, - defaultValue: arg.defaultValue + defaultValue: arg.defaultValue, + astNode: arg.astNode, }; }); } @@ -587,6 +605,8 @@ export type GraphQLObjectTypeConfig = { isTypeOf?: ?GraphQLIsTypeOfFn; description?: ?string; isIntrospection?: boolean; + astNode?: ?ObjectTypeDefinitionNode; + extensionASTNodes?: ?Array; }; export type GraphQLTypeResolver = ( @@ -630,6 +650,7 @@ export type GraphQLFieldConfig = { subscribe?: GraphQLFieldResolver; deprecationReason?: ?string; description?: ?string; + astNode?: ?FieldDefinitionNode; }; export type GraphQLFieldConfigArgumentMap = { @@ -640,6 +661,7 @@ export type GraphQLArgumentConfig = { type: GraphQLInputType; defaultValue?: mixed; description?: ?string; + astNode?: ?InputValueDefinitionNode; }; export type GraphQLFieldConfigMap = { @@ -655,6 +677,7 @@ export type GraphQLField = { subscribe?: GraphQLFieldResolver; isDeprecated?: boolean; deprecationReason?: ?string; + astNode?: ?FieldDefinitionNode; }; export type GraphQLArgument = { @@ -662,6 +685,7 @@ export type GraphQLArgument = { type: GraphQLInputType; defaultValue?: mixed; description?: ?string; + astNode?: ?InputValueDefinitionNode; }; export type GraphQLFieldMap = { @@ -691,6 +715,7 @@ export type GraphQLFieldMap = { export class GraphQLInterfaceType { name: string; description: ?string; + astNode: ?InterfaceTypeDefinitionNode; resolveType: ?GraphQLTypeResolver<*, *>; _typeConfig: GraphQLInterfaceTypeConfig<*, *>; @@ -700,6 +725,7 @@ export class GraphQLInterfaceType { assertValidName(config.name); this.name = config.name; this.description = config.description; + this.astNode = config.astNode || null; if (config.resolveType) { invariant( typeof config.resolveType === 'function', @@ -737,7 +763,8 @@ export type GraphQLInterfaceTypeConfig = { * Object type. */ resolveType?: ?GraphQLTypeResolver, - description?: ?string + description?: ?string, + astNode?: ?InterfaceTypeDefinitionNode, }; @@ -768,6 +795,7 @@ export type GraphQLInterfaceTypeConfig = { export class GraphQLUnionType { name: string; description: ?string; + astNode: ?UnionTypeDefinitionNode; resolveType: ?GraphQLTypeResolver<*, *>; _typeConfig: GraphQLUnionTypeConfig<*, *>; @@ -778,6 +806,7 @@ export class GraphQLUnionType { assertValidName(config.name); this.name = config.name; this.description = config.description; + this.astNode = config.astNode || null; if (config.resolveType) { invariant( typeof config.resolveType === 'function', @@ -854,6 +883,7 @@ export type GraphQLUnionTypeConfig = { */ resolveType?: ?GraphQLTypeResolver; description?: ?string; + astNode?: ?UnionTypeDefinitionNode; }; @@ -882,6 +912,7 @@ export type GraphQLUnionTypeConfig = { export class GraphQLEnumType/* */ { name: string; description: ?string; + astNode: ?EnumTypeDefinitionNode; _enumConfig: GraphQLEnumTypeConfig/* */; _values: Array */>; @@ -892,6 +923,7 @@ export class GraphQLEnumType/* */ { this.name = config.name; assertValidName(config.name, config.isIntrospection); this.description = config.description; + this.astNode = config.astNode || null; this._values = defineEnumValues(this, config.values); this._enumConfig = config; } @@ -1008,6 +1040,7 @@ function defineEnumValues( description: value.description, isDeprecated: Boolean(value.deprecationReason), deprecationReason: value.deprecationReason, + astNode: value.astNode || null, value: value.hasOwnProperty('value') ? value.value : valueName, }; }); @@ -1017,6 +1050,7 @@ export type GraphQLEnumTypeConfig/* */ = { name: string; values: GraphQLEnumValueConfigMap/* */; description?: ?string; + astNode?: ?EnumTypeDefinitionNode; isIntrospection?: boolean; }; @@ -1028,6 +1062,7 @@ export type GraphQLEnumValueConfig/* */ = { value?: any/* T */; deprecationReason?: ?string; description?: ?string; + astNode?: ?EnumValueDefinitionNode; }; export type GraphQLEnumValue/* */ = { @@ -1035,6 +1070,7 @@ export type GraphQLEnumValue/* */ = { description: ?string; isDeprecated?: boolean; deprecationReason: ?string; + astNode?: ?EnumValueDefinitionNode; value: any/* T */; }; @@ -1063,6 +1099,7 @@ export type GraphQLEnumValue/* */ = { export class GraphQLInputObjectType { name: string; description: ?string; + astNode: ?InputObjectTypeDefinitionNode; _typeConfig: GraphQLInputObjectTypeConfig; _fields: GraphQLInputFieldMap; @@ -1071,6 +1108,7 @@ export class GraphQLInputObjectType { assertValidName(config.name); this.name = config.name; this.description = config.description; + this.astNode = config.astNode || null; this._typeConfig = config; } @@ -1130,12 +1168,14 @@ export type GraphQLInputObjectTypeConfig = { name: string; fields: Thunk; description?: ?string; + astNode?: ?InputObjectTypeDefinitionNode; }; export type GraphQLInputFieldConfig = { type: GraphQLInputType; defaultValue?: mixed; description?: ?string; + astNode?: ?InputValueDefinitionNode; }; export type GraphQLInputFieldConfigMap = { @@ -1147,6 +1187,7 @@ export type GraphQLInputField = { type: GraphQLInputType; defaultValue?: mixed; description?: ?string; + astNode?: ?InputValueDefinitionNode; }; export type GraphQLInputFieldMap = { diff --git a/src/type/directives.js b/src/type/directives.js index bc2feff27c8..6edc0307818 100644 --- a/src/type/directives.js +++ b/src/type/directives.js @@ -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 = { @@ -52,6 +53,7 @@ export class GraphQLDirective { description: ?string; locations: Array; args: Array; + astNode: ?DirectiveDefinitionNode; constructor(config: GraphQLDirectiveConfig): void { invariant(config.name, 'Directive must be named.'); @@ -84,10 +86,13 @@ export class GraphQLDirective { name: argName, description: arg.description === undefined ? null : arg.description, type: arg.type, - defaultValue: arg.defaultValue + defaultValue: arg.defaultValue, + astNode: arg.astNode || null, }; }); } + + this.astNode = config.astNode || null; } } @@ -96,6 +101,7 @@ type GraphQLDirectiveConfig = { description?: ?string; locations: Array; args?: ?GraphQLFieldConfigArgumentMap; + astNode?: ?DirectiveDefinitionNode; }; /** diff --git a/src/type/schema.js b/src/type/schema.js index 45c5cb5988d..92fb2365383 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -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'; @@ -55,6 +56,7 @@ import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; * */ export class GraphQLSchema { + astNode: ?SchemaDefinitionNode; _queryType: GraphQLObjectType; _mutationType: ?GraphQLObjectType; _subscriptionType: ?GraphQLObjectType; @@ -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 = [ @@ -227,6 +230,7 @@ type GraphQLSchemaConfig = { subscription?: ?GraphQLObjectType; types?: ?Array; directives?: ?Array; + astNode?: ?SchemaDefinitionNode; }; function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { diff --git a/src/utilities/__tests__/buildASTSchema-test.js b/src/utilities/__tests__/buildASTSchema-test.js index ae96986d343..a589923cd1a 100644 --- a/src/utilities/__tests__/buildASTSchema-test.js +++ b/src/utilities/__tests__/buildASTSchema-test.js @@ -9,7 +9,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { parse } from '../../language'; +import { parse, print } from '../../language'; import { printSchema } from '../schemaPrinter'; import { buildASTSchema, buildSchema } from '../buildASTSchema'; import { @@ -538,29 +538,18 @@ type Query { const ast = parse(body); const schema = buildASTSchema(ast); - expect(schema.getType('MyEnum').getValues()).to.deep.equal([ - { - name: 'VALUE', - description: '', - isDeprecated: false, - deprecationReason: undefined, - value: 'VALUE' - }, - { - name: 'OLD_VALUE', - description: '', - isDeprecated: true, - deprecationReason: 'No longer supported', - value: 'OLD_VALUE' - }, - { - name: 'OTHER_VALUE', - description: '', - isDeprecated: true, - deprecationReason: 'Terrible reasons', - value: 'OTHER_VALUE' - } - ]); + const myEnum = schema.getType('MyEnum'); + + const value = myEnum.getValue('VALUE'); + expect(value.isDeprecated).to.equal(false); + + const oldValue = myEnum.getValue('OLD_VALUE'); + expect(oldValue.isDeprecated).to.equal(true); + expect(oldValue.deprecationReason).to.equal('No longer supported'); + + const otherValue = myEnum.getValue('OTHER_VALUE'); + expect(otherValue.isDeprecated).to.equal(true); + expect(otherValue.deprecationReason).to.equal('Terrible reasons'); const rootFields = schema.getType('Query').getFields(); expect(rootFields.field1.isDeprecated).to.equal(true); @@ -569,6 +558,79 @@ type Query { expect(rootFields.field2.isDeprecated).to.equal(true); expect(rootFields.field2.deprecationReason).to.equal('Because I said so'); }); + + it('Correctly assign AST nodes', () => { + const idl = ` + schema { + query: Query + } + + type Query { + testField(testArg: TestInput): TestUnion + } + + input TestInput { + testInputField: TestEnum + } + + enum TestEnum { + TEST_VALUE + } + + union TestUnion = TestType + + interface TestInterface { + interfaceField: String + } + + type TestType implements TestInterface { + interfaceField: String + } + + directive @test(arg: Int) on FIELD + `; + const schema = buildSchema(idl); + const query = schema.getType('Query'); + const testInput = schema.getType('TestInput'); + const testEnum = schema.getType('TestEnum'); + const testUnion = schema.getType('TestUnion'); + const testInterface = schema.getType('TestInterface'); + const testType = schema.getType('TestType'); + const testDirective = schema.getDirective('test'); + + const restoreIDL = cycleOutput( + print(schema.astNode) + '\n' + + print(query.astNode) + '\n' + + print(testInput.astNode) + '\n' + + print(testEnum.astNode) + '\n' + + print(testUnion.astNode) + '\n' + + print(testInterface.astNode) + '\n' + + print(testType.astNode) + '\n' + + print(testDirective.astNode) + ); + expect(restoreIDL).to.be.equal(cycleOutput(idl)); + + const testField = query.getFields().testField; + expect(print(testField.astNode)).to.equal( + 'testField(testArg: TestInput): TestUnion' + ); + expect(print(testField.args[0].astNode)).to.equal( + 'testArg: TestInput' + ); + expect(print(testInput.getFields().testInputField.astNode)).to.equal( + 'testInputField: TestEnum' + ); + expect(print(testEnum.getValue('TEST_VALUE').astNode)).to.equal( + 'TEST_VALUE' + ); + expect(print(testInterface.getFields().interfaceField.astNode)).to.equal( + 'interfaceField: String' + ); + expect(print(testType.getFields().interfaceField.astNode)).to.equal( + 'interfaceField: String' + ); + expect(print(testDirective.args[0].astNode)).to.equal('arg: Int'); + }); }); describe('Failures', () => { diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.js index e1ca2e62da1..453e13abef2 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.js @@ -404,27 +404,32 @@ describe('Type System: build schema from introspection', () => { value: 'VEGETABLES', description: 'Foods that are vegetables.', isDeprecated: false, - deprecationReason: null, }, + deprecationReason: null, + astNode: null, }, { name: 'FRUITS', value: 'FRUITS', description: 'Foods that are fruits.', isDeprecated: false, - deprecationReason: null, }, + deprecationReason: null, + astNode: null, }, { name: 'OILS', value: 'OILS', description: 'Foods that are oils.', isDeprecated: false, - deprecationReason: null, }, + deprecationReason: null, + astNode: null, }, { name: 'DAIRY', value: 'DAIRY', description: 'Foods that are dairy.', isDeprecated: false, - deprecationReason: null, }, + deprecationReason: null, + astNode: null, }, { name: 'MEAT', value: 'MEAT', description: 'Foods that are meat.', isDeprecated: false, - deprecationReason: null, }, + deprecationReason: null, + astNode: null, }, ]); }); diff --git a/src/utilities/__tests__/extendSchema-test.js b/src/utilities/__tests__/extendSchema-test.js index b636bc1f855..dac544ed1b3 100644 --- a/src/utilities/__tests__/extendSchema-test.js +++ b/src/utilities/__tests__/extendSchema-test.js @@ -9,9 +9,10 @@ import { describe, it } from 'mocha'; import { expect } from 'chai'; +import { buildSchema } from '../buildASTSchema'; import { extendSchema } from '../extendSchema'; import { execute } from '../../execution'; -import { parse } from '../../language'; +import { parse, print } from '../../language'; import { printSchema } from '../schemaPrinter'; import { GraphQLSchema, @@ -193,6 +194,79 @@ interface SomeInterface { union SomeUnion = Foo | Biz `); + + }); + + it('correctly assign AST nodes to new and extended types', () => { + const schemaIDL = printSchema(testSchema); + const schemaFromIDL = buildSchema(schemaIDL); + const extensionAst = parse(` + type NewType { + foo: String + } + + extend type Foo { + newField: String + } + `); + const extendedSchema = extendSchema(schemaFromIDL, extensionAst); + + expect( + extendedSchema.getType('Query').extensionASTNodes + ).to.have.lengthOf(0); + const newType = extendedSchema.getType('NewType'); + expect(print(newType.astNode)).to.be.equal( +`type NewType { + foo: String +}`); + expect(newType.extensionASTNodes).to.have.lengthOf(0); + + const extendedFoo = extendedSchema.getType('Foo'); + expect(print(extendedFoo.astNode)).to.equal( +`type Foo implements SomeInterface { + name: String + some: SomeInterface + tree: [Foo]! +}`); + + expect(extendedFoo.extensionASTNodes).to.have.lengthOf(1); + const extensionIDL = print(extendedFoo.extensionASTNodes[0]); + expect(extensionIDL).to.be.equal( +`extend type Foo { + newField: String +}`); + + const newField = extendedFoo.getFields().newField; + expect(print(newField.astNode)).to.equal('newField: String'); + + const secondExtensionAst = parse(` + extend type Foo { + secondNewField: Float + } + `); + const extendedTwiceSchema = extendSchema(extendedSchema, + secondExtensionAst); + + const extendedTwiceFoo = extendedTwiceSchema.getType('Foo'); + expect(print(extendedTwiceFoo.astNode)).to.equal( +`type Foo implements SomeInterface { + name: String + some: SomeInterface + tree: [Foo]! +}`); + + expect(extendedTwiceFoo.extensionASTNodes).to.have.lengthOf(2); + expect(print(extendedTwiceFoo.extensionASTNodes[0])).to.be.equal( +`extend type Foo { + newField: String +}`); + expect(print(extendedTwiceFoo.extensionASTNodes[1])).to.be.equal( +`extend type Foo { + secondNewField: Float +}`); + + const secondNewField = extendedTwiceFoo.getFields().secondNewField; + expect(print(secondNewField.astNode)).to.equal('secondNewField: Float'); }); it('builds types with deprecated fields/values', () => { @@ -214,16 +288,10 @@ union SomeUnion = Foo | Biz expect(deprecatedFieldDef.deprecationReason).to.equal('not used anymore'); const deprecatedEnumDef = extendedSchema - .getType('EnumWithDeprecatedValue'); - expect(deprecatedEnumDef.getValues()).to.deep.equal([ - { - name: 'DEPRECATED', - description: '', - isDeprecated: true, - deprecationReason: 'do not use', - value: 'DEPRECATED' - } - ]); + .getType('EnumWithDeprecatedValue') + .getValue('DEPRECATED'); + expect(deprecatedEnumDef.isDeprecated).to.equal(true); + expect(deprecatedEnumDef.deprecationReason).to.equal('do not use'); }); it('extends objects with deprecated fields', () => { diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.js index 7b6ef88b740..101948cf99a 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.js @@ -272,6 +272,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { null, types, directives, + astNode: schemaDef, }); function getDirective( @@ -284,6 +285,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { node => ((node.value: any): DirectiveLocationEnum) ), args: directiveNode.arguments && makeInputValues(directiveNode.arguments), + astNode: directiveNode, }); } @@ -368,6 +370,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { description: getDescription(def), fields: () => makeFieldDefMap(def), interfaces: () => makeImplementedInterfaces(def), + astNode: def, }); } @@ -381,7 +384,8 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { type: produceOutputType(field.type), description: getDescription(field), args: makeInputValues(field.arguments), - deprecationReason: getDeprecationReason(field.directives) + deprecationReason: getDeprecationReason(field.directives), + astNode: field, }) ); } @@ -400,7 +404,8 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { return { type, description: getDescription(value), - defaultValue: valueFromAST(value.defaultValue, type) + defaultValue: valueFromAST(value.defaultValue, type), + astNode: value, }; } ); @@ -412,6 +417,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { name: typeName, description: getDescription(def), fields: () => makeFieldDefMap(def), + astNode: def, resolveType: cannotExecuteSchema, }); } @@ -425,9 +431,11 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { enumValue => enumValue.name.value, enumValue => ({ description: getDescription(enumValue), - deprecationReason: getDeprecationReason(enumValue.directives) + deprecationReason: getDeprecationReason(enumValue.directives), + astNode: enumValue }) ), + astNode: def, }); return enumType; @@ -439,6 +447,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { description: getDescription(def), types: def.types.map(t => produceObjectType(t)), resolveType: cannotExecuteSchema, + astNode: def, }); } @@ -446,6 +455,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { return new GraphQLScalarType({ name: def.name.value, description: getDescription(def), + astNode: def, serialize: () => null, // Note: validation calls the parse functions to determine if a // literal value is correct. Returning null would cause use of custom @@ -461,6 +471,7 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { name: def.name.value, description: getDescription(def), fields: () => makeInputValues(def.fields), + astNode: def, }); } } diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.js index 2b24a3e1575..5d7bcf7bdbd 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.js @@ -252,6 +252,7 @@ export function extendSchema( subscription: subscriptionType, types, directives: getMergedDirectives(), + astNode: schema.astNode, }); // Below are functions used for producing this schema that have closed over @@ -344,11 +345,19 @@ export function extendSchema( } function extendObjectType(type: GraphQLObjectType): GraphQLObjectType { + const name = type.name; + let extensionASTNodes = type.extensionASTNodes; + if (typeExtensionsMap[name]) { + extensionASTNodes = extensionASTNodes.concat(typeExtensionsMap[name]); + } + return new GraphQLObjectType({ - name: type.name, + name, description: type.description, interfaces: () => extendImplementedInterfaces(type), fields: () => extendFieldMap(type), + astNode: type.astNode, + extensionASTNodes, isTypeOf: type.isTypeOf, }); } @@ -360,6 +369,7 @@ export function extendSchema( name: type.name, description: type.description, fields: () => extendFieldMap(type), + astNode: type.astNode, resolveType: type.resolveType, }); } @@ -369,6 +379,7 @@ export function extendSchema( name: type.name, description: type.description, types: type.getTypes().map(getTypeFromDef), + astNode: type.astNode, resolveType: type.resolveType, }); } @@ -409,6 +420,7 @@ export function extendSchema( deprecationReason: field.deprecationReason, type: extendFieldType(field.type), args: keyMap(field.args, arg => arg.name), + astNode: field.astNode, resolve: field.resolve, }; }); @@ -430,6 +442,7 @@ export function extendSchema( description: getDescription(field), type: buildOutputFieldType(field.type), args: buildInputValues(field.arguments), + astNode: field, deprecationReason: getDeprecationReason(field.directives), }; }); @@ -467,6 +480,7 @@ export function extendSchema( description: getDescription(typeNode), interfaces: () => buildImplementedInterfaces(typeNode), fields: () => buildFieldMap(typeNode), + astNode: typeNode, }); } @@ -475,6 +489,7 @@ export function extendSchema( name: typeNode.name.value, description: getDescription(typeNode), fields: () => buildFieldMap(typeNode), + astNode: typeNode, resolveType: cannotExecuteExtendedSchema, }); } @@ -484,6 +499,7 @@ export function extendSchema( name: typeNode.name.value, description: getDescription(typeNode), types: typeNode.types.map(getObjectTypeFromAST), + astNode: typeNode, resolveType: cannotExecuteExtendedSchema, }); } @@ -492,6 +508,7 @@ export function extendSchema( return new GraphQLScalarType({ name: typeNode.name.value, description: getDescription(typeNode), + astNode: typeNode, serialize: id => id, // Note: validation calls the parse functions to determine if a // literal value is correct. Returning null would cause use of custom @@ -512,8 +529,10 @@ export function extendSchema( enumValue => ({ description: getDescription(enumValue), deprecationReason: getDeprecationReason(enumValue.directives), + astNode: enumValue, }), ), + astNode: typeNode, }); } @@ -522,6 +541,7 @@ export function extendSchema( name: typeNode.name.value, description: getDescription(typeNode), fields: () => buildInputValues(typeNode.fields), + astNode: typeNode, }); } @@ -535,6 +555,7 @@ export function extendSchema( ), args: directiveNode.arguments && buildInputValues(directiveNode.arguments), + astNode: directiveNode, }); } @@ -552,6 +573,7 @@ export function extendSchema( description: getDescription(field), args: buildInputValues(field.arguments), deprecationReason: getDeprecationReason(field.directives), + astNode: field, }) ); } @@ -565,7 +587,8 @@ export function extendSchema( return { type, description: getDescription(value), - defaultValue: valueFromAST(value.defaultValue, type) + defaultValue: valueFromAST(value.defaultValue, type), + astNode: value, }; } );