diff --git a/src/error/__tests__/GraphQLError-test.ts b/src/error/__tests__/GraphQLError-test.ts index 60f35e9b6c..1aa7d92f0c 100644 --- a/src/error/__tests__/GraphQLError-test.ts +++ b/src/error/__tests__/GraphQLError-test.ts @@ -40,15 +40,14 @@ describe('GraphQLError', () => { }); it('enumerate only properties prescribed by the spec', () => { - const e = new GraphQLError( - 'msg' /* message */, - [fieldNode] /* nodes */, - source /* source */, - [1, 2, 3] /* positions */, - ['a', 'b', 'c'] /* path */, - new Error('test') /* originalError */, - { foo: 'bar' } /* extensions */, - ); + const e = new GraphQLError('msg' /* message */, { + nodes: [fieldNode], + source, + positions: [1, 2, 3], + path: ['a', 'b', 'c'], + originalError: new Error('test'), + extensions: { foo: 'bar' }, + }); expect(Object.keys(e)).to.deep.equal([ 'message', @@ -60,14 +59,9 @@ describe('GraphQLError', () => { it('uses the stack of an original error', () => { const original = new Error('original'); - const e = new GraphQLError( - 'msg', - undefined, - undefined, - undefined, - undefined, - original, - ); + const e = new GraphQLError('msg', { + originalError: original, + }); expect(e).to.include({ name: 'GraphQLError', @@ -79,7 +73,7 @@ describe('GraphQLError', () => { it('creates new stack if original error has no stack', () => { const original = new Error('original'); - const e = new GraphQLError('msg', null, null, null, null, original); + const e = new GraphQLError('msg', { originalError: original }); expect(e).to.include({ name: 'GraphQLError', @@ -90,7 +84,7 @@ describe('GraphQLError', () => { }); it('converts nodes to positions and locations', () => { - const e = new GraphQLError('msg', [fieldNode]); + const e = new GraphQLError('msg', { nodes: [fieldNode] }); expect(e).to.deep.include({ source, nodes: [fieldNode], @@ -100,7 +94,7 @@ describe('GraphQLError', () => { }); it('converts single node to positions and locations', () => { - const e = new GraphQLError('msg', fieldNode); // Non-array value. + const e = new GraphQLError('msg', { nodes: fieldNode }); // Non-array value. expect(e).to.deep.include({ source, nodes: [fieldNode], @@ -110,7 +104,7 @@ describe('GraphQLError', () => { }); it('converts node with loc.start === 0 to positions and locations', () => { - const e = new GraphQLError('msg', operationNode); + const e = new GraphQLError('msg', { nodes: operationNode }); expect(e).to.deep.include({ source, nodes: [operationNode], @@ -125,7 +119,7 @@ describe('GraphQLError', () => { loc: undefined, }; - const e = new GraphQLError('msg', fieldNodeNoLocation); + const e = new GraphQLError('msg', { nodes: fieldNodeNoLocation }); expect(e).to.deep.include({ nodes: [fieldNodeNoLocation], source: undefined, @@ -135,7 +129,7 @@ describe('GraphQLError', () => { }); it('converts source and positions to locations', () => { - const e = new GraphQLError('msg', null, source, [6]); + const e = new GraphQLError('msg', { source, positions: [6] }); expect(e).to.deep.include({ source, nodes: undefined, @@ -155,15 +149,9 @@ describe('GraphQLError', () => { } const original = new ErrorWithExtensions('original'); - const inheritedExtensions = new GraphQLError( - 'InheritedExtensions', - undefined, - undefined, - undefined, - undefined, - original, - undefined, - ); + const inheritedExtensions = new GraphQLError('InheritedExtensions', { + originalError: original, + }); expect(inheritedExtensions).to.deep.include({ message: 'InheritedExtensions', @@ -171,15 +159,10 @@ describe('GraphQLError', () => { extensions: { original: 'extensions' }, }); - const ownExtensions = new GraphQLError( - 'OwnExtensions', - undefined, - undefined, - undefined, - undefined, - original, - { own: 'extensions' }, - ); + const ownExtensions = new GraphQLError('OwnExtensions', { + originalError: original, + extensions: { own: 'extensions' }, + }); expect(ownExtensions).to.deep.include({ message: 'OwnExtensions', @@ -187,15 +170,10 @@ describe('GraphQLError', () => { extensions: { own: 'extensions' }, }); - const ownEmptyExtensions = new GraphQLError( - 'OwnEmptyExtensions', - undefined, - undefined, - undefined, - undefined, - original, - {}, - ); + const ownEmptyExtensions = new GraphQLError('OwnEmptyExtensions', { + originalError: original, + extensions: {}, + }); expect(ownEmptyExtensions).to.deep.include({ message: 'OwnEmptyExtensions', @@ -214,15 +192,11 @@ describe('GraphQLError', () => { const path = ['path', 2, 'field']; const extensions = { foo: 'bar' }; - const eFull = new GraphQLError( - 'msg', - fieldNode, - undefined, - undefined, + const eFull = new GraphQLError('msg', { + nodes: fieldNode, path, - undefined, extensions, - ); + }); // We should try to keep order of fields stable // Changing it wouldn't be breaking change but will fail some tests in other libraries. @@ -260,10 +234,9 @@ describe('toString', () => { }); it('prints an error using node without location', () => { - const error = new GraphQLError( - 'Error attached to node without location', - parse('{ foo }', { noLocation: true }), - ); + const error = new GraphQLError('Error attached to node without location', { + nodes: parse('{ foo }', { noLocation: true }), + }); expect(error.toString()).to.equal( 'Error attached to node without location', ); @@ -330,12 +303,7 @@ describe('toJSON', () => { }); it('includes path', () => { - const error = new GraphQLError('msg', null, null, null, [ - 'path', - 3, - 'to', - 'field', - ]); + const error = new GraphQLError('msg', { path: ['path', 3, 'to', 'field'] }); expect(error.toJSON()).to.deep.equal({ message: 'msg', @@ -344,8 +312,8 @@ describe('toJSON', () => { }); it('includes extension fields', () => { - const error = new GraphQLError('msg', null, null, null, null, null, { - foo: 'bar', + const error = new GraphQLError('msg', { + extensions: { foo: 'bar' }, }); expect(error.toJSON()).to.deep.equal({ @@ -354,15 +322,16 @@ describe('toJSON', () => { }); }); - it('can be created with the alternative object argument', () => { - const error = new GraphQLError('msg', { - nodes: [operationNode], + it('can be created with the legacy argument list', () => { + const error = new GraphQLError( + 'msg', + [operationNode], source, - positions: [6], - path: ['path', 2, 'a'], - originalError: new Error('I like turtles'), - extensions: { hee: 'I like turtles' }, - }); + [6], + ['path', 2, 'a'], + new Error('I like turtles'), + { hee: 'I like turtles' }, + ); expect(error.toJSON()).to.deep.equal({ message: 'msg', diff --git a/src/error/__tests__/locatedError-test.ts b/src/error/__tests__/locatedError-test.ts index 2e35723ac2..e270d09a6d 100644 --- a/src/error/__tests__/locatedError-test.ts +++ b/src/error/__tests__/locatedError-test.ts @@ -6,12 +6,7 @@ import { locatedError } from '../locatedError'; describe('locatedError', () => { it('passes GraphQLError through', () => { - const e = new GraphQLError('msg', null, null, null, [ - 'path', - 3, - 'to', - 'field', - ]); + const e = new GraphQLError('msg', { path: ['path', 3, 'to', 'field'] }); expect(locatedError(e, [], [])).to.deep.equal(e); }); diff --git a/src/error/locatedError.ts b/src/error/locatedError.ts index 2fec320422..bafb9da9b6 100644 --- a/src/error/locatedError.ts +++ b/src/error/locatedError.ts @@ -22,14 +22,13 @@ export function locatedError( return originalError; } - return new GraphQLError( - originalError.message, - (originalError as GraphQLError).nodes ?? nodes, - (originalError as GraphQLError).source, - (originalError as GraphQLError).positions, + return new GraphQLError(originalError.message, { + nodes: (originalError as GraphQLError).nodes ?? nodes, + source: (originalError as GraphQLError).source, + positions: (originalError as GraphQLError).positions, path, originalError, - ); + }); } function isLocatedGraphQLError(error: any): error is GraphQLError { diff --git a/src/error/syntaxError.ts b/src/error/syntaxError.ts index 21a2dc18e4..386ece72da 100644 --- a/src/error/syntaxError.ts +++ b/src/error/syntaxError.ts @@ -11,7 +11,8 @@ export function syntaxError( position: number, description: string, ): GraphQLError { - return new GraphQLError(`Syntax Error: ${description}`, undefined, source, [ - position, - ]); + return new GraphQLError(`Syntax Error: ${description}`, { + source, + positions: [position], + }); } diff --git a/src/execution/execute.ts b/src/execution/execute.ts index d3c21385e8..4b8cf3a6f7 100644 --- a/src/execution/execute.ts +++ b/src/execution/execute.ts @@ -362,7 +362,7 @@ function executeOperation( if (rootType == null) { throw new GraphQLError( `Schema is not configured to execute ${operation.operation} operation.`, - operation, + { nodes: operation }, ); } @@ -881,21 +881,21 @@ function ensureValidRuntimeType( if (runtimeType == null) { throw new GraphQLError( `Abstract type "${returnType.name}" was resolved to a type "${runtimeTypeName}" that does not exist inside the schema.`, - fieldNodes, + { nodes: fieldNodes }, ); } if (!isObjectType(runtimeType)) { throw new GraphQLError( `Abstract type "${returnType.name}" was resolved to a non-object type "${runtimeTypeName}".`, - fieldNodes, + { nodes: fieldNodes }, ); } if (!exeContext.schema.isSubType(returnType, runtimeType)) { throw new GraphQLError( `Runtime Object type "${runtimeType.name}" is not a possible type for "${returnType.name}".`, - fieldNodes, + { nodes: fieldNodes }, ); } @@ -952,7 +952,7 @@ function invalidReturnTypeError( ): GraphQLError { return new GraphQLError( `Expected value of type "${returnType.name}" but got: ${inspect(result)}.`, - fieldNodes, + { nodes: fieldNodes }, ); } diff --git a/src/execution/subscribe.ts b/src/execution/subscribe.ts index 7ff5712550..91a8231538 100644 --- a/src/execution/subscribe.ts +++ b/src/execution/subscribe.ts @@ -194,7 +194,7 @@ async function executeSubscription( if (rootType == null) { throw new GraphQLError( 'Schema is not configured to execute subscription operation.', - operation, + { nodes: operation }, ); } @@ -212,7 +212,7 @@ async function executeSubscription( const fieldName = fieldNodes[0].name.value; throw new GraphQLError( `The subscription field "${fieldName}" is not defined.`, - fieldNodes, + { nodes: fieldNodes }, ); } diff --git a/src/execution/values.ts b/src/execution/values.ts index 79ec77361f..023e028109 100644 --- a/src/execution/values.ts +++ b/src/execution/values.ts @@ -86,7 +86,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`, - varDefNode.type, + { nodes: varDefNode.type }, ), ); continue; @@ -100,7 +100,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" of required type "${varTypeStr}" was not provided.`, - varDefNode, + { nodes: varDefNode }, ), ); } @@ -113,7 +113,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" of non-null type "${varTypeStr}" must not be null.`, - varDefNode, + { nodes: varDefNode }, ), ); continue; @@ -129,14 +129,10 @@ function coerceVariableValues( prefix += ` at "${varName}${printPathArray(path)}"`; } onError( - new GraphQLError( - prefix + '; ' + error.message, - varDefNode, - undefined, - undefined, - undefined, - error.originalError, - ), + new GraphQLError(prefix + '; ' + error.message, { + nodes: varDefNode, + originalError: error.originalError, + }), ); }, ); @@ -177,7 +173,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of required type "${inspect(argType)}" ` + 'was not provided.', - node, + { nodes: node }, ); } continue; @@ -198,7 +194,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of required type "${inspect(argType)}" ` + `was provided the variable "$${variableName}" which was not provided a runtime value.`, - valueNode, + { nodes: valueNode }, ); } continue; @@ -210,7 +206,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of non-null type "${inspect(argType)}" ` + 'must not be null.', - valueNode, + { nodes: valueNode }, ); } @@ -221,7 +217,7 @@ export function getArgumentValues( // continue with an invalid argument value. throw new GraphQLError( `Argument "${name}" has invalid value ${print(valueNode)}.`, - valueNode, + { nodes: valueNode }, ); } coercedValues[name] = coercedValue; diff --git a/src/type/definition.ts b/src/type/definition.ts index 5e0c6d0472..d9192c723a 100644 --- a/src/type/definition.ts +++ b/src/type/definition.ts @@ -1441,7 +1441,7 @@ export class GraphQLEnumType /* */ { throw new GraphQLError( `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr), - valueNode, + { nodes: valueNode }, ); } @@ -1451,7 +1451,7 @@ export class GraphQLEnumType /* */ { throw new GraphQLError( `Value "${valueStr}" does not exist in "${this.name}" enum.` + didYouMeanEnumValue(this, valueStr), - valueNode, + { nodes: valueNode }, ); } return enumValue.value; diff --git a/src/type/scalars.ts b/src/type/scalars.ts index de78e6b050..4990347887 100644 --- a/src/type/scalars.ts +++ b/src/type/scalars.ts @@ -70,14 +70,14 @@ export const GraphQLInt = new GraphQLScalarType({ if (valueNode.kind !== Kind.INT) { throw new GraphQLError( `Int cannot represent non-integer value: ${print(valueNode)}`, - valueNode, + { nodes: valueNode }, ); } const num = parseInt(valueNode.value, 10); if (num > GRAPHQL_MAX_INT || num < GRAPHQL_MIN_INT) { throw new GraphQLError( `Int cannot represent non 32-bit signed integer value: ${valueNode.value}`, - valueNode, + { nodes: valueNode }, ); } return num; @@ -166,7 +166,7 @@ export const GraphQLString = new GraphQLScalarType({ if (valueNode.kind !== Kind.STRING) { throw new GraphQLError( `String cannot represent a non string value: ${print(valueNode)}`, - valueNode, + { nodes: valueNode }, ); } return valueNode.value; @@ -204,7 +204,7 @@ export const GraphQLBoolean = new GraphQLScalarType({ if (valueNode.kind !== Kind.BOOLEAN) { throw new GraphQLError( `Boolean cannot represent a non boolean value: ${print(valueNode)}`, - valueNode, + { nodes: valueNode }, ); } return valueNode.value; @@ -245,7 +245,7 @@ export const GraphQLID = new GraphQLScalarType({ throw new GraphQLError( 'ID cannot represent a non-string and non-integer value: ' + print(valueNode), - valueNode, + { nodes: valueNode }, ); } return valueNode.value; diff --git a/src/type/validate.ts b/src/type/validate.ts index 92f7078757..126e97d980 100644 --- a/src/type/validate.ts +++ b/src/type/validate.ts @@ -102,7 +102,7 @@ class SchemaValidationContext { const _nodes = Array.isArray(nodes) ? (nodes.filter(Boolean) as ReadonlyArray) : (nodes as Maybe); - this._errors.push(new GraphQLError(message, _nodes)); + this._errors.push(new GraphQLError(message, { nodes: _nodes })); } getErrors(): ReadonlyArray { diff --git a/src/utilities/coerceInputValue.ts b/src/utilities/coerceInputValue.ts index 07883db85d..136bee63c9 100644 --- a/src/utilities/coerceInputValue.ts +++ b/src/utilities/coerceInputValue.ts @@ -160,14 +160,9 @@ function coerceInputValueImpl( onError( pathToArray(path), inputValue, - new GraphQLError( - `Expected type "${type.name}". ` + error.message, - undefined, - undefined, - undefined, - undefined, - error, - ), + new GraphQLError(`Expected type "${type.name}". ` + error.message, { + originalError: error, + }), ); } return; diff --git a/src/utilities/getOperationRootType.ts b/src/utilities/getOperationRootType.ts index 86302be854..db20a793a8 100644 --- a/src/utilities/getOperationRootType.ts +++ b/src/utilities/getOperationRootType.ts @@ -22,7 +22,7 @@ export function getOperationRootType( if (!queryType) { throw new GraphQLError( 'Schema does not define the required query root type.', - operation, + { nodes: operation }, ); } return queryType; @@ -31,10 +31,9 @@ export function getOperationRootType( if (operation.operation === 'mutation') { const mutationType = schema.getMutationType(); if (!mutationType) { - throw new GraphQLError( - 'Schema is not configured for mutations.', - operation, - ); + throw new GraphQLError('Schema is not configured for mutations.', { + nodes: operation, + }); } return mutationType; } @@ -42,16 +41,15 @@ export function getOperationRootType( if (operation.operation === 'subscription') { const subscriptionType = schema.getSubscriptionType(); if (!subscriptionType) { - throw new GraphQLError( - 'Schema is not configured for subscriptions.', - operation, - ); + throw new GraphQLError('Schema is not configured for subscriptions.', { + nodes: operation, + }); } return subscriptionType; } throw new GraphQLError( 'Can only have query, mutation and subscription operations.', - operation, + { nodes: operation }, ); } diff --git a/src/validation/__tests__/validation-test.ts b/src/validation/__tests__/validation-test.ts index e5b1318335..2d49f9335b 100644 --- a/src/validation/__tests__/validation-test.ts +++ b/src/validation/__tests__/validation-test.ts @@ -108,7 +108,7 @@ describe('Validate: Supports full validation', () => { const directiveDef = context.getDirective(); const error = new GraphQLError( 'Reporting directive: ' + String(directiveDef), - node, + { nodes: node }, ); context.reportError(error); }, diff --git a/src/validation/rules/ExecutableDefinitionsRule.ts b/src/validation/rules/ExecutableDefinitionsRule.ts index 8c4ec3d872..8f82a6797b 100644 --- a/src/validation/rules/ExecutableDefinitionsRule.ts +++ b/src/validation/rules/ExecutableDefinitionsRule.ts @@ -27,10 +27,9 @@ export function ExecutableDefinitionsRule( ? 'schema' : '"' + definition.name.value + '"'; context.reportError( - new GraphQLError( - `The ${defName} definition is not executable.`, - definition, - ), + new GraphQLError(`The ${defName} definition is not executable.`, { + nodes: definition, + }), ); } } diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.ts b/src/validation/rules/FieldsOnCorrectTypeRule.ts index e9d220efef..9182f9c4a1 100644 --- a/src/validation/rules/FieldsOnCorrectTypeRule.ts +++ b/src/validation/rules/FieldsOnCorrectTypeRule.ts @@ -58,7 +58,7 @@ export function FieldsOnCorrectTypeRule( new GraphQLError( `Cannot query field "${fieldName}" on type "${type.name}".` + suggestion, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/FragmentsOnCompositeTypesRule.ts b/src/validation/rules/FragmentsOnCompositeTypesRule.ts index 6fe51db906..fb71f63836 100644 --- a/src/validation/rules/FragmentsOnCompositeTypesRule.ts +++ b/src/validation/rules/FragmentsOnCompositeTypesRule.ts @@ -31,7 +31,7 @@ export function FragmentsOnCompositeTypesRule( context.reportError( new GraphQLError( `Fragment cannot condition on non composite type "${typeStr}".`, - typeCondition, + { nodes: typeCondition }, ), ); } @@ -44,7 +44,7 @@ export function FragmentsOnCompositeTypesRule( context.reportError( new GraphQLError( `Fragment "${node.name.value}" cannot condition on non composite type "${typeStr}".`, - node.typeCondition, + { nodes: node.typeCondition }, ), ); } diff --git a/src/validation/rules/KnownArgumentNamesRule.ts b/src/validation/rules/KnownArgumentNamesRule.ts index 5f5c4c70b5..332b21c1ca 100644 --- a/src/validation/rules/KnownArgumentNamesRule.ts +++ b/src/validation/rules/KnownArgumentNamesRule.ts @@ -39,7 +39,7 @@ export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor { new GraphQLError( `Unknown argument "${argName}" on field "${parentType.name}.${fieldDef.name}".` + didYouMean(suggestions), - argNode, + { nodes: argNode }, ), ); } @@ -88,7 +88,7 @@ export function KnownArgumentNamesOnDirectivesRule( new GraphQLError( `Unknown argument "${argName}" on directive "@${directiveName}".` + didYouMean(suggestions), - argNode, + { nodes: argNode }, ), ); } diff --git a/src/validation/rules/KnownDirectivesRule.ts b/src/validation/rules/KnownDirectivesRule.ts index 2b5b481165..f24dbe7d28 100644 --- a/src/validation/rules/KnownDirectivesRule.ts +++ b/src/validation/rules/KnownDirectivesRule.ts @@ -51,7 +51,7 @@ export function KnownDirectivesRule( if (!locations) { context.reportError( - new GraphQLError(`Unknown directive "@${name}".`, node), + new GraphQLError(`Unknown directive "@${name}".`, { nodes: node }), ); return; } @@ -61,7 +61,7 @@ export function KnownDirectivesRule( context.reportError( new GraphQLError( `Directive "@${name}" may not be used on ${candidateLocation}.`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/KnownFragmentNamesRule.ts b/src/validation/rules/KnownFragmentNamesRule.ts index 78fb244684..c37403f752 100644 --- a/src/validation/rules/KnownFragmentNamesRule.ts +++ b/src/validation/rules/KnownFragmentNamesRule.ts @@ -19,7 +19,9 @@ export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor { const fragment = context.getFragment(fragmentName); if (!fragment) { context.reportError( - new GraphQLError(`Unknown fragment "${fragmentName}".`, node.name), + new GraphQLError(`Unknown fragment "${fragmentName}".`, { + nodes: node.name, + }), ); } }, diff --git a/src/validation/rules/KnownTypeNamesRule.ts b/src/validation/rules/KnownTypeNamesRule.ts index 4802610a2e..fadc080c35 100644 --- a/src/validation/rules/KnownTypeNamesRule.ts +++ b/src/validation/rules/KnownTypeNamesRule.ts @@ -62,7 +62,7 @@ export function KnownTypeNamesRule( context.reportError( new GraphQLError( `Unknown type "${typeName}".` + didYouMean(suggestedTypes), - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/LoneAnonymousOperationRule.ts b/src/validation/rules/LoneAnonymousOperationRule.ts index ddd537dd9d..291a494c76 100644 --- a/src/validation/rules/LoneAnonymousOperationRule.ts +++ b/src/validation/rules/LoneAnonymousOperationRule.ts @@ -28,7 +28,7 @@ export function LoneAnonymousOperationRule( context.reportError( new GraphQLError( 'This anonymous operation must be the only defined operation.', - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/LoneSchemaDefinitionRule.ts b/src/validation/rules/LoneSchemaDefinitionRule.ts index df96238700..4eeb8cdcba 100644 --- a/src/validation/rules/LoneSchemaDefinitionRule.ts +++ b/src/validation/rules/LoneSchemaDefinitionRule.ts @@ -26,7 +26,7 @@ export function LoneSchemaDefinitionRule( context.reportError( new GraphQLError( 'Cannot define a new schema within a schema extension.', - node, + { nodes: node }, ), ); return; @@ -34,7 +34,9 @@ export function LoneSchemaDefinitionRule( if (schemaDefinitionsCount > 0) { context.reportError( - new GraphQLError('Must provide only one schema definition.', node), + new GraphQLError('Must provide only one schema definition.', { + nodes: node, + }), ); } ++schemaDefinitionsCount; diff --git a/src/validation/rules/NoFragmentCyclesRule.ts b/src/validation/rules/NoFragmentCyclesRule.ts index 0a33f4508d..448b1cf496 100644 --- a/src/validation/rules/NoFragmentCyclesRule.ts +++ b/src/validation/rules/NoFragmentCyclesRule.ts @@ -78,7 +78,7 @@ export function NoFragmentCyclesRule( new GraphQLError( `Cannot spread fragment "${spreadName}" within itself` + (viaPath !== '' ? ` via ${viaPath}.` : '.'), - cyclePath, + { nodes: cyclePath }, ), ); } diff --git a/src/validation/rules/NoUndefinedVariablesRule.ts b/src/validation/rules/NoUndefinedVariablesRule.ts index 36bfe049b4..3d499b5dcc 100644 --- a/src/validation/rules/NoUndefinedVariablesRule.ts +++ b/src/validation/rules/NoUndefinedVariablesRule.ts @@ -33,7 +33,7 @@ export function NoUndefinedVariablesRule( operation.name ? `Variable "$${varName}" is not defined by operation "${operation.name.value}".` : `Variable "$${varName}" is not defined.`, - [node, operation], + { nodes: [node, operation] }, ), ); } diff --git a/src/validation/rules/NoUnusedFragmentsRule.ts b/src/validation/rules/NoUnusedFragmentsRule.ts index 2047945463..aebf34535d 100644 --- a/src/validation/rules/NoUnusedFragmentsRule.ts +++ b/src/validation/rules/NoUnusedFragmentsRule.ts @@ -46,10 +46,9 @@ export function NoUnusedFragmentsRule( const fragName = fragmentDef.name.value; if (fragmentNameUsed[fragName] !== true) { context.reportError( - new GraphQLError( - `Fragment "${fragName}" is never used.`, - fragmentDef, - ), + new GraphQLError(`Fragment "${fragName}" is never used.`, { + nodes: fragmentDef, + }), ); } } diff --git a/src/validation/rules/NoUnusedVariablesRule.ts b/src/validation/rules/NoUnusedVariablesRule.ts index b81fd07843..5083af4f28 100644 --- a/src/validation/rules/NoUnusedVariablesRule.ts +++ b/src/validation/rules/NoUnusedVariablesRule.ts @@ -37,7 +37,7 @@ export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor { operation.name ? `Variable "$${variableName}" is never used in operation "${operation.name.value}".` : `Variable "$${variableName}" is never used.`, - variableDef, + { nodes: variableDef }, ), ); } diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts index a7d2b257b7..bdf6eb874e 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts +++ b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts @@ -82,7 +82,7 @@ export function OverlappingFieldsCanBeMergedRule( context.reportError( new GraphQLError( `Fields "${responseName}" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`, - fields1.concat(fields2), + { nodes: fields1.concat(fields2) }, ), ); } diff --git a/src/validation/rules/PossibleFragmentSpreadsRule.ts b/src/validation/rules/PossibleFragmentSpreadsRule.ts index b2210e5a3e..fe738e5559 100644 --- a/src/validation/rules/PossibleFragmentSpreadsRule.ts +++ b/src/validation/rules/PossibleFragmentSpreadsRule.ts @@ -37,7 +37,7 @@ export function PossibleFragmentSpreadsRule( context.reportError( new GraphQLError( `Fragment cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, - node, + { nodes: node }, ), ); } @@ -56,7 +56,7 @@ export function PossibleFragmentSpreadsRule( context.reportError( new GraphQLError( `Fragment "${fragName}" cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/PossibleTypeExtensionsRule.ts b/src/validation/rules/PossibleTypeExtensionsRule.ts index 4abca7b78c..57d16b473f 100644 --- a/src/validation/rules/PossibleTypeExtensionsRule.ts +++ b/src/validation/rules/PossibleTypeExtensionsRule.ts @@ -65,10 +65,9 @@ export function PossibleTypeExtensionsRule( if (expectedKind !== node.kind) { const kindStr = extensionKindToTypeName(node.kind); context.reportError( - new GraphQLError( - `Cannot extend non-${kindStr} type "${typeName}".`, - defNode ? [defNode, node] : node, - ), + new GraphQLError(`Cannot extend non-${kindStr} type "${typeName}".`, { + nodes: defNode ? [defNode, node] : node, + }), ); } } else { @@ -82,7 +81,7 @@ export function PossibleTypeExtensionsRule( new GraphQLError( `Cannot extend type "${typeName}" because it is not defined.` + didYouMean(suggestedTypes), - node.name, + { nodes: node.name }, ), ); } diff --git a/src/validation/rules/ProvidedRequiredArgumentsRule.ts b/src/validation/rules/ProvidedRequiredArgumentsRule.ts index b16079b1c6..b111dcee1b 100644 --- a/src/validation/rules/ProvidedRequiredArgumentsRule.ts +++ b/src/validation/rules/ProvidedRequiredArgumentsRule.ts @@ -49,7 +49,7 @@ export function ProvidedRequiredArgumentsRule( context.reportError( new GraphQLError( `Field "${fieldDef.name}" argument "${argDef.name}" of type "${argTypeStr}" is required, but it was not provided.`, - fieldNode, + { nodes: fieldNode }, ), ); } @@ -111,7 +111,7 @@ export function ProvidedRequiredArgumentsOnDirectivesRule( context.reportError( new GraphQLError( `Directive "@${directiveName}" argument "${argName}" of type "${argType}" is required, but it was not provided.`, - directiveNode, + { nodes: directiveNode }, ), ); } diff --git a/src/validation/rules/ScalarLeafsRule.ts b/src/validation/rules/ScalarLeafsRule.ts index c59667d91c..fb573d47e0 100644 --- a/src/validation/rules/ScalarLeafsRule.ts +++ b/src/validation/rules/ScalarLeafsRule.ts @@ -28,7 +28,7 @@ export function ScalarLeafsRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${fieldName}" must not have a selection since type "${typeStr}" has no subfields.`, - selectionSet, + { nodes: selectionSet }, ), ); } @@ -38,7 +38,7 @@ export function ScalarLeafsRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${fieldName}" of type "${typeStr}" must have a selection of subfields. Did you mean "${fieldName} { ... }"?`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.ts b/src/validation/rules/SingleFieldSubscriptionsRule.ts index db0e6446a1..21cb1abaf6 100644 --- a/src/validation/rules/SingleFieldSubscriptionsRule.ts +++ b/src/validation/rules/SingleFieldSubscriptionsRule.ts @@ -57,7 +57,7 @@ export function SingleFieldSubscriptionsRule( operationName != null ? `Subscription "${operationName}" must select only one top level field.` : 'Anonymous Subscription must select only one top level field.', - extraFieldSelections, + { nodes: extraFieldSelections }, ), ); } @@ -70,7 +70,7 @@ export function SingleFieldSubscriptionsRule( operationName != null ? `Subscription "${operationName}" must not select an introspection top level field.` : 'Anonymous Subscription must not select an introspection top level field.', - fieldNodes, + { nodes: fieldNodes }, ), ); } diff --git a/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts b/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts index 3f6e79dfa2..2348276338 100644 --- a/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts +++ b/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts @@ -68,7 +68,7 @@ export function UniqueArgumentDefinitionNamesRule( context.reportError( new GraphQLError( `Argument "${parentName}(${argName}:)" can only be defined once.`, - argNodes.map((node) => node.name), + { nodes: argNodes.map((node) => node.name) }, ), ); } diff --git a/src/validation/rules/UniqueArgumentNamesRule.ts b/src/validation/rules/UniqueArgumentNamesRule.ts index fad6ed0e2d..19667efaa7 100644 --- a/src/validation/rules/UniqueArgumentNamesRule.ts +++ b/src/validation/rules/UniqueArgumentNamesRule.ts @@ -37,7 +37,7 @@ export function UniqueArgumentNamesRule( context.reportError( new GraphQLError( `There can be only one argument named "${argName}".`, - argNodes.map((node) => node.name), + { nodes: argNodes.map((node) => node.name) }, ), ); } diff --git a/src/validation/rules/UniqueDirectiveNamesRule.ts b/src/validation/rules/UniqueDirectiveNamesRule.ts index cbd39ce254..ade517ddce 100644 --- a/src/validation/rules/UniqueDirectiveNamesRule.ts +++ b/src/validation/rules/UniqueDirectiveNamesRule.ts @@ -23,7 +23,7 @@ export function UniqueDirectiveNamesRule( context.reportError( new GraphQLError( `Directive "@${directiveName}" already exists in the schema. It cannot be redefined.`, - node.name, + { nodes: node.name }, ), ); return; @@ -33,7 +33,7 @@ export function UniqueDirectiveNamesRule( context.reportError( new GraphQLError( `There can be only one directive named "@${directiveName}".`, - [knownDirectiveNames[directiveName], node.name], + { nodes: [knownDirectiveNames[directiveName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueDirectivesPerLocationRule.ts b/src/validation/rules/UniqueDirectivesPerLocationRule.ts index 18b04c505e..a4fc54690a 100644 --- a/src/validation/rules/UniqueDirectivesPerLocationRule.ts +++ b/src/validation/rules/UniqueDirectivesPerLocationRule.ts @@ -78,7 +78,7 @@ export function UniqueDirectivesPerLocationRule( context.reportError( new GraphQLError( `The directive "@${directiveName}" can only be used once at this location.`, - [seenDirectives[directiveName], directive], + { nodes: [seenDirectives[directiveName], directive] }, ), ); } else { diff --git a/src/validation/rules/UniqueEnumValueNamesRule.ts b/src/validation/rules/UniqueEnumValueNamesRule.ts index 5fbe62ce27..2bdf8749a2 100644 --- a/src/validation/rules/UniqueEnumValueNamesRule.ts +++ b/src/validation/rules/UniqueEnumValueNamesRule.ts @@ -49,14 +49,14 @@ export function UniqueEnumValueNamesRule( context.reportError( new GraphQLError( `Enum value "${typeName}.${valueName}" already exists in the schema. It cannot also be defined in this type extension.`, - valueDef.name, + { nodes: valueDef.name }, ), ); } else if (valueNames[valueName]) { context.reportError( new GraphQLError( `Enum value "${typeName}.${valueName}" can only be defined once.`, - [valueNames[valueName], valueDef.name], + { nodes: [valueNames[valueName], valueDef.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueFieldDefinitionNamesRule.ts b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts index f312b76d76..52f6527d64 100644 --- a/src/validation/rules/UniqueFieldDefinitionNamesRule.ts +++ b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts @@ -61,14 +61,14 @@ export function UniqueFieldDefinitionNamesRule( context.reportError( new GraphQLError( `Field "${typeName}.${fieldName}" already exists in the schema. It cannot also be defined in this type extension.`, - fieldDef.name, + { nodes: fieldDef.name }, ), ); } else if (fieldNames[fieldName]) { context.reportError( new GraphQLError( `Field "${typeName}.${fieldName}" can only be defined once.`, - [fieldNames[fieldName], fieldDef.name], + { nodes: [fieldNames[fieldName], fieldDef.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueFragmentNamesRule.ts b/src/validation/rules/UniqueFragmentNamesRule.ts index 47e129e1ee..3b4311e9c8 100644 --- a/src/validation/rules/UniqueFragmentNamesRule.ts +++ b/src/validation/rules/UniqueFragmentNamesRule.ts @@ -23,7 +23,7 @@ export function UniqueFragmentNamesRule( context.reportError( new GraphQLError( `There can be only one fragment named "${fragmentName}".`, - [knownFragmentNames[fragmentName], node.name], + { nodes: [knownFragmentNames[fragmentName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueInputFieldNamesRule.ts b/src/validation/rules/UniqueInputFieldNamesRule.ts index 392df444a4..c1916a73b3 100644 --- a/src/validation/rules/UniqueInputFieldNamesRule.ts +++ b/src/validation/rules/UniqueInputFieldNamesRule.ts @@ -40,7 +40,7 @@ export function UniqueInputFieldNamesRule( context.reportError( new GraphQLError( `There can be only one input field named "${fieldName}".`, - [knownNames[fieldName], node.name], + { nodes: [knownNames[fieldName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueOperationNamesRule.ts b/src/validation/rules/UniqueOperationNamesRule.ts index fb6b11cddd..6df98be8c7 100644 --- a/src/validation/rules/UniqueOperationNamesRule.ts +++ b/src/validation/rules/UniqueOperationNamesRule.ts @@ -23,7 +23,12 @@ export function UniqueOperationNamesRule( context.reportError( new GraphQLError( `There can be only one operation named "${operationName.value}".`, - [knownOperationNames[operationName.value], operationName], + { + nodes: [ + knownOperationNames[operationName.value], + operationName, + ], + }, ), ); } else { diff --git a/src/validation/rules/UniqueOperationTypesRule.ts b/src/validation/rules/UniqueOperationTypesRule.ts index 59aa4c9507..f8ac6871ec 100644 --- a/src/validation/rules/UniqueOperationTypesRule.ts +++ b/src/validation/rules/UniqueOperationTypesRule.ts @@ -46,14 +46,14 @@ export function UniqueOperationTypesRule( context.reportError( new GraphQLError( `Type for ${operation} already defined in the schema. It cannot be redefined.`, - operationType, + { nodes: operationType }, ), ); } else if (alreadyDefinedOperationType) { context.reportError( new GraphQLError( `There can be only one ${operation} type in schema.`, - [alreadyDefinedOperationType, operationType], + { nodes: [alreadyDefinedOperationType, operationType] }, ), ); } else { diff --git a/src/validation/rules/UniqueTypeNamesRule.ts b/src/validation/rules/UniqueTypeNamesRule.ts index 7d11a32015..a1f6588b11 100644 --- a/src/validation/rules/UniqueTypeNamesRule.ts +++ b/src/validation/rules/UniqueTypeNamesRule.ts @@ -30,7 +30,7 @@ export function UniqueTypeNamesRule(context: SDLValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Type "${typeName}" already exists in the schema. It cannot also be defined in this type definition.`, - node.name, + { nodes: node.name }, ), ); return; @@ -38,10 +38,9 @@ export function UniqueTypeNamesRule(context: SDLValidationContext): ASTVisitor { if (knownTypeNames[typeName]) { context.reportError( - new GraphQLError(`There can be only one type named "${typeName}".`, [ - knownTypeNames[typeName], - node.name, - ]), + new GraphQLError(`There can be only one type named "${typeName}".`, { + nodes: [knownTypeNames[typeName], node.name], + }), ); } else { knownTypeNames[typeName] = node.name; diff --git a/src/validation/rules/UniqueVariableNamesRule.ts b/src/validation/rules/UniqueVariableNamesRule.ts index 1e9a5f8dab..3c9f76d885 100644 --- a/src/validation/rules/UniqueVariableNamesRule.ts +++ b/src/validation/rules/UniqueVariableNamesRule.ts @@ -30,7 +30,7 @@ export function UniqueVariableNamesRule( context.reportError( new GraphQLError( `There can be only one variable named "$${variableName}".`, - variableNodes.map((node) => node.variable.name), + { nodes: variableNodes.map((node) => node.variable.name) }, ), ); } diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.ts b/src/validation/rules/ValuesOfCorrectTypeRule.ts index 158691c50c..5d81a3833a 100644 --- a/src/validation/rules/ValuesOfCorrectTypeRule.ts +++ b/src/validation/rules/ValuesOfCorrectTypeRule.ts @@ -57,7 +57,7 @@ export function ValuesOfCorrectTypeRule( context.reportError( new GraphQLError( `Field "${type.name}.${fieldDef.name}" of required type "${typeStr}" was not provided.`, - node, + { nodes: node }, ), ); } @@ -75,7 +75,7 @@ export function ValuesOfCorrectTypeRule( new GraphQLError( `Field "${node.name.value}" is not defined by type "${parentType.name}".` + didYouMean(suggestions), - node, + { nodes: node }, ), ); } @@ -86,7 +86,7 @@ export function ValuesOfCorrectTypeRule( context.reportError( new GraphQLError( `Expected value of type "${inspect(type)}", found ${print(node)}.`, - node, + { nodes: node }, ), ); } @@ -117,7 +117,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { context.reportError( new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}.`, - node, + { nodes: node }, ), ); return; @@ -132,7 +132,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { context.reportError( new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}.`, - node, + { nodes: node }, ), ); } @@ -145,11 +145,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}; ` + error.message, - node, - undefined, - undefined, - undefined, - error, // Ensure a reference to the original error is maintained. + { nodes: node, originalError: error }, ), ); } diff --git a/src/validation/rules/VariablesAreInputTypesRule.ts b/src/validation/rules/VariablesAreInputTypesRule.ts index bf83038016..58d535ce81 100644 --- a/src/validation/rules/VariablesAreInputTypesRule.ts +++ b/src/validation/rules/VariablesAreInputTypesRule.ts @@ -32,7 +32,7 @@ export function VariablesAreInputTypesRule( context.reportError( new GraphQLError( `Variable "$${variableName}" cannot be non-input type "${typeName}".`, - node.type, + { nodes: node.type }, ), ); } diff --git a/src/validation/rules/VariablesInAllowedPositionRule.ts b/src/validation/rules/VariablesInAllowedPositionRule.ts index d8d50025c4..a0b7e991a6 100644 --- a/src/validation/rules/VariablesInAllowedPositionRule.ts +++ b/src/validation/rules/VariablesInAllowedPositionRule.ts @@ -62,7 +62,7 @@ export function VariablesInAllowedPositionRule( context.reportError( new GraphQLError( `Variable "$${varName}" of type "${varTypeStr}" used in position expecting type "${typeStr}".`, - [varDef, node], + { nodes: [varDef, node] }, ), ); } diff --git a/src/validation/rules/custom/NoDeprecatedCustomRule.ts b/src/validation/rules/custom/NoDeprecatedCustomRule.ts index 38b688a203..e06ac2e789 100644 --- a/src/validation/rules/custom/NoDeprecatedCustomRule.ts +++ b/src/validation/rules/custom/NoDeprecatedCustomRule.ts @@ -29,7 +29,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `The field ${parentType.name}.${fieldDef.name} is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -43,7 +43,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Directive "@${directiveDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } else { @@ -53,7 +53,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${parentType.name}.${fieldDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -68,7 +68,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `The input field ${inputObjectDef.name}.${inputFieldDef.name} is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -83,7 +83,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `The enum value "${enumTypeDef.name}.${enumValueDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts index 7a1c1f2ab9..257d58d723 100644 --- a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts +++ b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts @@ -28,7 +28,7 @@ export function NoSchemaIntrospectionCustomRule( context.reportError( new GraphQLError( `GraphQL introspection has been disabled, but the requested query contained the field "${node.name.value}".`, - node, + { nodes: node }, ), ); }