diff --git a/src/validation/__tests__/ExecutableDefinitions-test.js b/src/validation/__tests__/ExecutableDefinitions-test.js index beb71ac04f..2bf551bfc7 100644 --- a/src/validation/__tests__/ExecutableDefinitions-test.js +++ b/src/validation/__tests__/ExecutableDefinitions-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - ExecutableDefinitions, - nonExecutableDefinitionMessage, -} from '../rules/ExecutableDefinitions'; +import { ExecutableDefinitions } from '../rules/ExecutableDefinitions'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function nonExecutableDefinition(defName, line, column) { - return { - message: nonExecutableDefinitionMessage(defName), - locations: [{ line, column }], - }; -} - describe('Validate: Executable definitions', () => { it('with only operation', () => { expectValid(` @@ -66,8 +56,14 @@ describe('Validate: Executable definitions', () => { color: String } `).to.deep.equal([ - nonExecutableDefinition('Cow', 8, 7), - nonExecutableDefinition('Dog', 12, 7), + { + message: 'The Cow definition is not executable.', + locations: [{ line: 8, column: 7 }], + }, + { + message: 'The Dog definition is not executable.', + locations: [{ line: 12, column: 7 }], + }, ]); }); @@ -83,9 +79,18 @@ describe('Validate: Executable definitions', () => { extend schema @directive `).to.deep.equal([ - nonExecutableDefinition('schema', 2, 7), - nonExecutableDefinition('Query', 6, 7), - nonExecutableDefinition('schema', 10, 7), + { + message: 'The schema definition is not executable.', + locations: [{ line: 2, column: 7 }], + }, + { + message: 'The Query definition is not executable.', + locations: [{ line: 6, column: 7 }], + }, + { + message: 'The schema definition is not executable.', + locations: [{ line: 10, column: 7 }], + }, ]); }); }); diff --git a/src/validation/__tests__/FieldsOnCorrectType-test.js b/src/validation/__tests__/FieldsOnCorrectType-test.js index 7d833b7df4..47b3cf5177 100644 --- a/src/validation/__tests__/FieldsOnCorrectType-test.js +++ b/src/validation/__tests__/FieldsOnCorrectType-test.js @@ -3,10 +3,12 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { - FieldsOnCorrectType, - undefinedFieldMessage, -} from '../rules/FieldsOnCorrectType'; +import { parse } from '../../language/parser'; + +import { buildSchema } from '../../utilities/buildASTSchema'; + +import { validate } from '../validate'; +import { FieldsOnCorrectType } from '../rules/FieldsOnCorrectType'; import { expectValidationErrors } from './harness'; @@ -18,25 +20,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function undefinedField( - field, - type, - suggestedTypes, - suggestedFields, - line, - column, -) { - return { - message: undefinedFieldMessage( - field, - type, - suggestedTypes, - suggestedFields, - ), - locations: [{ line, column }], - }; -} - describe('Validate: Fields on correct type', () => { it('Object field selection', () => { expectValid(` @@ -99,8 +82,14 @@ describe('Validate: Fields on correct type', () => { } } `).to.deep.equal([ - undefinedField('unknown_pet_field', 'Pet', [], [], 3, 9), - undefinedField('unknown_cat_field', 'Cat', [], [], 5, 13), + { + message: 'Cannot query field "unknown_pet_field" on type "Pet".', + locations: [{ line: 3, column: 9 }], + }, + { + message: 'Cannot query field "unknown_cat_field" on type "Cat".', + locations: [{ line: 5, column: 13 }], + }, ]); }); @@ -110,7 +99,11 @@ describe('Validate: Fields on correct type', () => { meowVolume } `).to.deep.equal([ - undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 3, 9), + { + message: + 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -121,7 +114,12 @@ describe('Validate: Fields on correct type', () => { deeper_unknown_field } } - `).to.deep.equal([undefinedField('unknown_field', 'Dog', [], [], 3, 9)]); + `).to.deep.equal([ + { + message: 'Cannot query field "unknown_field" on type "Dog".', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('Sub-field not defined', () => { @@ -131,7 +129,12 @@ describe('Validate: Fields on correct type', () => { unknown_field } } - `).to.deep.equal([undefinedField('unknown_field', 'Pet', [], [], 4, 11)]); + `).to.deep.equal([ + { + message: 'Cannot query field "unknown_field" on type "Pet".', + locations: [{ line: 4, column: 11 }], + }, + ]); }); it('Field not defined on inline fragment', () => { @@ -142,7 +145,11 @@ describe('Validate: Fields on correct type', () => { } } `).to.deep.equal([ - undefinedField('meowVolume', 'Dog', [], ['barkVolume'], 4, 11), + { + message: + 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', + locations: [{ line: 4, column: 11 }], + }, ]); }); @@ -152,7 +159,11 @@ describe('Validate: Fields on correct type', () => { volume : mooVolume } `).to.deep.equal([ - undefinedField('mooVolume', 'Dog', [], ['barkVolume'], 3, 9), + { + message: + 'Cannot query field "mooVolume" on type "Dog". Did you mean "barkVolume"?', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -162,7 +173,11 @@ describe('Validate: Fields on correct type', () => { barkVolume : kawVolume } `).to.deep.equal([ - undefinedField('kawVolume', 'Dog', [], ['barkVolume'], 3, 9), + { + message: + 'Cannot query field "kawVolume" on type "Dog". Did you mean "barkVolume"?', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -171,7 +186,12 @@ describe('Validate: Fields on correct type', () => { fragment notDefinedOnInterface on Pet { tailLength } - `).to.deep.equal([undefinedField('tailLength', 'Pet', [], [], 3, 9)]); + `).to.deep.equal([ + { + message: 'Cannot query field "tailLength" on type "Pet".', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('Defined on implementors but not on interface', () => { @@ -180,7 +200,11 @@ describe('Validate: Fields on correct type', () => { nickname } `).to.deep.equal([ - undefinedField('nickname', 'Pet', ['Dog', 'Cat'], ['name'], 3, 9), + { + message: + 'Cannot query field "nickname" on type "Pet". Did you mean to use an inline fragment on "Dog" or "Cat"?', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -197,7 +221,12 @@ describe('Validate: Fields on correct type', () => { fragment directFieldSelectionOnUnion on CatOrDog { directField } - `).to.deep.equal([undefinedField('directField', 'CatOrDog', [], [], 3, 9)]); + `).to.deep.equal([ + { + message: 'Cannot query field "directField" on type "CatOrDog".', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('Defined on implementors queried on union', () => { @@ -206,14 +235,11 @@ describe('Validate: Fields on correct type', () => { name } `).to.deep.equal([ - undefinedField( - 'name', - 'CatOrDog', - ['Being', 'Pet', 'Canine', 'Dog', 'Cat'], - [], - 3, - 9, - ), + { + message: + 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Being", "Pet", "Canine", "Dog", or "Cat"?', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -231,42 +257,110 @@ describe('Validate: Fields on correct type', () => { }); describe('Fields on correct type error message', () => { + function expectErrorMessage(schema, queryStr) { + const errors = validate(schema, parse(queryStr), [FieldsOnCorrectType]); + expect(errors.length).to.equal(1); + return expect(errors[0].message); + } + it('Works with no suggestions', () => { - expect(undefinedFieldMessage('f', 'T', [], [])).to.equal( + const schema = buildSchema(` + type T { + fieldWithVeryLongNameThatWillNeverBeSuggested: String + } + type Query { t: T } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T".', ); }); it('Works with no small numbers of type suggestions', () => { - expect(undefinedFieldMessage('f', 'T', ['A', 'B'], [])).to.equal( + const schema = buildSchema(` + union T = A | B + type Query { t: T } + + type A { f: String } + type B { f: String } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?', ); }); it('Works with no small numbers of field suggestions', () => { - expect(undefinedFieldMessage('f', 'T', [], ['z', 'y'])).to.equal( + const schema = buildSchema(` + type T { + z: String + y: String + } + type Query { t: T } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T". Did you mean "z" or "y"?', ); }); it('Only shows one set of suggestions at a time, preferring types', () => { - expect(undefinedFieldMessage('f', 'T', ['A', 'B'], ['z', 'y'])).to.equal( + const schema = buildSchema(` + interface T { + z: String + y: String + } + type Query { t: T } + + type A implements T { + f: String + z: String + y: String + } + type B implements T { + f: String + z: String + y: String + } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?', ); }); it('Limits lots of type suggestions', () => { - expect( - undefinedFieldMessage('f', 'T', ['A', 'B', 'C', 'D', 'E', 'F'], []), - ).to.equal( + const schema = buildSchema(` + union T = A | B | C | D | E | F + type Query { t: T } + + type A { f: String } + type B { f: String } + type C { f: String } + type D { f: String } + type E { f: String } + type F { f: String } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A", "B", "C", "D", or "E"?', ); }); it('Limits lots of field suggestions', () => { - expect( - undefinedFieldMessage('f', 'T', [], ['z', 'y', 'x', 'w', 'v', 'u']), - ).to.equal( + const schema = buildSchema(` + type T { + z: String + y: String + x: String + w: String + v: String + u: String + } + type Query { t: T } + `); + + expectErrorMessage(schema, '{ t { f } }').to.equal( 'Cannot query field "f" on type "T". Did you mean "z", "y", "x", "w", or "v"?', ); }); diff --git a/src/validation/__tests__/FragmentsOnCompositeTypes-test.js b/src/validation/__tests__/FragmentsOnCompositeTypes-test.js index 76eef0a8af..1438be623b 100644 --- a/src/validation/__tests__/FragmentsOnCompositeTypes-test.js +++ b/src/validation/__tests__/FragmentsOnCompositeTypes-test.js @@ -2,11 +2,7 @@ import { describe, it } from 'mocha'; -import { - FragmentsOnCompositeTypes, - inlineFragmentOnNonCompositeErrorMessage, - fragmentOnNonCompositeErrorMessage, -} from '../rules/FragmentsOnCompositeTypes'; +import { FragmentsOnCompositeTypes } from '../rules/FragmentsOnCompositeTypes'; import { expectValidationErrors } from './harness'; @@ -18,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function fragmentOnNonComposite(fragName, typeName, line, column) { - return { - message: fragmentOnNonCompositeErrorMessage(fragName, typeName), - locations: [{ line, column }], - }; -} - describe('Validate: Fragments on composite types', () => { it('object is valid fragment type', () => { expectValid(` @@ -76,7 +65,11 @@ describe('Validate: Fragments on composite types', () => { bad } `).to.deep.equal([ - fragmentOnNonComposite('scalarFragment', 'Boolean', 2, 34), + { + message: + 'Fragment "scalarFragment" cannot condition on non composite type "Boolean".', + locations: [{ line: 2, column: 34 }], + }, ]); }); @@ -86,7 +79,11 @@ describe('Validate: Fragments on composite types', () => { bad } `).to.deep.equal([ - fragmentOnNonComposite('scalarFragment', 'FurColor', 2, 34), + { + message: + 'Fragment "scalarFragment" cannot condition on non composite type "FurColor".', + locations: [{ line: 2, column: 34 }], + }, ]); }); @@ -96,7 +93,11 @@ describe('Validate: Fragments on composite types', () => { stringField } `).to.deep.equal([ - fragmentOnNonComposite('inputFragment', 'ComplexInput', 2, 33), + { + message: + 'Fragment "inputFragment" cannot condition on non composite type "ComplexInput".', + locations: [{ line: 2, column: 33 }], + }, ]); }); @@ -109,7 +110,7 @@ describe('Validate: Fragments on composite types', () => { } `).to.deep.equal([ { - message: inlineFragmentOnNonCompositeErrorMessage('String'), + message: 'Fragment cannot condition on non composite type "String".', locations: [{ line: 3, column: 16 }], }, ]); diff --git a/src/validation/__tests__/KnownArgumentNames-test.js b/src/validation/__tests__/KnownArgumentNames-test.js index df6d9672d8..4ea92f27c3 100644 --- a/src/validation/__tests__/KnownArgumentNames-test.js +++ b/src/validation/__tests__/KnownArgumentNames-test.js @@ -7,8 +7,6 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { KnownArgumentNames, KnownArgumentNamesOnDirectives, - unknownArgMessage, - unknownDirectiveArgMessage, } from '../rules/KnownArgumentNames'; import { expectValidationErrors, expectSDLValidationErrors } from './harness'; @@ -33,26 +31,6 @@ function expectValidSDL(sdlStr) { expectSDLErrors(sdlStr).to.deep.equal([]); } -function unknownArg(argName, fieldName, typeName, suggestedArgs, line, column) { - return { - message: unknownArgMessage(argName, fieldName, typeName, suggestedArgs), - locations: [{ line, column }], - }; -} - -function unknownDirectiveArg( - argName, - directiveName, - suggestedArgs, - line, - column, -) { - return { - message: unknownDirectiveArgMessage(argName, directiveName, suggestedArgs), - locations: [{ line, column }], - }; -} - describe('Validate: Known argument names', () => { it('single arg is known', () => { expectValid(` @@ -124,7 +102,12 @@ describe('Validate: Known argument names', () => { { dog @skip(unless: true) } - `).to.deep.equal([unknownDirectiveArg('unless', 'skip', [], 3, 19)]); + `).to.deep.equal([ + { + message: 'Unknown argument "unless" on directive "@skip".', + locations: [{ line: 3, column: 19 }], + }, + ]); }); it('misspelled directive args are reported', () => { @@ -132,7 +115,13 @@ describe('Validate: Known argument names', () => { { dog @skip(iff: true) } - `).to.deep.equal([unknownDirectiveArg('iff', 'skip', ['if'], 3, 19)]); + `).to.deep.equal([ + { + message: + 'Unknown argument "iff" on directive "@skip". Did you mean "if"?', + locations: [{ line: 3, column: 19 }], + }, + ]); }); it('invalid arg name', () => { @@ -141,7 +130,11 @@ describe('Validate: Known argument names', () => { doesKnowCommand(unknown: true) } `).to.deep.equal([ - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 25), + { + message: + 'Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".', + locations: [{ line: 3, column: 25 }], + }, ]); }); @@ -151,7 +144,11 @@ describe('Validate: Known argument names', () => { doesKnowCommand(dogcommand: true) } `).to.deep.equal([ - unknownArg('dogcommand', 'doesKnowCommand', 'Dog', ['dogCommand'], 3, 25), + { + message: + 'Unknown argument "dogcommand" on field "doesKnowCommand" of type "Dog". Did you mean "dogCommand"?', + locations: [{ line: 3, column: 25 }], + }, ]); }); @@ -161,8 +158,16 @@ describe('Validate: Known argument names', () => { doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) } `).to.deep.equal([ - unknownArg('whoknows', 'doesKnowCommand', 'Dog', [], 3, 25), - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 3, 55), + { + message: + 'Unknown argument "whoknows" on field "doesKnowCommand" of type "Dog".', + locations: [{ line: 3, column: 25 }], + }, + { + message: + 'Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".', + locations: [{ line: 3, column: 55 }], + }, ]); }); @@ -181,8 +186,16 @@ describe('Validate: Known argument names', () => { } } `).to.deep.equal([ - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 4, 27), - unknownArg('unknown', 'doesKnowCommand', 'Dog', [], 9, 31), + { + message: + 'Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".', + locations: [{ line: 4, column: 27 }], + }, + { + message: + 'Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".', + locations: [{ line: 9, column: 31 }], + }, ]); }); @@ -204,7 +217,12 @@ describe('Validate: Known argument names', () => { } directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([unknownDirectiveArg('unknown', 'test', [], 3, 29)]); + `).to.deep.equal([ + { + message: 'Unknown argument "unknown" on directive "@test".', + locations: [{ line: 3, column: 29 }], + }, + ]); }); it('misspelled arg name is reported on directive defined inside SDL', () => { @@ -214,7 +232,13 @@ describe('Validate: Known argument names', () => { } directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([unknownDirectiveArg('agr', 'test', ['arg'], 3, 29)]); + `).to.deep.equal([ + { + message: + 'Unknown argument "agr" on directive "@test". Did you mean "arg"?', + locations: [{ line: 3, column: 29 }], + }, + ]); }); it('unknown arg on standard directive', () => { @@ -223,7 +247,10 @@ describe('Validate: Known argument names', () => { foo: String @deprecated(unknown: "") } `).to.deep.equal([ - unknownDirectiveArg('unknown', 'deprecated', [], 3, 35), + { + message: 'Unknown argument "unknown" on directive "@deprecated".', + locations: [{ line: 3, column: 35 }], + }, ]); }); @@ -234,7 +261,10 @@ describe('Validate: Known argument names', () => { } directive @deprecated(arg: String) on FIELD `).to.deep.equal([ - unknownDirectiveArg('reason', 'deprecated', [], 3, 35), + { + message: 'Unknown argument "reason" on directive "@deprecated".', + locations: [{ line: 3, column: 35 }], + }, ]); }); @@ -251,7 +281,12 @@ describe('Validate: Known argument names', () => { extend type Query @test(unknown: "") `, schema, - ).to.deep.equal([unknownDirectiveArg('unknown', 'test', [], 4, 36)]); + ).to.deep.equal([ + { + message: 'Unknown argument "unknown" on directive "@test".', + locations: [{ line: 4, column: 36 }], + }, + ]); }); it('unknown arg on directive used in schema extension', () => { @@ -267,7 +302,12 @@ describe('Validate: Known argument names', () => { extend type Query @test(unknown: "") `, schema, - ).to.deep.equal([unknownDirectiveArg('unknown', 'test', [], 2, 35)]); + ).to.deep.equal([ + { + message: 'Unknown argument "unknown" on directive "@test".', + locations: [{ line: 2, column: 35 }], + }, + ]); }); }); }); diff --git a/src/validation/__tests__/KnownDirectives-test.js b/src/validation/__tests__/KnownDirectives-test.js index 4cbed91f96..899715352a 100644 --- a/src/validation/__tests__/KnownDirectives-test.js +++ b/src/validation/__tests__/KnownDirectives-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - KnownDirectives, - unknownDirectiveMessage, - misplacedDirectiveMessage, -} from '../rules/KnownDirectives'; +import { KnownDirectives } from '../rules/KnownDirectives'; import { expectValidationErrors, expectSDLValidationErrors } from './harness'; @@ -28,20 +24,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function unknownDirective(directiveName, line, column) { - return { - message: unknownDirectiveMessage(directiveName), - locations: [{ line, column }], - }; -} - -function misplacedDirective(directiveName, placement, line, column) { - return { - message: misplacedDirectiveMessage(directiveName, placement), - locations: [{ line, column }], - }; -} - const schemaWithSDLDirectives = buildSchema(` directive @onSchema on SCHEMA directive @onScalar on SCALAR @@ -90,7 +72,12 @@ describe('Validate: Known directives', () => { name } } - `).to.deep.equal([unknownDirective('unknown', 3, 13)]); + `).to.deep.equal([ + { + message: 'Unknown directive "unknown".', + locations: [{ line: 3, column: 13 }], + }, + ]); }); it('with many unknown directives', () => { @@ -107,9 +94,18 @@ describe('Validate: Known directives', () => { } } `).to.deep.equal([ - unknownDirective('unknown', 3, 13), - unknownDirective('unknown', 6, 15), - unknownDirective('unknown', 8, 16), + { + message: 'Unknown directive "unknown".', + locations: [{ line: 3, column: 13 }], + }, + { + message: 'Unknown directive "unknown".', + locations: [{ line: 6, column: 15 }], + }, + { + message: 'Unknown directive "unknown".', + locations: [{ line: 8, column: 16 }], + }, ]); }); @@ -147,10 +143,22 @@ describe('Validate: Known directives', () => { someField } `).to.deep.equal([ - misplacedDirective('include', 'QUERY', 2, 32), - misplacedDirective('onQuery', 'FIELD', 3, 14), - misplacedDirective('onQuery', 'FRAGMENT_SPREAD', 4, 17), - misplacedDirective('onQuery', 'MUTATION', 7, 20), + { + message: 'Directive "include" may not be used on QUERY.', + locations: [{ line: 2, column: 32 }], + }, + { + message: 'Directive "onQuery" may not be used on FIELD.', + locations: [{ line: 3, column: 14 }], + }, + { + message: 'Directive "onQuery" may not be used on FRAGMENT_SPREAD.', + locations: [{ line: 4, column: 17 }], + }, + { + message: 'Directive "onQuery" may not be used on MUTATION.', + locations: [{ line: 7, column: 20 }], + }, ]); }); @@ -160,7 +168,10 @@ describe('Validate: Known directives', () => { name } `).to.deep.equal([ - misplacedDirective('onField', 'VARIABLE_DEFINITION', 2, 31), + { + message: 'Directive "onField" may not be used on VARIABLE_DEFINITION.', + locations: [{ line: 2, column: 31 }], + }, ]); }); @@ -235,7 +246,12 @@ describe('Validate: Known directives', () => { extend type Query @unknown `, schema, - ).to.deep.equal([unknownDirective('unknown', 2, 29)]); + ).to.deep.equal([ + { + message: 'Unknown directive "unknown".', + locations: [{ line: 2, column: 29 }], + }, + ]); }); it('with well placed directives', () => { @@ -314,35 +330,67 @@ describe('Validate: Known directives', () => { `, schemaWithSDLDirectives, ).to.deep.equal([ - misplacedDirective('onInterface', 'OBJECT', 2, 45), - misplacedDirective( - 'onInputFieldDefinition', - 'ARGUMENT_DEFINITION', - 3, - 32, - ), - misplacedDirective('onInputFieldDefinition', 'FIELD_DEFINITION', 3, 65), - misplacedDirective('onEnum', 'SCALAR', 6, 27), - misplacedDirective('onObject', 'INTERFACE', 8, 33), - misplacedDirective( - 'onInputFieldDefinition', - 'ARGUMENT_DEFINITION', - 9, - 32, - ), - misplacedDirective('onInputFieldDefinition', 'FIELD_DEFINITION', 9, 65), - misplacedDirective('onEnumValue', 'UNION', 12, 25), - misplacedDirective('onScalar', 'ENUM', 14, 23), - misplacedDirective('onUnion', 'ENUM_VALUE', 15, 22), - misplacedDirective('onEnum', 'INPUT_OBJECT', 18, 25), - misplacedDirective( - 'onArgumentDefinition', - 'INPUT_FIELD_DEFINITION', - 19, - 26, - ), - misplacedDirective('onObject', 'SCHEMA', 22, 18), - misplacedDirective('onObject', 'SCHEMA', 26, 25), + { + message: 'Directive "onInterface" may not be used on OBJECT.', + locations: [{ line: 2, column: 45 }], + }, + { + message: + 'Directive "onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.', + locations: [{ line: 3, column: 32 }], + }, + { + message: + 'Directive "onInputFieldDefinition" may not be used on FIELD_DEFINITION.', + locations: [{ line: 3, column: 65 }], + }, + { + message: 'Directive "onEnum" may not be used on SCALAR.', + locations: [{ line: 6, column: 27 }], + }, + { + message: 'Directive "onObject" may not be used on INTERFACE.', + locations: [{ line: 8, column: 33 }], + }, + { + message: + 'Directive "onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.', + locations: [{ line: 9, column: 32 }], + }, + { + message: + 'Directive "onInputFieldDefinition" may not be used on FIELD_DEFINITION.', + locations: [{ line: 9, column: 65 }], + }, + { + message: 'Directive "onEnumValue" may not be used on UNION.', + locations: [{ line: 12, column: 25 }], + }, + { + message: 'Directive "onScalar" may not be used on ENUM.', + locations: [{ line: 14, column: 23 }], + }, + { + message: 'Directive "onUnion" may not be used on ENUM_VALUE.', + locations: [{ line: 15, column: 22 }], + }, + { + message: 'Directive "onEnum" may not be used on INPUT_OBJECT.', + locations: [{ line: 18, column: 25 }], + }, + { + message: + 'Directive "onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION.', + locations: [{ line: 19, column: 26 }], + }, + { + message: 'Directive "onObject" may not be used on SCHEMA.', + locations: [{ line: 22, column: 18 }], + }, + { + message: 'Directive "onObject" may not be used on SCHEMA.', + locations: [{ line: 26, column: 25 }], + }, ]); }); }); diff --git a/src/validation/__tests__/KnownFragmentNames-test.js b/src/validation/__tests__/KnownFragmentNames-test.js index 0af503075e..aea9505c29 100644 --- a/src/validation/__tests__/KnownFragmentNames-test.js +++ b/src/validation/__tests__/KnownFragmentNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - KnownFragmentNames, - unknownFragmentMessage, -} from '../rules/KnownFragmentNames'; +import { KnownFragmentNames } from '../rules/KnownFragmentNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function unknownFragment(fragName, line, column) { - return { - message: unknownFragmentMessage(fragName), - locations: [{ line, column }], - }; -} - describe('Validate: Known fragment names', () => { it('known fragment names are valid', () => { expectValid(` @@ -66,9 +56,18 @@ describe('Validate: Known fragment names', () => { ...UnknownFragment3 } `).to.deep.equal([ - unknownFragment('UnknownFragment1', 4, 14), - unknownFragment('UnknownFragment2', 6, 16), - unknownFragment('UnknownFragment3', 12, 12), + { + message: 'Unknown fragment "UnknownFragment1".', + locations: [{ line: 4, column: 14 }], + }, + { + message: 'Unknown fragment "UnknownFragment2".', + locations: [{ line: 6, column: 16 }], + }, + { + message: 'Unknown fragment "UnknownFragment3".', + locations: [{ line: 12, column: 12 }], + }, ]); }); }); diff --git a/src/validation/__tests__/KnownTypeNames-test.js b/src/validation/__tests__/KnownTypeNames-test.js index 7d38236a18..0e3d8e0ffd 100644 --- a/src/validation/__tests__/KnownTypeNames-test.js +++ b/src/validation/__tests__/KnownTypeNames-test.js @@ -4,7 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { KnownTypeNames, unknownTypeMessage } from '../rules/KnownTypeNames'; +import { KnownTypeNames } from '../rules/KnownTypeNames'; import { expectValidationErrors, @@ -32,13 +32,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function unknownType(typeName, suggestedTypes, line, column) { - return { - message: unknownTypeMessage(typeName, suggestedTypes), - locations: [{ line, column }], - }; -} - describe('Validate: Known type names', () => { it('known type names are valid', () => { expectValid(` @@ -65,9 +58,18 @@ describe('Validate: Known type names', () => { name } `).to.deep.equal([ - unknownType('JumbledUpLetters', [], 2, 23), - unknownType('Badger', [], 5, 25), - unknownType('Peettt', ['Pet'], 8, 29), + { + message: 'Unknown type "JumbledUpLetters".', + locations: [{ line: 2, column: 23 }], + }, + { + message: 'Unknown type "Badger".', + locations: [{ line: 5, column: 25 }], + }, + { + message: 'Unknown type "Peettt". Did you mean "Pet"?', + locations: [{ line: 8, column: 29 }], + }, ]); }); @@ -79,9 +81,18 @@ describe('Validate: Known type names', () => { } `; expectErrorsWithSchema(schema, query).to.deep.equal([ - unknownType('ID', [], 2, 19), - unknownType('Float', [], 2, 31), - unknownType('Int', [], 2, 44), + { + message: 'Unknown type "ID".', + locations: [{ line: 2, column: 19 }], + }, + { + message: 'Unknown type "Float".', + locations: [{ line: 2, column: 31 }], + }, + { + message: 'Unknown type "Int".', + locations: [{ line: 2, column: 44 }], + }, ]); }); @@ -160,18 +171,54 @@ describe('Validate: Known type names', () => { subscription: N } `).to.deep.equal([ - unknownType('C', ['A', 'B'], 5, 36), - unknownType('D', ['ID', 'A', 'B'], 6, 16), - unknownType('E', ['A', 'B'], 6, 20), - unknownType('F', ['A', 'B'], 9, 27), - unknownType('G', ['A', 'B'], 9, 31), - unknownType('H', ['A', 'B'], 12, 16), - unknownType('I', ['ID', 'A', 'B'], 12, 20), - unknownType('J', ['A', 'B'], 16, 14), - unknownType('K', ['A', 'B'], 19, 37), - unknownType('L', ['A', 'B'], 22, 18), - unknownType('M', ['A', 'B'], 23, 21), - unknownType('N', ['A', 'B'], 24, 25), + { + message: 'Unknown type "C". Did you mean "A" or "B"?', + locations: [{ line: 5, column: 36 }], + }, + { + message: 'Unknown type "D". Did you mean "ID", "A", or "B"?', + locations: [{ line: 6, column: 16 }], + }, + { + message: 'Unknown type "E". Did you mean "A" or "B"?', + locations: [{ line: 6, column: 20 }], + }, + { + message: 'Unknown type "F". Did you mean "A" or "B"?', + locations: [{ line: 9, column: 27 }], + }, + { + message: 'Unknown type "G". Did you mean "A" or "B"?', + locations: [{ line: 9, column: 31 }], + }, + { + message: 'Unknown type "H". Did you mean "A" or "B"?', + locations: [{ line: 12, column: 16 }], + }, + { + message: 'Unknown type "I". Did you mean "ID", "A", or "B"?', + locations: [{ line: 12, column: 20 }], + }, + { + message: 'Unknown type "J". Did you mean "A" or "B"?', + locations: [{ line: 16, column: 14 }], + }, + { + message: 'Unknown type "K". Did you mean "A" or "B"?', + locations: [{ line: 19, column: 37 }], + }, + { + message: 'Unknown type "L". Did you mean "A" or "B"?', + locations: [{ line: 22, column: 18 }], + }, + { + message: 'Unknown type "M". Did you mean "A" or "B"?', + locations: [{ line: 23, column: 21 }], + }, + { + message: 'Unknown type "N". Did you mean "A" or "B"?', + locations: [{ line: 24, column: 25 }], + }, ]); }); @@ -184,7 +231,12 @@ describe('Validate: Known type names', () => { type Query { foo: Foo } - `).to.deep.equal([unknownType('Foo', [], 7, 16)]); + `).to.deep.equal([ + { + message: 'Unknown type "Foo".', + locations: [{ line: 7, column: 16 }], + }, + ]); }); it('reference standard scalars inside extension document', () => { @@ -249,18 +301,54 @@ describe('Validate: Known type names', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - unknownType('C', ['A', 'B'], 4, 36), - unknownType('D', ['ID', 'A', 'B'], 5, 16), - unknownType('E', ['A', 'B'], 5, 20), - unknownType('F', ['A', 'B'], 8, 27), - unknownType('G', ['A', 'B'], 8, 31), - unknownType('H', ['A', 'B'], 11, 16), - unknownType('I', ['ID', 'A', 'B'], 11, 20), - unknownType('J', ['A', 'B'], 15, 14), - unknownType('K', ['A', 'B'], 18, 37), - unknownType('L', ['A', 'B'], 21, 18), - unknownType('M', ['A', 'B'], 22, 21), - unknownType('N', ['A', 'B'], 23, 25), + { + message: 'Unknown type "C". Did you mean "A" or "B"?', + locations: [{ line: 4, column: 36 }], + }, + { + message: 'Unknown type "D". Did you mean "ID", "A", or "B"?', + locations: [{ line: 5, column: 16 }], + }, + { + message: 'Unknown type "E". Did you mean "A" or "B"?', + locations: [{ line: 5, column: 20 }], + }, + { + message: 'Unknown type "F". Did you mean "A" or "B"?', + locations: [{ line: 8, column: 27 }], + }, + { + message: 'Unknown type "G". Did you mean "A" or "B"?', + locations: [{ line: 8, column: 31 }], + }, + { + message: 'Unknown type "H". Did you mean "A" or "B"?', + locations: [{ line: 11, column: 16 }], + }, + { + message: 'Unknown type "I". Did you mean "ID", "A", or "B"?', + locations: [{ line: 11, column: 20 }], + }, + { + message: 'Unknown type "J". Did you mean "A" or "B"?', + locations: [{ line: 15, column: 14 }], + }, + { + message: 'Unknown type "K". Did you mean "A" or "B"?', + locations: [{ line: 18, column: 37 }], + }, + { + message: 'Unknown type "L". Did you mean "A" or "B"?', + locations: [{ line: 21, column: 18 }], + }, + { + message: 'Unknown type "M". Did you mean "A" or "B"?', + locations: [{ line: 22, column: 21 }], + }, + { + message: 'Unknown type "N". Did you mean "A" or "B"?', + locations: [{ line: 23, column: 25 }], + }, ]); }); }); diff --git a/src/validation/__tests__/LoneAnonymousOperation-test.js b/src/validation/__tests__/LoneAnonymousOperation-test.js index ef39e4a2c6..013e035358 100644 --- a/src/validation/__tests__/LoneAnonymousOperation-test.js +++ b/src/validation/__tests__/LoneAnonymousOperation-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - LoneAnonymousOperation, - anonOperationNotAloneMessage, -} from '../rules/LoneAnonymousOperation'; +import { LoneAnonymousOperation } from '../rules/LoneAnonymousOperation'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function anonOperationNotAlone(line, column) { - return { - message: anonOperationNotAloneMessage(), - locations: [{ line, column }], - }; -} - describe('Validate: Anonymous operation must be alone', () => { it('no operations', () => { expectValid(` @@ -73,8 +63,14 @@ describe('Validate: Anonymous operation must be alone', () => { fieldB } `).to.deep.equal([ - anonOperationNotAlone(2, 7), - anonOperationNotAlone(5, 7), + { + message: 'This anonymous operation must be the only defined operation.', + locations: [{ line: 2, column: 7 }], + }, + { + message: 'This anonymous operation must be the only defined operation.', + locations: [{ line: 5, column: 7 }], + }, ]); }); @@ -86,7 +82,12 @@ describe('Validate: Anonymous operation must be alone', () => { mutation Foo { fieldB } - `).to.deep.equal([anonOperationNotAlone(2, 7)]); + `).to.deep.equal([ + { + message: 'This anonymous operation must be the only defined operation.', + locations: [{ line: 2, column: 7 }], + }, + ]); }); it('anon operation with a subscription', () => { @@ -97,6 +98,11 @@ describe('Validate: Anonymous operation must be alone', () => { subscription Foo { fieldB } - `).to.deep.equal([anonOperationNotAlone(2, 7)]); + `).to.deep.equal([ + { + message: 'This anonymous operation must be the only defined operation.', + locations: [{ line: 2, column: 7 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/LoneSchemaDefinition-test.js b/src/validation/__tests__/LoneSchemaDefinition-test.js index 6384f58f85..621e90cf9c 100644 --- a/src/validation/__tests__/LoneSchemaDefinition-test.js +++ b/src/validation/__tests__/LoneSchemaDefinition-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - LoneSchemaDefinition, - schemaDefinitionNotAloneMessage, - canNotDefineSchemaWithinExtensionMessage, -} from '../rules/LoneSchemaDefinition'; +import { LoneSchemaDefinition } from '../rules/LoneSchemaDefinition'; import { expectSDLValidationErrors } from './harness'; @@ -20,20 +16,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function schemaDefinitionNotAlone(line, column) { - return { - message: schemaDefinitionNotAloneMessage(), - locations: [{ line, column }], - }; -} - -function canNotDefineSchemaWithinExtension(line, column) { - return { - message: canNotDefineSchemaWithinExtensionMessage(), - locations: [{ line, column }], - }; -} - describe('Validate: Schema definition should be alone', () => { it('no schema', () => { expectValidSDL(` @@ -73,8 +55,14 @@ describe('Validate: Schema definition should be alone', () => { subscription: Foo } `).to.deep.equal([ - schemaDefinitionNotAlone(10, 7), - schemaDefinitionNotAlone(14, 7), + { + message: 'Must provide only one schema definition.', + locations: [{ line: 10, column: 7 }], + }, + { + message: 'Must provide only one schema definition.', + locations: [{ line: 14, column: 7 }], + }, ]); }); @@ -113,7 +101,12 @@ describe('Validate: Schema definition should be alone', () => { } `, schema, - ).to.deep.equal([canNotDefineSchemaWithinExtension(2, 9)]); + ).to.deep.equal([ + { + message: 'Cannot define a new schema within a schema extension.', + locations: [{ line: 2, column: 9 }], + }, + ]); }); it('redefine implicit schema in schema extension', () => { @@ -134,7 +127,12 @@ describe('Validate: Schema definition should be alone', () => { } `, schema, - ).to.deep.equal([canNotDefineSchemaWithinExtension(2, 9)]); + ).to.deep.equal([ + { + message: 'Cannot define a new schema within a schema extension.', + locations: [{ line: 2, column: 9 }], + }, + ]); }); it('extend schema in schema extension', () => { diff --git a/src/validation/__tests__/NoFragmentCycles-test.js b/src/validation/__tests__/NoFragmentCycles-test.js index 6a40a49eaf..55ad865944 100644 --- a/src/validation/__tests__/NoFragmentCycles-test.js +++ b/src/validation/__tests__/NoFragmentCycles-test.js @@ -2,7 +2,7 @@ import { describe, it } from 'mocha'; -import { NoFragmentCycles, cycleErrorMessage } from '../rules/NoFragmentCycles'; +import { NoFragmentCycles } from '../rules/NoFragmentCycles'; import { expectValidationErrors } from './harness'; @@ -64,7 +64,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Human { relatives { ...fragA } }, `).to.deep.equal([ { - message: cycleErrorMessage('fragA', []), + message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 2, column: 45 }], }, ]); @@ -75,7 +75,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Dog { ...fragA } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', []), + message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 2, column: 31 }], }, ]); @@ -90,7 +90,7 @@ describe('Validate: No circular fragment spreads', () => { } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', []), + message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 4, column: 11 }], }, ]); @@ -102,7 +102,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragB on Dog { ...fragA } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', ['fragB']), + message: 'Cannot spread fragment "fragA" within itself via fragB.', locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], }, ]); @@ -114,7 +114,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Dog { ...fragB } `).to.deep.equal([ { - message: cycleErrorMessage('fragB', ['fragA']), + message: 'Cannot spread fragment "fragB" within itself via fragA.', locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], }, ]); @@ -134,7 +134,7 @@ describe('Validate: No circular fragment spreads', () => { } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', ['fragB']), + message: 'Cannot spread fragment "fragA" within itself via fragB.', locations: [{ line: 4, column: 11 }, { line: 9, column: 11 }], }, ]); @@ -152,12 +152,8 @@ describe('Validate: No circular fragment spreads', () => { fragment fragP on Dog { ...fragA, ...fragX } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', [ - 'fragB', - 'fragC', - 'fragO', - 'fragP', - ]), + message: + 'Cannot spread fragment "fragA" within itself via fragB, fragC, fragO, fragP.', locations: [ { line: 2, column: 31 }, { line: 3, column: 31 }, @@ -167,12 +163,8 @@ describe('Validate: No circular fragment spreads', () => { ], }, { - message: cycleErrorMessage('fragO', [ - 'fragP', - 'fragX', - 'fragY', - 'fragZ', - ]), + message: + 'Cannot spread fragment "fragO" within itself via fragP, fragX, fragY, fragZ.', locations: [ { line: 8, column: 31 }, { line: 9, column: 41 }, @@ -191,11 +183,11 @@ describe('Validate: No circular fragment spreads', () => { fragment fragC on Dog { ...fragA } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', ['fragB']), + message: 'Cannot spread fragment "fragA" within itself via fragB.', locations: [{ line: 2, column: 31 }, { line: 3, column: 31 }], }, { - message: cycleErrorMessage('fragA', ['fragC']), + message: 'Cannot spread fragment "fragA" within itself via fragC.', locations: [{ line: 2, column: 41 }, { line: 4, column: 31 }], }, ]); @@ -208,11 +200,11 @@ describe('Validate: No circular fragment spreads', () => { fragment fragC on Dog { ...fragA, ...fragB } `).to.deep.equal([ { - message: cycleErrorMessage('fragA', ['fragC']), + message: 'Cannot spread fragment "fragA" within itself via fragC.', locations: [{ line: 2, column: 31 }, { line: 4, column: 31 }], }, { - message: cycleErrorMessage('fragC', ['fragB']), + message: 'Cannot spread fragment "fragC" within itself via fragB.', locations: [{ line: 4, column: 41 }, { line: 3, column: 31 }], }, ]); @@ -225,11 +217,12 @@ describe('Validate: No circular fragment spreads', () => { fragment fragC on Dog { ...fragA, ...fragB } `).to.deep.equal([ { - message: cycleErrorMessage('fragB', []), + message: 'Cannot spread fragment "fragB" within itself.', locations: [{ line: 3, column: 31 }], }, { - message: cycleErrorMessage('fragA', ['fragB', 'fragC']), + message: + 'Cannot spread fragment "fragA" within itself via fragB, fragC.', locations: [ { line: 2, column: 31 }, { line: 3, column: 41 }, @@ -237,7 +230,7 @@ describe('Validate: No circular fragment spreads', () => { ], }, { - message: cycleErrorMessage('fragB', ['fragC']), + message: 'Cannot spread fragment "fragB" within itself via fragC.', locations: [{ line: 3, column: 41 }, { line: 4, column: 41 }], }, ]); diff --git a/src/validation/__tests__/NoUndefinedVariables-test.js b/src/validation/__tests__/NoUndefinedVariables-test.js index b3b3ec7ac7..88a2e7995f 100644 --- a/src/validation/__tests__/NoUndefinedVariables-test.js +++ b/src/validation/__tests__/NoUndefinedVariables-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - NoUndefinedVariables, - undefinedVarMessage, -} from '../rules/NoUndefinedVariables'; +import { NoUndefinedVariables } from '../rules/NoUndefinedVariables'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function undefVar(varName, l1, c1, opName, l2, c2) { - return { - message: undefinedVarMessage(varName, opName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: No undefined variables', () => { it('all variables defined', () => { expectValid(` @@ -131,7 +121,12 @@ describe('Validate: No undefined variables', () => { query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } - `).to.deep.equal([undefVar('d', 3, 39, 'Foo', 2, 7)]); + `).to.deep.equal([ + { + message: 'Variable "$d" is not defined by operation "Foo".', + locations: [{ line: 3, column: 39 }, { line: 2, column: 7 }], + }, + ]); }); it('variable not defined by un-named query', () => { @@ -139,7 +134,12 @@ describe('Validate: No undefined variables', () => { { field(a: $a) } - `).to.deep.equal([undefVar('a', 3, 18, '', 2, 7)]); + `).to.deep.equal([ + { + message: 'Variable "$a" is not defined.', + locations: [{ line: 3, column: 18 }, { line: 2, column: 7 }], + }, + ]); }); it('multiple variables not defined', () => { @@ -148,8 +148,14 @@ describe('Validate: No undefined variables', () => { field(a: $a, b: $b, c: $c) } `).to.deep.equal([ - undefVar('a', 3, 18, 'Foo', 2, 7), - undefVar('c', 3, 32, 'Foo', 2, 7), + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 3, column: 18 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$c" is not defined by operation "Foo".', + locations: [{ line: 3, column: 32 }, { line: 2, column: 7 }], + }, ]); }); @@ -161,7 +167,12 @@ describe('Validate: No undefined variables', () => { fragment FragA on Type { field(a: $a) } - `).to.deep.equal([undefVar('a', 6, 18, '', 2, 7)]); + `).to.deep.equal([ + { + message: 'Variable "$a" is not defined.', + locations: [{ line: 6, column: 18 }, { line: 2, column: 7 }], + }, + ]); }); it('variable in fragment not defined by operation', () => { @@ -182,7 +193,12 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `).to.deep.equal([undefVar('c', 16, 18, 'Foo', 2, 7)]); + `).to.deep.equal([ + { + message: 'Variable "$c" is not defined by operation "Foo".', + locations: [{ line: 16, column: 18 }, { line: 2, column: 7 }], + }, + ]); }); it('multiple variables in fragments not defined', () => { @@ -204,8 +220,14 @@ describe('Validate: No undefined variables', () => { field(c: $c) } `).to.deep.equal([ - undefVar('a', 6, 18, 'Foo', 2, 7), - undefVar('c', 16, 18, 'Foo', 2, 7), + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 6, column: 18 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$c" is not defined by operation "Foo".', + locations: [{ line: 16, column: 18 }, { line: 2, column: 7 }], + }, ]); }); @@ -221,8 +243,14 @@ describe('Validate: No undefined variables', () => { field(a: $a, b: $b) } `).to.deep.equal([ - undefVar('b', 9, 25, 'Foo', 2, 7), - undefVar('b', 9, 25, 'Bar', 5, 7), + { + message: 'Variable "$b" is not defined by operation "Foo".', + locations: [{ line: 9, column: 25 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$b" is not defined by operation "Bar".', + locations: [{ line: 9, column: 25 }, { line: 5, column: 7 }], + }, ]); }); @@ -238,8 +266,14 @@ describe('Validate: No undefined variables', () => { field(a: $a, b: $b) } `).to.deep.equal([ - undefVar('a', 9, 18, 'Foo', 2, 7), - undefVar('b', 9, 25, 'Bar', 5, 7), + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 9, column: 18 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$b" is not defined by operation "Bar".', + locations: [{ line: 9, column: 25 }, { line: 5, column: 7 }], + }, ]); }); @@ -258,8 +292,14 @@ describe('Validate: No undefined variables', () => { field(b: $b) } `).to.deep.equal([ - undefVar('a', 9, 18, 'Foo', 2, 7), - undefVar('b', 12, 18, 'Bar', 5, 7), + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 9, column: 18 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$b" is not defined by operation "Bar".', + locations: [{ line: 12, column: 18 }, { line: 5, column: 7 }], + }, ]); }); @@ -280,12 +320,30 @@ describe('Validate: No undefined variables', () => { field2(c: $c) } `).to.deep.equal([ - undefVar('a', 9, 19, 'Foo', 2, 7), - undefVar('a', 11, 19, 'Foo', 2, 7), - undefVar('c', 14, 19, 'Foo', 2, 7), - undefVar('b', 9, 26, 'Bar', 5, 7), - undefVar('b', 11, 26, 'Bar', 5, 7), - undefVar('c', 14, 19, 'Bar', 5, 7), + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 9, column: 19 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$a" is not defined by operation "Foo".', + locations: [{ line: 11, column: 19 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$c" is not defined by operation "Foo".', + locations: [{ line: 14, column: 19 }, { line: 2, column: 7 }], + }, + { + message: 'Variable "$b" is not defined by operation "Bar".', + locations: [{ line: 9, column: 26 }, { line: 5, column: 7 }], + }, + { + message: 'Variable "$b" is not defined by operation "Bar".', + locations: [{ line: 11, column: 26 }, { line: 5, column: 7 }], + }, + { + message: 'Variable "$c" is not defined by operation "Bar".', + locations: [{ line: 14, column: 19 }, { line: 5, column: 7 }], + }, ]); }); }); diff --git a/src/validation/__tests__/NoUnusedFragments-test.js b/src/validation/__tests__/NoUnusedFragments-test.js index cafc50e678..20bf0ee4ac 100644 --- a/src/validation/__tests__/NoUnusedFragments-test.js +++ b/src/validation/__tests__/NoUnusedFragments-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - NoUnusedFragments, - unusedFragMessage, -} from '../rules/NoUnusedFragments'; +import { NoUnusedFragments } from '../rules/NoUnusedFragments'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function unusedFrag(fragName, line, column) { - return { - message: unusedFragMessage(fragName), - locations: [{ line, column }], - }; -} - describe('Validate: No unused fragments', () => { it('all fragment names are used', () => { expectValid(` @@ -102,8 +92,14 @@ describe('Validate: No unused fragments', () => { name } `).to.deep.equal([ - unusedFrag('Unused1', 22, 7), - unusedFrag('Unused2', 25, 7), + { + message: 'Fragment "Unused1" is never used.', + locations: [{ line: 22, column: 7 }], + }, + { + message: 'Fragment "Unused2" is never used.', + locations: [{ line: 25, column: 7 }], + }, ]); }); @@ -138,8 +134,14 @@ describe('Validate: No unused fragments', () => { ...Unused1 } `).to.deep.equal([ - unusedFrag('Unused1', 22, 7), - unusedFrag('Unused2', 26, 7), + { + message: 'Fragment "Unused1" is never used.', + locations: [{ line: 22, column: 7 }], + }, + { + message: 'Fragment "Unused2" is never used.', + locations: [{ line: 26, column: 7 }], + }, ]); }); @@ -153,6 +155,11 @@ describe('Validate: No unused fragments', () => { fragment foo on Human { name } - `).to.deep.equal([unusedFrag('foo', 7, 7)]); + `).to.deep.equal([ + { + message: 'Fragment "foo" is never used.', + locations: [{ line: 7, column: 7 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/NoUnusedVariables-test.js b/src/validation/__tests__/NoUnusedVariables-test.js index 29ccbd8e26..ac4530c7f1 100644 --- a/src/validation/__tests__/NoUnusedVariables-test.js +++ b/src/validation/__tests__/NoUnusedVariables-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - NoUnusedVariables, - unusedVariableMessage, -} from '../rules/NoUnusedVariables'; +import { NoUnusedVariables } from '../rules/NoUnusedVariables'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function unusedVar(varName, opName, line, column) { - return { - message: unusedVariableMessage(varName, opName), - locations: [{ line, column }], - }; -} - describe('Validate: No unused variables', () => { it('uses all variables', () => { expectValid(` @@ -117,7 +107,12 @@ describe('Validate: No unused variables', () => { query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } - `).to.deep.equal([unusedVar('c', null, 2, 38)]); + `).to.deep.equal([ + { + message: 'Variable "$c" is never used.', + locations: [{ line: 2, column: 38 }], + }, + ]); }); it('multiple variables not used', () => { @@ -126,8 +121,14 @@ describe('Validate: No unused variables', () => { field(b: $b) } `).to.deep.equal([ - unusedVar('a', 'Foo', 2, 17), - unusedVar('c', 'Foo', 2, 41), + { + message: 'Variable "$a" is never used in operation "Foo".', + locations: [{ line: 2, column: 17 }], + }, + { + message: 'Variable "$c" is never used in operation "Foo".', + locations: [{ line: 2, column: 41 }], + }, ]); }); @@ -149,7 +150,12 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field } - `).to.deep.equal([unusedVar('c', 'Foo', 2, 41)]); + `).to.deep.equal([ + { + message: 'Variable "$c" is never used in operation "Foo".', + locations: [{ line: 2, column: 41 }], + }, + ]); }); it('multiple variables not used in fragments', () => { @@ -171,8 +177,14 @@ describe('Validate: No unused variables', () => { field } `).to.deep.equal([ - unusedVar('a', 'Foo', 2, 17), - unusedVar('c', 'Foo', 2, 41), + { + message: 'Variable "$a" is never used in operation "Foo".', + locations: [{ line: 2, column: 17 }], + }, + { + message: 'Variable "$c" is never used in operation "Foo".', + locations: [{ line: 2, column: 41 }], + }, ]); }); @@ -187,7 +199,12 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `).to.deep.equal([unusedVar('b', 'Foo', 2, 17)]); + `).to.deep.equal([ + { + message: 'Variable "$b" is never used in operation "Foo".', + locations: [{ line: 2, column: 17 }], + }, + ]); }); it('variable not used by fragment used by other operation', () => { @@ -205,8 +222,14 @@ describe('Validate: No unused variables', () => { field(b: $b) } `).to.deep.equal([ - unusedVar('b', 'Foo', 2, 17), - unusedVar('a', 'Bar', 5, 17), + { + message: 'Variable "$b" is never used in operation "Foo".', + locations: [{ line: 2, column: 17 }], + }, + { + message: 'Variable "$a" is never used in operation "Bar".', + locations: [{ line: 5, column: 17 }], + }, ]); }); }); diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js b/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js index c608b992ec..cd259ef001 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js +++ b/src/validation/__tests__/OverlappingFieldsCanBeMerged-test.js @@ -1,14 +1,10 @@ // @flow strict -import { expect } from 'chai'; import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - OverlappingFieldsCanBeMerged, - fieldsConflictMessage, -} from '../rules/OverlappingFieldsCanBeMerged'; +import { OverlappingFieldsCanBeMerged } from '../rules/OverlappingFieldsCanBeMerged'; import { expectValidationErrors, @@ -110,10 +106,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'fido', - 'name and nickname are different fields', - ), + message: + 'Fields "fido" conflict because name and nickname are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], }, ]); @@ -142,10 +136,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'name', - 'nickname and name are different fields', - ), + message: + 'Fields "name" conflict because nickname and name are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], }, ]); @@ -159,10 +151,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), + message: + 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], }, ]); @@ -176,10 +166,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), + message: + 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], }, ]); @@ -193,10 +181,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'doesKnowCommand', - 'they have differing arguments', - ), + message: + 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 3, column: 9 }, { line: 4, column: 9 }], }, ]); @@ -231,7 +217,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('x', 'a and b are different fields'), + message: + 'Fields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 7, column: 9 }, { line: 10, column: 9 }], }, ]); @@ -262,15 +249,18 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('x', 'a and b are different fields'), + message: + 'Fields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 18, column: 9 }, { line: 21, column: 9 }], }, { - message: fieldsConflictMessage('x', 'c and a are different fields'), + message: + 'Fields "x" conflict because c and a are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 14, column: 11 }, { line: 18, column: 9 }], }, { - message: fieldsConflictMessage('x', 'c and b are different fields'), + message: + 'Fields "x" conflict because c and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 14, column: 11 }, { line: 21, column: 9 }], }, ]); @@ -288,9 +278,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ]), + message: + 'Fields "field" conflict because subfields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 3, column: 9 }, { line: 4, column: 11 }, @@ -315,10 +304,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ['y', 'c and d are different fields'], - ]), + message: + 'Fields "field" conflict because subfields "x" conflict because a and b are different fields and subfields "y" conflict because c and d are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 3, column: 9 }, { line: 4, column: 11 }, @@ -347,9 +334,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('field', [ - ['deepField', [['x', 'a and b are different fields']]], - ]), + message: + 'Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 3, column: 9 }, { line: 4, column: 11 }, @@ -381,9 +367,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('deepField', [ - ['x', 'a and b are different fields'], - ]), + message: + 'Fields "deepField" conflict because subfields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 4, column: 11 }, { line: 5, column: 13 }, @@ -421,9 +406,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('deeperField', [ - ['x', 'a and b are different fields'], - ]), + message: + 'Fields "deeperField" conflict because subfields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 12, column: 11 }, { line: 13, column: 13 }, @@ -460,10 +444,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage('field', [ - ['x', 'a and b are different fields'], - ['y', 'c and d are different fields'], - ]), + message: + 'Fields "field" conflict because subfields "x" conflict because a and b are different fields and subfields "y" conflict because c and d are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 3, column: 9 }, { line: 11, column: 9 }, @@ -576,10 +558,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types Int and String!', - ), + message: + 'Fields "scalar" conflict because they return conflicting types Int and String!. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], }, ]); @@ -627,10 +607,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types Int and String', - ), + message: + 'Fields "scalar" conflict because they return conflicting types Int and String. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], }, ]); @@ -685,9 +663,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage('other', [ - ['scalar', 'scalar and unrelatedField are different fields'], - ]), + message: + 'Fields "other" conflict because subfields "scalar" conflict because scalar and unrelatedField are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 31, column: 13 }, { line: 39, column: 13 }, @@ -715,10 +692,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'scalar', - 'they return conflicting types String! and String', - ), + message: + 'Fields "scalar" conflict because they return conflicting types String! and String. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 5, column: 17 }, { line: 8, column: 17 }], }, ]); @@ -745,10 +720,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'box', - 'they return conflicting types [StringBox] and StringBox', - ), + message: + 'Fields "box" conflict because they return conflicting types [StringBox] and StringBox. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 5, column: 17 }, { line: 10, column: 17 }], }, ]); @@ -773,10 +746,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'box', - 'they return conflicting types StringBox and [StringBox]', - ), + message: + 'Fields "box" conflict because they return conflicting types StringBox and [StringBox]. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 5, column: 17 }, { line: 10, column: 17 }], }, ]); @@ -804,10 +775,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage( - 'val', - 'scalar and unrelatedField are different fields', - ), + message: + 'Fields "val" conflict because scalar and unrelatedField are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 6, column: 19 }, { line: 7, column: 19 }], }, ]); @@ -834,9 +803,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage('box', [ - ['scalar', 'they return conflicting types String and Int'], - ]), + message: + 'Fields "box" conflict because subfields "scalar" conflict because they return conflicting types String and Int. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 5, column: 17 }, { line: 6, column: 19 }, @@ -922,9 +890,8 @@ describe('Validate: Overlapping fields can be merged', () => { `, ).to.deep.equal([ { - message: fieldsConflictMessage('edges', [ - ['node', [['id', 'name and id are different fields']]], - ]), + message: + 'Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because name and id are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [ { line: 5, column: 15 }, { line: 6, column: 17 }, @@ -955,15 +922,6 @@ describe('Validate: Overlapping fields can be merged', () => { ); }); - it('error message contains hint for alias conflict', () => { - // The error template should end with a hint for the user to try using - // different aliases. - const error = fieldsConflictMessage('x', 'a and b are different fields'); - expect(error).to.equal( - 'Fields "x" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.', - ); - }); - it('works for field names that are JS keywords', () => { const schemaWithKeywords = buildSchema(` type Foo { @@ -1017,10 +975,8 @@ describe('Validate: Overlapping fields can be merged', () => { } `).to.deep.equal([ { - message: fieldsConflictMessage( - 'fido', - 'name and nickname are different fields', - ), + message: + 'Fields "fido" conflict because name and nickname are different fields. Use different aliases on the fields to fetch both if this was intentional.', locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], }, ]); diff --git a/src/validation/__tests__/PossibleFragmentSpreads-test.js b/src/validation/__tests__/PossibleFragmentSpreads-test.js index e9dda2ffcf..2ee75b87b3 100644 --- a/src/validation/__tests__/PossibleFragmentSpreads-test.js +++ b/src/validation/__tests__/PossibleFragmentSpreads-test.js @@ -2,11 +2,7 @@ import { describe, it } from 'mocha'; -import { - PossibleFragmentSpreads, - typeIncompatibleSpreadMessage, - typeIncompatibleAnonSpreadMessage, -} from '../rules/PossibleFragmentSpreads'; +import { PossibleFragmentSpreads } from '../rules/PossibleFragmentSpreads'; import { expectValidationErrors } from './harness'; @@ -18,20 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function error(fragName, parentType, fragType, line, column) { - return { - message: typeIncompatibleSpreadMessage(fragName, parentType, fragType), - locations: [{ line, column }], - }; -} - -function errorAnon(parentType, fragType, line, column) { - return { - message: typeIncompatibleAnonSpreadMessage(parentType, fragType), - locations: [{ line, column }], - }; -} - describe('Validate: Possible fragment spreads', () => { it('of the same object', () => { expectValid(` @@ -119,7 +101,13 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `).to.deep.equal([error('dogFragment', 'Cat', 'Dog', 2, 51)]); + `).to.deep.equal([ + { + message: + 'Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog".', + locations: [{ line: 2, column: 51 }], + }, + ]); }); it('different object into object in inline fragment', () => { @@ -127,28 +115,52 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } - `).to.deep.equal([errorAnon('Cat', 'Dog', 3, 9)]); + `).to.deep.equal([ + { + message: + 'Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog".', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('object into not implementing interface', () => { expectErrors(` fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } - `).to.deep.equal([error('humanFragment', 'Pet', 'Human', 2, 54)]); + `).to.deep.equal([ + { + message: + 'Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human".', + locations: [{ line: 2, column: 54 }], + }, + ]); }); it('object into not containing union', () => { expectErrors(` fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } - `).to.deep.equal([error('humanFragment', 'CatOrDog', 'Human', 2, 55)]); + `).to.deep.equal([ + { + message: + 'Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human".', + locations: [{ line: 2, column: 55 }], + }, + ]); }); it('union into not contained object', () => { expectErrors(` fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `).to.deep.equal([error('catOrDogFragment', 'Human', 'CatOrDog', 2, 52)]); + `).to.deep.equal([ + { + message: + 'Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog".', + locations: [{ line: 2, column: 52 }], + }, + ]); }); it('union into non overlapping interface', () => { @@ -156,7 +168,11 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } `).to.deep.equal([ - error('humanOrAlienFragment', 'Pet', 'HumanOrAlien', 2, 53), + { + message: + 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien".', + locations: [{ line: 2, column: 53 }], + }, ]); }); @@ -165,7 +181,11 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } `).to.deep.equal([ - error('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', 2, 54), + { + message: + 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien".', + locations: [{ line: 2, column: 54 }], + }, ]); }); @@ -174,7 +194,11 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } `).to.deep.equal([ - error('intelligentFragment', 'Cat', 'Intelligent', 2, 54), + { + message: + 'Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent".', + locations: [{ line: 2, column: 54 }], + }, ]); }); @@ -185,7 +209,11 @@ describe('Validate: Possible fragment spreads', () => { } fragment intelligentFragment on Intelligent { iq } `).to.deep.equal([ - error('intelligentFragment', 'Pet', 'Intelligent', 3, 9), + { + message: + 'Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', + locations: [{ line: 3, column: 9 }], + }, ]); }); @@ -194,13 +222,25 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } - `).to.deep.equal([errorAnon('Pet', 'Intelligent', 3, 9)]); + `).to.deep.equal([ + { + message: + 'Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('interface into non overlapping union', () => { expectErrors(` fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } - `).to.deep.equal([error('petFragment', 'HumanOrAlien', 'Pet', 2, 62)]); + `).to.deep.equal([ + { + message: + 'Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet".', + locations: [{ line: 2, column: 62 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/PossibleTypeExtensions-test.js b/src/validation/__tests__/PossibleTypeExtensions-test.js index a0c89f8c6c..45f6b2039e 100644 --- a/src/validation/__tests__/PossibleTypeExtensions-test.js +++ b/src/validation/__tests__/PossibleTypeExtensions-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - PossibleTypeExtensions, - extendingUnknownTypeMessage, - extendingDifferentTypeKindMessage, -} from '../rules/PossibleTypeExtensions'; +import { PossibleTypeExtensions } from '../rules/PossibleTypeExtensions'; import { expectSDLValidationErrors } from './harness'; @@ -20,23 +16,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function extendingUnknownType(typeName, suggestedTypes, line, column) { - return { - message: extendingUnknownTypeMessage(typeName, suggestedTypes), - locations: [{ line, column }], - }; -} - -function extendingDifferentTypeKind(typeName, kind, l1, c1, l2, c2) { - const message = extendingDifferentTypeKindMessage(typeName, kind); - const locations = [{ line: l1, column: c1 }]; - - if (l2 !== undefined && c2 !== undefined) { - locations.push({ line: l2, column: c2 }); - } - return { message, locations }; -} - describe('Validate: Possible type extensions', () => { it('no extensions', () => { expectValidSDL(` @@ -93,6 +72,9 @@ describe('Validate: Possible type extensions', () => { }); it('extending unknown type', () => { + const message = + 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?'; + expectSDLErrors(` type Known @@ -103,16 +85,18 @@ describe('Validate: Possible type extensions', () => { extend enum Unknown @dummy extend input Unknown @dummy `).to.deep.equal([ - extendingUnknownType('Unknown', ['Known'], 4, 21), - extendingUnknownType('Unknown', ['Known'], 5, 19), - extendingUnknownType('Unknown', ['Known'], 6, 24), - extendingUnknownType('Unknown', ['Known'], 7, 20), - extendingUnknownType('Unknown', ['Known'], 8, 19), - extendingUnknownType('Unknown', ['Known'], 9, 20), + { message, locations: [{ line: 4, column: 21 }] }, + { message, locations: [{ line: 5, column: 19 }] }, + { message, locations: [{ line: 6, column: 24 }] }, + { message, locations: [{ line: 7, column: 20 }] }, + { message, locations: [{ line: 8, column: 19 }] }, + { message, locations: [{ line: 9, column: 20 }] }, ]); }); it('does not consider non-type definitions', () => { + const message = 'Cannot extend type "Foo" because it is not defined.'; + expectSDLErrors(` query Foo { __typename } fragment Foo on Query { __typename } @@ -125,12 +109,12 @@ describe('Validate: Possible type extensions', () => { extend enum Foo @dummy extend input Foo @dummy `).to.deep.equal([ - extendingUnknownType('Foo', [], 6, 21), - extendingUnknownType('Foo', [], 7, 19), - extendingUnknownType('Foo', [], 8, 24), - extendingUnknownType('Foo', [], 9, 20), - extendingUnknownType('Foo', [], 10, 19), - extendingUnknownType('Foo', [], 11, 20), + { message, locations: [{ line: 6, column: 21 }] }, + { message, locations: [{ line: 7, column: 19 }] }, + { message, locations: [{ line: 8, column: 24 }] }, + { message, locations: [{ line: 9, column: 20 }] }, + { message, locations: [{ line: 10, column: 19 }] }, + { message, locations: [{ line: 11, column: 20 }] }, ]); }); @@ -150,12 +134,30 @@ describe('Validate: Possible type extensions', () => { extend input FooEnum @dummy extend scalar FooInputObject @dummy `).to.deep.equal([ - extendingDifferentTypeKind('FooScalar', 'scalar', 2, 7, 9, 7), - extendingDifferentTypeKind('FooObject', 'object', 3, 7, 10, 7), - extendingDifferentTypeKind('FooInterface', 'interface', 4, 7, 11, 7), - extendingDifferentTypeKind('FooUnion', 'union', 5, 7, 12, 7), - extendingDifferentTypeKind('FooEnum', 'enum', 6, 7, 13, 7), - extendingDifferentTypeKind('FooInputObject', 'input object', 7, 7, 14, 7), + { + message: 'Cannot extend non-scalar type "FooScalar".', + locations: [{ line: 2, column: 7 }, { line: 9, column: 7 }], + }, + { + message: 'Cannot extend non-object type "FooObject".', + locations: [{ line: 3, column: 7 }, { line: 10, column: 7 }], + }, + { + message: 'Cannot extend non-interface type "FooInterface".', + locations: [{ line: 4, column: 7 }, { line: 11, column: 7 }], + }, + { + message: 'Cannot extend non-union type "FooUnion".', + locations: [{ line: 5, column: 7 }, { line: 12, column: 7 }], + }, + { + message: 'Cannot extend non-enum type "FooEnum".', + locations: [{ line: 6, column: 7 }, { line: 13, column: 7 }], + }, + { + message: 'Cannot extend non-input object type "FooInputObject".', + locations: [{ line: 7, column: 7 }, { line: 14, column: 7 }], + }, ]); }); @@ -191,13 +193,15 @@ describe('Validate: Possible type extensions', () => { extend input Unknown @dummy `; + const message = + 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?'; expectSDLErrors(sdl, schema).to.deep.equal([ - extendingUnknownType('Unknown', ['Known'], 2, 21), - extendingUnknownType('Unknown', ['Known'], 3, 19), - extendingUnknownType('Unknown', ['Known'], 4, 24), - extendingUnknownType('Unknown', ['Known'], 5, 20), - extendingUnknownType('Unknown', ['Known'], 6, 19), - extendingUnknownType('Unknown', ['Known'], 7, 20), + { message, locations: [{ line: 2, column: 21 }] }, + { message, locations: [{ line: 3, column: 19 }] }, + { message, locations: [{ line: 4, column: 24 }] }, + { message, locations: [{ line: 5, column: 20 }] }, + { message, locations: [{ line: 6, column: 19 }] }, + { message, locations: [{ line: 7, column: 20 }] }, ]); }); @@ -220,12 +224,30 @@ describe('Validate: Possible type extensions', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - extendingDifferentTypeKind('FooScalar', 'scalar', 2, 7), - extendingDifferentTypeKind('FooObject', 'object', 3, 7), - extendingDifferentTypeKind('FooInterface', 'interface', 4, 7), - extendingDifferentTypeKind('FooUnion', 'union', 5, 7), - extendingDifferentTypeKind('FooEnum', 'enum', 6, 7), - extendingDifferentTypeKind('FooInputObject', 'input object', 7, 7), + { + message: 'Cannot extend non-scalar type "FooScalar".', + locations: [{ line: 2, column: 7 }], + }, + { + message: 'Cannot extend non-object type "FooObject".', + locations: [{ line: 3, column: 7 }], + }, + { + message: 'Cannot extend non-interface type "FooInterface".', + locations: [{ line: 4, column: 7 }], + }, + { + message: 'Cannot extend non-union type "FooUnion".', + locations: [{ line: 5, column: 7 }], + }, + { + message: 'Cannot extend non-enum type "FooEnum".', + locations: [{ line: 6, column: 7 }], + }, + { + message: 'Cannot extend non-input object type "FooInputObject".', + locations: [{ line: 7, column: 7 }], + }, ]); }); }); diff --git a/src/validation/__tests__/ProvidedRequiredArguments-test.js b/src/validation/__tests__/ProvidedRequiredArguments-test.js index 158ee5a1e5..6afcde0ad7 100644 --- a/src/validation/__tests__/ProvidedRequiredArguments-test.js +++ b/src/validation/__tests__/ProvidedRequiredArguments-test.js @@ -7,8 +7,6 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { ProvidedRequiredArguments, ProvidedRequiredArgumentsOnDirectives, - missingFieldArgMessage, - missingDirectiveArgMessage, } from '../rules/ProvidedRequiredArguments'; import { expectValidationErrors, expectSDLValidationErrors } from './harness'; @@ -33,20 +31,6 @@ function expectValidSDL(sdlStr) { expectSDLErrors(sdlStr).to.deep.equal([]); } -function missingFieldArg(fieldName, argName, typeName, line, column) { - return { - message: missingFieldArgMessage(fieldName, argName, typeName), - locations: [{ line, column }], - }; -} - -function missingDirectiveArg(directiveName, argName, typeName, line, column) { - return { - message: missingDirectiveArgMessage(directiveName, argName, typeName), - locations: [{ line, column }], - }; -} - describe('Validate: Provided required arguments', () => { it('ignores unknown arguments', () => { expectValid(` @@ -179,7 +163,11 @@ describe('Validate: Provided required arguments', () => { } } `).to.deep.equal([ - missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13), + { + message: + 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', + locations: [{ line: 4, column: 13 }], + }, ]); }); @@ -191,8 +179,16 @@ describe('Validate: Provided required arguments', () => { } } `).to.deep.equal([ - missingFieldArg('multipleReqs', 'req1', 'Int!', 4, 13), - missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13), + { + message: + 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', + locations: [{ line: 4, column: 13 }], + }, + { + message: + 'Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.', + locations: [{ line: 4, column: 13 }], + }, ]); }); @@ -204,7 +200,11 @@ describe('Validate: Provided required arguments', () => { } } `).to.deep.equal([ - missingFieldArg('multipleReqs', 'req2', 'Int!', 4, 13), + { + message: + 'Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.', + locations: [{ line: 4, column: 13 }], + }, ]); }); }); @@ -239,8 +239,16 @@ describe('Validate: Provided required arguments', () => { } } `).to.deep.equal([ - missingDirectiveArg('include', 'if', 'Boolean!', 3, 15), - missingDirectiveArg('skip', 'if', 'Boolean!', 4, 18), + { + message: + 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', + locations: [{ line: 3, column: 15 }], + }, + { + message: + 'Directive "@skip" argument "if" of type "Boolean!" is required, but it was not provided.', + locations: [{ line: 4, column: 18 }], + }, ]); }); }); @@ -263,7 +271,13 @@ describe('Validate: Provided required arguments', () => { } directive @test(arg: String!) on FIELD_DEFINITION - `).to.deep.equal([missingDirectiveArg('test', 'arg', 'String!', 3, 23)]); + `).to.deep.equal([ + { + message: + 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', + locations: [{ line: 3, column: 23 }], + }, + ]); }); it('Missing arg on standard directive', () => { @@ -272,7 +286,11 @@ describe('Validate: Provided required arguments', () => { foo: String @include } `).to.deep.equal([ - missingDirectiveArg('include', 'if', 'Boolean!', 3, 23), + { + message: + 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', + locations: [{ line: 3, column: 23 }], + }, ]); }); @@ -283,7 +301,11 @@ describe('Validate: Provided required arguments', () => { } directive @deprecated(reason: String!) on FIELD `).to.deep.equal([ - missingDirectiveArg('deprecated', 'reason', 'String!', 3, 23), + { + message: + 'Directive "@deprecated" argument "reason" of type "String!" is required, but it was not provided.', + locations: [{ line: 3, column: 23 }], + }, ]); }); @@ -300,7 +322,13 @@ describe('Validate: Provided required arguments', () => { extend type Query @test `, schema, - ).to.deep.equal([missingDirectiveArg('test', 'arg', 'String!', 4, 30)]); + ).to.deep.equal([ + { + message: + 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', + locations: [{ line: 4, column: 30 }], + }, + ]); }); it('Missing arg on directive used in schema extension', () => { @@ -316,7 +344,13 @@ describe('Validate: Provided required arguments', () => { extend type Query @test `, schema, - ).to.deep.equal([missingDirectiveArg('test', 'arg', 'String!', 2, 29)]); + ).to.deep.equal([ + { + message: + 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', + locations: [{ line: 2, column: 29 }], + }, + ]); }); }); }); diff --git a/src/validation/__tests__/ScalarLeafs-test.js b/src/validation/__tests__/ScalarLeafs-test.js index 8b9a75808e..b60f9f943b 100644 --- a/src/validation/__tests__/ScalarLeafs-test.js +++ b/src/validation/__tests__/ScalarLeafs-test.js @@ -2,11 +2,7 @@ import { describe, it } from 'mocha'; -import { - ScalarLeafs, - noSubselectionAllowedMessage, - requiredSubselectionMessage, -} from '../rules/ScalarLeafs'; +import { ScalarLeafs } from '../rules/ScalarLeafs'; import { expectValidationErrors } from './harness'; @@ -18,20 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function noScalarSubselection(field, type, line, column) { - return { - message: noSubselectionAllowedMessage(field, type), - locations: [{ line, column }], - }; -} - -function missingObjSubselection(field, type, line, column) { - return { - message: requiredSubselectionMessage(field, type), - locations: [{ line, column }], - }; -} - describe('Validate: Scalar leafs', () => { it('valid scalar selection', () => { expectValid(` @@ -46,7 +28,13 @@ describe('Validate: Scalar leafs', () => { query directQueryOnObjectWithoutSubFields { human } - `).to.deep.equal([missingObjSubselection('human', 'Human', 3, 9)]); + `).to.deep.equal([ + { + message: + 'Field "human" of type "Human" must have a selection of subfields. Did you mean "human { ... }"?', + locations: [{ line: 3, column: 9 }], + }, + ]); }); it('interface type missing selection', () => { @@ -54,7 +42,13 @@ describe('Validate: Scalar leafs', () => { { human { pets } } - `).to.deep.equal([missingObjSubselection('pets', '[Pet]', 3, 17)]); + `).to.deep.equal([ + { + message: + 'Field "pets" of type "[Pet]" must have a selection of subfields. Did you mean "pets { ... }"?', + locations: [{ line: 3, column: 17 }], + }, + ]); }); it('valid scalar selection with args', () => { @@ -70,7 +64,13 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } - `).to.deep.equal([noScalarSubselection('barks', 'Boolean', 3, 15)]); + `).to.deep.equal([ + { + message: + 'Field "barks" must not have a selection since type "Boolean" has no subfields.', + locations: [{ line: 3, column: 15 }], + }, + ]); }); it('scalar selection not allowed on Enum', () => { @@ -78,7 +78,13 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexdec } } - `).to.deep.equal([noScalarSubselection('furColor', 'FurColor', 3, 18)]); + `).to.deep.equal([ + { + message: + 'Field "furColor" must not have a selection since type "FurColor" has no subfields.', + locations: [{ line: 3, column: 18 }], + }, + ]); }); it('scalar selection not allowed with args', () => { @@ -87,7 +93,11 @@ describe('Validate: Scalar leafs', () => { doesKnowCommand(dogCommand: SIT) { sinceWhen } } `).to.deep.equal([ - noScalarSubselection('doesKnowCommand', 'Boolean', 3, 42), + { + message: + 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', + locations: [{ line: 3, column: 42 }], + }, ]); }); @@ -96,7 +106,13 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } - `).to.deep.equal([noScalarSubselection('name', 'String', 3, 33)]); + `).to.deep.equal([ + { + message: + 'Field "name" must not have a selection since type "String" has no subfields.', + locations: [{ line: 3, column: 33 }], + }, + ]); }); it('Scalar selection not allowed with directives and args', () => { @@ -105,7 +121,11 @@ describe('Validate: Scalar leafs', () => { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } `).to.deep.equal([ - noScalarSubselection('doesKnowCommand', 'Boolean', 3, 61), + { + message: + 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', + locations: [{ line: 3, column: 61 }], + }, ]); }); }); diff --git a/src/validation/__tests__/SingleFieldSubscriptions-test.js b/src/validation/__tests__/SingleFieldSubscriptions-test.js index b100509e0b..b8d084f853 100644 --- a/src/validation/__tests__/SingleFieldSubscriptions-test.js +++ b/src/validation/__tests__/SingleFieldSubscriptions-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - SingleFieldSubscriptions, - singleFieldOnlyMessage, -} from '../rules/SingleFieldSubscriptions'; +import { SingleFieldSubscriptions } from '../rules/SingleFieldSubscriptions'; import { expectValidationErrors } from './harness'; @@ -34,7 +31,8 @@ describe('Validate: Subscriptions with single field', () => { } `).to.deep.equal([ { - message: singleFieldOnlyMessage('ImportantEmails'), + message: + 'Subscription "ImportantEmails" must select only one top level field.', locations: [{ line: 4, column: 9 }], }, ]); @@ -48,7 +46,8 @@ describe('Validate: Subscriptions with single field', () => { } `).to.deep.equal([ { - message: singleFieldOnlyMessage('ImportantEmails'), + message: + 'Subscription "ImportantEmails" must select only one top level field.', locations: [{ line: 4, column: 9 }], }, ]); @@ -63,7 +62,8 @@ describe('Validate: Subscriptions with single field', () => { } `).to.deep.equal([ { - message: singleFieldOnlyMessage('ImportantEmails'), + message: + 'Subscription "ImportantEmails" must select only one top level field.', locations: [{ line: 4, column: 9 }, { line: 5, column: 9 }], }, ]); @@ -77,7 +77,7 @@ describe('Validate: Subscriptions with single field', () => { } `).to.deep.equal([ { - message: singleFieldOnlyMessage(null), + message: 'Anonymous Subscription must select only one top level field.', locations: [{ line: 4, column: 9 }], }, ]); diff --git a/src/validation/__tests__/UniqueArgumentNames-test.js b/src/validation/__tests__/UniqueArgumentNames-test.js index 269fd1fcec..a4396accbc 100644 --- a/src/validation/__tests__/UniqueArgumentNames-test.js +++ b/src/validation/__tests__/UniqueArgumentNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - UniqueArgumentNames, - duplicateArgMessage, -} from '../rules/UniqueArgumentNames'; +import { UniqueArgumentNames } from '../rules/UniqueArgumentNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function duplicateArg(argName, l1, c1, l2, c2) { - return { - message: duplicateArgMessage(argName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique argument names', () => { it('no arguments on field', () => { expectValid(` @@ -103,7 +93,12 @@ describe('Validate: Unique argument names', () => { { field(arg1: "value", arg1: "value") } - `).to.deep.equal([duplicateArg('arg1', 3, 15, 3, 30)]); + `).to.deep.equal([ + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 15 }, { line: 3, column: 30 }], + }, + ]); }); it('many duplicate field arguments', () => { @@ -112,8 +107,14 @@ describe('Validate: Unique argument names', () => { field(arg1: "value", arg1: "value", arg1: "value") } `).to.deep.equal([ - duplicateArg('arg1', 3, 15, 3, 30), - duplicateArg('arg1', 3, 15, 3, 45), + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 15 }, { line: 3, column: 30 }], + }, + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 15 }, { line: 3, column: 45 }], + }, ]); }); @@ -122,7 +123,12 @@ describe('Validate: Unique argument names', () => { { field @directive(arg1: "value", arg1: "value") } - `).to.deep.equal([duplicateArg('arg1', 3, 26, 3, 41)]); + `).to.deep.equal([ + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 26 }, { line: 3, column: 41 }], + }, + ]); }); it('many duplicate directive arguments', () => { @@ -131,8 +137,14 @@ describe('Validate: Unique argument names', () => { field @directive(arg1: "value", arg1: "value", arg1: "value") } `).to.deep.equal([ - duplicateArg('arg1', 3, 26, 3, 41), - duplicateArg('arg1', 3, 26, 3, 56), + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 26 }, { line: 3, column: 41 }], + }, + { + message: 'There can be only one argument named "arg1".', + locations: [{ line: 3, column: 26 }, { line: 3, column: 56 }], + }, ]); }); }); diff --git a/src/validation/__tests__/UniqueDirectiveNames-test.js b/src/validation/__tests__/UniqueDirectiveNames-test.js index 2682314ba0..f14608803e 100644 --- a/src/validation/__tests__/UniqueDirectiveNames-test.js +++ b/src/validation/__tests__/UniqueDirectiveNames-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - UniqueDirectiveNames, - existedDirectiveNameMessage, - duplicateDirectiveNameMessage, -} from '../rules/UniqueDirectiveNames'; +import { UniqueDirectiveNames } from '../rules/UniqueDirectiveNames'; import { expectSDLValidationErrors } from './harness'; @@ -58,7 +54,7 @@ describe('Validate: Unique directive names', () => { directive @foo on SCHEMA `).to.deep.equal([ { - message: duplicateDirectiveNameMessage('foo'), + message: 'There can be only one directive named "foo".', locations: [{ line: 2, column: 18 }, { line: 4, column: 18 }], }, ]); @@ -75,7 +71,8 @@ describe('Validate: Unique directive names', () => { expectSDLErrors('directive @skip on SCHEMA', schema).to.deep.equal([ { - message: existedDirectiveNameMessage('skip'), + message: + 'Directive "skip" already exists in the schema. It cannot be redefined.', locations: [{ line: 1, column: 12 }], }, ]); @@ -92,7 +89,8 @@ describe('Validate: Unique directive names', () => { expectSDLErrors('directive @foo on SCHEMA', schema).to.deep.equal([ { - message: existedDirectiveNameMessage('foo'), + message: + 'Directive "foo" already exists in the schema. It cannot be redefined.', locations: [{ line: 1, column: 12 }], }, ]); diff --git a/src/validation/__tests__/UniqueDirectivesPerLocation-test.js b/src/validation/__tests__/UniqueDirectivesPerLocation-test.js index a18ae01f97..8b2ad100a9 100644 --- a/src/validation/__tests__/UniqueDirectivesPerLocation-test.js +++ b/src/validation/__tests__/UniqueDirectivesPerLocation-test.js @@ -5,10 +5,7 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; import { extendSchema } from '../../utilities/extendSchema'; -import { - UniqueDirectivesPerLocation, - duplicateDirectiveMessage, -} from '../rules/UniqueDirectivesPerLocation'; +import { UniqueDirectivesPerLocation } from '../rules/UniqueDirectivesPerLocation'; import { testSchema, @@ -40,13 +37,6 @@ function expectSDLErrors(sdlStr, schema) { return expectSDLValidationErrors(schema, UniqueDirectivesPerLocation, sdlStr); } -function duplicateDirective(directiveName, l1, c1, l2, c2) { - return { - message: duplicateDirectiveMessage(directiveName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Directives Are Unique Per Location', () => { it('no directives', () => { expectValid(` @@ -114,7 +104,13 @@ describe('Validate: Directives Are Unique Per Location', () => { fragment Test on Type { field @directive @directive } - `).to.deep.equal([duplicateDirective('directive', 3, 15, 3, 26)]); + `).to.deep.equal([ + { + message: + 'The directive "directive" can only be used once at this location.', + locations: [{ line: 3, column: 15 }, { line: 3, column: 26 }], + }, + ]); }); it('many duplicate directives in one location', () => { @@ -123,8 +119,16 @@ describe('Validate: Directives Are Unique Per Location', () => { field @directive @directive @directive } `).to.deep.equal([ - duplicateDirective('directive', 3, 15, 3, 26), - duplicateDirective('directive', 3, 15, 3, 37), + { + message: + 'The directive "directive" can only be used once at this location.', + locations: [{ line: 3, column: 15 }, { line: 3, column: 26 }], + }, + { + message: + 'The directive "directive" can only be used once at this location.', + locations: [{ line: 3, column: 15 }, { line: 3, column: 37 }], + }, ]); }); @@ -134,8 +138,16 @@ describe('Validate: Directives Are Unique Per Location', () => { field @directiveA @directiveB @directiveA @directiveB } `).to.deep.equal([ - duplicateDirective('directiveA', 3, 15, 3, 39), - duplicateDirective('directiveB', 3, 27, 3, 51), + { + message: + 'The directive "directiveA" can only be used once at this location.', + locations: [{ line: 3, column: 15 }, { line: 3, column: 39 }], + }, + { + message: + 'The directive "directiveB" can only be used once at this location.', + locations: [{ line: 3, column: 27 }, { line: 3, column: 51 }], + }, ]); }); @@ -145,8 +157,16 @@ describe('Validate: Directives Are Unique Per Location', () => { field @directive @directive } `).to.deep.equal([ - duplicateDirective('directive', 2, 29, 2, 40), - duplicateDirective('directive', 3, 15, 3, 26), + { + message: + 'The directive "directive" can only be used once at this location.', + locations: [{ line: 2, column: 29 }, { line: 2, column: 40 }], + }, + { + message: + 'The directive "directive" can only be used once at this location.', + locations: [{ line: 3, column: 15 }, { line: 3, column: 26 }], + }, ]); }); @@ -173,18 +193,66 @@ describe('Validate: Directives Are Unique Per Location', () => { input TestInput @nonRepeatable @nonRepeatable extend input TestInput @nonRepeatable @nonRepeatable `).to.deep.equal([ - duplicateDirective('nonRepeatable', 5, 14, 5, 29), - duplicateDirective('nonRepeatable', 6, 21, 6, 36), - duplicateDirective('nonRepeatable', 8, 25, 8, 40), - duplicateDirective('nonRepeatable', 9, 32, 9, 47), - duplicateDirective('nonRepeatable', 11, 23, 11, 38), - duplicateDirective('nonRepeatable', 12, 30, 12, 45), - duplicateDirective('nonRepeatable', 14, 31, 14, 46), - duplicateDirective('nonRepeatable', 15, 38, 15, 53), - duplicateDirective('nonRepeatable', 17, 23, 17, 38), - duplicateDirective('nonRepeatable', 18, 30, 18, 45), - duplicateDirective('nonRepeatable', 20, 23, 20, 38), - duplicateDirective('nonRepeatable', 21, 30, 21, 45), + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 5, column: 14 }, { line: 5, column: 29 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 6, column: 21 }, { line: 6, column: 36 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 8, column: 25 }, { line: 8, column: 40 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 9, column: 32 }, { line: 9, column: 47 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 11, column: 23 }, { line: 11, column: 38 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 12, column: 30 }, { line: 12, column: 45 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 14, column: 31 }, { line: 14, column: 46 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 15, column: 38 }, { line: 15, column: 53 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 17, column: 23 }, { line: 17, column: 38 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 18, column: 30 }, { line: 18, column: 45 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 20, column: 23 }, { line: 20, column: 38 }], + }, + { + message: + 'The directive "nonRepeatable" can only be used once at this location.', + locations: [{ line: 21, column: 30 }, { line: 21, column: 45 }], + }, ]); }); }); diff --git a/src/validation/__tests__/UniqueEnumValueNames-test.js b/src/validation/__tests__/UniqueEnumValueNames-test.js index 06384d1fe7..98ff97a3f4 100644 --- a/src/validation/__tests__/UniqueEnumValueNames-test.js +++ b/src/validation/__tests__/UniqueEnumValueNames-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - UniqueEnumValueNames, - duplicateEnumValueNameMessage, - existedEnumValueNameMessage, -} from '../rules/UniqueEnumValueNames'; +import { UniqueEnumValueNames } from '../rules/UniqueEnumValueNames'; import { expectSDLValidationErrors } from './harness'; @@ -20,20 +16,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function duplicateEnumValuesName(typeName, valueName, l1, c1, l2, c2) { - return { - message: duplicateEnumValueNameMessage(typeName, valueName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - -function existedEnumValueName(typeName, valueName, l1, c1) { - return { - message: existedEnumValueNameMessage(typeName, valueName), - locations: [{ line: l1, column: c1 }], - }; -} - describe('Validate: Unique enum value names', () => { it('no values', () => { expectValidSDL(` @@ -65,7 +47,12 @@ describe('Validate: Unique enum value names', () => { BAR FOO } - `).to.deep.equal([duplicateEnumValuesName('SomeEnum', 'FOO', 3, 9, 5, 9)]); + `).to.deep.equal([ + { + message: 'Enum value "SomeEnum.FOO" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 5, column: 9 }], + }, + ]); }); it('extend enum with new value', () => { @@ -90,7 +77,12 @@ describe('Validate: Unique enum value names', () => { enum SomeEnum { FOO } - `).to.deep.equal([duplicateEnumValuesName('SomeEnum', 'FOO', 3, 9, 6, 9)]); + `).to.deep.equal([ + { + message: 'Enum value "SomeEnum.FOO" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 6, column: 9 }], + }, + ]); }); it('duplicate value inside extension', () => { @@ -101,7 +93,12 @@ describe('Validate: Unique enum value names', () => { BAR FOO } - `).to.deep.equal([duplicateEnumValuesName('SomeEnum', 'FOO', 4, 9, 6, 9)]); + `).to.deep.equal([ + { + message: 'Enum value "SomeEnum.FOO" can only be defined once.', + locations: [{ line: 4, column: 9 }, { line: 6, column: 9 }], + }, + ]); }); it('duplicate value inside different extensions', () => { @@ -113,7 +110,12 @@ describe('Validate: Unique enum value names', () => { extend enum SomeEnum { FOO } - `).to.deep.equal([duplicateEnumValuesName('SomeEnum', 'FOO', 4, 9, 7, 9)]); + `).to.deep.equal([ + { + message: 'Enum value "SomeEnum.FOO" can only be defined once.', + locations: [{ line: 4, column: 9 }, { line: 7, column: 9 }], + }, + ]); }); it('adding new value to the type inside existing schema', () => { @@ -143,8 +145,16 @@ describe('Validate: Unique enum value names', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - existedEnumValueName('SomeEnum', 'FOO', 3, 9), - existedEnumValueName('SomeEnum', 'FOO', 6, 9), + { + message: + 'Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 6, column: 9 }], + }, ]); }); @@ -160,7 +170,10 @@ describe('Validate: Unique enum value names', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - duplicateEnumValuesName('SomeEnum', 'FOO', 3, 9, 6, 9), + { + message: 'Enum value "SomeEnum.FOO" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 6, column: 9 }], + }, ]); }); }); diff --git a/src/validation/__tests__/UniqueFieldDefinitionNames-test.js b/src/validation/__tests__/UniqueFieldDefinitionNames-test.js index cd33954146..c3ff9a73cc 100644 --- a/src/validation/__tests__/UniqueFieldDefinitionNames-test.js +++ b/src/validation/__tests__/UniqueFieldDefinitionNames-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - UniqueFieldDefinitionNames, - duplicateFieldDefinitionNameMessage, - existedFieldDefinitionNameMessage, -} from '../rules/UniqueFieldDefinitionNames'; +import { UniqueFieldDefinitionNames } from '../rules/UniqueFieldDefinitionNames'; import { expectSDLValidationErrors } from './harness'; @@ -20,20 +16,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function duplicateFieldName(typeName, fieldName, l1, c1, l2, c2) { - return { - message: duplicateFieldDefinitionNameMessage(typeName, fieldName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - -function existedFieldName(typeName, fieldName, l1, c1) { - return { - message: existedFieldDefinitionNameMessage(typeName, fieldName), - locations: [{ line: l1, column: c1 }], - }; -} - describe('Validate: Unique field definition names', () => { it('no fields', () => { expectValidSDL(` @@ -98,9 +80,18 @@ describe('Validate: Unique field definition names', () => { foo: String } `).to.deep.equal([ - duplicateFieldName('SomeObject', 'foo', 3, 9, 5, 9), - duplicateFieldName('SomeInterface', 'foo', 9, 9, 11, 9), - duplicateFieldName('SomeInputObject', 'foo', 15, 9, 17, 9), + { + message: 'Field "SomeObject.foo" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 5, column: 9 }], + }, + { + message: 'Field "SomeInterface.foo" can only be defined once.', + locations: [{ line: 9, column: 9 }, { line: 11, column: 9 }], + }, + { + message: 'Field "SomeInputObject.foo" can only be defined once.', + locations: [{ line: 15, column: 9 }, { line: 17, column: 9 }], + }, ]); }); @@ -161,9 +152,18 @@ describe('Validate: Unique field definition names', () => { foo: String } `).to.deep.equal([ - duplicateFieldName('SomeObject', 'foo', 3, 9, 6, 9), - duplicateFieldName('SomeInterface', 'foo', 10, 9, 13, 9), - duplicateFieldName('SomeInputObject', 'foo', 17, 9, 20, 9), + { + message: 'Field "SomeObject.foo" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 6, column: 9 }], + }, + { + message: 'Field "SomeInterface.foo" can only be defined once.', + locations: [{ line: 10, column: 9 }, { line: 13, column: 9 }], + }, + { + message: 'Field "SomeInputObject.foo" can only be defined once.', + locations: [{ line: 17, column: 9 }, { line: 20, column: 9 }], + }, ]); }); @@ -190,9 +190,18 @@ describe('Validate: Unique field definition names', () => { foo: String } `).to.deep.equal([ - duplicateFieldName('SomeObject', 'foo', 4, 9, 6, 9), - duplicateFieldName('SomeInterface', 'foo', 11, 9, 13, 9), - duplicateFieldName('SomeInputObject', 'foo', 18, 9, 20, 9), + { + message: 'Field "SomeObject.foo" can only be defined once.', + locations: [{ line: 4, column: 9 }, { line: 6, column: 9 }], + }, + { + message: 'Field "SomeInterface.foo" can only be defined once.', + locations: [{ line: 11, column: 9 }, { line: 13, column: 9 }], + }, + { + message: 'Field "SomeInputObject.foo" can only be defined once.', + locations: [{ line: 18, column: 9 }, { line: 20, column: 9 }], + }, ]); }); @@ -222,9 +231,18 @@ describe('Validate: Unique field definition names', () => { foo: String } `).to.deep.equal([ - duplicateFieldName('SomeObject', 'foo', 4, 9, 7, 9), - duplicateFieldName('SomeInterface', 'foo', 12, 9, 15, 9), - duplicateFieldName('SomeInputObject', 'foo', 20, 9, 23, 9), + { + message: 'Field "SomeObject.foo" can only be defined once.', + locations: [{ line: 4, column: 9 }, { line: 7, column: 9 }], + }, + { + message: 'Field "SomeInterface.foo" can only be defined once.', + locations: [{ line: 12, column: 9 }, { line: 15, column: 9 }], + }, + { + message: 'Field "SomeInputObject.foo" can only be defined once.', + locations: [{ line: 20, column: 9 }, { line: 23, column: 9 }], + }, ]); }); @@ -288,13 +306,36 @@ describe('Validate: Unique field definition names', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - existedFieldName('SomeObject', 'foo', 3, 9), - existedFieldName('SomeInterface', 'foo', 6, 9), - existedFieldName('SomeInputObject', 'foo', 9, 9), - - existedFieldName('SomeObject', 'foo', 13, 9), - existedFieldName('SomeInterface', 'foo', 16, 9), - existedFieldName('SomeInputObject', 'foo', 19, 9), + { + message: + 'Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 6, column: 9 }], + }, + { + message: + 'Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 9, column: 9 }], + }, + { + message: + 'Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 13, column: 9 }], + }, + { + message: + 'Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 16, column: 9 }], + }, + { + message: + 'Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.', + locations: [{ line: 19, column: 9 }], + }, ]); }); @@ -328,9 +369,18 @@ describe('Validate: Unique field definition names', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - duplicateFieldName('SomeObject', 'foo', 3, 9, 6, 9), - duplicateFieldName('SomeInterface', 'foo', 10, 9, 13, 9), - duplicateFieldName('SomeInputObject', 'foo', 17, 9, 20, 9), + { + message: 'Field "SomeObject.foo" can only be defined once.', + locations: [{ line: 3, column: 9 }, { line: 6, column: 9 }], + }, + { + message: 'Field "SomeInterface.foo" can only be defined once.', + locations: [{ line: 10, column: 9 }, { line: 13, column: 9 }], + }, + { + message: 'Field "SomeInputObject.foo" can only be defined once.', + locations: [{ line: 17, column: 9 }, { line: 20, column: 9 }], + }, ]); }); }); diff --git a/src/validation/__tests__/UniqueFragmentNames-test.js b/src/validation/__tests__/UniqueFragmentNames-test.js index a799736f82..af5298059a 100644 --- a/src/validation/__tests__/UniqueFragmentNames-test.js +++ b/src/validation/__tests__/UniqueFragmentNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - UniqueFragmentNames, - duplicateFragmentNameMessage, -} from '../rules/UniqueFragmentNames'; +import { UniqueFragmentNames } from '../rules/UniqueFragmentNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function duplicateFrag(fragName, l1, c1, l2, c2) { - return { - message: duplicateFragmentNameMessage(fragName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique fragment names', () => { it('no fragments', () => { expectValid(` @@ -99,7 +89,12 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { fieldB } - `).to.deep.equal([duplicateFrag('fragA', 5, 16, 8, 16)]); + `).to.deep.equal([ + { + message: 'There can be only one fragment named "fragA".', + locations: [{ line: 5, column: 16 }, { line: 8, column: 16 }], + }, + ]); }); it('fragments named the same without being referenced', () => { @@ -110,6 +105,11 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { fieldB } - `).to.deep.equal([duplicateFrag('fragA', 2, 16, 5, 16)]); + `).to.deep.equal([ + { + message: 'There can be only one fragment named "fragA".', + locations: [{ line: 2, column: 16 }, { line: 5, column: 16 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/UniqueInputFieldNames-test.js b/src/validation/__tests__/UniqueInputFieldNames-test.js index cace6cf9d7..4286026c5c 100644 --- a/src/validation/__tests__/UniqueInputFieldNames-test.js +++ b/src/validation/__tests__/UniqueInputFieldNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - UniqueInputFieldNames, - duplicateInputFieldMessage, -} from '../rules/UniqueInputFieldNames'; +import { UniqueInputFieldNames } from '../rules/UniqueInputFieldNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function duplicateField(name, l1, c1, l2, c2) { - return { - message: duplicateInputFieldMessage(name), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique input field names', () => { it('input object with fields', () => { expectValid(` @@ -70,7 +60,12 @@ describe('Validate: Unique input field names', () => { { field(arg: { f1: "value", f1: "value" }) } - `).to.deep.equal([duplicateField('f1', 3, 22, 3, 35)]); + `).to.deep.equal([ + { + message: 'There can be only one input field named "f1".', + locations: [{ line: 3, column: 22 }, { line: 3, column: 35 }], + }, + ]); }); it('many duplicate input object fields', () => { @@ -79,8 +74,14 @@ describe('Validate: Unique input field names', () => { field(arg: { f1: "value", f1: "value", f1: "value" }) } `).to.deep.equal([ - duplicateField('f1', 3, 22, 3, 35), - duplicateField('f1', 3, 22, 3, 48), + { + message: 'There can be only one input field named "f1".', + locations: [{ line: 3, column: 22 }, { line: 3, column: 35 }], + }, + { + message: 'There can be only one input field named "f1".', + locations: [{ line: 3, column: 22 }, { line: 3, column: 48 }], + }, ]); }); @@ -89,6 +90,11 @@ describe('Validate: Unique input field names', () => { { field(arg: { f1: {f2: "value", f2: "value" }}) } - `).to.deep.equal([duplicateField('f2', 3, 27, 3, 40)]); + `).to.deep.equal([ + { + message: 'There can be only one input field named "f2".', + locations: [{ line: 3, column: 27 }, { line: 3, column: 40 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/UniqueOperationNames-test.js b/src/validation/__tests__/UniqueOperationNames-test.js index fbb56bcae9..ed5331802c 100644 --- a/src/validation/__tests__/UniqueOperationNames-test.js +++ b/src/validation/__tests__/UniqueOperationNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - UniqueOperationNames, - duplicateOperationNameMessage, -} from '../rules/UniqueOperationNames'; +import { UniqueOperationNames } from '../rules/UniqueOperationNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function duplicateOp(opName, l1, c1, l2, c2) { - return { - message: duplicateOperationNameMessage(opName), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique operation names', () => { it('no operations', () => { expectValid(` @@ -96,7 +86,12 @@ describe('Validate: Unique operation names', () => { query Foo { fieldB } - `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 13)]); + `).to.deep.equal([ + { + message: 'There can be only one operation named "Foo".', + locations: [{ line: 2, column: 13 }, { line: 5, column: 13 }], + }, + ]); }); it('multiple ops of same name of different types (mutation)', () => { @@ -107,7 +102,12 @@ describe('Validate: Unique operation names', () => { mutation Foo { fieldB } - `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 16)]); + `).to.deep.equal([ + { + message: 'There can be only one operation named "Foo".', + locations: [{ line: 2, column: 13 }, { line: 5, column: 16 }], + }, + ]); }); it('multiple ops of same name of different types (subscription)', () => { @@ -118,6 +118,11 @@ describe('Validate: Unique operation names', () => { subscription Foo { fieldB } - `).to.deep.equal([duplicateOp('Foo', 2, 13, 5, 20)]); + `).to.deep.equal([ + { + message: 'There can be only one operation named "Foo".', + locations: [{ line: 2, column: 13 }, { line: 5, column: 20 }], + }, + ]); }); }); diff --git a/src/validation/__tests__/UniqueOperationTypes-test.js b/src/validation/__tests__/UniqueOperationTypes-test.js index b5330626bb..ea8cd95590 100644 --- a/src/validation/__tests__/UniqueOperationTypes-test.js +++ b/src/validation/__tests__/UniqueOperationTypes-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - UniqueOperationTypes, - existedOperationTypeMessage, - duplicateOperationTypeMessage, -} from '../rules/UniqueOperationTypes'; +import { UniqueOperationTypes } from '../rules/UniqueOperationTypes'; import { expectSDLValidationErrors } from './harness'; @@ -20,20 +16,6 @@ function expectValidSDL(sdlStr, schema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } -function existedOperationType(operation, l1, c1) { - return { - message: existedOperationTypeMessage(operation), - locations: [{ line: l1, column: c1 }], - }; -} - -function duplicateOperationType(operation, l1, c1, l2, c2) { - return { - message: duplicateOperationTypeMessage(operation), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique operation types', () => { it('no schema definition', () => { expectValidSDL(` @@ -101,9 +83,18 @@ describe('Validate: Unique operation types', () => { subscription: Foo } `).to.deep.equal([ - duplicateOperationType('query', 5, 9, 9, 9), - duplicateOperationType('mutation', 6, 9, 10, 9), - duplicateOperationType('subscription', 7, 9, 11, 9), + { + message: 'There can be only one query type in schema.', + locations: [{ line: 5, column: 9 }, { line: 9, column: 9 }], + }, + { + message: 'There can be only one mutation type in schema.', + locations: [{ line: 6, column: 9 }, { line: 10, column: 9 }], + }, + { + message: 'There can be only one subscription type in schema.', + locations: [{ line: 7, column: 9 }, { line: 11, column: 9 }], + }, ]); }); @@ -123,9 +114,18 @@ describe('Validate: Unique operation types', () => { subscription: Foo } `).to.deep.equal([ - duplicateOperationType('query', 5, 9, 11, 9), - duplicateOperationType('mutation', 6, 9, 12, 9), - duplicateOperationType('subscription', 7, 9, 13, 9), + { + message: 'There can be only one query type in schema.', + locations: [{ line: 5, column: 9 }, { line: 11, column: 9 }], + }, + { + message: 'There can be only one mutation type in schema.', + locations: [{ line: 6, column: 9 }, { line: 12, column: 9 }], + }, + { + message: 'There can be only one subscription type in schema.', + locations: [{ line: 7, column: 9 }, { line: 13, column: 9 }], + }, ]); }); @@ -151,12 +151,30 @@ describe('Validate: Unique operation types', () => { subscription: Foo } `).to.deep.equal([ - duplicateOperationType('query', 5, 9, 11, 9), - duplicateOperationType('mutation', 6, 9, 12, 9), - duplicateOperationType('subscription', 7, 9, 13, 9), - duplicateOperationType('query', 5, 9, 17, 9), - duplicateOperationType('mutation', 6, 9, 18, 9), - duplicateOperationType('subscription', 7, 9, 19, 9), + { + message: 'There can be only one query type in schema.', + locations: [{ line: 5, column: 9 }, { line: 11, column: 9 }], + }, + { + message: 'There can be only one mutation type in schema.', + locations: [{ line: 6, column: 9 }, { line: 12, column: 9 }], + }, + { + message: 'There can be only one subscription type in schema.', + locations: [{ line: 7, column: 9 }, { line: 13, column: 9 }], + }, + { + message: 'There can be only one query type in schema.', + locations: [{ line: 5, column: 9 }, { line: 17, column: 9 }], + }, + { + message: 'There can be only one mutation type in schema.', + locations: [{ line: 6, column: 9 }, { line: 18, column: 9 }], + }, + { + message: 'There can be only one subscription type in schema.', + locations: [{ line: 7, column: 9 }, { line: 19, column: 9 }], + }, ]); }); @@ -179,9 +197,18 @@ describe('Validate: Unique operation types', () => { subscription: Foo } `).to.deep.equal([ - duplicateOperationType('query', 5, 9, 14, 9), - duplicateOperationType('mutation', 9, 9, 15, 9), - duplicateOperationType('subscription', 10, 9, 16, 9), + { + message: 'There can be only one query type in schema.', + locations: [{ line: 5, column: 9 }, { line: 14, column: 9 }], + }, + { + message: 'There can be only one mutation type in schema.', + locations: [{ line: 9, column: 9 }, { line: 15, column: 9 }], + }, + { + message: 'There can be only one subscription type in schema.', + locations: [{ line: 10, column: 9 }, { line: 16, column: 9 }], + }, ]); }); @@ -237,9 +264,21 @@ describe('Validate: Unique operation types', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - existedOperationType('query', 3, 9), - existedOperationType('mutation', 4, 9), - existedOperationType('subscription', 5, 9), + { + message: + 'Type for query already defined in the schema. It cannot be redefined.', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'Type for mutation already defined in the schema. It cannot be redefined.', + locations: [{ line: 4, column: 9 }], + }, + { + message: + 'Type for subscription already defined in the schema. It cannot be redefined.', + locations: [{ line: 5, column: 9 }], + }, ]); }); @@ -265,12 +304,36 @@ describe('Validate: Unique operation types', () => { `; expectSDLErrors(sdl, schema).to.deep.equal([ - existedOperationType('query', 3, 9), - existedOperationType('mutation', 4, 9), - existedOperationType('subscription', 5, 9), - existedOperationType('query', 9, 9), - existedOperationType('mutation', 10, 9), - existedOperationType('subscription', 11, 9), + { + message: + 'Type for query already defined in the schema. It cannot be redefined.', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'Type for mutation already defined in the schema. It cannot be redefined.', + locations: [{ line: 4, column: 9 }], + }, + { + message: + 'Type for subscription already defined in the schema. It cannot be redefined.', + locations: [{ line: 5, column: 9 }], + }, + { + message: + 'Type for query already defined in the schema. It cannot be redefined.', + locations: [{ line: 9, column: 9 }], + }, + { + message: + 'Type for mutation already defined in the schema. It cannot be redefined.', + locations: [{ line: 10, column: 9 }], + }, + { + message: + 'Type for subscription already defined in the schema. It cannot be redefined.', + locations: [{ line: 11, column: 9 }], + }, ]); }); }); diff --git a/src/validation/__tests__/UniqueTypeNames-test.js b/src/validation/__tests__/UniqueTypeNames-test.js index 9a9134599d..2acc9cf678 100644 --- a/src/validation/__tests__/UniqueTypeNames-test.js +++ b/src/validation/__tests__/UniqueTypeNames-test.js @@ -4,11 +4,7 @@ import { describe, it } from 'mocha'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { - UniqueTypeNames, - existedTypeNameMessage, - duplicateTypeNameMessage, -} from '../rules/UniqueTypeNames'; +import { UniqueTypeNames } from '../rules/UniqueTypeNames'; import { expectSDLValidationErrors } from './harness'; @@ -63,27 +59,27 @@ describe('Validate: Unique type names', () => { input Foo `).to.deep.equal([ { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 4, column: 14 }], }, { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 5, column: 12 }], }, { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 6, column: 17 }], }, { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 7, column: 13 }], }, { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 8, column: 12 }], }, { - message: duplicateTypeNameMessage('Foo'), + message: 'There can be only one type named "Foo".', locations: [{ line: 2, column: 12 }, { line: 9, column: 13 }], }, ]); @@ -114,27 +110,33 @@ describe('Validate: Unique type names', () => { expectSDLErrors(sdl, schema).to.deep.equal([ { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 2, column: 14 }], }, { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 3, column: 12 }], }, { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 4, column: 17 }], }, { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 5, column: 13 }], }, { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 6, column: 12 }], }, { - message: existedTypeNameMessage('Foo'), + message: + 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', locations: [{ line: 7, column: 13 }], }, ]); diff --git a/src/validation/__tests__/UniqueVariableNames-test.js b/src/validation/__tests__/UniqueVariableNames-test.js index 8f555f6410..1f1202b380 100644 --- a/src/validation/__tests__/UniqueVariableNames-test.js +++ b/src/validation/__tests__/UniqueVariableNames-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - UniqueVariableNames, - duplicateVariableMessage, -} from '../rules/UniqueVariableNames'; +import { UniqueVariableNames } from '../rules/UniqueVariableNames'; import { expectValidationErrors } from './harness'; @@ -17,13 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function duplicateVariable(name, l1, c1, l2, c2) { - return { - message: duplicateVariableMessage(name), - locations: [{ line: l1, column: c1 }, { line: l2, column: c2 }], - }; -} - describe('Validate: Unique variable names', () => { it('unique variable names', () => { expectValid(` @@ -38,10 +28,22 @@ describe('Validate: Unique variable names', () => { query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } `).to.deep.equal([ - duplicateVariable('x', 2, 16, 2, 25), - duplicateVariable('x', 2, 16, 2, 34), - duplicateVariable('x', 3, 16, 3, 28), - duplicateVariable('x', 4, 16, 4, 25), + { + message: 'There can be only one variable named "x".', + locations: [{ line: 2, column: 16 }, { line: 2, column: 25 }], + }, + { + message: 'There can be only one variable named "x".', + locations: [{ line: 2, column: 16 }, { line: 2, column: 34 }], + }, + { + message: 'There can be only one variable named "x".', + locations: [{ line: 3, column: 16 }, { line: 3, column: 28 }], + }, + { + message: 'There can be only one variable named "x".', + locations: [{ line: 4, column: 16 }, { line: 4, column: 25 }], + }, ]); }); }); diff --git a/src/validation/__tests__/ValuesOfCorrectType-test.js b/src/validation/__tests__/ValuesOfCorrectType-test.js index 19dcf33659..dbbec28af8 100644 --- a/src/validation/__tests__/ValuesOfCorrectType-test.js +++ b/src/validation/__tests__/ValuesOfCorrectType-test.js @@ -2,13 +2,7 @@ import { describe, it } from 'mocha'; -import { - ValuesOfCorrectType, - badValueMessage, - badEnumValueMessage, - requiredFieldMessage, - unknownFieldMessage, -} from '../rules/ValuesOfCorrectType'; +import { ValuesOfCorrectType } from '../rules/ValuesOfCorrectType'; import { expectValidationErrors } from './harness'; @@ -20,34 +14,6 @@ function expectValid(queryStr) { expectErrors(queryStr).to.deep.equal([]); } -function badValue(typeName, value, line, column, message) { - return { - message: badValueMessage(typeName, value, message), - locations: [{ line, column }], - }; -} - -function badEnumValue(typeName, value, line, column, message) { - return { - message: badEnumValueMessage(typeName, value, message), - locations: [{ line, column }], - }; -} - -function requiredField(typeName, fieldName, fieldTypeName, line, column) { - return { - message: requiredFieldMessage(typeName, fieldName, fieldTypeName), - locations: [{ line, column }], - }; -} - -function unknownField(typeName, fieldName, line, column, suggestedFields) { - return { - message: unknownFieldMessage(typeName, fieldName, suggestedFields), - locations: [{ line, column }], - }; -} - describe('Validate: Values of correct type', () => { describe('Valid values', () => { it('Good int value', () => { @@ -197,7 +163,12 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: 1) } } - `).to.deep.equal([badValue('String', '1', 4, 39)]); + `).to.deep.equal([ + { + message: 'Expected type String, found 1.', + locations: [{ line: 4, column: 39 }], + }, + ]); }); it('Float into String', () => { @@ -207,7 +178,12 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: 1.0) } } - `).to.deep.equal([badValue('String', '1.0', 4, 39)]); + `).to.deep.equal([ + { + message: 'Expected type String, found 1.0.', + locations: [{ line: 4, column: 39 }], + }, + ]); }); it('Boolean into String', () => { @@ -217,7 +193,12 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: true) } } - `).to.deep.equal([badValue('String', 'true', 4, 39)]); + `).to.deep.equal([ + { + message: 'Expected type String, found true.', + locations: [{ line: 4, column: 39 }], + }, + ]); }); it('Unquoted String into String', () => { @@ -227,7 +208,12 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: BAR) } } - `).to.deep.equal([badValue('String', 'BAR', 4, 39)]); + `).to.deep.equal([ + { + message: 'Expected type String, found BAR.', + locations: [{ line: 4, column: 39 }], + }, + ]); }); }); @@ -239,7 +225,12 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: "3") } } - `).to.deep.equal([badValue('Int', '"3"', 4, 33)]); + `).to.deep.equal([ + { + message: 'Expected type Int, found "3".', + locations: [{ line: 4, column: 33 }], + }, + ]); }); it('Big Int into Int', () => { @@ -249,7 +240,12 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 829384293849283498239482938) } } - `).to.deep.equal([badValue('Int', '829384293849283498239482938', 4, 33)]); + `).to.deep.equal([ + { + message: 'Expected type Int, found 829384293849283498239482938.', + locations: [{ line: 4, column: 33 }], + }, + ]); }); it('Unquoted String into Int', () => { @@ -259,7 +255,12 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: FOO) } } - `).to.deep.equal([badValue('Int', 'FOO', 4, 33)]); + `).to.deep.equal([ + { + message: 'Expected type Int, found FOO.', + locations: [{ line: 4, column: 33 }], + }, + ]); }); it('Simple Float into Int', () => { @@ -269,7 +270,12 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 3.0) } } - `).to.deep.equal([badValue('Int', '3.0', 4, 33)]); + `).to.deep.equal([ + { + message: 'Expected type Int, found 3.0.', + locations: [{ line: 4, column: 33 }], + }, + ]); }); it('Float into Int', () => { @@ -279,7 +285,12 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 3.333) } } - `).to.deep.equal([badValue('Int', '3.333', 4, 33)]); + `).to.deep.equal([ + { + message: 'Expected type Int, found 3.333.', + locations: [{ line: 4, column: 33 }], + }, + ]); }); }); @@ -291,7 +302,12 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: "3.333") } } - `).to.deep.equal([badValue('Float', '"3.333"', 4, 37)]); + `).to.deep.equal([ + { + message: 'Expected type Float, found "3.333".', + locations: [{ line: 4, column: 37 }], + }, + ]); }); it('Boolean into Float', () => { @@ -301,7 +317,12 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: true) } } - `).to.deep.equal([badValue('Float', 'true', 4, 37)]); + `).to.deep.equal([ + { + message: 'Expected type Float, found true.', + locations: [{ line: 4, column: 37 }], + }, + ]); }); it('Unquoted into Float', () => { @@ -311,7 +332,12 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: FOO) } } - `).to.deep.equal([badValue('Float', 'FOO', 4, 37)]); + `).to.deep.equal([ + { + message: 'Expected type Float, found FOO.', + locations: [{ line: 4, column: 37 }], + }, + ]); }); }); @@ -323,7 +349,12 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: 2) } } - `).to.deep.equal([badValue('Boolean', '2', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type Boolean, found 2.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Float into Boolean', () => { @@ -333,7 +364,12 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: 1.0) } } - `).to.deep.equal([badValue('Boolean', '1.0', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type Boolean, found 1.0.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('String into Boolean', () => { @@ -343,7 +379,12 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: "true") } } - `).to.deep.equal([badValue('Boolean', '"true"', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type Boolean, found "true".', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Unquoted into Boolean', () => { @@ -353,7 +394,12 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: TRUE) } } - `).to.deep.equal([badValue('Boolean', 'TRUE', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type Boolean, found TRUE.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); }); @@ -365,7 +411,12 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: 1.0) } } - `).to.deep.equal([badValue('ID', '1.0', 4, 31)]); + `).to.deep.equal([ + { + message: 'Expected type ID, found 1.0.', + locations: [{ line: 4, column: 31 }], + }, + ]); }); it('Boolean into ID', () => { @@ -375,7 +426,12 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: true) } } - `).to.deep.equal([badValue('ID', 'true', 4, 31)]); + `).to.deep.equal([ + { + message: 'Expected type ID, found true.', + locations: [{ line: 4, column: 31 }], + }, + ]); }); it('Unquoted into ID', () => { @@ -385,7 +441,12 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: SOMETHING) } } - `).to.deep.equal([badValue('ID', 'SOMETHING', 4, 31)]); + `).to.deep.equal([ + { + message: 'Expected type ID, found SOMETHING.', + locations: [{ line: 4, column: 31 }], + }, + ]); }); }); @@ -397,7 +458,12 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: 2) } } - `).to.deep.equal([badValue('DogCommand', '2', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type DogCommand, found 2.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Float into Enum', () => { @@ -407,7 +473,12 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: 1.0) } } - `).to.deep.equal([badValue('DogCommand', '1.0', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type DogCommand, found 1.0.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('String into Enum', () => { @@ -417,7 +488,13 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: "SIT") } } - `).to.deep.equal([badEnumValue('DogCommand', '"SIT"', 4, 41, ['SIT'])]); + `).to.deep.equal([ + { + message: + 'Expected type DogCommand, found "SIT". Did you mean the enum value SIT?', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Boolean into Enum', () => { @@ -427,7 +504,12 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: true) } } - `).to.deep.equal([badValue('DogCommand', 'true', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type DogCommand, found true.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Unknown Enum Value into Enum', () => { @@ -437,7 +519,12 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: JUGGLE) } } - `).to.deep.equal([badValue('DogCommand', 'JUGGLE', 4, 41)]); + `).to.deep.equal([ + { + message: 'Expected type DogCommand, found JUGGLE.', + locations: [{ line: 4, column: 41 }], + }, + ]); }); it('Different case Enum Value into Enum', () => { @@ -447,7 +534,13 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: sit) } } - `).to.deep.equal([badEnumValue('DogCommand', 'sit', 4, 41, ['SIT'])]); + `).to.deep.equal([ + { + message: + 'Expected type DogCommand, found sit. Did you mean the enum value SIT?', + locations: [{ line: 4, column: 41 }], + }, + ]); }); }); @@ -501,7 +594,12 @@ describe('Validate: Values of correct type', () => { stringListArgField(stringListArg: ["one", 2]) } } - `).to.deep.equal([badValue('String', '2', 4, 55)]); + `).to.deep.equal([ + { + message: 'Expected type String, found 2.', + locations: [{ line: 4, column: 55 }], + }, + ]); }); it('Single value of incorrect type', () => { @@ -511,7 +609,12 @@ describe('Validate: Values of correct type', () => { stringListArgField(stringListArg: 1) } } - `).to.deep.equal([badValue('[String]', '1', 4, 47)]); + `).to.deep.equal([ + { + message: 'Expected type [String], found 1.', + locations: [{ line: 4, column: 47 }], + }, + ]); }); }); @@ -626,8 +729,14 @@ describe('Validate: Values of correct type', () => { } } `).to.deep.equal([ - badValue('Int!', '"two"', 4, 32), - badValue('Int!', '"one"', 4, 45), + { + message: 'Expected type Int!, found "two".', + locations: [{ line: 4, column: 32 }], + }, + { + message: 'Expected type Int!, found "one".', + locations: [{ line: 4, column: 45 }], + }, ]); }); @@ -638,7 +747,12 @@ describe('Validate: Values of correct type', () => { multipleReqs(req1: "one") } } - `).to.deep.equal([badValue('Int!', '"one"', 4, 32)]); + `).to.deep.equal([ + { + message: 'Expected type Int!, found "one".', + locations: [{ line: 4, column: 32 }], + }, + ]); }); it('Null value', () => { @@ -648,7 +762,12 @@ describe('Validate: Values of correct type', () => { multipleReqs(req1: null) } } - `).to.deep.equal([badValue('Int!', 'null', 4, 32)]); + `).to.deep.equal([ + { + message: 'Expected type Int!, found null.', + locations: [{ line: 4, column: 32 }], + }, + ]); }); }); @@ -735,7 +854,11 @@ describe('Validate: Values of correct type', () => { } } `).to.deep.equal([ - requiredField('ComplexInput', 'requiredField', 'Boolean!', 4, 41), + { + message: + 'Field ComplexInput.requiredField of required type Boolean! was not provided.', + locations: [{ line: 4, column: 41 }], + }, ]); }); @@ -749,7 +872,12 @@ describe('Validate: Values of correct type', () => { }) } } - `).to.deep.equal([badValue('String', '2', 5, 40)]); + `).to.deep.equal([ + { + message: 'Expected type String, found 2.', + locations: [{ line: 5, column: 40 }], + }, + ]); }); it('Partial object, null to non-null field', () => { @@ -762,7 +890,12 @@ describe('Validate: Values of correct type', () => { }) } } - `).to.deep.equal([badValue('Boolean!', 'null', 6, 29)]); + `).to.deep.equal([ + { + message: 'Expected type Boolean!, found null.', + locations: [{ line: 6, column: 29 }], + }, + ]); }); it('Partial object, unknown field arg', () => { @@ -776,11 +909,11 @@ describe('Validate: Values of correct type', () => { } } `).to.deep.equal([ - unknownField('ComplexInput', 'unknownField', 6, 15, [ - 'nonNullField', - 'intField', - 'booleanField', - ]), + { + message: + 'Field "unknownField" is not defined by type ComplexInput. Did you mean nonNullField, intField, or booleanField?', + locations: [{ line: 6, column: 15 }], + }, ]); }); @@ -792,13 +925,11 @@ describe('Validate: Values of correct type', () => { `); expectedErrors.to.deep.equal([ - badValue( - 'Invalid', - '123', - 3, - 27, - 'Invalid scalar is always invalid: 123', - ), + { + message: + 'Expected type Invalid, found 123; Invalid scalar is always invalid: 123', + locations: [{ line: 3, column: 27 }], + }, ]); expectedErrors.to.have.nested.property( @@ -841,8 +972,14 @@ describe('Validate: Values of correct type', () => { } } `).to.deep.equal([ - badValue('Boolean!', '"yes"', 3, 28), - badValue('Boolean!', 'ENUM', 4, 28), + { + message: 'Expected type Boolean!, found "yes".', + locations: [{ line: 3, column: 28 }], + }, + { + message: 'Expected type Boolean!, found ENUM.', + locations: [{ line: 4, column: 28 }], + }, ]); }); }); @@ -883,9 +1020,18 @@ describe('Validate: Values of correct type', () => { dog { name } } `).to.deep.equal([ - badValue('Int!', 'null', 3, 22), - badValue('String!', 'null', 4, 25), - badValue('Boolean!', 'null', 5, 47), + { + message: 'Expected type Int!, found null.', + locations: [{ line: 3, column: 22 }], + }, + { + message: 'Expected type String!, found null.', + locations: [{ line: 4, column: 25 }], + }, + { + message: 'Expected type Boolean!, found null.', + locations: [{ line: 5, column: 47 }], + }, ]); }); @@ -899,9 +1045,18 @@ describe('Validate: Values of correct type', () => { dog { name } } `).to.deep.equal([ - badValue('Int', '"one"', 3, 21), - badValue('String', '4', 4, 24), - badValue('ComplexInput', '"notverycomplex"', 5, 30), + { + message: 'Expected type Int, found "one".', + locations: [{ line: 3, column: 21 }], + }, + { + message: 'Expected type String, found 4.', + locations: [{ line: 4, column: 24 }], + }, + { + message: 'Expected type ComplexInput, found "notverycomplex".', + locations: [{ line: 5, column: 30 }], + }, ]); }); @@ -913,8 +1068,14 @@ describe('Validate: Values of correct type', () => { dog { name } } `).to.deep.equal([ - badValue('Boolean!', '123', 3, 47), - badValue('Int', '"abc"', 3, 62), + { + message: 'Expected type Boolean!, found 123.', + locations: [{ line: 3, column: 47 }], + }, + { + message: 'Expected type Int, found "abc".', + locations: [{ line: 3, column: 62 }], + }, ]); }); @@ -924,7 +1085,11 @@ describe('Validate: Values of correct type', () => { dog { name } } `).to.deep.equal([ - requiredField('ComplexInput', 'requiredField', 'Boolean!', 2, 55), + { + message: + 'Field ComplexInput.requiredField of required type Boolean! was not provided.', + locations: [{ line: 2, column: 55 }], + }, ]); }); @@ -933,7 +1098,12 @@ describe('Validate: Values of correct type', () => { query InvalidItem($a: [String] = ["one", 2]) { dog { name } } - `).to.deep.equal([badValue('String', '2', 2, 50)]); + `).to.deep.equal([ + { + message: 'Expected type String, found 2.', + locations: [{ line: 2, column: 50 }], + }, + ]); }); }); }); diff --git a/src/validation/__tests__/VariablesAreInputTypes-test.js b/src/validation/__tests__/VariablesAreInputTypes-test.js index 1039f24fdd..a4132a6b6f 100644 --- a/src/validation/__tests__/VariablesAreInputTypes-test.js +++ b/src/validation/__tests__/VariablesAreInputTypes-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - VariablesAreInputTypes, - nonInputTypeOnVarMessage, -} from '../rules/VariablesAreInputTypes'; +import { VariablesAreInputTypes } from '../rules/VariablesAreInputTypes'; import { expectValidationErrors } from './harness'; @@ -34,15 +31,15 @@ describe('Validate: Variables are input types', () => { `).to.deep.equal([ { locations: [{ line: 2, column: 21 }], - message: nonInputTypeOnVarMessage('a', 'Dog'), + message: 'Variable "$a" cannot be non-input type "Dog".', }, { locations: [{ line: 2, column: 30 }], - message: nonInputTypeOnVarMessage('b', '[[CatOrDog!]]!'), + message: 'Variable "$b" cannot be non-input type "[[CatOrDog!]]!".', }, { locations: [{ line: 2, column: 50 }], - message: nonInputTypeOnVarMessage('c', 'Pet'), + message: 'Variable "$c" cannot be non-input type "Pet".', }, ]); }); diff --git a/src/validation/__tests__/VariablesInAllowedPosition-test.js b/src/validation/__tests__/VariablesInAllowedPosition-test.js index 2be79e0daf..ab58bb6f08 100644 --- a/src/validation/__tests__/VariablesInAllowedPosition-test.js +++ b/src/validation/__tests__/VariablesInAllowedPosition-test.js @@ -2,10 +2,7 @@ import { describe, it } from 'mocha'; -import { - VariablesInAllowedPosition, - badVarPosMessage, -} from '../rules/VariablesInAllowedPosition'; +import { VariablesInAllowedPosition } from '../rules/VariablesInAllowedPosition'; import { expectValidationErrors } from './harness'; @@ -165,7 +162,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('intArg', 'Int', 'Int!'), + message: + 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], }, ]); @@ -184,7 +182,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('intArg', 'Int', 'Int!'), + message: + 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', locations: [{ line: 6, column: 19 }, { line: 3, column: 43 }], }, ]); @@ -207,7 +206,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('intArg', 'Int', 'Int!'), + message: + 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', locations: [{ line: 10, column: 19 }, { line: 7, column: 43 }], }, ]); @@ -222,7 +222,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('stringVar', 'String', 'Boolean'), + message: + 'Variable "$stringVar" of type "String" used in position expecting type "Boolean".', locations: [{ line: 2, column: 19 }, { line: 4, column: 39 }], }, ]); @@ -237,7 +238,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('stringVar', 'String', '[String]'), + message: + 'Variable "$stringVar" of type "String" used in position expecting type "[String]".', locations: [{ line: 2, column: 19 }, { line: 4, column: 45 }], }, ]); @@ -250,7 +252,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('boolVar', 'Boolean', 'Boolean!'), + message: + 'Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!".', locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], }, ]); @@ -263,7 +266,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('stringVar', 'String', 'Boolean!'), + message: + 'Variable "$stringVar" of type "String" used in position expecting type "Boolean!".', locations: [{ line: 2, column: 19 }, { line: 3, column: 26 }], }, ]); @@ -279,7 +283,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('stringListVar', '[String]', '[String!]'), + message: + 'Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]".', locations: [{ line: 2, column: 19 }, { line: 5, column: 59 }], }, ]); @@ -295,7 +300,8 @@ describe('Validate: Variables are in allowed positions', () => { } `).to.deep.equal([ { - message: badVarPosMessage('intVar', 'Int', 'Int!'), + message: + 'Variable "$intVar" of type "Int" used in position expecting type "Int!".', locations: [{ line: 2, column: 21 }, { line: 4, column: 47 }], }, ]); diff --git a/src/validation/rules/ExecutableDefinitions.js b/src/validation/rules/ExecutableDefinitions.js index 83da1fd8f5..2b2e1d4380 100644 --- a/src/validation/rules/ExecutableDefinitions.js +++ b/src/validation/rules/ExecutableDefinitions.js @@ -8,10 +8,6 @@ import { isExecutableDefinitionNode } from '../../language/predicates'; import { type ASTValidationContext } from '../ValidationContext'; -export function nonExecutableDefinitionMessage(defName: string): string { - return `The ${defName} definition is not executable.`; -} - /** * Executable definitions * @@ -25,14 +21,14 @@ export function ExecutableDefinitions( Document(node) { for (const definition of node.definitions) { if (!isExecutableDefinitionNode(definition)) { + const defName = + definition.kind === Kind.SCHEMA_DEFINITION || + definition.kind === Kind.SCHEMA_EXTENSION + ? 'schema' + : definition.name.value; context.reportError( new GraphQLError( - nonExecutableDefinitionMessage( - definition.kind === Kind.SCHEMA_DEFINITION || - definition.kind === Kind.SCHEMA_EXTENSION - ? 'schema' - : definition.name.value, - ), + `The ${defName} definition is not executable.`, definition, ), ); diff --git a/src/validation/rules/FieldsOnCorrectType.js b/src/validation/rules/FieldsOnCorrectType.js index bc628a961f..d2d83e8ff0 100644 --- a/src/validation/rules/FieldsOnCorrectType.js +++ b/src/validation/rules/FieldsOnCorrectType.js @@ -18,21 +18,6 @@ import { import { type ValidationContext } from '../ValidationContext'; -export function undefinedFieldMessage( - fieldName: string, - type: string, - suggestedTypeNames: $ReadOnlyArray, - suggestedFieldNames: $ReadOnlyArray, -): string { - const quotedTypeNames = suggestedTypeNames.map(x => `"${x}"`); - const quotedFieldNames = suggestedFieldNames.map(x => `"${x}"`); - return ( - `Cannot query field "${fieldName}" on type "${type}".` + - (didYouMean('to use an inline fragment on', quotedTypeNames) || - didYouMean(quotedFieldNames)) - ); -} - /** * Fields on correct type * @@ -62,14 +47,13 @@ export function FieldsOnCorrectType(context: ValidationContext): ASTVisitor { : getSuggestedFieldNames(schema, type, fieldName); // Report an error, including helpful suggestions. + const quotedTypeNames = suggestedTypeNames.map(x => `"${x}"`); + const quotedFieldNames = suggestedFieldNames.map(x => `"${x}"`); context.reportError( new GraphQLError( - undefinedFieldMessage( - fieldName, - type.name, - suggestedTypeNames, - suggestedFieldNames, - ), + `Cannot query field "${fieldName}" on type "${type.name}".` + + (didYouMean('to use an inline fragment on', quotedTypeNames) || + didYouMean(quotedFieldNames)), node, ), ); diff --git a/src/validation/rules/FragmentsOnCompositeTypes.js b/src/validation/rules/FragmentsOnCompositeTypes.js index 5eb3f22a66..5d3680cc29 100644 --- a/src/validation/rules/FragmentsOnCompositeTypes.js +++ b/src/validation/rules/FragmentsOnCompositeTypes.js @@ -11,17 +11,6 @@ import { typeFromAST } from '../../utilities/typeFromAST'; import { type ValidationContext } from '../ValidationContext'; -export function inlineFragmentOnNonCompositeErrorMessage(type: string): string { - return `Fragment cannot condition on non composite type "${type}".`; -} - -export function fragmentOnNonCompositeErrorMessage( - fragName: string, - type: string, -): string { - return `Fragment "${fragName}" cannot condition on non composite type "${type}".`; -} - /** * Fragments on composite type * @@ -38,9 +27,10 @@ export function FragmentsOnCompositeTypes( if (typeCondition) { const type = typeFromAST(context.getSchema(), typeCondition); if (type && !isCompositeType(type)) { + const typeStr = print(typeCondition); context.reportError( new GraphQLError( - inlineFragmentOnNonCompositeErrorMessage(print(typeCondition)), + `Fragment cannot condition on non composite type "${typeStr}".`, typeCondition, ), ); @@ -50,12 +40,10 @@ export function FragmentsOnCompositeTypes( FragmentDefinition(node) { const type = typeFromAST(context.getSchema(), node.typeCondition); if (type && !isCompositeType(type)) { + const typeStr = print(node.typeCondition); context.reportError( new GraphQLError( - fragmentOnNonCompositeErrorMessage( - node.name.value, - print(node.typeCondition), - ), + `Fragment "${node.name.value}" cannot condition on non composite type "${typeStr}".`, node.typeCondition, ), ); diff --git a/src/validation/rules/KnownArgumentNames.js b/src/validation/rules/KnownArgumentNames.js index af68d93764..61d3e1d99a 100644 --- a/src/validation/rules/KnownArgumentNames.js +++ b/src/validation/rules/KnownArgumentNames.js @@ -15,29 +15,6 @@ import { type SDLValidationContext, } from '../ValidationContext'; -export function unknownArgMessage( - argName: string, - fieldName: string, - typeName: string, - suggestedArgs: $ReadOnlyArray, -): string { - return ( - `Unknown argument "${argName}" on field "${fieldName}" of type "${typeName}".` + - didYouMean(suggestedArgs.map(x => `"${x}"`)) - ); -} - -export function unknownDirectiveArgMessage( - argName: string, - directiveName: string, - suggestedArgs: $ReadOnlyArray, -): string { - return ( - `Unknown argument "${argName}" on directive "@${directiveName}".` + - didYouMean(suggestedArgs.map(x => `"${x}"`)) - ); -} - /** * Known argument names * @@ -55,14 +32,11 @@ export function KnownArgumentNames(context: ValidationContext): ASTVisitor { if (!argDef && fieldDef && parentType) { const argName = argNode.name.value; const knownArgsNames = fieldDef.args.map(arg => arg.name); + const suggestions = suggestionList(argName, knownArgsNames); context.reportError( new GraphQLError( - unknownArgMessage( - argName, - fieldDef.name, - parentType.name, - suggestionList(argName, knownArgsNames), - ), + `Unknown argument "${argName}" on field "${fieldDef.name}" of type "${parentType.name}".` + + didYouMean(suggestions.map(x => `"${x}"`)), argNode, ), ); @@ -106,7 +80,8 @@ export function KnownArgumentNamesOnDirectives( const suggestions = suggestionList(argName, knownArgs); context.reportError( new GraphQLError( - unknownDirectiveArgMessage(argName, directiveName, suggestions), + `Unknown argument "${argName}" on directive "@${directiveName}".` + + didYouMean(suggestions.map(x => `"${x}"`)), argNode, ), ); diff --git a/src/validation/rules/KnownDirectives.js b/src/validation/rules/KnownDirectives.js index 4506c31dc0..f1c40f4626 100644 --- a/src/validation/rules/KnownDirectives.js +++ b/src/validation/rules/KnownDirectives.js @@ -13,17 +13,6 @@ import { type SDLValidationContext, } from '../ValidationContext'; -export function unknownDirectiveMessage(directiveName: string): string { - return `Unknown directive "${directiveName}".`; -} - -export function misplacedDirectiveMessage( - directiveName: string, - location: string, -): string { - return `Directive "${directiveName}" may not be used on ${location}.`; -} - /** * Known directives * @@ -57,15 +46,16 @@ export function KnownDirectives( if (!locations) { context.reportError( - new GraphQLError(unknownDirectiveMessage(name), node), + new GraphQLError(`Unknown directive "${name}".`, node), ); return; } + const candidateLocation = getDirectiveLocationForASTPath(ancestors); if (candidateLocation && locations.indexOf(candidateLocation) === -1) { context.reportError( new GraphQLError( - misplacedDirectiveMessage(name, candidateLocation), + `Directive "${name}" may not be used on ${candidateLocation}.`, node, ), ); diff --git a/src/validation/rules/KnownFragmentNames.js b/src/validation/rules/KnownFragmentNames.js index 81b607d322..a023affec9 100644 --- a/src/validation/rules/KnownFragmentNames.js +++ b/src/validation/rules/KnownFragmentNames.js @@ -5,10 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ValidationContext } from '../ValidationContext'; -export function unknownFragmentMessage(fragName: string): string { - return `Unknown fragment "${fragName}".`; -} - /** * Known fragment names * @@ -22,7 +18,7 @@ export function KnownFragmentNames(context: ValidationContext): ASTVisitor { const fragment = context.getFragment(fragmentName); if (!fragment) { context.reportError( - new GraphQLError(unknownFragmentMessage(fragmentName), node.name), + new GraphQLError(`Unknown fragment "${fragmentName}".`, node.name), ); } }, diff --git a/src/validation/rules/KnownTypeNames.js b/src/validation/rules/KnownTypeNames.js index f6b491ed7c..338096e6fb 100644 --- a/src/validation/rules/KnownTypeNames.js +++ b/src/validation/rules/KnownTypeNames.js @@ -20,16 +20,6 @@ import { type SDLValidationContext, } from '../ValidationContext'; -export function unknownTypeMessage( - typeName: string, - suggestedTypes: $ReadOnlyArray, -): string { - return ( - `Unknown type "${typeName}".` + - didYouMean(suggestedTypes.map(x => `"${x}"`)) - ); -} - /** * Known type names * @@ -68,7 +58,11 @@ export function KnownTypeNames( isSDL ? specifiedScalarsNames.concat(typeNames) : typeNames, ); context.reportError( - new GraphQLError(unknownTypeMessage(typeName, suggestedTypes), node), + new GraphQLError( + `Unknown type "${typeName}".` + + didYouMean(suggestedTypes.map(x => `"${x}"`)), + node, + ), ); } }, diff --git a/src/validation/rules/LoneAnonymousOperation.js b/src/validation/rules/LoneAnonymousOperation.js index 363d7c45ad..b78fc7d262 100644 --- a/src/validation/rules/LoneAnonymousOperation.js +++ b/src/validation/rules/LoneAnonymousOperation.js @@ -7,10 +7,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ASTValidationContext } from '../ValidationContext'; -export function anonOperationNotAloneMessage(): string { - return 'This anonymous operation must be the only defined operation.'; -} - /** * Lone anonymous operation * @@ -30,7 +26,10 @@ export function LoneAnonymousOperation( OperationDefinition(node) { if (!node.name && operationCount > 1) { context.reportError( - new GraphQLError(anonOperationNotAloneMessage(), node), + new GraphQLError( + 'This anonymous operation must be the only defined operation.', + node, + ), ); } }, diff --git a/src/validation/rules/LoneSchemaDefinition.js b/src/validation/rules/LoneSchemaDefinition.js index 38edd610fe..b44953e570 100644 --- a/src/validation/rules/LoneSchemaDefinition.js +++ b/src/validation/rules/LoneSchemaDefinition.js @@ -5,14 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type SDLValidationContext } from '../ValidationContext'; -export function schemaDefinitionNotAloneMessage(): string { - return 'Must provide only one schema definition.'; -} - -export function canNotDefineSchemaWithinExtensionMessage(): string { - return 'Cannot define a new schema within a schema extension.'; -} - /** * Lone Schema definition * @@ -34,14 +26,17 @@ export function LoneSchemaDefinition( SchemaDefinition(node) { if (alreadyDefined) { context.reportError( - new GraphQLError(canNotDefineSchemaWithinExtensionMessage(), node), + new GraphQLError( + 'Cannot define a new schema within a schema extension.', + node, + ), ); return; } if (schemaDefinitionsCount > 0) { context.reportError( - new GraphQLError(schemaDefinitionNotAloneMessage(), node), + new GraphQLError('Must provide only one schema definition.', node), ); } ++schemaDefinitionsCount; diff --git a/src/validation/rules/NoFragmentCycles.js b/src/validation/rules/NoFragmentCycles.js index 1e62a4a6b0..74d171a34a 100644 --- a/src/validation/rules/NoFragmentCycles.js +++ b/src/validation/rules/NoFragmentCycles.js @@ -7,14 +7,6 @@ import { type FragmentDefinitionNode } from '../../language/ast'; import { type ASTValidationContext } from '../ValidationContext'; -export function cycleErrorMessage( - fragName: string, - spreadNames: $ReadOnlyArray, -): string { - const via = spreadNames.length ? ' via ' + spreadNames.join(', ') : ''; - return `Cannot spread fragment "${fragName}" within itself${via}.`; -} - export function NoFragmentCycles(context: ASTValidationContext): ASTVisitor { // Tracks already visited fragments to maintain O(N) and to ensure that cycles // are not redundantly reported. @@ -64,10 +56,12 @@ export function NoFragmentCycles(context: ASTValidationContext): ASTVisitor { } } else { const cyclePath = spreadPath.slice(cycleIndex); - const fragmentNames = cyclePath.slice(0, -1).map(s => s.name.value); + const viaNames = cyclePath.slice(0, -1).map(s => s.name.value); + context.reportError( new GraphQLError( - cycleErrorMessage(spreadName, fragmentNames), + `Cannot spread fragment "${spreadName}" within itself` + + (viaNames.length > 0 ? ` via ${viaNames.join(', ')}.` : '.'), cyclePath, ), ); diff --git a/src/validation/rules/NoUndefinedVariables.js b/src/validation/rules/NoUndefinedVariables.js index aee4f9ef06..8c6f9578e2 100644 --- a/src/validation/rules/NoUndefinedVariables.js +++ b/src/validation/rules/NoUndefinedVariables.js @@ -5,12 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ValidationContext } from '../ValidationContext'; -export function undefinedVarMessage(varName: string, opName: ?string): string { - return opName - ? `Variable "$${varName}" is not defined by operation "${opName}".` - : `Variable "$${varName}" is not defined.`; -} - /** * No undefined variables * @@ -33,10 +27,9 @@ export function NoUndefinedVariables(context: ValidationContext): ASTVisitor { if (variableNameDefined[varName] !== true) { context.reportError( new GraphQLError( - undefinedVarMessage( - varName, - operation.name && operation.name.value, - ), + operation.name + ? `Variable "$${varName}" is not defined by operation "${operation.name.value}".` + : `Variable "$${varName}" is not defined.`, [node, operation], ), ); diff --git a/src/validation/rules/NoUnusedFragments.js b/src/validation/rules/NoUnusedFragments.js index 5c0847da20..47135a5d4b 100644 --- a/src/validation/rules/NoUnusedFragments.js +++ b/src/validation/rules/NoUnusedFragments.js @@ -5,10 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ASTValidationContext } from '../ValidationContext'; -export function unusedFragMessage(fragName: string): string { - return `Fragment "${fragName}" is never used.`; -} - /** * No unused fragments * @@ -43,7 +39,10 @@ export function NoUnusedFragments(context: ASTValidationContext): ASTVisitor { const fragName = fragmentDef.name.value; if (fragmentNameUsed[fragName] !== true) { context.reportError( - new GraphQLError(unusedFragMessage(fragName), fragmentDef), + new GraphQLError( + `Fragment "${fragName}" is never used.`, + fragmentDef, + ), ); } } diff --git a/src/validation/rules/NoUnusedVariables.js b/src/validation/rules/NoUnusedVariables.js index a8055de4bc..a9fed2d067 100644 --- a/src/validation/rules/NoUnusedVariables.js +++ b/src/validation/rules/NoUnusedVariables.js @@ -5,15 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ValidationContext } from '../ValidationContext'; -export function unusedVariableMessage( - varName: string, - opName: ?string, -): string { - return opName - ? `Variable "$${varName}" is never used in operation "${opName}".` - : `Variable "$${varName}" is never used.`; -} - /** * No unused variables * @@ -31,7 +22,6 @@ export function NoUnusedVariables(context: ValidationContext): ASTVisitor { leave(operation) { const variableNameUsed = Object.create(null); const usages = context.getRecursiveVariableUsages(operation); - const opName = operation.name ? operation.name.value : null; for (const { node } of usages) { variableNameUsed[node.name.value] = true; @@ -42,7 +32,9 @@ export function NoUnusedVariables(context: ValidationContext): ASTVisitor { if (variableNameUsed[variableName] !== true) { context.reportError( new GraphQLError( - unusedVariableMessage(variableName, opName), + operation.name + ? `Variable "$${variableName}" is never used in operation "${operation.name.value}".` + : `Variable "$${variableName}" is never used.`, variableDef, ), ); diff --git a/src/validation/rules/OverlappingFieldsCanBeMerged.js b/src/validation/rules/OverlappingFieldsCanBeMerged.js index a9db2291da..e7a6581091 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMerged.js +++ b/src/validation/rules/OverlappingFieldsCanBeMerged.js @@ -35,16 +35,6 @@ import { typeFromAST } from '../../utilities/typeFromAST'; import { type ValidationContext } from '../ValidationContext'; -export function fieldsConflictMessage( - responseName: string, - reason: ConflictReasonMessage, -): string { - return ( - `Fields "${responseName}" conflict because ${reasonMessage(reason)}. ` + - 'Use different aliases on the fields to fetch both if this was intentional.' - ); -} - function reasonMessage(reason: ConflictReasonMessage): string { if (Array.isArray(reason)) { return reason @@ -89,9 +79,10 @@ export function OverlappingFieldsCanBeMerged( selectionSet, ); for (const [[responseName, reason], fields1, fields2] of conflicts) { + const reasonMsg = reasonMessage(reason); context.reportError( new GraphQLError( - fieldsConflictMessage(responseName, reason), + `Fields "${responseName}" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`, fields1.concat(fields2), ), ); diff --git a/src/validation/rules/PossibleFragmentSpreads.js b/src/validation/rules/PossibleFragmentSpreads.js index 29f5a3e26f..ea84c6f61a 100644 --- a/src/validation/rules/PossibleFragmentSpreads.js +++ b/src/validation/rules/PossibleFragmentSpreads.js @@ -13,21 +13,6 @@ import { doTypesOverlap } from '../../utilities/typeComparators'; import { type ValidationContext } from '../ValidationContext'; -export function typeIncompatibleSpreadMessage( - fragName: string, - parentType: string, - fragType: string, -): string { - return `Fragment "${fragName}" cannot be spread here as objects of type "${parentType}" can never be of type "${fragType}".`; -} - -export function typeIncompatibleAnonSpreadMessage( - parentType: string, - fragType: string, -): string { - return `Fragment cannot be spread here as objects of type "${parentType}" can never be of type "${fragType}".`; -} - /** * Possible fragment spread * @@ -47,12 +32,11 @@ export function PossibleFragmentSpreads( isCompositeType(parentType) && !doTypesOverlap(context.getSchema(), fragType, parentType) ) { + const parentTypeStr = inspect(parentType); + const fragTypeStr = inspect(fragType); context.reportError( new GraphQLError( - typeIncompatibleAnonSpreadMessage( - inspect(parentType), - inspect(fragType), - ), + `Fragment cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, node, ), ); @@ -67,13 +51,11 @@ export function PossibleFragmentSpreads( parentType && !doTypesOverlap(context.getSchema(), fragType, parentType) ) { + const parentTypeStr = inspect(parentType); + const fragTypeStr = inspect(fragType); context.reportError( new GraphQLError( - typeIncompatibleSpreadMessage( - fragName, - inspect(parentType), - inspect(fragType), - ), + `Fragment "${fragName}" cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, node, ), ); diff --git a/src/validation/rules/PossibleTypeExtensions.js b/src/validation/rules/PossibleTypeExtensions.js index 9d6f68efeb..a885f29278 100644 --- a/src/validation/rules/PossibleTypeExtensions.js +++ b/src/validation/rules/PossibleTypeExtensions.js @@ -20,23 +20,6 @@ import { import { type SDLValidationContext } from '../ValidationContext'; -export function extendingUnknownTypeMessage( - typeName: string, - suggestedTypes: $ReadOnlyArray, -): string { - return ( - `Cannot extend type "${typeName}" because it is not defined.` + - didYouMean(suggestedTypes.map(x => `"${x}"`)) - ); -} - -export function extendingDifferentTypeKindMessage( - typeName: string, - kind: string, -): string { - return `Cannot extend non-${kind} type "${typeName}".`; -} - /** * Possible type extension * @@ -68,29 +51,20 @@ export function PossibleTypeExtensions( const defNode = definedTypes[typeName]; const existingType = schema && schema.getType(typeName); + let expectedKind; if (defNode) { - const expectedKind = defKindToExtKind[defNode.kind]; - if (expectedKind !== node.kind) { - context.reportError( - new GraphQLError( - extendingDifferentTypeKindMessage( - typeName, - extensionKindToTypeName(expectedKind), - ), - [defNode, node], - ), - ); - } + expectedKind = defKindToExtKind[defNode.kind]; } else if (existingType) { - const expectedKind = typeToExtKind(existingType); + expectedKind = typeToExtKind(existingType); + } + + if (expectedKind) { if (expectedKind !== node.kind) { + const kindStr = extensionKindToTypeName(expectedKind); context.reportError( new GraphQLError( - extendingDifferentTypeKindMessage( - typeName, - extensionKindToTypeName(expectedKind), - ), - node, + `Cannot extend non-${kindStr} type "${typeName}".`, + defNode ? [defNode, node] : node, ), ); } @@ -103,7 +77,8 @@ export function PossibleTypeExtensions( const suggestedTypes = suggestionList(typeName, allTypeNames); context.reportError( new GraphQLError( - extendingUnknownTypeMessage(typeName, suggestedTypes), + `Cannot extend type "${typeName}" because it is not defined.` + + didYouMean(suggestedTypes.map(x => `"${x}"`)), node.name, ), ); diff --git a/src/validation/rules/ProvidedRequiredArguments.js b/src/validation/rules/ProvidedRequiredArguments.js index c8d0a2320c..2a019304b2 100644 --- a/src/validation/rules/ProvidedRequiredArguments.js +++ b/src/validation/rules/ProvidedRequiredArguments.js @@ -57,13 +57,10 @@ export function ProvidedRequiredArguments( for (const argDef of fieldDef.args) { const argNode = argNodeMap[argDef.name]; if (!argNode && isRequiredArgument(argDef)) { + const argTypeStr = inspect(argDef.type); context.reportError( new GraphQLError( - missingFieldArgMessage( - fieldDef.name, - argDef.name, - inspect(argDef.type), - ), + `Field "${fieldDef.name}" argument "${argDef.name}" of type "${argTypeStr}" is required, but it was not provided.`, fieldNode, ), ); @@ -113,13 +110,13 @@ export function ProvidedRequiredArgumentsOnDirectives( for (const argName of Object.keys(requiredArgs)) { if (!argNodeMap[argName]) { const argType = requiredArgs[argName].type; + const argTypeStr = isType(argType) + ? inspect(argType) + : print(argType); + context.reportError( new GraphQLError( - missingDirectiveArgMessage( - directiveName, - argName, - isType(argType) ? inspect(argType) : print(argType), - ), + `Directive "@${directiveName}" argument "${argName}" of type "${argTypeStr}" is required, but it was not provided.`, directiveNode, ), ); diff --git a/src/validation/rules/ScalarLeafs.js b/src/validation/rules/ScalarLeafs.js index 13a71b69b8..93c82715bf 100644 --- a/src/validation/rules/ScalarLeafs.js +++ b/src/validation/rules/ScalarLeafs.js @@ -39,17 +39,21 @@ export function ScalarLeafs(context: ValidationContext): ASTVisitor { if (type) { if (isLeafType(getNamedType(type))) { if (selectionSet) { + const fieldName = node.name.value; + const typeStr = inspect(type); context.reportError( new GraphQLError( - noSubselectionAllowedMessage(node.name.value, inspect(type)), + `Field "${fieldName}" must not have a selection since type "${typeStr}" has no subfields.`, selectionSet, ), ); } } else if (!selectionSet) { + const fieldName = node.name.value; + const typeStr = inspect(type); context.reportError( new GraphQLError( - requiredSubselectionMessage(node.name.value, inspect(type)), + `Field "${fieldName}" of type "${typeStr}" must have a selection of subfields. Did you mean "${fieldName} { ... }"?`, node, ), ); diff --git a/src/validation/rules/SingleFieldSubscriptions.js b/src/validation/rules/SingleFieldSubscriptions.js index 3714d3412b..2e709ee66d 100644 --- a/src/validation/rules/SingleFieldSubscriptions.js +++ b/src/validation/rules/SingleFieldSubscriptions.js @@ -7,12 +7,6 @@ import { type OperationDefinitionNode } from '../../language/ast'; import { type ASTValidationContext } from '../ValidationContext'; -export function singleFieldOnlyMessage(name: ?string): string { - return name - ? `Subscription "${name}" must select only one top level field.` - : 'Anonymous Subscription must select only one top level field.'; -} - /** * Subscriptions must only include one field. * @@ -27,7 +21,9 @@ export function SingleFieldSubscriptions( if (node.selectionSet.selections.length !== 1) { context.reportError( new GraphQLError( - singleFieldOnlyMessage(node.name && node.name.value), + node.name + ? `Subscription "${node.name.value}" must select only one top level field.` + : 'Anonymous Subscription must select only one top level field.', node.selectionSet.selections.slice(1), ), ); diff --git a/src/validation/rules/UniqueArgumentNames.js b/src/validation/rules/UniqueArgumentNames.js index c0372ef3aa..f98e87acd0 100644 --- a/src/validation/rules/UniqueArgumentNames.js +++ b/src/validation/rules/UniqueArgumentNames.js @@ -28,10 +28,10 @@ export function UniqueArgumentNames(context: ASTValidationContext): ASTVisitor { const argName = node.name.value; if (knownArgNames[argName]) { context.reportError( - new GraphQLError(duplicateArgMessage(argName), [ - knownArgNames[argName], - node.name, - ]), + new GraphQLError( + `There can be only one argument named "${argName}".`, + [knownArgNames[argName], node.name], + ), ); } else { knownArgNames[argName] = node.name; diff --git a/src/validation/rules/UniqueDirectiveNames.js b/src/validation/rules/UniqueDirectiveNames.js index 7e4458d3a4..b020bf5f9c 100644 --- a/src/validation/rules/UniqueDirectiveNames.js +++ b/src/validation/rules/UniqueDirectiveNames.js @@ -31,7 +31,7 @@ export function UniqueDirectiveNames( if (schema && schema.getDirective(directiveName)) { context.reportError( new GraphQLError( - existedDirectiveNameMessage(directiveName), + `Directive "${directiveName}" already exists in the schema. It cannot be redefined.`, node.name, ), ); @@ -40,10 +40,10 @@ export function UniqueDirectiveNames( if (knownDirectiveNames[directiveName]) { context.reportError( - new GraphQLError(duplicateDirectiveNameMessage(directiveName), [ - knownDirectiveNames[directiveName], - node.name, - ]), + new GraphQLError( + `There can be only one directive named "${directiveName}".`, + [knownDirectiveNames[directiveName], node.name], + ), ); } else { knownDirectiveNames[directiveName] = node.name; diff --git a/src/validation/rules/UniqueDirectivesPerLocation.js b/src/validation/rules/UniqueDirectivesPerLocation.js index 32cbce3003..2e4e2e7fc6 100644 --- a/src/validation/rules/UniqueDirectivesPerLocation.js +++ b/src/validation/rules/UniqueDirectivesPerLocation.js @@ -13,10 +13,6 @@ import { type ValidationContext, } from '../ValidationContext'; -export function duplicateDirectiveMessage(directiveName: string): string { - return `The directive "${directiveName}" can only be used once at this location.`; -} - /** * Unique directive names per location * @@ -59,10 +55,10 @@ export function UniqueDirectivesPerLocation( if (uniqueDirectiveMap[directiveName]) { if (knownDirectives[directiveName]) { context.reportError( - new GraphQLError(duplicateDirectiveMessage(directiveName), [ - knownDirectives[directiveName], - directive, - ]), + new GraphQLError( + `The directive "${directiveName}" can only be used once at this location.`, + [knownDirectives[directiveName], directive], + ), ); } else { knownDirectives[directiveName] = directive; diff --git a/src/validation/rules/UniqueEnumValueNames.js b/src/validation/rules/UniqueEnumValueNames.js index a2a64e6251..c809cafb3b 100644 --- a/src/validation/rules/UniqueEnumValueNames.js +++ b/src/validation/rules/UniqueEnumValueNames.js @@ -6,20 +6,6 @@ import { isEnumType } from '../../type/definition'; import { type SDLValidationContext } from '../ValidationContext'; -export function duplicateEnumValueNameMessage( - typeName: string, - valueName: string, -): string { - return `Enum value "${typeName}.${valueName}" can only be defined once.`; -} - -export function existedEnumValueNameMessage( - typeName: string, - valueName: string, -): string { - return `Enum value "${typeName}.${valueName}" already exists in the schema. It cannot also be defined in this type extension.`; -} - /** * Unique enum value names * @@ -54,14 +40,14 @@ export function UniqueEnumValueNames( if (isEnumType(existingType) && existingType.getValue(valueName)) { context.reportError( new GraphQLError( - existedEnumValueNameMessage(typeName, valueName), + `Enum value "${typeName}.${valueName}" already exists in the schema. It cannot also be defined in this type extension.`, valueDef.name, ), ); } else if (valueNames[valueName]) { context.reportError( new GraphQLError( - duplicateEnumValueNameMessage(typeName, valueName), + `Enum value "${typeName}.${valueName}" can only be defined once.`, [valueNames[valueName], valueDef.name], ), ); diff --git a/src/validation/rules/UniqueFieldDefinitionNames.js b/src/validation/rules/UniqueFieldDefinitionNames.js index 5b78913dea..8b0d93633e 100644 --- a/src/validation/rules/UniqueFieldDefinitionNames.js +++ b/src/validation/rules/UniqueFieldDefinitionNames.js @@ -10,20 +10,6 @@ import { import { type SDLValidationContext } from '../ValidationContext'; -export function duplicateFieldDefinitionNameMessage( - typeName: string, - fieldName: string, -): string { - return `Field "${typeName}.${fieldName}" can only be defined once.`; -} - -export function existedFieldDefinitionNameMessage( - typeName: string, - fieldName: string, -): string { - return `Field "${typeName}.${fieldName}" already exists in the schema. It cannot also be defined in this type extension.`; -} - /** * Unique field definition names * @@ -61,14 +47,14 @@ export function UniqueFieldDefinitionNames( if (hasField(existingTypeMap[typeName], fieldName)) { context.reportError( new GraphQLError( - existedFieldDefinitionNameMessage(typeName, fieldName), + `Field "${typeName}.${fieldName}" already exists in the schema. It cannot also be defined in this type extension.`, fieldDef.name, ), ); } else if (fieldNames[fieldName]) { context.reportError( new GraphQLError( - duplicateFieldDefinitionNameMessage(typeName, fieldName), + `Field "${typeName}.${fieldName}" can only be defined once.`, [fieldNames[fieldName], fieldDef.name], ), ); diff --git a/src/validation/rules/UniqueFragmentNames.js b/src/validation/rules/UniqueFragmentNames.js index 1dc86432fb..223f70fba5 100644 --- a/src/validation/rules/UniqueFragmentNames.js +++ b/src/validation/rules/UniqueFragmentNames.js @@ -5,10 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ASTValidationContext } from '../ValidationContext'; -export function duplicateFragmentNameMessage(fragName: string): string { - return `There can be only one fragment named "${fragName}".`; -} - /** * Unique fragment names * @@ -22,10 +18,10 @@ export function UniqueFragmentNames(context: ASTValidationContext): ASTVisitor { const fragmentName = node.name.value; if (knownFragmentNames[fragmentName]) { context.reportError( - new GraphQLError(duplicateFragmentNameMessage(fragmentName), [ - knownFragmentNames[fragmentName], - node.name, - ]), + new GraphQLError( + `There can be only one fragment named "${fragmentName}".`, + [knownFragmentNames[fragmentName], node.name], + ), ); } else { knownFragmentNames[fragmentName] = node.name; diff --git a/src/validation/rules/UniqueInputFieldNames.js b/src/validation/rules/UniqueInputFieldNames.js index 2c42ce40b7..71483ec24c 100644 --- a/src/validation/rules/UniqueInputFieldNames.js +++ b/src/validation/rules/UniqueInputFieldNames.js @@ -5,10 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ASTValidationContext } from '../ValidationContext'; -export function duplicateInputFieldMessage(fieldName: string): string { - return `There can be only one input field named "${fieldName}".`; -} - /** * Unique input field names * @@ -35,10 +31,10 @@ export function UniqueInputFieldNames( const fieldName = node.name.value; if (knownNames[fieldName]) { context.reportError( - new GraphQLError(duplicateInputFieldMessage(fieldName), [ - knownNames[fieldName], - node.name, - ]), + new GraphQLError( + `There can be only one input field named "${fieldName}".`, + [knownNames[fieldName], node.name], + ), ); } else { knownNames[fieldName] = node.name; diff --git a/src/validation/rules/UniqueOperationNames.js b/src/validation/rules/UniqueOperationNames.js index 1f615f29f4..ebecf1bcc8 100644 --- a/src/validation/rules/UniqueOperationNames.js +++ b/src/validation/rules/UniqueOperationNames.js @@ -5,10 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type ASTValidationContext } from '../ValidationContext'; -export function duplicateOperationNameMessage(operationName: string): string { - return `There can be only one operation named "${operationName}".`; -} - /** * Unique operation names * @@ -25,7 +21,7 @@ export function UniqueOperationNames( if (knownOperationNames[operationName.value]) { context.reportError( new GraphQLError( - duplicateOperationNameMessage(operationName.value), + `There can be only one operation named "${operationName.value}".`, [knownOperationNames[operationName.value], operationName], ), ); diff --git a/src/validation/rules/UniqueOperationTypes.js b/src/validation/rules/UniqueOperationTypes.js index c49b551594..16a474e13c 100644 --- a/src/validation/rules/UniqueOperationTypes.js +++ b/src/validation/rules/UniqueOperationTypes.js @@ -5,14 +5,6 @@ import { type ASTVisitor } from '../../language/visitor'; import { type SDLValidationContext } from '../ValidationContext'; -export function duplicateOperationTypeMessage(operation: string): string { - return `There can be only one ${operation} type in schema.`; -} - -export function existedOperationTypeMessage(operation: string): string { - return `Type for ${operation} already defined in the schema. It cannot be redefined.`; -} - /** * Unique operation types * @@ -45,16 +37,16 @@ export function UniqueOperationTypes( if (existingOperationTypes[operation]) { context.reportError( new GraphQLError( - existedOperationTypeMessage(operation), + `Type for ${operation} already defined in the schema. It cannot be redefined.`, operationType, ), ); } else if (alreadyDefinedOperationType) { context.reportError( - new GraphQLError(duplicateOperationTypeMessage(operation), [ - alreadyDefinedOperationType, - operationType, - ]), + new GraphQLError( + `There can be only one ${operation} type in schema.`, + [alreadyDefinedOperationType, operationType], + ), ); } else { definedOperationTypes[operation] = operationType; diff --git a/src/validation/rules/UniqueTypeNames.js b/src/validation/rules/UniqueTypeNames.js index 6986336e71..58ba64a946 100644 --- a/src/validation/rules/UniqueTypeNames.js +++ b/src/validation/rules/UniqueTypeNames.js @@ -7,14 +7,6 @@ import { type TypeDefinitionNode } from '../../language/ast'; import { type SDLValidationContext } from '../ValidationContext'; -export function duplicateTypeNameMessage(typeName: string): string { - return `There can be only one type named "${typeName}".`; -} - -export function existedTypeNameMessage(typeName: string): string { - return `Type "${typeName}" already exists in the schema. It cannot also be defined in this type definition.`; -} - /** * Unique type names * @@ -38,14 +30,17 @@ export function UniqueTypeNames(context: SDLValidationContext): ASTVisitor { if (schema && schema.getType(typeName)) { context.reportError( - new GraphQLError(existedTypeNameMessage(typeName), node.name), + new GraphQLError( + `Type "${typeName}" already exists in the schema. It cannot also be defined in this type definition.`, + node.name, + ), ); return; } if (knownTypeNames[typeName]) { context.reportError( - new GraphQLError(duplicateTypeNameMessage(typeName), [ + new GraphQLError(`There can be only one type named "${typeName}".`, [ knownTypeNames[typeName], node.name, ]), diff --git a/src/validation/rules/UniqueVariableNames.js b/src/validation/rules/UniqueVariableNames.js index 850091aef8..21cae15cfe 100644 --- a/src/validation/rules/UniqueVariableNames.js +++ b/src/validation/rules/UniqueVariableNames.js @@ -7,10 +7,6 @@ import { type VariableDefinitionNode } from '../../language/ast'; import { type ASTValidationContext } from '../ValidationContext'; -export function duplicateVariableMessage(variableName: string): string { - return `There can be only one variable named "${variableName}".`; -} - /** * Unique variable names * @@ -26,10 +22,10 @@ export function UniqueVariableNames(context: ASTValidationContext): ASTVisitor { const variableName = node.variable.name.value; if (knownVariableNames[variableName]) { context.reportError( - new GraphQLError(duplicateVariableMessage(variableName), [ - knownVariableNames[variableName], - node.variable.name, - ]), + new GraphQLError( + `There can be only one variable named "${variableName}".`, + [knownVariableNames[variableName], node.variable.name], + ), ); } else { knownVariableNames[variableName] = node.variable.name; diff --git a/src/validation/rules/ValuesOfCorrectType.js b/src/validation/rules/ValuesOfCorrectType.js index 320fa9f397..246b380481 100644 --- a/src/validation/rules/ValuesOfCorrectType.js +++ b/src/validation/rules/ValuesOfCorrectType.js @@ -28,47 +28,6 @@ import { import { type ValidationContext } from '../ValidationContext'; -export function badValueMessage( - typeName: string, - valueName: string, - message?: string, -): string { - return ( - `Expected type ${typeName}, found ${valueName}` + - (message ? `; ${message}` : '.') - ); -} - -export function badEnumValueMessage( - typeName: string, - valueName: string, - suggestedValues: $ReadOnlyArray, -) { - return ( - `Expected type ${typeName}, found ${valueName}.` + - didYouMean('the enum value', suggestedValues) - ); -} - -export function requiredFieldMessage( - typeName: string, - fieldName: string, - fieldTypeName: string, -): string { - return `Field ${typeName}.${fieldName} of required type ${fieldTypeName} was not provided.`; -} - -export function unknownFieldMessage( - typeName: string, - fieldName: string, - suggestedFields: $ReadOnlyArray, -): string { - return ( - `Field "${fieldName}" is not defined by type ${typeName}.` + - didYouMean(suggestedFields) - ); -} - /** * Value literals of correct type * @@ -100,7 +59,7 @@ export function ValuesOfCorrectType(context: ValidationContext): ASTVisitor { const typeStr = inspect(fieldDef.type); context.reportError( new GraphQLError( - requiredFieldMessage(type.name, fieldDef.name, typeStr), + `Field ${type.name}.${fieldDef.name} of required type ${typeStr} was not provided.`, node, ), ); @@ -117,7 +76,8 @@ export function ValuesOfCorrectType(context: ValidationContext): ASTVisitor { ); context.reportError( new GraphQLError( - unknownFieldMessage(parentType.name, node.name.value, suggestions), + `Field "${node.name.value}" is not defined by type ${parentType.name}.` + + didYouMean(suggestions), node, ), ); @@ -127,7 +87,10 @@ export function ValuesOfCorrectType(context: ValidationContext): ASTVisitor { const type = context.getInputType(); if (isNonNullType(type)) { context.reportError( - new GraphQLError(badValueMessage(inspect(type), print(node)), node), + new GraphQLError( + `Expected type ${inspect(type)}, found ${print(node)}.`, + node, + ), ); } }, @@ -154,13 +117,13 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { if (isEnumType(type)) { if (node.kind !== Kind.ENUM || !type.getValue(node.value)) { + const allNames = type.getValues().map(value => value.name); + const suggestedValues = suggestionList(print(node), allNames); + context.reportError( new GraphQLError( - badEnumValueMessage( - type.name, - print(node), - enumTypeSuggestion(type, node), - ), + `Expected type ${type.name}, found ${print(node)}.` + + didYouMean('the enum value', suggestedValues), node, ), ); @@ -171,7 +134,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { if (!isScalarType(type)) { context.reportError( new GraphQLError( - badValueMessage(inspect(locationType), print(node)), + `Expected type ${inspect(locationType)}, found ${print(node)}.`, node, ), ); @@ -185,7 +148,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { if (isInvalid(parseResult)) { context.reportError( new GraphQLError( - badValueMessage(inspect(locationType), print(node)), + `Expected type ${inspect(locationType)}, found ${print(node)}.`, node, ), ); @@ -194,7 +157,8 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { // Ensure a reference to the original error is maintained. context.reportError( new GraphQLError( - badValueMessage(inspect(locationType), print(node), error.message), + `Expected type ${inspect(locationType)}, found ${print(node)}; ` + + error.message, node, undefined, undefined, @@ -204,8 +168,3 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { ); } } - -function enumTypeSuggestion(type, node) { - const allNames = type.getValues().map(value => value.name); - return suggestionList(print(node), allNames); -} diff --git a/src/validation/rules/VariablesAreInputTypes.js b/src/validation/rules/VariablesAreInputTypes.js index 3230d44bbb..7336a42f73 100644 --- a/src/validation/rules/VariablesAreInputTypes.js +++ b/src/validation/rules/VariablesAreInputTypes.js @@ -12,13 +12,6 @@ import { typeFromAST } from '../../utilities/typeFromAST'; import { type ValidationContext } from '../ValidationContext'; -export function nonInputTypeOnVarMessage( - variableName: string, - typeName: string, -): string { - return `Variable "$${variableName}" cannot be non-input type "${typeName}".`; -} - /** * Variables are input types * @@ -30,12 +23,13 @@ export function VariablesAreInputTypes(context: ValidationContext): ASTVisitor { VariableDefinition(node: VariableDefinitionNode): ?GraphQLError { const type = typeFromAST(context.getSchema(), node.type); - // If the variable type is not an input type, return an error. if (type && !isInputType(type)) { const variableName = node.variable.name.value; + const typeName = print(node.type); + context.reportError( new GraphQLError( - nonInputTypeOnVarMessage(variableName, print(node.type)), + `Variable "$${variableName}" cannot be non-input type "${typeName}".`, node.type, ), ); diff --git a/src/validation/rules/VariablesInAllowedPosition.js b/src/validation/rules/VariablesInAllowedPosition.js index f61d2cb5a5..bc4a630170 100644 --- a/src/validation/rules/VariablesInAllowedPosition.js +++ b/src/validation/rules/VariablesInAllowedPosition.js @@ -16,14 +16,6 @@ import { isTypeSubTypeOf } from '../../utilities/typeComparators'; import { type ValidationContext } from '../ValidationContext'; -export function badVarPosMessage( - varName: string, - varType: string, - expectedType: string, -): string { - return `Variable "$${varName}" of type "${varType}" used in position expecting type "${expectedType}".`; -} - /** * Variables passed to field arguments conform to type */ @@ -61,9 +53,11 @@ export function VariablesInAllowedPosition( defaultValue, ) ) { + const varTypeStr = inspect(varType); + const typeStr = inspect(type); context.reportError( new GraphQLError( - badVarPosMessage(varName, inspect(varType), inspect(type)), + `Variable "$${varName}" of type "${varTypeStr}" used in position expecting type "${typeStr}".`, [varDef, node], ), ); diff --git a/tstypes/validation/rules/ExecutableDefinitions.d.ts b/tstypes/validation/rules/ExecutableDefinitions.d.ts index e079dea2f0..9f2b89e214 100644 --- a/tstypes/validation/rules/ExecutableDefinitions.d.ts +++ b/tstypes/validation/rules/ExecutableDefinitions.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function nonExecutableDefinitionMessage(defName: string): string; - /** * Executable definitions * diff --git a/tstypes/validation/rules/FieldsOnCorrectType.d.ts b/tstypes/validation/rules/FieldsOnCorrectType.d.ts index 130cb83d13..5622375866 100644 --- a/tstypes/validation/rules/FieldsOnCorrectType.d.ts +++ b/tstypes/validation/rules/FieldsOnCorrectType.d.ts @@ -1,13 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function undefinedFieldMessage( - fieldName: string, - type: string, - suggestedTypeNames: ReadonlyArray, - suggestedFieldNames: ReadonlyArray, -): string; - /** * Fields on correct type * diff --git a/tstypes/validation/rules/FragmentsOnCompositeTypes.d.ts b/tstypes/validation/rules/FragmentsOnCompositeTypes.d.ts index 32bd7c7f7d..90bffff79e 100644 --- a/tstypes/validation/rules/FragmentsOnCompositeTypes.d.ts +++ b/tstypes/validation/rules/FragmentsOnCompositeTypes.d.ts @@ -1,13 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function inlineFragmentOnNonCompositeErrorMessage(type: string): string; - -export function fragmentOnNonCompositeErrorMessage( - fragName: string, - type: string, -): string; - /** * Fragments on composite type * diff --git a/tstypes/validation/rules/KnownArgumentNames.d.ts b/tstypes/validation/rules/KnownArgumentNames.d.ts index e3869ca72e..33541a7906 100644 --- a/tstypes/validation/rules/KnownArgumentNames.d.ts +++ b/tstypes/validation/rules/KnownArgumentNames.d.ts @@ -1,19 +1,6 @@ import { ValidationContext, SDLValidationContext } from '../ValidationContext'; import { ASTVisitor } from '../../language/visitor'; -export function unknownArgMessage( - argName: string, - fieldName: string, - typeName: string, - suggestedArgs: ReadonlyArray, -): string; - -export function unknownDirectiveArgMessage( - argName: string, - directiveName: string, - suggestedArgs: ReadonlyArray, -): string; - /** * Known argument names * diff --git a/tstypes/validation/rules/KnownDirectives.d.ts b/tstypes/validation/rules/KnownDirectives.d.ts index ecff9172a2..9ea490d42e 100644 --- a/tstypes/validation/rules/KnownDirectives.d.ts +++ b/tstypes/validation/rules/KnownDirectives.d.ts @@ -1,13 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext, SDLValidationContext } from '../ValidationContext'; -export function unknownDirectiveMessage(directiveName: string): string; - -export function misplacedDirectiveMessage( - directiveName: string, - location: string, -): string; - /** * Known directives * diff --git a/tstypes/validation/rules/KnownFragmentNames.d.ts b/tstypes/validation/rules/KnownFragmentNames.d.ts index 0f91fd895a..88c80be54c 100644 --- a/tstypes/validation/rules/KnownFragmentNames.d.ts +++ b/tstypes/validation/rules/KnownFragmentNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function unknownFragmentMessage(fragName: string): string; - /** * Known fragment names * diff --git a/tstypes/validation/rules/KnownTypeNames.d.ts b/tstypes/validation/rules/KnownTypeNames.d.ts index cc8280db0f..9276f6b705 100644 --- a/tstypes/validation/rules/KnownTypeNames.d.ts +++ b/tstypes/validation/rules/KnownTypeNames.d.ts @@ -1,11 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function unknownTypeMessage( - typeName: string, - suggestedTypes: Array, -): string; - /** * Known type names * diff --git a/tstypes/validation/rules/LoneAnonymousOperation.d.ts b/tstypes/validation/rules/LoneAnonymousOperation.d.ts index ed1ce2505b..eee806407d 100644 --- a/tstypes/validation/rules/LoneAnonymousOperation.d.ts +++ b/tstypes/validation/rules/LoneAnonymousOperation.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function anonOperationNotAloneMessage(): string; - /** * Lone anonymous operation * diff --git a/tstypes/validation/rules/LoneSchemaDefinition.d.ts b/tstypes/validation/rules/LoneSchemaDefinition.d.ts index fab68bee8d..f24bb5184a 100644 --- a/tstypes/validation/rules/LoneSchemaDefinition.d.ts +++ b/tstypes/validation/rules/LoneSchemaDefinition.d.ts @@ -1,10 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function schemaDefinitionNotAloneMessage(): string; - -export function canNotDefineSchemaWithinExtensionMessage(): string; - /** * Lone Schema definition * diff --git a/tstypes/validation/rules/NoFragmentCycles.d.ts b/tstypes/validation/rules/NoFragmentCycles.d.ts index 80eff89fa6..eb4a0a47e9 100644 --- a/tstypes/validation/rules/NoFragmentCycles.d.ts +++ b/tstypes/validation/rules/NoFragmentCycles.d.ts @@ -1,9 +1,4 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function cycleErrorMessage( - fragName: string, - spreadNames: ReadonlyArray, -): string; - export function NoFragmentCycles(context: ValidationContext): ASTVisitor; diff --git a/tstypes/validation/rules/NoUndefinedVariables.d.ts b/tstypes/validation/rules/NoUndefinedVariables.d.ts index 54797d3d6c..c761ba58ca 100644 --- a/tstypes/validation/rules/NoUndefinedVariables.d.ts +++ b/tstypes/validation/rules/NoUndefinedVariables.d.ts @@ -1,12 +1,6 @@ -import Maybe from '../../tsutils/Maybe'; import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function undefinedVarMessage( - varName: string, - opName: Maybe, -): string; - /** * No undefined variables * diff --git a/tstypes/validation/rules/NoUnusedFragments.d.ts b/tstypes/validation/rules/NoUnusedFragments.d.ts index 8c9631e8bd..a48e792451 100644 --- a/tstypes/validation/rules/NoUnusedFragments.d.ts +++ b/tstypes/validation/rules/NoUnusedFragments.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function unusedFragMessage(fragName: string): string; - /** * No unused fragments * diff --git a/tstypes/validation/rules/NoUnusedVariables.d.ts b/tstypes/validation/rules/NoUnusedVariables.d.ts index 055faa1145..15d5316dbc 100644 --- a/tstypes/validation/rules/NoUnusedVariables.d.ts +++ b/tstypes/validation/rules/NoUnusedVariables.d.ts @@ -1,12 +1,6 @@ -import Maybe from '../../tsutils/Maybe'; import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function unusedVariableMessage( - varName: string, - opName: Maybe, -): string; - /** * No unused variables * diff --git a/tstypes/validation/rules/OverlappingFieldsCanBeMerged.d.ts b/tstypes/validation/rules/OverlappingFieldsCanBeMerged.d.ts index b581ee9c43..22e0e30968 100644 --- a/tstypes/validation/rules/OverlappingFieldsCanBeMerged.d.ts +++ b/tstypes/validation/rules/OverlappingFieldsCanBeMerged.d.ts @@ -1,11 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function fieldsConflictMessage( - responseName: string, - reason: ConflictReasonMessage, -): string; - /** * Overlapping fields can be merged * @@ -16,9 +11,3 @@ export function fieldsConflictMessage( export function OverlappingFieldsCanBeMerged( context: ValidationContext, ): ASTVisitor; - -// Field name and reason. -type ConflictReason = [string, string]; - -// Reason is a string, or a nested list of conflicts. -type ConflictReasonMessage = string | Array; diff --git a/tstypes/validation/rules/PossibleFragmentSpreads.d.ts b/tstypes/validation/rules/PossibleFragmentSpreads.d.ts index cd1a3fc074..18f8e7a3a4 100644 --- a/tstypes/validation/rules/PossibleFragmentSpreads.d.ts +++ b/tstypes/validation/rules/PossibleFragmentSpreads.d.ts @@ -1,17 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function typeIncompatibleSpreadMessage( - fragName: string, - parentType: string, - fragType: string, -): string; - -export function typeIncompatibleAnonSpreadMessage( - parentType: string, - fragType: string, -): string; - /** * Possible fragment spread * diff --git a/tstypes/validation/rules/PossibleTypeExtensions.d.ts b/tstypes/validation/rules/PossibleTypeExtensions.d.ts index 404784021c..9b83748eef 100644 --- a/tstypes/validation/rules/PossibleTypeExtensions.d.ts +++ b/tstypes/validation/rules/PossibleTypeExtensions.d.ts @@ -1,16 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function extendingUnknownTypeMessage( - typeName: string, - suggestedTypes: ReadonlyArray, -): string; - -export function extendingDifferentTypeKindMessage( - typeName: string, - kind: string, -): string; - /** * Possible type extension * diff --git a/tstypes/validation/rules/ProvidedRequiredArguments.d.ts b/tstypes/validation/rules/ProvidedRequiredArguments.d.ts index c1bc4c4683..4a02ae6151 100644 --- a/tstypes/validation/rules/ProvidedRequiredArguments.d.ts +++ b/tstypes/validation/rules/ProvidedRequiredArguments.d.ts @@ -1,18 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext, SDLValidationContext } from '../ValidationContext'; -export function missingFieldArgMessage( - fieldName: string, - argName: string, - type: string, -): string; - -export function missingDirectiveArgMessage( - directiveName: string, - argName: string, - type: string, -): string; - /** * Provided required arguments * diff --git a/tstypes/validation/rules/ScalarLeafs.d.ts b/tstypes/validation/rules/ScalarLeafs.d.ts index f01448beef..3f915c8953 100644 --- a/tstypes/validation/rules/ScalarLeafs.d.ts +++ b/tstypes/validation/rules/ScalarLeafs.d.ts @@ -1,16 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function noSubselectionAllowedMessage( - fieldName: string, - type: string, -): string; - -export function requiredSubselectionMessage( - fieldName: string, - type: string, -): string; - /** * Scalar leafs * diff --git a/tstypes/validation/rules/SingleFieldSubscriptions.d.ts b/tstypes/validation/rules/SingleFieldSubscriptions.d.ts index 7dbbb23cf3..43ac2d9d91 100644 --- a/tstypes/validation/rules/SingleFieldSubscriptions.d.ts +++ b/tstypes/validation/rules/SingleFieldSubscriptions.d.ts @@ -2,8 +2,6 @@ import Maybe from '../../tsutils/Maybe'; import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function singleFieldOnlyMessage(name: Maybe): string; - /** * Subscriptions must only include one field. * diff --git a/tstypes/validation/rules/UniqueArgumentNames.d.ts b/tstypes/validation/rules/UniqueArgumentNames.d.ts index fdd51e1020..b84e43caa8 100644 --- a/tstypes/validation/rules/UniqueArgumentNames.d.ts +++ b/tstypes/validation/rules/UniqueArgumentNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateArgMessage(argName: string): string; - /** * Unique argument names * diff --git a/tstypes/validation/rules/UniqueDirectiveNames.d.ts b/tstypes/validation/rules/UniqueDirectiveNames.d.ts index 9080be2ed4..2c956df5dc 100644 --- a/tstypes/validation/rules/UniqueDirectiveNames.d.ts +++ b/tstypes/validation/rules/UniqueDirectiveNames.d.ts @@ -1,10 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function duplicateDirectiveNameMessage(directiveName: string): string; - -export function existedDirectiveNameMessage(directiveName: string): string; - /** * Unique directive names * diff --git a/tstypes/validation/rules/UniqueDirectivesPerLocation.d.ts b/tstypes/validation/rules/UniqueDirectivesPerLocation.d.ts index 02c73123cd..f83ed52424 100644 --- a/tstypes/validation/rules/UniqueDirectivesPerLocation.d.ts +++ b/tstypes/validation/rules/UniqueDirectivesPerLocation.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateDirectiveMessage(directiveName: string): string; - /** * Unique directive names per location * diff --git a/tstypes/validation/rules/UniqueEnumValueNames.d.ts b/tstypes/validation/rules/UniqueEnumValueNames.d.ts index 2f3f654092..4bdca87b62 100644 --- a/tstypes/validation/rules/UniqueEnumValueNames.d.ts +++ b/tstypes/validation/rules/UniqueEnumValueNames.d.ts @@ -1,16 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function duplicateEnumValueNameMessage( - typeName: string, - valueName: string, -): string; - -export function existedEnumValueNameMessage( - typeName: string, - valueName: string, -): string; - /** * Unique enum value names * diff --git a/tstypes/validation/rules/UniqueFieldDefinitionNames.d.ts b/tstypes/validation/rules/UniqueFieldDefinitionNames.d.ts index 11d6e4fb64..ca861f9474 100644 --- a/tstypes/validation/rules/UniqueFieldDefinitionNames.d.ts +++ b/tstypes/validation/rules/UniqueFieldDefinitionNames.d.ts @@ -1,16 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function duplicateFieldDefinitionNameMessage( - typeName: string, - fieldName: string, -): string; - -export function existedFieldDefinitionNameMessage( - typeName: string, - fieldName: string, -): string; - /** * Unique field definition names * diff --git a/tstypes/validation/rules/UniqueFragmentNames.d.ts b/tstypes/validation/rules/UniqueFragmentNames.d.ts index ebd4bb2d6e..b3cd884a49 100644 --- a/tstypes/validation/rules/UniqueFragmentNames.d.ts +++ b/tstypes/validation/rules/UniqueFragmentNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateFragmentNameMessage(fragName: string): string; - /** * Unique fragment names * diff --git a/tstypes/validation/rules/UniqueInputFieldNames.d.ts b/tstypes/validation/rules/UniqueInputFieldNames.d.ts index 3894428ca8..7bc3573099 100644 --- a/tstypes/validation/rules/UniqueInputFieldNames.d.ts +++ b/tstypes/validation/rules/UniqueInputFieldNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateInputFieldMessage(fieldName: string): string; - /** * Unique input field names * diff --git a/tstypes/validation/rules/UniqueOperationNames.d.ts b/tstypes/validation/rules/UniqueOperationNames.d.ts index 0c6234965a..802701ed0b 100644 --- a/tstypes/validation/rules/UniqueOperationNames.d.ts +++ b/tstypes/validation/rules/UniqueOperationNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateOperationNameMessage(operationName: string): string; - /** * Unique operation names * diff --git a/tstypes/validation/rules/UniqueOperationTypes.d.ts b/tstypes/validation/rules/UniqueOperationTypes.d.ts index fef615bbc1..5464966c01 100644 --- a/tstypes/validation/rules/UniqueOperationTypes.d.ts +++ b/tstypes/validation/rules/UniqueOperationTypes.d.ts @@ -1,10 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function duplicateOperationTypeMessage(operation: string): string; - -export function existedOperationTypeMessage(operation: string): string; - /** * Unique operation types * diff --git a/tstypes/validation/rules/UniqueTypeNames.d.ts b/tstypes/validation/rules/UniqueTypeNames.d.ts index 8b9e3ad3ab..ff3251e377 100644 --- a/tstypes/validation/rules/UniqueTypeNames.d.ts +++ b/tstypes/validation/rules/UniqueTypeNames.d.ts @@ -1,10 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { SDLValidationContext } from '../ValidationContext'; -export function duplicateTypeNameMessage(typeName: string): string; - -export function existedTypeNameMessage(typeName: string): string; - /** * Unique type names * diff --git a/tstypes/validation/rules/UniqueVariableNames.d.ts b/tstypes/validation/rules/UniqueVariableNames.d.ts index 0ed9633804..bd9e84a637 100644 --- a/tstypes/validation/rules/UniqueVariableNames.d.ts +++ b/tstypes/validation/rules/UniqueVariableNames.d.ts @@ -1,8 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ASTValidationContext } from '../ValidationContext'; -export function duplicateVariableMessage(variableName: string): string; - /** * Unique variable names * diff --git a/tstypes/validation/rules/ValuesOfCorrectType.d.ts b/tstypes/validation/rules/ValuesOfCorrectType.d.ts index 9b475cf272..74b4dc6ae1 100644 --- a/tstypes/validation/rules/ValuesOfCorrectType.d.ts +++ b/tstypes/validation/rules/ValuesOfCorrectType.d.ts @@ -1,30 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function badValueMessage( - typeName: string, - valueName: string, - message?: string, -): string; - -export function badEnumValueMessage( - typeName: string, - valueName: string, - suggestedValues: ReadonlyArray, -): string; - -export function requiredFieldMessage( - typeName: string, - fieldName: string, - fieldTypeName: string, -): string; - -export function unknownFieldMessage( - typeName: string, - fieldName: string, - suggestedFields: ReadonlyArray, -): string; - /** * Value literals of correct type * diff --git a/tstypes/validation/rules/VariablesAreInputTypes.d.ts b/tstypes/validation/rules/VariablesAreInputTypes.d.ts index ace6fea4b5..cff4c5f095 100644 --- a/tstypes/validation/rules/VariablesAreInputTypes.d.ts +++ b/tstypes/validation/rules/VariablesAreInputTypes.d.ts @@ -1,11 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function nonInputTypeOnVarMessage( - variableName: string, - typeName: string, -): string; - /** * Variables are input types * diff --git a/tstypes/validation/rules/VariablesInAllowedPosition.d.ts b/tstypes/validation/rules/VariablesInAllowedPosition.d.ts index 3401c9767f..afb52dd701 100644 --- a/tstypes/validation/rules/VariablesInAllowedPosition.d.ts +++ b/tstypes/validation/rules/VariablesInAllowedPosition.d.ts @@ -1,12 +1,6 @@ import { ASTVisitor } from '../../language/visitor'; import { ValidationContext } from '../ValidationContext'; -export function badVarPosMessage( - varName: string, - varType: string, - expectedType: string, -): string; - /** * Variables passed to field arguments conform to type */