From e58762afd2bab3abc7e5d40e48158560b27c567d Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Tue, 30 Jul 2019 19:46:12 +0300 Subject: [PATCH] =?UTF-8?q?Use=20'invariant'=20only=20for=20real=20invaria?= =?UTF-8?q?nts,=20add=20'devAssert'=20for=20t=E2=80=A6=20(#2066)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flowconfig | 2 +- resources/inline-invariant.js | 31 +++--- src/error/formatError.js | 4 +- src/execution/execute.js | 15 +-- src/jsutils/devAssert.js | 10 ++ src/language/parser.js | 4 +- src/language/source.js | 6 +- src/type/definition.js | 170 ++++++++++++++--------------- src/type/directives.js | 17 +-- src/type/schema.js | 27 +++-- src/utilities/assertValidName.js | 4 +- src/utilities/buildASTSchema.js | 8 +- src/utilities/buildClientSchema.js | 18 +-- src/utilities/extendSchema.js | 10 +- src/validation/validate.js | 4 +- 15 files changed, 172 insertions(+), 158 deletions(-) create mode 100644 src/jsutils/devAssert.js diff --git a/.flowconfig b/.flowconfig index 89693b4fc5..7e20a06845 100644 --- a/.flowconfig +++ b/.flowconfig @@ -26,7 +26,7 @@ unsafe-getters-setters=error inexact-spread=error implicit-inexact-object=error unnecessary-optional-chain=error -unnecessary-invariant=off +unnecessary-invariant=error signature-verification-failure=error uninitialized-instance-property=error non-array-spread=error diff --git a/resources/inline-invariant.js b/resources/inline-invariant.js index d0a6517985..3cacdcc8f6 100644 --- a/resources/inline-invariant.js +++ b/resources/inline-invariant.js @@ -14,9 +14,12 @@ * ! ? invariant(0, ...) : undefined; */ module.exports = function inlineInvariant(context) { - const replaceTemplate = context.template(` + const invariantTemplate = context.template(` (%%cond%%) || invariant(0, %%args%%) `); + const assertTemplate = context.template(` + (%%cond%%) || devAssert(0, %%args%%) + `); return { visitor: { @@ -24,22 +27,24 @@ module.exports = function inlineInvariant(context) { const node = path.node; const parent = path.parent; - if (!isAppropriateInvariantCall(node, parent)) { + if ( + parent.type !== 'ExpressionStatement' || + node.callee.type !== 'Identifier' || + node.arguments.length === 0 + ) { return; } - const [cond, args] = node.arguments; - path.replaceWith(replaceTemplate({ cond, args })); + const calleeName = node.callee.name; + if (calleeName === 'invariant') { + const [cond, args] = node.arguments; + path.addComment('leading', ' istanbul ignore next '); + path.replaceWith(invariantTemplate({ cond, args })); + } else if (calleeName === 'devAssert') { + const [cond, args] = node.arguments; + path.replaceWith(assertTemplate({ cond, args })); + } }, }, }; }; - -function isAppropriateInvariantCall(node, parent) { - return ( - parent.type === 'ExpressionStatement' && - node.callee.type === 'Identifier' && - node.callee.name === 'invariant' && - node.arguments.length > 0 - ); -} diff --git a/src/error/formatError.js b/src/error/formatError.js index 714c2ab0d4..c0c055dca5 100644 --- a/src/error/formatError.js +++ b/src/error/formatError.js @@ -1,6 +1,6 @@ // @flow strict -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import { type SourceLocation } from '../language/location'; @@ -11,7 +11,7 @@ import { type GraphQLError } from './GraphQLError'; * Response Format, Errors section of the GraphQL Specification. */ export function formatError(error: GraphQLError): GraphQLFormattedError { - invariant(error, 'Received null or undefined error.'); + devAssert(error, 'Received null or undefined error.'); const message = error.message || 'An unknown error occurred.'; const locations = error.locations; const path = error.path; diff --git a/src/execution/execute.js b/src/execution/execute.js index ad630f8aac..121e4e1d45 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.js @@ -4,7 +4,7 @@ import { forEach, isCollection } from 'iterall'; import inspect from '../jsutils/inspect'; import memoize3 from '../jsutils/memoize3'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import isInvalid from '../jsutils/isInvalid'; import isNullish from '../jsutils/isNullish'; import isPromise from '../jsutils/isPromise'; @@ -249,13 +249,13 @@ export function assertValidExecutionArguments( document: DocumentNode, rawVariableValues: ?{ +[variable: string]: mixed, ... }, ): void { - invariant(document, 'Must provide document'); + devAssert(document, 'Must provide document'); // If the schema used for execution is invalid, throw an error. assertValidSchema(schema); // Variables, if provided, must be an object. - invariant( + devAssert( rawVariableValues == null || isObjectLike(rawVariableValues), 'Variables must be provided as an Object where each property is a variable value. Perhaps look to see if an unparsed JSON string was provided.', ); @@ -892,10 +892,11 @@ function completeListValue( path: Path, result: mixed, ): PromiseOrValue<$ReadOnlyArray> { - invariant( - isCollection(result), - `Expected Iterable, but did not find one for field ${info.parentType.name}.${info.fieldName}.`, - ); + if (!isCollection(result)) { + throw new GraphQLError( + `Expected Iterable, but did not find one for field ${info.parentType.name}.${info.fieldName}.`, + ); + } // This is specified as a simple map, however we're optimizing the path // where the list contains no Promises by avoiding creating another Promise. diff --git a/src/jsutils/devAssert.js b/src/jsutils/devAssert.js new file mode 100644 index 0000000000..813ea7ad55 --- /dev/null +++ b/src/jsutils/devAssert.js @@ -0,0 +1,10 @@ +// @flow strict + +/* istanbul ignore file */ +export default function devAssert(condition: mixed, message: string): void { + const booleanCondition = Boolean(condition); + /* istanbul ignore else */ + if (!booleanCondition) { + throw new Error(message); + } +} diff --git a/src/language/parser.js b/src/language/parser.js index 8d06f4d93c..8e79c9db12 100644 --- a/src/language/parser.js +++ b/src/language/parser.js @@ -1,7 +1,7 @@ // @flow strict import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import defineToJSON from '../jsutils/defineToJSON'; import { syntaxError } from '../error/syntaxError'; @@ -173,7 +173,7 @@ class Parser { constructor(source: string | Source, options?: ParseOptions) { const sourceObj = typeof source === 'string' ? new Source(source) : source; - invariant( + devAssert( sourceObj instanceof Source, `Must provide Source. Received: ${inspect(sourceObj)}`, ); diff --git a/src/language/source.js b/src/language/source.js index 914e490616..b7c31ef464 100644 --- a/src/language/source.js +++ b/src/language/source.js @@ -1,6 +1,6 @@ // @flow strict -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import defineToStringTag from '../jsutils/defineToStringTag'; type Location = {| @@ -25,11 +25,11 @@ export class Source { this.body = body; this.name = name || 'GraphQL request'; this.locationOffset = locationOffset || { line: 1, column: 1 }; - invariant( + devAssert( this.locationOffset.line > 0, 'line in locationOffset is 1-indexed and must be positive', ); - invariant( + devAssert( this.locationOffset.column > 0, 'column in locationOffset is 1-indexed and must be positive', ); diff --git a/src/type/definition.js b/src/type/definition.js index 53776274d8..f3ab900aa0 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -9,9 +9,9 @@ import inspect from '../jsutils/inspect'; import keyMap from '../jsutils/keyMap'; import mapValue from '../jsutils/mapValue'; import { type Path } from '../jsutils/Path'; +import devAssert from '../jsutils/devAssert'; import keyValMap from '../jsutils/keyValMap'; import { type ObjMap } from '../jsutils/ObjMap'; -import invariant from '../jsutils/invariant'; import instanceOf from '../jsutils/instanceOf'; import isObjectLike from '../jsutils/isObjectLike'; import identityFunc from '../jsutils/identityFunc'; @@ -75,7 +75,9 @@ export function isType(type: mixed): boolean %checks { } export function assertType(type: mixed): GraphQLType { - invariant(isType(type), `Expected ${inspect(type)} to be a GraphQL type.`); + if (!isType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); + } return type; } @@ -91,10 +93,9 @@ export function isScalarType(type) { } export function assertScalarType(type: mixed): GraphQLScalarType { - invariant( - isScalarType(type), - `Expected ${inspect(type)} to be a GraphQL Scalar type.`, - ); + if (!isScalarType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); + } return type; } @@ -106,10 +107,9 @@ export function isObjectType(type) { } export function assertObjectType(type: mixed): GraphQLObjectType { - invariant( - isObjectType(type), - `Expected ${inspect(type)} to be a GraphQL Object type.`, - ); + if (!isObjectType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); + } return type; } @@ -121,10 +121,11 @@ export function isInterfaceType(type) { } export function assertInterfaceType(type: mixed): GraphQLInterfaceType { - invariant( - isInterfaceType(type), - `Expected ${inspect(type)} to be a GraphQL Interface type.`, - ); + if (!isInterfaceType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Interface type.`, + ); + } return type; } @@ -136,10 +137,9 @@ export function isUnionType(type) { } export function assertUnionType(type: mixed): GraphQLUnionType { - invariant( - isUnionType(type), - `Expected ${inspect(type)} to be a GraphQL Union type.`, - ); + if (!isUnionType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); + } return type; } @@ -151,10 +151,9 @@ export function isEnumType(type) { } export function assertEnumType(type: mixed): GraphQLEnumType { - invariant( - isEnumType(type), - `Expected ${inspect(type)} to be a GraphQL Enum type.`, - ); + if (!isEnumType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); + } return type; } @@ -166,10 +165,11 @@ export function isInputObjectType(type) { } export function assertInputObjectType(type: mixed): GraphQLInputObjectType { - invariant( - isInputObjectType(type), - `Expected ${inspect(type)} to be a GraphQL Input Object type.`, - ); + if (!isInputObjectType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Input Object type.`, + ); + } return type; } @@ -181,10 +181,9 @@ export function isListType(type) { } export function assertListType(type: mixed): GraphQLList { - invariant( - isListType(type), - `Expected ${inspect(type)} to be a GraphQL List type.`, - ); + if (!isListType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); + } return type; } @@ -196,10 +195,9 @@ export function isNonNullType(type) { } export function assertNonNullType(type: mixed): GraphQLNonNull { - invariant( - isNonNullType(type), - `Expected ${inspect(type)} to be a GraphQL Non-Null type.`, - ); + if (!isNonNullType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); + } return type; } @@ -228,10 +226,9 @@ export function isInputType(type: mixed): boolean %checks { } export function assertInputType(type: mixed): GraphQLInputType { - invariant( - isInputType(type), - `Expected ${inspect(type)} to be a GraphQL input type.`, - ); + if (!isInputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`); + } return type; } @@ -266,10 +263,9 @@ export function isOutputType(type: mixed): boolean %checks { } export function assertOutputType(type: mixed): GraphQLOutputType { - invariant( - isOutputType(type), - `Expected ${inspect(type)} to be a GraphQL output type.`, - ); + if (!isOutputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); + } return type; } @@ -283,10 +279,9 @@ export function isLeafType(type: mixed): boolean %checks { } export function assertLeafType(type: mixed): GraphQLLeafType { - invariant( - isLeafType(type), - `Expected ${inspect(type)} to be a GraphQL leaf type.`, - ); + if (!isLeafType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); + } return type; } @@ -303,10 +298,11 @@ export function isCompositeType(type: mixed): boolean %checks { } export function assertCompositeType(type: mixed): GraphQLCompositeType { - invariant( - isCompositeType(type), - `Expected ${inspect(type)} to be a GraphQL composite type.`, - ); + if (!isCompositeType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL composite type.`, + ); + } return type; } @@ -320,10 +316,9 @@ export function isAbstractType(type: mixed): boolean %checks { } export function assertAbstractType(type: mixed): GraphQLAbstractType { - invariant( - isAbstractType(type), - `Expected ${inspect(type)} to be a GraphQL abstract type.`, - ); + if (!isAbstractType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`); + } return type; } @@ -424,10 +419,9 @@ export function isWrappingType(type: mixed): boolean %checks { } export function assertWrappingType(type: mixed): GraphQLWrappingType { - invariant( - isWrappingType(type), - `Expected ${inspect(type)} to be a GraphQL wrapping type.`, - ); + if (!isWrappingType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); + } return type; } @@ -448,10 +442,9 @@ export function isNullableType(type: mixed): boolean %checks { } export function assertNullableType(type: mixed): GraphQLNullableType { - invariant( - isNullableType(type), - `Expected ${inspect(type)} to be a GraphQL nullable type.`, - ); + if (!isNullableType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); + } return type; } @@ -489,10 +482,9 @@ export function isNamedType(type: mixed): boolean %checks { } export function assertNamedType(type: mixed): GraphQLNamedType { - invariant( - isNamedType(type), - `Expected ${inspect(type)} to be a GraphQL named type.`, - ); + if (!isNamedType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); + } return type; } @@ -569,14 +561,14 @@ export class GraphQLScalarType { this.astNode = config.astNode; this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - invariant(typeof config.name === 'string', 'Must provide name.'); - invariant( + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert( config.serialize == null || typeof config.serialize === 'function', `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`, ); if (config.parseLiteral) { - invariant( + devAssert( typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function', `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, @@ -686,8 +678,8 @@ export class GraphQLObjectType { this.isTypeOf = config.isTypeOf; this._fields = defineFieldMap.bind(undefined, config); this._interfaces = defineInterfaces.bind(undefined, config); - invariant(typeof config.name === 'string', 'Must provide name.'); - invariant( + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert( config.isTypeOf == null || typeof config.isTypeOf === 'function', `${this.name} must provide "isTypeOf" as a function, ` + `but got: ${inspect(config.isTypeOf)}.`, @@ -738,7 +730,7 @@ function defineInterfaces( config: GraphQLObjectTypeConfig, ): Array { const interfaces = resolveThunk(config.interfaces) || []; - invariant( + devAssert( Array.isArray(interfaces), `${config.name} interfaces must be an Array or a function which returns an Array.`, ); @@ -751,28 +743,28 @@ function defineFieldMap( | GraphQLInterfaceTypeConfig, ): GraphQLFieldMap { const fieldMap = resolveThunk(config.fields) || {}; - invariant( + devAssert( isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, ); return mapValue(fieldMap, (fieldConfig, fieldName) => { - invariant( + devAssert( isPlainObj(fieldConfig), `${config.name}.${fieldName} field config must be an object`, ); - invariant( + devAssert( !('isDeprecated' in fieldConfig), `${config.name}.${fieldName} should provide "deprecationReason" instead of "isDeprecated".`, ); - invariant( + devAssert( fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', `${config.name}.${fieldName} field resolver must be a function if ` + `provided, but got: ${inspect(fieldConfig.resolve)}.`, ); const argsConfig = fieldConfig.args || {}; - invariant( + devAssert( isPlainObj(argsConfig), `${config.name}.${fieldName} args must be an object with argument names as keys.`, ); @@ -967,8 +959,8 @@ export class GraphQLInterfaceType { this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); this.resolveType = config.resolveType; this._fields = defineFieldMap.bind(undefined, config); - invariant(typeof config.name === 'string', 'Must provide name.'); - invariant( + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert( config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`, @@ -1059,8 +1051,8 @@ export class GraphQLUnionType { this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); this.resolveType = config.resolveType; this._types = defineTypes.bind(undefined, config); - invariant(typeof config.name === 'string', 'Must provide name.'); - invariant( + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert( config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`, @@ -1102,7 +1094,7 @@ function defineTypes( config: GraphQLUnionTypeConfig, ): Array { const types = resolveThunk(config.types) || []; - invariant( + devAssert( Array.isArray(types), `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, ); @@ -1165,7 +1157,7 @@ export class GraphQLEnumType /* */ { ); this._nameLookup = keyMap(this._values, value => value.name); - invariant(typeof config.name === 'string', 'Must provide name.'); + devAssert(typeof config.name === 'string', 'Must provide name.'); } getValues(): Array */> { @@ -1239,17 +1231,17 @@ function defineEnumValues( typeName: string, valueMap: GraphQLEnumValueConfigMap /* */, ): Array */> { - invariant( + devAssert( isPlainObj(valueMap), `${typeName} values must be an object with value names as keys.`, ); return objectEntries(valueMap).map(([valueName, value]) => { - invariant( + devAssert( isPlainObj(value), `${typeName}.${valueName} must refer to an object with a "value" key ` + `representing an internal value but got: ${inspect(value)}.`, ); - invariant( + devAssert( !('isDeprecated' in value), `${typeName}.${valueName} should provide "deprecationReason" instead of "isDeprecated".`, ); @@ -1325,7 +1317,7 @@ export class GraphQLInputObjectType { this.astNode = config.astNode; this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); this._fields = defineInputFieldMap.bind(undefined, config); - invariant(typeof config.name === 'string', 'Must provide name.'); + devAssert(typeof config.name === 'string', 'Must provide name.'); } getFields(): GraphQLInputFieldMap { @@ -1369,12 +1361,12 @@ function defineInputFieldMap( config: GraphQLInputObjectTypeConfig, ): GraphQLInputFieldMap { const fieldMap = resolveThunk(config.fields) || {}; - invariant( + devAssert( isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, ); return mapValue(fieldMap, (fieldConfig, fieldName) => { - invariant( + devAssert( !('resolve' in fieldConfig), `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, ); diff --git a/src/type/directives.js b/src/type/directives.js index 46d8c76770..64640a5c48 100644 --- a/src/type/directives.js +++ b/src/type/directives.js @@ -3,7 +3,7 @@ import objectEntries from '../polyfills/objectEntries'; import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import instanceOf from '../jsutils/instanceOf'; import defineToJSON from '../jsutils/defineToJSON'; import isObjectLike from '../jsutils/isObjectLike'; @@ -35,10 +35,11 @@ export function isDirective(directive) { } export function assertDirective(directive: mixed): GraphQLDirective { - invariant( - isDirective(directive), - `Expected ${inspect(directive)} to be a GraphQL directive.`, - ); + if (!isDirective(directive)) { + throw new Error( + `Expected ${inspect(directive)} to be a GraphQL directive.`, + ); + } return directive; } @@ -61,14 +62,14 @@ export class GraphQLDirective { this.locations = config.locations; this.isRepeatable = config.isRepeatable != null && config.isRepeatable; this.astNode = config.astNode; - invariant(config.name, 'Directive must be named.'); - invariant( + devAssert(config.name, 'Directive must be named.'); + devAssert( Array.isArray(config.locations), `@${config.name} locations must be an Array.`, ); const args = config.args || {}; - invariant( + devAssert( isObjectLike(args) && !Array.isArray(args), `@${config.name} args must be an object with argument names as keys.`, ); diff --git a/src/type/schema.js b/src/type/schema.js index 3a5343361e..f9ca1e5631 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -4,7 +4,7 @@ import find from '../polyfills/find'; import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import instanceOf from '../jsutils/instanceOf'; import { type ObjMap } from '../jsutils/ObjMap'; import isObjectLike from '../jsutils/isObjectLike'; @@ -46,10 +46,9 @@ export function isSchema(schema) { } export function assertSchema(schema: mixed): GraphQLSchema { - invariant( - isSchema(schema), - `Expected ${inspect(schema)} to be a GraphQL schema.`, - ); + if (!isSchema(schema)) { + throw new Error(`Expected ${inspect(schema)} to be a GraphQL schema.`); + } return schema; } @@ -141,17 +140,17 @@ export class GraphQLSchema { // Otherwise check for common mistakes during construction to produce // clear and early error messages. - invariant(isObjectLike(config), 'Must provide configuration object.'); - invariant( + devAssert(isObjectLike(config), 'Must provide configuration object.'); + devAssert( !config.types || Array.isArray(config.types), `"types" must be Array if provided but got: ${inspect(config.types)}.`, ); - invariant( + devAssert( !config.directives || Array.isArray(config.directives), '"directives" must be Array if provided but got: ' + `${inspect(config.directives)}.`, ); - invariant( + devAssert( !config.allowedLegacyNames || Array.isArray(config.allowedLegacyNames), '"allowedLegacyNames" must be Array if provided but got: ' + `${inspect(config.allowedLegacyNames)}.`, @@ -329,11 +328,11 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { return typeMapReducer(map, type.ofType); } if (map[type.name]) { - invariant( - map[type.name] === type, - 'Schema must contain uniquely named types but contains multiple ' + - `types named "${type.name}".`, - ); + if (map[type.name] !== type) { + throw new Error( + `Schema must contain uniquely named types but contains multiple types named "${type.name}".`, + ); + } return map; } map[type.name] = type; diff --git a/src/utilities/assertValidName.js b/src/utilities/assertValidName.js index 7a132d944d..8622236dd2 100644 --- a/src/utilities/assertValidName.js +++ b/src/utilities/assertValidName.js @@ -1,6 +1,6 @@ // @flow strict -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import { GraphQLError } from '../error/GraphQLError'; import { type ASTNode } from '../language/ast'; @@ -25,7 +25,7 @@ export function isValidNameError( name: string, node?: ASTNode | void, ): GraphQLError | void { - invariant(typeof name === 'string', 'Expected string'); + devAssert(typeof name === 'string', 'Expected string'); if (name.length > 1 && name[0] === '_' && name[1] === '_') { return new GraphQLError( `Name "${name}" must not begin with "__", which is reserved by GraphQL introspection.`, diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.js index 16fcac87f3..9c8d0794b4 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.js @@ -4,7 +4,7 @@ import objectValues from '../polyfills/objectValues'; import keyMap from '../jsutils/keyMap'; import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import keyValMap from '../jsutils/keyValMap'; import { type ObjMap } from '../jsutils/ObjMap'; @@ -114,7 +114,7 @@ export function buildASTSchema( documentAST: DocumentNode, options?: BuildSchemaOptions, ): GraphQLSchema { - invariant( + devAssert( documentAST && documentAST.kind === Kind.DOCUMENT, 'Must provide valid Document AST', ); @@ -139,7 +139,9 @@ export function buildASTSchema( const astBuilder = new ASTDefinitionBuilder(options, typeName => { const type = typeMap[typeName]; - invariant(type, `Type "${typeName}" not found in document.`); + if (type === undefined) { + throw new Error(`Type "${typeName}" not found in document.`); + } return type; }); diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.js index b9f4df119d..6796f8ffd2 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.js @@ -3,7 +3,7 @@ import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import keyValMap from '../jsutils/keyValMap'; import isObjectLike from '../jsutils/isObjectLike'; @@ -72,7 +72,7 @@ export function buildClientSchema( introspection: IntrospectionQuery, options?: Options, ): GraphQLSchema { - invariant( + devAssert( isObjectLike(introspection) && isObjectLike(introspection.__schema), 'Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: ' + inspect(introspection), @@ -161,26 +161,28 @@ export function buildClientSchema( function getInputType(typeRef: IntrospectionInputTypeRef): GraphQLInputType { const type = getType(typeRef); - invariant( - isInputType(type), + if (isInputType(type)) { + return type; + } + throw new Error( 'Introspection must provide input type for arguments, but received: ' + inspect(type) + '.', ); - return type; } function getOutputType( typeRef: IntrospectionOutputTypeRef, ): GraphQLOutputType { const type = getType(typeRef); - invariant( - isOutputType(type), + if (isOutputType(type)) { + return type; + } + throw new Error( 'Introspection must provide output type for fields, but received: ' + inspect(type) + '.', ); - return type; } function getObjectType( diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.js index 14b78cbc77..bbdd9011a9 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.js @@ -5,7 +5,7 @@ import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; import mapValue from '../jsutils/mapValue'; -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import keyValMap from '../jsutils/keyValMap'; import { Kind } from '../language/kinds'; @@ -98,7 +98,7 @@ export function extendSchema( ): GraphQLSchema { assertSchema(schema); - invariant( + devAssert( documentAST && documentAST.kind === Kind.DOCUMENT, 'Must provide valid Document AST', ); @@ -152,7 +152,9 @@ export function extendSchema( const schemaConfig = schema.toConfig(); const astBuilder = new ASTDefinitionBuilder(options, typeName => { const type = typeMap[typeName]; - invariant(type, `Unknown type: "${typeName}".`); + if (type === undefined) { + throw new Error(`Unknown type: "${typeName}".`); + } return type; }); @@ -230,7 +232,7 @@ export function extendSchema( function getMergedDirectives(): Array { const existingDirectives = schema.getDirectives().map(extendDirective); - invariant(existingDirectives, 'schema must have default directives'); + devAssert(existingDirectives, 'schema must have default directives'); return existingDirectives.concat( directiveDefs.map(node => astBuilder.buildDirective(node)), diff --git a/src/validation/validate.js b/src/validation/validate.js index 4f17c2a66e..4da3e6d9c7 100644 --- a/src/validation/validate.js +++ b/src/validation/validate.js @@ -1,6 +1,6 @@ // @flow strict -import invariant from '../jsutils/invariant'; +import devAssert from '../jsutils/devAssert'; import { type GraphQLError } from '../error/GraphQLError'; @@ -42,7 +42,7 @@ export function validate( rules?: $ReadOnlyArray = specifiedRules, typeInfo?: TypeInfo = new TypeInfo(schema), ): $ReadOnlyArray { - invariant(documentAST, 'Must provide document'); + devAssert(documentAST, 'Must provide document'); // If the schema used for validation is invalid, throw an error. assertValidSchema(schema);