From b36a32cc93f87cb597dcf5094ea9f2b70e004ce7 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 31 Oct 2021 16:46:10 +0100 Subject: [PATCH] fix error report for `strict-id-in-types` and `naming-convention` rule (#744) --- .changeset/silent-files-build.md | 5 + .../plugin/src/rules/naming-convention.ts | 14 ++- .../plugin/src/rules/strict-id-in-types.ts | 10 +- .../naming-convention.spec.ts.snap | 102 +++++++++--------- .../strict-id-in-types.spec.ts.snap | 18 ++-- 5 files changed, 80 insertions(+), 69 deletions(-) create mode 100644 .changeset/silent-files-build.md diff --git a/.changeset/silent-files-build.md b/.changeset/silent-files-build.md new file mode 100644 index 00000000000..92ad22b6cee --- /dev/null +++ b/.changeset/silent-files-build.md @@ -0,0 +1,5 @@ +--- +'@graphql-eslint/eslint-plugin': patch +--- + +fix error report for `strict-id-in-types` and `naming-convention` rule diff --git a/packages/plugin/src/rules/naming-convention.ts b/packages/plugin/src/rules/naming-convention.ts index fda6cfdf1d4..53d16289e0a 100644 --- a/packages/plugin/src/rules/naming-convention.ts +++ b/packages/plugin/src/rules/naming-convention.ts @@ -1,6 +1,6 @@ import { Kind } from 'graphql'; import { GraphQLESLintRule } from '../types'; -import { isQueryType } from '../utils'; +import { getLocation, isQueryType } from '../utils'; const formats = { camelCase: /^[a-z][^_]*$/g, @@ -246,7 +246,7 @@ const rule: GraphQLESLintRule = { }); if (result.ok === false) { context.report({ - node, + loc: getLocation(node.loc, node.value), message: result.errorMessage, data: { prefix, @@ -275,10 +275,16 @@ const rule: GraphQLESLintRule = { return { Name: node => { if (node.value.startsWith('_') && options.leadingUnderscore === 'forbid') { - context.report({ node, message: 'Leading underscores are not allowed' }); + context.report({ + loc: getLocation(node.loc, node.value), + message: 'Leading underscores are not allowed', + }); } if (node.value.endsWith('_') && options.trailingUnderscore === 'forbid') { - context.report({ node, message: 'Trailing underscores are not allowed' }); + context.report({ + loc: getLocation(node.loc, node.value), + message: 'Trailing underscores are not allowed', + }); } }, ObjectTypeDefinition: node => { diff --git a/packages/plugin/src/rules/strict-id-in-types.ts b/packages/plugin/src/rules/strict-id-in-types.ts index 11a0ca8fe2c..01d11c257fe 100644 --- a/packages/plugin/src/rules/strict-id-in-types.ts +++ b/packages/plugin/src/rules/strict-id-in-types.ts @@ -1,6 +1,7 @@ import { Kind, ObjectTypeDefinitionNode } from 'graphql'; import { GraphQLESTreeNode } from '../estree-parser'; import { GraphQLESLintRule } from '../types'; +import { getLocation } from '../utils'; export interface ExceptionRule { types?: string[]; @@ -171,17 +172,16 @@ const rule: GraphQLESLintRule = { return isValidIdName && isValidIdType; }); - + const typeName = node.name.value; // Usually, there should be only one unique identifier field per type. // Some clients allow multiple fields to be used. If more people need this, // we can extend this rule later. if (validIds.length !== 1) { context.report({ - node, - message: - '{{nodeName}} must have exactly one non-nullable unique identifier. Accepted name(s): {{acceptedNamesString}} ; Accepted type(s): {{acceptedTypesString}}', + loc: getLocation(node.name.loc, typeName), + message: `{{ typeName }} must have exactly one non-nullable unique identifier. Accepted name(s): {{ acceptedNamesString }} ; Accepted type(s): {{ acceptedTypesString }}`, data: { - nodeName: node.name.value, + typeName, acceptedNamesString: options.acceptedIdNames.join(','), acceptedTypesString: options.acceptedIdTypes.join(','), }, diff --git a/packages/plugin/tests/__snapshots__/naming-convention.spec.ts.snap b/packages/plugin/tests/__snapshots__/naming-convention.spec.ts.snap index 69cc3f51677..5675763ff57 100644 --- a/packages/plugin/tests/__snapshots__/naming-convention.spec.ts.snap +++ b/packages/plugin/tests/__snapshots__/naming-convention.spec.ts.snap @@ -2,32 +2,32 @@ exports[` 1`] = ` > 1 | type b { test: String } - | ^ Type name "b" should be in PascalCase format + | ^ Type name "b" should be in PascalCase format `; exports[` 2`] = ` > 1 | type b { test: String } - | ^ Field name "test" should be in PascalCase format + | ^^^^ Field name "test" should be in PascalCase format `; exports[` 3`] = ` > 1 | type __b { test__: String } - | ^ Leading underscores are not allowed + | ^^^ Leading underscores are not allowed `; exports[` 4`] = ` > 1 | type __b { test__: String } - | ^ Trailing underscores are not allowed + | ^^^^^^ Trailing underscores are not allowed `; exports[` 5`] = ` > 1 | scalar BSONDecimal - | ^ Scalar name "BSONDecimal" should be in snake_case format + | ^^^^^^^^^^^ Scalar name "BSONDecimal" should be in snake_case format `; exports[` 6`] = ` > 1 | input _idOperatorsFilterFindManyUserInput { - | ^ Input type name "_idOperatorsFilterFindManyUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterFindManyUserInput" should be in PascalCase format 2 | gt: MongoID 3 | gte: MongoID 4 | lt: MongoID @@ -1151,7 +1151,7 @@ exports[` 7`] = ` 9 | } 10 | > 11 | input _idOperatorsFilterFindOneUserInput { - | ^ Input type name "_idOperatorsFilterFindOneUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterFindOneUserInput" should be in PascalCase format 12 | gt: MongoID 13 | gte: MongoID 14 | lt: MongoID @@ -2275,7 +2275,7 @@ exports[` 8`] = ` 19 | } 20 | > 21 | input _idOperatorsFilterRemoveManyUserInput { - | ^ Input type name "_idOperatorsFilterRemoveManyUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterRemoveManyUserInput" should be in PascalCase format 22 | gt: MongoID 23 | gte: MongoID 24 | lt: MongoID @@ -3399,7 +3399,7 @@ exports[` 9`] = ` 29 | } 30 | > 31 | input _idOperatorsFilterRemoveOneUserInput { - | ^ Input type name "_idOperatorsFilterRemoveOneUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterRemoveOneUserInput" should be in PascalCase format 32 | gt: MongoID 33 | gte: MongoID 34 | lt: MongoID @@ -4523,7 +4523,7 @@ exports[` 10`] = ` 39 | } 40 | > 41 | input _idOperatorsFilterUpdateManyUserInput { - | ^ Input type name "_idOperatorsFilterUpdateManyUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterUpdateManyUserInput" should be in PascalCase format 42 | gt: MongoID 43 | gte: MongoID 44 | lt: MongoID @@ -5647,7 +5647,7 @@ exports[` 11`] = ` 49 | } 50 | > 51 | input _idOperatorsFilterUpdateOneUserInput { - | ^ Input type name "_idOperatorsFilterUpdateOneUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterUpdateOneUserInput" should be in PascalCase format 52 | gt: MongoID 53 | gte: MongoID 54 | lt: MongoID @@ -6771,7 +6771,7 @@ exports[` 12`] = ` 59 | } 60 | > 61 | input _idOperatorsFilterUserInput { - | ^ Input type name "_idOperatorsFilterUserInput" should be in PascalCase format + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input type name "_idOperatorsFilterUserInput" should be in PascalCase format 62 | gt: MongoID 63 | gte: MongoID 64 | lt: MongoID @@ -8032,7 +8032,7 @@ exports[` 13`] = ` 206 | 207 | enum EnumUserGender { > 208 | male - | ^ Enumeration value name "male" should be in UPPER_CASE format + | ^^^^ Enumeration value name "male" should be in UPPER_CASE format 209 | female 210 | ladyboy 211 | } @@ -9147,7 +9147,7 @@ exports[` 14`] = ` 207 | enum EnumUserGender { 208 | male > 209 | female - | ^ Enumeration value name "female" should be in UPPER_CASE format + | ^^^^^^ Enumeration value name "female" should be in UPPER_CASE format 210 | ladyboy 211 | } 212 | @@ -10262,7 +10262,7 @@ exports[` 15`] = ` 208 | male 209 | female > 210 | ladyboy - | ^ Enumeration value name "ladyboy" should be in UPPER_CASE format + | ^^^^^^^ Enumeration value name "ladyboy" should be in UPPER_CASE format 211 | } 212 | 213 | enum EnumUserLanguagesSkill { @@ -11380,7 +11380,7 @@ exports[` 16`] = ` 212 | 213 | enum EnumUserLanguagesSkill { > 214 | basic - | ^ Enumeration value name "basic" should be in UPPER_CASE format + | ^^^^^ Enumeration value name "basic" should be in UPPER_CASE format 215 | fluent 216 | native 217 | } @@ -12495,7 +12495,7 @@ exports[` 17`] = ` 213 | enum EnumUserLanguagesSkill { 214 | basic > 215 | fluent - | ^ Enumeration value name "fluent" should be in UPPER_CASE format + | ^^^^^^ Enumeration value name "fluent" should be in UPPER_CASE format 216 | native 217 | } 218 | @@ -13610,7 +13610,7 @@ exports[` 18`] = ` 214 | basic 215 | fluent > 216 | native - | ^ Enumeration value name "native" should be in UPPER_CASE format + | ^^^^^^ Enumeration value name "native" should be in UPPER_CASE format 217 | } 218 | 219 | input FilterFindManyUserInput { @@ -14747,7 +14747,7 @@ exports[` 19`] = ` 237 | """ 238 | _operators: OperatorsFilterFindManyUserInput > 239 | OR: [FilterFindManyUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 240 | AND: [FilterFindManyUserInput!] 241 | 242 | """ @@ -15862,7 +15862,7 @@ exports[` 20`] = ` 238 | _operators: OperatorsFilterFindManyUserInput 239 | OR: [FilterFindManyUserInput!] > 240 | AND: [FilterFindManyUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 241 | 242 | """ 243 | Search by distance in meters @@ -17004,7 +17004,7 @@ exports[` 21`] = ` 266 | """ 267 | _operators: OperatorsFilterFindOneUserInput > 268 | OR: [FilterFindOneUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 269 | AND: [FilterFindOneUserInput!] 270 | } 271 | @@ -18119,7 +18119,7 @@ exports[` 22`] = ` 267 | _operators: OperatorsFilterFindOneUserInput 268 | OR: [FilterFindOneUserInput!] > 269 | AND: [FilterFindOneUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 270 | } 271 | 272 | input FilterRemoveManyUserInput { @@ -19256,7 +19256,7 @@ exports[` 23`] = ` 290 | """ 291 | _operators: OperatorsFilterRemoveManyUserInput > 292 | OR: [FilterRemoveManyUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 293 | AND: [FilterRemoveManyUserInput!] 294 | } 295 | @@ -20371,7 +20371,7 @@ exports[` 24`] = ` 291 | _operators: OperatorsFilterRemoveManyUserInput 292 | OR: [FilterRemoveManyUserInput!] > 293 | AND: [FilterRemoveManyUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 294 | } 295 | 296 | input FilterRemoveOneUserInput { @@ -21508,7 +21508,7 @@ exports[` 25`] = ` 314 | """ 315 | _operators: OperatorsFilterRemoveOneUserInput > 316 | OR: [FilterRemoveOneUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 317 | AND: [FilterRemoveOneUserInput!] 318 | } 319 | @@ -22623,7 +22623,7 @@ exports[` 26`] = ` 315 | _operators: OperatorsFilterRemoveOneUserInput 316 | OR: [FilterRemoveOneUserInput!] > 317 | AND: [FilterRemoveOneUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 318 | } 319 | 320 | input FilterUpdateManyUserInput { @@ -23760,7 +23760,7 @@ exports[` 27`] = ` 338 | """ 339 | _operators: OperatorsFilterUpdateManyUserInput > 340 | OR: [FilterUpdateManyUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 341 | AND: [FilterUpdateManyUserInput!] 342 | } 343 | @@ -24875,7 +24875,7 @@ exports[` 28`] = ` 339 | _operators: OperatorsFilterUpdateManyUserInput 340 | OR: [FilterUpdateManyUserInput!] > 341 | AND: [FilterUpdateManyUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 342 | } 343 | 344 | input FilterUpdateOneUserInput { @@ -26012,7 +26012,7 @@ exports[` 29`] = ` 362 | """ 363 | _operators: OperatorsFilterUpdateOneUserInput > 364 | OR: [FilterUpdateOneUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 365 | AND: [FilterUpdateOneUserInput!] 366 | } 367 | @@ -27127,7 +27127,7 @@ exports[` 30`] = ` 363 | _operators: OperatorsFilterUpdateOneUserInput 364 | OR: [FilterUpdateOneUserInput!] > 365 | AND: [FilterUpdateOneUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 366 | } 367 | 368 | input FilterUserInput { @@ -28264,7 +28264,7 @@ exports[` 31`] = ` 386 | """ 387 | _operators: OperatorsFilterUserInput > 388 | OR: [FilterUserInput!] - | ^ Input property name "OR" should be in camelCase format + | ^^ Input property name "OR" should be in camelCase format 389 | AND: [FilterUserInput!] 390 | } 391 | @@ -29379,7 +29379,7 @@ exports[` 32`] = ` 387 | _operators: OperatorsFilterUserInput 388 | OR: [FilterUserInput!] > 389 | AND: [FilterUserInput!] - | ^ Input property name "AND" should be in camelCase format + | ^^^ Input property name "AND" should be in camelCase format 390 | } 391 | 392 | input GenderOperatorsFilterFindManyUserInput { @@ -30105,95 +30105,95 @@ exports[` 32`] = ` exports[` 33`] = ` > 1 | enum B { test } - | ^ Enumerator name "B" should be in camelCase format + | ^ Enumerator name "B" should be in camelCase format `; exports[` 34`] = ` > 1 | enum B { test } - | ^ Enumeration value name "test" should be in UPPER_CASE format + | ^^^^ Enumeration value name "test" should be in UPPER_CASE format `; exports[` 35`] = ` > 1 | input test { _Value: String } - | ^ Input type name "test" should be in PascalCase format + | ^^^^ Input type name "test" should be in PascalCase format `; exports[` 36`] = ` > 1 | input test { _Value: String } - | ^ Input property name "_Value" should be in snake_case format + | ^^^^^^ Input property name "_Value" should be in snake_case format `; exports[` 37`] = ` > 1 | input test { _Value: String } - | ^ Leading underscores are not allowed + | ^^^^^^ Leading underscores are not allowed `; exports[` 38`] = ` > 1 | type TypeOne { aField: String } enum Z { VALUE_ONE VALUE_TWO } - | ^ Type name "TypeOne" should be in camelCase format + | ^^^^^^^ Type name "TypeOne" should be in camelCase format `; exports[` 39`] = ` > 1 | type TypeOne { aField: String } enum Z { VALUE_ONE VALUE_TWO } - | ^ Field name "aField" should have "AAA" suffix + | ^^^^^^ Field name "aField" should have "AAA" suffix `; exports[` 40`] = ` > 1 | type TypeOne { aField: String } enum Z { VALUE_ONE VALUE_TWO } - | ^ Enumeration value name "VALUE_ONE" should have "ENUM" suffix + | ^^^^^^^^^ Enumeration value name "VALUE_ONE" should have "ENUM" suffix `; exports[` 41`] = ` > 1 | type TypeOne { aField: String } enum Z { VALUE_ONE VALUE_TWO } - | ^ Enumeration value name "VALUE_TWO" should have "ENUM" suffix + | ^^^^^^^^^ Enumeration value name "VALUE_TWO" should have "ENUM" suffix `; exports[` 42`] = ` > 1 | type One { aField: String } enum Z { A_ENUM_VALUE_ONE VALUE_TWO } - | ^ Field name "aField" should have "Field" prefix + | ^^^^^^ Field name "aField" should have "Field" prefix `; exports[` 43`] = ` > 1 | type One { aField: String } enum Z { A_ENUM_VALUE_ONE VALUE_TWO } - | ^ Enumeration value name "A_ENUM_VALUE_ONE" should have "ENUM" prefix + | ^^^^^^^^^^^^^^^^ Enumeration value name "A_ENUM_VALUE_ONE" should have "ENUM" prefix `; exports[` 44`] = ` > 1 | type One { aField: String } enum Z { A_ENUM_VALUE_ONE VALUE_TWO } - | ^ Enumeration value name "VALUE_TWO" should have "ENUM" prefix + | ^^^^^^^^^ Enumeration value name "VALUE_TWO" should have "ENUM" prefix `; exports[` 45`] = ` > 1 | type One { getFoo: String, queryBar: String } type Query { getA(id: ID!): String, queryB: String } extend type Query { getC: String } - | ^ Type "One" should not have one of the following prefix(es): On + | ^^^ Type "One" should not have one of the following prefix(es): On `; exports[` 46`] = ` > 1 | type One { getFoo: String, queryBar: String } type Query { getA(id: ID!): String, queryB: String } extend type Query { getC: String } - | ^ Field "getFoo" should not have one of the following suffix(es): Foo + | ^^^^^^ Field "getFoo" should not have one of the following suffix(es): Foo `; exports[` 47`] = ` > 1 | type One { getFoo: String, queryBar: String } type Query { getA(id: ID!): String, queryB: String } extend type Query { getC: String } - | ^ Query "getA" should not have one of the following prefix(es): get, query + | ^^^^ Query "getA" should not have one of the following prefix(es): get, query `; exports[` 48`] = ` > 1 | type One { getFoo: String, queryBar: String } type Query { getA(id: ID!): String, queryB: String } extend type Query { getC: String } - | ^ Query "queryB" should not have one of the following prefix(es): get, query + | ^^^^^^ Query "queryB" should not have one of the following prefix(es): get, query `; exports[` 49`] = ` > 1 | type One { getFoo: String, queryBar: String } type Query { getA(id: ID!): String, queryB: String } extend type Query { getC: String } - | ^ Query "getC" should not have one of the following prefix(es): get, query + | ^^^^ Query "getC" should not have one of the following prefix(es): get, query `; exports[` 50`] = ` > 1 | query Foo { foo } query getBar { bar } - | ^ Operation name "Foo" should be in camelCase format + | ^^^ Operation name "Foo" should be in camelCase format `; exports[` 51`] = ` > 1 | query Foo { foo } query getBar { bar } - | ^ Operation "getBar" should not have one of the following prefix(es): get + | ^^^^^^ Operation "getBar" should not have one of the following prefix(es): get `; diff --git a/packages/plugin/tests/__snapshots__/strict-id-in-types.spec.ts.snap b/packages/plugin/tests/__snapshots__/strict-id-in-types.spec.ts.snap index f9b7357005d..c37c4488ea1 100644 --- a/packages/plugin/tests/__snapshots__/strict-id-in-types.spec.ts.snap +++ b/packages/plugin/tests/__snapshots__/strict-id-in-types.spec.ts.snap @@ -2,45 +2,45 @@ exports[` 1`] = ` > 1 | type B { name: String! } - | ^^^^^^^^^^^^^^^^^^^^^^^ B must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID + | ^ B must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID `; exports[` 2`] = ` > 1 | type B { id: ID! _id: String! } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B must have exactly one non-nullable unique identifier. Accepted name(s): id,_id ; Accepted type(s): ID,String + | ^ B must have exactly one non-nullable unique identifier. Accepted name(s): id,_id ; Accepted type(s): ID,String `; exports[` 3`] = ` > 1 | type B { id: String! } type B1 { id: [String] } type B2 { id: [String!] } type B3 { id: [String]! } type B4 { id: [String!]! } - | ^^^^^^^^^^^^^^^^^^^^^^^ B1 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String + | ^^ B1 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String `; exports[` 4`] = ` > 1 | type B { id: String! } type B1 { id: [String] } type B2 { id: [String!] } type B3 { id: [String]! } type B4 { id: [String!]! } - | ^^^^^^^^^^^^^^^^^^^^^^^^ B2 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String + | ^^ B2 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String `; exports[` 5`] = ` > 1 | type B { id: String! } type B1 { id: [String] } type B2 { id: [String!] } type B3 { id: [String]! } type B4 { id: [String!]! } - | ^^^^^^^^^^^^^^^^^^^^^^^^ B3 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String + | ^^ B3 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String `; exports[` 6`] = ` > 1 | type B { id: String! } type B1 { id: [String] } type B2 { id: [String!] } type B3 { id: [String]! } type B4 { id: [String!]! } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ B4 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String + | ^^ B4 must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): String `; exports[` 7`] = ` > 1 | type B { id: ID! } type Bresult { key: String! } type BPayload { bool: Boolean! } type BPagination { num: Int! } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Bresult must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID + | ^^^^^^^ Bresult must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID `; exports[` 8`] = ` > 1 | type B { id: ID! } type Bresult { key: String! } type BPayload { bool: Boolean! } type BPagination { num: Int! } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BPagination must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID + | ^^^^^^^^^^^ BPagination must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID `; exports[` 9`] = ` > 1 | type B { id: ID! } type BError { message: String! } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BError must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID + | ^^^^^^ BError must have exactly one non-nullable unique identifier. Accepted name(s): id ; Accepted type(s): ID `;