diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.js index c70d50abe5..e9110866ad 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.js @@ -39,7 +39,7 @@ describe('Execute: Handles basic execution tasks', () => { execute({ document: parse('{ field }'), }), - ).to.throw('Must provide schema'); + ).to.throw('Expected undefined to be a GraphQL schema.'); }); it('accepts an object with named properties as arguments', async () => { diff --git a/src/execution/execute.js b/src/execution/execute.js index e217c9b071..7c096574fc 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.js @@ -22,12 +22,15 @@ import { getDirectiveValues, } from './values'; import { - GraphQLObjectType, + isObjectType, isAbstractType, isLeafType, + isListType, + isNonNullType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; +import type { GraphQLList } from '../type/wrappers'; import type { + GraphQLObjectType, GraphQLOutputType, GraphQLLeafType, GraphQLAbstractType, @@ -807,7 +810,7 @@ function completeValueCatchingError( ): mixed { // If the field type is non-nullable, then it is resolved without any // protection from errors, however it still properly locates the error. - if (returnType instanceof GraphQLNonNull) { + if (isNonNullType(returnType)) { return completeValueWithLocatedError( exeContext, returnType, @@ -934,7 +937,7 @@ function completeValue( // If field type is NonNull, complete for inner type, and throw field error // if result is null. - if (returnType instanceof GraphQLNonNull) { + if (isNonNullType(returnType)) { const completed = completeValue( exeContext, returnType.ofType, @@ -959,7 +962,7 @@ function completeValue( } // If field type is List, complete each item in the list with the inner type - if (returnType instanceof GraphQLList) { + if (isListType(returnType)) { return completeListValue( exeContext, returnType, @@ -990,7 +993,7 @@ function completeValue( } // If field type is Object, execute and complete all sub-selections. - if (returnType instanceof GraphQLObjectType) { + if (isObjectType(returnType)) { return completeObjectValue( exeContext, returnType, @@ -1002,6 +1005,7 @@ function completeValue( } // Not reachable. All possible output types have been considered. + /* istanbul ignore next */ throw new Error( `Cannot complete value of unexpected type "${String( (returnType: empty), @@ -1015,7 +1019,7 @@ function completeValue( */ function completeListValue( exeContext: ExecutionContext, - returnType: GraphQLList<*>, + returnType: GraphQLList, fieldNodes: $ReadOnlyArray, info: GraphQLResolveInfo, path: ResponsePath, @@ -1138,7 +1142,7 @@ function ensureValidRuntimeType( ? exeContext.schema.getType(runtimeTypeOrName) : runtimeTypeOrName; - if (!(runtimeType instanceof GraphQLObjectType)) { + if (!isObjectType(runtimeType)) { throw new GraphQLError( `Abstract type ${returnType.name} must resolve to an Object type at ` + `runtime for field ${info.parentType.name}.${info.fieldName} with ` + diff --git a/src/execution/values.js b/src/execution/values.js index 1423720442..b914ce810d 100644 --- a/src/execution/values.js +++ b/src/execution/values.js @@ -17,9 +17,7 @@ import { valueFromAST } from '../utilities/valueFromAST'; import { isValidLiteralValue } from '../utilities/isValidLiteralValue'; import * as Kind from '../language/kinds'; import { print } from '../language/printer'; -import { isInputType } from '../type/definition'; -import { GraphQLNonNull } from '../type/wrappers'; - +import { isInputType, isNonNullType } from '../type/definition'; import type { ObjMap } from '../jsutils/ObjMap'; import type { GraphQLField } from '../type/definition'; import type { GraphQLDirective } from '../type/directives'; @@ -69,7 +67,7 @@ export function getVariableValues( } else { const value = inputs[varName]; if (isInvalid(value)) { - if (varType instanceof GraphQLNonNull) { + if (isNonNullType(varType)) { errors.push( new GraphQLError( `Variable "$${varName}" of required type ` + @@ -134,7 +132,7 @@ export function getArgumentValues( if (!argumentNode) { if (!isInvalid(defaultValue)) { coercedValues[name] = defaultValue; - } else if (argType instanceof GraphQLNonNull) { + } else if (isNonNullType(argType)) { throw new GraphQLError( `Argument "${name}" of required type ` + `"${String(argType)}" was not provided.`, @@ -154,7 +152,7 @@ export function getArgumentValues( coercedValues[name] = variableValues[variableName]; } else if (!isInvalid(defaultValue)) { coercedValues[name] = defaultValue; - } else if (argType instanceof GraphQLNonNull) { + } else if (isNonNullType(argType)) { throw new GraphQLError( `Argument "${name}" of required type "${String(argType)}" was ` + `provided the variable "$${variableName}" which was not provided ` + diff --git a/src/index.js b/src/index.js index b595e5047f..9955d56509 100644 --- a/src/index.js +++ b/src/index.js @@ -79,23 +79,45 @@ export { __EnumValue, __TypeKind, // Predicates + isSchema, + isDirective, isType, + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, isInputType, isOutputType, isLeafType, isCompositeType, isAbstractType, + isWrappingType, + isNullableType, isNamedType, isSpecifiedScalarType, isIntrospectionType, isSpecifiedDirective, // Assertions assertType, + assertScalarType, + assertObjectType, + assertInterfaceType, + assertUnionType, + assertEnumType, + assertInputObjectType, + assertListType, + assertNonNullType, assertInputType, assertOutputType, assertLeafType, assertCompositeType, assertAbstractType, + assertWrappingType, + assertNullableType, assertNamedType, // Un-modifiers getNullableType, @@ -112,6 +134,7 @@ export type { GraphQLLeafType, GraphQLCompositeType, GraphQLAbstractType, + GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, Thunk, diff --git a/src/jsutils/instanceOf.js b/src/jsutils/instanceOf.js new file mode 100644 index 0000000000..8c37778360 --- /dev/null +++ b/src/jsutils/instanceOf.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +/** + * A replacement for instanceof which includes an error warning when multi-realm + * constructors are detected. + */ +declare function instanceOf( + value: mixed, + constructor: mixed, +): boolean %checks(value instanceof constructor); + +// eslint-disable-next-line no-redeclare +export default function instanceOf(value, constructor) { + if (value instanceof constructor) { + return true; + } + if (value) { + const valueConstructor = value.constructor; + if (valueConstructor && valueConstructor.name === constructor.name) { + throw new Error( + `Cannot use ${constructor.name} "${value}" from another module or realm. + +Ensure that there is only one instance of "graphql" in the node_modules +directory. If different versions of "graphql" are the dependencies of other +relied on modules, use "resolutions" to ensure only one version is installed. + +https://yarnpkg.com/en/docs/selective-version-resolutions + +Duplicate "graphql" modules cannot be used at the same time since different +versions may have different capabilities and behavior. The data from one +version used in the function from another could produce confusing and +spurious results.`, + ); + } + } + return false; +} diff --git a/src/jsutils/invariant.js b/src/jsutils/invariant.js index 0b60045356..8704978fb3 100644 --- a/src/jsutils/invariant.js +++ b/src/jsutils/invariant.js @@ -8,6 +8,7 @@ */ export default function invariant(condition: mixed, message: string) { + /* istanbul ignore else */ if (!condition) { throw new Error(message); } diff --git a/src/subscription/__tests__/subscribe-test.js b/src/subscription/__tests__/subscribe-test.js index 5d0525521a..141733de36 100644 --- a/src/subscription/__tests__/subscribe-test.js +++ b/src/subscription/__tests__/subscribe-test.js @@ -313,12 +313,12 @@ describe('Subscription Initialization Phase', () => { await expectPromiseToThrow( () => subscribe(null, document), - 'Must provide schema.', + 'Expected null to be a GraphQL schema.', ); await expectPromiseToThrow( () => subscribe({ document }), - 'Must provide schema.', + 'Expected undefined to be a GraphQL schema.', ); }); diff --git a/src/type/__tests__/definition-test.js b/src/type/__tests__/definition-test.js index 68c8fde83f..da8aec0841 100644 --- a/src/type/__tests__/definition-test.js +++ b/src/type/__tests__/definition-test.js @@ -23,7 +23,7 @@ import { import { describe, it } from 'mocha'; import { expect } from 'chai'; -import { isInputType, isOutputType } from '../definition'; +import { isObjectType, isInputType, isOutputType } from '../definition'; const BlogImage = new GraphQLObjectType({ name: 'Image', @@ -118,19 +118,19 @@ describe('Type System: Example', () => { const articleFieldType = articleField ? articleField.type : null; const titleField = - articleFieldType instanceof GraphQLObjectType && + isObjectType(articleFieldType) && articleFieldType.getFields()[('title': string)]; expect(titleField && titleField.name).to.equal('title'); expect(titleField && titleField.type).to.equal(GraphQLString); expect(titleField && titleField.type.name).to.equal('String'); const authorField = - articleFieldType instanceof GraphQLObjectType && + isObjectType(articleFieldType) && articleFieldType.getFields()[('author': string)]; const authorFieldType = authorField ? authorField.type : null; const recentArticleField = - authorFieldType instanceof GraphQLObjectType && + isObjectType(authorFieldType) && authorFieldType.getFields()[('recentArticle': string)]; expect(recentArticleField && recentArticleField.type).to.equal(BlogArticle); @@ -374,12 +374,6 @@ describe('Type System: Example', () => { }); }); - it('prohibits nesting NonNull inside NonNull', () => { - expect(() => GraphQLNonNull(GraphQLNonNull(GraphQLInt))).to.throw( - 'Can only create NonNull of a Nullable GraphQLType but got: Int!.', - ); - }); - it('prohibits putting non-Object types in unions', () => { const badUnionTypes = [ GraphQLInt, @@ -476,7 +470,7 @@ describe('Type System: Example', () => { }); }); -describe('Type System: List must accept GraphQL types', () => { +describe('Type System: List must accept only types', () => { const types = [ GraphQLString, ScalarType, @@ -506,7 +500,7 @@ describe('Type System: List must accept GraphQL types', () => { }); }); -describe('Type System: NonNull must accept GraphQL types', () => { +describe('Type System: NonNull must only accept non-nullable types', () => { const nullableTypes = [ GraphQLString, ScalarType, @@ -536,7 +530,7 @@ describe('Type System: NonNull must accept GraphQL types', () => { notNullableTypes.forEach(type => { it(`rejects a non-type as nullable type of non-null: ${type}`, () => { expect(() => GraphQLNonNull(type)).to.throw( - `Can only create NonNull of a Nullable GraphQLType but got: ${type}.`, + `Expected ${type} to be a GraphQL nullable type.`, ); }); }); diff --git a/src/type/__tests__/predicate-test.js b/src/type/__tests__/predicate-test.js new file mode 100644 index 0000000000..148e42e240 --- /dev/null +++ b/src/type/__tests__/predicate-test.js @@ -0,0 +1,472 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { describe, it } from 'mocha'; +import { expect } from 'chai'; + +import { + GraphQLScalarType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLUnionType, + GraphQLList, + GraphQLNonNull, + GraphQLString, + isType, + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, + isInputType, + isOutputType, + isLeafType, + isCompositeType, + isAbstractType, + isWrappingType, + isNullableType, + isNamedType, + assertType, + assertScalarType, + assertObjectType, + assertInterfaceType, + assertUnionType, + assertEnumType, + assertInputObjectType, + assertListType, + assertNonNullType, + assertInputType, + assertOutputType, + assertLeafType, + assertCompositeType, + assertAbstractType, + assertWrappingType, + assertNullableType, + assertNamedType, + getNullableType, + getNamedType, +} from '../'; + +const ObjectType = new GraphQLObjectType({ name: 'Object' }); +const InterfaceType = new GraphQLInterfaceType({ name: 'Interface' }); +const UnionType = new GraphQLUnionType({ name: 'Union', types: [ObjectType] }); +const EnumType = new GraphQLEnumType({ name: 'Enum', values: { foo: {} } }); +const InputObjectType = new GraphQLInputObjectType({ name: 'InputObject' }); +const ScalarType = new GraphQLScalarType({ + name: 'Scalar', + serialize() {}, + parseValue() {}, + parseLiteral() {}, +}); + +describe('Type predicates', () => { + describe('isType', () => { + it('returns true for unwrapped types', () => { + expect(isType(GraphQLString)).to.equal(true); + expect(() => assertType(GraphQLString)).not.to.throw(); + expect(isType(ObjectType)).to.equal(true); + expect(() => assertType(ObjectType)).not.to.throw(); + }); + + it('returns true for wrapped types', () => { + expect(isType(GraphQLNonNull(GraphQLString))).to.equal(true); + expect(() => assertType(GraphQLNonNull(GraphQLString))).not.to.throw(); + }); + + it('returns false for type classes (rather than instances)', () => { + expect(isType(GraphQLObjectType)).to.equal(false); + expect(() => assertType(GraphQLObjectType)).to.throw(); + }); + + it('returns false for random garbage', () => { + expect(isType({ what: 'is this' })).to.equal(false); + expect(() => assertType({ what: 'is this' })).to.throw(); + }); + }); + + describe('isScalarType', () => { + it('returns true for spec defined scalar', () => { + expect(isScalarType(GraphQLString)).to.equal(true); + expect(() => assertScalarType(GraphQLString)).not.to.throw(); + }); + + it('returns true for custom scalar', () => { + expect(isScalarType(ScalarType)).to.equal(true); + expect(() => assertScalarType(ScalarType)).not.to.throw(); + }); + + it('returns false for wrapped scalar', () => { + expect(isScalarType(GraphQLList(ScalarType))).to.equal(false); + expect(() => assertScalarType(GraphQLList(ScalarType))).to.throw(); + }); + + it('returns false for non-scalar', () => { + expect(isScalarType(EnumType)).to.equal(false); + expect(() => assertScalarType(EnumType)).to.throw(); + }); + }); + + describe('isObjectType', () => { + it('returns true for object type', () => { + expect(isObjectType(ObjectType)).to.equal(true); + expect(() => assertObjectType(ObjectType)).not.to.throw(); + }); + + it('returns false for wrapped object type', () => { + expect(isObjectType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertObjectType(GraphQLList(ObjectType))).to.throw(); + }); + + it('returns false for non-object type', () => { + expect(isObjectType(InterfaceType)).to.equal(false); + expect(() => assertObjectType(InterfaceType)).to.throw(); + }); + }); + + describe('isInterfaceType', () => { + it('returns true for interface type', () => { + expect(isInterfaceType(InterfaceType)).to.equal(true); + expect(() => assertInterfaceType(InterfaceType)).not.to.throw(); + }); + + it('returns false for wrapped interface type', () => { + expect(isInterfaceType(GraphQLList(InterfaceType))).to.equal(false); + expect(() => assertInterfaceType(GraphQLList(InterfaceType))).to.throw(); + }); + + it('returns false for non-interface type', () => { + expect(isInterfaceType(ObjectType)).to.equal(false); + expect(() => assertInterfaceType(ObjectType)).to.throw(); + }); + }); + + describe('isUnionType', () => { + it('returns true for union type', () => { + expect(isUnionType(UnionType)).to.equal(true); + expect(() => assertUnionType(UnionType)).not.to.throw(); + }); + + it('returns false for wrapped union type', () => { + expect(isUnionType(GraphQLList(UnionType))).to.equal(false); + expect(() => assertUnionType(GraphQLList(UnionType))).to.throw(); + }); + + it('returns false for non-union type', () => { + expect(isUnionType(ObjectType)).to.equal(false); + expect(() => assertUnionType(ObjectType)).to.throw(); + }); + }); + + describe('isEnumType', () => { + it('returns true for enum type', () => { + expect(isEnumType(EnumType)).to.equal(true); + expect(() => assertEnumType(EnumType)).not.to.throw(); + }); + + it('returns false for wrapped enum type', () => { + expect(isEnumType(GraphQLList(EnumType))).to.equal(false); + expect(() => assertEnumType(GraphQLList(EnumType))).to.throw(); + }); + + it('returns false for non-enum type', () => { + expect(isEnumType(ScalarType)).to.equal(false); + expect(() => assertEnumType(ScalarType)).to.throw(); + }); + }); + + describe('isInputObjectType', () => { + it('returns true for input object type', () => { + expect(isInputObjectType(InputObjectType)).to.equal(true); + expect(() => assertInputObjectType(InputObjectType)).not.to.throw(); + }); + + it('returns false for wrapped input object type', () => { + expect(isInputObjectType(GraphQLList(InputObjectType))).to.equal(false); + expect(() => + assertInputObjectType(GraphQLList(InputObjectType)), + ).to.throw(); + }); + + it('returns false for non-input-object type', () => { + expect(isInputObjectType(ObjectType)).to.equal(false); + expect(() => assertInputObjectType(ObjectType)).to.throw(); + }); + }); + + describe('isListType', () => { + it('returns true for a list wrapped type', () => { + expect(isListType(GraphQLList(ObjectType))).to.equal(true); + expect(() => assertListType(GraphQLList(ObjectType))).not.to.throw(); + }); + + it('returns false for an unwrapped type', () => { + expect(isListType(ObjectType)).to.equal(false); + expect(() => assertListType(ObjectType)).to.throw(); + }); + + it('returns true for a non-list wrapped type', () => { + expect(isListType(GraphQLNonNull(GraphQLList(ObjectType)))).to.equal( + false, + ); + expect(() => + assertListType(GraphQLNonNull(GraphQLList(ObjectType))), + ).to.throw(); + }); + }); + + describe('isNonNullType', () => { + it('returns true for a non-null wrapped type', () => { + expect(isNonNullType(GraphQLNonNull(ObjectType))).to.equal(true); + expect(() => + assertNonNullType(GraphQLNonNull(ObjectType)), + ).not.to.throw(); + }); + + it('returns false for an unwrapped type', () => { + expect(isNonNullType(ObjectType)).to.equal(false); + expect(() => assertNonNullType(ObjectType)).to.throw(); + }); + + it('returns true for a not non-null wrapped type', () => { + expect(isNonNullType(GraphQLList(GraphQLNonNull(ObjectType)))).to.equal( + false, + ); + expect(() => + assertNonNullType(GraphQLList(GraphQLNonNull(ObjectType))), + ).to.throw(); + }); + }); + + describe('isInputType', () => { + it('returns true for an input type', () => { + expect(isInputType(InputObjectType)).to.equal(true); + expect(() => assertInputType(InputObjectType)).not.to.throw(); + }); + + it('returns true for a wrapped input type', () => { + expect(isInputType(GraphQLList(InputObjectType))).to.equal(true); + expect(() => + assertInputType(GraphQLList(InputObjectType)), + ).not.to.throw(); + expect(isInputType(GraphQLNonNull(InputObjectType))).to.equal(true); + expect(() => + assertInputType(GraphQLNonNull(InputObjectType)), + ).not.to.throw(); + }); + + it('returns false for an output type', () => { + expect(isInputType(ObjectType)).to.equal(false); + expect(() => assertInputType(ObjectType)).to.throw(); + }); + + it('returns false for a wrapped output type', () => { + expect(isInputType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertInputType(GraphQLList(ObjectType))).to.throw(); + expect(isInputType(GraphQLNonNull(ObjectType))).to.equal(false); + expect(() => assertInputType(GraphQLNonNull(ObjectType))).to.throw(); + }); + }); + + describe('isOutputType', () => { + it('returns true for an output type', () => { + expect(isOutputType(ObjectType)).to.equal(true); + expect(() => assertOutputType(ObjectType)).not.to.throw(); + }); + + it('returns true for a wrapped output type', () => { + expect(isOutputType(GraphQLList(ObjectType))).to.equal(true); + expect(() => assertOutputType(GraphQLList(ObjectType))).not.to.throw(); + expect(isOutputType(GraphQLNonNull(ObjectType))).to.equal(true); + expect(() => assertOutputType(GraphQLNonNull(ObjectType))).not.to.throw(); + }); + + it('returns false for an input type', () => { + expect(isOutputType(InputObjectType)).to.equal(false); + expect(() => assertOutputType(InputObjectType)).to.throw(); + }); + + it('returns false for a wrapped input type', () => { + expect(isOutputType(GraphQLList(InputObjectType))).to.equal(false); + expect(() => assertOutputType(GraphQLList(InputObjectType))).to.throw(); + expect(isOutputType(GraphQLNonNull(InputObjectType))).to.equal(false); + expect(() => + assertOutputType(GraphQLNonNull(InputObjectType)), + ).to.throw(); + }); + }); + + describe('isLeafType', () => { + it('returns true for scalar and enum types', () => { + expect(isLeafType(ScalarType)).to.equal(true); + expect(() => assertLeafType(ScalarType)).not.to.throw(); + expect(isLeafType(EnumType)).to.equal(true); + expect(() => assertLeafType(EnumType)).not.to.throw(); + }); + + it('returns false for wrapped leaf type', () => { + expect(isLeafType(GraphQLList(ScalarType))).to.equal(false); + expect(() => assertLeafType(GraphQLList(ScalarType))).to.throw(); + }); + + it('returns false for non-leaf type', () => { + expect(isLeafType(ObjectType)).to.equal(false); + expect(() => assertLeafType(ObjectType)).to.throw(); + }); + + it('returns false for wrapped non-leaf type', () => { + expect(isLeafType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertLeafType(GraphQLList(ObjectType))).to.throw(); + }); + }); + + describe('isCompositeType', () => { + it('returns true for object, interface, and union types', () => { + expect(isCompositeType(ObjectType)).to.equal(true); + expect(() => assertCompositeType(ObjectType)).not.to.throw(); + expect(isCompositeType(InterfaceType)).to.equal(true); + expect(() => assertCompositeType(InterfaceType)).not.to.throw(); + expect(isCompositeType(UnionType)).to.equal(true); + expect(() => assertCompositeType(UnionType)).not.to.throw(); + }); + + it('returns false for wrapped composite type', () => { + expect(isCompositeType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertCompositeType(GraphQLList(ObjectType))).to.throw(); + }); + + it('returns false for non-composite type', () => { + expect(isCompositeType(InputObjectType)).to.equal(false); + expect(() => assertCompositeType(InputObjectType)).to.throw(); + }); + + it('returns false for wrapped non-composite type', () => { + expect(isCompositeType(GraphQLList(InputObjectType))).to.equal(false); + expect(() => + assertCompositeType(GraphQLList(InputObjectType)), + ).to.throw(); + }); + }); + + describe('isAbstractType', () => { + it('returns true for interface and union types', () => { + expect(isAbstractType(InterfaceType)).to.equal(true); + expect(() => assertAbstractType(InterfaceType)).not.to.throw(); + expect(isAbstractType(UnionType)).to.equal(true); + expect(() => assertAbstractType(UnionType)).not.to.throw(); + }); + + it('returns false for wrapped abstract type', () => { + expect(isAbstractType(GraphQLList(InterfaceType))).to.equal(false); + expect(() => assertAbstractType(GraphQLList(InterfaceType))).to.throw(); + }); + + it('returns false for non-abstract type', () => { + expect(isAbstractType(ObjectType)).to.equal(false); + expect(() => assertAbstractType(ObjectType)).to.throw(); + }); + + it('returns false for wrapped non-abstract type', () => { + expect(isAbstractType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertAbstractType(GraphQLList(ObjectType))).to.throw(); + }); + }); + + describe('isWrappingType', () => { + it('returns true for list and non-null types', () => { + expect(isWrappingType(GraphQLList(ObjectType))).to.equal(true); + expect(() => assertWrappingType(GraphQLList(ObjectType))).not.to.throw(); + expect(isWrappingType(GraphQLNonNull(ObjectType))).to.equal(true); + expect(() => + assertWrappingType(GraphQLNonNull(ObjectType)), + ).not.to.throw(); + }); + + it('returns false for unwrapped types', () => { + expect(isWrappingType(ObjectType)).to.equal(false); + expect(() => assertWrappingType(ObjectType)).to.throw(); + }); + }); + + describe('isNullableType', () => { + it('returns true for unwrapped types', () => { + expect(isNullableType(ObjectType)).to.equal(true); + expect(() => assertNullableType(ObjectType)).not.to.throw(); + }); + + it('returns true for list of non-null types', () => { + expect(isNullableType(GraphQLList(GraphQLNonNull(ObjectType)))).to.equal( + true, + ); + expect(() => + assertNullableType(GraphQLList(GraphQLNonNull(ObjectType))), + ).not.to.throw(); + }); + + it('returns false for non-null types', () => { + expect(isNullableType(GraphQLNonNull(ObjectType))).to.equal(false); + expect(() => assertNullableType(GraphQLNonNull(ObjectType))).to.throw(); + }); + }); + + describe('getNullableType', () => { + it('returns undefined for no type', () => { + expect(getNullableType()).to.equal(undefined); + expect(getNullableType(null)).to.equal(undefined); + }); + + it('returns self for a nullable type', () => { + expect(getNullableType(ObjectType)).to.equal(ObjectType); + const listOfObj = GraphQLList(ObjectType); + expect(getNullableType(listOfObj)).to.equal(listOfObj); + }); + + it('unwraps non-null type', () => { + expect(getNullableType(GraphQLNonNull(ObjectType))).to.equal(ObjectType); + }); + }); + + describe('isNamedType', () => { + it('returns true for unwrapped types', () => { + expect(isNamedType(ObjectType)).to.equal(true); + expect(() => assertNamedType(ObjectType)).not.to.throw(); + }); + + it('returns false for list and non-null types', () => { + expect(isNamedType(GraphQLList(ObjectType))).to.equal(false); + expect(() => assertNamedType(GraphQLList(ObjectType))).to.throw(); + expect(isNamedType(GraphQLNonNull(ObjectType))).to.equal(false); + expect(() => assertNamedType(GraphQLNonNull(ObjectType))).to.throw(); + }); + }); + + describe('getNamedType', () => { + it('returns undefined for no type', () => { + expect(getNamedType()).to.equal(undefined); + expect(getNamedType(null)).to.equal(undefined); + }); + + it('returns self for a unwrapped type', () => { + expect(getNamedType(ObjectType)).to.equal(ObjectType); + }); + + it('unwraps wrapper types', () => { + expect(getNamedType(GraphQLNonNull(ObjectType))).to.equal(ObjectType); + expect(getNamedType(GraphQLList(ObjectType))).to.equal(ObjectType); + }); + + it('unwraps deeply wrapper types', () => { + expect( + getNamedType(GraphQLNonNull(GraphQLList(GraphQLNonNull(ObjectType)))), + ).to.equal(ObjectType); + }); + }); +}); diff --git a/src/type/definition.js b/src/type/definition.js index b4c78b2671..3107904ba6 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -7,6 +7,7 @@ * @flow */ +import instanceOf from '../jsutils/instanceOf'; import invariant from '../jsutils/invariant'; import isInvalid from '../jsutils/isInvalid'; import type { ObjMap } from '../jsutils/ObjMap'; @@ -50,14 +51,14 @@ export type GraphQLType = export function isType(type: mixed): boolean %checks { return ( - type instanceof GraphQLScalarType || - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType || - type instanceof GraphQLEnumType || - type instanceof GraphQLInputObjectType || - type instanceof GraphQLList || - type instanceof GraphQLNonNull + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) || + isListType(type) || + isNonNullType(type) ); } @@ -66,6 +67,130 @@ export function assertType(type: mixed): GraphQLType { return (type: any); } +/** + * There are predicates for each kind of GraphQL type. + */ + +declare function isScalarType(type: mixed): boolean %checks(type instanceof + GraphQLScalarType); +// eslint-disable-next-line no-redeclare +export function isScalarType(type) { + return instanceOf(type, GraphQLScalarType); +} + +export function assertScalarType(type: mixed): GraphQLScalarType { + invariant( + isScalarType(type), + `Expected ${String(type)} to be a GraphQL Scalar type.`, + ); + return type; +} + +declare function isObjectType(type: mixed): boolean %checks(type instanceof + GraphQLObjectType); +// eslint-disable-next-line no-redeclare +export function isObjectType(type) { + return instanceOf(type, GraphQLObjectType); +} + +export function assertObjectType(type: mixed): GraphQLObjectType { + invariant( + isObjectType(type), + `Expected ${String(type)} to be a GraphQL Object type.`, + ); + return type; +} + +declare function isInterfaceType(type: mixed): boolean %checks(type instanceof + GraphQLInterfaceType); +// eslint-disable-next-line no-redeclare +export function isInterfaceType(type) { + return instanceOf(type, GraphQLInterfaceType); +} + +export function assertInterfaceType(type: mixed): GraphQLInterfaceType { + invariant( + isInterfaceType(type), + `Expected ${String(type)} to be a GraphQL Interface type.`, + ); + return type; +} + +declare function isUnionType(type: mixed): boolean %checks(type instanceof + GraphQLUnionType); +// eslint-disable-next-line no-redeclare +export function isUnionType(type) { + return instanceOf(type, GraphQLUnionType); +} + +export function assertUnionType(type: mixed): GraphQLUnionType { + invariant( + isUnionType(type), + `Expected ${String(type)} to be a GraphQL Union type.`, + ); + return type; +} + +declare function isEnumType(type: mixed): boolean %checks(type instanceof + GraphQLEnumType); +// eslint-disable-next-line no-redeclare +export function isEnumType(type) { + return instanceOf(type, GraphQLEnumType); +} + +export function assertEnumType(type: mixed): GraphQLEnumType { + invariant( + isEnumType(type), + `Expected ${String(type)} to be a GraphQL Enum type.`, + ); + return type; +} + +declare function isInputObjectType(type: mixed): boolean %checks(type instanceof + GraphQLInputObjectType); +// eslint-disable-next-line no-redeclare +export function isInputObjectType(type) { + return instanceOf(type, GraphQLInputObjectType); +} + +export function assertInputObjectType(type: mixed): GraphQLInputObjectType { + invariant( + isInputObjectType(type), + `Expected ${String(type)} to be a GraphQL Input Object type.`, + ); + return type; +} + +declare function isListType(type: mixed): boolean %checks(type instanceof + GraphQLList); +// eslint-disable-next-line no-redeclare +export function isListType(type) { + return instanceOf(type, GraphQLList); +} + +export function assertListType(type: mixed): GraphQLList { + invariant( + isListType(type), + `Expected ${String(type)} to be a GraphQL List type.`, + ); + return type; +} + +declare function isNonNullType(type: mixed): boolean %checks(type instanceof + GraphQLNonNull); +// eslint-disable-next-line no-redeclare +export function isNonNullType(type) { + return instanceOf(type, GraphQLNonNull); +} + +export function assertNonNullType(type: mixed): GraphQLNonNull { + invariant( + isNonNullType(type), + `Expected ${String(type)} to be a GraphQL Non-Null type.`, + ); + return type; +} + /** * These types may be used as input types for arguments and directives. */ @@ -81,17 +206,16 @@ export type GraphQLInputType = | GraphQLList, >; -export function isInputType(type: ?GraphQLType): boolean %checks { +export function isInputType(type: mixed): boolean %checks { return ( - type instanceof GraphQLScalarType || - type instanceof GraphQLEnumType || - type instanceof GraphQLInputObjectType || - (type instanceof GraphQLNonNull && isInputType(type.ofType)) || - (type instanceof GraphQLList && isInputType(type.ofType)) + isScalarType(type) || + isEnumType(type) || + isInputObjectType(type) || + (isWrappingType(type) && isInputType(type.ofType)) ); } -export function assertInputType(type: ?GraphQLType): GraphQLInputType { +export function assertInputType(type: mixed): GraphQLInputType { invariant( isInputType(type), `Expected ${String(type)} to be a GraphQL input type.`, @@ -118,19 +242,18 @@ export type GraphQLOutputType = | GraphQLList, >; -export function isOutputType(type: ?GraphQLType): boolean %checks { +export function isOutputType(type: mixed): boolean %checks { return ( - type instanceof GraphQLScalarType || - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType || - type instanceof GraphQLEnumType || - (type instanceof GraphQLNonNull && isOutputType(type.ofType)) || - (type instanceof GraphQLList && isOutputType(type.ofType)) + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + (isWrappingType(type) && isOutputType(type.ofType)) ); } -export function assertOutputType(type: ?GraphQLType): GraphQLOutputType { +export function assertOutputType(type: mixed): GraphQLOutputType { invariant( isOutputType(type), `Expected ${String(type)} to be a GraphQL output type.`, @@ -143,11 +266,11 @@ export function assertOutputType(type: ?GraphQLType): GraphQLOutputType { */ export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; -export function isLeafType(type: ?GraphQLType): boolean %checks { - return type instanceof GraphQLScalarType || type instanceof GraphQLEnumType; +export function isLeafType(type: mixed): boolean %checks { + return isScalarType(type) || isEnumType(type); } -export function assertLeafType(type: ?GraphQLType): GraphQLLeafType { +export function assertLeafType(type: mixed): GraphQLLeafType { invariant( isLeafType(type), `Expected ${String(type)} to be a GraphQL leaf type.`, @@ -163,15 +286,11 @@ export type GraphQLCompositeType = | GraphQLInterfaceType | GraphQLUnionType; -export function isCompositeType(type: ?GraphQLType): boolean %checks { - return ( - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType - ); +export function isCompositeType(type: mixed): boolean %checks { + return isObjectType(type) || isInterfaceType(type) || isUnionType(type); } -export function assertCompositeType(type: ?GraphQLType): GraphQLCompositeType { +export function assertCompositeType(type: mixed): GraphQLCompositeType { invariant( isCompositeType(type), `Expected ${String(type)} to be a GraphQL composite type.`, @@ -184,13 +303,11 @@ export function assertCompositeType(type: ?GraphQLType): GraphQLCompositeType { */ export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; -export function isAbstractType(type: ?GraphQLType): boolean %checks { - return ( - type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType - ); +export function isAbstractType(type: mixed): boolean %checks { + return isInterfaceType(type) || isUnionType(type); } -export function assertAbstractType(type: ?GraphQLType): GraphQLAbstractType { +export function assertAbstractType(type: mixed): GraphQLAbstractType { invariant( isAbstractType(type), `Expected ${String(type)} to be a GraphQL abstract type.`, @@ -198,6 +315,24 @@ export function assertAbstractType(type: ?GraphQLType): GraphQLAbstractType { return type; } +/** + * These types wrap and modify other types + */ + +export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; + +export function isWrappingType(type: mixed): boolean %checks { + return isListType(type) || isNonNullType(type); +} + +export function assertWrappingType(type: mixed): GraphQLWrappingType { + invariant( + isWrappingType(type), + `Expected ${String(type)} to be a GraphQL wrapping type.`, + ); + return type; +} + /** * These types can all accept null as a value. */ @@ -210,6 +345,18 @@ export type GraphQLNullableType = | GraphQLInputObjectType | GraphQLList; +export function isNullableType(type: mixed): boolean %checks { + return isType(type) && !isNonNullType(type); +} + +export function assertNullableType(type: mixed): GraphQLNullableType { + invariant( + isNullableType(type), + `Expected ${String(type)} to be a GraphQL nullable type.`, + ); + return type; +} + /* eslint-disable no-redeclare */ declare function getNullableType(type: void | null): void; declare function getNullableType(type: T): T; @@ -217,7 +364,7 @@ declare function getNullableType(type: GraphQLNonNull): T; export function getNullableType(type) { /* eslint-enable no-redeclare */ if (type) { - return type instanceof GraphQLNonNull ? type.ofType : type; + return isNonNullType(type) ? type.ofType : type; } } @@ -232,18 +379,18 @@ export type GraphQLNamedType = | GraphQLEnumType | GraphQLInputObjectType; -export function isNamedType(type: ?GraphQLType): boolean %checks { +export function isNamedType(type: mixed): boolean %checks { return ( - type instanceof GraphQLScalarType || - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType || - type instanceof GraphQLEnumType || - type instanceof GraphQLInputObjectType + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) ); } -export function assertNamedType(type: ?GraphQLType): GraphQLNamedType { +export function assertNamedType(type: mixed): GraphQLNamedType { invariant( isNamedType(type), `Expected ${String(type)} to be a GraphQL named type.`, @@ -257,14 +404,11 @@ declare function getNamedType(type: GraphQLType): GraphQLNamedType; export function getNamedType(type) { /* eslint-enable no-redeclare */ if (type) { - let unmodifiedType = type; - while ( - unmodifiedType instanceof GraphQLList || - unmodifiedType instanceof GraphQLNonNull - ) { - unmodifiedType = unmodifiedType.ofType; + let unwrappedType = type; + while (isWrappingType(unwrappedType)) { + unwrappedType = unwrappedType.ofType; } - return unmodifiedType; + return unwrappedType; } } @@ -821,7 +965,7 @@ function defineTypes( const includedTypeNames = Object.create(null); types.forEach(objType => { invariant( - objType instanceof GraphQLObjectType, + isObjectType(objType), `${unionType.name} may only contain Object types, it cannot contain: ` + `${String(objType)}.`, ); diff --git a/src/type/directives.js b/src/type/directives.js index 944ac479ec..885087808d 100644 --- a/src/type/directives.js +++ b/src/type/directives.js @@ -15,6 +15,7 @@ import type { GraphQLArgument, } from './definition'; import { GraphQLString, GraphQLBoolean } from './scalars'; +import instanceOf from '../jsutils/instanceOf'; import invariant from '../jsutils/invariant'; import { assertValidName } from '../utilities/assertValidName'; import type { DirectiveDefinitionNode } from '../language/ast'; @@ -23,6 +24,17 @@ import { type DirectiveLocationEnum, } from '../language/directiveLocation'; +/** + * Test if the given value is a GraphQL directive. + */ +declare function isDirective( + directive: mixed, +): boolean %checks(directive instanceof GraphQLDirective); +// eslint-disable-next-line no-redeclare +export function isDirective(directive) { + return instanceOf(directive, GraphQLDirective); +} + /** * Directives are used by the GraphQL runtime as a way of modifying execution * behavior. Type system creators will usually not create these directly. diff --git a/src/type/index.js b/src/type/index.js index caf6904fd9..86686be003 100644 --- a/src/type/index.js +++ b/src/type/index.js @@ -7,25 +7,49 @@ * @flow */ -// GraphQL Schema definition -export { GraphQLSchema } from './schema'; +export { + // Predicate + isSchema, + // GraphQL Schema definition + GraphQLSchema, +} from './schema'; export { // Predicates isType, + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, isInputType, isOutputType, isLeafType, isCompositeType, isAbstractType, + isWrappingType, + isNullableType, isNamedType, // Assertions assertType, + assertScalarType, + assertObjectType, + assertInterfaceType, + assertUnionType, + assertEnumType, + assertInputObjectType, + assertListType, + assertNonNullType, assertInputType, assertOutputType, assertLeafType, assertCompositeType, assertAbstractType, + assertWrappingType, + assertNullableType, assertNamedType, // Un-modifiers getNullableType, @@ -46,6 +70,8 @@ export { } from './wrappers'; export { + // Predicate + isDirective, // Directives Definition GraphQLDirective, // Built-in Directives defined by the Spec @@ -96,6 +122,7 @@ export type { GraphQLLeafType, GraphQLCompositeType, GraphQLAbstractType, + GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, Thunk, diff --git a/src/type/introspection.js b/src/type/introspection.js index 3d1ac05d82..0340c182af 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -11,12 +11,16 @@ import isInvalid from '../jsutils/isInvalid'; import { astFromValue } from '../utilities/astFromValue'; import { print } from '../language/printer'; import { - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, - GraphQLInputObjectType, + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, isAbstractType, isNamedType, } from './definition'; @@ -212,21 +216,21 @@ export const __Type = new GraphQLObjectType({ kind: { type: GraphQLNonNull(__TypeKind), resolve(type) { - if (type instanceof GraphQLScalarType) { + if (isScalarType(type)) { return TypeKind.SCALAR; - } else if (type instanceof GraphQLObjectType) { + } else if (isObjectType(type)) { return TypeKind.OBJECT; - } else if (type instanceof GraphQLInterfaceType) { + } else if (isInterfaceType(type)) { return TypeKind.INTERFACE; - } else if (type instanceof GraphQLUnionType) { + } else if (isUnionType(type)) { return TypeKind.UNION; - } else if (type instanceof GraphQLEnumType) { + } else if (isEnumType(type)) { return TypeKind.ENUM; - } else if (type instanceof GraphQLInputObjectType) { + } else if (isInputObjectType(type)) { return TypeKind.INPUT_OBJECT; - } else if (type instanceof GraphQLList) { + } else if (isListType(type)) { return TypeKind.LIST; - } else if (type instanceof GraphQLNonNull) { + } else if (isNonNullType(type)) { return TypeKind.NON_NULL; } throw new Error('Unknown kind of type: ' + type); @@ -240,10 +244,7 @@ export const __Type = new GraphQLObjectType({ includeDeprecated: { type: GraphQLBoolean, defaultValue: false }, }, resolve(type, { includeDeprecated }) { - if ( - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType - ) { + if (isObjectType(type) || isInterfaceType(type)) { const fieldMap = type.getFields(); let fields = Object.keys(fieldMap).map( fieldName => fieldMap[fieldName], @@ -259,7 +260,7 @@ export const __Type = new GraphQLObjectType({ interfaces: { type: GraphQLList(GraphQLNonNull(__Type)), resolve(type) { - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { return type.getInterfaces(); } }, @@ -278,7 +279,7 @@ export const __Type = new GraphQLObjectType({ includeDeprecated: { type: GraphQLBoolean, defaultValue: false }, }, resolve(type, { includeDeprecated }) { - if (type instanceof GraphQLEnumType) { + if (isEnumType(type)) { let values = type.getValues(); if (!includeDeprecated) { values = values.filter(value => !value.deprecationReason); @@ -290,7 +291,7 @@ export const __Type = new GraphQLObjectType({ inputFields: { type: GraphQLList(GraphQLNonNull(__InputValue)), resolve(type) { - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { const fieldMap = type.getFields(); return Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]); } diff --git a/src/type/schema.js b/src/type/schema.js index f8730222f4..d5526443a0 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -8,25 +8,38 @@ */ import { - GraphQLObjectType, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLUnionType, + isObjectType, + isInterfaceType, + isUnionType, + isInputObjectType, + isWrappingType, } from './definition'; -import { GraphQLList, GraphQLNonNull } from './wrappers'; import type { GraphQLType, GraphQLNamedType, GraphQLAbstractType, + GraphQLObjectType, + GraphQLInterfaceType, } from './definition'; import type { SchemaDefinitionNode } from '../language/ast'; import { GraphQLDirective, specifiedDirectives } from './directives'; import type { GraphQLError } from '../error/GraphQLError'; import { __Schema } from './introspection'; import find from '../jsutils/find'; +import instanceOf from '../jsutils/instanceOf'; import invariant from '../jsutils/invariant'; import type { ObjMap } from '../jsutils/ObjMap'; +/** + * Test if the given value is a GraphQL schema. + */ +declare function isSchema(schema: mixed): boolean %checks(schema instanceof + GraphQLSchema); +// eslint-disable-next-line no-redeclare +export function isSchema(schema) { + return instanceOf(schema, GraphQLSchema); +} + /** * Schema Definition * @@ -117,7 +130,7 @@ export class GraphQLSchema { this._implementations = Object.create(null); Object.keys(this._typeMap).forEach(typeName => { const type = this._typeMap[typeName]; - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { type.getInterfaces().forEach(iface => { const impls = this._implementations[iface.name]; if (impls) { @@ -153,11 +166,10 @@ export class GraphQLSchema { getPossibleTypes( abstractType: GraphQLAbstractType, ): $ReadOnlyArray { - if (abstractType instanceof GraphQLUnionType) { + if (isUnionType(abstractType)) { return abstractType.getTypes(); } - invariant(abstractType instanceof GraphQLInterfaceType); - return this._implementations[abstractType.name]; + return this._implementations[(abstractType: GraphQLInterfaceType).name]; } isPossibleType( @@ -211,7 +223,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { if (!type) { return map; } - if (type instanceof GraphQLList || type instanceof GraphQLNonNull) { + if (isWrappingType(type)) { return typeMapReducer(map, type.ofType); } if (map[type.name]) { @@ -226,18 +238,15 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { let reducedMap = map; - if (type instanceof GraphQLUnionType) { + if (isUnionType(type)) { reducedMap = type.getTypes().reduce(typeMapReducer, reducedMap); } - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { reducedMap = type.getInterfaces().reduce(typeMapReducer, reducedMap); } - if ( - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType - ) { + if (isObjectType(type) || isInterfaceType(type)) { const fieldMap = type.getFields(); Object.keys(fieldMap).forEach(fieldName => { const field = fieldMap[fieldName]; @@ -250,7 +259,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { }); } - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { const fieldMap = type.getFields(); Object.keys(fieldMap).forEach(fieldName => { const field = fieldMap[fieldName]; diff --git a/src/type/validate.js b/src/type/validate.js index 1f02dcd39d..ef50d785e3 100644 --- a/src/type/validate.js +++ b/src/type/validate.js @@ -7,11 +7,18 @@ * @flow */ -import { GraphQLInterfaceType, GraphQLObjectType, isType } from './definition'; -import { GraphQLNonNull } from '../type/wrappers'; -import { GraphQLDirective } from './directives'; -import { GraphQLSchema } from './schema'; +import { + isType, + isObjectType, + isInterfaceType, + isNonNullType, +} from './definition'; +import type { GraphQLInterfaceType, GraphQLObjectType } from './definition'; +import { isDirective } from './directives'; +import { isSchema } from './schema'; +import type { GraphQLSchema } from './schema'; import find from '../jsutils/find'; +import invariant from '../jsutils/invariant'; import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; import type { ASTNode, @@ -33,33 +40,10 @@ export function validateSchema( schema: GraphQLSchema, ): $ReadOnlyArray { // First check to ensure the provided value is in fact a GraphQLSchema. - if (!(schema instanceof GraphQLSchema)) { - if (!schema) { - throw new Error('Must provide schema.'); - } - - // Provide as descriptive an error as possible when attempting to use a - // schema cross-realm. - if (Object.getPrototypeOf(schema).constructor.name === 'GraphQLSchema') { - throw new Error(`Cannot use a GraphQLSchema from another module or realm. - -Ensure that there is only one instance of "graphql" in the node_modules -directory. If different versions of "graphql" are the dependencies of other -relied on modules, use "resolutions" to ensure only one version is installed. - -https://yarnpkg.com/en/docs/selective-version-resolutions - -Duplicate "graphql" modules cannot be used at the same time since different -versions may have different capabilities and behavior. The data from one -version used in the function from another could produce confusing and -spurious results.`); - } else { - throw new Error( - 'Schema must be an instance of GraphQLSchema. ' + - `Received: ${String(schema)}`, - ); - } - } + invariant( + isSchema(schema), + `Expected ${String(schema)} to be a GraphQL schema.`, + ); // If this Schema has already been validated, return the previous results. if (schema.__validationErrors) { @@ -114,7 +98,7 @@ function validateRootTypes(context, schema) { const queryType = schema.getQueryType(); if (!queryType) { context.reportError(`Query root type must be provided.`, schema.astNode); - } else if (!(queryType instanceof GraphQLObjectType)) { + } else if (!isObjectType(queryType)) { context.reportError( `Query root type must be Object type but got: ${String(queryType)}.`, getOperationTypeNode(schema, queryType, 'query'), @@ -122,7 +106,7 @@ function validateRootTypes(context, schema) { } const mutationType = schema.getMutationType(); - if (mutationType && !(mutationType instanceof GraphQLObjectType)) { + if (mutationType && !isObjectType(mutationType)) { context.reportError( 'Mutation root type must be Object type if provided but got: ' + `${String(mutationType)}.`, @@ -131,7 +115,7 @@ function validateRootTypes(context, schema) { } const subscriptionType = schema.getSubscriptionType(); - if (subscriptionType && !(subscriptionType instanceof GraphQLObjectType)) { + if (subscriptionType && !isObjectType(subscriptionType)) { context.reportError( 'Subscription root type must be Object type if provided but got: ' + `${String(subscriptionType)}.`, @@ -160,7 +144,7 @@ function validateDirectives( ): void { const directives = schema.getDirectives(); directives.forEach(directive => { - if (!(directive instanceof GraphQLDirective)) { + if (!isDirective(directive)) { context.reportError( `Expected directive but got: ${String(directive)}.`, directive && directive.astNode, @@ -186,7 +170,7 @@ function validateTypes( } // Ensure objects implement the interfaces they claim to. - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { const implementedTypeNames = Object.create(null); type.getInterfaces().forEach(iface => { @@ -209,7 +193,7 @@ function validateObjectImplementsInterface( object: GraphQLObjectType, iface: GraphQLInterfaceType, ): void { - if (!(iface instanceof GraphQLInterfaceType)) { + if (!isInterfaceType(iface)) { context.reportError( `${String(object)} must only implement Interface types, it cannot ` + `implement ${String(iface)}.`, @@ -293,7 +277,7 @@ function validateObjectImplementsInterface( objectField.args.forEach(objectArg => { const argName = objectArg.name; const ifaceArg = find(ifaceField.args, arg => arg.name === argName); - if (!ifaceArg && objectArg.type instanceof GraphQLNonNull) { + if (!ifaceArg && isNonNullType(objectArg.type)) { context.reportError( `${object.name}.${fieldName}(${argName}:) is of required type ` + `"${String(objectArg.type)}" but is not also provided by the ` + diff --git a/src/type/wrappers.js b/src/type/wrappers.js index 69e7af471f..26a2e8ba9b 100644 --- a/src/type/wrappers.js +++ b/src/type/wrappers.js @@ -7,8 +7,7 @@ * @flow */ -import invariant from '../jsutils/invariant'; -import { isType, assertType } from './definition'; +import { assertType, assertNullableType } from './definition'; import type { GraphQLType, GraphQLNullableType } from './definition'; /** @@ -38,8 +37,7 @@ declare class GraphQLList<+T: GraphQLType> { // eslint-disable-next-line no-redeclare export function GraphQLList(ofType) { if (this instanceof GraphQLList) { - assertType(ofType); - this.ofType = ofType; + this.ofType = assertType(ofType); } else { return new GraphQLList(ofType); } @@ -80,13 +78,7 @@ declare class GraphQLNonNull<+T: GraphQLNullableType> { // eslint-disable-next-line no-redeclare export function GraphQLNonNull(ofType) { if (this instanceof GraphQLNonNull) { - invariant( - isType(ofType) && !(ofType instanceof GraphQLNonNull), - `Can only create NonNull of a Nullable GraphQLType but got: ${String( - ofType, - )}.`, - ); - this.ofType = ofType; + this.ofType = assertNullableType(ofType); } else { return new GraphQLNonNull(ofType); } diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.js index 26ed8522bb..d052dad0ab 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.js @@ -9,17 +9,17 @@ import * as Kind from '../language/kinds'; import { + isObjectType, + isInterfaceType, + isEnumType, + isInputObjectType, + isListType, isCompositeType, isInputType, isOutputType, getNullableType, getNamedType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLInputObjectType, - GraphQLEnumType, } from '../type/definition'; -import { GraphQLList } from '../type/wrappers'; import type { GraphQLType, GraphQLInputType, @@ -176,13 +176,13 @@ export class TypeInfo { case Kind.LIST: const listType = getNullableType(this.getInputType()); this._inputTypeStack.push( - listType instanceof GraphQLList ? listType.ofType : undefined, + isListType(listType) ? listType.ofType : undefined, ); break; case Kind.OBJECT_FIELD: const objectType = getNamedType(this.getInputType()); let fieldType; - if (objectType instanceof GraphQLInputObjectType) { + if (isInputObjectType(objectType)) { const inputField = objectType.getFields()[node.name.value]; fieldType = inputField ? inputField.type : undefined; } @@ -191,7 +191,7 @@ export class TypeInfo { case Kind.ENUM: const enumType = getNamedType(this.getInputType()); let enumValue; - if (enumType instanceof GraphQLEnumType) { + if (isEnumType(enumType)) { enumValue = enumType.getValue(node.value); } this._enumValue = enumValue; @@ -257,10 +257,7 @@ function getFieldDef( if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) { return TypeNameMetaFieldDef; } - if ( - parentType instanceof GraphQLObjectType || - parentType instanceof GraphQLInterfaceType - ) { + if (isObjectType(parentType) || isInterfaceType(parentType)) { return parentType.getFields()[name]; } } diff --git a/src/utilities/__tests__/extendSchema-test.js b/src/utilities/__tests__/extendSchema-test.js index 5c3b355907..aecee24072 100644 --- a/src/utilities/__tests__/extendSchema-test.js +++ b/src/utilities/__tests__/extendSchema-test.js @@ -23,7 +23,8 @@ import { GraphQLEnumType, GraphQLNonNull, GraphQLList, - GraphQLScalarType, + isScalarType, + isNonNullType, } from '../../type'; // Test schema. @@ -910,11 +911,11 @@ describe('extendSchema', () => { expect(args.length).to.equal(2); expect(arg0.name).to.equal('enable'); - expect(arg0.type).to.be.instanceof(GraphQLNonNull); - expect(arg0.type.ofType).to.be.instanceof(GraphQLScalarType); + expect(isNonNullType(arg0.type)).to.equal(true); + expect(isScalarType(arg0.type.ofType)).to.equal(true); expect(arg1.name).to.equal('tag'); - expect(arg1.type).to.be.instanceof(GraphQLScalarType); + expect(isScalarType(arg1.type)).to.equal(true); }); it('does not allow replacing a default directive', () => { diff --git a/src/utilities/astFromValue.js b/src/utilities/astFromValue.js index 88a4d22aed..c06e64fc57 100644 --- a/src/utilities/astFromValue.js +++ b/src/utilities/astFromValue.js @@ -9,7 +9,6 @@ import { forEach, isCollection } from 'iterall'; -import invariant from '../jsutils/invariant'; import isNullish from '../jsutils/isNullish'; import isInvalid from '../jsutils/isInvalid'; import type { @@ -26,11 +25,12 @@ import type { import * as Kind from '../language/kinds'; import type { GraphQLInputType } from '../type/definition'; import { - GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, + isScalarType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; import { GraphQLID } from '../type/scalars'; /** @@ -54,7 +54,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { // Ensure flow knows that we treat function params as const. const _value = value; - if (type instanceof GraphQLNonNull) { + if (isNonNullType(type)) { const astValue = astFromValue(_value, type.ofType); if (astValue && astValue.kind === Kind.NULL) { return null; @@ -74,7 +74,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but // the value is not an array, convert the value using the list's item type. - if (type instanceof GraphQLList) { + if (isListType(type)) { const itemType = type.ofType; if (isCollection(_value)) { const valuesNodes = []; @@ -91,7 +91,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { // Populate the fields of the input object by creating ASTs from each value // in the JavaScript object according to the fields in the input type. - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { if (_value === null || typeof _value !== 'object') { return null; } @@ -111,49 +111,49 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { return ({ kind: Kind.OBJECT, fields: fieldNodes }: ObjectValueNode); } - invariant( - type instanceof GraphQLScalarType || type instanceof GraphQLEnumType, - 'Must provide Input Type, cannot use: ' + String(type), - ); + if (isScalarType(type) || isEnumType(type)) { + // Since value is an internally represented value, it must be serialized + // to an externally represented value before converting into an AST. + const serialized = type.serialize(_value); + if (isNullish(serialized)) { + return null; + } - // Since value is an internally represented value, it must be serialized - // to an externally represented value before converting into an AST. - const serialized = type.serialize(_value); - if (isNullish(serialized)) { - return null; - } + // Others serialize based on their corresponding JavaScript scalar types. + if (typeof serialized === 'boolean') { + return ({ kind: Kind.BOOLEAN, value: serialized }: BooleanValueNode); + } - // Others serialize based on their corresponding JavaScript scalar types. - if (typeof serialized === 'boolean') { - return ({ kind: Kind.BOOLEAN, value: serialized }: BooleanValueNode); - } + // JavaScript numbers can be Int or Float values. + if (typeof serialized === 'number') { + const stringNum = String(serialized); + return /^[0-9]+$/.test(stringNum) + ? ({ kind: Kind.INT, value: stringNum }: IntValueNode) + : ({ kind: Kind.FLOAT, value: stringNum }: FloatValueNode); + } - // JavaScript numbers can be Int or Float values. - if (typeof serialized === 'number') { - const stringNum = String(serialized); - return /^[0-9]+$/.test(stringNum) - ? ({ kind: Kind.INT, value: stringNum }: IntValueNode) - : ({ kind: Kind.FLOAT, value: stringNum }: FloatValueNode); - } + if (typeof serialized === 'string') { + // Enum types use Enum literals. + if (isEnumType(type)) { + return ({ kind: Kind.ENUM, value: serialized }: EnumValueNode); + } - if (typeof serialized === 'string') { - // Enum types use Enum literals. - if (type instanceof GraphQLEnumType) { - return ({ kind: Kind.ENUM, value: serialized }: EnumValueNode); - } + // ID types can use Int literals. + if (type === GraphQLID && /^[0-9]+$/.test(serialized)) { + return ({ kind: Kind.INT, value: serialized }: IntValueNode); + } - // ID types can use Int literals. - if (type === GraphQLID && /^[0-9]+$/.test(serialized)) { - return ({ kind: Kind.INT, value: serialized }: IntValueNode); + // Use JSON stringify, which uses the same string encoding as GraphQL, + // then remove the quotes. + return ({ + kind: Kind.STRING, + value: JSON.stringify(serialized).slice(1, -1), + }: StringValueNode); } - // Use JSON stringify, which uses the same string encoding as GraphQL, - // then remove the quotes. - return ({ - kind: Kind.STRING, - value: JSON.stringify(serialized).slice(1, -1), - }: StringValueNode); + throw new TypeError('Cannot convert value to AST: ' + String(serialized)); } - throw new TypeError('Cannot convert value to AST: ' + String(serialized)); + /* istanbul ignore next */ + throw new Error(`Unknown type: ${(type: empty)}.`); } diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.js index b7b61d2291..7058df8c4c 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.js @@ -7,7 +7,6 @@ * @flow */ -import invariant from '../jsutils/invariant'; import keyMap from '../jsutils/keyMap'; import keyValMap from '../jsutils/keyValMap'; import type { ObjMap } from '../jsutils/ObjMap'; @@ -47,8 +46,11 @@ import { GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, + assertObjectType, + assertInterfaceType, assertInputType, assertOutputType, + assertNullableType, } from '../type/definition'; import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; @@ -103,8 +105,7 @@ function buildWrappedType( } if (inputTypeNode.kind === Kind.NON_NULL_TYPE) { const wrappedType = buildWrappedType(innerType, inputTypeNode.type); - invariant(!(wrappedType instanceof GraphQLNonNull), 'No nesting nonnull.'); - return GraphQLNonNull(wrappedType); + return GraphQLNonNull(assertNullableType(wrappedType)); } return innerType; } @@ -308,14 +309,12 @@ export class ASTDefinitionBuilder { buildObjectType(ref: string | NamedTypeNode): GraphQLObjectType { const type = this.buildType(ref); - invariant(type instanceof GraphQLObjectType, 'Expected Object type.'); - return type; + return assertObjectType(type); } buildInterfaceType(ref: string | NamedTypeNode): GraphQLInterfaceType { const type = this.buildType(ref); - invariant(type instanceof GraphQLInterfaceType, 'Expected Interface type.'); - return type; + return assertInterfaceType(type); } _buildWrappedType(typeNode: TypeNode): GraphQLType { diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.js index a80262f00d..cc883b3a88 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.js @@ -25,6 +25,9 @@ import { GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, + assertNullableType, + assertObjectType, + assertInterfaceType, } from '../type/definition'; import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; @@ -117,11 +120,7 @@ export function buildClientSchema( throw new Error('Decorated type deeper than introspection query.'); } const nullableType = getType(nullableRef); - invariant( - !(nullableType instanceof GraphQLNonNull), - 'No nesting nonnull.', - ); - return GraphQLNonNull(nullableType); + return GraphQLNonNull(assertNullableType(nullableType)); } if (!typeRef.name) { throw new Error('Unknown type reference: ' + JSON.stringify(typeRef)); @@ -170,22 +169,14 @@ export function buildClientSchema( typeRef: IntrospectionNamedTypeRef, ): GraphQLObjectType { const type = getType(typeRef); - invariant( - type instanceof GraphQLObjectType, - 'Introspection must provide object type for possibleTypes.', - ); - return type; + return assertObjectType(type); } function getInterfaceType( typeRef: IntrospectionTypeRef, ): GraphQLInterfaceType { const type = getType(typeRef); - invariant( - type instanceof GraphQLInterfaceType, - 'Introspection must provide interface type for interfaces.', - ); - return type; + return assertInterfaceType(type); } // Given a type's introspection result, construct the correct diff --git a/src/utilities/coerceValue.js b/src/utilities/coerceValue.js index 593a2f339c..4467fb0cab 100644 --- a/src/utilities/coerceValue.js +++ b/src/utilities/coerceValue.js @@ -13,11 +13,12 @@ import isNullish from '../jsutils/isNullish'; import { GraphQLError } from '../error'; import type { ASTNode } from '../language/ast'; import { - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLScalarType, + isScalarType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; import type { GraphQLInputType } from '../type/definition'; type CoercedValue = {| @@ -41,7 +42,7 @@ export function coerceValue( path?: Path, ): CoercedValue { // A value must be provided if the type is non-null. - if (type instanceof GraphQLNonNull) { + if (isNonNullType(type)) { if (isNullish(value)) { return ofErrors([ coercionError( @@ -59,7 +60,7 @@ export function coerceValue( return ofValue(null); } - if (type instanceof GraphQLScalarType) { + if (isScalarType(type)) { // Scalars determine if a value is valid via parseValue(), which can // throw to indicate failure. If it throws, maintain a reference to // the original error. @@ -78,7 +79,7 @@ export function coerceValue( } } - if (type instanceof GraphQLEnumType) { + if (isEnumType(type)) { if (typeof value === 'string') { const enumValue = type.getValue(value); if (enumValue) { @@ -90,7 +91,7 @@ export function coerceValue( ]); } - if (type instanceof GraphQLList) { + if (isListType(type)) { const itemType = type.ofType; if (isCollection(value)) { let errors; @@ -115,7 +116,7 @@ export function coerceValue( return coercedItem.errors ? coercedItem : ofValue([coercedItem.value]); } - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { if (typeof value !== 'object') { return ofErrors([ coercionError(`Expected object type ${type.name}`, blameNode, path), @@ -133,7 +134,7 @@ export function coerceValue( if (isInvalid(fieldValue)) { if (!isInvalid(field.defaultValue)) { coercedValue[fieldName] = field.defaultValue; - } else if (field.type instanceof GraphQLNonNull) { + } else if (isNonNullType(field.type)) { errors = add( errors, coercionError( @@ -178,7 +179,8 @@ export function coerceValue( return errors ? ofErrors(errors) : ofValue(coercedValue); } - throw new Error(`Unexpected type ${String((type: empty))}`); + /* istanbul ignore next */ + throw new Error(`Unexpected type: ${(type: empty)}.`); } function ofValue(value) { diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.js index 729774286f..36e7956458 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.js @@ -11,9 +11,14 @@ import invariant from '../jsutils/invariant'; import keyMap from '../jsutils/keyMap'; import { ASTDefinitionBuilder } from './buildASTSchema'; import { GraphQLError } from '../error/GraphQLError'; -import { GraphQLSchema } from '../type/schema'; +import { isSchema, GraphQLSchema } from '../type/schema'; import { + isObjectType, + isInterfaceType, + isUnionType, + isListType, + isNonNullType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, @@ -71,10 +76,7 @@ export function extendSchema( documentAST: DocumentNode, options?: Options, ): GraphQLSchema { - invariant( - schema instanceof GraphQLSchema, - 'Must provide valid GraphQLSchema', - ); + invariant(isSchema(schema), 'Must provide valid GraphQLSchema'); invariant( documentAST && documentAST.kind === Kind.DOCUMENT, @@ -122,7 +124,7 @@ export function extendSchema( [def], ); } - if (!(existingType instanceof GraphQLObjectType)) { + if (!isObjectType(existingType)) { throw new GraphQLError( `Cannot extend non-object type "${extendedTypeName}".`, [def], @@ -248,13 +250,13 @@ export function extendSchema( // Given a type's introspection result, construct the correct // GraphQLType instance. function extendType(type: GraphQLNamedType): GraphQLNamedType { - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { return extendObjectType(type); } - if (type instanceof GraphQLInterfaceType) { + if (isInterfaceType(type)) { return extendInterfaceType(type); } - if (type instanceof GraphQLUnionType) { + if (isUnionType(type)) { return extendUnionType(type); } return type; @@ -363,10 +365,10 @@ export function extendSchema( } function extendFieldType(typeDef: T): T { - if (typeDef instanceof GraphQLList) { + if (isListType(typeDef)) { return (GraphQLList(extendFieldType(typeDef.ofType)): any); } - if (typeDef instanceof GraphQLNonNull) { + if (isNonNullType(typeDef)) { return (GraphQLNonNull(extendFieldType(typeDef.ofType)): any); } return getTypeFromDef(typeDef); diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index a46d3d27a0..a33606cad7 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -8,17 +8,17 @@ */ import { + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isNonNullType, + isListType, isNamedType, - GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLObjectType, - GraphQLUnionType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; - import type { GraphQLNamedType, GraphQLFieldMap, @@ -140,7 +140,7 @@ export function findTypesThatChangedKind( } const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if (!(oldType instanceof newType.constructor)) { + if (oldType.constructor !== newType.constructor) { breakingChanges.push({ type: BreakingChangeType.TYPE_CHANGED_KIND, description: @@ -175,11 +175,9 @@ export function findArgChanges( const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; if ( - !( - oldType instanceof GraphQLObjectType || - oldType instanceof GraphQLInterfaceType - ) || - !(newType instanceof oldType.constructor) + !(isObjectType(oldType) || isInterfaceType(oldType)) || + !(isObjectType(newType) || isInterfaceType(newType)) || + newType.constructor !== oldType.constructor ) { return; } @@ -235,7 +233,7 @@ export function findArgChanges( const oldArgs = oldTypeFields[fieldName].args; const oldArgDef = oldArgs.find(arg => arg.name === newArgDef.name); if (!oldArgDef) { - if (newArgDef.type instanceof GraphQLNonNull) { + if (isNonNullType(newArgDef.type)) { breakingChanges.push({ type: BreakingChangeType.NON_NULL_ARG_ADDED, description: @@ -262,22 +260,22 @@ export function findArgChanges( } function typeKindName(type: GraphQLNamedType): string { - if (type instanceof GraphQLScalarType) { + if (isScalarType(type)) { return 'a Scalar type'; } - if (type instanceof GraphQLObjectType) { + if (isObjectType(type)) { return 'an Object type'; } - if (type instanceof GraphQLInterfaceType) { + if (isInterfaceType(type)) { return 'an Interface type'; } - if (type instanceof GraphQLUnionType) { + if (isUnionType(type)) { return 'a Union type'; } - if (type instanceof GraphQLEnumType) { + if (isEnumType(type)) { return 'an Enum type'; } - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { return 'an Input type'; } throw new TypeError('Unknown type ' + type.constructor.name); @@ -295,11 +293,9 @@ export function findFieldsThatChangedTypeOnObjectOrInterfaceTypes( const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; if ( - !( - oldType instanceof GraphQLObjectType || - oldType instanceof GraphQLInterfaceType - ) || - !(newType instanceof oldType.constructor) + !(isObjectType(oldType) || isInterfaceType(oldType)) || + !(isObjectType(newType) || isInterfaceType(newType)) || + newType.constructor !== oldType.constructor ) { return; } @@ -355,10 +351,7 @@ export function findFieldsThatChangedTypeOnInputObjectTypes( Object.keys(oldTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLInputObjectType) || - !(newType instanceof GraphQLInputObjectType) - ) { + if (!isInputObjectType(oldType) || !isInputObjectType(newType)) { return; } @@ -398,7 +391,7 @@ export function findFieldsThatChangedTypeOnInputObjectTypes( // Check if a field was added to the input object type Object.keys(newTypeFieldsDef).forEach(fieldName => { if (!(fieldName in oldTypeFieldsDef)) { - if (newTypeFieldsDef[fieldName].type instanceof GraphQLNonNull) { + if (isNonNullType(newTypeFieldsDef[fieldName].type)) { breakingChanges.push({ type: BreakingChangeType.NON_NULL_INPUT_FIELD_ADDED, description: @@ -431,25 +424,25 @@ function isChangeSafeForObjectOrInterfaceField( // if they're both named types, see if their names are equivalent (isNamedType(newType) && oldType.name === newType.name) || // moving from nullable to non-null of the same underlying type is safe - (newType instanceof GraphQLNonNull && + (isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)) ); - } else if (oldType instanceof GraphQLList) { + } else if (isListType(oldType)) { return ( // if they're both lists, make sure the underlying types are compatible - (newType instanceof GraphQLList && + (isListType(newType) && isChangeSafeForObjectOrInterfaceField( oldType.ofType, newType.ofType, )) || // moving from nullable to non-null of the same underlying type is safe - (newType instanceof GraphQLNonNull && + (isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)) ); - } else if (oldType instanceof GraphQLNonNull) { + } else if (isNonNullType(oldType)) { // if they're both non-null, make sure the underlying types are compatible return ( - newType instanceof GraphQLNonNull && + isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType) ); } @@ -463,23 +456,23 @@ function isChangeSafeForInputObjectFieldOrFieldArg( if (isNamedType(oldType)) { // if they're both named types, see if their names are equivalent return isNamedType(newType) && oldType.name === newType.name; - } else if (oldType instanceof GraphQLList) { + } else if (isListType(oldType)) { // if they're both lists, make sure the underlying types are compatible return ( - newType instanceof GraphQLList && + isListType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType) ); - } else if (oldType instanceof GraphQLNonNull) { + } else if (isNonNullType(oldType)) { return ( // if they're both non-null, make sure the underlying types are // compatible - (newType instanceof GraphQLNonNull && + (isNonNullType(newType) && isChangeSafeForInputObjectFieldOrFieldArg( oldType.ofType, newType.ofType, )) || // moving from non-null to nullable of the same underlying type is safe - (!(newType instanceof GraphQLNonNull) && + (!isNonNullType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType)) ); } @@ -501,10 +494,7 @@ export function findTypesRemovedFromUnions( Object.keys(oldTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLUnionType) || - !(newType instanceof GraphQLUnionType) - ) { + if (!isUnionType(oldType) || !isUnionType(newType)) { return; } const typeNamesInNewUnion = Object.create(null); @@ -538,10 +528,7 @@ export function findTypesAddedToUnions( Object.keys(newTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLUnionType) || - !(newType instanceof GraphQLUnionType) - ) { + if (!isUnionType(oldType) || !isUnionType(newType)) { return; } const typeNamesInOldUnion = Object.create(null); @@ -574,10 +561,7 @@ export function findValuesRemovedFromEnums( Object.keys(oldTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLEnumType) || - !(newType instanceof GraphQLEnumType) - ) { + if (!isEnumType(oldType) || !isEnumType(newType)) { return; } const valuesInNewEnum = Object.create(null); @@ -611,10 +595,7 @@ export function findValuesAddedToEnums( Object.keys(oldTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLEnumType) || - !(newType instanceof GraphQLEnumType) - ) { + if (!isEnumType(oldType) || !isEnumType(newType)) { return; } @@ -645,10 +626,7 @@ export function findInterfacesRemovedFromObjectTypes( Object.keys(oldTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLObjectType) || - !(newType instanceof GraphQLObjectType) - ) { + if (!isObjectType(oldType) || !isObjectType(newType)) { return; } @@ -679,10 +657,7 @@ export function findInterfacesAddedToObjectTypes( Object.keys(newTypeMap).forEach(typeName => { const oldType = oldTypeMap[typeName]; const newType = newTypeMap[typeName]; - if ( - !(oldType instanceof GraphQLObjectType) || - !(newType instanceof GraphQLObjectType) - ) { + if (!isObjectType(oldType) || !isObjectType(newType)) { return; } diff --git a/src/utilities/isValidLiteralValue.js b/src/utilities/isValidLiteralValue.js index 4b8b02b30c..4d9e15f6b1 100644 --- a/src/utilities/isValidLiteralValue.js +++ b/src/utilities/isValidLiteralValue.js @@ -15,13 +15,13 @@ import type { } from '../language/ast'; import * as Kind from '../language/kinds'; import { - GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, + isScalarType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; import type { GraphQLInputType } from '../type/definition'; -import invariant from '../jsutils/invariant'; import isInvalid from '../jsutils/isInvalid'; import keyMap from '../jsutils/keyMap'; @@ -37,7 +37,7 @@ export function isValidLiteralValue( valueNode: ValueNode, ): Array { // A value must be provided if the type is non-null. - if (type instanceof GraphQLNonNull) { + if (isNonNullType(type)) { if (!valueNode || valueNode.kind === Kind.NULL) { return [`Expected "${String(type)}", found null.`]; } @@ -55,7 +55,7 @@ export function isValidLiteralValue( } // Lists accept a non-list value as a list of one. - if (type instanceof GraphQLList) { + if (isListType(type)) { const itemType = type.ofType; if (valueNode.kind === Kind.LIST) { return (valueNode: ListValueNode).values.reduce((acc, item, index) => { @@ -69,7 +69,7 @@ export function isValidLiteralValue( } // Input objects check each defined field and look for undefined fields. - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { if (valueNode.kind !== Kind.OBJECT) { return [`Expected "${type.name}", found not an object.`]; } @@ -100,7 +100,7 @@ export function isValidLiteralValue( return errors; } - if (type instanceof GraphQLEnumType) { + if (isEnumType(type)) { if (valueNode.kind !== Kind.ENUM || !type.getValue(valueNode.value)) { return [`Expected type "${type.name}", found ${print(valueNode)}.`]; } @@ -108,19 +108,22 @@ export function isValidLiteralValue( return []; } - invariant(type instanceof GraphQLScalarType, 'Must be a scalar type'); - - // Scalars determine if a literal value is valid via parseLiteral(). - try { - const parseResult = type.parseLiteral(valueNode, null); - if (isInvalid(parseResult)) { - return [`Expected type "${type.name}", found ${print(valueNode)}.`]; + if (isScalarType(type)) { + // Scalars determine if a literal value is valid via parseLiteral(). + try { + const parseResult = type.parseLiteral(valueNode, null); + if (isInvalid(parseResult)) { + return [`Expected type "${type.name}", found ${print(valueNode)}.`]; + } + } catch (error) { + const printed = print(valueNode); + const message = error.message; + return [`Expected type "${type.name}", found ${printed}; ${message}`]; } - } catch (error) { - const printed = print(valueNode); - const message = error.message; - return [`Expected type "${type.name}", found ${printed}; ${message}`]; + + return []; } - return []; + /* istanbul ignore next */ + throw new Error(`Unknown type: ${(type: empty)}.`); } diff --git a/src/utilities/schemaPrinter.js b/src/utilities/schemaPrinter.js index bac60d576a..568274e148 100644 --- a/src/utilities/schemaPrinter.js +++ b/src/utilities/schemaPrinter.js @@ -7,19 +7,26 @@ * @flow */ -import invariant from '../jsutils/invariant'; import isNullish from '../jsutils/isNullish'; import isInvalid from '../jsutils/isInvalid'; import { astFromValue } from '../utilities/astFromValue'; import { print } from '../language/printer'; import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLType, GraphQLNamedType } from '../type/definition'; import { + isScalarType, + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, +} from '../type/definition'; +import type { + GraphQLNamedType, GraphQLScalarType, + GraphQLEnumType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, - GraphQLEnumType, GraphQLInputObjectType, } from '../type/definition'; import { GraphQLString, isSpecifiedScalarType } from '../type/scalars'; @@ -28,7 +35,6 @@ import { DEFAULT_DEPRECATION_REASON, isSpecifiedDirective, } from '../type/directives'; - import { isIntrospectionType } from '../type/introspection'; type Options = {| commentDescriptions?: boolean |}; @@ -145,20 +151,22 @@ function isSchemaOfCommonNames(schema: GraphQLSchema): boolean { return true; } -export function printType(type: GraphQLType, options?: Options): string { - if (type instanceof GraphQLScalarType) { +export function printType(type: GraphQLNamedType, options?: Options): string { + if (isScalarType(type)) { return printScalar(type, options); - } else if (type instanceof GraphQLObjectType) { + } else if (isObjectType(type)) { return printObject(type, options); - } else if (type instanceof GraphQLInterfaceType) { + } else if (isInterfaceType(type)) { return printInterface(type, options); - } else if (type instanceof GraphQLUnionType) { + } else if (isUnionType(type)) { return printUnion(type, options); - } else if (type instanceof GraphQLEnumType) { + } else if (isEnumType(type)) { return printEnum(type, options); + } else if (isInputObjectType(type)) { + return printInputObject(type, options); } - invariant(type instanceof GraphQLInputObjectType); - return printInputObject(type, options); + /* istanbul ignore next */ + throw new Error(`Unknown type: ${(type: empty)}.`); } function printScalar(type: GraphQLScalarType, options): string { diff --git a/src/utilities/typeComparators.js b/src/utilities/typeComparators.js index 285f5d02a5..616a04723b 100644 --- a/src/utilities/typeComparators.js +++ b/src/utilities/typeComparators.js @@ -7,8 +7,12 @@ * @flow */ -import { isAbstractType, GraphQLObjectType } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; +import { + isObjectType, + isListType, + isNonNullType, + isAbstractType, +} from '../type/definition'; import type { GraphQLType, GraphQLCompositeType } from '../type/definition'; import type { GraphQLSchema } from '../type/schema'; @@ -22,12 +26,12 @@ export function isEqualType(typeA: GraphQLType, typeB: GraphQLType): boolean { } // If either type is non-null, the other must also be non-null. - if (typeA instanceof GraphQLNonNull && typeB instanceof GraphQLNonNull) { + if (isNonNullType(typeA) && isNonNullType(typeB)) { return isEqualType(typeA.ofType, typeB.ofType); } // If either type is a list, the other must also be a list. - if (typeA instanceof GraphQLList && typeB instanceof GraphQLList) { + if (isListType(typeA) && isListType(typeB)) { return isEqualType(typeA.ofType, typeB.ofType); } @@ -50,23 +54,25 @@ export function isTypeSubTypeOf( } // If superType is non-null, maybeSubType must also be non-null. - if (superType instanceof GraphQLNonNull) { - if (maybeSubType instanceof GraphQLNonNull) { + if (isNonNullType(superType)) { + if (isNonNullType(maybeSubType)) { return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType); } return false; - } else if (maybeSubType instanceof GraphQLNonNull) { + } + if (isNonNullType(maybeSubType)) { // If superType is nullable, maybeSubType may be non-null or nullable. return isTypeSubTypeOf(schema, maybeSubType.ofType, superType); } // If superType type is a list, maybeSubType type must also be a list. - if (superType instanceof GraphQLList) { - if (maybeSubType instanceof GraphQLList) { + if (isListType(superType)) { + if (isListType(maybeSubType)) { return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType); } return false; - } else if (maybeSubType instanceof GraphQLList) { + } + if (isListType(maybeSubType)) { // If superType is not a list, maybeSubType must also be not a list. return false; } @@ -75,7 +81,7 @@ export function isTypeSubTypeOf( // possible object type. if ( isAbstractType(superType) && - maybeSubType instanceof GraphQLObjectType && + isObjectType(maybeSubType) && schema.isPossibleType(superType, maybeSubType) ) { return true; diff --git a/src/utilities/typeFromAST.js b/src/utilities/typeFromAST.js index 9700c80d49..de0a3891fe 100644 --- a/src/utilities/typeFromAST.js +++ b/src/utilities/typeFromAST.js @@ -7,7 +7,6 @@ * @flow */ -import invariant from '../jsutils/invariant'; import * as Kind from '../language/kinds'; import type { NamedTypeNode, @@ -49,8 +48,11 @@ function typeFromASTImpl(schema, typeNode) { innerType = typeFromAST(schema, typeNode.type); return innerType && GraphQLNonNull(innerType); } - invariant(typeNode.kind === Kind.NAMED_TYPE, 'Must be a named type.'); - return schema.getType(typeNode.name.value); + if (typeNode.kind === Kind.NAMED_TYPE) { + return schema.getType(typeNode.name.value); + } + /* istanbul ignore next */ + throw new Error(`Unexpected type kind: ${(typeNode.kind: empty)}.`); } // This will export typeFromAST with the correct type, but currently exposes // ~26 errors: https://gist.github.com/4a29403a99a8186fcb15064d69c5f3ae diff --git a/src/utilities/valueFromAST.js b/src/utilities/valueFromAST.js index e7b5d77ec8..9cf859bd42 100644 --- a/src/utilities/valueFromAST.js +++ b/src/utilities/valueFromAST.js @@ -8,16 +8,16 @@ */ import keyMap from '../jsutils/keyMap'; -import invariant from '../jsutils/invariant'; import isInvalid from '../jsutils/isInvalid'; import type { ObjMap } from '../jsutils/ObjMap'; import * as Kind from '../language/kinds'; import { - GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, + isScalarType, + isEnumType, + isInputObjectType, + isListType, + isNonNullType, } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/wrappers'; import type { GraphQLInputType } from '../type/definition'; import type { ValueNode, @@ -57,7 +57,7 @@ export function valueFromAST( return; } - if (type instanceof GraphQLNonNull) { + if (isNonNullType(type)) { if (valueNode.kind === Kind.NULL) { return; // Invalid: intentionally return no value. } @@ -81,7 +81,7 @@ export function valueFromAST( return variables[variableName]; } - if (type instanceof GraphQLList) { + if (isListType(type)) { const itemType = type.ofType; if (valueNode.kind === Kind.LIST) { const coercedValues = []; @@ -90,7 +90,7 @@ export function valueFromAST( if (isMissingVariable(itemNodes[i], variables)) { // If an array contains a missing variable, it is either coerced to // null or if the item type is non-null, it considered invalid. - if (itemType instanceof GraphQLNonNull) { + if (isNonNullType(itemType)) { return; // Invalid: intentionally return no value. } coercedValues.push(null); @@ -111,7 +111,7 @@ export function valueFromAST( return [coercedValue]; } - if (type instanceof GraphQLInputObjectType) { + if (isInputObjectType(type)) { if (valueNode.kind !== Kind.OBJECT) { return; // Invalid: intentionally return no value. } @@ -129,7 +129,7 @@ export function valueFromAST( if (!fieldNode || isMissingVariable(fieldNode.value, variables)) { if (!isInvalid(field.defaultValue)) { coercedObj[fieldName] = field.defaultValue; - } else if (field.type instanceof GraphQLNonNull) { + } else if (isNonNullType(field.type)) { return; // Invalid: intentionally return no value. } continue; @@ -143,7 +143,7 @@ export function valueFromAST( return coercedObj; } - if (type instanceof GraphQLEnumType) { + if (isEnumType(type)) { if (valueNode.kind !== Kind.ENUM) { return; // Invalid: intentionally return no value. } @@ -154,21 +154,24 @@ export function valueFromAST( return enumValue.value; } - invariant(type instanceof GraphQLScalarType, 'Must be scalar type'); - - // Scalars fulfill parsing a literal value via parseLiteral(). - // Invalid values represent a failure to parse correctly, in which case - // no value is returned. - let result; - try { - result = type.parseLiteral(valueNode, variables); - } catch (_error) { - return; // Invalid: intentionally return no value. - } - if (isInvalid(result)) { - return; // Invalid: intentionally return no value. + if (isScalarType(type)) { + // Scalars fulfill parsing a literal value via parseLiteral(). + // Invalid values represent a failure to parse correctly, in which case + // no value is returned. + let result; + try { + result = type.parseLiteral(valueNode, variables); + } catch (_error) { + return; // Invalid: intentionally return no value. + } + if (isInvalid(result)) { + return; // Invalid: intentionally return no value. + } + return result; } - return result; + + /* istanbul ignore next */ + throw new Error(`Unknown type: ${(type: empty)}.`); } // Returns true if the provided valueNode is a variable which is not defined diff --git a/src/utilities/valueFromASTUntyped.js b/src/utilities/valueFromASTUntyped.js index 000cda029b..7d64ce3fcf 100644 --- a/src/utilities/valueFromASTUntyped.js +++ b/src/utilities/valueFromASTUntyped.js @@ -58,7 +58,7 @@ export function valueFromASTUntyped( return variables && !isInvalid(variables[variableName]) ? variables[variableName] : undefined; - default: - throw new Error('Unexpected value kind: ' + (valueNode.kind: empty)); } + /* istanbul ignore next */ + throw new Error('Unexpected value kind: ' + (valueNode.kind: empty)); } diff --git a/src/validation/rules/DefaultValuesOfCorrectType.js b/src/validation/rules/DefaultValuesOfCorrectType.js index babb02c9a1..544eca4bff 100644 --- a/src/validation/rules/DefaultValuesOfCorrectType.js +++ b/src/validation/rules/DefaultValuesOfCorrectType.js @@ -10,7 +10,7 @@ import type { ValidationContext } from '../index'; import { GraphQLError } from '../../error'; import { print } from '../../language/printer'; -import { GraphQLNonNull } from '../../type/wrappers'; +import { isNonNullType } from '../../type/definition'; import { isValidLiteralValue } from '../../utilities/isValidLiteralValue'; import type { GraphQLType } from '../../type/definition'; @@ -51,7 +51,7 @@ export function DefaultValuesOfCorrectType(context: ValidationContext): any { const name = node.variable.name.value; const defaultValue = node.defaultValue; const type = context.getInputType(); - if (type instanceof GraphQLNonNull && defaultValue) { + if (isNonNullType(type) && defaultValue) { context.reportError( new GraphQLError( defaultForNonNullArgMessage(name, type, type.ofType), diff --git a/src/validation/rules/FieldsOnCorrectType.js b/src/validation/rules/FieldsOnCorrectType.js index 2ca4250965..644af5791d 100644 --- a/src/validation/rules/FieldsOnCorrectType.js +++ b/src/validation/rules/FieldsOnCorrectType.js @@ -15,8 +15,8 @@ import type { FieldNode } from '../../language/ast'; import type { GraphQLSchema } from '../../type/schema'; import type { GraphQLOutputType } from '../../type/definition'; import { - GraphQLObjectType, - GraphQLInterfaceType, + isObjectType, + isInterfaceType, isAbstractType, } from '../../type/definition'; @@ -134,10 +134,7 @@ function getSuggestedFieldNames( type: GraphQLOutputType, fieldName: string, ): Array { - if ( - type instanceof GraphQLObjectType || - type instanceof GraphQLInterfaceType - ) { + if (isObjectType(type) || isInterfaceType(type)) { const possibleFieldNames = Object.keys(type.getFields()); return suggestionList(fieldName, possibleFieldNames); } diff --git a/src/validation/rules/OverlappingFieldsCanBeMerged.js b/src/validation/rules/OverlappingFieldsCanBeMerged.js index 55cfa395e6..04b1745255 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMerged.js +++ b/src/validation/rules/OverlappingFieldsCanBeMerged.js @@ -21,11 +21,12 @@ import * as Kind from '../../language/kinds'; import { print } from '../../language/printer'; import { getNamedType, + isNonNullType, isLeafType, - GraphQLObjectType, - GraphQLInterfaceType, + isObjectType, + isListType, + isInterfaceType, } from '../../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../../type/wrappers'; import type { GraphQLNamedType, GraphQLOutputType, @@ -575,8 +576,8 @@ function findConflict( const areMutuallyExclusive = parentFieldsAreMutuallyExclusive || (parentType1 !== parentType2 && - parentType1 instanceof GraphQLObjectType && - parentType2 instanceof GraphQLObjectType); + isObjectType(parentType1) && + isObjectType(parentType2)); // The return type for each field. const type1 = def1 && def1.type; @@ -665,25 +666,21 @@ function doTypesConflict( type1: GraphQLOutputType, type2: GraphQLOutputType, ): boolean { - if (type1 instanceof GraphQLList) { - return type2 instanceof GraphQLList + if (isListType(type1)) { + return isListType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true; } - if (type2 instanceof GraphQLList) { - return type1 instanceof GraphQLList - ? doTypesConflict(type1.ofType, type2.ofType) - : true; + if (isListType(type2)) { + return true; } - if (type1 instanceof GraphQLNonNull) { - return type2 instanceof GraphQLNonNull + if (isNonNullType(type1)) { + return isNonNullType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true; } - if (type2 instanceof GraphQLNonNull) { - return type1 instanceof GraphQLNonNull - ? doTypesConflict(type1.ofType, type2.ofType) - : true; + if (isNonNullType(type2)) { + return true; } if (isLeafType(type1) || isLeafType(type2)) { return type1 !== type2; @@ -752,10 +749,7 @@ function _collectFieldsAndFragmentNames( case Kind.FIELD: const fieldName = selection.name.value; let fieldDef; - if ( - parentType instanceof GraphQLObjectType || - parentType instanceof GraphQLInterfaceType - ) { + if (isObjectType(parentType) || isInterfaceType(parentType)) { fieldDef = parentType.getFields()[fieldName]; } const responseName = selection.alias diff --git a/src/validation/rules/ProvidedNonNullArguments.js b/src/validation/rules/ProvidedNonNullArguments.js index b03cfa29fd..ee9569232c 100644 --- a/src/validation/rules/ProvidedNonNullArguments.js +++ b/src/validation/rules/ProvidedNonNullArguments.js @@ -10,7 +10,7 @@ import type { ValidationContext } from '../index'; import { GraphQLError } from '../../error'; import keyMap from '../../jsutils/keyMap'; -import { GraphQLNonNull } from '../../type/wrappers'; +import { isNonNullType } from '../../type/definition'; import type { GraphQLType } from '../../type/definition'; export function missingFieldArgMessage( @@ -55,7 +55,7 @@ export function ProvidedNonNullArguments(context: ValidationContext): any { const argNodeMap = keyMap(argNodes, arg => arg.name.value); fieldDef.args.forEach(argDef => { const argNode = argNodeMap[argDef.name]; - if (!argNode && argDef.type instanceof GraphQLNonNull) { + if (!argNode && isNonNullType(argDef.type)) { context.reportError( new GraphQLError( missingFieldArgMessage( @@ -83,7 +83,7 @@ export function ProvidedNonNullArguments(context: ValidationContext): any { const argNodeMap = keyMap(argNodes, arg => arg.name.value); directiveDef.args.forEach(argDef => { const argNode = argNodeMap[argDef.name]; - if (!argNode && argDef.type instanceof GraphQLNonNull) { + if (!argNode && isNonNullType(argDef.type)) { context.reportError( new GraphQLError( missingDirectiveArgMessage( diff --git a/src/validation/rules/VariablesInAllowedPosition.js b/src/validation/rules/VariablesInAllowedPosition.js index 10ffe4baac..857ac75672 100644 --- a/src/validation/rules/VariablesInAllowedPosition.js +++ b/src/validation/rules/VariablesInAllowedPosition.js @@ -9,6 +9,7 @@ import type { ValidationContext } from '../index'; import { GraphQLError } from '../../error'; +import { isNonNullType } from '../../type/definition'; import { GraphQLNonNull } from '../../type/wrappers'; import { isTypeSubTypeOf } from '../../utilities/typeComparators'; import { typeFromAST } from '../../utilities/typeFromAST'; @@ -73,7 +74,7 @@ export function VariablesInAllowedPosition(context: ValidationContext): any { // If a variable definition has a default value, it's effectively non-null. function effectiveType(varType, varDef) { - return !varDef.defaultValue || varType instanceof GraphQLNonNull + return !varDef.defaultValue || isNonNullType(varType) ? varType : GraphQLNonNull(varType); }