@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.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/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
59
|
+
'@graphql-eslint/strict-id-in-types': 'error',
|
60
|
+
'@graphql-eslint/unique-directive-names': 'error',
|
61
|
+
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
62
|
+
'@graphql-eslint/unique-enum-value-names': 'error',
|
63
|
+
'@graphql-eslint/unique-field-definition-names': 'error',
|
64
|
+
'@graphql-eslint/unique-operation-types': 'error',
|
65
|
+
'@graphql-eslint/unique-type-names': 'error',
|
66
|
+
},
|
67
|
+
};
|
68
|
+
|
69
|
+
/*
|
70
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
71
|
+
*/
|
72
|
+
const schemaAllConfig = {
|
73
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/schema-recommended'],
|
74
|
+
rules: {
|
75
|
+
'@graphql-eslint/alphabetize': [
|
76
|
+
'error',
|
77
|
+
{
|
78
|
+
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
79
|
+
values: ['EnumTypeDefinition'],
|
80
|
+
arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
|
81
|
+
},
|
82
|
+
],
|
83
|
+
'@graphql-eslint/input-name': 'error',
|
84
|
+
'@graphql-eslint/no-root-type': 'off',
|
85
|
+
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
86
|
+
'@graphql-eslint/no-unused-fields': 'off',
|
87
|
+
'@graphql-eslint/require-deprecation-date': 'error',
|
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: [
|
@@ -1509,6 +1289,24 @@ const rule$8 = {
|
|
1509
1289
|
type user {
|
1510
1290
|
first_name: String!
|
1511
1291
|
}
|
1292
|
+
`,
|
1293
|
+
},
|
1294
|
+
{
|
1295
|
+
title: 'Incorrect',
|
1296
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1297
|
+
code: /* GraphQL */ `
|
1298
|
+
fragment UserFragment on User {
|
1299
|
+
# ...
|
1300
|
+
}
|
1301
|
+
`,
|
1302
|
+
},
|
1303
|
+
{
|
1304
|
+
title: 'Incorrect',
|
1305
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1306
|
+
code: /* GraphQL */ `
|
1307
|
+
type Query {
|
1308
|
+
getUsers: [User!]!
|
1309
|
+
}
|
1512
1310
|
`,
|
1513
1311
|
},
|
1514
1312
|
{
|
@@ -1520,23 +1318,31 @@ const rule$8 = {
|
|
1520
1318
|
}
|
1521
1319
|
`,
|
1522
1320
|
},
|
1523
|
-
],
|
1524
|
-
optionsForConfig: [
|
1525
1321
|
{
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1322
|
+
title: 'Correct',
|
1323
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1324
|
+
code: /* GraphQL */ `
|
1325
|
+
fragment UserFields on User {
|
1326
|
+
# ...
|
1327
|
+
}
|
1328
|
+
`,
|
1329
|
+
},
|
1330
|
+
{
|
1331
|
+
title: 'Correct',
|
1332
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1333
|
+
code: /* GraphQL */ `
|
1334
|
+
type Query {
|
1335
|
+
users: [User!]!
|
1336
|
+
}
|
1337
|
+
`,
|
1338
|
+
},
|
1339
|
+
],
|
1340
|
+
configOptions: {
|
1341
|
+
schema: [
|
1342
|
+
{
|
1343
|
+
types: 'PascalCase',
|
1344
|
+
fields: 'camelCase',
|
1529
1345
|
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
1346
|
'FieldDefinition[parent.name.value=Query]': {
|
1541
1347
|
forbiddenPrefixes: ['query', 'get'],
|
1542
1348
|
forbiddenSuffixes: ['Query'],
|
@@ -1550,8 +1356,24 @@ const rule$8 = {
|
|
1550
1356
|
forbiddenSuffixes: ['Subscription'],
|
1551
1357
|
},
|
1552
1358
|
},
|
1553
|
-
|
1554
|
-
|
1359
|
+
],
|
1360
|
+
operations: [
|
1361
|
+
{
|
1362
|
+
Argument: 'camelCase',
|
1363
|
+
VariableDefinition: 'camelCase',
|
1364
|
+
OperationDefinition: {
|
1365
|
+
style: 'PascalCase',
|
1366
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1367
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1368
|
+
},
|
1369
|
+
FragmentDefinition: {
|
1370
|
+
style: 'PascalCase',
|
1371
|
+
forbiddenPrefixes: ['Fragment'],
|
1372
|
+
forbiddenSuffixes: ['Fragment'],
|
1373
|
+
},
|
1374
|
+
},
|
1375
|
+
],
|
1376
|
+
},
|
1555
1377
|
},
|
1556
1378
|
schema: {
|
1557
1379
|
definitions: {
|
@@ -1589,12 +1411,19 @@ const rule$8 = {
|
|
1589
1411
|
properties: {
|
1590
1412
|
types: {
|
1591
1413
|
...schemaOption$1,
|
1592
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `-
|
1414
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1593
1415
|
},
|
1594
1416
|
fields: {
|
1595
1417
|
...schemaOption$1,
|
1596
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `-
|
1418
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1597
1419
|
},
|
1420
|
+
...Object.fromEntries(ALLOWED_KINDS.map(kind => [
|
1421
|
+
kind,
|
1422
|
+
{
|
1423
|
+
...schemaOption$1,
|
1424
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
1425
|
+
},
|
1426
|
+
])),
|
1598
1427
|
allowLeadingUnderscore: {
|
1599
1428
|
type: 'boolean',
|
1600
1429
|
default: false,
|
@@ -1603,35 +1432,27 @@ const rule$8 = {
|
|
1603
1432
|
type: 'boolean',
|
1604
1433
|
default: false,
|
1605
1434
|
},
|
1606
|
-
overrides: {
|
1607
|
-
type: 'object',
|
1608
|
-
additionalProperties: false,
|
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
|
-
},
|
1621
|
-
},
|
1622
1435
|
},
|
1436
|
+
patternProperties: {
|
1437
|
+
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1438
|
+
},
|
1439
|
+
description: [
|
1440
|
+
"> It's possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with allowed `ASTNode` names which are described below.",
|
1441
|
+
'>',
|
1442
|
+
'> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.',
|
1443
|
+
'>',
|
1444
|
+
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`.',
|
1445
|
+
].join('\n'),
|
1623
1446
|
},
|
1624
1447
|
},
|
1625
1448
|
},
|
1626
1449
|
create(context) {
|
1627
|
-
const options = {
|
1628
|
-
|
1629
|
-
...context.options[0],
|
1630
|
-
};
|
1450
|
+
const options = context.options[0] || {};
|
1451
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, fields, ...restOptions } = options;
|
1631
1452
|
function normalisePropertyOption(kind) {
|
1632
|
-
let style = options
|
1453
|
+
let style = options[kind];
|
1633
1454
|
if (!style) {
|
1634
|
-
style = TYPES_KINDS.includes(kind) ?
|
1455
|
+
style = TYPES_KINDS.includes(kind) ? types : fields;
|
1635
1456
|
}
|
1636
1457
|
return typeof style === 'object' ? style : { style };
|
1637
1458
|
}
|
@@ -1652,10 +1473,10 @@ const rule$8 = {
|
|
1652
1473
|
}
|
1653
1474
|
function getErrorMessage() {
|
1654
1475
|
let name = nodeName;
|
1655
|
-
if (
|
1476
|
+
if (allowLeadingUnderscore) {
|
1656
1477
|
name = name.replace(/^_*/, '');
|
1657
1478
|
}
|
1658
|
-
if (
|
1479
|
+
if (allowTrailingUnderscore) {
|
1659
1480
|
name = name.replace(/_*$/, '');
|
1660
1481
|
}
|
1661
1482
|
if (prefix && !name.startsWith(prefix)) {
|
@@ -1689,15 +1510,13 @@ const rule$8 = {
|
|
1689
1510
|
});
|
1690
1511
|
};
|
1691
1512
|
const listeners = {};
|
1692
|
-
if (!
|
1513
|
+
if (!allowLeadingUnderscore) {
|
1693
1514
|
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1694
1515
|
}
|
1695
|
-
if (!
|
1516
|
+
if (!allowTrailingUnderscore) {
|
1696
1517
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1697
1518
|
}
|
1698
|
-
const selectors = new Set([
|
1699
|
-
.flat()
|
1700
|
-
.filter(Boolean));
|
1519
|
+
const selectors = new Set([types && TYPES_KINDS, fields && FIELDS_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1701
1520
|
for (const selector of selectors) {
|
1702
1521
|
listeners[selector] = checkNode(selector);
|
1703
1522
|
}
|
@@ -1706,11 +1525,11 @@ const rule$8 = {
|
|
1706
1525
|
};
|
1707
1526
|
|
1708
1527
|
const NO_ANONYMOUS_OPERATIONS = 'NO_ANONYMOUS_OPERATIONS';
|
1709
|
-
const rule$
|
1528
|
+
const rule$5 = {
|
1710
1529
|
meta: {
|
1711
1530
|
type: 'suggestion',
|
1712
1531
|
docs: {
|
1713
|
-
category: '
|
1532
|
+
category: 'Operations',
|
1714
1533
|
description: 'Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.',
|
1715
1534
|
recommended: true,
|
1716
1535
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-anonymous-operations.md',
|
@@ -1754,12 +1573,12 @@ const rule$9 = {
|
|
1754
1573
|
};
|
1755
1574
|
|
1756
1575
|
const ERROR_MESSAGE_ID = 'NO_CASE_INSENSITIVE_ENUM_VALUES_DUPLICATES';
|
1757
|
-
const rule$
|
1576
|
+
const rule$6 = {
|
1758
1577
|
meta: {
|
1759
1578
|
type: 'suggestion',
|
1760
1579
|
docs: {
|
1761
1580
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-case-insensitive-enum-values-duplicates.md',
|
1762
|
-
category: '
|
1581
|
+
category: 'Schema',
|
1763
1582
|
recommended: true,
|
1764
1583
|
description: 'Disallow case-insensitive enum values duplicates.',
|
1765
1584
|
examples: [
|
@@ -1810,11 +1629,11 @@ const rule$a = {
|
|
1810
1629
|
};
|
1811
1630
|
|
1812
1631
|
const NO_DEPRECATED = 'NO_DEPRECATED';
|
1813
|
-
const rule$
|
1632
|
+
const rule$7 = {
|
1814
1633
|
meta: {
|
1815
1634
|
type: 'suggestion',
|
1816
1635
|
docs: {
|
1817
|
-
category: '
|
1636
|
+
category: 'Operations',
|
1818
1637
|
description: `Enforce that deprecated fields or enum values are not in use by operations.`,
|
1819
1638
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-deprecated.md`,
|
1820
1639
|
requiresSchema: true,
|
@@ -1877,48 +1696,150 @@ const rule$b = {
|
|
1877
1696
|
fullName
|
1878
1697
|
}
|
1879
1698
|
}
|
1880
|
-
`,
|
1881
|
-
},
|
1882
|
-
],
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1699
|
+
`,
|
1700
|
+
},
|
1701
|
+
],
|
1702
|
+
recommended: true,
|
1703
|
+
},
|
1704
|
+
messages: {
|
1705
|
+
[NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
|
1706
|
+
},
|
1707
|
+
schema: [],
|
1708
|
+
},
|
1709
|
+
create(context) {
|
1710
|
+
return {
|
1711
|
+
EnumValue(node) {
|
1712
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1713
|
+
const typeInfo = node.typeInfo();
|
1714
|
+
if (typeInfo && typeInfo.enumValue) {
|
1715
|
+
if (typeInfo.enumValue.deprecationReason) {
|
1716
|
+
const enumValueName = node.value;
|
1717
|
+
context.report({
|
1718
|
+
loc: getLocation(node.loc, enumValueName),
|
1719
|
+
messageId: NO_DEPRECATED,
|
1720
|
+
data: {
|
1721
|
+
type: 'enum value',
|
1722
|
+
reason: typeInfo.enumValue.deprecationReason ? `(reason: ${typeInfo.enumValue.deprecationReason})` : '',
|
1723
|
+
},
|
1724
|
+
});
|
1725
|
+
}
|
1726
|
+
}
|
1727
|
+
},
|
1728
|
+
Field(node) {
|
1729
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1730
|
+
const typeInfo = node.typeInfo();
|
1731
|
+
if (typeInfo && typeInfo.fieldDef) {
|
1732
|
+
if (typeInfo.fieldDef.deprecationReason) {
|
1733
|
+
const fieldName = node.name.value;
|
1734
|
+
context.report({
|
1735
|
+
loc: getLocation(node.loc, fieldName),
|
1736
|
+
messageId: NO_DEPRECATED,
|
1737
|
+
data: {
|
1738
|
+
type: 'field',
|
1739
|
+
reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
|
1740
|
+
},
|
1741
|
+
});
|
1742
|
+
}
|
1743
|
+
}
|
1744
|
+
},
|
1745
|
+
};
|
1746
|
+
},
|
1747
|
+
};
|
1748
|
+
|
1749
|
+
const NO_DUPLICATE_FIELDS = 'NO_DUPLICATE_FIELDS';
|
1750
|
+
const rule$8 = {
|
1751
|
+
meta: {
|
1752
|
+
type: 'suggestion',
|
1753
|
+
docs: {
|
1754
|
+
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
1755
|
+
category: 'Operations',
|
1756
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-duplicate-fields.md',
|
1757
|
+
recommended: true,
|
1758
|
+
examples: [
|
1759
|
+
{
|
1760
|
+
title: 'Incorrect',
|
1761
|
+
code: /* GraphQL */ `
|
1762
|
+
query {
|
1763
|
+
user {
|
1764
|
+
name
|
1765
|
+
email
|
1766
|
+
name # duplicate field
|
1767
|
+
}
|
1768
|
+
}
|
1769
|
+
`,
|
1770
|
+
},
|
1771
|
+
{
|
1772
|
+
title: 'Incorrect',
|
1773
|
+
code: /* GraphQL */ `
|
1774
|
+
query {
|
1775
|
+
users(
|
1776
|
+
first: 100
|
1777
|
+
skip: 50
|
1778
|
+
after: "cji629tngfgou0b73kt7vi5jo"
|
1779
|
+
first: 100 # duplicate argument
|
1780
|
+
) {
|
1781
|
+
id
|
1782
|
+
}
|
1783
|
+
}
|
1784
|
+
`,
|
1785
|
+
},
|
1786
|
+
{
|
1787
|
+
title: 'Incorrect',
|
1788
|
+
code: /* GraphQL */ `
|
1789
|
+
query (
|
1790
|
+
$first: Int!
|
1791
|
+
$first: Int! # duplicate variable
|
1792
|
+
) {
|
1793
|
+
users(first: $first, skip: 50) {
|
1794
|
+
id
|
1795
|
+
}
|
1796
|
+
}
|
1797
|
+
`,
|
1798
|
+
},
|
1799
|
+
],
|
1800
|
+
},
|
1801
|
+
messages: {
|
1802
|
+
[NO_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
|
1803
|
+
},
|
1804
|
+
schema: [],
|
1805
|
+
},
|
1806
|
+
create(context) {
|
1807
|
+
function checkNode(usedFields, fieldName, type, node) {
|
1808
|
+
if (usedFields.has(fieldName)) {
|
1809
|
+
context.report({
|
1810
|
+
loc: getLocation((node.kind === Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
|
1811
|
+
offsetEnd: node.kind === Kind.VARIABLE_DEFINITION ? 0 : 1,
|
1812
|
+
}),
|
1813
|
+
messageId: NO_DUPLICATE_FIELDS,
|
1814
|
+
data: {
|
1815
|
+
type,
|
1816
|
+
fieldName,
|
1817
|
+
},
|
1818
|
+
});
|
1819
|
+
}
|
1820
|
+
else {
|
1821
|
+
usedFields.add(fieldName);
|
1822
|
+
}
|
1823
|
+
}
|
1890
1824
|
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
|
-
}
|
1825
|
+
OperationDefinition(node) {
|
1826
|
+
const set = new Set();
|
1827
|
+
for (const varDef of node.variableDefinitions) {
|
1828
|
+
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
1906
1829
|
}
|
1907
1830
|
},
|
1908
1831
|
Field(node) {
|
1909
|
-
|
1910
|
-
const
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
},
|
1921
|
-
});
|
1832
|
+
const set = new Set();
|
1833
|
+
for (const arg of node.arguments) {
|
1834
|
+
checkNode(set, arg.name.value, 'Field argument', arg);
|
1835
|
+
}
|
1836
|
+
},
|
1837
|
+
SelectionSet(node) {
|
1838
|
+
var _a;
|
1839
|
+
const set = new Set();
|
1840
|
+
for (const selection of node.selections) {
|
1841
|
+
if (selection.kind === Kind.FIELD) {
|
1842
|
+
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
1922
1843
|
}
|
1923
1844
|
}
|
1924
1845
|
},
|
@@ -1927,14 +1848,14 @@ const rule$b = {
|
|
1927
1848
|
};
|
1928
1849
|
|
1929
1850
|
const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
|
1930
|
-
const rule$
|
1851
|
+
const rule$9 = {
|
1931
1852
|
meta: {
|
1932
1853
|
messages: {
|
1933
1854
|
[HASHTAG_COMMENT]: 'Using hashtag (#) for adding GraphQL descriptions is not allowed. Prefer using """ for multiline, or " for a single line description.',
|
1934
1855
|
},
|
1935
1856
|
docs: {
|
1936
1857
|
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: '
|
1858
|
+
category: 'Schema',
|
1938
1859
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
|
1939
1860
|
examples: [
|
1940
1861
|
{
|
@@ -1971,6 +1892,7 @@ const rule$c = {
|
|
1971
1892
|
`,
|
1972
1893
|
},
|
1973
1894
|
],
|
1895
|
+
recommended: true,
|
1974
1896
|
},
|
1975
1897
|
type: 'suggestion',
|
1976
1898
|
schema: [],
|
@@ -1999,85 +1921,18 @@ const rule$c = {
|
|
1999
1921
|
},
|
2000
1922
|
};
|
2001
1923
|
|
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 = {
|
1924
|
+
const ROOT_TYPES = ['mutation', 'subscription'];
|
1925
|
+
const rule$a = {
|
2071
1926
|
meta: {
|
2072
1927
|
type: 'suggestion',
|
2073
1928
|
docs: {
|
2074
|
-
category: '
|
2075
|
-
description: 'Disallow using root types
|
1929
|
+
category: 'Schema',
|
1930
|
+
description: 'Disallow using root types `mutation` and/or `subscription`.',
|
2076
1931
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
|
2077
1932
|
requiresSchema: true,
|
2078
1933
|
examples: [
|
2079
1934
|
{
|
2080
|
-
title: 'Incorrect
|
1935
|
+
title: 'Incorrect',
|
2081
1936
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2082
1937
|
code: /* GraphQL */ `
|
2083
1938
|
type Mutation {
|
@@ -2086,16 +1941,7 @@ const rule$e = {
|
|
2086
1941
|
`,
|
2087
1942
|
},
|
2088
1943
|
{
|
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)',
|
1944
|
+
title: 'Correct',
|
2099
1945
|
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2100
1946
|
code: /* GraphQL */ `
|
2101
1947
|
type Query {
|
@@ -2104,7 +1950,6 @@ const rule$e = {
|
|
2104
1950
|
`,
|
2105
1951
|
},
|
2106
1952
|
],
|
2107
|
-
optionsForConfig: [{ disallow: ['subscription'] }],
|
2108
1953
|
},
|
2109
1954
|
schema: {
|
2110
1955
|
type: 'array',
|
@@ -2131,7 +1976,6 @@ const rule$e = {
|
|
2131
1976
|
const schema = requireGraphQLSchemaFromContext('no-root-type', context);
|
2132
1977
|
const disallow = new Set(context.options[0].disallow);
|
2133
1978
|
const rootTypeNames = [
|
2134
|
-
disallow.has('query') && schema.getQueryType(),
|
2135
1979
|
disallow.has('mutation') && schema.getMutationType(),
|
2136
1980
|
disallow.has('subscription') && schema.getSubscriptionType(),
|
2137
1981
|
]
|
@@ -2157,16 +2001,128 @@ const rule$e = {
|
|
2157
2001
|
},
|
2158
2002
|
};
|
2159
2003
|
|
2004
|
+
const rule$b = {
|
2005
|
+
meta: {
|
2006
|
+
type: 'suggestion',
|
2007
|
+
docs: {
|
2008
|
+
category: 'Schema',
|
2009
|
+
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
2010
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-scalar-result-type-on-mutation.md',
|
2011
|
+
requiresSchema: true,
|
2012
|
+
examples: [
|
2013
|
+
{
|
2014
|
+
title: 'Incorrect',
|
2015
|
+
code: /* GraphQL */ `
|
2016
|
+
type Mutation {
|
2017
|
+
createUser: Boolean
|
2018
|
+
}
|
2019
|
+
`,
|
2020
|
+
},
|
2021
|
+
{
|
2022
|
+
title: 'Correct',
|
2023
|
+
code: /* GraphQL */ `
|
2024
|
+
type Mutation {
|
2025
|
+
createUser: User!
|
2026
|
+
}
|
2027
|
+
`,
|
2028
|
+
},
|
2029
|
+
],
|
2030
|
+
},
|
2031
|
+
schema: [],
|
2032
|
+
},
|
2033
|
+
create(context) {
|
2034
|
+
const schema = requireGraphQLSchemaFromContext('no-scalar-result-type-on-mutation', context);
|
2035
|
+
const mutationType = schema.getMutationType();
|
2036
|
+
if (!mutationType) {
|
2037
|
+
return {};
|
2038
|
+
}
|
2039
|
+
const selector = [
|
2040
|
+
`:matches(${Kind.OBJECT_TYPE_DEFINITION}, ${Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
2041
|
+
'>',
|
2042
|
+
Kind.FIELD_DEFINITION,
|
2043
|
+
Kind.NAMED_TYPE,
|
2044
|
+
].join(' ');
|
2045
|
+
return {
|
2046
|
+
[selector](node) {
|
2047
|
+
const typeName = node.name.value;
|
2048
|
+
const graphQLType = schema.getType(typeName);
|
2049
|
+
if (isScalarType(graphQLType)) {
|
2050
|
+
context.report({
|
2051
|
+
loc: getLocation(node.loc, typeName),
|
2052
|
+
message: `Unexpected scalar result type "${typeName}"`,
|
2053
|
+
});
|
2054
|
+
}
|
2055
|
+
},
|
2056
|
+
};
|
2057
|
+
},
|
2058
|
+
};
|
2059
|
+
|
2060
|
+
const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
|
2061
|
+
const rule$c = {
|
2062
|
+
meta: {
|
2063
|
+
type: 'suggestion',
|
2064
|
+
docs: {
|
2065
|
+
category: 'Schema',
|
2066
|
+
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
2067
|
+
recommended: true,
|
2068
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
|
2069
|
+
examples: [
|
2070
|
+
{
|
2071
|
+
title: 'Incorrect',
|
2072
|
+
code: /* GraphQL */ `
|
2073
|
+
type User {
|
2074
|
+
userId: ID!
|
2075
|
+
}
|
2076
|
+
`,
|
2077
|
+
},
|
2078
|
+
{
|
2079
|
+
title: 'Correct',
|
2080
|
+
code: /* GraphQL */ `
|
2081
|
+
type User {
|
2082
|
+
id: ID!
|
2083
|
+
}
|
2084
|
+
`,
|
2085
|
+
},
|
2086
|
+
],
|
2087
|
+
},
|
2088
|
+
messages: {
|
2089
|
+
[NO_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
2090
|
+
},
|
2091
|
+
schema: [],
|
2092
|
+
},
|
2093
|
+
create(context) {
|
2094
|
+
return {
|
2095
|
+
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
2096
|
+
const typeName = node.name.value;
|
2097
|
+
const lowerTypeName = typeName.toLowerCase();
|
2098
|
+
for (const field of node.fields) {
|
2099
|
+
const fieldName = field.name.value;
|
2100
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
2101
|
+
context.report({
|
2102
|
+
data: {
|
2103
|
+
fieldName,
|
2104
|
+
typeName,
|
2105
|
+
},
|
2106
|
+
messageId: NO_TYPENAME_PREFIX,
|
2107
|
+
loc: getLocation(field.loc, lowerTypeName),
|
2108
|
+
});
|
2109
|
+
}
|
2110
|
+
}
|
2111
|
+
},
|
2112
|
+
};
|
2113
|
+
},
|
2114
|
+
};
|
2115
|
+
|
2160
2116
|
const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
|
2161
2117
|
const RULE_NAME = 'no-unreachable-types';
|
2162
|
-
const rule$
|
2118
|
+
const rule$d = {
|
2163
2119
|
meta: {
|
2164
2120
|
messages: {
|
2165
|
-
[UNREACHABLE_TYPE]:
|
2121
|
+
[UNREACHABLE_TYPE]: 'Type "{{ typeName }}" is unreachable',
|
2166
2122
|
},
|
2167
2123
|
docs: {
|
2168
2124
|
description: `Requires all types to be reachable at some level by root level fields.`,
|
2169
|
-
category: '
|
2125
|
+
category: 'Schema',
|
2170
2126
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
|
2171
2127
|
requiresSchema: true,
|
2172
2128
|
examples: [
|
@@ -2197,6 +2153,7 @@ const rule$f = {
|
|
2197
2153
|
`,
|
2198
2154
|
},
|
2199
2155
|
],
|
2156
|
+
recommended: true,
|
2200
2157
|
},
|
2201
2158
|
fixable: 'code',
|
2202
2159
|
type: 'suggestion',
|
@@ -2235,14 +2192,14 @@ const rule$f = {
|
|
2235
2192
|
|
2236
2193
|
const UNUSED_FIELD = 'UNUSED_FIELD';
|
2237
2194
|
const RULE_NAME$1 = 'no-unused-fields';
|
2238
|
-
const rule$
|
2195
|
+
const rule$e = {
|
2239
2196
|
meta: {
|
2240
2197
|
messages: {
|
2241
2198
|
[UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
|
2242
2199
|
},
|
2243
2200
|
docs: {
|
2244
2201
|
description: `Requires all fields to be used at some level by siblings operations.`,
|
2245
|
-
category: '
|
2202
|
+
category: 'Schema',
|
2246
2203
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
|
2247
2204
|
requiresSiblings: true,
|
2248
2205
|
requiresSchema: true,
|
@@ -2424,11 +2381,11 @@ const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
|
2424
2381
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
2425
2382
|
const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
|
2426
2383
|
const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
|
2427
|
-
const rule$
|
2384
|
+
const rule$f = {
|
2428
2385
|
meta: {
|
2429
2386
|
type: 'suggestion',
|
2430
2387
|
docs: {
|
2431
|
-
category: '
|
2388
|
+
category: 'Schema',
|
2432
2389
|
description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
|
2433
2390
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-date.md',
|
2434
2391
|
examples: [
|
@@ -2527,11 +2484,11 @@ const rule$h = {
|
|
2527
2484
|
},
|
2528
2485
|
};
|
2529
2486
|
|
2530
|
-
const rule$
|
2487
|
+
const rule$g = {
|
2531
2488
|
meta: {
|
2532
2489
|
docs: {
|
2533
2490
|
description: `Require all deprecation directives to specify a reason.`,
|
2534
|
-
category: '
|
2491
|
+
category: 'Schema',
|
2535
2492
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-reason.md`,
|
2536
2493
|
recommended: true,
|
2537
2494
|
examples: [
|
@@ -2589,16 +2546,16 @@ const ALLOWED_KINDS$1 = [
|
|
2589
2546
|
Kind.ENUM_VALUE_DEFINITION,
|
2590
2547
|
Kind.DIRECTIVE_DEFINITION,
|
2591
2548
|
];
|
2592
|
-
const rule$
|
2549
|
+
const rule$h = {
|
2593
2550
|
meta: {
|
2594
2551
|
docs: {
|
2595
|
-
category: '
|
2552
|
+
category: 'Schema',
|
2596
2553
|
description: 'Enforce descriptions in your type definitions.',
|
2597
2554
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md',
|
2598
2555
|
examples: [
|
2599
2556
|
{
|
2600
2557
|
title: 'Incorrect',
|
2601
|
-
usage: [{ types: true,
|
2558
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2602
2559
|
code: /* GraphQL */ `
|
2603
2560
|
type someTypeName {
|
2604
2561
|
name: String
|
@@ -2607,7 +2564,7 @@ const rule$j = {
|
|
2607
2564
|
},
|
2608
2565
|
{
|
2609
2566
|
title: 'Correct',
|
2610
|
-
usage: [{ types: true,
|
2567
|
+
usage: [{ types: true, FieldDefinition: true }],
|
2611
2568
|
code: /* GraphQL */ `
|
2612
2569
|
"""
|
2613
2570
|
Some type description
|
@@ -2621,14 +2578,13 @@ const rule$j = {
|
|
2621
2578
|
`,
|
2622
2579
|
},
|
2623
2580
|
],
|
2624
|
-
|
2581
|
+
configOptions: [
|
2625
2582
|
{
|
2626
2583
|
types: true,
|
2627
|
-
|
2628
|
-
[Kind.DIRECTIVE_DEFINITION]: true,
|
2629
|
-
},
|
2584
|
+
[Kind.DIRECTIVE_DEFINITION]: true,
|
2630
2585
|
},
|
2631
2586
|
],
|
2587
|
+
recommended: true,
|
2632
2588
|
},
|
2633
2589
|
type: 'suggestion',
|
2634
2590
|
messages: {
|
@@ -2645,22 +2601,23 @@ const rule$j = {
|
|
2645
2601
|
properties: {
|
2646
2602
|
types: {
|
2647
2603
|
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' }])),
|
2604
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
2655
2605
|
},
|
2606
|
+
...Object.fromEntries([...ALLOWED_KINDS$1].sort().map(kind => [
|
2607
|
+
kind,
|
2608
|
+
{
|
2609
|
+
type: 'boolean',
|
2610
|
+
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
2611
|
+
},
|
2612
|
+
])),
|
2656
2613
|
},
|
2657
2614
|
},
|
2658
2615
|
},
|
2659
2616
|
},
|
2660
2617
|
create(context) {
|
2661
|
-
const { types,
|
2618
|
+
const { types, ...restOptions } = context.options[0];
|
2662
2619
|
const kinds = new Set(types ? TYPES_KINDS : []);
|
2663
|
-
for (const [kind, isEnabled] of Object.entries(
|
2620
|
+
for (const [kind, isEnabled] of Object.entries(restOptions)) {
|
2664
2621
|
if (isEnabled) {
|
2665
2622
|
kinds.add(kind);
|
2666
2623
|
}
|
@@ -2688,11 +2645,11 @@ const rule$j = {
|
|
2688
2645
|
};
|
2689
2646
|
|
2690
2647
|
const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
|
2691
|
-
const rule$
|
2648
|
+
const rule$i = {
|
2692
2649
|
meta: {
|
2693
2650
|
type: 'suggestion',
|
2694
2651
|
docs: {
|
2695
|
-
category: '
|
2652
|
+
category: 'Schema',
|
2696
2653
|
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
2654
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
|
2698
2655
|
requiresSchema: true,
|
@@ -2856,13 +2813,13 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2856
2813
|
|
2857
2814
|
const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2858
2815
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2859
|
-
const rule$
|
2816
|
+
const rule$j = {
|
2860
2817
|
meta: {
|
2861
2818
|
type: 'suggestion',
|
2862
2819
|
docs: {
|
2863
|
-
category: '
|
2864
|
-
description:
|
2865
|
-
url:
|
2820
|
+
category: 'Operations',
|
2821
|
+
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2822
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
|
2866
2823
|
requiresSchema: true,
|
2867
2824
|
requiresSiblings: true,
|
2868
2825
|
examples: [
|
@@ -2902,17 +2859,17 @@ const rule$l = {
|
|
2902
2859
|
`,
|
2903
2860
|
},
|
2904
2861
|
],
|
2862
|
+
recommended: true,
|
2905
2863
|
},
|
2906
2864
|
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 }}".`,
|
2865
|
+
[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
2866
|
},
|
2909
2867
|
schema: {
|
2910
2868
|
type: 'array',
|
2911
|
-
additionalItems: false,
|
2912
|
-
minItems: 0,
|
2913
2869
|
maxItems: 1,
|
2914
2870
|
items: {
|
2915
2871
|
type: 'object',
|
2872
|
+
additionalProperties: false,
|
2916
2873
|
properties: {
|
2917
2874
|
fieldName: {
|
2918
2875
|
type: 'string',
|
@@ -2992,12 +2949,12 @@ const rule$l = {
|
|
2992
2949
|
},
|
2993
2950
|
};
|
2994
2951
|
|
2995
|
-
const rule$
|
2952
|
+
const rule$k = {
|
2996
2953
|
meta: {
|
2997
2954
|
docs: {
|
2998
|
-
category: '
|
2955
|
+
category: 'Operations',
|
2999
2956
|
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:
|
2957
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
|
3001
2958
|
requiresSiblings: true,
|
3002
2959
|
examples: [
|
3003
2960
|
{
|
@@ -3040,22 +2997,26 @@ const rule$m = {
|
|
3040
2997
|
`,
|
3041
2998
|
},
|
3042
2999
|
],
|
3000
|
+
recommended: true,
|
3001
|
+
configOptions: [{ maxDepth: 7 }],
|
3043
3002
|
},
|
3044
3003
|
type: 'suggestion',
|
3045
3004
|
schema: {
|
3046
3005
|
type: 'array',
|
3047
|
-
additionalItems: false,
|
3048
3006
|
minItems: 1,
|
3049
3007
|
maxItems: 1,
|
3050
3008
|
items: {
|
3051
3009
|
type: 'object',
|
3052
|
-
|
3010
|
+
additionalProperties: false,
|
3011
|
+
required: ['maxDepth'],
|
3053
3012
|
properties: {
|
3054
3013
|
maxDepth: {
|
3055
3014
|
type: 'number',
|
3056
3015
|
},
|
3057
3016
|
ignore: {
|
3058
3017
|
type: 'array',
|
3018
|
+
uniqueItems: true,
|
3019
|
+
minItems: 1,
|
3059
3020
|
items: {
|
3060
3021
|
type: 'string',
|
3061
3022
|
},
|
@@ -3114,12 +3075,12 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
|
|
3114
3075
|
}
|
3115
3076
|
return false;
|
3116
3077
|
};
|
3117
|
-
const rule$
|
3078
|
+
const rule$l = {
|
3118
3079
|
meta: {
|
3119
3080
|
type: 'suggestion',
|
3120
3081
|
docs: {
|
3121
3082
|
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: '
|
3083
|
+
category: 'Schema',
|
3123
3084
|
recommended: true,
|
3124
3085
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
|
3125
3086
|
examples: [
|
@@ -3179,13 +3140,15 @@ const rule$n = {
|
|
3179
3140
|
],
|
3180
3141
|
},
|
3181
3142
|
schema: {
|
3182
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
3183
3143
|
type: 'array',
|
3144
|
+
maxItems: 1,
|
3184
3145
|
items: {
|
3185
3146
|
type: 'object',
|
3147
|
+
additionalProperties: false,
|
3186
3148
|
properties: {
|
3187
3149
|
acceptedIdNames: {
|
3188
3150
|
type: 'array',
|
3151
|
+
uniqueItems: true,
|
3189
3152
|
items: {
|
3190
3153
|
type: 'string',
|
3191
3154
|
},
|
@@ -3193,6 +3156,7 @@ const rule$n = {
|
|
3193
3156
|
},
|
3194
3157
|
acceptedIdTypes: {
|
3195
3158
|
type: 'array',
|
3159
|
+
uniqueItems: true,
|
3196
3160
|
items: {
|
3197
3161
|
type: 'string',
|
3198
3162
|
},
|
@@ -3203,19 +3167,21 @@ const rule$n = {
|
|
3203
3167
|
properties: {
|
3204
3168
|
types: {
|
3205
3169
|
type: 'array',
|
3170
|
+
uniqueItems: true,
|
3171
|
+
minItems: 1,
|
3206
3172
|
description: 'This is used to exclude types with names that match one of the specified values.',
|
3207
3173
|
items: {
|
3208
3174
|
type: 'string',
|
3209
3175
|
},
|
3210
|
-
default: [],
|
3211
3176
|
},
|
3212
3177
|
suffixes: {
|
3213
3178
|
type: 'array',
|
3179
|
+
uniqueItems: true,
|
3180
|
+
minItems: 1,
|
3214
3181
|
description: 'This is used to exclude types with names with suffixes that match one of the specified values.',
|
3215
3182
|
items: {
|
3216
3183
|
type: 'string',
|
3217
3184
|
},
|
3218
|
-
default: [],
|
3219
3185
|
},
|
3220
3186
|
},
|
3221
3187
|
},
|
@@ -3291,11 +3257,11 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3291
3257
|
});
|
3292
3258
|
}
|
3293
3259
|
};
|
3294
|
-
const rule$
|
3260
|
+
const rule$m = {
|
3295
3261
|
meta: {
|
3296
3262
|
type: 'suggestion',
|
3297
3263
|
docs: {
|
3298
|
-
category: '
|
3264
|
+
category: 'Operations',
|
3299
3265
|
description: `Enforce unique fragment names across your project.`,
|
3300
3266
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
|
3301
3267
|
requiresSiblings: true,
|
@@ -3350,11 +3316,11 @@ const rule$o = {
|
|
3350
3316
|
|
3351
3317
|
const RULE_NAME$4 = 'unique-operation-name';
|
3352
3318
|
const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
|
3353
|
-
const rule$
|
3319
|
+
const rule$n = {
|
3354
3320
|
meta: {
|
3355
3321
|
type: 'suggestion',
|
3356
3322
|
docs: {
|
3357
|
-
category: '
|
3323
|
+
category: 'Operations',
|
3358
3324
|
description: `Enforce unique operation names across your project.`,
|
3359
3325
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
|
3360
3326
|
requiresSiblings: true,
|
@@ -3417,31 +3383,29 @@ const rule$p = {
|
|
3417
3383
|
const rules = {
|
3418
3384
|
...GRAPHQL_JS_VALIDATIONS,
|
3419
3385
|
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,
|
3386
|
+
'description-style': rule$1,
|
3387
|
+
'input-name': rule$2,
|
3388
|
+
'match-document-filename': rule$3,
|
3389
|
+
'naming-convention': rule$4,
|
3390
|
+
'no-anonymous-operations': rule$5,
|
3391
|
+
'no-case-insensitive-enum-values-duplicates': rule$6,
|
3392
|
+
'no-deprecated': rule$7,
|
3393
|
+
'no-duplicate-fields': rule$8,
|
3394
|
+
'no-hashtag-description': rule$9,
|
3395
|
+
'no-root-type': rule$a,
|
3396
|
+
'no-scalar-result-type-on-mutation': rule$b,
|
3397
|
+
'no-typename-prefix': rule$c,
|
3398
|
+
'no-unreachable-types': rule$d,
|
3399
|
+
'no-unused-fields': rule$e,
|
3400
|
+
'require-deprecation-date': rule$f,
|
3401
|
+
'require-deprecation-reason': rule$g,
|
3402
|
+
'require-description': rule$h,
|
3403
|
+
'require-field-of-type-query-in-mutation-result': rule$i,
|
3404
|
+
'require-id-when-available': rule$j,
|
3405
|
+
'selection-set-depth': rule$k,
|
3406
|
+
'strict-id-in-types': rule$l,
|
3407
|
+
'unique-fragment-name': rule$m,
|
3408
|
+
'unique-operation-name': rule$n,
|
3445
3409
|
};
|
3446
3410
|
|
3447
3411
|
const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];
|