@graphql-eslint/eslint-plugin 3.0.0-alpha-0a66b90.0 → 3.0.0-alpha-2918431.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 +21 -0
- package/configs/schema-recommended.d.ts +42 -0
- package/docs/README.md +10 -18
- 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 +140 -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 +36 -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 +651 -724
- package/index.mjs +652 -725
- 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.mjs
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Kind, validate,
|
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,14 +12,89 @@ 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
|
19
|
-
|
20
|
-
|
23
|
+
const schemaRecommendedConfig = {
|
24
|
+
extends: ['plugin:@graphql-eslint/base'],
|
25
|
+
rules: {
|
26
|
+
'@graphql-eslint/description-style': 'error',
|
27
|
+
'@graphql-eslint/known-argument-names': 'error',
|
28
|
+
'@graphql-eslint/known-directives': 'error',
|
29
|
+
'@graphql-eslint/known-type-names': 'error',
|
30
|
+
'@graphql-eslint/lone-schema-definition': 'error',
|
31
|
+
'@graphql-eslint/naming-convention': [
|
32
|
+
'error',
|
33
|
+
{
|
34
|
+
types: 'PascalCase',
|
35
|
+
fields: 'camelCase',
|
36
|
+
EnumValueDefinition: 'UPPER_CASE',
|
37
|
+
'FieldDefinition[parent.name.value=Query]': {
|
38
|
+
forbiddenPrefixes: ['query', 'get'],
|
39
|
+
forbiddenSuffixes: ['Query'],
|
40
|
+
},
|
41
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
42
|
+
forbiddenPrefixes: ['mutation'],
|
43
|
+
forbiddenSuffixes: ['Mutation'],
|
44
|
+
},
|
45
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
46
|
+
forbiddenPrefixes: ['subscription'],
|
47
|
+
forbiddenSuffixes: ['Subscription'],
|
48
|
+
},
|
49
|
+
},
|
50
|
+
],
|
51
|
+
'@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
|
52
|
+
'@graphql-eslint/no-hashtag-description': 'error',
|
53
|
+
'@graphql-eslint/no-typename-prefix': 'error',
|
54
|
+
'@graphql-eslint/no-unreachable-types': 'error',
|
55
|
+
'@graphql-eslint/possible-type-extension': 'error',
|
56
|
+
'@graphql-eslint/provided-required-arguments': 'error',
|
57
|
+
'@graphql-eslint/require-deprecation-reason': 'error',
|
58
|
+
'@graphql-eslint/strict-id-in-types': 'error',
|
59
|
+
'@graphql-eslint/unique-directive-names': 'error',
|
60
|
+
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
61
|
+
'@graphql-eslint/unique-enum-value-names': 'error',
|
62
|
+
'@graphql-eslint/unique-field-definition-names': 'error',
|
63
|
+
'@graphql-eslint/unique-operation-types': 'error',
|
64
|
+
'@graphql-eslint/unique-type-names': 'error',
|
65
|
+
},
|
66
|
+
};
|
67
|
+
|
68
|
+
/*
|
69
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
70
|
+
*/
|
71
|
+
const schemaAllConfig = {
|
72
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/schema-recommended'],
|
73
|
+
rules: {
|
74
|
+
'@graphql-eslint/alphabetize': [
|
75
|
+
'error',
|
76
|
+
{
|
77
|
+
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
78
|
+
values: ['EnumTypeDefinition'],
|
79
|
+
arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
|
80
|
+
},
|
81
|
+
],
|
82
|
+
'@graphql-eslint/input-name': 'error',
|
83
|
+
'@graphql-eslint/no-root-type': 'off',
|
84
|
+
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
85
|
+
'@graphql-eslint/no-unused-fields': 'off',
|
86
|
+
'@graphql-eslint/require-deprecation-date': 'error',
|
87
|
+
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
88
|
+
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
89
|
+
},
|
90
|
+
};
|
91
|
+
|
92
|
+
/*
|
93
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
94
|
+
*/
|
95
|
+
const operationsRecommendedConfig = {
|
96
|
+
extends: ['plugin:@graphql-eslint/base'],
|
21
97
|
rules: {
|
22
|
-
'@graphql-eslint/avoid-typename-prefix': 'error',
|
23
98
|
'@graphql-eslint/executable-definitions': 'error',
|
24
99
|
'@graphql-eslint/fields-on-correct-type': 'error',
|
25
100
|
'@graphql-eslint/fragments-on-composite-type': 'error',
|
@@ -28,58 +103,36 @@ const recommendedConfig = {
|
|
28
103
|
'@graphql-eslint/known-fragment-names': 'error',
|
29
104
|
'@graphql-eslint/known-type-names': 'error',
|
30
105
|
'@graphql-eslint/lone-anonymous-operation': 'error',
|
31
|
-
'@graphql-eslint/lone-schema-definition': 'error',
|
32
106
|
'@graphql-eslint/naming-convention': [
|
33
107
|
'error',
|
34
108
|
{
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
},
|
44
|
-
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
45
|
-
'FieldDefinition[parent.name.value=Query]': {
|
46
|
-
forbiddenPrefixes: ['query', 'get'],
|
47
|
-
forbiddenSuffixes: ['Query'],
|
48
|
-
},
|
49
|
-
'FieldDefinition[parent.name.value=Mutation]': {
|
50
|
-
forbiddenPrefixes: ['mutation'],
|
51
|
-
forbiddenSuffixes: ['Mutation'],
|
52
|
-
},
|
53
|
-
'FieldDefinition[parent.name.value=Subscription]': {
|
54
|
-
forbiddenPrefixes: ['subscription'],
|
55
|
-
forbiddenSuffixes: ['Subscription'],
|
56
|
-
},
|
57
|
-
},
|
109
|
+
Argument: 'camelCase',
|
110
|
+
VariableDefinition: 'camelCase',
|
111
|
+
OperationDefinition: {
|
112
|
+
style: 'PascalCase',
|
113
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
114
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
115
|
+
},
|
116
|
+
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
58
117
|
},
|
59
118
|
],
|
60
119
|
'@graphql-eslint/no-anonymous-operations': 'error',
|
61
|
-
'@graphql-eslint/no-
|
120
|
+
'@graphql-eslint/no-deprecated': 'error',
|
121
|
+
'@graphql-eslint/no-duplicate-fields': 'error',
|
62
122
|
'@graphql-eslint/no-fragment-cycles': 'error',
|
63
|
-
'@graphql-eslint/no-operation-name-suffix': 'error',
|
64
123
|
'@graphql-eslint/no-undefined-variables': 'error',
|
65
124
|
'@graphql-eslint/no-unused-fragments': 'error',
|
66
125
|
'@graphql-eslint/no-unused-variables': 'error',
|
67
126
|
'@graphql-eslint/one-field-subscriptions': 'error',
|
68
127
|
'@graphql-eslint/overlapping-fields-can-be-merged': 'error',
|
69
128
|
'@graphql-eslint/possible-fragment-spread': 'error',
|
70
|
-
'@graphql-eslint/possible-type-extension': 'error',
|
71
129
|
'@graphql-eslint/provided-required-arguments': 'error',
|
72
|
-
'@graphql-eslint/require-
|
130
|
+
'@graphql-eslint/require-id-when-available': 'error',
|
73
131
|
'@graphql-eslint/scalar-leafs': 'error',
|
74
|
-
'@graphql-eslint/
|
132
|
+
'@graphql-eslint/selection-set-depth': ['error', { maxDepth: 7 }],
|
75
133
|
'@graphql-eslint/unique-argument-names': 'error',
|
76
|
-
'@graphql-eslint/unique-directive-names': 'error',
|
77
134
|
'@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
135
|
'@graphql-eslint/unique-input-field-names': 'error',
|
81
|
-
'@graphql-eslint/unique-operation-types': 'error',
|
82
|
-
'@graphql-eslint/unique-type-names': 'error',
|
83
136
|
'@graphql-eslint/unique-variable-names': 'error',
|
84
137
|
'@graphql-eslint/value-literals-of-correct-type': 'error',
|
85
138
|
'@graphql-eslint/variables-are-input-types': 'error',
|
@@ -90,44 +143,32 @@ const recommendedConfig = {
|
|
90
143
|
/*
|
91
144
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
92
145
|
*/
|
93
|
-
const
|
94
|
-
|
146
|
+
const operationsAllConfig = {
|
147
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/operations-recommended'],
|
95
148
|
rules: {
|
96
|
-
...recommendedConfig.rules,
|
97
149
|
'@graphql-eslint/alphabetize': [
|
98
150
|
'error',
|
99
151
|
{
|
100
|
-
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
101
|
-
values: ['EnumTypeDefinition'],
|
102
152
|
selections: ['OperationDefinition', 'FragmentDefinition'],
|
103
153
|
variables: ['OperationDefinition'],
|
104
|
-
arguments: ['
|
154
|
+
arguments: ['Field', 'Directive'],
|
105
155
|
},
|
106
156
|
],
|
107
|
-
'@graphql-eslint/
|
108
|
-
|
109
|
-
|
110
|
-
|
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', { types: true, overrides: { DirectiveDefinition: true } }],
|
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',
|
157
|
+
'@graphql-eslint/match-document-filename': [
|
158
|
+
'error',
|
159
|
+
{ query: 'kebab-case', mutation: 'kebab-case', subscription: 'kebab-case', fragment: 'kebab-case' },
|
160
|
+
],
|
123
161
|
'@graphql-eslint/unique-fragment-name': 'error',
|
124
162
|
'@graphql-eslint/unique-operation-name': 'error',
|
125
163
|
},
|
126
164
|
};
|
127
165
|
|
128
166
|
const configs = {
|
129
|
-
|
130
|
-
recommended:
|
167
|
+
base,
|
168
|
+
'schema-recommended': schemaRecommendedConfig,
|
169
|
+
'schema-all': schemaAllConfig,
|
170
|
+
'operations-recommended': operationsRecommendedConfig,
|
171
|
+
'operations-all': operationsAllConfig,
|
131
172
|
};
|
132
173
|
|
133
174
|
function requireSiblingsOperations(ruleName, context) {
|
@@ -340,7 +381,6 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
340
381
|
docs: {
|
341
382
|
...docs,
|
342
383
|
graphQLJSRuleName: ruleName,
|
343
|
-
category: 'Validation',
|
344
384
|
recommended: true,
|
345
385
|
requiresSchema,
|
346
386
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
@@ -377,16 +417,22 @@ const importFiles = (context) => {
|
|
377
417
|
return processImport(context.getFilename());
|
378
418
|
};
|
379
419
|
const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
|
420
|
+
category: 'Operations',
|
380
421
|
description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
|
381
422
|
}), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
|
423
|
+
category: 'Operations',
|
382
424
|
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
425
|
}), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
|
426
|
+
category: 'Operations',
|
384
427
|
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
428
|
}), validationToRule('known-argument-names', 'KnownArgumentNames', {
|
429
|
+
category: ['Schema', 'Operations'],
|
386
430
|
description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
|
387
431
|
}), validationToRule('known-directives', 'KnownDirectives', {
|
432
|
+
category: ['Schema', 'Operations'],
|
388
433
|
description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
|
389
434
|
}), validationToRule('known-fragment-names', 'KnownFragmentNames', {
|
435
|
+
category: 'Operations',
|
390
436
|
description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
|
391
437
|
examples: [
|
392
438
|
{
|
@@ -453,17 +499,23 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
453
499
|
},
|
454
500
|
],
|
455
501
|
}, importFiles), validationToRule('known-type-names', 'KnownTypeNames', {
|
502
|
+
category: ['Schema', 'Operations'],
|
456
503
|
description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
|
457
504
|
}), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
|
505
|
+
category: 'Operations',
|
458
506
|
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
507
|
}), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
|
508
|
+
category: 'Schema',
|
460
509
|
description: `A GraphQL document is only valid if it contains only one schema definition.`,
|
461
510
|
requiresSchema: false,
|
462
511
|
}), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
|
512
|
+
category: 'Operations',
|
463
513
|
description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
|
464
514
|
}), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
|
515
|
+
category: 'Operations',
|
465
516
|
description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
|
466
517
|
}, importFiles), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
|
518
|
+
category: 'Operations',
|
467
519
|
description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
|
468
520
|
requiresSiblings: true,
|
469
521
|
}, context => {
|
@@ -493,49 +545,68 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
493
545
|
};
|
494
546
|
return getParentNode(context.getFilename());
|
495
547
|
}), validationToRule('no-unused-variables', 'NoUnusedVariables', {
|
548
|
+
category: 'Operations',
|
496
549
|
description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
|
497
550
|
}, importFiles), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
|
551
|
+
category: 'Operations',
|
498
552
|
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
553
|
}), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
|
554
|
+
category: 'Operations',
|
500
555
|
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
556
|
}), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
|
557
|
+
category: 'Schema',
|
502
558
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
503
559
|
requiresSchema: false,
|
504
560
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
561
|
+
category: ['Schema', 'Operations'],
|
505
562
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
506
563
|
}), validationToRule('scalar-leafs', 'ScalarLeafs', {
|
564
|
+
category: 'Operations',
|
507
565
|
description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
|
508
566
|
}), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
|
567
|
+
category: 'Operations',
|
509
568
|
description: `A GraphQL subscription is valid only if it contains a single root field.`,
|
510
569
|
}), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
|
570
|
+
category: 'Operations',
|
511
571
|
description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
|
512
572
|
}), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
|
573
|
+
category: 'Schema',
|
513
574
|
description: `A GraphQL document is only valid if all defined directives have unique names.`,
|
514
575
|
requiresSchema: false,
|
515
576
|
}), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
|
577
|
+
category: ['Schema', 'Operations'],
|
516
578
|
description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
|
517
579
|
}), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
|
580
|
+
category: 'Schema',
|
518
581
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
|
519
582
|
requiresSchema: false,
|
520
583
|
}), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
|
584
|
+
category: 'Schema',
|
521
585
|
description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
|
522
586
|
requiresSchema: false,
|
523
587
|
}), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
|
588
|
+
category: 'Operations',
|
524
589
|
description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
|
525
590
|
requiresSchema: false,
|
526
591
|
}), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
|
592
|
+
category: 'Schema',
|
527
593
|
description: `A GraphQL document is only valid if it has only one type per operation.`,
|
528
594
|
requiresSchema: false,
|
529
595
|
}), validationToRule('unique-type-names', 'UniqueTypeNames', {
|
596
|
+
category: 'Schema',
|
530
597
|
description: `A GraphQL document is only valid if all defined types have unique names.`,
|
531
598
|
requiresSchema: false,
|
532
599
|
}), validationToRule('unique-variable-names', 'UniqueVariableNames', {
|
600
|
+
category: 'Operations',
|
533
601
|
description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
|
534
602
|
}), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
|
603
|
+
category: 'Operations',
|
535
604
|
description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
|
536
605
|
}), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
|
606
|
+
category: 'Operations',
|
537
607
|
description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
|
538
608
|
}), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
|
609
|
+
category: 'Operations',
|
539
610
|
description: `Variables passed to field arguments conform to type.`,
|
540
611
|
}));
|
541
612
|
|
@@ -561,7 +632,7 @@ const rule = {
|
|
561
632
|
meta: {
|
562
633
|
type: 'suggestion',
|
563
634
|
docs: {
|
564
|
-
category: '
|
635
|
+
category: ['Schema', 'Operations'],
|
565
636
|
description: 'Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.',
|
566
637
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/alphabetize.md',
|
567
638
|
examples: [
|
@@ -640,15 +711,22 @@ const rule = {
|
|
640
711
|
`,
|
641
712
|
},
|
642
713
|
],
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
714
|
+
configOptions: {
|
715
|
+
schema: [
|
716
|
+
{
|
717
|
+
fields: fieldsEnum,
|
718
|
+
values: valuesEnum,
|
719
|
+
arguments: argumentsEnum,
|
720
|
+
},
|
721
|
+
],
|
722
|
+
operations: [
|
723
|
+
{
|
724
|
+
selections: selectionsEnum,
|
725
|
+
variables: variablesEnum,
|
726
|
+
arguments: [Kind.FIELD, Kind.DIRECTIVE],
|
727
|
+
},
|
728
|
+
],
|
729
|
+
},
|
652
730
|
},
|
653
731
|
messages: {
|
654
732
|
[ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"',
|
@@ -786,430 +864,128 @@ const rule = {
|
|
786
864
|
},
|
787
865
|
};
|
788
866
|
|
789
|
-
const AVOID_DUPLICATE_FIELDS = 'AVOID_DUPLICATE_FIELDS';
|
790
867
|
const rule$1 = {
|
791
868
|
meta: {
|
792
869
|
type: 'suggestion',
|
793
870
|
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
871
|
examples: [
|
798
872
|
{
|
799
873
|
title: 'Incorrect',
|
874
|
+
usage: [{ style: 'inline' }],
|
800
875
|
code: /* GraphQL */ `
|
801
|
-
|
802
|
-
|
803
|
-
|
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
|
-
}
|
876
|
+
""" Description """
|
877
|
+
type someTypeName {
|
878
|
+
# ...
|
822
879
|
}
|
823
880
|
`,
|
824
881
|
},
|
825
882
|
{
|
826
|
-
title: '
|
883
|
+
title: 'Correct',
|
884
|
+
usage: [{ style: 'inline' }],
|
827
885
|
code: /* GraphQL */ `
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
) {
|
832
|
-
users(first: $first, skip: 50) {
|
833
|
-
id
|
834
|
-
}
|
886
|
+
" Description "
|
887
|
+
type someTypeName {
|
888
|
+
# ...
|
835
889
|
}
|
836
890
|
`,
|
837
891
|
},
|
838
892
|
],
|
893
|
+
description: 'Require all comments to follow the same style (either block or inline).',
|
894
|
+
category: 'Schema',
|
895
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
|
896
|
+
recommended: true,
|
839
897
|
},
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
898
|
+
schema: [
|
899
|
+
{
|
900
|
+
type: 'object',
|
901
|
+
additionalProperties: false,
|
902
|
+
properties: {
|
903
|
+
style: {
|
904
|
+
enum: ['block', 'inline'],
|
905
|
+
default: 'block',
|
906
|
+
},
|
907
|
+
},
|
908
|
+
},
|
909
|
+
],
|
844
910
|
},
|
845
911
|
create(context) {
|
846
|
-
|
847
|
-
|
912
|
+
const { style = 'block' } = context.options[0] || {};
|
913
|
+
const isBlock = style === 'block';
|
914
|
+
return {
|
915
|
+
[`.description[type=StringValue][block!=${isBlock}]`](node) {
|
848
916
|
context.report({
|
849
|
-
loc: getLocation(
|
850
|
-
|
851
|
-
}),
|
852
|
-
messageId: AVOID_DUPLICATE_FIELDS,
|
853
|
-
data: {
|
854
|
-
type,
|
855
|
-
fieldName,
|
856
|
-
},
|
917
|
+
loc: getLocation(node.loc),
|
918
|
+
message: `Unexpected ${isBlock ? 'inline' : 'block'} description`,
|
857
919
|
});
|
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
920
|
},
|
885
921
|
};
|
886
922
|
},
|
887
923
|
};
|
888
924
|
|
889
|
-
const
|
925
|
+
const isObjectType = (node) => [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
926
|
+
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
927
|
+
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
890
928
|
const rule$2 = {
|
891
929
|
meta: {
|
892
930
|
type: 'suggestion',
|
893
931
|
docs: {
|
894
|
-
description: '
|
895
|
-
category: '
|
896
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/
|
932
|
+
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.',
|
933
|
+
category: 'Schema',
|
934
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
|
897
935
|
examples: [
|
898
936
|
{
|
899
937
|
title: 'Incorrect',
|
900
|
-
usage: [{
|
938
|
+
usage: [{ checkInputType: true }],
|
901
939
|
code: /* GraphQL */ `
|
902
|
-
|
903
|
-
|
904
|
-
}
|
940
|
+
type Mutation {
|
941
|
+
SetMessage(message: InputMessage): String
|
942
|
+
}
|
943
|
+
`,
|
905
944
|
},
|
906
945
|
{
|
907
|
-
title: 'Correct',
|
908
|
-
usage: [{
|
946
|
+
title: 'Correct (with checkInputType)',
|
947
|
+
usage: [{ checkInputType: true }],
|
909
948
|
code: /* GraphQL */ `
|
910
|
-
|
911
|
-
|
912
|
-
}
|
949
|
+
type Mutation {
|
950
|
+
SetMessage(input: SetMessageInput): String
|
951
|
+
}
|
952
|
+
`,
|
953
|
+
},
|
954
|
+
{
|
955
|
+
title: 'Correct (without checkInputType)',
|
956
|
+
usage: [{ checkInputType: false }],
|
957
|
+
code: /* GraphQL */ `
|
958
|
+
type Mutation {
|
959
|
+
SetMessage(input: AnyInputTypeName): String
|
960
|
+
}
|
961
|
+
`,
|
913
962
|
},
|
914
963
|
],
|
915
964
|
},
|
916
|
-
messages: {
|
917
|
-
[AVOID_OPERATION_NAME_PREFIX]: `Forbidden operation name prefix: "{{ invalidPrefix }}"`,
|
918
|
-
},
|
919
965
|
schema: [
|
920
966
|
{
|
921
|
-
additionalProperties: false,
|
922
967
|
type: 'object',
|
923
|
-
|
968
|
+
additionalProperties: false,
|
924
969
|
properties: {
|
925
|
-
|
970
|
+
checkInputType: {
|
971
|
+
type: 'boolean',
|
926
972
|
default: false,
|
973
|
+
description: 'Check that the input type name follows the convention <mutationName>Input',
|
974
|
+
},
|
975
|
+
caseSensitiveInputType: {
|
927
976
|
type: 'boolean',
|
977
|
+
default: true,
|
978
|
+
description: 'Allow for case discrepancies in the input type name',
|
928
979
|
},
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
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
|
-
meta: {
|
1091
|
-
type: 'suggestion',
|
1092
|
-
docs: {
|
1093
|
-
examples: [
|
1094
|
-
{
|
1095
|
-
title: 'Incorrect',
|
1096
|
-
usage: [{ style: 'inline' }],
|
1097
|
-
code: /* GraphQL */ `
|
1098
|
-
""" Description """
|
1099
|
-
type someTypeName {
|
1100
|
-
# ...
|
1101
|
-
}
|
1102
|
-
`,
|
1103
|
-
},
|
1104
|
-
{
|
1105
|
-
title: 'Correct',
|
1106
|
-
usage: [{ style: 'inline' }],
|
1107
|
-
code: /* GraphQL */ `
|
1108
|
-
" Description "
|
1109
|
-
type someTypeName {
|
1110
|
-
# ...
|
1111
|
-
}
|
1112
|
-
`,
|
1113
|
-
},
|
1114
|
-
],
|
1115
|
-
description: 'Require all comments to follow the same style (either block or inline).',
|
1116
|
-
category: 'Stylistic Issues',
|
1117
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
|
1118
|
-
},
|
1119
|
-
schema: [
|
1120
|
-
{
|
1121
|
-
type: 'object',
|
1122
|
-
properties: {
|
1123
|
-
style: {
|
1124
|
-
type: 'string',
|
1125
|
-
enum: ['block', 'inline'],
|
1126
|
-
default: 'inline',
|
1127
|
-
},
|
1128
|
-
},
|
1129
|
-
additionalProperties: false,
|
1130
|
-
},
|
1131
|
-
],
|
1132
|
-
},
|
1133
|
-
create(context) {
|
1134
|
-
const { style } = context.options[0] || { style: 'inline' };
|
1135
|
-
const wrongDescriptionType = style === 'block' ? 'inline' : 'block';
|
1136
|
-
return {
|
1137
|
-
'[description.type="StringValue"]': node => {
|
1138
|
-
if (node.description.block !== (style === 'block')) {
|
1139
|
-
context.report({
|
1140
|
-
loc: getLocation(node.description.loc),
|
1141
|
-
message: `Unexpected ${wrongDescriptionType} description`,
|
1142
|
-
});
|
1143
|
-
}
|
1144
|
-
},
|
1145
|
-
};
|
1146
|
-
},
|
1147
|
-
};
|
1148
|
-
|
1149
|
-
const isObjectType = (node) => [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
1150
|
-
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
1151
|
-
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
1152
|
-
const rule$6 = {
|
1153
|
-
meta: {
|
1154
|
-
type: 'suggestion',
|
1155
|
-
docs: {
|
1156
|
-
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',
|
1158
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
|
1159
|
-
examples: [
|
1160
|
-
{
|
1161
|
-
title: 'Incorrect',
|
1162
|
-
usage: [{ checkInputType: true }],
|
1163
|
-
code: /* GraphQL */ `
|
1164
|
-
type Mutation {
|
1165
|
-
SetMessage(message: InputMessage): String
|
1166
|
-
}
|
1167
|
-
`,
|
1168
|
-
},
|
1169
|
-
{
|
1170
|
-
title: 'Correct (with checkInputType)',
|
1171
|
-
usage: [{ checkInputType: true }],
|
1172
|
-
code: /* GraphQL */ `
|
1173
|
-
type Mutation {
|
1174
|
-
SetMessage(input: SetMessageInput): String
|
1175
|
-
}
|
1176
|
-
`,
|
1177
|
-
},
|
1178
|
-
{
|
1179
|
-
title: 'Correct (without checkInputType)',
|
1180
|
-
usage: [{ checkInputType: false }],
|
1181
|
-
code: /* GraphQL */ `
|
1182
|
-
type Mutation {
|
1183
|
-
SetMessage(input: AnyInputTypeName): String
|
1184
|
-
}
|
1185
|
-
`,
|
1186
|
-
},
|
1187
|
-
],
|
1188
|
-
},
|
1189
|
-
schema: [
|
1190
|
-
{
|
1191
|
-
type: 'object',
|
1192
|
-
additionalProperties: false,
|
1193
|
-
properties: {
|
1194
|
-
checkInputType: {
|
1195
|
-
type: 'boolean',
|
1196
|
-
default: false,
|
1197
|
-
description: 'Check that the input type name follows the convention <mutationName>Input',
|
1198
|
-
},
|
1199
|
-
caseSensitiveInputType: {
|
1200
|
-
type: 'boolean',
|
1201
|
-
default: true,
|
1202
|
-
description: 'Allow for case discrepancies in the input type name',
|
1203
|
-
},
|
1204
|
-
checkQueries: {
|
1205
|
-
type: 'boolean',
|
1206
|
-
default: false,
|
1207
|
-
description: 'Apply the rule to Queries',
|
1208
|
-
},
|
1209
|
-
checkMutations: {
|
1210
|
-
type: 'boolean',
|
1211
|
-
default: true,
|
1212
|
-
description: 'Apply the rule to Mutations',
|
980
|
+
checkQueries: {
|
981
|
+
type: 'boolean',
|
982
|
+
default: false,
|
983
|
+
description: 'Apply the rule to Queries',
|
984
|
+
},
|
985
|
+
checkMutations: {
|
986
|
+
type: 'boolean',
|
987
|
+
default: true,
|
988
|
+
description: 'Apply the rule to Mutations',
|
1213
989
|
},
|
1214
990
|
},
|
1215
991
|
},
|
@@ -1275,11 +1051,11 @@ const CASE_STYLES = [
|
|
1275
1051
|
const schemaOption = {
|
1276
1052
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1277
1053
|
};
|
1278
|
-
const rule$
|
1054
|
+
const rule$3 = {
|
1279
1055
|
meta: {
|
1280
1056
|
type: 'suggestion',
|
1281
1057
|
docs: {
|
1282
|
-
category: '
|
1058
|
+
category: 'Operations',
|
1283
1059
|
description: 'This rule allows you to enforce that the file name should match the operation name.',
|
1284
1060
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/match-document-filename.md`,
|
1285
1061
|
examples: [
|
@@ -1353,6 +1129,14 @@ const rule$7 = {
|
|
1353
1129
|
`,
|
1354
1130
|
},
|
1355
1131
|
],
|
1132
|
+
configOptions: [
|
1133
|
+
{
|
1134
|
+
query: CaseStyle.kebabCase,
|
1135
|
+
mutation: CaseStyle.kebabCase,
|
1136
|
+
subscription: CaseStyle.kebabCase,
|
1137
|
+
fragment: CaseStyle.kebabCase,
|
1138
|
+
},
|
1139
|
+
],
|
1356
1140
|
},
|
1357
1141
|
messages: {
|
1358
1142
|
[MATCH_EXTENSION]: `File extension "{{ fileExtension }}" don't match extension "{{ expectedFileExtension }}"`,
|
@@ -1361,27 +1145,29 @@ const rule$7 = {
|
|
1361
1145
|
schema: {
|
1362
1146
|
definitions: {
|
1363
1147
|
asString: {
|
1364
|
-
type: 'string',
|
1365
|
-
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1366
1148
|
enum: CASE_STYLES,
|
1149
|
+
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1367
1150
|
},
|
1368
1151
|
asObject: {
|
1369
1152
|
type: 'object',
|
1153
|
+
additionalProperties: false,
|
1370
1154
|
properties: {
|
1371
1155
|
style: {
|
1372
|
-
type: 'string',
|
1373
1156
|
enum: CASE_STYLES,
|
1374
1157
|
},
|
1158
|
+
suffix: {
|
1159
|
+
type: 'string',
|
1160
|
+
},
|
1375
1161
|
},
|
1376
1162
|
},
|
1377
1163
|
},
|
1378
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
1379
1164
|
type: 'array',
|
1165
|
+
maxItems: 1,
|
1380
1166
|
items: {
|
1381
1167
|
type: 'object',
|
1168
|
+
additionalProperties: false,
|
1382
1169
|
properties: {
|
1383
1170
|
fileExtension: {
|
1384
|
-
type: 'string',
|
1385
1171
|
enum: ACCEPTED_EXTENSIONS,
|
1386
1172
|
},
|
1387
1173
|
query: schemaOption,
|
@@ -1456,13 +1242,7 @@ const rule$7 = {
|
|
1456
1242
|
},
|
1457
1243
|
};
|
1458
1244
|
|
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
|
-
];
|
1245
|
+
const FIELDS_KINDS = [Kind.FIELD_DEFINITION, Kind.INPUT_VALUE_DEFINITION, Kind.ARGUMENT, Kind.DIRECTIVE_DEFINITION];
|
1466
1246
|
const KindToDisplayName = {
|
1467
1247
|
// types
|
1468
1248
|
[Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
@@ -1474,13 +1254,13 @@ const KindToDisplayName = {
|
|
1474
1254
|
// fields
|
1475
1255
|
[Kind.FIELD_DEFINITION]: 'Field',
|
1476
1256
|
[Kind.INPUT_VALUE_DEFINITION]: 'Input property',
|
1477
|
-
[Kind.VARIABLE_DEFINITION]: 'Variable',
|
1478
1257
|
[Kind.ARGUMENT]: 'Argument',
|
1479
1258
|
[Kind.DIRECTIVE_DEFINITION]: 'Directive',
|
1480
1259
|
// rest
|
1481
1260
|
[Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
|
1482
1261
|
[Kind.OPERATION_DEFINITION]: 'Operation',
|
1483
1262
|
[Kind.FRAGMENT_DEFINITION]: 'Fragment',
|
1263
|
+
[Kind.VARIABLE_DEFINITION]: 'Variable',
|
1484
1264
|
};
|
1485
1265
|
const StyleToRegex = {
|
1486
1266
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
@@ -1493,12 +1273,12 @@ const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
|
1493
1273
|
const schemaOption$1 = {
|
1494
1274
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1495
1275
|
};
|
1496
|
-
const rule$
|
1276
|
+
const rule$4 = {
|
1497
1277
|
meta: {
|
1498
1278
|
type: 'suggestion',
|
1499
1279
|
docs: {
|
1500
1280
|
description: 'Require names to follow specified conventions.',
|
1501
|
-
category: '
|
1281
|
+
category: ['Schema', 'Operations'],
|
1502
1282
|
recommended: true,
|
1503
1283
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/naming-convention.md',
|
1504
1284
|
examples: [
|
@@ -1521,22 +1301,12 @@ const rule$8 = {
|
|
1521
1301
|
`,
|
1522
1302
|
},
|
1523
1303
|
],
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1304
|
+
configOptions: {
|
1305
|
+
schema: [
|
1306
|
+
{
|
1307
|
+
types: 'PascalCase',
|
1308
|
+
fields: 'camelCase',
|
1529
1309
|
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
1310
|
'FieldDefinition[parent.name.value=Query]': {
|
1541
1311
|
forbiddenPrefixes: ['query', 'get'],
|
1542
1312
|
forbiddenSuffixes: ['Query'],
|
@@ -1550,8 +1320,24 @@ const rule$8 = {
|
|
1550
1320
|
forbiddenSuffixes: ['Subscription'],
|
1551
1321
|
},
|
1552
1322
|
},
|
1553
|
-
|
1554
|
-
|
1323
|
+
],
|
1324
|
+
operations: [
|
1325
|
+
{
|
1326
|
+
Argument: 'camelCase',
|
1327
|
+
VariableDefinition: 'camelCase',
|
1328
|
+
OperationDefinition: {
|
1329
|
+
style: 'PascalCase',
|
1330
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1331
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1332
|
+
},
|
1333
|
+
FragmentDefinition: {
|
1334
|
+
style: 'PascalCase',
|
1335
|
+
forbiddenPrefixes: ['Fragment'],
|
1336
|
+
forbiddenSuffixes: ['Fragment'],
|
1337
|
+
},
|
1338
|
+
},
|
1339
|
+
],
|
1340
|
+
},
|
1555
1341
|
},
|
1556
1342
|
schema: {
|
1557
1343
|
definitions: {
|
@@ -1587,14 +1373,6 @@ const rule$8 = {
|
|
1587
1373
|
type: 'object',
|
1588
1374
|
additionalProperties: false,
|
1589
1375
|
properties: {
|
1590
|
-
types: {
|
1591
|
-
...schemaOption$1,
|
1592
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
|
1593
|
-
},
|
1594
|
-
fields: {
|
1595
|
-
...schemaOption$1,
|
1596
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
|
1597
|
-
},
|
1598
1376
|
allowLeadingUnderscore: {
|
1599
1377
|
type: 'boolean',
|
1600
1378
|
default: false,
|
@@ -1603,35 +1381,42 @@ const rule$8 = {
|
|
1603
1381
|
type: 'boolean',
|
1604
1382
|
default: false,
|
1605
1383
|
},
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
description: [
|
1610
|
-
'May contain the following `ASTNode` names:',
|
1611
|
-
'',
|
1612
|
-
...ALLOWED_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`),
|
1613
|
-
'',
|
1614
|
-
"> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
|
1615
|
-
'>',
|
1616
|
-
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`',
|
1617
|
-
].join('\n'),
|
1618
|
-
patternProperties: {
|
1619
|
-
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1620
|
-
},
|
1384
|
+
types: {
|
1385
|
+
...schemaOption$1,
|
1386
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1621
1387
|
},
|
1622
|
-
|
1388
|
+
fields: {
|
1389
|
+
...schemaOption$1,
|
1390
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1391
|
+
},
|
1392
|
+
...Object.fromEntries(ALLOWED_KINDS.map(kind => [
|
1393
|
+
kind,
|
1394
|
+
{
|
1395
|
+
...schemaOption$1,
|
1396
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
1397
|
+
},
|
1398
|
+
])),
|
1399
|
+
},
|
1400
|
+
patternProperties: {
|
1401
|
+
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1402
|
+
},
|
1403
|
+
description: [
|
1404
|
+
"> It's possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with allowed `ASTNode` names which are described below.",
|
1405
|
+
'>',
|
1406
|
+
'> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.',
|
1407
|
+
'>',
|
1408
|
+
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`.',
|
1409
|
+
].join('\n'),
|
1623
1410
|
},
|
1624
1411
|
},
|
1625
1412
|
},
|
1626
1413
|
create(context) {
|
1627
|
-
const options = {
|
1628
|
-
|
1629
|
-
...context.options[0],
|
1630
|
-
};
|
1414
|
+
const options = context.options[0] || {};
|
1415
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, fields, ...restOptions } = options;
|
1631
1416
|
function normalisePropertyOption(kind) {
|
1632
|
-
let style = options
|
1417
|
+
let style = options[kind];
|
1633
1418
|
if (!style) {
|
1634
|
-
style = TYPES_KINDS.includes(kind) ?
|
1419
|
+
style = TYPES_KINDS.includes(kind) ? types : fields;
|
1635
1420
|
}
|
1636
1421
|
return typeof style === 'object' ? style : { style };
|
1637
1422
|
}
|
@@ -1652,10 +1437,10 @@ const rule$8 = {
|
|
1652
1437
|
}
|
1653
1438
|
function getErrorMessage() {
|
1654
1439
|
let name = nodeName;
|
1655
|
-
if (
|
1440
|
+
if (allowLeadingUnderscore) {
|
1656
1441
|
name = name.replace(/^_*/, '');
|
1657
1442
|
}
|
1658
|
-
if (
|
1443
|
+
if (allowTrailingUnderscore) {
|
1659
1444
|
name = name.replace(/_*$/, '');
|
1660
1445
|
}
|
1661
1446
|
if (prefix && !name.startsWith(prefix)) {
|
@@ -1689,15 +1474,13 @@ const rule$8 = {
|
|
1689
1474
|
});
|
1690
1475
|
};
|
1691
1476
|
const listeners = {};
|
1692
|
-
if (!
|
1477
|
+
if (!allowLeadingUnderscore) {
|
1693
1478
|
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1694
1479
|
}
|
1695
|
-
if (!
|
1480
|
+
if (!allowTrailingUnderscore) {
|
1696
1481
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1697
1482
|
}
|
1698
|
-
const selectors = new Set([
|
1699
|
-
.flat()
|
1700
|
-
.filter(Boolean));
|
1483
|
+
const selectors = new Set([types && TYPES_KINDS, fields && FIELDS_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1701
1484
|
for (const selector of selectors) {
|
1702
1485
|
listeners[selector] = checkNode(selector);
|
1703
1486
|
}
|
@@ -1706,11 +1489,11 @@ const rule$8 = {
|
|
1706
1489
|
};
|
1707
1490
|
|
1708
1491
|
const NO_ANONYMOUS_OPERATIONS = 'NO_ANONYMOUS_OPERATIONS';
|
1709
|
-
const rule$
|
1492
|
+
const rule$5 = {
|
1710
1493
|
meta: {
|
1711
1494
|
type: 'suggestion',
|
1712
1495
|
docs: {
|
1713
|
-
category: '
|
1496
|
+
category: 'Operations',
|
1714
1497
|
description: 'Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.',
|
1715
1498
|
recommended: true,
|
1716
1499
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-anonymous-operations.md',
|
@@ -1754,12 +1537,12 @@ const rule$9 = {
|
|
1754
1537
|
};
|
1755
1538
|
|
1756
1539
|
const ERROR_MESSAGE_ID = 'NO_CASE_INSENSITIVE_ENUM_VALUES_DUPLICATES';
|
1757
|
-
const rule$
|
1540
|
+
const rule$6 = {
|
1758
1541
|
meta: {
|
1759
1542
|
type: 'suggestion',
|
1760
1543
|
docs: {
|
1761
1544
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-case-insensitive-enum-values-duplicates.md',
|
1762
|
-
category: '
|
1545
|
+
category: 'Schema',
|
1763
1546
|
recommended: true,
|
1764
1547
|
description: 'Disallow case-insensitive enum values duplicates.',
|
1765
1548
|
examples: [
|
@@ -1810,11 +1593,11 @@ const rule$a = {
|
|
1810
1593
|
};
|
1811
1594
|
|
1812
1595
|
const NO_DEPRECATED = 'NO_DEPRECATED';
|
1813
|
-
const rule$
|
1596
|
+
const rule$7 = {
|
1814
1597
|
meta: {
|
1815
1598
|
type: 'suggestion',
|
1816
1599
|
docs: {
|
1817
|
-
category: '
|
1600
|
+
category: 'Operations',
|
1818
1601
|
description: `Enforce that deprecated fields or enum values are not in use by operations.`,
|
1819
1602
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-deprecated.md`,
|
1820
1603
|
requiresSchema: true,
|
@@ -1877,48 +1660,150 @@ const rule$b = {
|
|
1877
1660
|
fullName
|
1878
1661
|
}
|
1879
1662
|
}
|
1880
|
-
`,
|
1881
|
-
},
|
1882
|
-
],
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1663
|
+
`,
|
1664
|
+
},
|
1665
|
+
],
|
1666
|
+
recommended: true,
|
1667
|
+
},
|
1668
|
+
messages: {
|
1669
|
+
[NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
|
1670
|
+
},
|
1671
|
+
schema: [],
|
1672
|
+
},
|
1673
|
+
create(context) {
|
1674
|
+
return {
|
1675
|
+
EnumValue(node) {
|
1676
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1677
|
+
const typeInfo = node.typeInfo();
|
1678
|
+
if (typeInfo && typeInfo.enumValue) {
|
1679
|
+
if (typeInfo.enumValue.deprecationReason) {
|
1680
|
+
const enumValueName = node.value;
|
1681
|
+
context.report({
|
1682
|
+
loc: getLocation(node.loc, enumValueName),
|
1683
|
+
messageId: NO_DEPRECATED,
|
1684
|
+
data: {
|
1685
|
+
type: 'enum value',
|
1686
|
+
reason: typeInfo.enumValue.deprecationReason ? `(reason: ${typeInfo.enumValue.deprecationReason})` : '',
|
1687
|
+
},
|
1688
|
+
});
|
1689
|
+
}
|
1690
|
+
}
|
1691
|
+
},
|
1692
|
+
Field(node) {
|
1693
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1694
|
+
const typeInfo = node.typeInfo();
|
1695
|
+
if (typeInfo && typeInfo.fieldDef) {
|
1696
|
+
if (typeInfo.fieldDef.deprecationReason) {
|
1697
|
+
const fieldName = node.name.value;
|
1698
|
+
context.report({
|
1699
|
+
loc: getLocation(node.loc, fieldName),
|
1700
|
+
messageId: NO_DEPRECATED,
|
1701
|
+
data: {
|
1702
|
+
type: 'field',
|
1703
|
+
reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
|
1704
|
+
},
|
1705
|
+
});
|
1706
|
+
}
|
1707
|
+
}
|
1708
|
+
},
|
1709
|
+
};
|
1710
|
+
},
|
1711
|
+
};
|
1712
|
+
|
1713
|
+
const NO_DUPLICATE_FIELDS = 'NO_DUPLICATE_FIELDS';
|
1714
|
+
const rule$8 = {
|
1715
|
+
meta: {
|
1716
|
+
type: 'suggestion',
|
1717
|
+
docs: {
|
1718
|
+
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
1719
|
+
category: 'Operations',
|
1720
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-duplicate-fields.md',
|
1721
|
+
recommended: true,
|
1722
|
+
examples: [
|
1723
|
+
{
|
1724
|
+
title: 'Incorrect',
|
1725
|
+
code: /* GraphQL */ `
|
1726
|
+
query {
|
1727
|
+
user {
|
1728
|
+
name
|
1729
|
+
email
|
1730
|
+
name # duplicate field
|
1731
|
+
}
|
1732
|
+
}
|
1733
|
+
`,
|
1734
|
+
},
|
1735
|
+
{
|
1736
|
+
title: 'Incorrect',
|
1737
|
+
code: /* GraphQL */ `
|
1738
|
+
query {
|
1739
|
+
users(
|
1740
|
+
first: 100
|
1741
|
+
skip: 50
|
1742
|
+
after: "cji629tngfgou0b73kt7vi5jo"
|
1743
|
+
first: 100 # duplicate argument
|
1744
|
+
) {
|
1745
|
+
id
|
1746
|
+
}
|
1747
|
+
}
|
1748
|
+
`,
|
1749
|
+
},
|
1750
|
+
{
|
1751
|
+
title: 'Incorrect',
|
1752
|
+
code: /* GraphQL */ `
|
1753
|
+
query (
|
1754
|
+
$first: Int!
|
1755
|
+
$first: Int! # duplicate variable
|
1756
|
+
) {
|
1757
|
+
users(first: $first, skip: 50) {
|
1758
|
+
id
|
1759
|
+
}
|
1760
|
+
}
|
1761
|
+
`,
|
1762
|
+
},
|
1763
|
+
],
|
1764
|
+
},
|
1765
|
+
messages: {
|
1766
|
+
[NO_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
|
1767
|
+
},
|
1768
|
+
schema: [],
|
1769
|
+
},
|
1770
|
+
create(context) {
|
1771
|
+
function checkNode(usedFields, fieldName, type, node) {
|
1772
|
+
if (usedFields.has(fieldName)) {
|
1773
|
+
context.report({
|
1774
|
+
loc: getLocation((node.kind === Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
|
1775
|
+
offsetEnd: node.kind === Kind.VARIABLE_DEFINITION ? 0 : 1,
|
1776
|
+
}),
|
1777
|
+
messageId: NO_DUPLICATE_FIELDS,
|
1778
|
+
data: {
|
1779
|
+
type,
|
1780
|
+
fieldName,
|
1781
|
+
},
|
1782
|
+
});
|
1783
|
+
}
|
1784
|
+
else {
|
1785
|
+
usedFields.add(fieldName);
|
1786
|
+
}
|
1787
|
+
}
|
1890
1788
|
return {
|
1891
|
-
|
1892
|
-
|
1893
|
-
const
|
1894
|
-
|
1895
|
-
if (typeInfo.enumValue.deprecationReason) {
|
1896
|
-
const enumValueName = node.value;
|
1897
|
-
context.report({
|
1898
|
-
loc: getLocation(node.loc, enumValueName),
|
1899
|
-
messageId: NO_DEPRECATED,
|
1900
|
-
data: {
|
1901
|
-
type: 'enum value',
|
1902
|
-
reason: typeInfo.enumValue.deprecationReason ? `(reason: ${typeInfo.enumValue.deprecationReason})` : '',
|
1903
|
-
},
|
1904
|
-
});
|
1905
|
-
}
|
1789
|
+
OperationDefinition(node) {
|
1790
|
+
const set = new Set();
|
1791
|
+
for (const varDef of node.variableDefinitions) {
|
1792
|
+
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
1906
1793
|
}
|
1907
1794
|
},
|
1908
1795
|
Field(node) {
|
1909
|
-
|
1910
|
-
const
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
},
|
1921
|
-
});
|
1796
|
+
const set = new Set();
|
1797
|
+
for (const arg of node.arguments) {
|
1798
|
+
checkNode(set, arg.name.value, 'Field argument', arg);
|
1799
|
+
}
|
1800
|
+
},
|
1801
|
+
SelectionSet(node) {
|
1802
|
+
var _a;
|
1803
|
+
const set = new Set();
|
1804
|
+
for (const selection of node.selections) {
|
1805
|
+
if (selection.kind === Kind.FIELD) {
|
1806
|
+
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
1922
1807
|
}
|
1923
1808
|
}
|
1924
1809
|
},
|
@@ -1927,14 +1812,14 @@ const rule$b = {
|
|
1927
1812
|
};
|
1928
1813
|
|
1929
1814
|
const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
|
1930
|
-
const rule$
|
1815
|
+
const rule$9 = {
|
1931
1816
|
meta: {
|
1932
1817
|
messages: {
|
1933
1818
|
[HASHTAG_COMMENT]: 'Using hashtag (#) for adding GraphQL descriptions is not allowed. Prefer using """ for multiline, or " for a single line description.',
|
1934
1819
|
},
|
1935
1820
|
docs: {
|
1936
1821
|
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: '
|
1822
|
+
category: 'Schema',
|
1938
1823
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
|
1939
1824
|
examples: [
|
1940
1825
|
{
|
@@ -1971,6 +1856,7 @@ const rule$c = {
|
|
1971
1856
|
`,
|
1972
1857
|
},
|
1973
1858
|
],
|
1859
|
+
recommended: true,
|
1974
1860
|
},
|
1975
1861
|
type: 'suggestion',
|
1976
1862
|
schema: [],
|
@@ -1999,85 +1885,18 @@ const rule$c = {
|
|
1999
1885
|
},
|
2000
1886
|
};
|
2001
1887
|
|
2002
|
-
const
|
2003
|
-
const rule$
|
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
|
-
const ROOT_TYPES = ['query', 'mutation', 'subscription'];
|
2070
|
-
const rule$e = {
|
1888
|
+
const ROOT_TYPES = ['mutation', 'subscription'];
|
1889
|
+
const rule$a = {
|
2071
1890
|
meta: {
|
2072
1891
|
type: 'suggestion',
|
2073
1892
|
docs: {
|
2074
|
-
category: '
|
2075
|
-
description: 'Disallow using root types
|
1893
|
+
category: 'Schema',
|
1894
|
+
description: 'Disallow using root types `mutation` and/or `subscription`.',
|
2076
1895
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
|
2077
1896
|
requiresSchema: true,
|
2078
1897
|
examples: [
|
2079
1898
|
{
|
2080
|
-
title: 'Incorrect
|
1899
|
+
title: 'Incorrect',
|
2081
1900
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2082
1901
|
code: /* GraphQL */ `
|
2083
1902
|
type Mutation {
|
@@ -2086,16 +1905,7 @@ const rule$e = {
|
|
2086
1905
|
`,
|
2087
1906
|
},
|
2088
1907
|
{
|
2089
|
-
title: '
|
2090
|
-
usage: [{ disallow: ['query'] }],
|
2091
|
-
code: /* GraphQL */ `
|
2092
|
-
type Query {
|
2093
|
-
users: [User!]!
|
2094
|
-
}
|
2095
|
-
`,
|
2096
|
-
},
|
2097
|
-
{
|
2098
|
-
title: 'Correct (`read-only` schema)',
|
1908
|
+
title: 'Correct',
|
2099
1909
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2100
1910
|
code: /* GraphQL */ `
|
2101
1911
|
type Query {
|
@@ -2104,7 +1914,6 @@ const rule$e = {
|
|
2104
1914
|
`,
|
2105
1915
|
},
|
2106
1916
|
],
|
2107
|
-
optionsForConfig: [{ disallow: ['subscription'] }],
|
2108
1917
|
},
|
2109
1918
|
schema: {
|
2110
1919
|
type: 'array',
|
@@ -2131,7 +1940,6 @@ const rule$e = {
|
|
2131
1940
|
const schema = requireGraphQLSchemaFromContext('no-root-type', context);
|
2132
1941
|
const disallow = new Set(context.options[0].disallow);
|
2133
1942
|
const rootTypeNames = [
|
2134
|
-
disallow.has('query') && schema.getQueryType(),
|
2135
1943
|
disallow.has('mutation') && schema.getMutationType(),
|
2136
1944
|
disallow.has('subscription') && schema.getSubscriptionType(),
|
2137
1945
|
]
|
@@ -2157,16 +1965,128 @@ const rule$e = {
|
|
2157
1965
|
},
|
2158
1966
|
};
|
2159
1967
|
|
1968
|
+
const rule$b = {
|
1969
|
+
meta: {
|
1970
|
+
type: 'suggestion',
|
1971
|
+
docs: {
|
1972
|
+
category: 'Schema',
|
1973
|
+
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
1974
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-scalar-result-type-on-mutation.md',
|
1975
|
+
requiresSchema: true,
|
1976
|
+
examples: [
|
1977
|
+
{
|
1978
|
+
title: 'Incorrect',
|
1979
|
+
code: /* GraphQL */ `
|
1980
|
+
type Mutation {
|
1981
|
+
createUser: Boolean
|
1982
|
+
}
|
1983
|
+
`,
|
1984
|
+
},
|
1985
|
+
{
|
1986
|
+
title: 'Correct',
|
1987
|
+
code: /* GraphQL */ `
|
1988
|
+
type Mutation {
|
1989
|
+
createUser: User!
|
1990
|
+
}
|
1991
|
+
`,
|
1992
|
+
},
|
1993
|
+
],
|
1994
|
+
},
|
1995
|
+
schema: [],
|
1996
|
+
},
|
1997
|
+
create(context) {
|
1998
|
+
const schema = requireGraphQLSchemaFromContext('no-scalar-result-type-on-mutation', context);
|
1999
|
+
const mutationType = schema.getMutationType();
|
2000
|
+
if (!mutationType) {
|
2001
|
+
return {};
|
2002
|
+
}
|
2003
|
+
const selector = [
|
2004
|
+
`:matches(${Kind.OBJECT_TYPE_DEFINITION}, ${Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
2005
|
+
'>',
|
2006
|
+
Kind.FIELD_DEFINITION,
|
2007
|
+
Kind.NAMED_TYPE,
|
2008
|
+
].join(' ');
|
2009
|
+
return {
|
2010
|
+
[selector](node) {
|
2011
|
+
const typeName = node.name.value;
|
2012
|
+
const graphQLType = schema.getType(typeName);
|
2013
|
+
if (isScalarType(graphQLType)) {
|
2014
|
+
context.report({
|
2015
|
+
loc: getLocation(node.loc, typeName),
|
2016
|
+
message: `Unexpected scalar result type "${typeName}"`,
|
2017
|
+
});
|
2018
|
+
}
|
2019
|
+
},
|
2020
|
+
};
|
2021
|
+
},
|
2022
|
+
};
|
2023
|
+
|
2024
|
+
const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
|
2025
|
+
const rule$c = {
|
2026
|
+
meta: {
|
2027
|
+
type: 'suggestion',
|
2028
|
+
docs: {
|
2029
|
+
category: 'Schema',
|
2030
|
+
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
2031
|
+
recommended: true,
|
2032
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
|
2033
|
+
examples: [
|
2034
|
+
{
|
2035
|
+
title: 'Incorrect',
|
2036
|
+
code: /* GraphQL */ `
|
2037
|
+
type User {
|
2038
|
+
userId: ID!
|
2039
|
+
}
|
2040
|
+
`,
|
2041
|
+
},
|
2042
|
+
{
|
2043
|
+
title: 'Correct',
|
2044
|
+
code: /* GraphQL */ `
|
2045
|
+
type User {
|
2046
|
+
id: ID!
|
2047
|
+
}
|
2048
|
+
`,
|
2049
|
+
},
|
2050
|
+
],
|
2051
|
+
},
|
2052
|
+
messages: {
|
2053
|
+
[NO_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
2054
|
+
},
|
2055
|
+
schema: [],
|
2056
|
+
},
|
2057
|
+
create(context) {
|
2058
|
+
return {
|
2059
|
+
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
2060
|
+
const typeName = node.name.value;
|
2061
|
+
const lowerTypeName = typeName.toLowerCase();
|
2062
|
+
for (const field of node.fields) {
|
2063
|
+
const fieldName = field.name.value;
|
2064
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
2065
|
+
context.report({
|
2066
|
+
data: {
|
2067
|
+
fieldName,
|
2068
|
+
typeName,
|
2069
|
+
},
|
2070
|
+
messageId: NO_TYPENAME_PREFIX,
|
2071
|
+
loc: getLocation(field.loc, lowerTypeName),
|
2072
|
+
});
|
2073
|
+
}
|
2074
|
+
}
|
2075
|
+
},
|
2076
|
+
};
|
2077
|
+
},
|
2078
|
+
};
|
2079
|
+
|
2160
2080
|
const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
|
2161
2081
|
const RULE_NAME = 'no-unreachable-types';
|
2162
|
-
const rule$
|
2082
|
+
const rule$d = {
|
2163
2083
|
meta: {
|
2164
2084
|
messages: {
|
2165
|
-
[UNREACHABLE_TYPE]:
|
2085
|
+
[UNREACHABLE_TYPE]: 'Type "{{ typeName }}" is unreachable',
|
2166
2086
|
},
|
2167
2087
|
docs: {
|
2168
2088
|
description: `Requires all types to be reachable at some level by root level fields.`,
|
2169
|
-
category: '
|
2089
|
+
category: 'Schema',
|
2170
2090
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
|
2171
2091
|
requiresSchema: true,
|
2172
2092
|
examples: [
|
@@ -2197,6 +2117,7 @@ const rule$f = {
|
|
2197
2117
|
`,
|
2198
2118
|
},
|
2199
2119
|
],
|
2120
|
+
recommended: true,
|
2200
2121
|
},
|
2201
2122
|
fixable: 'code',
|
2202
2123
|
type: 'suggestion',
|
@@ -2235,14 +2156,14 @@ const rule$f = {
|
|
2235
2156
|
|
2236
2157
|
const UNUSED_FIELD = 'UNUSED_FIELD';
|
2237
2158
|
const RULE_NAME$1 = 'no-unused-fields';
|
2238
|
-
const rule$
|
2159
|
+
const rule$e = {
|
2239
2160
|
meta: {
|
2240
2161
|
messages: {
|
2241
2162
|
[UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
|
2242
2163
|
},
|
2243
2164
|
docs: {
|
2244
2165
|
description: `Requires all fields to be used at some level by siblings operations.`,
|
2245
|
-
category: '
|
2166
|
+
category: 'Schema',
|
2246
2167
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
|
2247
2168
|
requiresSiblings: true,
|
2248
2169
|
requiresSchema: true,
|
@@ -2424,11 +2345,11 @@ const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
|
2424
2345
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
2425
2346
|
const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
|
2426
2347
|
const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
|
2427
|
-
const rule$
|
2348
|
+
const rule$f = {
|
2428
2349
|
meta: {
|
2429
2350
|
type: 'suggestion',
|
2430
2351
|
docs: {
|
2431
|
-
category: '
|
2352
|
+
category: 'Schema',
|
2432
2353
|
description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
|
2433
2354
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-date.md',
|
2434
2355
|
examples: [
|
@@ -2527,11 +2448,11 @@ const rule$h = {
|
|
2527
2448
|
},
|
2528
2449
|
};
|
2529
2450
|
|
2530
|
-
const rule$
|
2451
|
+
const rule$g = {
|
2531
2452
|
meta: {
|
2532
2453
|
docs: {
|
2533
2454
|
description: `Require all deprecation directives to specify a reason.`,
|
2534
|
-
category: '
|
2455
|
+
category: 'Schema',
|
2535
2456
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-reason.md`,
|
2536
2457
|
recommended: true,
|
2537
2458
|
examples: [
|
@@ -2589,16 +2510,16 @@ const ALLOWED_KINDS$1 = [
|
|
2589
2510
|
Kind.ENUM_VALUE_DEFINITION,
|
2590
2511
|
Kind.DIRECTIVE_DEFINITION,
|
2591
2512
|
];
|
2592
|
-
const rule$
|
2513
|
+
const rule$h = {
|
2593
2514
|
meta: {
|
2594
2515
|
docs: {
|
2595
|
-
category: '
|
2516
|
+
category: 'Schema',
|
2596
2517
|
description: 'Enforce descriptions in your type definitions.',
|
2597
2518
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md',
|
2598
2519
|
examples: [
|
2599
2520
|
{
|
2600
2521
|
title: 'Incorrect',
|
2601
|
-
usage: [{ types: true,
|
2522
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2602
2523
|
code: /* GraphQL */ `
|
2603
2524
|
type someTypeName {
|
2604
2525
|
name: String
|
@@ -2607,7 +2528,7 @@ const rule$j = {
|
|
2607
2528
|
},
|
2608
2529
|
{
|
2609
2530
|
title: 'Correct',
|
2610
|
-
usage: [{ types: true,
|
2531
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2611
2532
|
code: /* GraphQL */ `
|
2612
2533
|
"""
|
2613
2534
|
Some type description
|
@@ -2621,12 +2542,10 @@ const rule$j = {
|
|
2621
2542
|
`,
|
2622
2543
|
},
|
2623
2544
|
],
|
2624
|
-
|
2545
|
+
configOptions: [
|
2625
2546
|
{
|
2626
2547
|
types: true,
|
2627
|
-
|
2628
|
-
[Kind.DIRECTIVE_DEFINITION]: true,
|
2629
|
-
},
|
2548
|
+
[Kind.DIRECTIVE_DEFINITION]: true,
|
2630
2549
|
},
|
2631
2550
|
],
|
2632
2551
|
},
|
@@ -2645,22 +2564,23 @@ const rule$j = {
|
|
2645
2564
|
properties: {
|
2646
2565
|
types: {
|
2647
2566
|
type: 'boolean',
|
2648
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `-
|
2649
|
-
},
|
2650
|
-
overrides: {
|
2651
|
-
type: 'object',
|
2652
|
-
description: 'Configuration for precise `ASTNode`',
|
2653
|
-
additionalProperties: false,
|
2654
|
-
properties: Object.fromEntries(ALLOWED_KINDS$1.map(kind => [kind, { type: 'boolean' }])),
|
2567
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
2655
2568
|
},
|
2569
|
+
...Object.fromEntries([...ALLOWED_KINDS$1].sort().map(kind => [
|
2570
|
+
kind,
|
2571
|
+
{
|
2572
|
+
type: 'boolean',
|
2573
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
2574
|
+
},
|
2575
|
+
])),
|
2656
2576
|
},
|
2657
2577
|
},
|
2658
2578
|
},
|
2659
2579
|
},
|
2660
2580
|
create(context) {
|
2661
|
-
const { types,
|
2581
|
+
const { types, ...restOptions } = context.options[0];
|
2662
2582
|
const kinds = new Set(types ? TYPES_KINDS : []);
|
2663
|
-
for (const [kind, isEnabled] of Object.entries(
|
2583
|
+
for (const [kind, isEnabled] of Object.entries(restOptions)) {
|
2664
2584
|
if (isEnabled) {
|
2665
2585
|
kinds.add(kind);
|
2666
2586
|
}
|
@@ -2688,11 +2608,11 @@ const rule$j = {
|
|
2688
2608
|
};
|
2689
2609
|
|
2690
2610
|
const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
|
2691
|
-
const rule$
|
2611
|
+
const rule$i = {
|
2692
2612
|
meta: {
|
2693
2613
|
type: 'suggestion',
|
2694
2614
|
docs: {
|
2695
|
-
category: '
|
2615
|
+
category: 'Schema',
|
2696
2616
|
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`.',
|
2697
2617
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
|
2698
2618
|
requiresSchema: true,
|
@@ -2856,13 +2776,13 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2856
2776
|
|
2857
2777
|
const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2858
2778
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2859
|
-
const rule$
|
2779
|
+
const rule$j = {
|
2860
2780
|
meta: {
|
2861
2781
|
type: 'suggestion',
|
2862
2782
|
docs: {
|
2863
|
-
category: '
|
2864
|
-
description:
|
2865
|
-
url:
|
2783
|
+
category: 'Operations',
|
2784
|
+
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2785
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
|
2866
2786
|
requiresSchema: true,
|
2867
2787
|
requiresSiblings: true,
|
2868
2788
|
examples: [
|
@@ -2902,17 +2822,17 @@ const rule$l = {
|
|
2902
2822
|
`,
|
2903
2823
|
},
|
2904
2824
|
],
|
2825
|
+
recommended: true,
|
2905
2826
|
},
|
2906
2827
|
messages: {
|
2907
|
-
[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 }}".`,
|
2828
|
+
[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 }}".`,
|
2908
2829
|
},
|
2909
2830
|
schema: {
|
2910
2831
|
type: 'array',
|
2911
|
-
additionalItems: false,
|
2912
|
-
minItems: 0,
|
2913
2832
|
maxItems: 1,
|
2914
2833
|
items: {
|
2915
2834
|
type: 'object',
|
2835
|
+
additionalProperties: false,
|
2916
2836
|
properties: {
|
2917
2837
|
fieldName: {
|
2918
2838
|
type: 'string',
|
@@ -2992,12 +2912,12 @@ const rule$l = {
|
|
2992
2912
|
},
|
2993
2913
|
};
|
2994
2914
|
|
2995
|
-
const rule$
|
2915
|
+
const rule$k = {
|
2996
2916
|
meta: {
|
2997
2917
|
docs: {
|
2998
|
-
category: '
|
2918
|
+
category: 'Operations',
|
2999
2919
|
description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
|
3000
|
-
url:
|
2920
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
|
3001
2921
|
requiresSiblings: true,
|
3002
2922
|
examples: [
|
3003
2923
|
{
|
@@ -3040,22 +2960,26 @@ const rule$m = {
|
|
3040
2960
|
`,
|
3041
2961
|
},
|
3042
2962
|
],
|
2963
|
+
recommended: true,
|
2964
|
+
configOptions: [{ maxDepth: 7 }],
|
3043
2965
|
},
|
3044
2966
|
type: 'suggestion',
|
3045
2967
|
schema: {
|
3046
2968
|
type: 'array',
|
3047
|
-
additionalItems: false,
|
3048
2969
|
minItems: 1,
|
3049
2970
|
maxItems: 1,
|
3050
2971
|
items: {
|
3051
2972
|
type: 'object',
|
3052
|
-
|
2973
|
+
additionalProperties: false,
|
2974
|
+
required: ['maxDepth'],
|
3053
2975
|
properties: {
|
3054
2976
|
maxDepth: {
|
3055
2977
|
type: 'number',
|
3056
2978
|
},
|
3057
2979
|
ignore: {
|
3058
2980
|
type: 'array',
|
2981
|
+
uniqueItems: true,
|
2982
|
+
minItems: 1,
|
3059
2983
|
items: {
|
3060
2984
|
type: 'string',
|
3061
2985
|
},
|
@@ -3114,12 +3038,12 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
|
|
3114
3038
|
}
|
3115
3039
|
return false;
|
3116
3040
|
};
|
3117
|
-
const rule$
|
3041
|
+
const rule$l = {
|
3118
3042
|
meta: {
|
3119
3043
|
type: 'suggestion',
|
3120
3044
|
docs: {
|
3121
3045
|
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.',
|
3122
|
-
category: '
|
3046
|
+
category: 'Schema',
|
3123
3047
|
recommended: true,
|
3124
3048
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
|
3125
3049
|
examples: [
|
@@ -3179,13 +3103,15 @@ const rule$n = {
|
|
3179
3103
|
],
|
3180
3104
|
},
|
3181
3105
|
schema: {
|
3182
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
3183
3106
|
type: 'array',
|
3107
|
+
maxItems: 1,
|
3184
3108
|
items: {
|
3185
3109
|
type: 'object',
|
3110
|
+
additionalProperties: false,
|
3186
3111
|
properties: {
|
3187
3112
|
acceptedIdNames: {
|
3188
3113
|
type: 'array',
|
3114
|
+
uniqueItems: true,
|
3189
3115
|
items: {
|
3190
3116
|
type: 'string',
|
3191
3117
|
},
|
@@ -3193,6 +3119,7 @@ const rule$n = {
|
|
3193
3119
|
},
|
3194
3120
|
acceptedIdTypes: {
|
3195
3121
|
type: 'array',
|
3122
|
+
uniqueItems: true,
|
3196
3123
|
items: {
|
3197
3124
|
type: 'string',
|
3198
3125
|
},
|
@@ -3203,19 +3130,21 @@ const rule$n = {
|
|
3203
3130
|
properties: {
|
3204
3131
|
types: {
|
3205
3132
|
type: 'array',
|
3133
|
+
uniqueItems: true,
|
3134
|
+
minItems: 1,
|
3206
3135
|
description: 'This is used to exclude types with names that match one of the specified values.',
|
3207
3136
|
items: {
|
3208
3137
|
type: 'string',
|
3209
3138
|
},
|
3210
|
-
default: [],
|
3211
3139
|
},
|
3212
3140
|
suffixes: {
|
3213
3141
|
type: 'array',
|
3142
|
+
uniqueItems: true,
|
3143
|
+
minItems: 1,
|
3214
3144
|
description: 'This is used to exclude types with names with suffixes that match one of the specified values.',
|
3215
3145
|
items: {
|
3216
3146
|
type: 'string',
|
3217
3147
|
},
|
3218
|
-
default: [],
|
3219
3148
|
},
|
3220
3149
|
},
|
3221
3150
|
},
|
@@ -3291,11 +3220,11 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3291
3220
|
});
|
3292
3221
|
}
|
3293
3222
|
};
|
3294
|
-
const rule$
|
3223
|
+
const rule$m = {
|
3295
3224
|
meta: {
|
3296
3225
|
type: 'suggestion',
|
3297
3226
|
docs: {
|
3298
|
-
category: '
|
3227
|
+
category: 'Operations',
|
3299
3228
|
description: `Enforce unique fragment names across your project.`,
|
3300
3229
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
|
3301
3230
|
requiresSiblings: true,
|
@@ -3350,11 +3279,11 @@ const rule$o = {
|
|
3350
3279
|
|
3351
3280
|
const RULE_NAME$4 = 'unique-operation-name';
|
3352
3281
|
const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
|
3353
|
-
const rule$
|
3282
|
+
const rule$n = {
|
3354
3283
|
meta: {
|
3355
3284
|
type: 'suggestion',
|
3356
3285
|
docs: {
|
3357
|
-
category: '
|
3286
|
+
category: 'Operations',
|
3358
3287
|
description: `Enforce unique operation names across your project.`,
|
3359
3288
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
|
3360
3289
|
requiresSiblings: true,
|
@@ -3417,31 +3346,29 @@ const rule$p = {
|
|
3417
3346
|
const rules = {
|
3418
3347
|
...GRAPHQL_JS_VALIDATIONS,
|
3419
3348
|
alphabetize: rule,
|
3420
|
-
'
|
3421
|
-
'
|
3422
|
-
'
|
3423
|
-
'
|
3424
|
-
'
|
3425
|
-
'
|
3426
|
-
'
|
3427
|
-
'
|
3428
|
-
'no-
|
3429
|
-
'no-
|
3430
|
-
'no-
|
3431
|
-
'no-
|
3432
|
-
'no-
|
3433
|
-
'no-
|
3434
|
-
'
|
3435
|
-
'
|
3436
|
-
'require-
|
3437
|
-
'require-
|
3438
|
-
'require-
|
3439
|
-
'
|
3440
|
-
'
|
3441
|
-
'
|
3442
|
-
'
|
3443
|
-
'unique-fragment-name': rule$o,
|
3444
|
-
'unique-operation-name': rule$p,
|
3349
|
+
'description-style': rule$1,
|
3350
|
+
'input-name': rule$2,
|
3351
|
+
'match-document-filename': rule$3,
|
3352
|
+
'naming-convention': rule$4,
|
3353
|
+
'no-anonymous-operations': rule$5,
|
3354
|
+
'no-case-insensitive-enum-values-duplicates': rule$6,
|
3355
|
+
'no-deprecated': rule$7,
|
3356
|
+
'no-duplicate-fields': rule$8,
|
3357
|
+
'no-hashtag-description': rule$9,
|
3358
|
+
'no-root-type': rule$a,
|
3359
|
+
'no-scalar-result-type-on-mutation': rule$b,
|
3360
|
+
'no-typename-prefix': rule$c,
|
3361
|
+
'no-unreachable-types': rule$d,
|
3362
|
+
'no-unused-fields': rule$e,
|
3363
|
+
'require-deprecation-date': rule$f,
|
3364
|
+
'require-deprecation-reason': rule$g,
|
3365
|
+
'require-description': rule$h,
|
3366
|
+
'require-field-of-type-query-in-mutation-result': rule$i,
|
3367
|
+
'require-id-when-available': rule$j,
|
3368
|
+
'selection-set-depth': rule$k,
|
3369
|
+
'strict-id-in-types': rule$l,
|
3370
|
+
'unique-fragment-name': rule$m,
|
3371
|
+
'unique-operation-name': rule$n,
|
3445
3372
|
};
|
3446
3373
|
|
3447
3374
|
const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];
|