@graphql-eslint/eslint-plugin 3.0.0-alpha-069461d.0 → 3.0.0-alpha-698204a.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.
Files changed (88) hide show
  1. package/README.md +19 -8
  2. package/configs/base.d.ts +5 -0
  3. package/configs/index.d.ts +59 -91
  4. package/configs/operations-all.d.ts +19 -0
  5. package/configs/{recommended.d.ts → operations-recommended.d.ts} +11 -30
  6. package/configs/schema-all.d.ts +23 -0
  7. package/configs/schema-recommended.d.ts +44 -0
  8. package/docs/README.md +9 -17
  9. package/docs/deprecated-rules.md +21 -0
  10. package/docs/rules/alphabetize.md +1 -1
  11. package/docs/rules/description-style.md +4 -2
  12. package/docs/rules/executable-definitions.md +2 -2
  13. package/docs/rules/fields-on-correct-type.md +2 -2
  14. package/docs/rules/fragments-on-composite-type.md +2 -2
  15. package/docs/rules/input-name.md +1 -1
  16. package/docs/rules/known-argument-names.md +2 -2
  17. package/docs/rules/known-directives.md +2 -2
  18. package/docs/rules/known-fragment-names.md +2 -2
  19. package/docs/rules/known-type-names.md +2 -2
  20. package/docs/rules/lone-anonymous-operation.md +2 -2
  21. package/docs/rules/lone-schema-definition.md +2 -2
  22. package/docs/rules/match-document-filename.md +6 -4
  23. package/docs/rules/naming-convention.md +26 -27
  24. package/docs/rules/no-anonymous-operations.md +2 -2
  25. package/docs/rules/no-case-insensitive-enum-values-duplicates.md +2 -2
  26. package/docs/rules/no-deprecated.md +3 -1
  27. package/docs/rules/{avoid-duplicate-fields.md → no-duplicate-fields.md} +10 -8
  28. package/docs/rules/no-fragment-cycles.md +2 -2
  29. package/docs/rules/no-hashtag-description.md +3 -1
  30. package/docs/rules/no-root-type.md +7 -1
  31. package/docs/rules/{avoid-scalar-result-type-on-mutation.md → no-scalar-result-type-on-mutation.md} +7 -7
  32. package/docs/rules/no-typename-prefix.md +37 -0
  33. package/docs/rules/no-undefined-variables.md +2 -2
  34. package/docs/rules/no-unreachable-types.md +3 -1
  35. package/docs/rules/no-unused-fields.md +1 -1
  36. package/docs/rules/no-unused-fragments.md +2 -2
  37. package/docs/rules/no-unused-variables.md +2 -2
  38. package/docs/rules/one-field-subscriptions.md +2 -2
  39. package/docs/rules/overlapping-fields-can-be-merged.md +2 -2
  40. package/docs/rules/possible-fragment-spread.md +2 -2
  41. package/docs/rules/possible-type-extension.md +2 -2
  42. package/docs/rules/provided-required-arguments.md +2 -2
  43. package/docs/rules/require-deprecation-date.md +1 -1
  44. package/docs/rules/require-deprecation-reason.md +2 -2
  45. package/docs/rules/require-description.md +36 -7
  46. package/docs/rules/require-field-of-type-query-in-mutation-result.md +1 -1
  47. package/docs/rules/require-id-when-available.md +3 -1
  48. package/docs/rules/scalar-leafs.md +2 -2
  49. package/docs/rules/selection-set-depth.md +9 -2
  50. package/docs/rules/strict-id-in-types.md +16 -10
  51. package/docs/rules/unique-argument-names.md +2 -2
  52. package/docs/rules/unique-directive-names-per-location.md +2 -2
  53. package/docs/rules/unique-directive-names.md +2 -2
  54. package/docs/rules/unique-enum-value-names.md +2 -2
  55. package/docs/rules/unique-field-definition-names.md +2 -2
  56. package/docs/rules/unique-fragment-name.md +1 -1
  57. package/docs/rules/unique-input-field-names.md +2 -2
  58. package/docs/rules/unique-operation-name.md +1 -1
  59. package/docs/rules/unique-operation-types.md +2 -2
  60. package/docs/rules/unique-type-names.md +2 -2
  61. package/docs/rules/unique-variable-names.md +2 -2
  62. package/docs/rules/value-literals-of-correct-type.md +2 -2
  63. package/docs/rules/variables-are-input-types.md +2 -2
  64. package/docs/rules/variables-in-allowed-position.md +2 -2
  65. package/index.js +566 -599
  66. package/index.mjs +567 -600
  67. package/package.json +1 -1
  68. package/rules/alphabetize.d.ts +8 -10
  69. package/rules/description-style.d.ts +4 -6
  70. package/rules/index.d.ts +18 -8
  71. package/rules/input-name.d.ts +1 -1
  72. package/rules/match-document-filename.d.ts +8 -10
  73. package/rules/naming-convention.d.ts +1 -1
  74. package/rules/{avoid-duplicate-fields.d.ts → no-duplicate-fields.d.ts} +0 -0
  75. package/rules/{avoid-scalar-result-type-on-mutation.d.ts → no-scalar-result-type-on-mutation.d.ts} +0 -0
  76. package/rules/{avoid-typename-prefix.d.ts → no-typename-prefix.d.ts} +0 -0
  77. package/rules/require-description.d.ts +10 -6
  78. package/rules/require-id-when-available.d.ts +3 -3
  79. package/rules/selection-set-depth.d.ts +3 -3
  80. package/rules/strict-id-in-types.d.ts +6 -8
  81. package/types.d.ts +9 -5
  82. package/utils.d.ts +1 -1
  83. package/configs/all.d.ts +0 -99
  84. package/docs/rules/avoid-operation-name-prefix.md +0 -50
  85. package/docs/rules/avoid-typename-prefix.md +0 -37
  86. package/docs/rules/no-operation-name-suffix.md +0 -38
  87. package/rules/avoid-operation-name-prefix.d.ts +0 -9
  88. package/rules/no-operation-name-suffix.d.ts +0 -3
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { Kind, validate, isScalarType, TokenKind, isNonNullType, isListType, isObjectType as isObjectType$1, visit, visitWithTypeInfo, GraphQLObjectType, GraphQLInterfaceType, TypeInfo, isInterfaceType, Source, GraphQLError } from 'graphql';
1
+ import { Kind, validate, TokenKind, isScalarType, isNonNullType, isListType, isObjectType as isObjectType$1, visit, visitWithTypeInfo, GraphQLObjectType, GraphQLInterfaceType, TypeInfo, isInterfaceType, Source, GraphQLError } from 'graphql';
2
2
  import { validateSDL } from 'graphql/validation/validate';
3
3
  import { processImport, parseImportLine } from '@graphql-tools/import';
4
4
  import { statSync, existsSync, readFileSync } from 'fs';
@@ -12,22 +12,21 @@ import { CodeFileLoader } from '@graphql-tools/code-file-loader';
12
12
  import { RuleTester, Linter } from 'eslint';
13
13
  import { codeFrameColumns } from '@babel/code-frame';
14
14
 
15
+ const base = {
16
+ parser: '@graphql-eslint/eslint-plugin',
17
+ plugins: ['@graphql-eslint'],
18
+ };
19
+
15
20
  /*
16
21
  * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
17
22
  */
18
- const recommendedConfig = {
19
- parser: '@graphql-eslint/eslint-plugin',
20
- plugins: ['@graphql-eslint'],
23
+ const schemaRecommendedConfig = {
24
+ extends: ['plugin:@graphql-eslint/base'],
21
25
  rules: {
22
- '@graphql-eslint/avoid-typename-prefix': 'error',
23
- '@graphql-eslint/executable-definitions': 'error',
24
- '@graphql-eslint/fields-on-correct-type': 'error',
25
- '@graphql-eslint/fragments-on-composite-type': 'error',
26
+ '@graphql-eslint/description-style': 'error',
26
27
  '@graphql-eslint/known-argument-names': 'error',
27
28
  '@graphql-eslint/known-directives': 'error',
28
- '@graphql-eslint/known-fragment-names': 'error',
29
29
  '@graphql-eslint/known-type-names': 'error',
30
- '@graphql-eslint/lone-anonymous-operation': 'error',
31
30
  '@graphql-eslint/lone-schema-definition': 'error',
32
31
  '@graphql-eslint/naming-convention': [
33
32
  'error',
@@ -36,12 +35,6 @@ const recommendedConfig = {
36
35
  fields: 'camelCase',
37
36
  overrides: {
38
37
  EnumValueDefinition: 'UPPER_CASE',
39
- OperationDefinition: {
40
- style: 'PascalCase',
41
- forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
42
- forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
43
- },
44
- FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
45
38
  'FieldDefinition[parent.name.value=Query]': {
46
39
  forbiddenPrefixes: ['query', 'get'],
47
40
  forbiddenSuffixes: ['Query'],
@@ -57,29 +50,93 @@ const recommendedConfig = {
57
50
  },
58
51
  },
59
52
  ],
60
- '@graphql-eslint/no-anonymous-operations': 'error',
61
53
  '@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
54
+ '@graphql-eslint/no-hashtag-description': 'error',
55
+ '@graphql-eslint/no-typename-prefix': 'error',
56
+ '@graphql-eslint/no-unreachable-types': 'error',
57
+ '@graphql-eslint/possible-type-extension': 'error',
58
+ '@graphql-eslint/provided-required-arguments': 'error',
59
+ '@graphql-eslint/require-deprecation-reason': 'error',
60
+ '@graphql-eslint/strict-id-in-types': 'error',
61
+ '@graphql-eslint/unique-directive-names': 'error',
62
+ '@graphql-eslint/unique-directive-names-per-location': 'error',
63
+ '@graphql-eslint/unique-enum-value-names': 'error',
64
+ '@graphql-eslint/unique-field-definition-names': 'error',
65
+ '@graphql-eslint/unique-operation-types': 'error',
66
+ '@graphql-eslint/unique-type-names': 'error',
67
+ },
68
+ };
69
+
70
+ /*
71
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
72
+ */
73
+ const schemaAllConfig = {
74
+ extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/schema-recommended'],
75
+ rules: {
76
+ '@graphql-eslint/alphabetize': [
77
+ 'error',
78
+ {
79
+ fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
80
+ values: ['EnumTypeDefinition'],
81
+ arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
82
+ },
83
+ ],
84
+ '@graphql-eslint/input-name': 'error',
85
+ '@graphql-eslint/no-root-type': 'off',
86
+ '@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
87
+ '@graphql-eslint/no-unused-fields': 'off',
88
+ '@graphql-eslint/require-deprecation-date': 'error',
89
+ '@graphql-eslint/require-description': ['error', { types: true, overrides: { DirectiveDefinition: true } }],
90
+ '@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
91
+ },
92
+ };
93
+
94
+ /*
95
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
96
+ */
97
+ const operationsRecommendedConfig = {
98
+ extends: ['plugin:@graphql-eslint/base'],
99
+ rules: {
100
+ '@graphql-eslint/executable-definitions': 'error',
101
+ '@graphql-eslint/fields-on-correct-type': 'error',
102
+ '@graphql-eslint/fragments-on-composite-type': 'error',
103
+ '@graphql-eslint/known-argument-names': 'error',
104
+ '@graphql-eslint/known-directives': 'error',
105
+ '@graphql-eslint/known-fragment-names': 'error',
106
+ '@graphql-eslint/known-type-names': 'error',
107
+ '@graphql-eslint/lone-anonymous-operation': 'error',
108
+ '@graphql-eslint/naming-convention': [
109
+ 'error',
110
+ {
111
+ overrides: {
112
+ Argument: 'camelCase',
113
+ VariableDefinition: 'camelCase',
114
+ OperationDefinition: {
115
+ style: 'PascalCase',
116
+ forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
117
+ forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
118
+ },
119
+ FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
120
+ },
121
+ },
122
+ ],
123
+ '@graphql-eslint/no-anonymous-operations': 'error',
124
+ '@graphql-eslint/no-deprecated': 'error',
125
+ '@graphql-eslint/no-duplicate-fields': 'error',
62
126
  '@graphql-eslint/no-fragment-cycles': 'error',
63
- '@graphql-eslint/no-operation-name-suffix': 'error',
64
127
  '@graphql-eslint/no-undefined-variables': 'error',
65
128
  '@graphql-eslint/no-unused-fragments': 'error',
66
129
  '@graphql-eslint/no-unused-variables': 'error',
67
130
  '@graphql-eslint/one-field-subscriptions': 'error',
68
131
  '@graphql-eslint/overlapping-fields-can-be-merged': 'error',
69
132
  '@graphql-eslint/possible-fragment-spread': 'error',
70
- '@graphql-eslint/possible-type-extension': 'error',
71
133
  '@graphql-eslint/provided-required-arguments': 'error',
72
- '@graphql-eslint/require-deprecation-reason': 'error',
134
+ '@graphql-eslint/require-id-when-available': 'error',
73
135
  '@graphql-eslint/scalar-leafs': 'error',
74
- '@graphql-eslint/strict-id-in-types': 'error',
136
+ '@graphql-eslint/selection-set-depth': ['error', { maxDepth: 7 }],
75
137
  '@graphql-eslint/unique-argument-names': 'error',
76
- '@graphql-eslint/unique-directive-names': 'error',
77
138
  '@graphql-eslint/unique-directive-names-per-location': 'error',
78
- '@graphql-eslint/unique-enum-value-names': 'error',
79
- '@graphql-eslint/unique-field-definition-names': 'error',
80
139
  '@graphql-eslint/unique-input-field-names': 'error',
81
- '@graphql-eslint/unique-operation-types': 'error',
82
- '@graphql-eslint/unique-type-names': 'error',
83
140
  '@graphql-eslint/unique-variable-names': 'error',
84
141
  '@graphql-eslint/value-literals-of-correct-type': 'error',
85
142
  '@graphql-eslint/variables-are-input-types': 'error',
@@ -90,44 +147,32 @@ const recommendedConfig = {
90
147
  /*
91
148
  * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
92
149
  */
93
- const allConfig = {
94
- ...recommendedConfig,
150
+ const operationsAllConfig = {
151
+ extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/operations-recommended'],
95
152
  rules: {
96
- ...recommendedConfig.rules,
97
153
  '@graphql-eslint/alphabetize': [
98
154
  'error',
99
155
  {
100
- fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
101
- values: ['EnumTypeDefinition'],
102
156
  selections: ['OperationDefinition', 'FragmentDefinition'],
103
157
  variables: ['OperationDefinition'],
104
- arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
158
+ arguments: ['Field', 'Directive'],
105
159
  },
106
160
  ],
107
- '@graphql-eslint/avoid-duplicate-fields': 'error',
108
- '@graphql-eslint/avoid-operation-name-prefix': 'error',
109
- '@graphql-eslint/avoid-scalar-result-type-on-mutation': 'error',
110
- '@graphql-eslint/description-style': 'error',
111
- '@graphql-eslint/input-name': 'error',
112
- '@graphql-eslint/match-document-filename': 'error',
113
- '@graphql-eslint/no-deprecated': 'error',
114
- '@graphql-eslint/no-hashtag-description': 'error',
115
- '@graphql-eslint/no-root-type': ['error', { disallow: ['subscription'] }],
116
- '@graphql-eslint/no-unreachable-types': 'error',
117
- '@graphql-eslint/no-unused-fields': 'error',
118
- '@graphql-eslint/require-deprecation-date': 'error',
119
- '@graphql-eslint/require-description': 'error',
120
- '@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
121
- '@graphql-eslint/require-id-when-available': 'error',
122
- '@graphql-eslint/selection-set-depth': 'error',
161
+ '@graphql-eslint/match-document-filename': [
162
+ 'error',
163
+ { query: 'kebab-case', mutation: 'kebab-case', subscription: 'kebab-case', fragment: 'kebab-case' },
164
+ ],
123
165
  '@graphql-eslint/unique-fragment-name': 'error',
124
166
  '@graphql-eslint/unique-operation-name': 'error',
125
167
  },
126
168
  };
127
169
 
128
170
  const configs = {
129
- all: allConfig,
130
- recommended: recommendedConfig,
171
+ base,
172
+ 'schema-recommended': schemaRecommendedConfig,
173
+ 'schema-all': schemaAllConfig,
174
+ 'operations-recommended': operationsRecommendedConfig,
175
+ 'operations-all': operationsAllConfig,
131
176
  };
132
177
 
133
178
  function requireSiblingsOperations(ruleName, context) {
@@ -340,7 +385,6 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
340
385
  docs: {
341
386
  ...docs,
342
387
  graphQLJSRuleName: ruleName,
343
- category: 'Validation',
344
388
  recommended: true,
345
389
  requiresSchema,
346
390
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
@@ -377,16 +421,22 @@ const importFiles = (context) => {
377
421
  return processImport(context.getFilename());
378
422
  };
379
423
  const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
424
+ category: 'Operations',
380
425
  description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
381
426
  }), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
427
+ category: 'Operations',
382
428
  description: 'A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.',
383
429
  }), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
430
+ category: 'Operations',
384
431
  description: `Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.`,
385
432
  }), validationToRule('known-argument-names', 'KnownArgumentNames', {
433
+ category: ['Schema', 'Operations'],
386
434
  description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
387
435
  }), validationToRule('known-directives', 'KnownDirectives', {
436
+ category: ['Schema', 'Operations'],
388
437
  description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
389
438
  }), validationToRule('known-fragment-names', 'KnownFragmentNames', {
439
+ category: 'Operations',
390
440
  description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
391
441
  examples: [
392
442
  {
@@ -453,17 +503,23 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
453
503
  },
454
504
  ],
455
505
  }, importFiles), validationToRule('known-type-names', 'KnownTypeNames', {
506
+ category: ['Schema', 'Operations'],
456
507
  description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
457
508
  }), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
509
+ category: 'Operations',
458
510
  description: `A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.`,
459
511
  }), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
512
+ category: 'Schema',
460
513
  description: `A GraphQL document is only valid if it contains only one schema definition.`,
461
514
  requiresSchema: false,
462
515
  }), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
516
+ category: 'Operations',
463
517
  description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
464
518
  }), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
519
+ category: 'Operations',
465
520
  description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
466
521
  }, importFiles), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
522
+ category: 'Operations',
467
523
  description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
468
524
  requiresSiblings: true,
469
525
  }, context => {
@@ -493,49 +549,68 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
493
549
  };
494
550
  return getParentNode(context.getFilename());
495
551
  }), validationToRule('no-unused-variables', 'NoUnusedVariables', {
552
+ category: 'Operations',
496
553
  description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
497
554
  }, importFiles), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
555
+ category: 'Operations',
498
556
  description: `A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.`,
499
557
  }), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
558
+ category: 'Operations',
500
559
  description: `A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.`,
501
560
  }), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
561
+ category: 'Schema',
502
562
  description: `A type extension is only valid if the type is defined and has the same kind.`,
503
563
  requiresSchema: false,
504
564
  }), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
565
+ category: ['Schema', 'Operations'],
505
566
  description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
506
567
  }), validationToRule('scalar-leafs', 'ScalarLeafs', {
568
+ category: 'Operations',
507
569
  description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
508
570
  }), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
571
+ category: 'Operations',
509
572
  description: `A GraphQL subscription is valid only if it contains a single root field.`,
510
573
  }), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
574
+ category: 'Operations',
511
575
  description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
512
576
  }), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
577
+ category: 'Schema',
513
578
  description: `A GraphQL document is only valid if all defined directives have unique names.`,
514
579
  requiresSchema: false,
515
580
  }), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
581
+ category: ['Schema', 'Operations'],
516
582
  description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
517
583
  }), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
584
+ category: 'Schema',
518
585
  description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
519
586
  requiresSchema: false,
520
587
  }), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
588
+ category: 'Schema',
521
589
  description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
522
590
  requiresSchema: false,
523
591
  }), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
592
+ category: 'Operations',
524
593
  description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
525
594
  requiresSchema: false,
526
595
  }), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
596
+ category: 'Schema',
527
597
  description: `A GraphQL document is only valid if it has only one type per operation.`,
528
598
  requiresSchema: false,
529
599
  }), validationToRule('unique-type-names', 'UniqueTypeNames', {
600
+ category: 'Schema',
530
601
  description: `A GraphQL document is only valid if all defined types have unique names.`,
531
602
  requiresSchema: false,
532
603
  }), validationToRule('unique-variable-names', 'UniqueVariableNames', {
604
+ category: 'Operations',
533
605
  description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
534
606
  }), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
607
+ category: 'Operations',
535
608
  description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
536
609
  }), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
610
+ category: 'Operations',
537
611
  description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
538
612
  }), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
613
+ category: 'Operations',
539
614
  description: `Variables passed to field arguments conform to type.`,
540
615
  }));
541
616
 
@@ -561,7 +636,7 @@ const rule = {
561
636
  meta: {
562
637
  type: 'suggestion',
563
638
  docs: {
564
- category: 'Best Practices',
639
+ category: ['Schema', 'Operations'],
565
640
  description: 'Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.',
566
641
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/alphabetize.md',
567
642
  examples: [
@@ -640,15 +715,22 @@ const rule = {
640
715
  `,
641
716
  },
642
717
  ],
643
- optionsForConfig: [
644
- {
645
- fields: fieldsEnum,
646
- values: valuesEnum,
647
- selections: selectionsEnum,
648
- variables: variablesEnum,
649
- arguments: argumentsEnum,
650
- },
651
- ],
718
+ configOptions: {
719
+ schema: [
720
+ {
721
+ fields: fieldsEnum,
722
+ values: valuesEnum,
723
+ arguments: argumentsEnum,
724
+ },
725
+ ],
726
+ operations: [
727
+ {
728
+ selections: selectionsEnum,
729
+ variables: variablesEnum,
730
+ arguments: [Kind.FIELD, Kind.DIRECTIVE],
731
+ },
732
+ ],
733
+ },
652
734
  },
653
735
  messages: {
654
736
  [ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"',
@@ -786,307 +868,7 @@ const rule = {
786
868
  },
787
869
  };
788
870
 
789
- const AVOID_DUPLICATE_FIELDS = 'AVOID_DUPLICATE_FIELDS';
790
871
  const rule$1 = {
791
- meta: {
792
- type: 'suggestion',
793
- docs: {
794
- description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
795
- category: 'Stylistic Issues',
796
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-duplicate-fields.md',
797
- examples: [
798
- {
799
- title: 'Incorrect',
800
- code: /* GraphQL */ `
801
- query {
802
- user {
803
- name
804
- email
805
- name # duplicate field
806
- }
807
- }
808
- `,
809
- },
810
- {
811
- title: 'Incorrect',
812
- code: /* GraphQL */ `
813
- query {
814
- users(
815
- first: 100
816
- skip: 50
817
- after: "cji629tngfgou0b73kt7vi5jo"
818
- first: 100 # duplicate argument
819
- ) {
820
- id
821
- }
822
- }
823
- `,
824
- },
825
- {
826
- title: 'Incorrect',
827
- code: /* GraphQL */ `
828
- query (
829
- $first: Int!
830
- $first: Int! # duplicate variable
831
- ) {
832
- users(first: $first, skip: 50) {
833
- id
834
- }
835
- }
836
- `,
837
- },
838
- ],
839
- },
840
- messages: {
841
- [AVOID_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
842
- },
843
- schema: [],
844
- },
845
- create(context) {
846
- function checkNode(usedFields, fieldName, type, node) {
847
- if (usedFields.has(fieldName)) {
848
- context.report({
849
- loc: getLocation((node.kind === Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
850
- offsetEnd: node.kind === Kind.VARIABLE_DEFINITION ? 0 : 1,
851
- }),
852
- messageId: AVOID_DUPLICATE_FIELDS,
853
- data: {
854
- type,
855
- fieldName,
856
- },
857
- });
858
- }
859
- else {
860
- usedFields.add(fieldName);
861
- }
862
- }
863
- return {
864
- OperationDefinition(node) {
865
- const set = new Set();
866
- for (const varDef of node.variableDefinitions) {
867
- checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
868
- }
869
- },
870
- Field(node) {
871
- const set = new Set();
872
- for (const arg of node.arguments) {
873
- checkNode(set, arg.name.value, 'Field argument', arg);
874
- }
875
- },
876
- SelectionSet(node) {
877
- var _a;
878
- const set = new Set();
879
- for (const selection of node.selections) {
880
- if (selection.kind === Kind.FIELD) {
881
- checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
882
- }
883
- }
884
- },
885
- };
886
- },
887
- };
888
-
889
- const AVOID_OPERATION_NAME_PREFIX = 'AVOID_OPERATION_NAME_PREFIX';
890
- const rule$2 = {
891
- meta: {
892
- type: 'suggestion',
893
- docs: {
894
- description: 'Enforce/avoid operation name prefix, useful if you wish to avoid prefix in your root fields, or avoid using REST terminology in your schema.',
895
- category: 'Stylistic Issues',
896
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-operation-name-prefix.md',
897
- examples: [
898
- {
899
- title: 'Incorrect',
900
- usage: [{ keywords: ['get'] }],
901
- code: /* GraphQL */ `
902
- query getUserDetails {
903
- # ...
904
- }`,
905
- },
906
- {
907
- title: 'Correct',
908
- usage: [{ keywords: ['get'] }],
909
- code: /* GraphQL */ `
910
- query userDetails {
911
- # ...
912
- }`,
913
- },
914
- ],
915
- },
916
- messages: {
917
- [AVOID_OPERATION_NAME_PREFIX]: `Forbidden operation name prefix: "{{ invalidPrefix }}"`,
918
- },
919
- schema: [
920
- {
921
- additionalProperties: false,
922
- type: 'object',
923
- required: ['keywords'],
924
- properties: {
925
- caseSensitive: {
926
- default: false,
927
- type: 'boolean',
928
- },
929
- keywords: {
930
- additionalItems: false,
931
- type: 'array',
932
- minItems: 1,
933
- items: {
934
- type: 'string',
935
- },
936
- },
937
- },
938
- },
939
- ],
940
- },
941
- create(context) {
942
- return {
943
- 'OperationDefinition, FragmentDefinition'(node) {
944
- const config = context.options[0] || { keywords: [], caseSensitive: false };
945
- const caseSensitive = config.caseSensitive;
946
- const keywords = config.keywords || [];
947
- if (node && node.name && node.name.value !== '') {
948
- for (const keyword of keywords) {
949
- const testKeyword = caseSensitive ? keyword : keyword.toLowerCase();
950
- const testName = caseSensitive ? node.name.value : node.name.value.toLowerCase();
951
- if (testName.startsWith(testKeyword)) {
952
- const { start } = node.name.loc;
953
- context.report({
954
- loc: {
955
- start: {
956
- line: start.line,
957
- column: start.column - 1,
958
- },
959
- end: {
960
- line: start.line,
961
- column: start.column - 1 + testKeyword.length,
962
- },
963
- },
964
- data: {
965
- invalidPrefix: keyword,
966
- },
967
- messageId: AVOID_OPERATION_NAME_PREFIX,
968
- });
969
- }
970
- }
971
- }
972
- },
973
- };
974
- },
975
- };
976
-
977
- const rule$3 = {
978
- meta: {
979
- type: 'suggestion',
980
- docs: {
981
- category: 'Best Practices',
982
- description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
983
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-scalar-result-type-on-mutation.md',
984
- requiresSchema: true,
985
- examples: [
986
- {
987
- title: 'Incorrect',
988
- code: /* GraphQL */ `
989
- type Mutation {
990
- createUser: Boolean
991
- }
992
- `,
993
- },
994
- {
995
- title: 'Correct',
996
- code: /* GraphQL */ `
997
- type Mutation {
998
- createUser: User!
999
- }
1000
- `,
1001
- },
1002
- ],
1003
- },
1004
- schema: [],
1005
- },
1006
- create(context) {
1007
- const schema = requireGraphQLSchemaFromContext('avoid-scalar-result-type-on-mutation', context);
1008
- const mutationType = schema.getMutationType();
1009
- if (!mutationType) {
1010
- return {};
1011
- }
1012
- const selector = [
1013
- `:matches(${Kind.OBJECT_TYPE_DEFINITION}, ${Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
1014
- '>',
1015
- Kind.FIELD_DEFINITION,
1016
- Kind.NAMED_TYPE,
1017
- ].join(' ');
1018
- return {
1019
- [selector](node) {
1020
- const typeName = node.name.value;
1021
- const graphQLType = schema.getType(typeName);
1022
- if (isScalarType(graphQLType)) {
1023
- context.report({
1024
- loc: getLocation(node.loc, typeName),
1025
- message: `Unexpected scalar result type "${typeName}"`,
1026
- });
1027
- }
1028
- },
1029
- };
1030
- },
1031
- };
1032
-
1033
- const AVOID_TYPENAME_PREFIX = 'AVOID_TYPENAME_PREFIX';
1034
- const rule$4 = {
1035
- meta: {
1036
- type: 'suggestion',
1037
- docs: {
1038
- category: 'Best Practices',
1039
- description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
1040
- recommended: true,
1041
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-typename-prefix.md',
1042
- examples: [
1043
- {
1044
- title: 'Incorrect',
1045
- code: /* GraphQL */ `
1046
- type User {
1047
- userId: ID!
1048
- }
1049
- `,
1050
- },
1051
- {
1052
- title: 'Correct',
1053
- code: /* GraphQL */ `
1054
- type User {
1055
- id: ID!
1056
- }
1057
- `,
1058
- },
1059
- ],
1060
- },
1061
- messages: {
1062
- [AVOID_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
1063
- },
1064
- schema: [],
1065
- },
1066
- create(context) {
1067
- return {
1068
- 'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
1069
- const typeName = node.name.value;
1070
- const lowerTypeName = typeName.toLowerCase();
1071
- for (const field of node.fields) {
1072
- const fieldName = field.name.value;
1073
- if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
1074
- context.report({
1075
- data: {
1076
- fieldName,
1077
- typeName,
1078
- },
1079
- messageId: AVOID_TYPENAME_PREFIX,
1080
- loc: getLocation(field.loc, lowerTypeName),
1081
- });
1082
- }
1083
- }
1084
- },
1085
- };
1086
- },
1087
- };
1088
-
1089
- const rule$5 = {
1090
872
  meta: {
1091
873
  type: 'suggestion',
1092
874
  docs: {
@@ -1113,20 +895,20 @@ const rule$5 = {
1113
895
  },
1114
896
  ],
1115
897
  description: 'Require all comments to follow the same style (either block or inline).',
1116
- category: 'Stylistic Issues',
898
+ category: 'Schema',
1117
899
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
900
+ recommended: true,
1118
901
  },
1119
902
  schema: [
1120
903
  {
1121
904
  type: 'object',
905
+ additionalProperties: false,
1122
906
  properties: {
1123
907
  style: {
1124
- type: 'string',
1125
908
  enum: ['block', 'inline'],
1126
909
  default: 'inline',
1127
910
  },
1128
911
  },
1129
- additionalProperties: false,
1130
912
  },
1131
913
  ],
1132
914
  },
@@ -1149,12 +931,12 @@ const rule$5 = {
1149
931
  const isObjectType = (node) => [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
1150
932
  const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
1151
933
  const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
1152
- const rule$6 = {
934
+ const rule$2 = {
1153
935
  meta: {
1154
936
  type: 'suggestion',
1155
937
  docs: {
1156
938
  description: 'Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".\nUsing the same name for all input parameters will make your schemas easier to consume and more predictable. Using the same name as mutation for InputType will make it easier to find mutations that InputType belongs to.',
1157
- category: 'Stylistic Issues',
939
+ category: 'Schema',
1158
940
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
1159
941
  examples: [
1160
942
  {
@@ -1275,11 +1057,11 @@ const CASE_STYLES = [
1275
1057
  const schemaOption = {
1276
1058
  oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
1277
1059
  };
1278
- const rule$7 = {
1060
+ const rule$3 = {
1279
1061
  meta: {
1280
1062
  type: 'suggestion',
1281
1063
  docs: {
1282
- category: 'Best Practices',
1064
+ category: 'Operations',
1283
1065
  description: 'This rule allows you to enforce that the file name should match the operation name.',
1284
1066
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/match-document-filename.md`,
1285
1067
  examples: [
@@ -1353,6 +1135,14 @@ const rule$7 = {
1353
1135
  `,
1354
1136
  },
1355
1137
  ],
1138
+ configOptions: [
1139
+ {
1140
+ query: CaseStyle.kebabCase,
1141
+ mutation: CaseStyle.kebabCase,
1142
+ subscription: CaseStyle.kebabCase,
1143
+ fragment: CaseStyle.kebabCase,
1144
+ },
1145
+ ],
1356
1146
  },
1357
1147
  messages: {
1358
1148
  [MATCH_EXTENSION]: `File extension "{{ fileExtension }}" don't match extension "{{ expectedFileExtension }}"`,
@@ -1361,27 +1151,29 @@ const rule$7 = {
1361
1151
  schema: {
1362
1152
  definitions: {
1363
1153
  asString: {
1364
- type: 'string',
1365
- description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
1366
1154
  enum: CASE_STYLES,
1155
+ description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
1367
1156
  },
1368
1157
  asObject: {
1369
1158
  type: 'object',
1159
+ additionalProperties: false,
1370
1160
  properties: {
1371
1161
  style: {
1372
- type: 'string',
1373
1162
  enum: CASE_STYLES,
1374
1163
  },
1164
+ suffix: {
1165
+ type: 'string',
1166
+ },
1375
1167
  },
1376
1168
  },
1377
1169
  },
1378
- $schema: 'http://json-schema.org/draft-04/schema#',
1379
1170
  type: 'array',
1171
+ maxItems: 1,
1380
1172
  items: {
1381
1173
  type: 'object',
1174
+ additionalProperties: false,
1382
1175
  properties: {
1383
1176
  fileExtension: {
1384
- type: 'string',
1385
1177
  enum: ACCEPTED_EXTENSIONS,
1386
1178
  },
1387
1179
  query: schemaOption,
@@ -1456,13 +1248,7 @@ const rule$7 = {
1456
1248
  },
1457
1249
  };
1458
1250
 
1459
- const FIELDS_KINDS = [
1460
- Kind.FIELD_DEFINITION,
1461
- Kind.INPUT_VALUE_DEFINITION,
1462
- Kind.VARIABLE_DEFINITION,
1463
- Kind.ARGUMENT,
1464
- Kind.DIRECTIVE_DEFINITION,
1465
- ];
1251
+ const FIELDS_KINDS = [Kind.FIELD_DEFINITION, Kind.INPUT_VALUE_DEFINITION, Kind.ARGUMENT, Kind.DIRECTIVE_DEFINITION];
1466
1252
  const KindToDisplayName = {
1467
1253
  // types
1468
1254
  [Kind.OBJECT_TYPE_DEFINITION]: 'Type',
@@ -1474,13 +1260,13 @@ const KindToDisplayName = {
1474
1260
  // fields
1475
1261
  [Kind.FIELD_DEFINITION]: 'Field',
1476
1262
  [Kind.INPUT_VALUE_DEFINITION]: 'Input property',
1477
- [Kind.VARIABLE_DEFINITION]: 'Variable',
1478
1263
  [Kind.ARGUMENT]: 'Argument',
1479
1264
  [Kind.DIRECTIVE_DEFINITION]: 'Directive',
1480
1265
  // rest
1481
1266
  [Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
1482
1267
  [Kind.OPERATION_DEFINITION]: 'Operation',
1483
1268
  [Kind.FRAGMENT_DEFINITION]: 'Fragment',
1269
+ [Kind.VARIABLE_DEFINITION]: 'Variable',
1484
1270
  };
1485
1271
  const StyleToRegex = {
1486
1272
  camelCase: /^[a-z][\dA-Za-z]*$/,
@@ -1493,12 +1279,12 @@ const ALLOWED_STYLES = Object.keys(StyleToRegex);
1493
1279
  const schemaOption$1 = {
1494
1280
  oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
1495
1281
  };
1496
- const rule$8 = {
1282
+ const rule$4 = {
1497
1283
  meta: {
1498
1284
  type: 'suggestion',
1499
1285
  docs: {
1500
1286
  description: 'Require names to follow specified conventions.',
1501
- category: 'Best Practices',
1287
+ category: ['Schema', 'Operations'],
1502
1288
  recommended: true,
1503
1289
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/naming-convention.md',
1504
1290
  examples: [
@@ -1521,37 +1307,47 @@ const rule$8 = {
1521
1307
  `,
1522
1308
  },
1523
1309
  ],
1524
- optionsForConfig: [
1525
- {
1526
- types: 'PascalCase',
1527
- fields: 'camelCase',
1528
- overrides: {
1529
- EnumValueDefinition: 'UPPER_CASE',
1530
- OperationDefinition: {
1531
- style: 'PascalCase',
1532
- forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
1533
- forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
1534
- },
1535
- FragmentDefinition: {
1536
- style: 'PascalCase',
1537
- forbiddenPrefixes: ['Fragment'],
1538
- forbiddenSuffixes: ['Fragment'],
1539
- },
1540
- 'FieldDefinition[parent.name.value=Query]': {
1541
- forbiddenPrefixes: ['query', 'get'],
1542
- forbiddenSuffixes: ['Query'],
1543
- },
1544
- 'FieldDefinition[parent.name.value=Mutation]': {
1545
- forbiddenPrefixes: ['mutation'],
1546
- forbiddenSuffixes: ['Mutation'],
1310
+ configOptions: {
1311
+ schema: [
1312
+ {
1313
+ types: 'PascalCase',
1314
+ fields: 'camelCase',
1315
+ overrides: {
1316
+ EnumValueDefinition: 'UPPER_CASE',
1317
+ 'FieldDefinition[parent.name.value=Query]': {
1318
+ forbiddenPrefixes: ['query', 'get'],
1319
+ forbiddenSuffixes: ['Query'],
1320
+ },
1321
+ 'FieldDefinition[parent.name.value=Mutation]': {
1322
+ forbiddenPrefixes: ['mutation'],
1323
+ forbiddenSuffixes: ['Mutation'],
1324
+ },
1325
+ 'FieldDefinition[parent.name.value=Subscription]': {
1326
+ forbiddenPrefixes: ['subscription'],
1327
+ forbiddenSuffixes: ['Subscription'],
1328
+ },
1547
1329
  },
1548
- 'FieldDefinition[parent.name.value=Subscription]': {
1549
- forbiddenPrefixes: ['subscription'],
1550
- forbiddenSuffixes: ['Subscription'],
1330
+ },
1331
+ ],
1332
+ operations: [
1333
+ {
1334
+ overrides: {
1335
+ Argument: 'camelCase',
1336
+ VariableDefinition: 'camelCase',
1337
+ OperationDefinition: {
1338
+ style: 'PascalCase',
1339
+ forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
1340
+ forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
1341
+ },
1342
+ FragmentDefinition: {
1343
+ style: 'PascalCase',
1344
+ forbiddenPrefixes: ['Fragment'],
1345
+ forbiddenSuffixes: ['Fragment'],
1346
+ },
1551
1347
  },
1552
1348
  },
1553
- },
1554
- ],
1349
+ ],
1350
+ },
1555
1351
  },
1556
1352
  schema: {
1557
1353
  definitions: {
@@ -1589,11 +1385,11 @@ const rule$8 = {
1589
1385
  properties: {
1590
1386
  types: {
1591
1387
  ...schemaOption$1,
1592
- description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
1388
+ description: `Includes:\n\n${TYPES_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
1593
1389
  },
1594
1390
  fields: {
1595
1391
  ...schemaOption$1,
1596
- description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
1392
+ description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
1597
1393
  },
1598
1394
  allowLeadingUnderscore: {
1599
1395
  type: 'boolean',
@@ -1609,7 +1405,7 @@ const rule$8 = {
1609
1405
  description: [
1610
1406
  'May contain the following `ASTNode` names:',
1611
1407
  '',
1612
- ...ALLOWED_KINDS.map(kind => `- \`${kind}\``),
1408
+ ...ALLOWED_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`),
1613
1409
  '',
1614
1410
  "> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
1615
1411
  '>',
@@ -1706,11 +1502,11 @@ const rule$8 = {
1706
1502
  };
1707
1503
 
1708
1504
  const NO_ANONYMOUS_OPERATIONS = 'NO_ANONYMOUS_OPERATIONS';
1709
- const rule$9 = {
1505
+ const rule$5 = {
1710
1506
  meta: {
1711
1507
  type: 'suggestion',
1712
1508
  docs: {
1713
- category: 'Best Practices',
1509
+ category: 'Operations',
1714
1510
  description: 'Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.',
1715
1511
  recommended: true,
1716
1512
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-anonymous-operations.md',
@@ -1754,12 +1550,12 @@ const rule$9 = {
1754
1550
  };
1755
1551
 
1756
1552
  const ERROR_MESSAGE_ID = 'NO_CASE_INSENSITIVE_ENUM_VALUES_DUPLICATES';
1757
- const rule$a = {
1553
+ const rule$6 = {
1758
1554
  meta: {
1759
1555
  type: 'suggestion',
1760
1556
  docs: {
1761
1557
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-case-insensitive-enum-values-duplicates.md',
1762
- category: 'Best Practices',
1558
+ category: 'Schema',
1763
1559
  recommended: true,
1764
1560
  description: 'Disallow case-insensitive enum values duplicates.',
1765
1561
  examples: [
@@ -1810,11 +1606,11 @@ const rule$a = {
1810
1606
  };
1811
1607
 
1812
1608
  const NO_DEPRECATED = 'NO_DEPRECATED';
1813
- const rule$b = {
1609
+ const rule$7 = {
1814
1610
  meta: {
1815
1611
  type: 'suggestion',
1816
1612
  docs: {
1817
- category: 'Best Practices',
1613
+ category: 'Operations',
1818
1614
  description: `Enforce that deprecated fields or enum values are not in use by operations.`,
1819
1615
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-deprecated.md`,
1820
1616
  requiresSchema: true,
@@ -1880,6 +1676,7 @@ const rule$b = {
1880
1676
  `,
1881
1677
  },
1882
1678
  ],
1679
+ recommended: true,
1883
1680
  },
1884
1681
  messages: {
1885
1682
  [NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
@@ -1906,19 +1703,120 @@ const rule$b = {
1906
1703
  }
1907
1704
  },
1908
1705
  Field(node) {
1909
- requireGraphQLSchemaFromContext('no-deprecated', context);
1910
- const typeInfo = node.typeInfo();
1911
- if (typeInfo && typeInfo.fieldDef) {
1912
- if (typeInfo.fieldDef.deprecationReason) {
1913
- const fieldName = node.name.value;
1914
- context.report({
1915
- loc: getLocation(node.loc, fieldName),
1916
- messageId: NO_DEPRECATED,
1917
- data: {
1918
- type: 'field',
1919
- reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
1920
- },
1921
- });
1706
+ requireGraphQLSchemaFromContext('no-deprecated', context);
1707
+ const typeInfo = node.typeInfo();
1708
+ if (typeInfo && typeInfo.fieldDef) {
1709
+ if (typeInfo.fieldDef.deprecationReason) {
1710
+ const fieldName = node.name.value;
1711
+ context.report({
1712
+ loc: getLocation(node.loc, fieldName),
1713
+ messageId: NO_DEPRECATED,
1714
+ data: {
1715
+ type: 'field',
1716
+ reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
1717
+ },
1718
+ });
1719
+ }
1720
+ }
1721
+ },
1722
+ };
1723
+ },
1724
+ };
1725
+
1726
+ const NO_DUPLICATE_FIELDS = 'NO_DUPLICATE_FIELDS';
1727
+ const rule$8 = {
1728
+ meta: {
1729
+ type: 'suggestion',
1730
+ docs: {
1731
+ description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
1732
+ category: 'Operations',
1733
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-duplicate-fields.md',
1734
+ recommended: true,
1735
+ examples: [
1736
+ {
1737
+ title: 'Incorrect',
1738
+ code: /* GraphQL */ `
1739
+ query {
1740
+ user {
1741
+ name
1742
+ email
1743
+ name # duplicate field
1744
+ }
1745
+ }
1746
+ `,
1747
+ },
1748
+ {
1749
+ title: 'Incorrect',
1750
+ code: /* GraphQL */ `
1751
+ query {
1752
+ users(
1753
+ first: 100
1754
+ skip: 50
1755
+ after: "cji629tngfgou0b73kt7vi5jo"
1756
+ first: 100 # duplicate argument
1757
+ ) {
1758
+ id
1759
+ }
1760
+ }
1761
+ `,
1762
+ },
1763
+ {
1764
+ title: 'Incorrect',
1765
+ code: /* GraphQL */ `
1766
+ query (
1767
+ $first: Int!
1768
+ $first: Int! # duplicate variable
1769
+ ) {
1770
+ users(first: $first, skip: 50) {
1771
+ id
1772
+ }
1773
+ }
1774
+ `,
1775
+ },
1776
+ ],
1777
+ },
1778
+ messages: {
1779
+ [NO_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
1780
+ },
1781
+ schema: [],
1782
+ },
1783
+ create(context) {
1784
+ function checkNode(usedFields, fieldName, type, node) {
1785
+ if (usedFields.has(fieldName)) {
1786
+ context.report({
1787
+ loc: getLocation((node.kind === Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
1788
+ offsetEnd: node.kind === Kind.VARIABLE_DEFINITION ? 0 : 1,
1789
+ }),
1790
+ messageId: NO_DUPLICATE_FIELDS,
1791
+ data: {
1792
+ type,
1793
+ fieldName,
1794
+ },
1795
+ });
1796
+ }
1797
+ else {
1798
+ usedFields.add(fieldName);
1799
+ }
1800
+ }
1801
+ return {
1802
+ OperationDefinition(node) {
1803
+ const set = new Set();
1804
+ for (const varDef of node.variableDefinitions) {
1805
+ checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
1806
+ }
1807
+ },
1808
+ Field(node) {
1809
+ const set = new Set();
1810
+ for (const arg of node.arguments) {
1811
+ checkNode(set, arg.name.value, 'Field argument', arg);
1812
+ }
1813
+ },
1814
+ SelectionSet(node) {
1815
+ var _a;
1816
+ const set = new Set();
1817
+ for (const selection of node.selections) {
1818
+ if (selection.kind === Kind.FIELD) {
1819
+ checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
1922
1820
  }
1923
1821
  }
1924
1822
  },
@@ -1927,14 +1825,14 @@ const rule$b = {
1927
1825
  };
1928
1826
 
1929
1827
  const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
1930
- const rule$c = {
1828
+ const rule$9 = {
1931
1829
  meta: {
1932
1830
  messages: {
1933
1831
  [HASHTAG_COMMENT]: 'Using hashtag (#) for adding GraphQL descriptions is not allowed. Prefer using """ for multiline, or " for a single line description.',
1934
1832
  },
1935
1833
  docs: {
1936
1834
  description: 'Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.\nAllows to use hashtag for comments, as long as it\'s not attached to an AST definition.',
1937
- category: 'Best Practices',
1835
+ category: 'Schema',
1938
1836
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
1939
1837
  examples: [
1940
1838
  {
@@ -1971,6 +1869,7 @@ const rule$c = {
1971
1869
  `,
1972
1870
  },
1973
1871
  ],
1872
+ recommended: true,
1974
1873
  },
1975
1874
  type: 'suggestion',
1976
1875
  schema: [],
@@ -1999,79 +1898,12 @@ const rule$c = {
1999
1898
  },
2000
1899
  };
2001
1900
 
2002
- const NO_OPERATION_NAME_SUFFIX = 'NO_OPERATION_NAME_SUFFIX';
2003
- const rule$d = {
2004
- meta: {
2005
- fixable: 'code',
2006
- type: 'suggestion',
2007
- docs: {
2008
- category: 'Stylistic Issues',
2009
- recommended: true,
2010
- description: `Makes sure you are not adding the operation type to the name of the operation.`,
2011
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-operation-name-suffix.md`,
2012
- examples: [
2013
- {
2014
- title: 'Incorrect',
2015
- code: /* GraphQL */ `
2016
- query userQuery {
2017
- # ...
2018
- }
2019
- `,
2020
- },
2021
- {
2022
- title: 'Correct',
2023
- code: /* GraphQL */ `
2024
- query user {
2025
- # ...
2026
- }
2027
- `,
2028
- },
2029
- ],
2030
- },
2031
- messages: {
2032
- [NO_OPERATION_NAME_SUFFIX]: `Unnecessary "{{ invalidSuffix }}" suffix in your operation name!`,
2033
- },
2034
- schema: [],
2035
- },
2036
- create(context) {
2037
- return {
2038
- 'OperationDefinition, FragmentDefinition'(node) {
2039
- var _a;
2040
- const name = ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '';
2041
- if (name.length > 0) {
2042
- const invalidSuffix = 'operation' in node ? node.operation : 'fragment';
2043
- if (name.toLowerCase().endsWith(invalidSuffix)) {
2044
- const { start, end } = node.name.loc;
2045
- context.report({
2046
- loc: {
2047
- start: {
2048
- column: start.column - 1 + name.length - invalidSuffix.length,
2049
- line: start.line,
2050
- },
2051
- end: {
2052
- column: end.column - 1 + name.length,
2053
- line: end.line,
2054
- },
2055
- },
2056
- data: {
2057
- invalidSuffix,
2058
- },
2059
- fix: fixer => fixer.removeRange([node.name.range[1] - invalidSuffix.length, node.name.range[1]]),
2060
- messageId: NO_OPERATION_NAME_SUFFIX,
2061
- });
2062
- }
2063
- }
2064
- },
2065
- };
2066
- },
2067
- };
2068
-
2069
1901
  const ROOT_TYPES = ['query', 'mutation', 'subscription'];
2070
- const rule$e = {
1902
+ const rule$a = {
2071
1903
  meta: {
2072
1904
  type: 'suggestion',
2073
1905
  docs: {
2074
- category: 'Validation',
1906
+ category: 'Schema',
2075
1907
  description: 'Disallow using root types for `read-only` or `write-only` schemas.',
2076
1908
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
2077
1909
  requiresSchema: true,
@@ -2104,7 +1936,6 @@ const rule$e = {
2104
1936
  `,
2105
1937
  },
2106
1938
  ],
2107
- optionsForConfig: [{ disallow: ['subscription'] }],
2108
1939
  },
2109
1940
  schema: {
2110
1941
  type: 'array',
@@ -2157,16 +1988,128 @@ const rule$e = {
2157
1988
  },
2158
1989
  };
2159
1990
 
1991
+ const rule$b = {
1992
+ meta: {
1993
+ type: 'suggestion',
1994
+ docs: {
1995
+ category: 'Schema',
1996
+ description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
1997
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-scalar-result-type-on-mutation.md',
1998
+ requiresSchema: true,
1999
+ examples: [
2000
+ {
2001
+ title: 'Incorrect',
2002
+ code: /* GraphQL */ `
2003
+ type Mutation {
2004
+ createUser: Boolean
2005
+ }
2006
+ `,
2007
+ },
2008
+ {
2009
+ title: 'Correct',
2010
+ code: /* GraphQL */ `
2011
+ type Mutation {
2012
+ createUser: User!
2013
+ }
2014
+ `,
2015
+ },
2016
+ ],
2017
+ },
2018
+ schema: [],
2019
+ },
2020
+ create(context) {
2021
+ const schema = requireGraphQLSchemaFromContext('no-scalar-result-type-on-mutation', context);
2022
+ const mutationType = schema.getMutationType();
2023
+ if (!mutationType) {
2024
+ return {};
2025
+ }
2026
+ const selector = [
2027
+ `:matches(${Kind.OBJECT_TYPE_DEFINITION}, ${Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
2028
+ '>',
2029
+ Kind.FIELD_DEFINITION,
2030
+ Kind.NAMED_TYPE,
2031
+ ].join(' ');
2032
+ return {
2033
+ [selector](node) {
2034
+ const typeName = node.name.value;
2035
+ const graphQLType = schema.getType(typeName);
2036
+ if (isScalarType(graphQLType)) {
2037
+ context.report({
2038
+ loc: getLocation(node.loc, typeName),
2039
+ message: `Unexpected scalar result type "${typeName}"`,
2040
+ });
2041
+ }
2042
+ },
2043
+ };
2044
+ },
2045
+ };
2046
+
2047
+ const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
2048
+ const rule$c = {
2049
+ meta: {
2050
+ type: 'suggestion',
2051
+ docs: {
2052
+ category: 'Schema',
2053
+ description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
2054
+ recommended: true,
2055
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
2056
+ examples: [
2057
+ {
2058
+ title: 'Incorrect',
2059
+ code: /* GraphQL */ `
2060
+ type User {
2061
+ userId: ID!
2062
+ }
2063
+ `,
2064
+ },
2065
+ {
2066
+ title: 'Correct',
2067
+ code: /* GraphQL */ `
2068
+ type User {
2069
+ id: ID!
2070
+ }
2071
+ `,
2072
+ },
2073
+ ],
2074
+ },
2075
+ messages: {
2076
+ [NO_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
2077
+ },
2078
+ schema: [],
2079
+ },
2080
+ create(context) {
2081
+ return {
2082
+ 'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
2083
+ const typeName = node.name.value;
2084
+ const lowerTypeName = typeName.toLowerCase();
2085
+ for (const field of node.fields) {
2086
+ const fieldName = field.name.value;
2087
+ if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
2088
+ context.report({
2089
+ data: {
2090
+ fieldName,
2091
+ typeName,
2092
+ },
2093
+ messageId: NO_TYPENAME_PREFIX,
2094
+ loc: getLocation(field.loc, lowerTypeName),
2095
+ });
2096
+ }
2097
+ }
2098
+ },
2099
+ };
2100
+ },
2101
+ };
2102
+
2160
2103
  const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
2161
2104
  const RULE_NAME = 'no-unreachable-types';
2162
- const rule$f = {
2105
+ const rule$d = {
2163
2106
  meta: {
2164
2107
  messages: {
2165
- [UNREACHABLE_TYPE]: `Type "{{ typeName }}" is unreachable`,
2108
+ [UNREACHABLE_TYPE]: 'Type "{{ typeName }}" is unreachable',
2166
2109
  },
2167
2110
  docs: {
2168
2111
  description: `Requires all types to be reachable at some level by root level fields.`,
2169
- category: 'Best Practices',
2112
+ category: 'Schema',
2170
2113
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
2171
2114
  requiresSchema: true,
2172
2115
  examples: [
@@ -2197,6 +2140,7 @@ const rule$f = {
2197
2140
  `,
2198
2141
  },
2199
2142
  ],
2143
+ recommended: true,
2200
2144
  },
2201
2145
  fixable: 'code',
2202
2146
  type: 'suggestion',
@@ -2235,14 +2179,14 @@ const rule$f = {
2235
2179
 
2236
2180
  const UNUSED_FIELD = 'UNUSED_FIELD';
2237
2181
  const RULE_NAME$1 = 'no-unused-fields';
2238
- const rule$g = {
2182
+ const rule$e = {
2239
2183
  meta: {
2240
2184
  messages: {
2241
2185
  [UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
2242
2186
  },
2243
2187
  docs: {
2244
2188
  description: `Requires all fields to be used at some level by siblings operations.`,
2245
- category: 'Best Practices',
2189
+ category: 'Schema',
2246
2190
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
2247
2191
  requiresSiblings: true,
2248
2192
  requiresSchema: true,
@@ -2424,11 +2368,11 @@ const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
2424
2368
  const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
2425
2369
  const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
2426
2370
  const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
2427
- const rule$h = {
2371
+ const rule$f = {
2428
2372
  meta: {
2429
2373
  type: 'suggestion',
2430
2374
  docs: {
2431
- category: 'Best Practices',
2375
+ category: 'Schema',
2432
2376
  description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
2433
2377
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-date.md',
2434
2378
  examples: [
@@ -2527,11 +2471,11 @@ const rule$h = {
2527
2471
  },
2528
2472
  };
2529
2473
 
2530
- const rule$i = {
2474
+ const rule$g = {
2531
2475
  meta: {
2532
2476
  docs: {
2533
2477
  description: `Require all deprecation directives to specify a reason.`,
2534
- category: 'Best Practices',
2478
+ category: 'Schema',
2535
2479
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-reason.md`,
2536
2480
  recommended: true,
2537
2481
  examples: [
@@ -2582,41 +2526,23 @@ const rule$i = {
2582
2526
  };
2583
2527
 
2584
2528
  const REQUIRE_DESCRIPTION_ERROR = 'REQUIRE_DESCRIPTION_ERROR';
2585
- const DESCRIBABLE_NODES = [
2586
- Kind.SCHEMA_DEFINITION,
2587
- Kind.OBJECT_TYPE_DEFINITION,
2529
+ const ALLOWED_KINDS$1 = [
2530
+ ...TYPES_KINDS,
2588
2531
  Kind.FIELD_DEFINITION,
2589
2532
  Kind.INPUT_VALUE_DEFINITION,
2590
- Kind.INTERFACE_TYPE_DEFINITION,
2591
- Kind.UNION_TYPE_DEFINITION,
2592
- Kind.ENUM_TYPE_DEFINITION,
2593
2533
  Kind.ENUM_VALUE_DEFINITION,
2594
- Kind.INPUT_OBJECT_TYPE_DEFINITION,
2595
2534
  Kind.DIRECTIVE_DEFINITION,
2596
2535
  ];
2597
- function verifyRule(context, node) {
2598
- if (node) {
2599
- if (!node.description || !node.description.value || node.description.value.trim().length === 0) {
2600
- context.report({
2601
- loc: getLocation(('name' in node ? node.name : node).loc, 'name' in node ? node.name.value : 'schema'),
2602
- messageId: REQUIRE_DESCRIPTION_ERROR,
2603
- data: {
2604
- nodeType: node.kind,
2605
- },
2606
- });
2607
- }
2608
- }
2609
- }
2610
- const rule$j = {
2536
+ const rule$h = {
2611
2537
  meta: {
2612
2538
  docs: {
2613
- category: 'Best Practices',
2614
- description: `Enforce descriptions in your type definitions.`,
2615
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md`,
2539
+ category: 'Schema',
2540
+ description: 'Enforce descriptions in your type definitions.',
2541
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md',
2616
2542
  examples: [
2617
2543
  {
2618
2544
  title: 'Incorrect',
2619
- usage: [{ on: [Kind.OBJECT_TYPE_DEFINITION, Kind.FIELD_DEFINITION] }],
2545
+ usage: [{ types: true, overrides: { FieldDefinition: true } }],
2620
2546
  code: /* GraphQL */ `
2621
2547
  type someTypeName {
2622
2548
  name: String
@@ -2625,7 +2551,7 @@ const rule$j = {
2625
2551
  },
2626
2552
  {
2627
2553
  title: 'Correct',
2628
- usage: [{ on: [Kind.OBJECT_TYPE_DEFINITION, Kind.FIELD_DEFINITION] }],
2554
+ usage: [{ types: true, overrides: { FieldDefinition: true } }],
2629
2555
  code: /* GraphQL */ `
2630
2556
  """
2631
2557
  Some type description
@@ -2639,44 +2565,78 @@ const rule$j = {
2639
2565
  `,
2640
2566
  },
2641
2567
  ],
2568
+ configOptions: [
2569
+ {
2570
+ types: true,
2571
+ overrides: {
2572
+ [Kind.DIRECTIVE_DEFINITION]: true,
2573
+ },
2574
+ },
2575
+ ],
2642
2576
  },
2643
2577
  type: 'suggestion',
2644
2578
  messages: {
2645
- [REQUIRE_DESCRIPTION_ERROR]: `Description is required for nodes of type "{{ nodeType }}"`,
2579
+ [REQUIRE_DESCRIPTION_ERROR]: 'Description is required for nodes of type "{{ nodeType }}"',
2646
2580
  },
2647
2581
  schema: {
2648
2582
  type: 'array',
2649
- additionalItems: false,
2650
2583
  minItems: 1,
2651
2584
  maxItems: 1,
2652
2585
  items: {
2653
2586
  type: 'object',
2654
- require: ['on'],
2587
+ additionalProperties: false,
2588
+ minProperties: 1,
2655
2589
  properties: {
2656
- on: {
2657
- type: 'array',
2658
- minItems: 1,
2659
- additionalItems: false,
2660
- items: {
2661
- type: 'string',
2662
- enum: DESCRIBABLE_NODES,
2663
- },
2590
+ types: {
2591
+ type: 'boolean',
2592
+ description: `Includes:\n\n${TYPES_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
2593
+ },
2594
+ overrides: {
2595
+ type: 'object',
2596
+ description: 'Configuration for precise `ASTNode`',
2597
+ additionalProperties: false,
2598
+ properties: Object.fromEntries(ALLOWED_KINDS$1.map(kind => [kind, { type: 'boolean' }])),
2664
2599
  },
2665
2600
  },
2666
2601
  },
2667
2602
  },
2668
2603
  },
2669
2604
  create(context) {
2670
- return Object.fromEntries(context.options[0].on.map(optionKey => [optionKey, node => verifyRule(context, node)]));
2605
+ const { types, overrides = {} } = context.options[0];
2606
+ const kinds = new Set(types ? TYPES_KINDS : []);
2607
+ for (const [kind, isEnabled] of Object.entries(overrides)) {
2608
+ if (isEnabled) {
2609
+ kinds.add(kind);
2610
+ }
2611
+ else {
2612
+ kinds.delete(kind);
2613
+ }
2614
+ }
2615
+ const selector = [...kinds].join(',');
2616
+ return {
2617
+ [selector](node) {
2618
+ var _a;
2619
+ const description = ((_a = node.description) === null || _a === void 0 ? void 0 : _a.value) || '';
2620
+ if (description.trim().length === 0) {
2621
+ context.report({
2622
+ loc: getLocation(node.name.loc, node.name.value),
2623
+ messageId: REQUIRE_DESCRIPTION_ERROR,
2624
+ data: {
2625
+ nodeType: node.kind,
2626
+ },
2627
+ });
2628
+ }
2629
+ },
2630
+ };
2671
2631
  },
2672
2632
  };
2673
2633
 
2674
2634
  const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
2675
- const rule$k = {
2635
+ const rule$i = {
2676
2636
  meta: {
2677
2637
  type: 'suggestion',
2678
2638
  docs: {
2679
- category: 'Best Practices',
2639
+ category: 'Schema',
2680
2640
  description: 'Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.\n> Currently, no errors are reported for result type `union`, `interface` and `scalar`.',
2681
2641
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
2682
2642
  requiresSchema: true,
@@ -2840,13 +2800,13 @@ const convertNode = (typeInfo) => (node, key, parent) => {
2840
2800
 
2841
2801
  const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
2842
2802
  const DEFAULT_ID_FIELD_NAME = 'id';
2843
- const rule$l = {
2803
+ const rule$j = {
2844
2804
  meta: {
2845
2805
  type: 'suggestion',
2846
2806
  docs: {
2847
- category: 'Best Practices',
2848
- description: `Enforce selecting specific fields when they are available on the GraphQL type.`,
2849
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md`,
2807
+ category: 'Operations',
2808
+ description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
2809
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
2850
2810
  requiresSchema: true,
2851
2811
  requiresSiblings: true,
2852
2812
  examples: [
@@ -2886,17 +2846,17 @@ const rule$l = {
2886
2846
  `,
2887
2847
  },
2888
2848
  ],
2849
+ recommended: true,
2889
2850
  },
2890
2851
  messages: {
2891
- [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{checkedFragments}} specifies the field "{{ fieldName }}".`,
2852
+ [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{ checkedFragments }} specifies the field "{{ fieldName }}".`,
2892
2853
  },
2893
2854
  schema: {
2894
2855
  type: 'array',
2895
- additionalItems: false,
2896
- minItems: 0,
2897
2856
  maxItems: 1,
2898
2857
  items: {
2899
2858
  type: 'object',
2859
+ additionalProperties: false,
2900
2860
  properties: {
2901
2861
  fieldName: {
2902
2862
  type: 'string',
@@ -2976,12 +2936,12 @@ const rule$l = {
2976
2936
  },
2977
2937
  };
2978
2938
 
2979
- const rule$m = {
2939
+ const rule$k = {
2980
2940
  meta: {
2981
2941
  docs: {
2982
- category: 'Best Practices',
2942
+ category: 'Operations',
2983
2943
  description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
2984
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md`,
2944
+ url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
2985
2945
  requiresSiblings: true,
2986
2946
  examples: [
2987
2947
  {
@@ -3024,22 +2984,26 @@ const rule$m = {
3024
2984
  `,
3025
2985
  },
3026
2986
  ],
2987
+ recommended: true,
2988
+ configOptions: [{ maxDepth: 7 }],
3027
2989
  },
3028
2990
  type: 'suggestion',
3029
2991
  schema: {
3030
2992
  type: 'array',
3031
- additionalItems: false,
3032
2993
  minItems: 1,
3033
2994
  maxItems: 1,
3034
2995
  items: {
3035
2996
  type: 'object',
3036
- require: ['maxDepth'],
2997
+ additionalProperties: false,
2998
+ required: ['maxDepth'],
3037
2999
  properties: {
3038
3000
  maxDepth: {
3039
3001
  type: 'number',
3040
3002
  },
3041
3003
  ignore: {
3042
3004
  type: 'array',
3005
+ uniqueItems: true,
3006
+ minItems: 1,
3043
3007
  items: {
3044
3008
  type: 'string',
3045
3009
  },
@@ -3098,12 +3062,12 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
3098
3062
  }
3099
3063
  return false;
3100
3064
  };
3101
- const rule$n = {
3065
+ const rule$l = {
3102
3066
  meta: {
3103
3067
  type: 'suggestion',
3104
3068
  docs: {
3105
3069
  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.',
3106
- category: 'Best Practices',
3070
+ category: 'Schema',
3107
3071
  recommended: true,
3108
3072
  url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
3109
3073
  examples: [
@@ -3163,13 +3127,15 @@ const rule$n = {
3163
3127
  ],
3164
3128
  },
3165
3129
  schema: {
3166
- $schema: 'http://json-schema.org/draft-04/schema#',
3167
3130
  type: 'array',
3131
+ maxItems: 1,
3168
3132
  items: {
3169
3133
  type: 'object',
3134
+ additionalProperties: false,
3170
3135
  properties: {
3171
3136
  acceptedIdNames: {
3172
3137
  type: 'array',
3138
+ uniqueItems: true,
3173
3139
  items: {
3174
3140
  type: 'string',
3175
3141
  },
@@ -3177,6 +3143,7 @@ const rule$n = {
3177
3143
  },
3178
3144
  acceptedIdTypes: {
3179
3145
  type: 'array',
3146
+ uniqueItems: true,
3180
3147
  items: {
3181
3148
  type: 'string',
3182
3149
  },
@@ -3187,19 +3154,21 @@ const rule$n = {
3187
3154
  properties: {
3188
3155
  types: {
3189
3156
  type: 'array',
3157
+ uniqueItems: true,
3158
+ minItems: 1,
3190
3159
  description: 'This is used to exclude types with names that match one of the specified values.',
3191
3160
  items: {
3192
3161
  type: 'string',
3193
3162
  },
3194
- default: [],
3195
3163
  },
3196
3164
  suffixes: {
3197
3165
  type: 'array',
3166
+ uniqueItems: true,
3167
+ minItems: 1,
3198
3168
  description: 'This is used to exclude types with names with suffixes that match one of the specified values.',
3199
3169
  items: {
3200
3170
  type: 'string',
3201
3171
  },
3202
- default: [],
3203
3172
  },
3204
3173
  },
3205
3174
  },
@@ -3275,11 +3244,11 @@ const checkNode = (context, node, ruleName, messageId) => {
3275
3244
  });
3276
3245
  }
3277
3246
  };
3278
- const rule$o = {
3247
+ const rule$m = {
3279
3248
  meta: {
3280
3249
  type: 'suggestion',
3281
3250
  docs: {
3282
- category: 'Best Practices',
3251
+ category: 'Operations',
3283
3252
  description: `Enforce unique fragment names across your project.`,
3284
3253
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
3285
3254
  requiresSiblings: true,
@@ -3334,11 +3303,11 @@ const rule$o = {
3334
3303
 
3335
3304
  const RULE_NAME$4 = 'unique-operation-name';
3336
3305
  const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
3337
- const rule$p = {
3306
+ const rule$n = {
3338
3307
  meta: {
3339
3308
  type: 'suggestion',
3340
3309
  docs: {
3341
- category: 'Best Practices',
3310
+ category: 'Operations',
3342
3311
  description: `Enforce unique operation names across your project.`,
3343
3312
  url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
3344
3313
  requiresSiblings: true,
@@ -3401,31 +3370,29 @@ const rule$p = {
3401
3370
  const rules = {
3402
3371
  ...GRAPHQL_JS_VALIDATIONS,
3403
3372
  alphabetize: rule,
3404
- 'avoid-duplicate-fields': rule$1,
3405
- 'avoid-operation-name-prefix': rule$2,
3406
- 'avoid-scalar-result-type-on-mutation': rule$3,
3407
- 'avoid-typename-prefix': rule$4,
3408
- 'description-style': rule$5,
3409
- 'input-name': rule$6,
3410
- 'match-document-filename': rule$7,
3411
- 'naming-convention': rule$8,
3412
- 'no-anonymous-operations': rule$9,
3413
- 'no-case-insensitive-enum-values-duplicates': rule$a,
3414
- 'no-deprecated': rule$b,
3415
- 'no-hashtag-description': rule$c,
3416
- 'no-operation-name-suffix': rule$d,
3417
- 'no-root-type': rule$e,
3418
- 'no-unreachable-types': rule$f,
3419
- 'no-unused-fields': rule$g,
3420
- 'require-deprecation-date': rule$h,
3421
- 'require-deprecation-reason': rule$i,
3422
- 'require-description': rule$j,
3423
- 'require-field-of-type-query-in-mutation-result': rule$k,
3424
- 'require-id-when-available': rule$l,
3425
- 'selection-set-depth': rule$m,
3426
- 'strict-id-in-types': rule$n,
3427
- 'unique-fragment-name': rule$o,
3428
- 'unique-operation-name': rule$p,
3373
+ 'description-style': rule$1,
3374
+ 'input-name': rule$2,
3375
+ 'match-document-filename': rule$3,
3376
+ 'naming-convention': rule$4,
3377
+ 'no-anonymous-operations': rule$5,
3378
+ 'no-case-insensitive-enum-values-duplicates': rule$6,
3379
+ 'no-deprecated': rule$7,
3380
+ 'no-duplicate-fields': rule$8,
3381
+ 'no-hashtag-description': rule$9,
3382
+ 'no-root-type': rule$a,
3383
+ 'no-scalar-result-type-on-mutation': rule$b,
3384
+ 'no-typename-prefix': rule$c,
3385
+ 'no-unreachable-types': rule$d,
3386
+ 'no-unused-fields': rule$e,
3387
+ 'require-deprecation-date': rule$f,
3388
+ 'require-deprecation-reason': rule$g,
3389
+ 'require-description': rule$h,
3390
+ 'require-field-of-type-query-in-mutation-result': rule$i,
3391
+ 'require-id-when-available': rule$j,
3392
+ 'selection-set-depth': rule$k,
3393
+ 'strict-id-in-types': rule$l,
3394
+ 'unique-fragment-name': rule$m,
3395
+ 'unique-operation-name': rule$n,
3429
3396
  };
3430
3397
 
3431
3398
  const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];