@graphql-eslint/eslint-plugin 3.4.0-alpha-735b6ae.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,7 +23,7 @@ type User {
23
23
  }
24
24
 
25
25
  # Query
26
- query user {
26
+ query {
27
27
  user {
28
28
  name
29
29
  }
@@ -42,7 +42,7 @@ type User {
42
42
  }
43
43
 
44
44
  # Query
45
- query user {
45
+ query {
46
46
  user {
47
47
  id
48
48
  name
@@ -4,7 +4,7 @@
4
4
 
5
5
  - Category: `Schema`
6
6
  - Rule name: `@graphql-eslint/strict-id-in-types`
7
- - Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
7
+ - Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
8
8
  - Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
9
9
 
10
10
  Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.
package/index.js CHANGED
@@ -2896,7 +2896,8 @@ const convertNode = (typeInfo) => (node, key, parent) => {
2896
2896
  }
2897
2897
  };
2898
2898
 
2899
- const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
2899
+ const RULE_ID$2 = 'require-id-when-available';
2900
+ const MESSAGE_ID = 'REQUIRE_ID_WHEN_AVAILABLE';
2900
2901
  const DEFAULT_ID_FIELD_NAME = 'id';
2901
2902
  const rule$j = {
2902
2903
  meta: {
@@ -2904,7 +2905,7 @@ const rule$j = {
2904
2905
  docs: {
2905
2906
  category: 'Operations',
2906
2907
  description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
2907
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
2908
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
2908
2909
  requiresSchema: true,
2909
2910
  requiresSiblings: true,
2910
2911
  examples: [
@@ -2918,7 +2919,7 @@ const rule$j = {
2918
2919
  }
2919
2920
 
2920
2921
  # Query
2921
- query user {
2922
+ query {
2922
2923
  user {
2923
2924
  name
2924
2925
  }
@@ -2935,7 +2936,7 @@ const rule$j = {
2935
2936
  }
2936
2937
 
2937
2938
  # Query
2938
- query user {
2939
+ query {
2939
2940
  user {
2940
2941
  id
2941
2942
  name
@@ -2947,7 +2948,7 @@ const rule$j = {
2947
2948
  recommended: true,
2948
2949
  },
2949
2950
  messages: {
2950
- [REQUIRE_ID_WHEN_AVAILABLE]: [
2951
+ [MESSAGE_ID]: [
2951
2952
  `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2952
2953
  `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2953
2954
  ].join('\n'),
@@ -2978,14 +2979,16 @@ const rule$j = {
2978
2979
  },
2979
2980
  },
2980
2981
  create(context) {
2981
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2982
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2982
+ requireGraphQLSchemaFromContext(RULE_ID$2, context);
2983
+ const siblings = requireSiblingsOperations(RULE_ID$2, context);
2983
2984
  const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2984
- const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2985
+ const idNames = utils.asArray(fieldName);
2985
2986
  const isFound = (s) => s.kind === graphql.Kind.FIELD && idNames.includes(s.name.value);
2987
+ // Skip check selections in FragmentDefinition
2988
+ const selector = 'OperationDefinition SelectionSet[parent.kind!=OperationDefinition]';
2986
2989
  return {
2987
- SelectionSet(node) {
2988
- var _a, _b;
2990
+ [selector](node) {
2991
+ var _a;
2989
2992
  const typeInfo = node.typeInfo();
2990
2993
  if (!typeInfo.gqlType) {
2991
2994
  return;
@@ -3002,53 +3005,50 @@ const rule$j = {
3002
3005
  return;
3003
3006
  }
3004
3007
  const checkedFragmentSpreads = new Set();
3005
- let found = false;
3006
3008
  for (const selection of node.selections) {
3007
3009
  if (isFound(selection)) {
3008
- found = true;
3010
+ return;
3009
3011
  }
3010
- else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
3011
- found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
3012
+ if (selection.kind === graphql.Kind.INLINE_FRAGMENT && selection.selectionSet.selections.some(isFound)) {
3013
+ return;
3012
3014
  }
3013
- else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
3015
+ if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
3014
3016
  const [foundSpread] = siblings.getFragment(selection.name.value);
3015
3017
  if (foundSpread) {
3016
3018
  checkedFragmentSpreads.add(foundSpread.document.name.value);
3017
- found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
3019
+ if (foundSpread.document.selectionSet.selections.some(isFound)) {
3020
+ return;
3021
+ }
3018
3022
  }
3019
3023
  }
3020
- if (found) {
3021
- break;
3022
- }
3023
3024
  }
3024
3025
  const { parent } = node;
3025
- const hasIdFieldInInterfaceSelectionSet = parent &&
3026
- parent.kind === graphql.Kind.INLINE_FRAGMENT &&
3027
- parent.parent &&
3028
- parent.parent.kind === graphql.Kind.SELECTION_SET &&
3029
- parent.parent.selections.some(s => isFound(s));
3030
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
3031
- context.report({
3032
- loc: getLocation(node.loc),
3033
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
3034
- data: {
3035
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
3036
- fieldName: idNames.map(name => `"${name}"`).join(' or '),
3037
- },
3038
- });
3026
+ const hasIdFieldInInterfaceSelectionSet = (parent === null || parent === void 0 ? void 0 : parent.kind) === graphql.Kind.INLINE_FRAGMENT &&
3027
+ ((_a = parent.parent) === null || _a === void 0 ? void 0 : _a.kind) === graphql.Kind.SELECTION_SET &&
3028
+ parent.parent.selections.some(isFound);
3029
+ if (hasIdFieldInInterfaceSelectionSet) {
3030
+ return;
3039
3031
  }
3032
+ context.report({
3033
+ loc: getLocation(node.loc),
3034
+ messageId: MESSAGE_ID,
3035
+ data: {
3036
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
3037
+ fieldName: idNames.map(name => `"${name}"`).join(' or '),
3038
+ },
3039
+ });
3040
3040
  },
3041
3041
  };
3042
3042
  },
3043
3043
  };
3044
3044
 
3045
- const RULE_ID$2 = 'selection-set-depth';
3045
+ const RULE_ID$3 = 'selection-set-depth';
3046
3046
  const rule$k = {
3047
3047
  meta: {
3048
3048
  docs: {
3049
3049
  category: 'Operations',
3050
3050
  description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
3051
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
3051
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$3}.md`,
3052
3052
  requiresSiblings: true,
3053
3053
  examples: [
3054
3054
  {
@@ -3122,10 +3122,10 @@ const rule$k = {
3122
3122
  create(context) {
3123
3123
  let siblings = null;
3124
3124
  try {
3125
- siblings = requireSiblingsOperations(RULE_ID$2, context);
3125
+ siblings = requireSiblingsOperations(RULE_ID$3, context);
3126
3126
  }
3127
3127
  catch (e) {
3128
- logger.warn(`Rule "${RULE_ID$2}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3128
+ logger.warn(`Rule "${RULE_ID$3}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3129
3129
  }
3130
3130
  const { maxDepth } = context.options[0];
3131
3131
  const ignore = context.options[0].ignore || [];
@@ -3150,35 +3150,33 @@ const rule$k = {
3150
3150
  });
3151
3151
  }
3152
3152
  catch (e) {
3153
- logger.warn(`Rule "${RULE_ID$2}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3153
+ logger.warn(`Rule "${RULE_ID$3}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3154
3154
  }
3155
3155
  },
3156
3156
  };
3157
3157
  },
3158
3158
  };
3159
3159
 
3160
- const shouldIgnoreNode = ({ node, exceptions }) => {
3161
- const rawNode = node.rawNode();
3162
- if (exceptions.types && exceptions.types.includes(rawNode.name.value)) {
3163
- return true;
3164
- }
3165
- if (exceptions.suffixes && exceptions.suffixes.some(suffix => rawNode.name.value.endsWith(suffix))) {
3166
- return true;
3167
- }
3168
- return false;
3169
- };
3160
+ const RULE_ID$4 = 'strict-id-in-types';
3170
3161
  const rule$l = {
3171
3162
  meta: {
3172
3163
  type: 'suggestion',
3173
3164
  docs: {
3174
- description: 'Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.',
3165
+ description: `Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.`,
3175
3166
  category: 'Schema',
3176
3167
  recommended: true,
3177
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
3168
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$4}.md`,
3169
+ requiresSchema: true,
3178
3170
  examples: [
3179
3171
  {
3180
3172
  title: 'Incorrect',
3181
- usage: [{ acceptedIdNames: ['id', '_id'], acceptedIdTypes: ['ID'], exceptions: { suffixes: ['Payload'] } }],
3173
+ usage: [
3174
+ {
3175
+ acceptedIdNames: ['id', '_id'],
3176
+ acceptedIdTypes: ['ID'],
3177
+ exceptions: { suffixes: ['Payload'] },
3178
+ },
3179
+ ],
3182
3180
  code: /* GraphQL */ `
3183
3181
  # Incorrect field name
3184
3182
  type InvalidFieldName {
@@ -3280,6 +3278,9 @@ const rule$l = {
3280
3278
  },
3281
3279
  },
3282
3280
  },
3281
+ messages: {
3282
+ [RULE_ID$4]: `{{ typeName }} must have exactly one non-nullable unique identifier. Accepted name(s): {{ acceptedNamesString }}; Accepted type(s): {{ acceptedTypesString }}.`,
3283
+ },
3283
3284
  },
3284
3285
  create(context) {
3285
3286
  const options = {
@@ -3288,9 +3289,18 @@ const rule$l = {
3288
3289
  exceptions: {},
3289
3290
  ...context.options[0],
3290
3291
  };
3292
+ const schema = requireGraphQLSchemaFromContext(RULE_ID$4, context);
3293
+ const rootTypeNames = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
3294
+ .filter(Boolean)
3295
+ .map(type => type.name);
3296
+ const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join('|')})$/]`;
3291
3297
  return {
3292
- ObjectTypeDefinition(node) {
3293
- if (shouldIgnoreNode({ node, exceptions: options.exceptions })) {
3298
+ [selector](node) {
3299
+ var _a, _b;
3300
+ const typeName = node.name.value;
3301
+ const shouldIgnoreNode = ((_a = options.exceptions.types) === null || _a === void 0 ? void 0 : _a.includes(typeName)) ||
3302
+ ((_b = options.exceptions.suffixes) === null || _b === void 0 ? void 0 : _b.some(suffix => typeName.endsWith(suffix)));
3303
+ if (shouldIgnoreNode) {
3294
3304
  return;
3295
3305
  }
3296
3306
  const validIds = node.fields.filter(field => {
@@ -3303,18 +3313,17 @@ const rule$l = {
3303
3313
  }
3304
3314
  return isValidIdName && isValidIdType;
3305
3315
  });
3306
- const typeName = node.name.value;
3307
3316
  // Usually, there should be only one unique identifier field per type.
3308
3317
  // Some clients allow multiple fields to be used. If more people need this,
3309
3318
  // we can extend this rule later.
3310
3319
  if (validIds.length !== 1) {
3311
3320
  context.report({
3312
3321
  loc: getLocation(node.name.loc, typeName),
3313
- message: `{{ typeName }} must have exactly one non-nullable unique identifier. Accepted name(s): {{ acceptedNamesString }} ; Accepted type(s): {{ acceptedTypesString }}`,
3322
+ messageId: RULE_ID$4,
3314
3323
  data: {
3315
3324
  typeName,
3316
- acceptedNamesString: options.acceptedIdNames.join(','),
3317
- acceptedTypesString: options.acceptedIdTypes.join(','),
3325
+ acceptedNamesString: options.acceptedIdNames.join(', '),
3326
+ acceptedTypesString: options.acceptedIdTypes.join(', '),
3318
3327
  },
3319
3328
  });
3320
3329
  }
package/index.mjs CHANGED
@@ -2890,7 +2890,8 @@ const convertNode = (typeInfo) => (node, key, parent) => {
2890
2890
  }
2891
2891
  };
2892
2892
 
2893
- const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
2893
+ const RULE_ID$2 = 'require-id-when-available';
2894
+ const MESSAGE_ID = 'REQUIRE_ID_WHEN_AVAILABLE';
2894
2895
  const DEFAULT_ID_FIELD_NAME = 'id';
2895
2896
  const rule$j = {
2896
2897
  meta: {
@@ -2898,7 +2899,7 @@ const rule$j = {
2898
2899
  docs: {
2899
2900
  category: 'Operations',
2900
2901
  description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
2901
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
2902
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
2902
2903
  requiresSchema: true,
2903
2904
  requiresSiblings: true,
2904
2905
  examples: [
@@ -2912,7 +2913,7 @@ const rule$j = {
2912
2913
  }
2913
2914
 
2914
2915
  # Query
2915
- query user {
2916
+ query {
2916
2917
  user {
2917
2918
  name
2918
2919
  }
@@ -2929,7 +2930,7 @@ const rule$j = {
2929
2930
  }
2930
2931
 
2931
2932
  # Query
2932
- query user {
2933
+ query {
2933
2934
  user {
2934
2935
  id
2935
2936
  name
@@ -2941,7 +2942,7 @@ const rule$j = {
2941
2942
  recommended: true,
2942
2943
  },
2943
2944
  messages: {
2944
- [REQUIRE_ID_WHEN_AVAILABLE]: [
2945
+ [MESSAGE_ID]: [
2945
2946
  `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2946
2947
  `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2947
2948
  ].join('\n'),
@@ -2972,14 +2973,16 @@ const rule$j = {
2972
2973
  },
2973
2974
  },
2974
2975
  create(context) {
2975
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2976
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2976
+ requireGraphQLSchemaFromContext(RULE_ID$2, context);
2977
+ const siblings = requireSiblingsOperations(RULE_ID$2, context);
2977
2978
  const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2978
- const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2979
+ const idNames = asArray(fieldName);
2979
2980
  const isFound = (s) => s.kind === Kind.FIELD && idNames.includes(s.name.value);
2981
+ // Skip check selections in FragmentDefinition
2982
+ const selector = 'OperationDefinition SelectionSet[parent.kind!=OperationDefinition]';
2980
2983
  return {
2981
- SelectionSet(node) {
2982
- var _a, _b;
2984
+ [selector](node) {
2985
+ var _a;
2983
2986
  const typeInfo = node.typeInfo();
2984
2987
  if (!typeInfo.gqlType) {
2985
2988
  return;
@@ -2996,53 +2999,50 @@ const rule$j = {
2996
2999
  return;
2997
3000
  }
2998
3001
  const checkedFragmentSpreads = new Set();
2999
- let found = false;
3000
3002
  for (const selection of node.selections) {
3001
3003
  if (isFound(selection)) {
3002
- found = true;
3004
+ return;
3003
3005
  }
3004
- else if (selection.kind === Kind.INLINE_FRAGMENT) {
3005
- found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
3006
+ if (selection.kind === Kind.INLINE_FRAGMENT && selection.selectionSet.selections.some(isFound)) {
3007
+ return;
3006
3008
  }
3007
- else if (selection.kind === Kind.FRAGMENT_SPREAD) {
3009
+ if (selection.kind === Kind.FRAGMENT_SPREAD) {
3008
3010
  const [foundSpread] = siblings.getFragment(selection.name.value);
3009
3011
  if (foundSpread) {
3010
3012
  checkedFragmentSpreads.add(foundSpread.document.name.value);
3011
- found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
3013
+ if (foundSpread.document.selectionSet.selections.some(isFound)) {
3014
+ return;
3015
+ }
3012
3016
  }
3013
3017
  }
3014
- if (found) {
3015
- break;
3016
- }
3017
3018
  }
3018
3019
  const { parent } = node;
3019
- const hasIdFieldInInterfaceSelectionSet = parent &&
3020
- parent.kind === Kind.INLINE_FRAGMENT &&
3021
- parent.parent &&
3022
- parent.parent.kind === Kind.SELECTION_SET &&
3023
- parent.parent.selections.some(s => isFound(s));
3024
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
3025
- context.report({
3026
- loc: getLocation(node.loc),
3027
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
3028
- data: {
3029
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
3030
- fieldName: idNames.map(name => `"${name}"`).join(' or '),
3031
- },
3032
- });
3020
+ const hasIdFieldInInterfaceSelectionSet = (parent === null || parent === void 0 ? void 0 : parent.kind) === Kind.INLINE_FRAGMENT &&
3021
+ ((_a = parent.parent) === null || _a === void 0 ? void 0 : _a.kind) === Kind.SELECTION_SET &&
3022
+ parent.parent.selections.some(isFound);
3023
+ if (hasIdFieldInInterfaceSelectionSet) {
3024
+ return;
3033
3025
  }
3026
+ context.report({
3027
+ loc: getLocation(node.loc),
3028
+ messageId: MESSAGE_ID,
3029
+ data: {
3030
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
3031
+ fieldName: idNames.map(name => `"${name}"`).join(' or '),
3032
+ },
3033
+ });
3034
3034
  },
3035
3035
  };
3036
3036
  },
3037
3037
  };
3038
3038
 
3039
- const RULE_ID$2 = 'selection-set-depth';
3039
+ const RULE_ID$3 = 'selection-set-depth';
3040
3040
  const rule$k = {
3041
3041
  meta: {
3042
3042
  docs: {
3043
3043
  category: 'Operations',
3044
3044
  description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
3045
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
3045
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$3}.md`,
3046
3046
  requiresSiblings: true,
3047
3047
  examples: [
3048
3048
  {
@@ -3116,10 +3116,10 @@ const rule$k = {
3116
3116
  create(context) {
3117
3117
  let siblings = null;
3118
3118
  try {
3119
- siblings = requireSiblingsOperations(RULE_ID$2, context);
3119
+ siblings = requireSiblingsOperations(RULE_ID$3, context);
3120
3120
  }
3121
3121
  catch (e) {
3122
- logger.warn(`Rule "${RULE_ID$2}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3122
+ logger.warn(`Rule "${RULE_ID$3}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3123
3123
  }
3124
3124
  const { maxDepth } = context.options[0];
3125
3125
  const ignore = context.options[0].ignore || [];
@@ -3144,35 +3144,33 @@ const rule$k = {
3144
3144
  });
3145
3145
  }
3146
3146
  catch (e) {
3147
- logger.warn(`Rule "${RULE_ID$2}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3147
+ logger.warn(`Rule "${RULE_ID$3}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3148
3148
  }
3149
3149
  },
3150
3150
  };
3151
3151
  },
3152
3152
  };
3153
3153
 
3154
- const shouldIgnoreNode = ({ node, exceptions }) => {
3155
- const rawNode = node.rawNode();
3156
- if (exceptions.types && exceptions.types.includes(rawNode.name.value)) {
3157
- return true;
3158
- }
3159
- if (exceptions.suffixes && exceptions.suffixes.some(suffix => rawNode.name.value.endsWith(suffix))) {
3160
- return true;
3161
- }
3162
- return false;
3163
- };
3154
+ const RULE_ID$4 = 'strict-id-in-types';
3164
3155
  const rule$l = {
3165
3156
  meta: {
3166
3157
  type: 'suggestion',
3167
3158
  docs: {
3168
- description: 'Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.',
3159
+ description: `Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.`,
3169
3160
  category: 'Schema',
3170
3161
  recommended: true,
3171
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
3162
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$4}.md`,
3163
+ requiresSchema: true,
3172
3164
  examples: [
3173
3165
  {
3174
3166
  title: 'Incorrect',
3175
- usage: [{ acceptedIdNames: ['id', '_id'], acceptedIdTypes: ['ID'], exceptions: { suffixes: ['Payload'] } }],
3167
+ usage: [
3168
+ {
3169
+ acceptedIdNames: ['id', '_id'],
3170
+ acceptedIdTypes: ['ID'],
3171
+ exceptions: { suffixes: ['Payload'] },
3172
+ },
3173
+ ],
3176
3174
  code: /* GraphQL */ `
3177
3175
  # Incorrect field name
3178
3176
  type InvalidFieldName {
@@ -3274,6 +3272,9 @@ const rule$l = {
3274
3272
  },
3275
3273
  },
3276
3274
  },
3275
+ messages: {
3276
+ [RULE_ID$4]: `{{ typeName }} must have exactly one non-nullable unique identifier. Accepted name(s): {{ acceptedNamesString }}; Accepted type(s): {{ acceptedTypesString }}.`,
3277
+ },
3277
3278
  },
3278
3279
  create(context) {
3279
3280
  const options = {
@@ -3282,9 +3283,18 @@ const rule$l = {
3282
3283
  exceptions: {},
3283
3284
  ...context.options[0],
3284
3285
  };
3286
+ const schema = requireGraphQLSchemaFromContext(RULE_ID$4, context);
3287
+ const rootTypeNames = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
3288
+ .filter(Boolean)
3289
+ .map(type => type.name);
3290
+ const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join('|')})$/]`;
3285
3291
  return {
3286
- ObjectTypeDefinition(node) {
3287
- if (shouldIgnoreNode({ node, exceptions: options.exceptions })) {
3292
+ [selector](node) {
3293
+ var _a, _b;
3294
+ const typeName = node.name.value;
3295
+ const shouldIgnoreNode = ((_a = options.exceptions.types) === null || _a === void 0 ? void 0 : _a.includes(typeName)) ||
3296
+ ((_b = options.exceptions.suffixes) === null || _b === void 0 ? void 0 : _b.some(suffix => typeName.endsWith(suffix)));
3297
+ if (shouldIgnoreNode) {
3288
3298
  return;
3289
3299
  }
3290
3300
  const validIds = node.fields.filter(field => {
@@ -3297,18 +3307,17 @@ const rule$l = {
3297
3307
  }
3298
3308
  return isValidIdName && isValidIdType;
3299
3309
  });
3300
- const typeName = node.name.value;
3301
3310
  // Usually, there should be only one unique identifier field per type.
3302
3311
  // Some clients allow multiple fields to be used. If more people need this,
3303
3312
  // we can extend this rule later.
3304
3313
  if (validIds.length !== 1) {
3305
3314
  context.report({
3306
3315
  loc: getLocation(node.name.loc, typeName),
3307
- message: `{{ typeName }} must have exactly one non-nullable unique identifier. Accepted name(s): {{ acceptedNamesString }} ; Accepted type(s): {{ acceptedTypesString }}`,
3316
+ messageId: RULE_ID$4,
3308
3317
  data: {
3309
3318
  typeName,
3310
- acceptedNamesString: options.acceptedIdNames.join(','),
3311
- acceptedTypesString: options.acceptedIdTypes.join(','),
3319
+ acceptedNamesString: options.acceptedIdNames.join(', '),
3320
+ acceptedTypesString: options.acceptedIdTypes.join(', '),
3312
3321
  },
3313
3322
  });
3314
3323
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.4.0-alpha-735b6ae.0",
3
+ "version": "3.6.0",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
package/rules/index.d.ts CHANGED
@@ -48,18 +48,12 @@ export declare const rules: {
48
48
  DirectiveDefinition?: boolean;
49
49
  }], false>;
50
50
  'require-field-of-type-query-in-mutation-result': import("..").GraphQLESLintRule<any[], false>;
51
- 'require-id-when-available': import("..").GraphQLESLintRule<[{
52
- fieldName: string;
53
- }], true>;
51
+ 'require-id-when-available': import("..").GraphQLESLintRule<[import("./require-id-when-available").RequireIdWhenAvailableRuleConfig], true>;
54
52
  'selection-set-depth': import("..").GraphQLESLintRule<[{
55
53
  maxDepth: number;
56
54
  ignore?: string[];
57
55
  }], false>;
58
- 'strict-id-in-types': import("..").GraphQLESLintRule<[{
59
- acceptedIdNames?: string[];
60
- acceptedIdTypes?: string[];
61
- exceptions?: import("./strict-id-in-types").ExceptionRule;
62
- }], false>;
56
+ 'strict-id-in-types': import("..").GraphQLESLintRule<[import("./strict-id-in-types").StrictIdInTypesRuleConfig], false>;
63
57
  'unique-fragment-name': import("..").GraphQLESLintRule<any[], false>;
64
58
  'unique-operation-name': import("..").GraphQLESLintRule<any[], false>;
65
59
  };
@@ -1,6 +1,6 @@
1
1
  import { GraphQLESLintRule } from '../types';
2
- declare type RequireIdWhenAvailableRuleConfig = {
3
- fieldName: string;
2
+ export declare type RequireIdWhenAvailableRuleConfig = {
3
+ fieldName: string | string[];
4
4
  };
5
5
  declare const rule: GraphQLESLintRule<[RequireIdWhenAvailableRuleConfig], true>;
6
6
  export default rule;
@@ -1,12 +1,11 @@
1
1
  import { GraphQLESLintRule } from '../types';
2
- export interface ExceptionRule {
3
- types?: string[];
4
- suffixes?: string[];
5
- }
6
- declare type StrictIdInTypesRuleConfig = {
2
+ export declare type StrictIdInTypesRuleConfig = {
7
3
  acceptedIdNames?: string[];
8
4
  acceptedIdTypes?: string[];
9
- exceptions?: ExceptionRule;
5
+ exceptions?: {
6
+ types?: string[];
7
+ suffixes?: string[];
8
+ };
10
9
  };
11
10
  declare const rule: GraphQLESLintRule<[StrictIdInTypesRuleConfig]>;
12
11
  export default rule;