@graphql-eslint/eslint-plugin 3.0.0-alpha-580615a.0 → 3.0.0-alpha-4613dfe.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.
- package/README.md +19 -8
- package/configs/base.d.ts +5 -0
- package/configs/index.d.ts +78 -121
- package/configs/operations-all.d.ts +19 -0
- package/configs/operations-recommended.d.ts +51 -0
- package/configs/schema-all.d.ts +17 -0
- package/configs/schema-recommended.d.ts +46 -0
- package/docs/README.md +11 -19
- package/docs/deprecated-rules.md +21 -0
- package/docs/rules/alphabetize.md +1 -1
- package/docs/rules/description-style.md +5 -3
- package/docs/rules/executable-definitions.md +2 -2
- package/docs/rules/fields-on-correct-type.md +2 -2
- package/docs/rules/fragments-on-composite-type.md +2 -2
- package/docs/rules/input-name.md +1 -1
- package/docs/rules/known-argument-names.md +2 -2
- package/docs/rules/known-directives.md +2 -2
- package/docs/rules/known-fragment-names.md +2 -2
- package/docs/rules/known-type-names.md +2 -2
- package/docs/rules/lone-anonymous-operation.md +2 -2
- package/docs/rules/lone-schema-definition.md +2 -2
- package/docs/rules/match-document-filename.md +6 -4
- package/docs/rules/naming-convention.md +180 -41
- package/docs/rules/no-anonymous-operations.md +2 -2
- package/docs/rules/no-case-insensitive-enum-values-duplicates.md +2 -2
- package/docs/rules/no-deprecated.md +3 -1
- package/docs/rules/{avoid-duplicate-fields.md → no-duplicate-fields.md} +10 -8
- package/docs/rules/no-fragment-cycles.md +2 -2
- package/docs/rules/no-hashtag-description.md +3 -1
- package/docs/rules/no-root-type.md +9 -14
- package/docs/rules/{avoid-scalar-result-type-on-mutation.md → no-scalar-result-type-on-mutation.md} +7 -7
- package/docs/rules/no-typename-prefix.md +37 -0
- package/docs/rules/no-undefined-variables.md +2 -2
- package/docs/rules/no-unreachable-types.md +3 -1
- package/docs/rules/no-unused-fields.md +1 -1
- package/docs/rules/no-unused-fragments.md +2 -2
- package/docs/rules/no-unused-variables.md +2 -2
- package/docs/rules/one-field-subscriptions.md +2 -2
- package/docs/rules/overlapping-fields-can-be-merged.md +2 -2
- package/docs/rules/possible-fragment-spread.md +2 -2
- package/docs/rules/possible-type-extension.md +2 -2
- package/docs/rules/provided-required-arguments.md +2 -2
- package/docs/rules/require-deprecation-date.md +1 -1
- package/docs/rules/require-deprecation-reason.md +2 -2
- package/docs/rules/require-description.md +38 -22
- package/docs/rules/require-field-of-type-query-in-mutation-result.md +1 -1
- package/docs/rules/require-id-when-available.md +3 -1
- package/docs/rules/scalar-leafs.md +2 -2
- package/docs/rules/selection-set-depth.md +9 -2
- package/docs/rules/strict-id-in-types.md +16 -10
- package/docs/rules/unique-argument-names.md +2 -2
- package/docs/rules/unique-directive-names-per-location.md +2 -2
- package/docs/rules/unique-directive-names.md +2 -2
- package/docs/rules/unique-enum-value-names.md +2 -2
- package/docs/rules/unique-field-definition-names.md +2 -2
- package/docs/rules/unique-fragment-name.md +1 -1
- package/docs/rules/unique-input-field-names.md +2 -2
- package/docs/rules/unique-operation-name.md +1 -1
- package/docs/rules/unique-operation-types.md +2 -2
- package/docs/rules/unique-type-names.md +2 -2
- package/docs/rules/unique-variable-names.md +2 -2
- package/docs/rules/value-literals-of-correct-type.md +2 -2
- package/docs/rules/variables-are-input-types.md +2 -2
- package/docs/rules/variables-in-allowed-position.md +2 -2
- package/index.js +682 -718
- package/index.mjs +683 -719
- package/package.json +1 -1
- package/rules/alphabetize.d.ts +8 -10
- package/rules/description-style.d.ts +4 -6
- package/rules/index.d.ts +115 -119
- package/rules/input-name.d.ts +1 -1
- package/rules/match-document-filename.d.ts +8 -10
- package/rules/naming-convention.d.ts +3 -4
- package/rules/{avoid-duplicate-fields.d.ts → no-duplicate-fields.d.ts} +0 -0
- package/rules/no-root-type.d.ts +1 -1
- package/rules/{avoid-scalar-result-type-on-mutation.d.ts → no-scalar-result-type-on-mutation.d.ts} +0 -0
- package/rules/{avoid-typename-prefix.d.ts → no-typename-prefix.d.ts} +0 -0
- package/rules/require-description.d.ts +2 -3
- package/rules/require-id-when-available.d.ts +3 -3
- package/rules/selection-set-depth.d.ts +3 -3
- package/rules/strict-id-in-types.d.ts +6 -8
- package/types.d.ts +9 -5
- package/configs/all.d.ts +0 -104
- package/configs/recommended.d.ts +0 -72
- package/docs/rules/avoid-operation-name-prefix.md +0 -50
- package/docs/rules/avoid-typename-prefix.md +0 -37
- package/docs/rules/no-operation-name-suffix.md +0 -38
- package/rules/avoid-operation-name-prefix.d.ts +0 -9
- package/rules/no-operation-name-suffix.d.ts +0 -3
package/index.js
CHANGED
@@ -18,14 +18,89 @@ const codeFileLoader = require('@graphql-tools/code-file-loader');
|
|
18
18
|
const eslint = require('eslint');
|
19
19
|
const codeFrame = require('@babel/code-frame');
|
20
20
|
|
21
|
+
const base = {
|
22
|
+
parser: '@graphql-eslint/eslint-plugin',
|
23
|
+
plugins: ['@graphql-eslint'],
|
24
|
+
};
|
25
|
+
|
21
26
|
/*
|
22
27
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
23
28
|
*/
|
24
|
-
const
|
25
|
-
|
26
|
-
|
29
|
+
const schemaRecommendedConfig = {
|
30
|
+
extends: ['plugin:@graphql-eslint/base'],
|
31
|
+
rules: {
|
32
|
+
'@graphql-eslint/description-style': 'error',
|
33
|
+
'@graphql-eslint/known-argument-names': 'error',
|
34
|
+
'@graphql-eslint/known-directives': 'error',
|
35
|
+
'@graphql-eslint/known-type-names': 'error',
|
36
|
+
'@graphql-eslint/lone-schema-definition': 'error',
|
37
|
+
'@graphql-eslint/naming-convention': [
|
38
|
+
'error',
|
39
|
+
{
|
40
|
+
types: 'PascalCase',
|
41
|
+
fields: 'camelCase',
|
42
|
+
EnumValueDefinition: 'UPPER_CASE',
|
43
|
+
'FieldDefinition[parent.name.value=Query]': {
|
44
|
+
forbiddenPrefixes: ['query', 'get'],
|
45
|
+
forbiddenSuffixes: ['Query'],
|
46
|
+
},
|
47
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
48
|
+
forbiddenPrefixes: ['mutation'],
|
49
|
+
forbiddenSuffixes: ['Mutation'],
|
50
|
+
},
|
51
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
52
|
+
forbiddenPrefixes: ['subscription'],
|
53
|
+
forbiddenSuffixes: ['Subscription'],
|
54
|
+
},
|
55
|
+
},
|
56
|
+
],
|
57
|
+
'@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
|
58
|
+
'@graphql-eslint/no-hashtag-description': 'error',
|
59
|
+
'@graphql-eslint/no-typename-prefix': 'error',
|
60
|
+
'@graphql-eslint/no-unreachable-types': 'error',
|
61
|
+
'@graphql-eslint/possible-type-extension': 'error',
|
62
|
+
'@graphql-eslint/provided-required-arguments': 'error',
|
63
|
+
'@graphql-eslint/require-deprecation-reason': 'error',
|
64
|
+
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
65
|
+
'@graphql-eslint/strict-id-in-types': 'error',
|
66
|
+
'@graphql-eslint/unique-directive-names': 'error',
|
67
|
+
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
68
|
+
'@graphql-eslint/unique-enum-value-names': 'error',
|
69
|
+
'@graphql-eslint/unique-field-definition-names': 'error',
|
70
|
+
'@graphql-eslint/unique-operation-types': 'error',
|
71
|
+
'@graphql-eslint/unique-type-names': 'error',
|
72
|
+
},
|
73
|
+
};
|
74
|
+
|
75
|
+
/*
|
76
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
77
|
+
*/
|
78
|
+
const schemaAllConfig = {
|
79
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/schema-recommended'],
|
80
|
+
rules: {
|
81
|
+
'@graphql-eslint/alphabetize': [
|
82
|
+
'error',
|
83
|
+
{
|
84
|
+
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
85
|
+
values: ['EnumTypeDefinition'],
|
86
|
+
arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
|
87
|
+
},
|
88
|
+
],
|
89
|
+
'@graphql-eslint/input-name': 'error',
|
90
|
+
'@graphql-eslint/no-root-type': 'off',
|
91
|
+
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
92
|
+
'@graphql-eslint/no-unused-fields': 'off',
|
93
|
+
'@graphql-eslint/require-deprecation-date': 'error',
|
94
|
+
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
95
|
+
},
|
96
|
+
};
|
97
|
+
|
98
|
+
/*
|
99
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
100
|
+
*/
|
101
|
+
const operationsRecommendedConfig = {
|
102
|
+
extends: ['plugin:@graphql-eslint/base'],
|
27
103
|
rules: {
|
28
|
-
'@graphql-eslint/avoid-typename-prefix': 'error',
|
29
104
|
'@graphql-eslint/executable-definitions': 'error',
|
30
105
|
'@graphql-eslint/fields-on-correct-type': 'error',
|
31
106
|
'@graphql-eslint/fragments-on-composite-type': 'error',
|
@@ -34,58 +109,36 @@ const recommendedConfig = {
|
|
34
109
|
'@graphql-eslint/known-fragment-names': 'error',
|
35
110
|
'@graphql-eslint/known-type-names': 'error',
|
36
111
|
'@graphql-eslint/lone-anonymous-operation': 'error',
|
37
|
-
'@graphql-eslint/lone-schema-definition': 'error',
|
38
112
|
'@graphql-eslint/naming-convention': [
|
39
113
|
'error',
|
40
114
|
{
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
},
|
50
|
-
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
51
|
-
'FieldDefinition[parent.name.value=Query]': {
|
52
|
-
forbiddenPrefixes: ['query', 'get'],
|
53
|
-
forbiddenSuffixes: ['Query'],
|
54
|
-
},
|
55
|
-
'FieldDefinition[parent.name.value=Mutation]': {
|
56
|
-
forbiddenPrefixes: ['mutation'],
|
57
|
-
forbiddenSuffixes: ['Mutation'],
|
58
|
-
},
|
59
|
-
'FieldDefinition[parent.name.value=Subscription]': {
|
60
|
-
forbiddenPrefixes: ['subscription'],
|
61
|
-
forbiddenSuffixes: ['Subscription'],
|
62
|
-
},
|
63
|
-
},
|
115
|
+
Argument: 'camelCase',
|
116
|
+
VariableDefinition: 'camelCase',
|
117
|
+
OperationDefinition: {
|
118
|
+
style: 'PascalCase',
|
119
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
120
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
121
|
+
},
|
122
|
+
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
64
123
|
},
|
65
124
|
],
|
66
125
|
'@graphql-eslint/no-anonymous-operations': 'error',
|
67
|
-
'@graphql-eslint/no-
|
126
|
+
'@graphql-eslint/no-deprecated': 'error',
|
127
|
+
'@graphql-eslint/no-duplicate-fields': 'error',
|
68
128
|
'@graphql-eslint/no-fragment-cycles': 'error',
|
69
|
-
'@graphql-eslint/no-operation-name-suffix': 'error',
|
70
129
|
'@graphql-eslint/no-undefined-variables': 'error',
|
71
130
|
'@graphql-eslint/no-unused-fragments': 'error',
|
72
131
|
'@graphql-eslint/no-unused-variables': 'error',
|
73
132
|
'@graphql-eslint/one-field-subscriptions': 'error',
|
74
133
|
'@graphql-eslint/overlapping-fields-can-be-merged': 'error',
|
75
134
|
'@graphql-eslint/possible-fragment-spread': 'error',
|
76
|
-
'@graphql-eslint/possible-type-extension': 'error',
|
77
135
|
'@graphql-eslint/provided-required-arguments': 'error',
|
78
|
-
'@graphql-eslint/require-
|
136
|
+
'@graphql-eslint/require-id-when-available': 'error',
|
79
137
|
'@graphql-eslint/scalar-leafs': 'error',
|
80
|
-
'@graphql-eslint/
|
138
|
+
'@graphql-eslint/selection-set-depth': ['error', { maxDepth: 7 }],
|
81
139
|
'@graphql-eslint/unique-argument-names': 'error',
|
82
|
-
'@graphql-eslint/unique-directive-names': 'error',
|
83
140
|
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
84
|
-
'@graphql-eslint/unique-enum-value-names': 'error',
|
85
|
-
'@graphql-eslint/unique-field-definition-names': 'error',
|
86
141
|
'@graphql-eslint/unique-input-field-names': 'error',
|
87
|
-
'@graphql-eslint/unique-operation-types': 'error',
|
88
|
-
'@graphql-eslint/unique-type-names': 'error',
|
89
142
|
'@graphql-eslint/unique-variable-names': 'error',
|
90
143
|
'@graphql-eslint/value-literals-of-correct-type': 'error',
|
91
144
|
'@graphql-eslint/variables-are-input-types': 'error',
|
@@ -96,44 +149,32 @@ const recommendedConfig = {
|
|
96
149
|
/*
|
97
150
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
98
151
|
*/
|
99
|
-
const
|
100
|
-
|
152
|
+
const operationsAllConfig = {
|
153
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/operations-recommended'],
|
101
154
|
rules: {
|
102
|
-
...recommendedConfig.rules,
|
103
155
|
'@graphql-eslint/alphabetize': [
|
104
156
|
'error',
|
105
157
|
{
|
106
|
-
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
107
|
-
values: ['EnumTypeDefinition'],
|
108
158
|
selections: ['OperationDefinition', 'FragmentDefinition'],
|
109
159
|
variables: ['OperationDefinition'],
|
110
|
-
arguments: ['
|
160
|
+
arguments: ['Field', 'Directive'],
|
111
161
|
},
|
112
162
|
],
|
113
|
-
'@graphql-eslint/
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
'@graphql-eslint/input-name': 'error',
|
118
|
-
'@graphql-eslint/match-document-filename': 'error',
|
119
|
-
'@graphql-eslint/no-deprecated': 'error',
|
120
|
-
'@graphql-eslint/no-hashtag-description': 'error',
|
121
|
-
'@graphql-eslint/no-root-type': ['error', { disallow: ['subscription'] }],
|
122
|
-
'@graphql-eslint/no-unreachable-types': 'error',
|
123
|
-
'@graphql-eslint/no-unused-fields': 'error',
|
124
|
-
'@graphql-eslint/require-deprecation-date': 'error',
|
125
|
-
'@graphql-eslint/require-description': ['error', { types: true, overrides: { DirectiveDefinition: true } }],
|
126
|
-
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
127
|
-
'@graphql-eslint/require-id-when-available': 'error',
|
128
|
-
'@graphql-eslint/selection-set-depth': 'error',
|
163
|
+
'@graphql-eslint/match-document-filename': [
|
164
|
+
'error',
|
165
|
+
{ query: 'kebab-case', mutation: 'kebab-case', subscription: 'kebab-case', fragment: 'kebab-case' },
|
166
|
+
],
|
129
167
|
'@graphql-eslint/unique-fragment-name': 'error',
|
130
168
|
'@graphql-eslint/unique-operation-name': 'error',
|
131
169
|
},
|
132
170
|
};
|
133
171
|
|
134
172
|
const configs = {
|
135
|
-
|
136
|
-
recommended:
|
173
|
+
base,
|
174
|
+
'schema-recommended': schemaRecommendedConfig,
|
175
|
+
'schema-all': schemaAllConfig,
|
176
|
+
'operations-recommended': operationsRecommendedConfig,
|
177
|
+
'operations-all': operationsAllConfig,
|
137
178
|
};
|
138
179
|
|
139
180
|
function requireSiblingsOperations(ruleName, context) {
|
@@ -346,7 +387,6 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
346
387
|
docs: {
|
347
388
|
...docs,
|
348
389
|
graphQLJSRuleName: ruleName,
|
349
|
-
category: 'Validation',
|
350
390
|
recommended: true,
|
351
391
|
requiresSchema,
|
352
392
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
@@ -383,16 +423,22 @@ const importFiles = (context) => {
|
|
383
423
|
return _import.processImport(context.getFilename());
|
384
424
|
};
|
385
425
|
const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
|
426
|
+
category: 'Operations',
|
386
427
|
description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
|
387
428
|
}), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
|
429
|
+
category: 'Operations',
|
388
430
|
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`.',
|
389
431
|
}), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
|
432
|
+
category: 'Operations',
|
390
433
|
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.`,
|
391
434
|
}), validationToRule('known-argument-names', 'KnownArgumentNames', {
|
435
|
+
category: ['Schema', 'Operations'],
|
392
436
|
description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
|
393
437
|
}), validationToRule('known-directives', 'KnownDirectives', {
|
438
|
+
category: ['Schema', 'Operations'],
|
394
439
|
description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
|
395
440
|
}), validationToRule('known-fragment-names', 'KnownFragmentNames', {
|
441
|
+
category: 'Operations',
|
396
442
|
description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
|
397
443
|
examples: [
|
398
444
|
{
|
@@ -459,17 +505,23 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
459
505
|
},
|
460
506
|
],
|
461
507
|
}, importFiles), validationToRule('known-type-names', 'KnownTypeNames', {
|
508
|
+
category: ['Schema', 'Operations'],
|
462
509
|
description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
|
463
510
|
}), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
|
511
|
+
category: 'Operations',
|
464
512
|
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.`,
|
465
513
|
}), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
|
514
|
+
category: 'Schema',
|
466
515
|
description: `A GraphQL document is only valid if it contains only one schema definition.`,
|
467
516
|
requiresSchema: false,
|
468
517
|
}), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
|
518
|
+
category: 'Operations',
|
469
519
|
description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
|
470
520
|
}), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
|
521
|
+
category: 'Operations',
|
471
522
|
description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
|
472
523
|
}, importFiles), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
|
524
|
+
category: 'Operations',
|
473
525
|
description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
|
474
526
|
requiresSiblings: true,
|
475
527
|
}, context => {
|
@@ -499,49 +551,68 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
499
551
|
};
|
500
552
|
return getParentNode(context.getFilename());
|
501
553
|
}), validationToRule('no-unused-variables', 'NoUnusedVariables', {
|
554
|
+
category: 'Operations',
|
502
555
|
description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
|
503
556
|
}, importFiles), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
|
557
|
+
category: 'Operations',
|
504
558
|
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.`,
|
505
559
|
}), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
|
560
|
+
category: 'Operations',
|
506
561
|
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.`,
|
507
562
|
}), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
|
563
|
+
category: 'Schema',
|
508
564
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
509
565
|
requiresSchema: false,
|
510
566
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
567
|
+
category: ['Schema', 'Operations'],
|
511
568
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
512
569
|
}), validationToRule('scalar-leafs', 'ScalarLeafs', {
|
570
|
+
category: 'Operations',
|
513
571
|
description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
|
514
572
|
}), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
|
573
|
+
category: 'Operations',
|
515
574
|
description: `A GraphQL subscription is valid only if it contains a single root field.`,
|
516
575
|
}), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
|
576
|
+
category: 'Operations',
|
517
577
|
description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
|
518
578
|
}), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
|
579
|
+
category: 'Schema',
|
519
580
|
description: `A GraphQL document is only valid if all defined directives have unique names.`,
|
520
581
|
requiresSchema: false,
|
521
582
|
}), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
|
583
|
+
category: ['Schema', 'Operations'],
|
522
584
|
description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
|
523
585
|
}), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
|
586
|
+
category: 'Schema',
|
524
587
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
|
525
588
|
requiresSchema: false,
|
526
589
|
}), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
|
590
|
+
category: 'Schema',
|
527
591
|
description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
|
528
592
|
requiresSchema: false,
|
529
593
|
}), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
|
594
|
+
category: 'Operations',
|
530
595
|
description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
|
531
596
|
requiresSchema: false,
|
532
597
|
}), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
|
598
|
+
category: 'Schema',
|
533
599
|
description: `A GraphQL document is only valid if it has only one type per operation.`,
|
534
600
|
requiresSchema: false,
|
535
601
|
}), validationToRule('unique-type-names', 'UniqueTypeNames', {
|
602
|
+
category: 'Schema',
|
536
603
|
description: `A GraphQL document is only valid if all defined types have unique names.`,
|
537
604
|
requiresSchema: false,
|
538
605
|
}), validationToRule('unique-variable-names', 'UniqueVariableNames', {
|
606
|
+
category: 'Operations',
|
539
607
|
description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
|
540
608
|
}), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
|
609
|
+
category: 'Operations',
|
541
610
|
description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
|
542
611
|
}), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
|
612
|
+
category: 'Operations',
|
543
613
|
description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
|
544
614
|
}), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
|
615
|
+
category: 'Operations',
|
545
616
|
description: `Variables passed to field arguments conform to type.`,
|
546
617
|
}));
|
547
618
|
|
@@ -567,7 +638,7 @@ const rule = {
|
|
567
638
|
meta: {
|
568
639
|
type: 'suggestion',
|
569
640
|
docs: {
|
570
|
-
category: '
|
641
|
+
category: ['Schema', 'Operations'],
|
571
642
|
description: 'Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.',
|
572
643
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/alphabetize.md',
|
573
644
|
examples: [
|
@@ -646,15 +717,22 @@ const rule = {
|
|
646
717
|
`,
|
647
718
|
},
|
648
719
|
],
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
720
|
+
configOptions: {
|
721
|
+
schema: [
|
722
|
+
{
|
723
|
+
fields: fieldsEnum,
|
724
|
+
values: valuesEnum,
|
725
|
+
arguments: argumentsEnum,
|
726
|
+
},
|
727
|
+
],
|
728
|
+
operations: [
|
729
|
+
{
|
730
|
+
selections: selectionsEnum,
|
731
|
+
variables: variablesEnum,
|
732
|
+
arguments: [graphql.Kind.FIELD, graphql.Kind.DIRECTIVE],
|
733
|
+
},
|
734
|
+
],
|
735
|
+
},
|
658
736
|
},
|
659
737
|
messages: {
|
660
738
|
[ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"',
|
@@ -792,430 +870,128 @@ const rule = {
|
|
792
870
|
},
|
793
871
|
};
|
794
872
|
|
795
|
-
const AVOID_DUPLICATE_FIELDS = 'AVOID_DUPLICATE_FIELDS';
|
796
873
|
const rule$1 = {
|
797
874
|
meta: {
|
798
875
|
type: 'suggestion',
|
799
876
|
docs: {
|
800
|
-
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
801
|
-
category: 'Stylistic Issues',
|
802
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-duplicate-fields.md',
|
803
877
|
examples: [
|
804
878
|
{
|
805
879
|
title: 'Incorrect',
|
880
|
+
usage: [{ style: 'inline' }],
|
806
881
|
code: /* GraphQL */ `
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
email
|
811
|
-
name # duplicate field
|
812
|
-
}
|
813
|
-
}
|
814
|
-
`,
|
815
|
-
},
|
816
|
-
{
|
817
|
-
title: 'Incorrect',
|
818
|
-
code: /* GraphQL */ `
|
819
|
-
query {
|
820
|
-
users(
|
821
|
-
first: 100
|
822
|
-
skip: 50
|
823
|
-
after: "cji629tngfgou0b73kt7vi5jo"
|
824
|
-
first: 100 # duplicate argument
|
825
|
-
) {
|
826
|
-
id
|
827
|
-
}
|
882
|
+
""" Description """
|
883
|
+
type someTypeName {
|
884
|
+
# ...
|
828
885
|
}
|
829
886
|
`,
|
830
887
|
},
|
831
888
|
{
|
832
|
-
title: '
|
889
|
+
title: 'Correct',
|
890
|
+
usage: [{ style: 'inline' }],
|
833
891
|
code: /* GraphQL */ `
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
) {
|
838
|
-
users(first: $first, skip: 50) {
|
839
|
-
id
|
840
|
-
}
|
892
|
+
" Description "
|
893
|
+
type someTypeName {
|
894
|
+
# ...
|
841
895
|
}
|
842
896
|
`,
|
843
897
|
},
|
844
898
|
],
|
899
|
+
description: 'Require all comments to follow the same style (either block or inline).',
|
900
|
+
category: 'Schema',
|
901
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
|
902
|
+
recommended: true,
|
845
903
|
},
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
904
|
+
schema: [
|
905
|
+
{
|
906
|
+
type: 'object',
|
907
|
+
additionalProperties: false,
|
908
|
+
properties: {
|
909
|
+
style: {
|
910
|
+
enum: ['block', 'inline'],
|
911
|
+
default: 'block',
|
912
|
+
},
|
913
|
+
},
|
914
|
+
},
|
915
|
+
],
|
850
916
|
},
|
851
917
|
create(context) {
|
852
|
-
|
853
|
-
|
918
|
+
const { style = 'block' } = context.options[0] || {};
|
919
|
+
const isBlock = style === 'block';
|
920
|
+
return {
|
921
|
+
[`.description[type=StringValue][block!=${isBlock}]`](node) {
|
854
922
|
context.report({
|
855
|
-
loc: getLocation(
|
856
|
-
|
857
|
-
}),
|
858
|
-
messageId: AVOID_DUPLICATE_FIELDS,
|
859
|
-
data: {
|
860
|
-
type,
|
861
|
-
fieldName,
|
862
|
-
},
|
923
|
+
loc: getLocation(node.loc),
|
924
|
+
message: `Unexpected ${isBlock ? 'inline' : 'block'} description`,
|
863
925
|
});
|
864
|
-
}
|
865
|
-
else {
|
866
|
-
usedFields.add(fieldName);
|
867
|
-
}
|
868
|
-
}
|
869
|
-
return {
|
870
|
-
OperationDefinition(node) {
|
871
|
-
const set = new Set();
|
872
|
-
for (const varDef of node.variableDefinitions) {
|
873
|
-
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
874
|
-
}
|
875
|
-
},
|
876
|
-
Field(node) {
|
877
|
-
const set = new Set();
|
878
|
-
for (const arg of node.arguments) {
|
879
|
-
checkNode(set, arg.name.value, 'Field argument', arg);
|
880
|
-
}
|
881
|
-
},
|
882
|
-
SelectionSet(node) {
|
883
|
-
var _a;
|
884
|
-
const set = new Set();
|
885
|
-
for (const selection of node.selections) {
|
886
|
-
if (selection.kind === graphql.Kind.FIELD) {
|
887
|
-
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
888
|
-
}
|
889
|
-
}
|
890
926
|
},
|
891
927
|
};
|
892
928
|
},
|
893
929
|
};
|
894
930
|
|
895
|
-
const
|
931
|
+
const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
932
|
+
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
933
|
+
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
896
934
|
const rule$2 = {
|
897
935
|
meta: {
|
898
936
|
type: 'suggestion',
|
899
937
|
docs: {
|
900
|
-
description: '
|
901
|
-
category: '
|
902
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/
|
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.',
|
939
|
+
category: 'Schema',
|
940
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
|
903
941
|
examples: [
|
904
942
|
{
|
905
943
|
title: 'Incorrect',
|
906
|
-
usage: [{
|
944
|
+
usage: [{ checkInputType: true }],
|
907
945
|
code: /* GraphQL */ `
|
908
|
-
|
909
|
-
|
910
|
-
}
|
946
|
+
type Mutation {
|
947
|
+
SetMessage(message: InputMessage): String
|
948
|
+
}
|
949
|
+
`,
|
911
950
|
},
|
912
951
|
{
|
913
|
-
title: 'Correct',
|
914
|
-
usage: [{
|
952
|
+
title: 'Correct (with checkInputType)',
|
953
|
+
usage: [{ checkInputType: true }],
|
915
954
|
code: /* GraphQL */ `
|
916
|
-
|
917
|
-
|
918
|
-
}
|
955
|
+
type Mutation {
|
956
|
+
SetMessage(input: SetMessageInput): String
|
957
|
+
}
|
958
|
+
`,
|
959
|
+
},
|
960
|
+
{
|
961
|
+
title: 'Correct (without checkInputType)',
|
962
|
+
usage: [{ checkInputType: false }],
|
963
|
+
code: /* GraphQL */ `
|
964
|
+
type Mutation {
|
965
|
+
SetMessage(input: AnyInputTypeName): String
|
966
|
+
}
|
967
|
+
`,
|
919
968
|
},
|
920
969
|
],
|
921
970
|
},
|
922
|
-
messages: {
|
923
|
-
[AVOID_OPERATION_NAME_PREFIX]: `Forbidden operation name prefix: "{{ invalidPrefix }}"`,
|
924
|
-
},
|
925
971
|
schema: [
|
926
972
|
{
|
927
|
-
additionalProperties: false,
|
928
973
|
type: 'object',
|
929
|
-
|
974
|
+
additionalProperties: false,
|
930
975
|
properties: {
|
931
|
-
|
976
|
+
checkInputType: {
|
977
|
+
type: 'boolean',
|
932
978
|
default: false,
|
979
|
+
description: 'Check that the input type name follows the convention <mutationName>Input',
|
980
|
+
},
|
981
|
+
caseSensitiveInputType: {
|
933
982
|
type: 'boolean',
|
983
|
+
default: true,
|
984
|
+
description: 'Allow for case discrepancies in the input type name',
|
934
985
|
},
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
},
|
945
|
-
],
|
946
|
-
},
|
947
|
-
create(context) {
|
948
|
-
return {
|
949
|
-
'OperationDefinition, FragmentDefinition'(node) {
|
950
|
-
const config = context.options[0] || { keywords: [], caseSensitive: false };
|
951
|
-
const caseSensitive = config.caseSensitive;
|
952
|
-
const keywords = config.keywords || [];
|
953
|
-
if (node && node.name && node.name.value !== '') {
|
954
|
-
for (const keyword of keywords) {
|
955
|
-
const testKeyword = caseSensitive ? keyword : keyword.toLowerCase();
|
956
|
-
const testName = caseSensitive ? node.name.value : node.name.value.toLowerCase();
|
957
|
-
if (testName.startsWith(testKeyword)) {
|
958
|
-
const { start } = node.name.loc;
|
959
|
-
context.report({
|
960
|
-
loc: {
|
961
|
-
start: {
|
962
|
-
line: start.line,
|
963
|
-
column: start.column - 1,
|
964
|
-
},
|
965
|
-
end: {
|
966
|
-
line: start.line,
|
967
|
-
column: start.column - 1 + testKeyword.length,
|
968
|
-
},
|
969
|
-
},
|
970
|
-
data: {
|
971
|
-
invalidPrefix: keyword,
|
972
|
-
},
|
973
|
-
messageId: AVOID_OPERATION_NAME_PREFIX,
|
974
|
-
});
|
975
|
-
}
|
976
|
-
}
|
977
|
-
}
|
978
|
-
},
|
979
|
-
};
|
980
|
-
},
|
981
|
-
};
|
982
|
-
|
983
|
-
const rule$3 = {
|
984
|
-
meta: {
|
985
|
-
type: 'suggestion',
|
986
|
-
docs: {
|
987
|
-
category: 'Best Practices',
|
988
|
-
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
989
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-scalar-result-type-on-mutation.md',
|
990
|
-
requiresSchema: true,
|
991
|
-
examples: [
|
992
|
-
{
|
993
|
-
title: 'Incorrect',
|
994
|
-
code: /* GraphQL */ `
|
995
|
-
type Mutation {
|
996
|
-
createUser: Boolean
|
997
|
-
}
|
998
|
-
`,
|
999
|
-
},
|
1000
|
-
{
|
1001
|
-
title: 'Correct',
|
1002
|
-
code: /* GraphQL */ `
|
1003
|
-
type Mutation {
|
1004
|
-
createUser: User!
|
1005
|
-
}
|
1006
|
-
`,
|
1007
|
-
},
|
1008
|
-
],
|
1009
|
-
},
|
1010
|
-
schema: [],
|
1011
|
-
},
|
1012
|
-
create(context) {
|
1013
|
-
const schema = requireGraphQLSchemaFromContext('avoid-scalar-result-type-on-mutation', context);
|
1014
|
-
const mutationType = schema.getMutationType();
|
1015
|
-
if (!mutationType) {
|
1016
|
-
return {};
|
1017
|
-
}
|
1018
|
-
const selector = [
|
1019
|
-
`:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
1020
|
-
'>',
|
1021
|
-
graphql.Kind.FIELD_DEFINITION,
|
1022
|
-
graphql.Kind.NAMED_TYPE,
|
1023
|
-
].join(' ');
|
1024
|
-
return {
|
1025
|
-
[selector](node) {
|
1026
|
-
const typeName = node.name.value;
|
1027
|
-
const graphQLType = schema.getType(typeName);
|
1028
|
-
if (graphql.isScalarType(graphQLType)) {
|
1029
|
-
context.report({
|
1030
|
-
loc: getLocation(node.loc, typeName),
|
1031
|
-
message: `Unexpected scalar result type "${typeName}"`,
|
1032
|
-
});
|
1033
|
-
}
|
1034
|
-
},
|
1035
|
-
};
|
1036
|
-
},
|
1037
|
-
};
|
1038
|
-
|
1039
|
-
const AVOID_TYPENAME_PREFIX = 'AVOID_TYPENAME_PREFIX';
|
1040
|
-
const rule$4 = {
|
1041
|
-
meta: {
|
1042
|
-
type: 'suggestion',
|
1043
|
-
docs: {
|
1044
|
-
category: 'Best Practices',
|
1045
|
-
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
1046
|
-
recommended: true,
|
1047
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-typename-prefix.md',
|
1048
|
-
examples: [
|
1049
|
-
{
|
1050
|
-
title: 'Incorrect',
|
1051
|
-
code: /* GraphQL */ `
|
1052
|
-
type User {
|
1053
|
-
userId: ID!
|
1054
|
-
}
|
1055
|
-
`,
|
1056
|
-
},
|
1057
|
-
{
|
1058
|
-
title: 'Correct',
|
1059
|
-
code: /* GraphQL */ `
|
1060
|
-
type User {
|
1061
|
-
id: ID!
|
1062
|
-
}
|
1063
|
-
`,
|
1064
|
-
},
|
1065
|
-
],
|
1066
|
-
},
|
1067
|
-
messages: {
|
1068
|
-
[AVOID_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
1069
|
-
},
|
1070
|
-
schema: [],
|
1071
|
-
},
|
1072
|
-
create(context) {
|
1073
|
-
return {
|
1074
|
-
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
1075
|
-
const typeName = node.name.value;
|
1076
|
-
const lowerTypeName = typeName.toLowerCase();
|
1077
|
-
for (const field of node.fields) {
|
1078
|
-
const fieldName = field.name.value;
|
1079
|
-
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
1080
|
-
context.report({
|
1081
|
-
data: {
|
1082
|
-
fieldName,
|
1083
|
-
typeName,
|
1084
|
-
},
|
1085
|
-
messageId: AVOID_TYPENAME_PREFIX,
|
1086
|
-
loc: getLocation(field.loc, lowerTypeName),
|
1087
|
-
});
|
1088
|
-
}
|
1089
|
-
}
|
1090
|
-
},
|
1091
|
-
};
|
1092
|
-
},
|
1093
|
-
};
|
1094
|
-
|
1095
|
-
const rule$5 = {
|
1096
|
-
meta: {
|
1097
|
-
type: 'suggestion',
|
1098
|
-
docs: {
|
1099
|
-
examples: [
|
1100
|
-
{
|
1101
|
-
title: 'Incorrect',
|
1102
|
-
usage: [{ style: 'inline' }],
|
1103
|
-
code: /* GraphQL */ `
|
1104
|
-
""" Description """
|
1105
|
-
type someTypeName {
|
1106
|
-
# ...
|
1107
|
-
}
|
1108
|
-
`,
|
1109
|
-
},
|
1110
|
-
{
|
1111
|
-
title: 'Correct',
|
1112
|
-
usage: [{ style: 'inline' }],
|
1113
|
-
code: /* GraphQL */ `
|
1114
|
-
" Description "
|
1115
|
-
type someTypeName {
|
1116
|
-
# ...
|
1117
|
-
}
|
1118
|
-
`,
|
1119
|
-
},
|
1120
|
-
],
|
1121
|
-
description: 'Require all comments to follow the same style (either block or inline).',
|
1122
|
-
category: 'Stylistic Issues',
|
1123
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
|
1124
|
-
},
|
1125
|
-
schema: [
|
1126
|
-
{
|
1127
|
-
type: 'object',
|
1128
|
-
properties: {
|
1129
|
-
style: {
|
1130
|
-
type: 'string',
|
1131
|
-
enum: ['block', 'inline'],
|
1132
|
-
default: 'inline',
|
1133
|
-
},
|
1134
|
-
},
|
1135
|
-
additionalProperties: false,
|
1136
|
-
},
|
1137
|
-
],
|
1138
|
-
},
|
1139
|
-
create(context) {
|
1140
|
-
const { style } = context.options[0] || { style: 'inline' };
|
1141
|
-
const wrongDescriptionType = style === 'block' ? 'inline' : 'block';
|
1142
|
-
return {
|
1143
|
-
'[description.type="StringValue"]': node => {
|
1144
|
-
if (node.description.block !== (style === 'block')) {
|
1145
|
-
context.report({
|
1146
|
-
loc: getLocation(node.description.loc),
|
1147
|
-
message: `Unexpected ${wrongDescriptionType} description`,
|
1148
|
-
});
|
1149
|
-
}
|
1150
|
-
},
|
1151
|
-
};
|
1152
|
-
},
|
1153
|
-
};
|
1154
|
-
|
1155
|
-
const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
1156
|
-
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
1157
|
-
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
1158
|
-
const rule$6 = {
|
1159
|
-
meta: {
|
1160
|
-
type: 'suggestion',
|
1161
|
-
docs: {
|
1162
|
-
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.',
|
1163
|
-
category: 'Stylistic Issues',
|
1164
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
|
1165
|
-
examples: [
|
1166
|
-
{
|
1167
|
-
title: 'Incorrect',
|
1168
|
-
usage: [{ checkInputType: true }],
|
1169
|
-
code: /* GraphQL */ `
|
1170
|
-
type Mutation {
|
1171
|
-
SetMessage(message: InputMessage): String
|
1172
|
-
}
|
1173
|
-
`,
|
1174
|
-
},
|
1175
|
-
{
|
1176
|
-
title: 'Correct (with checkInputType)',
|
1177
|
-
usage: [{ checkInputType: true }],
|
1178
|
-
code: /* GraphQL */ `
|
1179
|
-
type Mutation {
|
1180
|
-
SetMessage(input: SetMessageInput): String
|
1181
|
-
}
|
1182
|
-
`,
|
1183
|
-
},
|
1184
|
-
{
|
1185
|
-
title: 'Correct (without checkInputType)',
|
1186
|
-
usage: [{ checkInputType: false }],
|
1187
|
-
code: /* GraphQL */ `
|
1188
|
-
type Mutation {
|
1189
|
-
SetMessage(input: AnyInputTypeName): String
|
1190
|
-
}
|
1191
|
-
`,
|
1192
|
-
},
|
1193
|
-
],
|
1194
|
-
},
|
1195
|
-
schema: [
|
1196
|
-
{
|
1197
|
-
type: 'object',
|
1198
|
-
additionalProperties: false,
|
1199
|
-
properties: {
|
1200
|
-
checkInputType: {
|
1201
|
-
type: 'boolean',
|
1202
|
-
default: false,
|
1203
|
-
description: 'Check that the input type name follows the convention <mutationName>Input',
|
1204
|
-
},
|
1205
|
-
caseSensitiveInputType: {
|
1206
|
-
type: 'boolean',
|
1207
|
-
default: true,
|
1208
|
-
description: 'Allow for case discrepancies in the input type name',
|
1209
|
-
},
|
1210
|
-
checkQueries: {
|
1211
|
-
type: 'boolean',
|
1212
|
-
default: false,
|
1213
|
-
description: 'Apply the rule to Queries',
|
1214
|
-
},
|
1215
|
-
checkMutations: {
|
1216
|
-
type: 'boolean',
|
1217
|
-
default: true,
|
1218
|
-
description: 'Apply the rule to Mutations',
|
986
|
+
checkQueries: {
|
987
|
+
type: 'boolean',
|
988
|
+
default: false,
|
989
|
+
description: 'Apply the rule to Queries',
|
990
|
+
},
|
991
|
+
checkMutations: {
|
992
|
+
type: 'boolean',
|
993
|
+
default: true,
|
994
|
+
description: 'Apply the rule to Mutations',
|
1219
995
|
},
|
1220
996
|
},
|
1221
997
|
},
|
@@ -1281,11 +1057,11 @@ const CASE_STYLES = [
|
|
1281
1057
|
const schemaOption = {
|
1282
1058
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1283
1059
|
};
|
1284
|
-
const rule$
|
1060
|
+
const rule$3 = {
|
1285
1061
|
meta: {
|
1286
1062
|
type: 'suggestion',
|
1287
1063
|
docs: {
|
1288
|
-
category: '
|
1064
|
+
category: 'Operations',
|
1289
1065
|
description: 'This rule allows you to enforce that the file name should match the operation name.',
|
1290
1066
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/match-document-filename.md`,
|
1291
1067
|
examples: [
|
@@ -1359,6 +1135,14 @@ const rule$7 = {
|
|
1359
1135
|
`,
|
1360
1136
|
},
|
1361
1137
|
],
|
1138
|
+
configOptions: [
|
1139
|
+
{
|
1140
|
+
query: CaseStyle.kebabCase,
|
1141
|
+
mutation: CaseStyle.kebabCase,
|
1142
|
+
subscription: CaseStyle.kebabCase,
|
1143
|
+
fragment: CaseStyle.kebabCase,
|
1144
|
+
},
|
1145
|
+
],
|
1362
1146
|
},
|
1363
1147
|
messages: {
|
1364
1148
|
[MATCH_EXTENSION]: `File extension "{{ fileExtension }}" don't match extension "{{ expectedFileExtension }}"`,
|
@@ -1367,27 +1151,29 @@ const rule$7 = {
|
|
1367
1151
|
schema: {
|
1368
1152
|
definitions: {
|
1369
1153
|
asString: {
|
1370
|
-
type: 'string',
|
1371
|
-
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1372
1154
|
enum: CASE_STYLES,
|
1155
|
+
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1373
1156
|
},
|
1374
1157
|
asObject: {
|
1375
1158
|
type: 'object',
|
1159
|
+
additionalProperties: false,
|
1376
1160
|
properties: {
|
1377
1161
|
style: {
|
1378
|
-
type: 'string',
|
1379
1162
|
enum: CASE_STYLES,
|
1380
1163
|
},
|
1164
|
+
suffix: {
|
1165
|
+
type: 'string',
|
1166
|
+
},
|
1381
1167
|
},
|
1382
1168
|
},
|
1383
1169
|
},
|
1384
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
1385
1170
|
type: 'array',
|
1171
|
+
maxItems: 1,
|
1386
1172
|
items: {
|
1387
1173
|
type: 'object',
|
1174
|
+
additionalProperties: false,
|
1388
1175
|
properties: {
|
1389
1176
|
fileExtension: {
|
1390
|
-
type: 'string',
|
1391
1177
|
enum: ACCEPTED_EXTENSIONS,
|
1392
1178
|
},
|
1393
1179
|
query: schemaOption,
|
@@ -1462,13 +1248,7 @@ const rule$7 = {
|
|
1462
1248
|
},
|
1463
1249
|
};
|
1464
1250
|
|
1465
|
-
const FIELDS_KINDS = [
|
1466
|
-
graphql.Kind.FIELD_DEFINITION,
|
1467
|
-
graphql.Kind.INPUT_VALUE_DEFINITION,
|
1468
|
-
graphql.Kind.VARIABLE_DEFINITION,
|
1469
|
-
graphql.Kind.ARGUMENT,
|
1470
|
-
graphql.Kind.DIRECTIVE_DEFINITION,
|
1471
|
-
];
|
1251
|
+
const FIELDS_KINDS = [graphql.Kind.FIELD_DEFINITION, graphql.Kind.INPUT_VALUE_DEFINITION, graphql.Kind.ARGUMENT, graphql.Kind.DIRECTIVE_DEFINITION];
|
1472
1252
|
const KindToDisplayName = {
|
1473
1253
|
// types
|
1474
1254
|
[graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
@@ -1480,13 +1260,13 @@ const KindToDisplayName = {
|
|
1480
1260
|
// fields
|
1481
1261
|
[graphql.Kind.FIELD_DEFINITION]: 'Field',
|
1482
1262
|
[graphql.Kind.INPUT_VALUE_DEFINITION]: 'Input property',
|
1483
|
-
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1484
1263
|
[graphql.Kind.ARGUMENT]: 'Argument',
|
1485
1264
|
[graphql.Kind.DIRECTIVE_DEFINITION]: 'Directive',
|
1486
1265
|
// rest
|
1487
1266
|
[graphql.Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
|
1488
1267
|
[graphql.Kind.OPERATION_DEFINITION]: 'Operation',
|
1489
1268
|
[graphql.Kind.FRAGMENT_DEFINITION]: 'Fragment',
|
1269
|
+
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1490
1270
|
};
|
1491
1271
|
const StyleToRegex = {
|
1492
1272
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
@@ -1499,12 +1279,12 @@ const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
|
1499
1279
|
const schemaOption$1 = {
|
1500
1280
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1501
1281
|
};
|
1502
|
-
const rule$
|
1282
|
+
const rule$4 = {
|
1503
1283
|
meta: {
|
1504
1284
|
type: 'suggestion',
|
1505
1285
|
docs: {
|
1506
1286
|
description: 'Require names to follow specified conventions.',
|
1507
|
-
category: '
|
1287
|
+
category: ['Schema', 'Operations'],
|
1508
1288
|
recommended: true,
|
1509
1289
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/naming-convention.md',
|
1510
1290
|
examples: [
|
@@ -1515,6 +1295,24 @@ const rule$8 = {
|
|
1515
1295
|
type user {
|
1516
1296
|
first_name: String!
|
1517
1297
|
}
|
1298
|
+
`,
|
1299
|
+
},
|
1300
|
+
{
|
1301
|
+
title: 'Incorrect',
|
1302
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1303
|
+
code: /* GraphQL */ `
|
1304
|
+
fragment UserFragment on User {
|
1305
|
+
# ...
|
1306
|
+
}
|
1307
|
+
`,
|
1308
|
+
},
|
1309
|
+
{
|
1310
|
+
title: 'Incorrect',
|
1311
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1312
|
+
code: /* GraphQL */ `
|
1313
|
+
type Query {
|
1314
|
+
getUsers: [User!]!
|
1315
|
+
}
|
1518
1316
|
`,
|
1519
1317
|
},
|
1520
1318
|
{
|
@@ -1526,23 +1324,31 @@ const rule$8 = {
|
|
1526
1324
|
}
|
1527
1325
|
`,
|
1528
1326
|
},
|
1529
|
-
],
|
1530
|
-
optionsForConfig: [
|
1531
1327
|
{
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1328
|
+
title: 'Correct',
|
1329
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1330
|
+
code: /* GraphQL */ `
|
1331
|
+
fragment UserFields on User {
|
1332
|
+
# ...
|
1333
|
+
}
|
1334
|
+
`,
|
1335
|
+
},
|
1336
|
+
{
|
1337
|
+
title: 'Correct',
|
1338
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1339
|
+
code: /* GraphQL */ `
|
1340
|
+
type Query {
|
1341
|
+
users: [User!]!
|
1342
|
+
}
|
1343
|
+
`,
|
1344
|
+
},
|
1345
|
+
],
|
1346
|
+
configOptions: {
|
1347
|
+
schema: [
|
1348
|
+
{
|
1349
|
+
types: 'PascalCase',
|
1350
|
+
fields: 'camelCase',
|
1535
1351
|
EnumValueDefinition: 'UPPER_CASE',
|
1536
|
-
OperationDefinition: {
|
1537
|
-
style: 'PascalCase',
|
1538
|
-
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1539
|
-
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1540
|
-
},
|
1541
|
-
FragmentDefinition: {
|
1542
|
-
style: 'PascalCase',
|
1543
|
-
forbiddenPrefixes: ['Fragment'],
|
1544
|
-
forbiddenSuffixes: ['Fragment'],
|
1545
|
-
},
|
1546
1352
|
'FieldDefinition[parent.name.value=Query]': {
|
1547
1353
|
forbiddenPrefixes: ['query', 'get'],
|
1548
1354
|
forbiddenSuffixes: ['Query'],
|
@@ -1556,8 +1362,24 @@ const rule$8 = {
|
|
1556
1362
|
forbiddenSuffixes: ['Subscription'],
|
1557
1363
|
},
|
1558
1364
|
},
|
1559
|
-
|
1560
|
-
|
1365
|
+
],
|
1366
|
+
operations: [
|
1367
|
+
{
|
1368
|
+
Argument: 'camelCase',
|
1369
|
+
VariableDefinition: 'camelCase',
|
1370
|
+
OperationDefinition: {
|
1371
|
+
style: 'PascalCase',
|
1372
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1373
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1374
|
+
},
|
1375
|
+
FragmentDefinition: {
|
1376
|
+
style: 'PascalCase',
|
1377
|
+
forbiddenPrefixes: ['Fragment'],
|
1378
|
+
forbiddenSuffixes: ['Fragment'],
|
1379
|
+
},
|
1380
|
+
},
|
1381
|
+
],
|
1382
|
+
},
|
1561
1383
|
},
|
1562
1384
|
schema: {
|
1563
1385
|
definitions: {
|
@@ -1595,12 +1417,19 @@ const rule$8 = {
|
|
1595
1417
|
properties: {
|
1596
1418
|
types: {
|
1597
1419
|
...schemaOption$1,
|
1598
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `-
|
1420
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1599
1421
|
},
|
1600
1422
|
fields: {
|
1601
1423
|
...schemaOption$1,
|
1602
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `-
|
1424
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1603
1425
|
},
|
1426
|
+
...Object.fromEntries(ALLOWED_KINDS.map(kind => [
|
1427
|
+
kind,
|
1428
|
+
{
|
1429
|
+
...schemaOption$1,
|
1430
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
1431
|
+
},
|
1432
|
+
])),
|
1604
1433
|
allowLeadingUnderscore: {
|
1605
1434
|
type: 'boolean',
|
1606
1435
|
default: false,
|
@@ -1609,35 +1438,27 @@ const rule$8 = {
|
|
1609
1438
|
type: 'boolean',
|
1610
1439
|
default: false,
|
1611
1440
|
},
|
1612
|
-
overrides: {
|
1613
|
-
type: 'object',
|
1614
|
-
additionalProperties: false,
|
1615
|
-
description: [
|
1616
|
-
'May contain the following `ASTNode` names:',
|
1617
|
-
'',
|
1618
|
-
...ALLOWED_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`),
|
1619
|
-
'',
|
1620
|
-
"> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
|
1621
|
-
'>',
|
1622
|
-
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`',
|
1623
|
-
].join('\n'),
|
1624
|
-
patternProperties: {
|
1625
|
-
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1626
|
-
},
|
1627
|
-
},
|
1628
1441
|
},
|
1442
|
+
patternProperties: {
|
1443
|
+
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1444
|
+
},
|
1445
|
+
description: [
|
1446
|
+
"> It's possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with allowed `ASTNode` names which are described below.",
|
1447
|
+
'>',
|
1448
|
+
'> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.',
|
1449
|
+
'>',
|
1450
|
+
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`.',
|
1451
|
+
].join('\n'),
|
1629
1452
|
},
|
1630
1453
|
},
|
1631
1454
|
},
|
1632
1455
|
create(context) {
|
1633
|
-
const options = {
|
1634
|
-
|
1635
|
-
...context.options[0],
|
1636
|
-
};
|
1456
|
+
const options = context.options[0] || {};
|
1457
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, fields, ...restOptions } = options;
|
1637
1458
|
function normalisePropertyOption(kind) {
|
1638
|
-
let style = options
|
1459
|
+
let style = options[kind];
|
1639
1460
|
if (!style) {
|
1640
|
-
style = TYPES_KINDS.includes(kind) ?
|
1461
|
+
style = TYPES_KINDS.includes(kind) ? types : fields;
|
1641
1462
|
}
|
1642
1463
|
return typeof style === 'object' ? style : { style };
|
1643
1464
|
}
|
@@ -1658,10 +1479,10 @@ const rule$8 = {
|
|
1658
1479
|
}
|
1659
1480
|
function getErrorMessage() {
|
1660
1481
|
let name = nodeName;
|
1661
|
-
if (
|
1482
|
+
if (allowLeadingUnderscore) {
|
1662
1483
|
name = name.replace(/^_*/, '');
|
1663
1484
|
}
|
1664
|
-
if (
|
1485
|
+
if (allowTrailingUnderscore) {
|
1665
1486
|
name = name.replace(/_*$/, '');
|
1666
1487
|
}
|
1667
1488
|
if (prefix && !name.startsWith(prefix)) {
|
@@ -1695,15 +1516,13 @@ const rule$8 = {
|
|
1695
1516
|
});
|
1696
1517
|
};
|
1697
1518
|
const listeners = {};
|
1698
|
-
if (!
|
1519
|
+
if (!allowLeadingUnderscore) {
|
1699
1520
|
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1700
1521
|
}
|
1701
|
-
if (!
|
1522
|
+
if (!allowTrailingUnderscore) {
|
1702
1523
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1703
1524
|
}
|
1704
|
-
const selectors = new Set([
|
1705
|
-
.flat()
|
1706
|
-
.filter(Boolean));
|
1525
|
+
const selectors = new Set([types && TYPES_KINDS, fields && FIELDS_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1707
1526
|
for (const selector of selectors) {
|
1708
1527
|
listeners[selector] = checkNode(selector);
|
1709
1528
|
}
|
@@ -1712,11 +1531,11 @@ const rule$8 = {
|
|
1712
1531
|
};
|
1713
1532
|
|
1714
1533
|
const NO_ANONYMOUS_OPERATIONS = 'NO_ANONYMOUS_OPERATIONS';
|
1715
|
-
const rule$
|
1534
|
+
const rule$5 = {
|
1716
1535
|
meta: {
|
1717
1536
|
type: 'suggestion',
|
1718
1537
|
docs: {
|
1719
|
-
category: '
|
1538
|
+
category: 'Operations',
|
1720
1539
|
description: 'Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.',
|
1721
1540
|
recommended: true,
|
1722
1541
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-anonymous-operations.md',
|
@@ -1760,12 +1579,12 @@ const rule$9 = {
|
|
1760
1579
|
};
|
1761
1580
|
|
1762
1581
|
const ERROR_MESSAGE_ID = 'NO_CASE_INSENSITIVE_ENUM_VALUES_DUPLICATES';
|
1763
|
-
const rule$
|
1582
|
+
const rule$6 = {
|
1764
1583
|
meta: {
|
1765
1584
|
type: 'suggestion',
|
1766
1585
|
docs: {
|
1767
1586
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-case-insensitive-enum-values-duplicates.md',
|
1768
|
-
category: '
|
1587
|
+
category: 'Schema',
|
1769
1588
|
recommended: true,
|
1770
1589
|
description: 'Disallow case-insensitive enum values duplicates.',
|
1771
1590
|
examples: [
|
@@ -1816,11 +1635,11 @@ const rule$a = {
|
|
1816
1635
|
};
|
1817
1636
|
|
1818
1637
|
const NO_DEPRECATED = 'NO_DEPRECATED';
|
1819
|
-
const rule$
|
1638
|
+
const rule$7 = {
|
1820
1639
|
meta: {
|
1821
1640
|
type: 'suggestion',
|
1822
1641
|
docs: {
|
1823
|
-
category: '
|
1642
|
+
category: 'Operations',
|
1824
1643
|
description: `Enforce that deprecated fields or enum values are not in use by operations.`,
|
1825
1644
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-deprecated.md`,
|
1826
1645
|
requiresSchema: true,
|
@@ -1883,48 +1702,150 @@ const rule$b = {
|
|
1883
1702
|
fullName
|
1884
1703
|
}
|
1885
1704
|
}
|
1886
|
-
`,
|
1887
|
-
},
|
1888
|
-
],
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1705
|
+
`,
|
1706
|
+
},
|
1707
|
+
],
|
1708
|
+
recommended: true,
|
1709
|
+
},
|
1710
|
+
messages: {
|
1711
|
+
[NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
|
1712
|
+
},
|
1713
|
+
schema: [],
|
1714
|
+
},
|
1715
|
+
create(context) {
|
1716
|
+
return {
|
1717
|
+
EnumValue(node) {
|
1718
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1719
|
+
const typeInfo = node.typeInfo();
|
1720
|
+
if (typeInfo && typeInfo.enumValue) {
|
1721
|
+
if (typeInfo.enumValue.deprecationReason) {
|
1722
|
+
const enumValueName = node.value;
|
1723
|
+
context.report({
|
1724
|
+
loc: getLocation(node.loc, enumValueName),
|
1725
|
+
messageId: NO_DEPRECATED,
|
1726
|
+
data: {
|
1727
|
+
type: 'enum value',
|
1728
|
+
reason: typeInfo.enumValue.deprecationReason ? `(reason: ${typeInfo.enumValue.deprecationReason})` : '',
|
1729
|
+
},
|
1730
|
+
});
|
1731
|
+
}
|
1732
|
+
}
|
1733
|
+
},
|
1734
|
+
Field(node) {
|
1735
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1736
|
+
const typeInfo = node.typeInfo();
|
1737
|
+
if (typeInfo && typeInfo.fieldDef) {
|
1738
|
+
if (typeInfo.fieldDef.deprecationReason) {
|
1739
|
+
const fieldName = node.name.value;
|
1740
|
+
context.report({
|
1741
|
+
loc: getLocation(node.loc, fieldName),
|
1742
|
+
messageId: NO_DEPRECATED,
|
1743
|
+
data: {
|
1744
|
+
type: 'field',
|
1745
|
+
reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
|
1746
|
+
},
|
1747
|
+
});
|
1748
|
+
}
|
1749
|
+
}
|
1750
|
+
},
|
1751
|
+
};
|
1752
|
+
},
|
1753
|
+
};
|
1754
|
+
|
1755
|
+
const NO_DUPLICATE_FIELDS = 'NO_DUPLICATE_FIELDS';
|
1756
|
+
const rule$8 = {
|
1757
|
+
meta: {
|
1758
|
+
type: 'suggestion',
|
1759
|
+
docs: {
|
1760
|
+
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
1761
|
+
category: 'Operations',
|
1762
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-duplicate-fields.md',
|
1763
|
+
recommended: true,
|
1764
|
+
examples: [
|
1765
|
+
{
|
1766
|
+
title: 'Incorrect',
|
1767
|
+
code: /* GraphQL */ `
|
1768
|
+
query {
|
1769
|
+
user {
|
1770
|
+
name
|
1771
|
+
email
|
1772
|
+
name # duplicate field
|
1773
|
+
}
|
1774
|
+
}
|
1775
|
+
`,
|
1776
|
+
},
|
1777
|
+
{
|
1778
|
+
title: 'Incorrect',
|
1779
|
+
code: /* GraphQL */ `
|
1780
|
+
query {
|
1781
|
+
users(
|
1782
|
+
first: 100
|
1783
|
+
skip: 50
|
1784
|
+
after: "cji629tngfgou0b73kt7vi5jo"
|
1785
|
+
first: 100 # duplicate argument
|
1786
|
+
) {
|
1787
|
+
id
|
1788
|
+
}
|
1789
|
+
}
|
1790
|
+
`,
|
1791
|
+
},
|
1792
|
+
{
|
1793
|
+
title: 'Incorrect',
|
1794
|
+
code: /* GraphQL */ `
|
1795
|
+
query (
|
1796
|
+
$first: Int!
|
1797
|
+
$first: Int! # duplicate variable
|
1798
|
+
) {
|
1799
|
+
users(first: $first, skip: 50) {
|
1800
|
+
id
|
1801
|
+
}
|
1802
|
+
}
|
1803
|
+
`,
|
1804
|
+
},
|
1805
|
+
],
|
1806
|
+
},
|
1807
|
+
messages: {
|
1808
|
+
[NO_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
|
1809
|
+
},
|
1810
|
+
schema: [],
|
1811
|
+
},
|
1812
|
+
create(context) {
|
1813
|
+
function checkNode(usedFields, fieldName, type, node) {
|
1814
|
+
if (usedFields.has(fieldName)) {
|
1815
|
+
context.report({
|
1816
|
+
loc: getLocation((node.kind === graphql.Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
|
1817
|
+
offsetEnd: node.kind === graphql.Kind.VARIABLE_DEFINITION ? 0 : 1,
|
1818
|
+
}),
|
1819
|
+
messageId: NO_DUPLICATE_FIELDS,
|
1820
|
+
data: {
|
1821
|
+
type,
|
1822
|
+
fieldName,
|
1823
|
+
},
|
1824
|
+
});
|
1825
|
+
}
|
1826
|
+
else {
|
1827
|
+
usedFields.add(fieldName);
|
1828
|
+
}
|
1829
|
+
}
|
1896
1830
|
return {
|
1897
|
-
|
1898
|
-
|
1899
|
-
const
|
1900
|
-
|
1901
|
-
if (typeInfo.enumValue.deprecationReason) {
|
1902
|
-
const enumValueName = node.value;
|
1903
|
-
context.report({
|
1904
|
-
loc: getLocation(node.loc, enumValueName),
|
1905
|
-
messageId: NO_DEPRECATED,
|
1906
|
-
data: {
|
1907
|
-
type: 'enum value',
|
1908
|
-
reason: typeInfo.enumValue.deprecationReason ? `(reason: ${typeInfo.enumValue.deprecationReason})` : '',
|
1909
|
-
},
|
1910
|
-
});
|
1911
|
-
}
|
1831
|
+
OperationDefinition(node) {
|
1832
|
+
const set = new Set();
|
1833
|
+
for (const varDef of node.variableDefinitions) {
|
1834
|
+
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
1912
1835
|
}
|
1913
1836
|
},
|
1914
1837
|
Field(node) {
|
1915
|
-
|
1916
|
-
const
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
},
|
1927
|
-
});
|
1838
|
+
const set = new Set();
|
1839
|
+
for (const arg of node.arguments) {
|
1840
|
+
checkNode(set, arg.name.value, 'Field argument', arg);
|
1841
|
+
}
|
1842
|
+
},
|
1843
|
+
SelectionSet(node) {
|
1844
|
+
var _a;
|
1845
|
+
const set = new Set();
|
1846
|
+
for (const selection of node.selections) {
|
1847
|
+
if (selection.kind === graphql.Kind.FIELD) {
|
1848
|
+
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
1928
1849
|
}
|
1929
1850
|
}
|
1930
1851
|
},
|
@@ -1933,14 +1854,14 @@ const rule$b = {
|
|
1933
1854
|
};
|
1934
1855
|
|
1935
1856
|
const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
|
1936
|
-
const rule$
|
1857
|
+
const rule$9 = {
|
1937
1858
|
meta: {
|
1938
1859
|
messages: {
|
1939
1860
|
[HASHTAG_COMMENT]: 'Using hashtag (#) for adding GraphQL descriptions is not allowed. Prefer using """ for multiline, or " for a single line description.',
|
1940
1861
|
},
|
1941
1862
|
docs: {
|
1942
1863
|
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.',
|
1943
|
-
category: '
|
1864
|
+
category: 'Schema',
|
1944
1865
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
|
1945
1866
|
examples: [
|
1946
1867
|
{
|
@@ -1977,6 +1898,7 @@ const rule$c = {
|
|
1977
1898
|
`,
|
1978
1899
|
},
|
1979
1900
|
],
|
1901
|
+
recommended: true,
|
1980
1902
|
},
|
1981
1903
|
type: 'suggestion',
|
1982
1904
|
schema: [],
|
@@ -2005,85 +1927,18 @@ const rule$c = {
|
|
2005
1927
|
},
|
2006
1928
|
};
|
2007
1929
|
|
2008
|
-
const
|
2009
|
-
const rule$
|
2010
|
-
meta: {
|
2011
|
-
fixable: 'code',
|
2012
|
-
type: 'suggestion',
|
2013
|
-
docs: {
|
2014
|
-
category: 'Stylistic Issues',
|
2015
|
-
recommended: true,
|
2016
|
-
description: `Makes sure you are not adding the operation type to the name of the operation.`,
|
2017
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-operation-name-suffix.md`,
|
2018
|
-
examples: [
|
2019
|
-
{
|
2020
|
-
title: 'Incorrect',
|
2021
|
-
code: /* GraphQL */ `
|
2022
|
-
query userQuery {
|
2023
|
-
# ...
|
2024
|
-
}
|
2025
|
-
`,
|
2026
|
-
},
|
2027
|
-
{
|
2028
|
-
title: 'Correct',
|
2029
|
-
code: /* GraphQL */ `
|
2030
|
-
query user {
|
2031
|
-
# ...
|
2032
|
-
}
|
2033
|
-
`,
|
2034
|
-
},
|
2035
|
-
],
|
2036
|
-
},
|
2037
|
-
messages: {
|
2038
|
-
[NO_OPERATION_NAME_SUFFIX]: `Unnecessary "{{ invalidSuffix }}" suffix in your operation name!`,
|
2039
|
-
},
|
2040
|
-
schema: [],
|
2041
|
-
},
|
2042
|
-
create(context) {
|
2043
|
-
return {
|
2044
|
-
'OperationDefinition, FragmentDefinition'(node) {
|
2045
|
-
var _a;
|
2046
|
-
const name = ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '';
|
2047
|
-
if (name.length > 0) {
|
2048
|
-
const invalidSuffix = 'operation' in node ? node.operation : 'fragment';
|
2049
|
-
if (name.toLowerCase().endsWith(invalidSuffix)) {
|
2050
|
-
const { start, end } = node.name.loc;
|
2051
|
-
context.report({
|
2052
|
-
loc: {
|
2053
|
-
start: {
|
2054
|
-
column: start.column - 1 + name.length - invalidSuffix.length,
|
2055
|
-
line: start.line,
|
2056
|
-
},
|
2057
|
-
end: {
|
2058
|
-
column: end.column - 1 + name.length,
|
2059
|
-
line: end.line,
|
2060
|
-
},
|
2061
|
-
},
|
2062
|
-
data: {
|
2063
|
-
invalidSuffix,
|
2064
|
-
},
|
2065
|
-
fix: fixer => fixer.removeRange([node.name.range[1] - invalidSuffix.length, node.name.range[1]]),
|
2066
|
-
messageId: NO_OPERATION_NAME_SUFFIX,
|
2067
|
-
});
|
2068
|
-
}
|
2069
|
-
}
|
2070
|
-
},
|
2071
|
-
};
|
2072
|
-
},
|
2073
|
-
};
|
2074
|
-
|
2075
|
-
const ROOT_TYPES = ['query', 'mutation', 'subscription'];
|
2076
|
-
const rule$e = {
|
1930
|
+
const ROOT_TYPES = ['mutation', 'subscription'];
|
1931
|
+
const rule$a = {
|
2077
1932
|
meta: {
|
2078
1933
|
type: 'suggestion',
|
2079
1934
|
docs: {
|
2080
|
-
category: '
|
2081
|
-
description: 'Disallow using root types
|
1935
|
+
category: 'Schema',
|
1936
|
+
description: 'Disallow using root types `mutation` and/or `subscription`.',
|
2082
1937
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
|
2083
1938
|
requiresSchema: true,
|
2084
1939
|
examples: [
|
2085
1940
|
{
|
2086
|
-
title: 'Incorrect
|
1941
|
+
title: 'Incorrect',
|
2087
1942
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2088
1943
|
code: /* GraphQL */ `
|
2089
1944
|
type Mutation {
|
@@ -2092,16 +1947,7 @@ const rule$e = {
|
|
2092
1947
|
`,
|
2093
1948
|
},
|
2094
1949
|
{
|
2095
|
-
title: '
|
2096
|
-
usage: [{ disallow: ['query'] }],
|
2097
|
-
code: /* GraphQL */ `
|
2098
|
-
type Query {
|
2099
|
-
users: [User!]!
|
2100
|
-
}
|
2101
|
-
`,
|
2102
|
-
},
|
2103
|
-
{
|
2104
|
-
title: 'Correct (`read-only` schema)',
|
1950
|
+
title: 'Correct',
|
2105
1951
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2106
1952
|
code: /* GraphQL */ `
|
2107
1953
|
type Query {
|
@@ -2110,7 +1956,6 @@ const rule$e = {
|
|
2110
1956
|
`,
|
2111
1957
|
},
|
2112
1958
|
],
|
2113
|
-
optionsForConfig: [{ disallow: ['subscription'] }],
|
2114
1959
|
},
|
2115
1960
|
schema: {
|
2116
1961
|
type: 'array',
|
@@ -2137,7 +1982,6 @@ const rule$e = {
|
|
2137
1982
|
const schema = requireGraphQLSchemaFromContext('no-root-type', context);
|
2138
1983
|
const disallow = new Set(context.options[0].disallow);
|
2139
1984
|
const rootTypeNames = [
|
2140
|
-
disallow.has('query') && schema.getQueryType(),
|
2141
1985
|
disallow.has('mutation') && schema.getMutationType(),
|
2142
1986
|
disallow.has('subscription') && schema.getSubscriptionType(),
|
2143
1987
|
]
|
@@ -2163,16 +2007,128 @@ const rule$e = {
|
|
2163
2007
|
},
|
2164
2008
|
};
|
2165
2009
|
|
2010
|
+
const rule$b = {
|
2011
|
+
meta: {
|
2012
|
+
type: 'suggestion',
|
2013
|
+
docs: {
|
2014
|
+
category: 'Schema',
|
2015
|
+
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
2016
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-scalar-result-type-on-mutation.md',
|
2017
|
+
requiresSchema: true,
|
2018
|
+
examples: [
|
2019
|
+
{
|
2020
|
+
title: 'Incorrect',
|
2021
|
+
code: /* GraphQL */ `
|
2022
|
+
type Mutation {
|
2023
|
+
createUser: Boolean
|
2024
|
+
}
|
2025
|
+
`,
|
2026
|
+
},
|
2027
|
+
{
|
2028
|
+
title: 'Correct',
|
2029
|
+
code: /* GraphQL */ `
|
2030
|
+
type Mutation {
|
2031
|
+
createUser: User!
|
2032
|
+
}
|
2033
|
+
`,
|
2034
|
+
},
|
2035
|
+
],
|
2036
|
+
},
|
2037
|
+
schema: [],
|
2038
|
+
},
|
2039
|
+
create(context) {
|
2040
|
+
const schema = requireGraphQLSchemaFromContext('no-scalar-result-type-on-mutation', context);
|
2041
|
+
const mutationType = schema.getMutationType();
|
2042
|
+
if (!mutationType) {
|
2043
|
+
return {};
|
2044
|
+
}
|
2045
|
+
const selector = [
|
2046
|
+
`:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
2047
|
+
'>',
|
2048
|
+
graphql.Kind.FIELD_DEFINITION,
|
2049
|
+
graphql.Kind.NAMED_TYPE,
|
2050
|
+
].join(' ');
|
2051
|
+
return {
|
2052
|
+
[selector](node) {
|
2053
|
+
const typeName = node.name.value;
|
2054
|
+
const graphQLType = schema.getType(typeName);
|
2055
|
+
if (graphql.isScalarType(graphQLType)) {
|
2056
|
+
context.report({
|
2057
|
+
loc: getLocation(node.loc, typeName),
|
2058
|
+
message: `Unexpected scalar result type "${typeName}"`,
|
2059
|
+
});
|
2060
|
+
}
|
2061
|
+
},
|
2062
|
+
};
|
2063
|
+
},
|
2064
|
+
};
|
2065
|
+
|
2066
|
+
const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
|
2067
|
+
const rule$c = {
|
2068
|
+
meta: {
|
2069
|
+
type: 'suggestion',
|
2070
|
+
docs: {
|
2071
|
+
category: 'Schema',
|
2072
|
+
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
2073
|
+
recommended: true,
|
2074
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
|
2075
|
+
examples: [
|
2076
|
+
{
|
2077
|
+
title: 'Incorrect',
|
2078
|
+
code: /* GraphQL */ `
|
2079
|
+
type User {
|
2080
|
+
userId: ID!
|
2081
|
+
}
|
2082
|
+
`,
|
2083
|
+
},
|
2084
|
+
{
|
2085
|
+
title: 'Correct',
|
2086
|
+
code: /* GraphQL */ `
|
2087
|
+
type User {
|
2088
|
+
id: ID!
|
2089
|
+
}
|
2090
|
+
`,
|
2091
|
+
},
|
2092
|
+
],
|
2093
|
+
},
|
2094
|
+
messages: {
|
2095
|
+
[NO_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
2096
|
+
},
|
2097
|
+
schema: [],
|
2098
|
+
},
|
2099
|
+
create(context) {
|
2100
|
+
return {
|
2101
|
+
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
2102
|
+
const typeName = node.name.value;
|
2103
|
+
const lowerTypeName = typeName.toLowerCase();
|
2104
|
+
for (const field of node.fields) {
|
2105
|
+
const fieldName = field.name.value;
|
2106
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
2107
|
+
context.report({
|
2108
|
+
data: {
|
2109
|
+
fieldName,
|
2110
|
+
typeName,
|
2111
|
+
},
|
2112
|
+
messageId: NO_TYPENAME_PREFIX,
|
2113
|
+
loc: getLocation(field.loc, lowerTypeName),
|
2114
|
+
});
|
2115
|
+
}
|
2116
|
+
}
|
2117
|
+
},
|
2118
|
+
};
|
2119
|
+
},
|
2120
|
+
};
|
2121
|
+
|
2166
2122
|
const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
|
2167
2123
|
const RULE_NAME = 'no-unreachable-types';
|
2168
|
-
const rule$
|
2124
|
+
const rule$d = {
|
2169
2125
|
meta: {
|
2170
2126
|
messages: {
|
2171
|
-
[UNREACHABLE_TYPE]:
|
2127
|
+
[UNREACHABLE_TYPE]: 'Type "{{ typeName }}" is unreachable',
|
2172
2128
|
},
|
2173
2129
|
docs: {
|
2174
2130
|
description: `Requires all types to be reachable at some level by root level fields.`,
|
2175
|
-
category: '
|
2131
|
+
category: 'Schema',
|
2176
2132
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
|
2177
2133
|
requiresSchema: true,
|
2178
2134
|
examples: [
|
@@ -2203,6 +2159,7 @@ const rule$f = {
|
|
2203
2159
|
`,
|
2204
2160
|
},
|
2205
2161
|
],
|
2162
|
+
recommended: true,
|
2206
2163
|
},
|
2207
2164
|
fixable: 'code',
|
2208
2165
|
type: 'suggestion',
|
@@ -2241,14 +2198,14 @@ const rule$f = {
|
|
2241
2198
|
|
2242
2199
|
const UNUSED_FIELD = 'UNUSED_FIELD';
|
2243
2200
|
const RULE_NAME$1 = 'no-unused-fields';
|
2244
|
-
const rule$
|
2201
|
+
const rule$e = {
|
2245
2202
|
meta: {
|
2246
2203
|
messages: {
|
2247
2204
|
[UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
|
2248
2205
|
},
|
2249
2206
|
docs: {
|
2250
2207
|
description: `Requires all fields to be used at some level by siblings operations.`,
|
2251
|
-
category: '
|
2208
|
+
category: 'Schema',
|
2252
2209
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
|
2253
2210
|
requiresSiblings: true,
|
2254
2211
|
requiresSchema: true,
|
@@ -2430,11 +2387,11 @@ const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
|
2430
2387
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
2431
2388
|
const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
|
2432
2389
|
const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
|
2433
|
-
const rule$
|
2390
|
+
const rule$f = {
|
2434
2391
|
meta: {
|
2435
2392
|
type: 'suggestion',
|
2436
2393
|
docs: {
|
2437
|
-
category: '
|
2394
|
+
category: 'Schema',
|
2438
2395
|
description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
|
2439
2396
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-date.md',
|
2440
2397
|
examples: [
|
@@ -2533,11 +2490,11 @@ const rule$h = {
|
|
2533
2490
|
},
|
2534
2491
|
};
|
2535
2492
|
|
2536
|
-
const rule$
|
2493
|
+
const rule$g = {
|
2537
2494
|
meta: {
|
2538
2495
|
docs: {
|
2539
2496
|
description: `Require all deprecation directives to specify a reason.`,
|
2540
|
-
category: '
|
2497
|
+
category: 'Schema',
|
2541
2498
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-reason.md`,
|
2542
2499
|
recommended: true,
|
2543
2500
|
examples: [
|
@@ -2595,16 +2552,16 @@ const ALLOWED_KINDS$1 = [
|
|
2595
2552
|
graphql.Kind.ENUM_VALUE_DEFINITION,
|
2596
2553
|
graphql.Kind.DIRECTIVE_DEFINITION,
|
2597
2554
|
];
|
2598
|
-
const rule$
|
2555
|
+
const rule$h = {
|
2599
2556
|
meta: {
|
2600
2557
|
docs: {
|
2601
|
-
category: '
|
2558
|
+
category: 'Schema',
|
2602
2559
|
description: 'Enforce descriptions in your type definitions.',
|
2603
2560
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md',
|
2604
2561
|
examples: [
|
2605
2562
|
{
|
2606
2563
|
title: 'Incorrect',
|
2607
|
-
usage: [{ types: true,
|
2564
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2608
2565
|
code: /* GraphQL */ `
|
2609
2566
|
type someTypeName {
|
2610
2567
|
name: String
|
@@ -2613,7 +2570,7 @@ const rule$j = {
|
|
2613
2570
|
},
|
2614
2571
|
{
|
2615
2572
|
title: 'Correct',
|
2616
|
-
usage: [{ types: true,
|
2573
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2617
2574
|
code: /* GraphQL */ `
|
2618
2575
|
"""
|
2619
2576
|
Some type description
|
@@ -2627,14 +2584,13 @@ const rule$j = {
|
|
2627
2584
|
`,
|
2628
2585
|
},
|
2629
2586
|
],
|
2630
|
-
|
2587
|
+
configOptions: [
|
2631
2588
|
{
|
2632
2589
|
types: true,
|
2633
|
-
|
2634
|
-
[graphql.Kind.DIRECTIVE_DEFINITION]: true,
|
2635
|
-
},
|
2590
|
+
[graphql.Kind.DIRECTIVE_DEFINITION]: true,
|
2636
2591
|
},
|
2637
2592
|
],
|
2593
|
+
recommended: true,
|
2638
2594
|
},
|
2639
2595
|
type: 'suggestion',
|
2640
2596
|
messages: {
|
@@ -2651,22 +2607,23 @@ const rule$j = {
|
|
2651
2607
|
properties: {
|
2652
2608
|
types: {
|
2653
2609
|
type: 'boolean',
|
2654
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `-
|
2655
|
-
},
|
2656
|
-
overrides: {
|
2657
|
-
type: 'object',
|
2658
|
-
description: 'Configuration for precise `ASTNode`',
|
2659
|
-
additionalProperties: false,
|
2660
|
-
properties: Object.fromEntries(ALLOWED_KINDS$1.map(kind => [kind, { type: 'boolean' }])),
|
2610
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
2661
2611
|
},
|
2612
|
+
...Object.fromEntries([...ALLOWED_KINDS$1].sort().map(kind => [
|
2613
|
+
kind,
|
2614
|
+
{
|
2615
|
+
type: 'boolean',
|
2616
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
2617
|
+
},
|
2618
|
+
])),
|
2662
2619
|
},
|
2663
2620
|
},
|
2664
2621
|
},
|
2665
2622
|
},
|
2666
2623
|
create(context) {
|
2667
|
-
const { types,
|
2624
|
+
const { types, ...restOptions } = context.options[0];
|
2668
2625
|
const kinds = new Set(types ? TYPES_KINDS : []);
|
2669
|
-
for (const [kind, isEnabled] of Object.entries(
|
2626
|
+
for (const [kind, isEnabled] of Object.entries(restOptions)) {
|
2670
2627
|
if (isEnabled) {
|
2671
2628
|
kinds.add(kind);
|
2672
2629
|
}
|
@@ -2694,11 +2651,11 @@ const rule$j = {
|
|
2694
2651
|
};
|
2695
2652
|
|
2696
2653
|
const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
|
2697
|
-
const rule$
|
2654
|
+
const rule$i = {
|
2698
2655
|
meta: {
|
2699
2656
|
type: 'suggestion',
|
2700
2657
|
docs: {
|
2701
|
-
category: '
|
2658
|
+
category: 'Schema',
|
2702
2659
|
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`.',
|
2703
2660
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
|
2704
2661
|
requiresSchema: true,
|
@@ -2862,13 +2819,13 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2862
2819
|
|
2863
2820
|
const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2864
2821
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2865
|
-
const rule$
|
2822
|
+
const rule$j = {
|
2866
2823
|
meta: {
|
2867
2824
|
type: 'suggestion',
|
2868
2825
|
docs: {
|
2869
|
-
category: '
|
2870
|
-
description:
|
2871
|
-
url:
|
2826
|
+
category: 'Operations',
|
2827
|
+
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2828
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
|
2872
2829
|
requiresSchema: true,
|
2873
2830
|
requiresSiblings: true,
|
2874
2831
|
examples: [
|
@@ -2908,17 +2865,17 @@ const rule$l = {
|
|
2908
2865
|
`,
|
2909
2866
|
},
|
2910
2867
|
],
|
2868
|
+
recommended: true,
|
2911
2869
|
},
|
2912
2870
|
messages: {
|
2913
|
-
[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 }}".`,
|
2871
|
+
[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 }}".`,
|
2914
2872
|
},
|
2915
2873
|
schema: {
|
2916
2874
|
type: 'array',
|
2917
|
-
additionalItems: false,
|
2918
|
-
minItems: 0,
|
2919
2875
|
maxItems: 1,
|
2920
2876
|
items: {
|
2921
2877
|
type: 'object',
|
2878
|
+
additionalProperties: false,
|
2922
2879
|
properties: {
|
2923
2880
|
fieldName: {
|
2924
2881
|
type: 'string',
|
@@ -2998,12 +2955,12 @@ const rule$l = {
|
|
2998
2955
|
},
|
2999
2956
|
};
|
3000
2957
|
|
3001
|
-
const rule$
|
2958
|
+
const rule$k = {
|
3002
2959
|
meta: {
|
3003
2960
|
docs: {
|
3004
|
-
category: '
|
2961
|
+
category: 'Operations',
|
3005
2962
|
description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
|
3006
|
-
url:
|
2963
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
|
3007
2964
|
requiresSiblings: true,
|
3008
2965
|
examples: [
|
3009
2966
|
{
|
@@ -3046,22 +3003,26 @@ const rule$m = {
|
|
3046
3003
|
`,
|
3047
3004
|
},
|
3048
3005
|
],
|
3006
|
+
recommended: true,
|
3007
|
+
configOptions: [{ maxDepth: 7 }],
|
3049
3008
|
},
|
3050
3009
|
type: 'suggestion',
|
3051
3010
|
schema: {
|
3052
3011
|
type: 'array',
|
3053
|
-
additionalItems: false,
|
3054
3012
|
minItems: 1,
|
3055
3013
|
maxItems: 1,
|
3056
3014
|
items: {
|
3057
3015
|
type: 'object',
|
3058
|
-
|
3016
|
+
additionalProperties: false,
|
3017
|
+
required: ['maxDepth'],
|
3059
3018
|
properties: {
|
3060
3019
|
maxDepth: {
|
3061
3020
|
type: 'number',
|
3062
3021
|
},
|
3063
3022
|
ignore: {
|
3064
3023
|
type: 'array',
|
3024
|
+
uniqueItems: true,
|
3025
|
+
minItems: 1,
|
3065
3026
|
items: {
|
3066
3027
|
type: 'string',
|
3067
3028
|
},
|
@@ -3120,12 +3081,12 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
|
|
3120
3081
|
}
|
3121
3082
|
return false;
|
3122
3083
|
};
|
3123
|
-
const rule$
|
3084
|
+
const rule$l = {
|
3124
3085
|
meta: {
|
3125
3086
|
type: 'suggestion',
|
3126
3087
|
docs: {
|
3127
3088
|
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.',
|
3128
|
-
category: '
|
3089
|
+
category: 'Schema',
|
3129
3090
|
recommended: true,
|
3130
3091
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
|
3131
3092
|
examples: [
|
@@ -3185,13 +3146,15 @@ const rule$n = {
|
|
3185
3146
|
],
|
3186
3147
|
},
|
3187
3148
|
schema: {
|
3188
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
3189
3149
|
type: 'array',
|
3150
|
+
maxItems: 1,
|
3190
3151
|
items: {
|
3191
3152
|
type: 'object',
|
3153
|
+
additionalProperties: false,
|
3192
3154
|
properties: {
|
3193
3155
|
acceptedIdNames: {
|
3194
3156
|
type: 'array',
|
3157
|
+
uniqueItems: true,
|
3195
3158
|
items: {
|
3196
3159
|
type: 'string',
|
3197
3160
|
},
|
@@ -3199,6 +3162,7 @@ const rule$n = {
|
|
3199
3162
|
},
|
3200
3163
|
acceptedIdTypes: {
|
3201
3164
|
type: 'array',
|
3165
|
+
uniqueItems: true,
|
3202
3166
|
items: {
|
3203
3167
|
type: 'string',
|
3204
3168
|
},
|
@@ -3209,19 +3173,21 @@ const rule$n = {
|
|
3209
3173
|
properties: {
|
3210
3174
|
types: {
|
3211
3175
|
type: 'array',
|
3176
|
+
uniqueItems: true,
|
3177
|
+
minItems: 1,
|
3212
3178
|
description: 'This is used to exclude types with names that match one of the specified values.',
|
3213
3179
|
items: {
|
3214
3180
|
type: 'string',
|
3215
3181
|
},
|
3216
|
-
default: [],
|
3217
3182
|
},
|
3218
3183
|
suffixes: {
|
3219
3184
|
type: 'array',
|
3185
|
+
uniqueItems: true,
|
3186
|
+
minItems: 1,
|
3220
3187
|
description: 'This is used to exclude types with names with suffixes that match one of the specified values.',
|
3221
3188
|
items: {
|
3222
3189
|
type: 'string',
|
3223
3190
|
},
|
3224
|
-
default: [],
|
3225
3191
|
},
|
3226
3192
|
},
|
3227
3193
|
},
|
@@ -3297,11 +3263,11 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3297
3263
|
});
|
3298
3264
|
}
|
3299
3265
|
};
|
3300
|
-
const rule$
|
3266
|
+
const rule$m = {
|
3301
3267
|
meta: {
|
3302
3268
|
type: 'suggestion',
|
3303
3269
|
docs: {
|
3304
|
-
category: '
|
3270
|
+
category: 'Operations',
|
3305
3271
|
description: `Enforce unique fragment names across your project.`,
|
3306
3272
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
|
3307
3273
|
requiresSiblings: true,
|
@@ -3356,11 +3322,11 @@ const rule$o = {
|
|
3356
3322
|
|
3357
3323
|
const RULE_NAME$4 = 'unique-operation-name';
|
3358
3324
|
const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
|
3359
|
-
const rule$
|
3325
|
+
const rule$n = {
|
3360
3326
|
meta: {
|
3361
3327
|
type: 'suggestion',
|
3362
3328
|
docs: {
|
3363
|
-
category: '
|
3329
|
+
category: 'Operations',
|
3364
3330
|
description: `Enforce unique operation names across your project.`,
|
3365
3331
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
|
3366
3332
|
requiresSiblings: true,
|
@@ -3423,31 +3389,29 @@ const rule$p = {
|
|
3423
3389
|
const rules = {
|
3424
3390
|
...GRAPHQL_JS_VALIDATIONS,
|
3425
3391
|
alphabetize: rule,
|
3426
|
-
'
|
3427
|
-
'
|
3428
|
-
'
|
3429
|
-
'
|
3430
|
-
'
|
3431
|
-
'
|
3432
|
-
'
|
3433
|
-
'
|
3434
|
-
'no-
|
3435
|
-
'no-
|
3436
|
-
'no-
|
3437
|
-
'no-
|
3438
|
-
'no-
|
3439
|
-
'no-
|
3440
|
-
'
|
3441
|
-
'
|
3442
|
-
'require-
|
3443
|
-
'require-
|
3444
|
-
'require-
|
3445
|
-
'
|
3446
|
-
'
|
3447
|
-
'
|
3448
|
-
'
|
3449
|
-
'unique-fragment-name': rule$o,
|
3450
|
-
'unique-operation-name': rule$p,
|
3392
|
+
'description-style': rule$1,
|
3393
|
+
'input-name': rule$2,
|
3394
|
+
'match-document-filename': rule$3,
|
3395
|
+
'naming-convention': rule$4,
|
3396
|
+
'no-anonymous-operations': rule$5,
|
3397
|
+
'no-case-insensitive-enum-values-duplicates': rule$6,
|
3398
|
+
'no-deprecated': rule$7,
|
3399
|
+
'no-duplicate-fields': rule$8,
|
3400
|
+
'no-hashtag-description': rule$9,
|
3401
|
+
'no-root-type': rule$a,
|
3402
|
+
'no-scalar-result-type-on-mutation': rule$b,
|
3403
|
+
'no-typename-prefix': rule$c,
|
3404
|
+
'no-unreachable-types': rule$d,
|
3405
|
+
'no-unused-fields': rule$e,
|
3406
|
+
'require-deprecation-date': rule$f,
|
3407
|
+
'require-deprecation-reason': rule$g,
|
3408
|
+
'require-description': rule$h,
|
3409
|
+
'require-field-of-type-query-in-mutation-result': rule$i,
|
3410
|
+
'require-id-when-available': rule$j,
|
3411
|
+
'selection-set-depth': rule$k,
|
3412
|
+
'strict-id-in-types': rule$l,
|
3413
|
+
'unique-fragment-name': rule$m,
|
3414
|
+
'unique-operation-name': rule$n,
|
3451
3415
|
};
|
3452
3416
|
|
3453
3417
|
const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];
|