@graphql-eslint/eslint-plugin 3.0.0-alpha-069461d.0 → 3.0.0-alpha-698204a.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -8
- package/configs/base.d.ts +5 -0
- package/configs/index.d.ts +59 -91
- package/configs/operations-all.d.ts +19 -0
- package/configs/{recommended.d.ts → operations-recommended.d.ts} +11 -30
- package/configs/schema-all.d.ts +23 -0
- package/configs/schema-recommended.d.ts +44 -0
- package/docs/README.md +9 -17
- package/docs/deprecated-rules.md +21 -0
- package/docs/rules/alphabetize.md +1 -1
- package/docs/rules/description-style.md +4 -2
- 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 +26 -27
- 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 +7 -1
- 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 -7
- 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 +566 -599
- package/index.mjs +567 -600
- 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 +18 -8
- package/rules/input-name.d.ts +1 -1
- package/rules/match-document-filename.d.ts +8 -10
- package/rules/naming-convention.d.ts +1 -1
- package/rules/{avoid-duplicate-fields.d.ts → no-duplicate-fields.d.ts} +0 -0
- 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 +10 -6
- 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/utils.d.ts +1 -1
- package/configs/all.d.ts +0 -99
- package/docs/rules/avoid-operation-name-prefix.md +0 -50
- package/docs/rules/avoid-typename-prefix.md +0 -37
- package/docs/rules/no-operation-name-suffix.md +0 -38
- package/rules/avoid-operation-name-prefix.d.ts +0 -9
- package/rules/no-operation-name-suffix.d.ts +0 -3
package/index.js
CHANGED
@@ -18,22 +18,21 @@ const codeFileLoader = require('@graphql-tools/code-file-loader');
|
|
18
18
|
const eslint = require('eslint');
|
19
19
|
const codeFrame = require('@babel/code-frame');
|
20
20
|
|
21
|
+
const base = {
|
22
|
+
parser: '@graphql-eslint/eslint-plugin',
|
23
|
+
plugins: ['@graphql-eslint'],
|
24
|
+
};
|
25
|
+
|
21
26
|
/*
|
22
27
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
23
28
|
*/
|
24
|
-
const
|
25
|
-
|
26
|
-
plugins: ['@graphql-eslint'],
|
29
|
+
const schemaRecommendedConfig = {
|
30
|
+
extends: ['plugin:@graphql-eslint/base'],
|
27
31
|
rules: {
|
28
|
-
'@graphql-eslint/
|
29
|
-
'@graphql-eslint/executable-definitions': 'error',
|
30
|
-
'@graphql-eslint/fields-on-correct-type': 'error',
|
31
|
-
'@graphql-eslint/fragments-on-composite-type': 'error',
|
32
|
+
'@graphql-eslint/description-style': 'error',
|
32
33
|
'@graphql-eslint/known-argument-names': 'error',
|
33
34
|
'@graphql-eslint/known-directives': 'error',
|
34
|
-
'@graphql-eslint/known-fragment-names': 'error',
|
35
35
|
'@graphql-eslint/known-type-names': 'error',
|
36
|
-
'@graphql-eslint/lone-anonymous-operation': 'error',
|
37
36
|
'@graphql-eslint/lone-schema-definition': 'error',
|
38
37
|
'@graphql-eslint/naming-convention': [
|
39
38
|
'error',
|
@@ -42,12 +41,6 @@ const recommendedConfig = {
|
|
42
41
|
fields: 'camelCase',
|
43
42
|
overrides: {
|
44
43
|
EnumValueDefinition: 'UPPER_CASE',
|
45
|
-
OperationDefinition: {
|
46
|
-
style: 'PascalCase',
|
47
|
-
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
48
|
-
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
49
|
-
},
|
50
|
-
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
51
44
|
'FieldDefinition[parent.name.value=Query]': {
|
52
45
|
forbiddenPrefixes: ['query', 'get'],
|
53
46
|
forbiddenSuffixes: ['Query'],
|
@@ -63,29 +56,93 @@ const recommendedConfig = {
|
|
63
56
|
},
|
64
57
|
},
|
65
58
|
],
|
66
|
-
'@graphql-eslint/no-anonymous-operations': 'error',
|
67
59
|
'@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
|
60
|
+
'@graphql-eslint/no-hashtag-description': 'error',
|
61
|
+
'@graphql-eslint/no-typename-prefix': 'error',
|
62
|
+
'@graphql-eslint/no-unreachable-types': 'error',
|
63
|
+
'@graphql-eslint/possible-type-extension': 'error',
|
64
|
+
'@graphql-eslint/provided-required-arguments': 'error',
|
65
|
+
'@graphql-eslint/require-deprecation-reason': 'error',
|
66
|
+
'@graphql-eslint/strict-id-in-types': 'error',
|
67
|
+
'@graphql-eslint/unique-directive-names': 'error',
|
68
|
+
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
69
|
+
'@graphql-eslint/unique-enum-value-names': 'error',
|
70
|
+
'@graphql-eslint/unique-field-definition-names': 'error',
|
71
|
+
'@graphql-eslint/unique-operation-types': 'error',
|
72
|
+
'@graphql-eslint/unique-type-names': 'error',
|
73
|
+
},
|
74
|
+
};
|
75
|
+
|
76
|
+
/*
|
77
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
78
|
+
*/
|
79
|
+
const schemaAllConfig = {
|
80
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/schema-recommended'],
|
81
|
+
rules: {
|
82
|
+
'@graphql-eslint/alphabetize': [
|
83
|
+
'error',
|
84
|
+
{
|
85
|
+
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
86
|
+
values: ['EnumTypeDefinition'],
|
87
|
+
arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
|
88
|
+
},
|
89
|
+
],
|
90
|
+
'@graphql-eslint/input-name': 'error',
|
91
|
+
'@graphql-eslint/no-root-type': 'off',
|
92
|
+
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
93
|
+
'@graphql-eslint/no-unused-fields': 'off',
|
94
|
+
'@graphql-eslint/require-deprecation-date': 'error',
|
95
|
+
'@graphql-eslint/require-description': ['error', { types: true, overrides: { DirectiveDefinition: true } }],
|
96
|
+
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
97
|
+
},
|
98
|
+
};
|
99
|
+
|
100
|
+
/*
|
101
|
+
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
102
|
+
*/
|
103
|
+
const operationsRecommendedConfig = {
|
104
|
+
extends: ['plugin:@graphql-eslint/base'],
|
105
|
+
rules: {
|
106
|
+
'@graphql-eslint/executable-definitions': 'error',
|
107
|
+
'@graphql-eslint/fields-on-correct-type': 'error',
|
108
|
+
'@graphql-eslint/fragments-on-composite-type': 'error',
|
109
|
+
'@graphql-eslint/known-argument-names': 'error',
|
110
|
+
'@graphql-eslint/known-directives': 'error',
|
111
|
+
'@graphql-eslint/known-fragment-names': 'error',
|
112
|
+
'@graphql-eslint/known-type-names': 'error',
|
113
|
+
'@graphql-eslint/lone-anonymous-operation': 'error',
|
114
|
+
'@graphql-eslint/naming-convention': [
|
115
|
+
'error',
|
116
|
+
{
|
117
|
+
overrides: {
|
118
|
+
Argument: 'camelCase',
|
119
|
+
VariableDefinition: 'camelCase',
|
120
|
+
OperationDefinition: {
|
121
|
+
style: 'PascalCase',
|
122
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
123
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
124
|
+
},
|
125
|
+
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
126
|
+
},
|
127
|
+
},
|
128
|
+
],
|
129
|
+
'@graphql-eslint/no-anonymous-operations': 'error',
|
130
|
+
'@graphql-eslint/no-deprecated': 'error',
|
131
|
+
'@graphql-eslint/no-duplicate-fields': 'error',
|
68
132
|
'@graphql-eslint/no-fragment-cycles': 'error',
|
69
|
-
'@graphql-eslint/no-operation-name-suffix': 'error',
|
70
133
|
'@graphql-eslint/no-undefined-variables': 'error',
|
71
134
|
'@graphql-eslint/no-unused-fragments': 'error',
|
72
135
|
'@graphql-eslint/no-unused-variables': 'error',
|
73
136
|
'@graphql-eslint/one-field-subscriptions': 'error',
|
74
137
|
'@graphql-eslint/overlapping-fields-can-be-merged': 'error',
|
75
138
|
'@graphql-eslint/possible-fragment-spread': 'error',
|
76
|
-
'@graphql-eslint/possible-type-extension': 'error',
|
77
139
|
'@graphql-eslint/provided-required-arguments': 'error',
|
78
|
-
'@graphql-eslint/require-
|
140
|
+
'@graphql-eslint/require-id-when-available': 'error',
|
79
141
|
'@graphql-eslint/scalar-leafs': 'error',
|
80
|
-
'@graphql-eslint/
|
142
|
+
'@graphql-eslint/selection-set-depth': ['error', { maxDepth: 7 }],
|
81
143
|
'@graphql-eslint/unique-argument-names': 'error',
|
82
|
-
'@graphql-eslint/unique-directive-names': 'error',
|
83
144
|
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
84
|
-
'@graphql-eslint/unique-enum-value-names': 'error',
|
85
|
-
'@graphql-eslint/unique-field-definition-names': 'error',
|
86
145
|
'@graphql-eslint/unique-input-field-names': 'error',
|
87
|
-
'@graphql-eslint/unique-operation-types': 'error',
|
88
|
-
'@graphql-eslint/unique-type-names': 'error',
|
89
146
|
'@graphql-eslint/unique-variable-names': 'error',
|
90
147
|
'@graphql-eslint/value-literals-of-correct-type': 'error',
|
91
148
|
'@graphql-eslint/variables-are-input-types': 'error',
|
@@ -96,44 +153,32 @@ const recommendedConfig = {
|
|
96
153
|
/*
|
97
154
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
98
155
|
*/
|
99
|
-
const
|
100
|
-
|
156
|
+
const operationsAllConfig = {
|
157
|
+
extends: ['plugin:@graphql-eslint/base', 'plugin:@graphql-eslint/operations-recommended'],
|
101
158
|
rules: {
|
102
|
-
...recommendedConfig.rules,
|
103
159
|
'@graphql-eslint/alphabetize': [
|
104
160
|
'error',
|
105
161
|
{
|
106
|
-
fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
|
107
|
-
values: ['EnumTypeDefinition'],
|
108
162
|
selections: ['OperationDefinition', 'FragmentDefinition'],
|
109
163
|
variables: ['OperationDefinition'],
|
110
|
-
arguments: ['
|
164
|
+
arguments: ['Field', 'Directive'],
|
111
165
|
},
|
112
166
|
],
|
113
|
-
'@graphql-eslint/
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
'@graphql-eslint/input-name': 'error',
|
118
|
-
'@graphql-eslint/match-document-filename': 'error',
|
119
|
-
'@graphql-eslint/no-deprecated': 'error',
|
120
|
-
'@graphql-eslint/no-hashtag-description': 'error',
|
121
|
-
'@graphql-eslint/no-root-type': ['error', { disallow: ['subscription'] }],
|
122
|
-
'@graphql-eslint/no-unreachable-types': 'error',
|
123
|
-
'@graphql-eslint/no-unused-fields': 'error',
|
124
|
-
'@graphql-eslint/require-deprecation-date': 'error',
|
125
|
-
'@graphql-eslint/require-description': 'error',
|
126
|
-
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
127
|
-
'@graphql-eslint/require-id-when-available': 'error',
|
128
|
-
'@graphql-eslint/selection-set-depth': 'error',
|
167
|
+
'@graphql-eslint/match-document-filename': [
|
168
|
+
'error',
|
169
|
+
{ query: 'kebab-case', mutation: 'kebab-case', subscription: 'kebab-case', fragment: 'kebab-case' },
|
170
|
+
],
|
129
171
|
'@graphql-eslint/unique-fragment-name': 'error',
|
130
172
|
'@graphql-eslint/unique-operation-name': 'error',
|
131
173
|
},
|
132
174
|
};
|
133
175
|
|
134
176
|
const configs = {
|
135
|
-
|
136
|
-
recommended:
|
177
|
+
base,
|
178
|
+
'schema-recommended': schemaRecommendedConfig,
|
179
|
+
'schema-all': schemaAllConfig,
|
180
|
+
'operations-recommended': operationsRecommendedConfig,
|
181
|
+
'operations-all': operationsAllConfig,
|
137
182
|
};
|
138
183
|
|
139
184
|
function requireSiblingsOperations(ruleName, context) {
|
@@ -346,7 +391,6 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
346
391
|
docs: {
|
347
392
|
...docs,
|
348
393
|
graphQLJSRuleName: ruleName,
|
349
|
-
category: 'Validation',
|
350
394
|
recommended: true,
|
351
395
|
requiresSchema,
|
352
396
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
@@ -383,16 +427,22 @@ const importFiles = (context) => {
|
|
383
427
|
return _import.processImport(context.getFilename());
|
384
428
|
};
|
385
429
|
const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
|
430
|
+
category: 'Operations',
|
386
431
|
description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
|
387
432
|
}), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
|
433
|
+
category: 'Operations',
|
388
434
|
description: 'A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.',
|
389
435
|
}), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
|
436
|
+
category: 'Operations',
|
390
437
|
description: `Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.`,
|
391
438
|
}), validationToRule('known-argument-names', 'KnownArgumentNames', {
|
439
|
+
category: ['Schema', 'Operations'],
|
392
440
|
description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
|
393
441
|
}), validationToRule('known-directives', 'KnownDirectives', {
|
442
|
+
category: ['Schema', 'Operations'],
|
394
443
|
description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
|
395
444
|
}), validationToRule('known-fragment-names', 'KnownFragmentNames', {
|
445
|
+
category: 'Operations',
|
396
446
|
description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
|
397
447
|
examples: [
|
398
448
|
{
|
@@ -459,17 +509,23 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
459
509
|
},
|
460
510
|
],
|
461
511
|
}, importFiles), validationToRule('known-type-names', 'KnownTypeNames', {
|
512
|
+
category: ['Schema', 'Operations'],
|
462
513
|
description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
|
463
514
|
}), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
|
515
|
+
category: 'Operations',
|
464
516
|
description: `A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.`,
|
465
517
|
}), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
|
518
|
+
category: 'Schema',
|
466
519
|
description: `A GraphQL document is only valid if it contains only one schema definition.`,
|
467
520
|
requiresSchema: false,
|
468
521
|
}), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
|
522
|
+
category: 'Operations',
|
469
523
|
description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
|
470
524
|
}), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
|
525
|
+
category: 'Operations',
|
471
526
|
description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
|
472
527
|
}, importFiles), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
|
528
|
+
category: 'Operations',
|
473
529
|
description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
|
474
530
|
requiresSiblings: true,
|
475
531
|
}, context => {
|
@@ -499,49 +555,68 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
499
555
|
};
|
500
556
|
return getParentNode(context.getFilename());
|
501
557
|
}), validationToRule('no-unused-variables', 'NoUnusedVariables', {
|
558
|
+
category: 'Operations',
|
502
559
|
description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
|
503
560
|
}, importFiles), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
|
561
|
+
category: 'Operations',
|
504
562
|
description: `A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.`,
|
505
563
|
}), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
|
564
|
+
category: 'Operations',
|
506
565
|
description: `A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.`,
|
507
566
|
}), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
|
567
|
+
category: 'Schema',
|
508
568
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
509
569
|
requiresSchema: false,
|
510
570
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
571
|
+
category: ['Schema', 'Operations'],
|
511
572
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
512
573
|
}), validationToRule('scalar-leafs', 'ScalarLeafs', {
|
574
|
+
category: 'Operations',
|
513
575
|
description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
|
514
576
|
}), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
|
577
|
+
category: 'Operations',
|
515
578
|
description: `A GraphQL subscription is valid only if it contains a single root field.`,
|
516
579
|
}), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
|
580
|
+
category: 'Operations',
|
517
581
|
description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
|
518
582
|
}), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
|
583
|
+
category: 'Schema',
|
519
584
|
description: `A GraphQL document is only valid if all defined directives have unique names.`,
|
520
585
|
requiresSchema: false,
|
521
586
|
}), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
|
587
|
+
category: ['Schema', 'Operations'],
|
522
588
|
description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
|
523
589
|
}), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
|
590
|
+
category: 'Schema',
|
524
591
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
|
525
592
|
requiresSchema: false,
|
526
593
|
}), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
|
594
|
+
category: 'Schema',
|
527
595
|
description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
|
528
596
|
requiresSchema: false,
|
529
597
|
}), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
|
598
|
+
category: 'Operations',
|
530
599
|
description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
|
531
600
|
requiresSchema: false,
|
532
601
|
}), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
|
602
|
+
category: 'Schema',
|
533
603
|
description: `A GraphQL document is only valid if it has only one type per operation.`,
|
534
604
|
requiresSchema: false,
|
535
605
|
}), validationToRule('unique-type-names', 'UniqueTypeNames', {
|
606
|
+
category: 'Schema',
|
536
607
|
description: `A GraphQL document is only valid if all defined types have unique names.`,
|
537
608
|
requiresSchema: false,
|
538
609
|
}), validationToRule('unique-variable-names', 'UniqueVariableNames', {
|
610
|
+
category: 'Operations',
|
539
611
|
description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
|
540
612
|
}), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
|
613
|
+
category: 'Operations',
|
541
614
|
description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
|
542
615
|
}), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
|
616
|
+
category: 'Operations',
|
543
617
|
description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
|
544
618
|
}), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
|
619
|
+
category: 'Operations',
|
545
620
|
description: `Variables passed to field arguments conform to type.`,
|
546
621
|
}));
|
547
622
|
|
@@ -567,7 +642,7 @@ const rule = {
|
|
567
642
|
meta: {
|
568
643
|
type: 'suggestion',
|
569
644
|
docs: {
|
570
|
-
category: '
|
645
|
+
category: ['Schema', 'Operations'],
|
571
646
|
description: 'Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.',
|
572
647
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/alphabetize.md',
|
573
648
|
examples: [
|
@@ -646,15 +721,22 @@ const rule = {
|
|
646
721
|
`,
|
647
722
|
},
|
648
723
|
],
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
724
|
+
configOptions: {
|
725
|
+
schema: [
|
726
|
+
{
|
727
|
+
fields: fieldsEnum,
|
728
|
+
values: valuesEnum,
|
729
|
+
arguments: argumentsEnum,
|
730
|
+
},
|
731
|
+
],
|
732
|
+
operations: [
|
733
|
+
{
|
734
|
+
selections: selectionsEnum,
|
735
|
+
variables: variablesEnum,
|
736
|
+
arguments: [graphql.Kind.FIELD, graphql.Kind.DIRECTIVE],
|
737
|
+
},
|
738
|
+
],
|
739
|
+
},
|
658
740
|
},
|
659
741
|
messages: {
|
660
742
|
[ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"',
|
@@ -792,307 +874,7 @@ const rule = {
|
|
792
874
|
},
|
793
875
|
};
|
794
876
|
|
795
|
-
const AVOID_DUPLICATE_FIELDS = 'AVOID_DUPLICATE_FIELDS';
|
796
877
|
const rule$1 = {
|
797
|
-
meta: {
|
798
|
-
type: 'suggestion',
|
799
|
-
docs: {
|
800
|
-
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
801
|
-
category: 'Stylistic Issues',
|
802
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-duplicate-fields.md',
|
803
|
-
examples: [
|
804
|
-
{
|
805
|
-
title: 'Incorrect',
|
806
|
-
code: /* GraphQL */ `
|
807
|
-
query {
|
808
|
-
user {
|
809
|
-
name
|
810
|
-
email
|
811
|
-
name # duplicate field
|
812
|
-
}
|
813
|
-
}
|
814
|
-
`,
|
815
|
-
},
|
816
|
-
{
|
817
|
-
title: 'Incorrect',
|
818
|
-
code: /* GraphQL */ `
|
819
|
-
query {
|
820
|
-
users(
|
821
|
-
first: 100
|
822
|
-
skip: 50
|
823
|
-
after: "cji629tngfgou0b73kt7vi5jo"
|
824
|
-
first: 100 # duplicate argument
|
825
|
-
) {
|
826
|
-
id
|
827
|
-
}
|
828
|
-
}
|
829
|
-
`,
|
830
|
-
},
|
831
|
-
{
|
832
|
-
title: 'Incorrect',
|
833
|
-
code: /* GraphQL */ `
|
834
|
-
query (
|
835
|
-
$first: Int!
|
836
|
-
$first: Int! # duplicate variable
|
837
|
-
) {
|
838
|
-
users(first: $first, skip: 50) {
|
839
|
-
id
|
840
|
-
}
|
841
|
-
}
|
842
|
-
`,
|
843
|
-
},
|
844
|
-
],
|
845
|
-
},
|
846
|
-
messages: {
|
847
|
-
[AVOID_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
|
848
|
-
},
|
849
|
-
schema: [],
|
850
|
-
},
|
851
|
-
create(context) {
|
852
|
-
function checkNode(usedFields, fieldName, type, node) {
|
853
|
-
if (usedFields.has(fieldName)) {
|
854
|
-
context.report({
|
855
|
-
loc: getLocation((node.kind === graphql.Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
|
856
|
-
offsetEnd: node.kind === graphql.Kind.VARIABLE_DEFINITION ? 0 : 1,
|
857
|
-
}),
|
858
|
-
messageId: AVOID_DUPLICATE_FIELDS,
|
859
|
-
data: {
|
860
|
-
type,
|
861
|
-
fieldName,
|
862
|
-
},
|
863
|
-
});
|
864
|
-
}
|
865
|
-
else {
|
866
|
-
usedFields.add(fieldName);
|
867
|
-
}
|
868
|
-
}
|
869
|
-
return {
|
870
|
-
OperationDefinition(node) {
|
871
|
-
const set = new Set();
|
872
|
-
for (const varDef of node.variableDefinitions) {
|
873
|
-
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
874
|
-
}
|
875
|
-
},
|
876
|
-
Field(node) {
|
877
|
-
const set = new Set();
|
878
|
-
for (const arg of node.arguments) {
|
879
|
-
checkNode(set, arg.name.value, 'Field argument', arg);
|
880
|
-
}
|
881
|
-
},
|
882
|
-
SelectionSet(node) {
|
883
|
-
var _a;
|
884
|
-
const set = new Set();
|
885
|
-
for (const selection of node.selections) {
|
886
|
-
if (selection.kind === graphql.Kind.FIELD) {
|
887
|
-
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
888
|
-
}
|
889
|
-
}
|
890
|
-
},
|
891
|
-
};
|
892
|
-
},
|
893
|
-
};
|
894
|
-
|
895
|
-
const AVOID_OPERATION_NAME_PREFIX = 'AVOID_OPERATION_NAME_PREFIX';
|
896
|
-
const rule$2 = {
|
897
|
-
meta: {
|
898
|
-
type: 'suggestion',
|
899
|
-
docs: {
|
900
|
-
description: 'Enforce/avoid operation name prefix, useful if you wish to avoid prefix in your root fields, or avoid using REST terminology in your schema.',
|
901
|
-
category: 'Stylistic Issues',
|
902
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-operation-name-prefix.md',
|
903
|
-
examples: [
|
904
|
-
{
|
905
|
-
title: 'Incorrect',
|
906
|
-
usage: [{ keywords: ['get'] }],
|
907
|
-
code: /* GraphQL */ `
|
908
|
-
query getUserDetails {
|
909
|
-
# ...
|
910
|
-
}`,
|
911
|
-
},
|
912
|
-
{
|
913
|
-
title: 'Correct',
|
914
|
-
usage: [{ keywords: ['get'] }],
|
915
|
-
code: /* GraphQL */ `
|
916
|
-
query userDetails {
|
917
|
-
# ...
|
918
|
-
}`,
|
919
|
-
},
|
920
|
-
],
|
921
|
-
},
|
922
|
-
messages: {
|
923
|
-
[AVOID_OPERATION_NAME_PREFIX]: `Forbidden operation name prefix: "{{ invalidPrefix }}"`,
|
924
|
-
},
|
925
|
-
schema: [
|
926
|
-
{
|
927
|
-
additionalProperties: false,
|
928
|
-
type: 'object',
|
929
|
-
required: ['keywords'],
|
930
|
-
properties: {
|
931
|
-
caseSensitive: {
|
932
|
-
default: false,
|
933
|
-
type: 'boolean',
|
934
|
-
},
|
935
|
-
keywords: {
|
936
|
-
additionalItems: false,
|
937
|
-
type: 'array',
|
938
|
-
minItems: 1,
|
939
|
-
items: {
|
940
|
-
type: 'string',
|
941
|
-
},
|
942
|
-
},
|
943
|
-
},
|
944
|
-
},
|
945
|
-
],
|
946
|
-
},
|
947
|
-
create(context) {
|
948
|
-
return {
|
949
|
-
'OperationDefinition, FragmentDefinition'(node) {
|
950
|
-
const config = context.options[0] || { keywords: [], caseSensitive: false };
|
951
|
-
const caseSensitive = config.caseSensitive;
|
952
|
-
const keywords = config.keywords || [];
|
953
|
-
if (node && node.name && node.name.value !== '') {
|
954
|
-
for (const keyword of keywords) {
|
955
|
-
const testKeyword = caseSensitive ? keyword : keyword.toLowerCase();
|
956
|
-
const testName = caseSensitive ? node.name.value : node.name.value.toLowerCase();
|
957
|
-
if (testName.startsWith(testKeyword)) {
|
958
|
-
const { start } = node.name.loc;
|
959
|
-
context.report({
|
960
|
-
loc: {
|
961
|
-
start: {
|
962
|
-
line: start.line,
|
963
|
-
column: start.column - 1,
|
964
|
-
},
|
965
|
-
end: {
|
966
|
-
line: start.line,
|
967
|
-
column: start.column - 1 + testKeyword.length,
|
968
|
-
},
|
969
|
-
},
|
970
|
-
data: {
|
971
|
-
invalidPrefix: keyword,
|
972
|
-
},
|
973
|
-
messageId: AVOID_OPERATION_NAME_PREFIX,
|
974
|
-
});
|
975
|
-
}
|
976
|
-
}
|
977
|
-
}
|
978
|
-
},
|
979
|
-
};
|
980
|
-
},
|
981
|
-
};
|
982
|
-
|
983
|
-
const rule$3 = {
|
984
|
-
meta: {
|
985
|
-
type: 'suggestion',
|
986
|
-
docs: {
|
987
|
-
category: 'Best Practices',
|
988
|
-
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
989
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-scalar-result-type-on-mutation.md',
|
990
|
-
requiresSchema: true,
|
991
|
-
examples: [
|
992
|
-
{
|
993
|
-
title: 'Incorrect',
|
994
|
-
code: /* GraphQL */ `
|
995
|
-
type Mutation {
|
996
|
-
createUser: Boolean
|
997
|
-
}
|
998
|
-
`,
|
999
|
-
},
|
1000
|
-
{
|
1001
|
-
title: 'Correct',
|
1002
|
-
code: /* GraphQL */ `
|
1003
|
-
type Mutation {
|
1004
|
-
createUser: User!
|
1005
|
-
}
|
1006
|
-
`,
|
1007
|
-
},
|
1008
|
-
],
|
1009
|
-
},
|
1010
|
-
schema: [],
|
1011
|
-
},
|
1012
|
-
create(context) {
|
1013
|
-
const schema = requireGraphQLSchemaFromContext('avoid-scalar-result-type-on-mutation', context);
|
1014
|
-
const mutationType = schema.getMutationType();
|
1015
|
-
if (!mutationType) {
|
1016
|
-
return {};
|
1017
|
-
}
|
1018
|
-
const selector = [
|
1019
|
-
`:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
1020
|
-
'>',
|
1021
|
-
graphql.Kind.FIELD_DEFINITION,
|
1022
|
-
graphql.Kind.NAMED_TYPE,
|
1023
|
-
].join(' ');
|
1024
|
-
return {
|
1025
|
-
[selector](node) {
|
1026
|
-
const typeName = node.name.value;
|
1027
|
-
const graphQLType = schema.getType(typeName);
|
1028
|
-
if (graphql.isScalarType(graphQLType)) {
|
1029
|
-
context.report({
|
1030
|
-
loc: getLocation(node.loc, typeName),
|
1031
|
-
message: `Unexpected scalar result type "${typeName}"`,
|
1032
|
-
});
|
1033
|
-
}
|
1034
|
-
},
|
1035
|
-
};
|
1036
|
-
},
|
1037
|
-
};
|
1038
|
-
|
1039
|
-
const AVOID_TYPENAME_PREFIX = 'AVOID_TYPENAME_PREFIX';
|
1040
|
-
const rule$4 = {
|
1041
|
-
meta: {
|
1042
|
-
type: 'suggestion',
|
1043
|
-
docs: {
|
1044
|
-
category: 'Best Practices',
|
1045
|
-
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
1046
|
-
recommended: true,
|
1047
|
-
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/avoid-typename-prefix.md',
|
1048
|
-
examples: [
|
1049
|
-
{
|
1050
|
-
title: 'Incorrect',
|
1051
|
-
code: /* GraphQL */ `
|
1052
|
-
type User {
|
1053
|
-
userId: ID!
|
1054
|
-
}
|
1055
|
-
`,
|
1056
|
-
},
|
1057
|
-
{
|
1058
|
-
title: 'Correct',
|
1059
|
-
code: /* GraphQL */ `
|
1060
|
-
type User {
|
1061
|
-
id: ID!
|
1062
|
-
}
|
1063
|
-
`,
|
1064
|
-
},
|
1065
|
-
],
|
1066
|
-
},
|
1067
|
-
messages: {
|
1068
|
-
[AVOID_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
1069
|
-
},
|
1070
|
-
schema: [],
|
1071
|
-
},
|
1072
|
-
create(context) {
|
1073
|
-
return {
|
1074
|
-
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
1075
|
-
const typeName = node.name.value;
|
1076
|
-
const lowerTypeName = typeName.toLowerCase();
|
1077
|
-
for (const field of node.fields) {
|
1078
|
-
const fieldName = field.name.value;
|
1079
|
-
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
1080
|
-
context.report({
|
1081
|
-
data: {
|
1082
|
-
fieldName,
|
1083
|
-
typeName,
|
1084
|
-
},
|
1085
|
-
messageId: AVOID_TYPENAME_PREFIX,
|
1086
|
-
loc: getLocation(field.loc, lowerTypeName),
|
1087
|
-
});
|
1088
|
-
}
|
1089
|
-
}
|
1090
|
-
},
|
1091
|
-
};
|
1092
|
-
},
|
1093
|
-
};
|
1094
|
-
|
1095
|
-
const rule$5 = {
|
1096
878
|
meta: {
|
1097
879
|
type: 'suggestion',
|
1098
880
|
docs: {
|
@@ -1119,20 +901,20 @@ const rule$5 = {
|
|
1119
901
|
},
|
1120
902
|
],
|
1121
903
|
description: 'Require all comments to follow the same style (either block or inline).',
|
1122
|
-
category: '
|
904
|
+
category: 'Schema',
|
1123
905
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/description-style.md',
|
906
|
+
recommended: true,
|
1124
907
|
},
|
1125
908
|
schema: [
|
1126
909
|
{
|
1127
910
|
type: 'object',
|
911
|
+
additionalProperties: false,
|
1128
912
|
properties: {
|
1129
913
|
style: {
|
1130
|
-
type: 'string',
|
1131
914
|
enum: ['block', 'inline'],
|
1132
915
|
default: 'inline',
|
1133
916
|
},
|
1134
917
|
},
|
1135
|
-
additionalProperties: false,
|
1136
918
|
},
|
1137
919
|
],
|
1138
920
|
},
|
@@ -1155,12 +937,12 @@ const rule$5 = {
|
|
1155
937
|
const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
1156
938
|
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
1157
939
|
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
1158
|
-
const rule$
|
940
|
+
const rule$2 = {
|
1159
941
|
meta: {
|
1160
942
|
type: 'suggestion',
|
1161
943
|
docs: {
|
1162
944
|
description: 'Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".\nUsing the same name for all input parameters will make your schemas easier to consume and more predictable. Using the same name as mutation for InputType will make it easier to find mutations that InputType belongs to.',
|
1163
|
-
category: '
|
945
|
+
category: 'Schema',
|
1164
946
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/input-name.md',
|
1165
947
|
examples: [
|
1166
948
|
{
|
@@ -1281,11 +1063,11 @@ const CASE_STYLES = [
|
|
1281
1063
|
const schemaOption = {
|
1282
1064
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1283
1065
|
};
|
1284
|
-
const rule$
|
1066
|
+
const rule$3 = {
|
1285
1067
|
meta: {
|
1286
1068
|
type: 'suggestion',
|
1287
1069
|
docs: {
|
1288
|
-
category: '
|
1070
|
+
category: 'Operations',
|
1289
1071
|
description: 'This rule allows you to enforce that the file name should match the operation name.',
|
1290
1072
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/match-document-filename.md`,
|
1291
1073
|
examples: [
|
@@ -1359,6 +1141,14 @@ const rule$7 = {
|
|
1359
1141
|
`,
|
1360
1142
|
},
|
1361
1143
|
],
|
1144
|
+
configOptions: [
|
1145
|
+
{
|
1146
|
+
query: CaseStyle.kebabCase,
|
1147
|
+
mutation: CaseStyle.kebabCase,
|
1148
|
+
subscription: CaseStyle.kebabCase,
|
1149
|
+
fragment: CaseStyle.kebabCase,
|
1150
|
+
},
|
1151
|
+
],
|
1362
1152
|
},
|
1363
1153
|
messages: {
|
1364
1154
|
[MATCH_EXTENSION]: `File extension "{{ fileExtension }}" don't match extension "{{ expectedFileExtension }}"`,
|
@@ -1367,27 +1157,29 @@ const rule$7 = {
|
|
1367
1157
|
schema: {
|
1368
1158
|
definitions: {
|
1369
1159
|
asString: {
|
1370
|
-
type: 'string',
|
1371
|
-
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1372
1160
|
enum: CASE_STYLES,
|
1161
|
+
description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1373
1162
|
},
|
1374
1163
|
asObject: {
|
1375
1164
|
type: 'object',
|
1165
|
+
additionalProperties: false,
|
1376
1166
|
properties: {
|
1377
1167
|
style: {
|
1378
|
-
type: 'string',
|
1379
1168
|
enum: CASE_STYLES,
|
1380
1169
|
},
|
1170
|
+
suffix: {
|
1171
|
+
type: 'string',
|
1172
|
+
},
|
1381
1173
|
},
|
1382
1174
|
},
|
1383
1175
|
},
|
1384
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
1385
1176
|
type: 'array',
|
1177
|
+
maxItems: 1,
|
1386
1178
|
items: {
|
1387
1179
|
type: 'object',
|
1180
|
+
additionalProperties: false,
|
1388
1181
|
properties: {
|
1389
1182
|
fileExtension: {
|
1390
|
-
type: 'string',
|
1391
1183
|
enum: ACCEPTED_EXTENSIONS,
|
1392
1184
|
},
|
1393
1185
|
query: schemaOption,
|
@@ -1462,13 +1254,7 @@ const rule$7 = {
|
|
1462
1254
|
},
|
1463
1255
|
};
|
1464
1256
|
|
1465
|
-
const FIELDS_KINDS = [
|
1466
|
-
graphql.Kind.FIELD_DEFINITION,
|
1467
|
-
graphql.Kind.INPUT_VALUE_DEFINITION,
|
1468
|
-
graphql.Kind.VARIABLE_DEFINITION,
|
1469
|
-
graphql.Kind.ARGUMENT,
|
1470
|
-
graphql.Kind.DIRECTIVE_DEFINITION,
|
1471
|
-
];
|
1257
|
+
const FIELDS_KINDS = [graphql.Kind.FIELD_DEFINITION, graphql.Kind.INPUT_VALUE_DEFINITION, graphql.Kind.ARGUMENT, graphql.Kind.DIRECTIVE_DEFINITION];
|
1472
1258
|
const KindToDisplayName = {
|
1473
1259
|
// types
|
1474
1260
|
[graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
@@ -1480,13 +1266,13 @@ const KindToDisplayName = {
|
|
1480
1266
|
// fields
|
1481
1267
|
[graphql.Kind.FIELD_DEFINITION]: 'Field',
|
1482
1268
|
[graphql.Kind.INPUT_VALUE_DEFINITION]: 'Input property',
|
1483
|
-
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1484
1269
|
[graphql.Kind.ARGUMENT]: 'Argument',
|
1485
1270
|
[graphql.Kind.DIRECTIVE_DEFINITION]: 'Directive',
|
1486
1271
|
// rest
|
1487
1272
|
[graphql.Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
|
1488
1273
|
[graphql.Kind.OPERATION_DEFINITION]: 'Operation',
|
1489
1274
|
[graphql.Kind.FRAGMENT_DEFINITION]: 'Fragment',
|
1275
|
+
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1490
1276
|
};
|
1491
1277
|
const StyleToRegex = {
|
1492
1278
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
@@ -1499,12 +1285,12 @@ const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
|
1499
1285
|
const schemaOption$1 = {
|
1500
1286
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1501
1287
|
};
|
1502
|
-
const rule$
|
1288
|
+
const rule$4 = {
|
1503
1289
|
meta: {
|
1504
1290
|
type: 'suggestion',
|
1505
1291
|
docs: {
|
1506
1292
|
description: 'Require names to follow specified conventions.',
|
1507
|
-
category: '
|
1293
|
+
category: ['Schema', 'Operations'],
|
1508
1294
|
recommended: true,
|
1509
1295
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/naming-convention.md',
|
1510
1296
|
examples: [
|
@@ -1527,37 +1313,47 @@ const rule$8 = {
|
|
1527
1313
|
`,
|
1528
1314
|
},
|
1529
1315
|
],
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
},
|
1550
|
-
'FieldDefinition[parent.name.value=Mutation]': {
|
1551
|
-
forbiddenPrefixes: ['mutation'],
|
1552
|
-
forbiddenSuffixes: ['Mutation'],
|
1316
|
+
configOptions: {
|
1317
|
+
schema: [
|
1318
|
+
{
|
1319
|
+
types: 'PascalCase',
|
1320
|
+
fields: 'camelCase',
|
1321
|
+
overrides: {
|
1322
|
+
EnumValueDefinition: 'UPPER_CASE',
|
1323
|
+
'FieldDefinition[parent.name.value=Query]': {
|
1324
|
+
forbiddenPrefixes: ['query', 'get'],
|
1325
|
+
forbiddenSuffixes: ['Query'],
|
1326
|
+
},
|
1327
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
1328
|
+
forbiddenPrefixes: ['mutation'],
|
1329
|
+
forbiddenSuffixes: ['Mutation'],
|
1330
|
+
},
|
1331
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
1332
|
+
forbiddenPrefixes: ['subscription'],
|
1333
|
+
forbiddenSuffixes: ['Subscription'],
|
1334
|
+
},
|
1553
1335
|
},
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1336
|
+
},
|
1337
|
+
],
|
1338
|
+
operations: [
|
1339
|
+
{
|
1340
|
+
overrides: {
|
1341
|
+
Argument: 'camelCase',
|
1342
|
+
VariableDefinition: 'camelCase',
|
1343
|
+
OperationDefinition: {
|
1344
|
+
style: 'PascalCase',
|
1345
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1346
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1347
|
+
},
|
1348
|
+
FragmentDefinition: {
|
1349
|
+
style: 'PascalCase',
|
1350
|
+
forbiddenPrefixes: ['Fragment'],
|
1351
|
+
forbiddenSuffixes: ['Fragment'],
|
1352
|
+
},
|
1557
1353
|
},
|
1558
1354
|
},
|
1559
|
-
|
1560
|
-
|
1355
|
+
],
|
1356
|
+
},
|
1561
1357
|
},
|
1562
1358
|
schema: {
|
1563
1359
|
definitions: {
|
@@ -1595,11 +1391,11 @@ const rule$8 = {
|
|
1595
1391
|
properties: {
|
1596
1392
|
types: {
|
1597
1393
|
...schemaOption$1,
|
1598
|
-
description: `Includes:\n\n${TYPES_KINDS.map(kind => `-
|
1394
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
|
1599
1395
|
},
|
1600
1396
|
fields: {
|
1601
1397
|
...schemaOption$1,
|
1602
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `-
|
1398
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
|
1603
1399
|
},
|
1604
1400
|
allowLeadingUnderscore: {
|
1605
1401
|
type: 'boolean',
|
@@ -1615,7 +1411,7 @@ const rule$8 = {
|
|
1615
1411
|
description: [
|
1616
1412
|
'May contain the following `ASTNode` names:',
|
1617
1413
|
'',
|
1618
|
-
...ALLOWED_KINDS.map(kind => `-
|
1414
|
+
...ALLOWED_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`),
|
1619
1415
|
'',
|
1620
1416
|
"> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
|
1621
1417
|
'>',
|
@@ -1712,11 +1508,11 @@ const rule$8 = {
|
|
1712
1508
|
};
|
1713
1509
|
|
1714
1510
|
const NO_ANONYMOUS_OPERATIONS = 'NO_ANONYMOUS_OPERATIONS';
|
1715
|
-
const rule$
|
1511
|
+
const rule$5 = {
|
1716
1512
|
meta: {
|
1717
1513
|
type: 'suggestion',
|
1718
1514
|
docs: {
|
1719
|
-
category: '
|
1515
|
+
category: 'Operations',
|
1720
1516
|
description: 'Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.',
|
1721
1517
|
recommended: true,
|
1722
1518
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-anonymous-operations.md',
|
@@ -1760,12 +1556,12 @@ const rule$9 = {
|
|
1760
1556
|
};
|
1761
1557
|
|
1762
1558
|
const ERROR_MESSAGE_ID = 'NO_CASE_INSENSITIVE_ENUM_VALUES_DUPLICATES';
|
1763
|
-
const rule$
|
1559
|
+
const rule$6 = {
|
1764
1560
|
meta: {
|
1765
1561
|
type: 'suggestion',
|
1766
1562
|
docs: {
|
1767
1563
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-case-insensitive-enum-values-duplicates.md',
|
1768
|
-
category: '
|
1564
|
+
category: 'Schema',
|
1769
1565
|
recommended: true,
|
1770
1566
|
description: 'Disallow case-insensitive enum values duplicates.',
|
1771
1567
|
examples: [
|
@@ -1816,11 +1612,11 @@ const rule$a = {
|
|
1816
1612
|
};
|
1817
1613
|
|
1818
1614
|
const NO_DEPRECATED = 'NO_DEPRECATED';
|
1819
|
-
const rule$
|
1615
|
+
const rule$7 = {
|
1820
1616
|
meta: {
|
1821
1617
|
type: 'suggestion',
|
1822
1618
|
docs: {
|
1823
|
-
category: '
|
1619
|
+
category: 'Operations',
|
1824
1620
|
description: `Enforce that deprecated fields or enum values are not in use by operations.`,
|
1825
1621
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-deprecated.md`,
|
1826
1622
|
requiresSchema: true,
|
@@ -1886,6 +1682,7 @@ const rule$b = {
|
|
1886
1682
|
`,
|
1887
1683
|
},
|
1888
1684
|
],
|
1685
|
+
recommended: true,
|
1889
1686
|
},
|
1890
1687
|
messages: {
|
1891
1688
|
[NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
|
@@ -1912,19 +1709,120 @@ const rule$b = {
|
|
1912
1709
|
}
|
1913
1710
|
},
|
1914
1711
|
Field(node) {
|
1915
|
-
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1916
|
-
const typeInfo = node.typeInfo();
|
1917
|
-
if (typeInfo && typeInfo.fieldDef) {
|
1918
|
-
if (typeInfo.fieldDef.deprecationReason) {
|
1919
|
-
const fieldName = node.name.value;
|
1920
|
-
context.report({
|
1921
|
-
loc: getLocation(node.loc, fieldName),
|
1922
|
-
messageId: NO_DEPRECATED,
|
1923
|
-
data: {
|
1924
|
-
type: 'field',
|
1925
|
-
reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
|
1926
|
-
},
|
1927
|
-
});
|
1712
|
+
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1713
|
+
const typeInfo = node.typeInfo();
|
1714
|
+
if (typeInfo && typeInfo.fieldDef) {
|
1715
|
+
if (typeInfo.fieldDef.deprecationReason) {
|
1716
|
+
const fieldName = node.name.value;
|
1717
|
+
context.report({
|
1718
|
+
loc: getLocation(node.loc, fieldName),
|
1719
|
+
messageId: NO_DEPRECATED,
|
1720
|
+
data: {
|
1721
|
+
type: 'field',
|
1722
|
+
reason: typeInfo.fieldDef.deprecationReason ? `(reason: ${typeInfo.fieldDef.deprecationReason})` : '',
|
1723
|
+
},
|
1724
|
+
});
|
1725
|
+
}
|
1726
|
+
}
|
1727
|
+
},
|
1728
|
+
};
|
1729
|
+
},
|
1730
|
+
};
|
1731
|
+
|
1732
|
+
const NO_DUPLICATE_FIELDS = 'NO_DUPLICATE_FIELDS';
|
1733
|
+
const rule$8 = {
|
1734
|
+
meta: {
|
1735
|
+
type: 'suggestion',
|
1736
|
+
docs: {
|
1737
|
+
description: `Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.`,
|
1738
|
+
category: 'Operations',
|
1739
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-duplicate-fields.md',
|
1740
|
+
recommended: true,
|
1741
|
+
examples: [
|
1742
|
+
{
|
1743
|
+
title: 'Incorrect',
|
1744
|
+
code: /* GraphQL */ `
|
1745
|
+
query {
|
1746
|
+
user {
|
1747
|
+
name
|
1748
|
+
email
|
1749
|
+
name # duplicate field
|
1750
|
+
}
|
1751
|
+
}
|
1752
|
+
`,
|
1753
|
+
},
|
1754
|
+
{
|
1755
|
+
title: 'Incorrect',
|
1756
|
+
code: /* GraphQL */ `
|
1757
|
+
query {
|
1758
|
+
users(
|
1759
|
+
first: 100
|
1760
|
+
skip: 50
|
1761
|
+
after: "cji629tngfgou0b73kt7vi5jo"
|
1762
|
+
first: 100 # duplicate argument
|
1763
|
+
) {
|
1764
|
+
id
|
1765
|
+
}
|
1766
|
+
}
|
1767
|
+
`,
|
1768
|
+
},
|
1769
|
+
{
|
1770
|
+
title: 'Incorrect',
|
1771
|
+
code: /* GraphQL */ `
|
1772
|
+
query (
|
1773
|
+
$first: Int!
|
1774
|
+
$first: Int! # duplicate variable
|
1775
|
+
) {
|
1776
|
+
users(first: $first, skip: 50) {
|
1777
|
+
id
|
1778
|
+
}
|
1779
|
+
}
|
1780
|
+
`,
|
1781
|
+
},
|
1782
|
+
],
|
1783
|
+
},
|
1784
|
+
messages: {
|
1785
|
+
[NO_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times`,
|
1786
|
+
},
|
1787
|
+
schema: [],
|
1788
|
+
},
|
1789
|
+
create(context) {
|
1790
|
+
function checkNode(usedFields, fieldName, type, node) {
|
1791
|
+
if (usedFields.has(fieldName)) {
|
1792
|
+
context.report({
|
1793
|
+
loc: getLocation((node.kind === graphql.Kind.FIELD && node.alias ? node.alias : node).loc, fieldName, {
|
1794
|
+
offsetEnd: node.kind === graphql.Kind.VARIABLE_DEFINITION ? 0 : 1,
|
1795
|
+
}),
|
1796
|
+
messageId: NO_DUPLICATE_FIELDS,
|
1797
|
+
data: {
|
1798
|
+
type,
|
1799
|
+
fieldName,
|
1800
|
+
},
|
1801
|
+
});
|
1802
|
+
}
|
1803
|
+
else {
|
1804
|
+
usedFields.add(fieldName);
|
1805
|
+
}
|
1806
|
+
}
|
1807
|
+
return {
|
1808
|
+
OperationDefinition(node) {
|
1809
|
+
const set = new Set();
|
1810
|
+
for (const varDef of node.variableDefinitions) {
|
1811
|
+
checkNode(set, varDef.variable.name.value, 'Operation variable', varDef);
|
1812
|
+
}
|
1813
|
+
},
|
1814
|
+
Field(node) {
|
1815
|
+
const set = new Set();
|
1816
|
+
for (const arg of node.arguments) {
|
1817
|
+
checkNode(set, arg.name.value, 'Field argument', arg);
|
1818
|
+
}
|
1819
|
+
},
|
1820
|
+
SelectionSet(node) {
|
1821
|
+
var _a;
|
1822
|
+
const set = new Set();
|
1823
|
+
for (const selection of node.selections) {
|
1824
|
+
if (selection.kind === graphql.Kind.FIELD) {
|
1825
|
+
checkNode(set, ((_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) || selection.name.value, 'Field', selection);
|
1928
1826
|
}
|
1929
1827
|
}
|
1930
1828
|
},
|
@@ -1933,14 +1831,14 @@ const rule$b = {
|
|
1933
1831
|
};
|
1934
1832
|
|
1935
1833
|
const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
|
1936
|
-
const rule$
|
1834
|
+
const rule$9 = {
|
1937
1835
|
meta: {
|
1938
1836
|
messages: {
|
1939
1837
|
[HASHTAG_COMMENT]: 'Using hashtag (#) for adding GraphQL descriptions is not allowed. Prefer using """ for multiline, or " for a single line description.',
|
1940
1838
|
},
|
1941
1839
|
docs: {
|
1942
1840
|
description: 'Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.\nAllows to use hashtag for comments, as long as it\'s not attached to an AST definition.',
|
1943
|
-
category: '
|
1841
|
+
category: 'Schema',
|
1944
1842
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
|
1945
1843
|
examples: [
|
1946
1844
|
{
|
@@ -1977,6 +1875,7 @@ const rule$c = {
|
|
1977
1875
|
`,
|
1978
1876
|
},
|
1979
1877
|
],
|
1878
|
+
recommended: true,
|
1980
1879
|
},
|
1981
1880
|
type: 'suggestion',
|
1982
1881
|
schema: [],
|
@@ -2005,79 +1904,12 @@ const rule$c = {
|
|
2005
1904
|
},
|
2006
1905
|
};
|
2007
1906
|
|
2008
|
-
const NO_OPERATION_NAME_SUFFIX = 'NO_OPERATION_NAME_SUFFIX';
|
2009
|
-
const rule$d = {
|
2010
|
-
meta: {
|
2011
|
-
fixable: 'code',
|
2012
|
-
type: 'suggestion',
|
2013
|
-
docs: {
|
2014
|
-
category: 'Stylistic Issues',
|
2015
|
-
recommended: true,
|
2016
|
-
description: `Makes sure you are not adding the operation type to the name of the operation.`,
|
2017
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-operation-name-suffix.md`,
|
2018
|
-
examples: [
|
2019
|
-
{
|
2020
|
-
title: 'Incorrect',
|
2021
|
-
code: /* GraphQL */ `
|
2022
|
-
query userQuery {
|
2023
|
-
# ...
|
2024
|
-
}
|
2025
|
-
`,
|
2026
|
-
},
|
2027
|
-
{
|
2028
|
-
title: 'Correct',
|
2029
|
-
code: /* GraphQL */ `
|
2030
|
-
query user {
|
2031
|
-
# ...
|
2032
|
-
}
|
2033
|
-
`,
|
2034
|
-
},
|
2035
|
-
],
|
2036
|
-
},
|
2037
|
-
messages: {
|
2038
|
-
[NO_OPERATION_NAME_SUFFIX]: `Unnecessary "{{ invalidSuffix }}" suffix in your operation name!`,
|
2039
|
-
},
|
2040
|
-
schema: [],
|
2041
|
-
},
|
2042
|
-
create(context) {
|
2043
|
-
return {
|
2044
|
-
'OperationDefinition, FragmentDefinition'(node) {
|
2045
|
-
var _a;
|
2046
|
-
const name = ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '';
|
2047
|
-
if (name.length > 0) {
|
2048
|
-
const invalidSuffix = 'operation' in node ? node.operation : 'fragment';
|
2049
|
-
if (name.toLowerCase().endsWith(invalidSuffix)) {
|
2050
|
-
const { start, end } = node.name.loc;
|
2051
|
-
context.report({
|
2052
|
-
loc: {
|
2053
|
-
start: {
|
2054
|
-
column: start.column - 1 + name.length - invalidSuffix.length,
|
2055
|
-
line: start.line,
|
2056
|
-
},
|
2057
|
-
end: {
|
2058
|
-
column: end.column - 1 + name.length,
|
2059
|
-
line: end.line,
|
2060
|
-
},
|
2061
|
-
},
|
2062
|
-
data: {
|
2063
|
-
invalidSuffix,
|
2064
|
-
},
|
2065
|
-
fix: fixer => fixer.removeRange([node.name.range[1] - invalidSuffix.length, node.name.range[1]]),
|
2066
|
-
messageId: NO_OPERATION_NAME_SUFFIX,
|
2067
|
-
});
|
2068
|
-
}
|
2069
|
-
}
|
2070
|
-
},
|
2071
|
-
};
|
2072
|
-
},
|
2073
|
-
};
|
2074
|
-
|
2075
1907
|
const ROOT_TYPES = ['query', 'mutation', 'subscription'];
|
2076
|
-
const rule$
|
1908
|
+
const rule$a = {
|
2077
1909
|
meta: {
|
2078
1910
|
type: 'suggestion',
|
2079
1911
|
docs: {
|
2080
|
-
category: '
|
1912
|
+
category: 'Schema',
|
2081
1913
|
description: 'Disallow using root types for `read-only` or `write-only` schemas.',
|
2082
1914
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
|
2083
1915
|
requiresSchema: true,
|
@@ -2110,7 +1942,6 @@ const rule$e = {
|
|
2110
1942
|
`,
|
2111
1943
|
},
|
2112
1944
|
],
|
2113
|
-
optionsForConfig: [{ disallow: ['subscription'] }],
|
2114
1945
|
},
|
2115
1946
|
schema: {
|
2116
1947
|
type: 'array',
|
@@ -2163,16 +1994,128 @@ const rule$e = {
|
|
2163
1994
|
},
|
2164
1995
|
};
|
2165
1996
|
|
1997
|
+
const rule$b = {
|
1998
|
+
meta: {
|
1999
|
+
type: 'suggestion',
|
2000
|
+
docs: {
|
2001
|
+
category: 'Schema',
|
2002
|
+
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
2003
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-scalar-result-type-on-mutation.md',
|
2004
|
+
requiresSchema: true,
|
2005
|
+
examples: [
|
2006
|
+
{
|
2007
|
+
title: 'Incorrect',
|
2008
|
+
code: /* GraphQL */ `
|
2009
|
+
type Mutation {
|
2010
|
+
createUser: Boolean
|
2011
|
+
}
|
2012
|
+
`,
|
2013
|
+
},
|
2014
|
+
{
|
2015
|
+
title: 'Correct',
|
2016
|
+
code: /* GraphQL */ `
|
2017
|
+
type Mutation {
|
2018
|
+
createUser: User!
|
2019
|
+
}
|
2020
|
+
`,
|
2021
|
+
},
|
2022
|
+
],
|
2023
|
+
},
|
2024
|
+
schema: [],
|
2025
|
+
},
|
2026
|
+
create(context) {
|
2027
|
+
const schema = requireGraphQLSchemaFromContext('no-scalar-result-type-on-mutation', context);
|
2028
|
+
const mutationType = schema.getMutationType();
|
2029
|
+
if (!mutationType) {
|
2030
|
+
return {};
|
2031
|
+
}
|
2032
|
+
const selector = [
|
2033
|
+
`:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
|
2034
|
+
'>',
|
2035
|
+
graphql.Kind.FIELD_DEFINITION,
|
2036
|
+
graphql.Kind.NAMED_TYPE,
|
2037
|
+
].join(' ');
|
2038
|
+
return {
|
2039
|
+
[selector](node) {
|
2040
|
+
const typeName = node.name.value;
|
2041
|
+
const graphQLType = schema.getType(typeName);
|
2042
|
+
if (graphql.isScalarType(graphQLType)) {
|
2043
|
+
context.report({
|
2044
|
+
loc: getLocation(node.loc, typeName),
|
2045
|
+
message: `Unexpected scalar result type "${typeName}"`,
|
2046
|
+
});
|
2047
|
+
}
|
2048
|
+
},
|
2049
|
+
};
|
2050
|
+
},
|
2051
|
+
};
|
2052
|
+
|
2053
|
+
const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
|
2054
|
+
const rule$c = {
|
2055
|
+
meta: {
|
2056
|
+
type: 'suggestion',
|
2057
|
+
docs: {
|
2058
|
+
category: 'Schema',
|
2059
|
+
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
2060
|
+
recommended: true,
|
2061
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
|
2062
|
+
examples: [
|
2063
|
+
{
|
2064
|
+
title: 'Incorrect',
|
2065
|
+
code: /* GraphQL */ `
|
2066
|
+
type User {
|
2067
|
+
userId: ID!
|
2068
|
+
}
|
2069
|
+
`,
|
2070
|
+
},
|
2071
|
+
{
|
2072
|
+
title: 'Correct',
|
2073
|
+
code: /* GraphQL */ `
|
2074
|
+
type User {
|
2075
|
+
id: ID!
|
2076
|
+
}
|
2077
|
+
`,
|
2078
|
+
},
|
2079
|
+
],
|
2080
|
+
},
|
2081
|
+
messages: {
|
2082
|
+
[NO_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
2083
|
+
},
|
2084
|
+
schema: [],
|
2085
|
+
},
|
2086
|
+
create(context) {
|
2087
|
+
return {
|
2088
|
+
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
2089
|
+
const typeName = node.name.value;
|
2090
|
+
const lowerTypeName = typeName.toLowerCase();
|
2091
|
+
for (const field of node.fields) {
|
2092
|
+
const fieldName = field.name.value;
|
2093
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
2094
|
+
context.report({
|
2095
|
+
data: {
|
2096
|
+
fieldName,
|
2097
|
+
typeName,
|
2098
|
+
},
|
2099
|
+
messageId: NO_TYPENAME_PREFIX,
|
2100
|
+
loc: getLocation(field.loc, lowerTypeName),
|
2101
|
+
});
|
2102
|
+
}
|
2103
|
+
}
|
2104
|
+
},
|
2105
|
+
};
|
2106
|
+
},
|
2107
|
+
};
|
2108
|
+
|
2166
2109
|
const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
|
2167
2110
|
const RULE_NAME = 'no-unreachable-types';
|
2168
|
-
const rule$
|
2111
|
+
const rule$d = {
|
2169
2112
|
meta: {
|
2170
2113
|
messages: {
|
2171
|
-
[UNREACHABLE_TYPE]:
|
2114
|
+
[UNREACHABLE_TYPE]: 'Type "{{ typeName }}" is unreachable',
|
2172
2115
|
},
|
2173
2116
|
docs: {
|
2174
2117
|
description: `Requires all types to be reachable at some level by root level fields.`,
|
2175
|
-
category: '
|
2118
|
+
category: 'Schema',
|
2176
2119
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
|
2177
2120
|
requiresSchema: true,
|
2178
2121
|
examples: [
|
@@ -2203,6 +2146,7 @@ const rule$f = {
|
|
2203
2146
|
`,
|
2204
2147
|
},
|
2205
2148
|
],
|
2149
|
+
recommended: true,
|
2206
2150
|
},
|
2207
2151
|
fixable: 'code',
|
2208
2152
|
type: 'suggestion',
|
@@ -2241,14 +2185,14 @@ const rule$f = {
|
|
2241
2185
|
|
2242
2186
|
const UNUSED_FIELD = 'UNUSED_FIELD';
|
2243
2187
|
const RULE_NAME$1 = 'no-unused-fields';
|
2244
|
-
const rule$
|
2188
|
+
const rule$e = {
|
2245
2189
|
meta: {
|
2246
2190
|
messages: {
|
2247
2191
|
[UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
|
2248
2192
|
},
|
2249
2193
|
docs: {
|
2250
2194
|
description: `Requires all fields to be used at some level by siblings operations.`,
|
2251
|
-
category: '
|
2195
|
+
category: 'Schema',
|
2252
2196
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
|
2253
2197
|
requiresSiblings: true,
|
2254
2198
|
requiresSchema: true,
|
@@ -2430,11 +2374,11 @@ const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
|
2430
2374
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
2431
2375
|
const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
|
2432
2376
|
const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
|
2433
|
-
const rule$
|
2377
|
+
const rule$f = {
|
2434
2378
|
meta: {
|
2435
2379
|
type: 'suggestion',
|
2436
2380
|
docs: {
|
2437
|
-
category: '
|
2381
|
+
category: 'Schema',
|
2438
2382
|
description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
|
2439
2383
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-date.md',
|
2440
2384
|
examples: [
|
@@ -2533,11 +2477,11 @@ const rule$h = {
|
|
2533
2477
|
},
|
2534
2478
|
};
|
2535
2479
|
|
2536
|
-
const rule$
|
2480
|
+
const rule$g = {
|
2537
2481
|
meta: {
|
2538
2482
|
docs: {
|
2539
2483
|
description: `Require all deprecation directives to specify a reason.`,
|
2540
|
-
category: '
|
2484
|
+
category: 'Schema',
|
2541
2485
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-deprecation-reason.md`,
|
2542
2486
|
recommended: true,
|
2543
2487
|
examples: [
|
@@ -2588,41 +2532,23 @@ const rule$i = {
|
|
2588
2532
|
};
|
2589
2533
|
|
2590
2534
|
const REQUIRE_DESCRIPTION_ERROR = 'REQUIRE_DESCRIPTION_ERROR';
|
2591
|
-
const
|
2592
|
-
|
2593
|
-
graphql.Kind.OBJECT_TYPE_DEFINITION,
|
2535
|
+
const ALLOWED_KINDS$1 = [
|
2536
|
+
...TYPES_KINDS,
|
2594
2537
|
graphql.Kind.FIELD_DEFINITION,
|
2595
2538
|
graphql.Kind.INPUT_VALUE_DEFINITION,
|
2596
|
-
graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
2597
|
-
graphql.Kind.UNION_TYPE_DEFINITION,
|
2598
|
-
graphql.Kind.ENUM_TYPE_DEFINITION,
|
2599
2539
|
graphql.Kind.ENUM_VALUE_DEFINITION,
|
2600
|
-
graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
2601
2540
|
graphql.Kind.DIRECTIVE_DEFINITION,
|
2602
2541
|
];
|
2603
|
-
|
2604
|
-
if (node) {
|
2605
|
-
if (!node.description || !node.description.value || node.description.value.trim().length === 0) {
|
2606
|
-
context.report({
|
2607
|
-
loc: getLocation(('name' in node ? node.name : node).loc, 'name' in node ? node.name.value : 'schema'),
|
2608
|
-
messageId: REQUIRE_DESCRIPTION_ERROR,
|
2609
|
-
data: {
|
2610
|
-
nodeType: node.kind,
|
2611
|
-
},
|
2612
|
-
});
|
2613
|
-
}
|
2614
|
-
}
|
2615
|
-
}
|
2616
|
-
const rule$j = {
|
2542
|
+
const rule$h = {
|
2617
2543
|
meta: {
|
2618
2544
|
docs: {
|
2619
|
-
category: '
|
2620
|
-
description:
|
2621
|
-
url:
|
2545
|
+
category: 'Schema',
|
2546
|
+
description: 'Enforce descriptions in your type definitions.',
|
2547
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-description.md',
|
2622
2548
|
examples: [
|
2623
2549
|
{
|
2624
2550
|
title: 'Incorrect',
|
2625
|
-
usage: [{
|
2551
|
+
usage: [{ types: true, overrides: { FieldDefinition: true } }],
|
2626
2552
|
code: /* GraphQL */ `
|
2627
2553
|
type someTypeName {
|
2628
2554
|
name: String
|
@@ -2631,7 +2557,7 @@ const rule$j = {
|
|
2631
2557
|
},
|
2632
2558
|
{
|
2633
2559
|
title: 'Correct',
|
2634
|
-
usage: [{
|
2560
|
+
usage: [{ types: true, overrides: { FieldDefinition: true } }],
|
2635
2561
|
code: /* GraphQL */ `
|
2636
2562
|
"""
|
2637
2563
|
Some type description
|
@@ -2645,44 +2571,78 @@ const rule$j = {
|
|
2645
2571
|
`,
|
2646
2572
|
},
|
2647
2573
|
],
|
2574
|
+
configOptions: [
|
2575
|
+
{
|
2576
|
+
types: true,
|
2577
|
+
overrides: {
|
2578
|
+
[graphql.Kind.DIRECTIVE_DEFINITION]: true,
|
2579
|
+
},
|
2580
|
+
},
|
2581
|
+
],
|
2648
2582
|
},
|
2649
2583
|
type: 'suggestion',
|
2650
2584
|
messages: {
|
2651
|
-
[REQUIRE_DESCRIPTION_ERROR]:
|
2585
|
+
[REQUIRE_DESCRIPTION_ERROR]: 'Description is required for nodes of type "{{ nodeType }}"',
|
2652
2586
|
},
|
2653
2587
|
schema: {
|
2654
2588
|
type: 'array',
|
2655
|
-
additionalItems: false,
|
2656
2589
|
minItems: 1,
|
2657
2590
|
maxItems: 1,
|
2658
2591
|
items: {
|
2659
2592
|
type: 'object',
|
2660
|
-
|
2593
|
+
additionalProperties: false,
|
2594
|
+
minProperties: 1,
|
2661
2595
|
properties: {
|
2662
|
-
|
2663
|
-
type: '
|
2664
|
-
|
2665
|
-
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2596
|
+
types: {
|
2597
|
+
type: 'boolean',
|
2598
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- [${kind}](https://spec.graphql.org/October2021/#${kind})`).join('\n')}`,
|
2599
|
+
},
|
2600
|
+
overrides: {
|
2601
|
+
type: 'object',
|
2602
|
+
description: 'Configuration for precise `ASTNode`',
|
2603
|
+
additionalProperties: false,
|
2604
|
+
properties: Object.fromEntries(ALLOWED_KINDS$1.map(kind => [kind, { type: 'boolean' }])),
|
2670
2605
|
},
|
2671
2606
|
},
|
2672
2607
|
},
|
2673
2608
|
},
|
2674
2609
|
},
|
2675
2610
|
create(context) {
|
2676
|
-
|
2611
|
+
const { types, overrides = {} } = context.options[0];
|
2612
|
+
const kinds = new Set(types ? TYPES_KINDS : []);
|
2613
|
+
for (const [kind, isEnabled] of Object.entries(overrides)) {
|
2614
|
+
if (isEnabled) {
|
2615
|
+
kinds.add(kind);
|
2616
|
+
}
|
2617
|
+
else {
|
2618
|
+
kinds.delete(kind);
|
2619
|
+
}
|
2620
|
+
}
|
2621
|
+
const selector = [...kinds].join(',');
|
2622
|
+
return {
|
2623
|
+
[selector](node) {
|
2624
|
+
var _a;
|
2625
|
+
const description = ((_a = node.description) === null || _a === void 0 ? void 0 : _a.value) || '';
|
2626
|
+
if (description.trim().length === 0) {
|
2627
|
+
context.report({
|
2628
|
+
loc: getLocation(node.name.loc, node.name.value),
|
2629
|
+
messageId: REQUIRE_DESCRIPTION_ERROR,
|
2630
|
+
data: {
|
2631
|
+
nodeType: node.kind,
|
2632
|
+
},
|
2633
|
+
});
|
2634
|
+
}
|
2635
|
+
},
|
2636
|
+
};
|
2677
2637
|
},
|
2678
2638
|
};
|
2679
2639
|
|
2680
2640
|
const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
|
2681
|
-
const rule$
|
2641
|
+
const rule$i = {
|
2682
2642
|
meta: {
|
2683
2643
|
type: 'suggestion',
|
2684
2644
|
docs: {
|
2685
|
-
category: '
|
2645
|
+
category: 'Schema',
|
2686
2646
|
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`.',
|
2687
2647
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
|
2688
2648
|
requiresSchema: true,
|
@@ -2846,13 +2806,13 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2846
2806
|
|
2847
2807
|
const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2848
2808
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2849
|
-
const rule$
|
2809
|
+
const rule$j = {
|
2850
2810
|
meta: {
|
2851
2811
|
type: 'suggestion',
|
2852
2812
|
docs: {
|
2853
|
-
category: '
|
2854
|
-
description:
|
2855
|
-
url:
|
2813
|
+
category: 'Operations',
|
2814
|
+
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2815
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/require-id-when-available.md',
|
2856
2816
|
requiresSchema: true,
|
2857
2817
|
requiresSiblings: true,
|
2858
2818
|
examples: [
|
@@ -2892,17 +2852,17 @@ const rule$l = {
|
|
2892
2852
|
`,
|
2893
2853
|
},
|
2894
2854
|
],
|
2855
|
+
recommended: true,
|
2895
2856
|
},
|
2896
2857
|
messages: {
|
2897
|
-
[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 }}".`,
|
2858
|
+
[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 }}".`,
|
2898
2859
|
},
|
2899
2860
|
schema: {
|
2900
2861
|
type: 'array',
|
2901
|
-
additionalItems: false,
|
2902
|
-
minItems: 0,
|
2903
2862
|
maxItems: 1,
|
2904
2863
|
items: {
|
2905
2864
|
type: 'object',
|
2865
|
+
additionalProperties: false,
|
2906
2866
|
properties: {
|
2907
2867
|
fieldName: {
|
2908
2868
|
type: 'string',
|
@@ -2982,12 +2942,12 @@ const rule$l = {
|
|
2982
2942
|
},
|
2983
2943
|
};
|
2984
2944
|
|
2985
|
-
const rule$
|
2945
|
+
const rule$k = {
|
2986
2946
|
meta: {
|
2987
2947
|
docs: {
|
2988
|
-
category: '
|
2948
|
+
category: 'Operations',
|
2989
2949
|
description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
|
2990
|
-
url:
|
2950
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
|
2991
2951
|
requiresSiblings: true,
|
2992
2952
|
examples: [
|
2993
2953
|
{
|
@@ -3030,22 +2990,26 @@ const rule$m = {
|
|
3030
2990
|
`,
|
3031
2991
|
},
|
3032
2992
|
],
|
2993
|
+
recommended: true,
|
2994
|
+
configOptions: [{ maxDepth: 7 }],
|
3033
2995
|
},
|
3034
2996
|
type: 'suggestion',
|
3035
2997
|
schema: {
|
3036
2998
|
type: 'array',
|
3037
|
-
additionalItems: false,
|
3038
2999
|
minItems: 1,
|
3039
3000
|
maxItems: 1,
|
3040
3001
|
items: {
|
3041
3002
|
type: 'object',
|
3042
|
-
|
3003
|
+
additionalProperties: false,
|
3004
|
+
required: ['maxDepth'],
|
3043
3005
|
properties: {
|
3044
3006
|
maxDepth: {
|
3045
3007
|
type: 'number',
|
3046
3008
|
},
|
3047
3009
|
ignore: {
|
3048
3010
|
type: 'array',
|
3011
|
+
uniqueItems: true,
|
3012
|
+
minItems: 1,
|
3049
3013
|
items: {
|
3050
3014
|
type: 'string',
|
3051
3015
|
},
|
@@ -3104,12 +3068,12 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
|
|
3104
3068
|
}
|
3105
3069
|
return false;
|
3106
3070
|
};
|
3107
|
-
const rule$
|
3071
|
+
const rule$l = {
|
3108
3072
|
meta: {
|
3109
3073
|
type: 'suggestion',
|
3110
3074
|
docs: {
|
3111
3075
|
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.',
|
3112
|
-
category: '
|
3076
|
+
category: 'Schema',
|
3113
3077
|
recommended: true,
|
3114
3078
|
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/strict-id-in-types.md',
|
3115
3079
|
examples: [
|
@@ -3169,13 +3133,15 @@ const rule$n = {
|
|
3169
3133
|
],
|
3170
3134
|
},
|
3171
3135
|
schema: {
|
3172
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
3173
3136
|
type: 'array',
|
3137
|
+
maxItems: 1,
|
3174
3138
|
items: {
|
3175
3139
|
type: 'object',
|
3140
|
+
additionalProperties: false,
|
3176
3141
|
properties: {
|
3177
3142
|
acceptedIdNames: {
|
3178
3143
|
type: 'array',
|
3144
|
+
uniqueItems: true,
|
3179
3145
|
items: {
|
3180
3146
|
type: 'string',
|
3181
3147
|
},
|
@@ -3183,6 +3149,7 @@ const rule$n = {
|
|
3183
3149
|
},
|
3184
3150
|
acceptedIdTypes: {
|
3185
3151
|
type: 'array',
|
3152
|
+
uniqueItems: true,
|
3186
3153
|
items: {
|
3187
3154
|
type: 'string',
|
3188
3155
|
},
|
@@ -3193,19 +3160,21 @@ const rule$n = {
|
|
3193
3160
|
properties: {
|
3194
3161
|
types: {
|
3195
3162
|
type: 'array',
|
3163
|
+
uniqueItems: true,
|
3164
|
+
minItems: 1,
|
3196
3165
|
description: 'This is used to exclude types with names that match one of the specified values.',
|
3197
3166
|
items: {
|
3198
3167
|
type: 'string',
|
3199
3168
|
},
|
3200
|
-
default: [],
|
3201
3169
|
},
|
3202
3170
|
suffixes: {
|
3203
3171
|
type: 'array',
|
3172
|
+
uniqueItems: true,
|
3173
|
+
minItems: 1,
|
3204
3174
|
description: 'This is used to exclude types with names with suffixes that match one of the specified values.',
|
3205
3175
|
items: {
|
3206
3176
|
type: 'string',
|
3207
3177
|
},
|
3208
|
-
default: [],
|
3209
3178
|
},
|
3210
3179
|
},
|
3211
3180
|
},
|
@@ -3281,11 +3250,11 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3281
3250
|
});
|
3282
3251
|
}
|
3283
3252
|
};
|
3284
|
-
const rule$
|
3253
|
+
const rule$m = {
|
3285
3254
|
meta: {
|
3286
3255
|
type: 'suggestion',
|
3287
3256
|
docs: {
|
3288
|
-
category: '
|
3257
|
+
category: 'Operations',
|
3289
3258
|
description: `Enforce unique fragment names across your project.`,
|
3290
3259
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
|
3291
3260
|
requiresSiblings: true,
|
@@ -3340,11 +3309,11 @@ const rule$o = {
|
|
3340
3309
|
|
3341
3310
|
const RULE_NAME$4 = 'unique-operation-name';
|
3342
3311
|
const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
|
3343
|
-
const rule$
|
3312
|
+
const rule$n = {
|
3344
3313
|
meta: {
|
3345
3314
|
type: 'suggestion',
|
3346
3315
|
docs: {
|
3347
|
-
category: '
|
3316
|
+
category: 'Operations',
|
3348
3317
|
description: `Enforce unique operation names across your project.`,
|
3349
3318
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
|
3350
3319
|
requiresSiblings: true,
|
@@ -3407,31 +3376,29 @@ const rule$p = {
|
|
3407
3376
|
const rules = {
|
3408
3377
|
...GRAPHQL_JS_VALIDATIONS,
|
3409
3378
|
alphabetize: rule,
|
3410
|
-
'
|
3411
|
-
'
|
3412
|
-
'
|
3413
|
-
'
|
3414
|
-
'
|
3415
|
-
'
|
3416
|
-
'
|
3417
|
-
'
|
3418
|
-
'no-
|
3419
|
-
'no-
|
3420
|
-
'no-
|
3421
|
-
'no-
|
3422
|
-
'no-
|
3423
|
-
'no-
|
3424
|
-
'
|
3425
|
-
'
|
3426
|
-
'require-
|
3427
|
-
'require-
|
3428
|
-
'require-
|
3429
|
-
'
|
3430
|
-
'
|
3431
|
-
'
|
3432
|
-
'
|
3433
|
-
'unique-fragment-name': rule$o,
|
3434
|
-
'unique-operation-name': rule$p,
|
3379
|
+
'description-style': rule$1,
|
3380
|
+
'input-name': rule$2,
|
3381
|
+
'match-document-filename': rule$3,
|
3382
|
+
'naming-convention': rule$4,
|
3383
|
+
'no-anonymous-operations': rule$5,
|
3384
|
+
'no-case-insensitive-enum-values-duplicates': rule$6,
|
3385
|
+
'no-deprecated': rule$7,
|
3386
|
+
'no-duplicate-fields': rule$8,
|
3387
|
+
'no-hashtag-description': rule$9,
|
3388
|
+
'no-root-type': rule$a,
|
3389
|
+
'no-scalar-result-type-on-mutation': rule$b,
|
3390
|
+
'no-typename-prefix': rule$c,
|
3391
|
+
'no-unreachable-types': rule$d,
|
3392
|
+
'no-unused-fields': rule$e,
|
3393
|
+
'require-deprecation-date': rule$f,
|
3394
|
+
'require-deprecation-reason': rule$g,
|
3395
|
+
'require-description': rule$h,
|
3396
|
+
'require-field-of-type-query-in-mutation-result': rule$i,
|
3397
|
+
'require-id-when-available': rule$j,
|
3398
|
+
'selection-set-depth': rule$k,
|
3399
|
+
'strict-id-in-types': rule$l,
|
3400
|
+
'unique-fragment-name': rule$m,
|
3401
|
+
'unique-operation-name': rule$n,
|
3435
3402
|
};
|
3436
3403
|
|
3437
3404
|
const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];
|