@graphql-eslint/eslint-plugin 3.0.0-alpha-2918431.0 → 3.0.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 +11 -1
- package/configs/index.d.ts +9 -7
- package/configs/operations-recommended.d.ts +0 -1
- package/configs/schema-all.d.ts +1 -4
- package/configs/schema-recommended.d.ts +8 -2
- package/docs/README.md +2 -2
- package/docs/rules/naming-convention.md +50 -24
- package/docs/rules/possible-type-extension.md +0 -2
- package/docs/rules/require-description.md +2 -0
- package/index.js +62 -28
- package/index.mjs +62 -28
- package/package.json +1 -1
- package/rules/index.d.ts +0 -7
- package/rules/naming-convention.d.ts +0 -1
package/README.md
CHANGED
@@ -180,6 +180,10 @@ You can find a list of [ESLint directives here](https://eslint.org/docs/2.13.1/u
|
|
180
180
|
|
181
181
|
You can find a complete list of [all available rules here](docs/README.md).
|
182
182
|
|
183
|
+
## Deprecated Rules
|
184
|
+
|
185
|
+
See [docs/deprecated-rules.md](docs/deprecated-rules.md).
|
186
|
+
|
183
187
|
## Available Configs
|
184
188
|
|
185
189
|
<!-- prettier-ignore-start -->
|
@@ -187,10 +191,16 @@ You can find a complete list of [all available rules here](docs/README.md).
|
|
187
191
|
|:-:|-|
|
188
192
|
|[`schema-recommended`](packages/plugin/src/configs/schema-recommended.ts)|enables all recommended rules|
|
189
193
|
|[`operations-recommended`](packages/plugin/src/configs/operations-recommended.ts) |enables all recommended rules|
|
190
|
-
|[`schema-all`](packages/plugin/src/configs/schema-all.ts)|enables all rules
|
194
|
+
|[`schema-all`](packages/plugin/src/configs/schema-all.ts)|enables all rules, except for those that require `parserOptions.operations` option)|
|
191
195
|
|[`operations-all`](packages/plugin/src/configs/operations-all.ts)|enables all rules|
|
192
196
|
<!-- prettier-ignore-end -->
|
193
197
|
|
198
|
+
> If you are in a project that develops the GraphQL schema, you'll need `schema` rules.
|
199
|
+
|
200
|
+
> If you are in a project that develops GraphQL operations (query/mutation/subscription), you'll need `operations` rules.
|
201
|
+
|
202
|
+
> If you are in a monorepo project, you probably need both sets of rules.
|
203
|
+
|
194
204
|
## Config usage
|
195
205
|
|
196
206
|
For example, to enable the `schema-recommended` config, enable it in your `.eslintrc` file with the `extends` option:
|
package/configs/index.d.ts
CHANGED
@@ -13,7 +13,10 @@ export declare const configs: {
|
|
13
13
|
'@graphql-eslint/lone-schema-definition': string;
|
14
14
|
'@graphql-eslint/naming-convention': (string | {
|
15
15
|
types: string;
|
16
|
-
|
16
|
+
FieldDefinition: string;
|
17
|
+
InputValueDefinition: string;
|
18
|
+
Argument: string;
|
19
|
+
DirectiveDefinition: string;
|
17
20
|
EnumValueDefinition: string;
|
18
21
|
'FieldDefinition[parent.name.value=Query]': {
|
19
22
|
forbiddenPrefixes: string[];
|
@@ -32,9 +35,12 @@ export declare const configs: {
|
|
32
35
|
'@graphql-eslint/no-hashtag-description': string;
|
33
36
|
'@graphql-eslint/no-typename-prefix': string;
|
34
37
|
'@graphql-eslint/no-unreachable-types': string;
|
35
|
-
'@graphql-eslint/possible-type-extension': string;
|
36
38
|
'@graphql-eslint/provided-required-arguments': string;
|
37
39
|
'@graphql-eslint/require-deprecation-reason': string;
|
40
|
+
'@graphql-eslint/require-description': (string | {
|
41
|
+
types: boolean;
|
42
|
+
DirectiveDefinition: boolean;
|
43
|
+
})[];
|
38
44
|
'@graphql-eslint/strict-id-in-types': string;
|
39
45
|
'@graphql-eslint/unique-directive-names': string;
|
40
46
|
'@graphql-eslint/unique-directive-names-per-location': string;
|
@@ -56,11 +62,8 @@ export declare const configs: {
|
|
56
62
|
'@graphql-eslint/no-root-type': string;
|
57
63
|
'@graphql-eslint/no-scalar-result-type-on-mutation': string;
|
58
64
|
'@graphql-eslint/no-unused-fields': string;
|
65
|
+
'@graphql-eslint/possible-type-extension': string;
|
59
66
|
'@graphql-eslint/require-deprecation-date': string;
|
60
|
-
'@graphql-eslint/require-description': (string | {
|
61
|
-
types: boolean;
|
62
|
-
DirectiveDefinition: boolean;
|
63
|
-
})[];
|
64
67
|
'@graphql-eslint/require-field-of-type-query-in-mutation-result': string;
|
65
68
|
};
|
66
69
|
};
|
@@ -76,7 +79,6 @@ export declare const configs: {
|
|
76
79
|
'@graphql-eslint/known-type-names': string;
|
77
80
|
'@graphql-eslint/lone-anonymous-operation': string;
|
78
81
|
'@graphql-eslint/naming-convention': (string | {
|
79
|
-
Argument: string;
|
80
82
|
VariableDefinition: string;
|
81
83
|
OperationDefinition: {
|
82
84
|
style: string;
|
@@ -10,7 +10,6 @@ declare const _default: {
|
|
10
10
|
'@graphql-eslint/known-type-names': string;
|
11
11
|
'@graphql-eslint/lone-anonymous-operation': string;
|
12
12
|
'@graphql-eslint/naming-convention': (string | {
|
13
|
-
Argument: string;
|
14
13
|
VariableDefinition: string;
|
15
14
|
OperationDefinition: {
|
16
15
|
style: string;
|
package/configs/schema-all.d.ts
CHANGED
@@ -10,11 +10,8 @@ declare const _default: {
|
|
10
10
|
'@graphql-eslint/no-root-type': string;
|
11
11
|
'@graphql-eslint/no-scalar-result-type-on-mutation': string;
|
12
12
|
'@graphql-eslint/no-unused-fields': string;
|
13
|
+
'@graphql-eslint/possible-type-extension': string;
|
13
14
|
'@graphql-eslint/require-deprecation-date': string;
|
14
|
-
'@graphql-eslint/require-description': (string | {
|
15
|
-
types: boolean;
|
16
|
-
DirectiveDefinition: boolean;
|
17
|
-
})[];
|
18
15
|
'@graphql-eslint/require-field-of-type-query-in-mutation-result': string;
|
19
16
|
};
|
20
17
|
};
|
@@ -8,7 +8,10 @@ declare const _default: {
|
|
8
8
|
'@graphql-eslint/lone-schema-definition': string;
|
9
9
|
'@graphql-eslint/naming-convention': (string | {
|
10
10
|
types: string;
|
11
|
-
|
11
|
+
FieldDefinition: string;
|
12
|
+
InputValueDefinition: string;
|
13
|
+
Argument: string;
|
14
|
+
DirectiveDefinition: string;
|
12
15
|
EnumValueDefinition: string;
|
13
16
|
'FieldDefinition[parent.name.value=Query]': {
|
14
17
|
forbiddenPrefixes: string[];
|
@@ -27,9 +30,12 @@ declare const _default: {
|
|
27
30
|
'@graphql-eslint/no-hashtag-description': string;
|
28
31
|
'@graphql-eslint/no-typename-prefix': string;
|
29
32
|
'@graphql-eslint/no-unreachable-types': string;
|
30
|
-
'@graphql-eslint/possible-type-extension': string;
|
31
33
|
'@graphql-eslint/provided-required-arguments': string;
|
32
34
|
'@graphql-eslint/require-deprecation-reason': string;
|
35
|
+
'@graphql-eslint/require-description': (string | {
|
36
|
+
types: boolean;
|
37
|
+
DirectiveDefinition: boolean;
|
38
|
+
})[];
|
33
39
|
'@graphql-eslint/strict-id-in-types': string;
|
34
40
|
'@graphql-eslint/unique-directive-names': string;
|
35
41
|
'@graphql-eslint/unique-directive-names-per-location': string;
|
package/docs/README.md
CHANGED
@@ -42,11 +42,11 @@ Name &nbs
|
|
42
42
|
[one-field-subscriptions](rules/one-field-subscriptions.md)|A GraphQL subscription is valid only if it contains a single root field.|🔮||✅
|
43
43
|
[overlapping-fields-can-be-merged](rules/overlapping-fields-can-be-merged.md)|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.|🔮||✅
|
44
44
|
[possible-fragment-spread](rules/possible-fragment-spread.md)|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.|🔮||✅
|
45
|
-
[possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind
|
45
|
+
[possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind.|🔮||
|
46
46
|
[provided-required-arguments](rules/provided-required-arguments.md)|A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.|🔮||✅
|
47
47
|
[require-deprecation-date](rules/require-deprecation-date.md)|Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.|🚀||
|
48
48
|
[require-deprecation-reason](rules/require-deprecation-reason.md)|Require all deprecation directives to specify a reason.|🚀||✅
|
49
|
-
[require-description](rules/require-description.md)|Enforce descriptions in your type definitions
|
49
|
+
[require-description](rules/require-description.md)|Enforce descriptions in your type definitions.|🚀||✅
|
50
50
|
[require-field-of-type-query-in-mutation-result](rules/require-field-of-type-query-in-mutation-result.md)|Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.|🚀||
|
51
51
|
[require-id-when-available](rules/require-id-when-available.md)|Enforce selecting specific fields when they are available on the GraphQL type.|🚀||✅
|
52
52
|
[scalar-leafs](rules/scalar-leafs.md)|A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.|🔮||✅
|
@@ -14,23 +14,63 @@ Require names to follow specified conventions.
|
|
14
14
|
### Incorrect
|
15
15
|
|
16
16
|
```graphql
|
17
|
-
# eslint @graphql-eslint/naming-convention: ['error', { types: 'PascalCase',
|
17
|
+
# eslint @graphql-eslint/naming-convention: ['error', { types: 'PascalCase', FieldDefinition: 'camelCase' }]
|
18
18
|
|
19
19
|
type user {
|
20
20
|
first_name: String!
|
21
21
|
}
|
22
22
|
```
|
23
23
|
|
24
|
+
### Incorrect
|
25
|
+
|
26
|
+
```graphql
|
27
|
+
# eslint @graphql-eslint/naming-convention: ['error', { FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }]
|
28
|
+
|
29
|
+
fragment UserFragment on User {
|
30
|
+
# ...
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
### Incorrect
|
35
|
+
|
36
|
+
```graphql
|
37
|
+
# eslint @graphql-eslint/naming-convention: ['error', { 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }]
|
38
|
+
|
39
|
+
type Query {
|
40
|
+
getUsers: [User!]!
|
41
|
+
}
|
42
|
+
```
|
43
|
+
|
24
44
|
### Correct
|
25
45
|
|
26
46
|
```graphql
|
27
|
-
# eslint @graphql-eslint/naming-convention: ['error', { types: 'PascalCase',
|
47
|
+
# eslint @graphql-eslint/naming-convention: ['error', { types: 'PascalCase', FieldDefinition: 'camelCase' }]
|
28
48
|
|
29
49
|
type User {
|
30
50
|
firstName: String
|
31
51
|
}
|
32
52
|
```
|
33
53
|
|
54
|
+
### Correct
|
55
|
+
|
56
|
+
```graphql
|
57
|
+
# eslint @graphql-eslint/naming-convention: ['error', { FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }]
|
58
|
+
|
59
|
+
fragment UserFields on User {
|
60
|
+
# ...
|
61
|
+
}
|
62
|
+
```
|
63
|
+
|
64
|
+
### Correct
|
65
|
+
|
66
|
+
```graphql
|
67
|
+
# eslint @graphql-eslint/naming-convention: ['error', { 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }]
|
68
|
+
|
69
|
+
type Query {
|
70
|
+
users: [User!]!
|
71
|
+
}
|
72
|
+
```
|
73
|
+
|
34
74
|
## Config Schema
|
35
75
|
|
36
76
|
> It's possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with allowed `ASTNode` names which are described below.
|
@@ -41,14 +81,6 @@ type User {
|
|
41
81
|
|
42
82
|
The schema defines the following properties:
|
43
83
|
|
44
|
-
### `allowLeadingUnderscore` (boolean)
|
45
|
-
|
46
|
-
Default: `false`
|
47
|
-
|
48
|
-
### `allowTrailingUnderscore` (boolean)
|
49
|
-
|
50
|
-
Default: `false`
|
51
|
-
|
52
84
|
### `types`
|
53
85
|
|
54
86
|
Includes:
|
@@ -65,20 +97,6 @@ The object must be one of the following types:
|
|
65
97
|
* `asString`
|
66
98
|
* `asObject`
|
67
99
|
|
68
|
-
### `fields`
|
69
|
-
|
70
|
-
Includes:
|
71
|
-
|
72
|
-
- `FieldDefinition`
|
73
|
-
- `InputValueDefinition`
|
74
|
-
- `Argument`
|
75
|
-
- `DirectiveDefinition`
|
76
|
-
|
77
|
-
The object must be one of the following types:
|
78
|
-
|
79
|
-
* `asString`
|
80
|
-
* `asObject`
|
81
|
-
|
82
100
|
### `Argument`
|
83
101
|
|
84
102
|
Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#Argument).
|
@@ -205,6 +223,14 @@ The object must be one of the following types:
|
|
205
223
|
* `asString`
|
206
224
|
* `asObject`
|
207
225
|
|
226
|
+
### `allowLeadingUnderscore` (boolean)
|
227
|
+
|
228
|
+
Default: `false`
|
229
|
+
|
230
|
+
### `allowTrailingUnderscore` (boolean)
|
231
|
+
|
232
|
+
Default: `false`
|
233
|
+
|
208
234
|
---
|
209
235
|
|
210
236
|
# Sub Schemas
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# `possible-type-extension`
|
2
2
|
|
3
|
-
✅ The `"extends": "plugin:@graphql-eslint/schema-recommended"` property in a configuration file enables this rule.
|
4
|
-
|
5
3
|
- Category: `Schema`
|
6
4
|
- Rule name: `@graphql-eslint/possible-type-extension`
|
7
5
|
- Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# `require-description`
|
2
2
|
|
3
|
+
✅ The `"extends": "plugin:@graphql-eslint/schema-recommended"` property in a configuration file enables this rule.
|
4
|
+
|
3
5
|
- Category: `Schema`
|
4
6
|
- Rule name: `@graphql-eslint/require-description`
|
5
7
|
- Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
|
package/index.js
CHANGED
@@ -38,7 +38,10 @@ const schemaRecommendedConfig = {
|
|
38
38
|
'error',
|
39
39
|
{
|
40
40
|
types: 'PascalCase',
|
41
|
-
|
41
|
+
FieldDefinition: 'camelCase',
|
42
|
+
InputValueDefinition: 'camelCase',
|
43
|
+
Argument: 'camelCase',
|
44
|
+
DirectiveDefinition: 'camelCase',
|
42
45
|
EnumValueDefinition: 'UPPER_CASE',
|
43
46
|
'FieldDefinition[parent.name.value=Query]': {
|
44
47
|
forbiddenPrefixes: ['query', 'get'],
|
@@ -58,9 +61,9 @@ const schemaRecommendedConfig = {
|
|
58
61
|
'@graphql-eslint/no-hashtag-description': 'error',
|
59
62
|
'@graphql-eslint/no-typename-prefix': 'error',
|
60
63
|
'@graphql-eslint/no-unreachable-types': 'error',
|
61
|
-
'@graphql-eslint/possible-type-extension': 'error',
|
62
64
|
'@graphql-eslint/provided-required-arguments': 'error',
|
63
65
|
'@graphql-eslint/require-deprecation-reason': 'error',
|
66
|
+
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
64
67
|
'@graphql-eslint/strict-id-in-types': 'error',
|
65
68
|
'@graphql-eslint/unique-directive-names': 'error',
|
66
69
|
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
@@ -89,8 +92,8 @@ const schemaAllConfig = {
|
|
89
92
|
'@graphql-eslint/no-root-type': 'off',
|
90
93
|
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
91
94
|
'@graphql-eslint/no-unused-fields': 'off',
|
95
|
+
'@graphql-eslint/possible-type-extension': 'off',
|
92
96
|
'@graphql-eslint/require-deprecation-date': 'error',
|
93
|
-
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
94
97
|
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
95
98
|
},
|
96
99
|
};
|
@@ -112,7 +115,6 @@ const operationsRecommendedConfig = {
|
|
112
115
|
'@graphql-eslint/naming-convention': [
|
113
116
|
'error',
|
114
117
|
{
|
115
|
-
Argument: 'camelCase',
|
116
118
|
VariableDefinition: 'camelCase',
|
117
119
|
OperationDefinition: {
|
118
120
|
style: 'PascalCase',
|
@@ -385,9 +387,9 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
385
387
|
[name]: {
|
386
388
|
meta: {
|
387
389
|
docs: {
|
390
|
+
recommended: true,
|
388
391
|
...docs,
|
389
392
|
graphQLJSRuleName: ruleName,
|
390
|
-
recommended: true,
|
391
393
|
requiresSchema,
|
392
394
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
393
395
|
description: `${docs.description}\n\n> This rule is a wrapper around a \`graphql-js\` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/${ruleName}Rule.ts).`,
|
@@ -563,6 +565,7 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
563
565
|
category: 'Schema',
|
564
566
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
565
567
|
requiresSchema: false,
|
568
|
+
recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
|
566
569
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
567
570
|
category: ['Schema', 'Operations'],
|
568
571
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
@@ -1248,7 +1251,6 @@ const rule$3 = {
|
|
1248
1251
|
},
|
1249
1252
|
};
|
1250
1253
|
|
1251
|
-
const FIELDS_KINDS = [graphql.Kind.FIELD_DEFINITION, graphql.Kind.INPUT_VALUE_DEFINITION, graphql.Kind.ARGUMENT, graphql.Kind.DIRECTIVE_DEFINITION];
|
1252
1254
|
const KindToDisplayName = {
|
1253
1255
|
// types
|
1254
1256
|
[graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
@@ -1290,20 +1292,56 @@ const rule$4 = {
|
|
1290
1292
|
examples: [
|
1291
1293
|
{
|
1292
1294
|
title: 'Incorrect',
|
1293
|
-
usage: [{ types: 'PascalCase',
|
1295
|
+
usage: [{ types: 'PascalCase', FieldDefinition: 'camelCase' }],
|
1294
1296
|
code: /* GraphQL */ `
|
1295
1297
|
type user {
|
1296
1298
|
first_name: String!
|
1297
1299
|
}
|
1300
|
+
`,
|
1301
|
+
},
|
1302
|
+
{
|
1303
|
+
title: 'Incorrect',
|
1304
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1305
|
+
code: /* GraphQL */ `
|
1306
|
+
fragment UserFragment on User {
|
1307
|
+
# ...
|
1308
|
+
}
|
1309
|
+
`,
|
1310
|
+
},
|
1311
|
+
{
|
1312
|
+
title: 'Incorrect',
|
1313
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1314
|
+
code: /* GraphQL */ `
|
1315
|
+
type Query {
|
1316
|
+
getUsers: [User!]!
|
1317
|
+
}
|
1298
1318
|
`,
|
1299
1319
|
},
|
1300
1320
|
{
|
1301
1321
|
title: 'Correct',
|
1302
|
-
usage: [{ types: 'PascalCase',
|
1322
|
+
usage: [{ types: 'PascalCase', FieldDefinition: 'camelCase' }],
|
1303
1323
|
code: /* GraphQL */ `
|
1304
1324
|
type User {
|
1305
1325
|
firstName: String
|
1306
1326
|
}
|
1327
|
+
`,
|
1328
|
+
},
|
1329
|
+
{
|
1330
|
+
title: 'Correct',
|
1331
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1332
|
+
code: /* GraphQL */ `
|
1333
|
+
fragment UserFields on User {
|
1334
|
+
# ...
|
1335
|
+
}
|
1336
|
+
`,
|
1337
|
+
},
|
1338
|
+
{
|
1339
|
+
title: 'Correct',
|
1340
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1341
|
+
code: /* GraphQL */ `
|
1342
|
+
type Query {
|
1343
|
+
users: [User!]!
|
1344
|
+
}
|
1307
1345
|
`,
|
1308
1346
|
},
|
1309
1347
|
],
|
@@ -1311,7 +1349,10 @@ const rule$4 = {
|
|
1311
1349
|
schema: [
|
1312
1350
|
{
|
1313
1351
|
types: 'PascalCase',
|
1314
|
-
|
1352
|
+
FieldDefinition: 'camelCase',
|
1353
|
+
InputValueDefinition: 'camelCase',
|
1354
|
+
Argument: 'camelCase',
|
1355
|
+
DirectiveDefinition: 'camelCase',
|
1315
1356
|
EnumValueDefinition: 'UPPER_CASE',
|
1316
1357
|
'FieldDefinition[parent.name.value=Query]': {
|
1317
1358
|
forbiddenPrefixes: ['query', 'get'],
|
@@ -1329,7 +1370,6 @@ const rule$4 = {
|
|
1329
1370
|
],
|
1330
1371
|
operations: [
|
1331
1372
|
{
|
1332
|
-
Argument: 'camelCase',
|
1333
1373
|
VariableDefinition: 'camelCase',
|
1334
1374
|
OperationDefinition: {
|
1335
1375
|
style: 'PascalCase',
|
@@ -1379,22 +1419,10 @@ const rule$4 = {
|
|
1379
1419
|
type: 'object',
|
1380
1420
|
additionalProperties: false,
|
1381
1421
|
properties: {
|
1382
|
-
allowLeadingUnderscore: {
|
1383
|
-
type: 'boolean',
|
1384
|
-
default: false,
|
1385
|
-
},
|
1386
|
-
allowTrailingUnderscore: {
|
1387
|
-
type: 'boolean',
|
1388
|
-
default: false,
|
1389
|
-
},
|
1390
1422
|
types: {
|
1391
1423
|
...schemaOption$1,
|
1392
1424
|
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1393
1425
|
},
|
1394
|
-
fields: {
|
1395
|
-
...schemaOption$1,
|
1396
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1397
|
-
},
|
1398
1426
|
...Object.fromEntries(ALLOWED_KINDS.map(kind => [
|
1399
1427
|
kind,
|
1400
1428
|
{
|
@@ -1402,6 +1430,14 @@ const rule$4 = {
|
|
1402
1430
|
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
1403
1431
|
},
|
1404
1432
|
])),
|
1433
|
+
allowLeadingUnderscore: {
|
1434
|
+
type: 'boolean',
|
1435
|
+
default: false,
|
1436
|
+
},
|
1437
|
+
allowTrailingUnderscore: {
|
1438
|
+
type: 'boolean',
|
1439
|
+
default: false,
|
1440
|
+
},
|
1405
1441
|
},
|
1406
1442
|
patternProperties: {
|
1407
1443
|
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
@@ -1418,12 +1454,9 @@ const rule$4 = {
|
|
1418
1454
|
},
|
1419
1455
|
create(context) {
|
1420
1456
|
const options = context.options[0] || {};
|
1421
|
-
const { allowLeadingUnderscore, allowTrailingUnderscore, types,
|
1457
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
1422
1458
|
function normalisePropertyOption(kind) {
|
1423
|
-
|
1424
|
-
if (!style) {
|
1425
|
-
style = TYPES_KINDS.includes(kind) ? types : fields;
|
1426
|
-
}
|
1459
|
+
const style = restOptions[kind] || types;
|
1427
1460
|
return typeof style === 'object' ? style : { style };
|
1428
1461
|
}
|
1429
1462
|
const checkNode = (selector) => (node) => {
|
@@ -1486,7 +1519,7 @@ const rule$4 = {
|
|
1486
1519
|
if (!allowTrailingUnderscore) {
|
1487
1520
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1488
1521
|
}
|
1489
|
-
const selectors = new Set([types && TYPES_KINDS,
|
1522
|
+
const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1490
1523
|
for (const selector of selectors) {
|
1491
1524
|
listeners[selector] = checkNode(selector);
|
1492
1525
|
}
|
@@ -2554,6 +2587,7 @@ const rule$h = {
|
|
2554
2587
|
[graphql.Kind.DIRECTIVE_DEFINITION]: true,
|
2555
2588
|
},
|
2556
2589
|
],
|
2590
|
+
recommended: true,
|
2557
2591
|
},
|
2558
2592
|
type: 'suggestion',
|
2559
2593
|
messages: {
|
package/index.mjs
CHANGED
@@ -32,7 +32,10 @@ const schemaRecommendedConfig = {
|
|
32
32
|
'error',
|
33
33
|
{
|
34
34
|
types: 'PascalCase',
|
35
|
-
|
35
|
+
FieldDefinition: 'camelCase',
|
36
|
+
InputValueDefinition: 'camelCase',
|
37
|
+
Argument: 'camelCase',
|
38
|
+
DirectiveDefinition: 'camelCase',
|
36
39
|
EnumValueDefinition: 'UPPER_CASE',
|
37
40
|
'FieldDefinition[parent.name.value=Query]': {
|
38
41
|
forbiddenPrefixes: ['query', 'get'],
|
@@ -52,9 +55,9 @@ const schemaRecommendedConfig = {
|
|
52
55
|
'@graphql-eslint/no-hashtag-description': 'error',
|
53
56
|
'@graphql-eslint/no-typename-prefix': 'error',
|
54
57
|
'@graphql-eslint/no-unreachable-types': 'error',
|
55
|
-
'@graphql-eslint/possible-type-extension': 'error',
|
56
58
|
'@graphql-eslint/provided-required-arguments': 'error',
|
57
59
|
'@graphql-eslint/require-deprecation-reason': 'error',
|
60
|
+
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
58
61
|
'@graphql-eslint/strict-id-in-types': 'error',
|
59
62
|
'@graphql-eslint/unique-directive-names': 'error',
|
60
63
|
'@graphql-eslint/unique-directive-names-per-location': 'error',
|
@@ -83,8 +86,8 @@ const schemaAllConfig = {
|
|
83
86
|
'@graphql-eslint/no-root-type': 'off',
|
84
87
|
'@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
|
85
88
|
'@graphql-eslint/no-unused-fields': 'off',
|
89
|
+
'@graphql-eslint/possible-type-extension': 'off',
|
86
90
|
'@graphql-eslint/require-deprecation-date': 'error',
|
87
|
-
'@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
|
88
91
|
'@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
|
89
92
|
},
|
90
93
|
};
|
@@ -106,7 +109,6 @@ const operationsRecommendedConfig = {
|
|
106
109
|
'@graphql-eslint/naming-convention': [
|
107
110
|
'error',
|
108
111
|
{
|
109
|
-
Argument: 'camelCase',
|
110
112
|
VariableDefinition: 'camelCase',
|
111
113
|
OperationDefinition: {
|
112
114
|
style: 'PascalCase',
|
@@ -379,9 +381,9 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
379
381
|
[name]: {
|
380
382
|
meta: {
|
381
383
|
docs: {
|
384
|
+
recommended: true,
|
382
385
|
...docs,
|
383
386
|
graphQLJSRuleName: ruleName,
|
384
|
-
recommended: true,
|
385
387
|
requiresSchema,
|
386
388
|
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
387
389
|
description: `${docs.description}\n\n> This rule is a wrapper around a \`graphql-js\` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/${ruleName}Rule.ts).`,
|
@@ -557,6 +559,7 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
557
559
|
category: 'Schema',
|
558
560
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
559
561
|
requiresSchema: false,
|
562
|
+
recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
|
560
563
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
561
564
|
category: ['Schema', 'Operations'],
|
562
565
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
@@ -1242,7 +1245,6 @@ const rule$3 = {
|
|
1242
1245
|
},
|
1243
1246
|
};
|
1244
1247
|
|
1245
|
-
const FIELDS_KINDS = [Kind.FIELD_DEFINITION, Kind.INPUT_VALUE_DEFINITION, Kind.ARGUMENT, Kind.DIRECTIVE_DEFINITION];
|
1246
1248
|
const KindToDisplayName = {
|
1247
1249
|
// types
|
1248
1250
|
[Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
@@ -1284,20 +1286,56 @@ const rule$4 = {
|
|
1284
1286
|
examples: [
|
1285
1287
|
{
|
1286
1288
|
title: 'Incorrect',
|
1287
|
-
usage: [{ types: 'PascalCase',
|
1289
|
+
usage: [{ types: 'PascalCase', FieldDefinition: 'camelCase' }],
|
1288
1290
|
code: /* GraphQL */ `
|
1289
1291
|
type user {
|
1290
1292
|
first_name: String!
|
1291
1293
|
}
|
1294
|
+
`,
|
1295
|
+
},
|
1296
|
+
{
|
1297
|
+
title: 'Incorrect',
|
1298
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1299
|
+
code: /* GraphQL */ `
|
1300
|
+
fragment UserFragment on User {
|
1301
|
+
# ...
|
1302
|
+
}
|
1303
|
+
`,
|
1304
|
+
},
|
1305
|
+
{
|
1306
|
+
title: 'Incorrect',
|
1307
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1308
|
+
code: /* GraphQL */ `
|
1309
|
+
type Query {
|
1310
|
+
getUsers: [User!]!
|
1311
|
+
}
|
1292
1312
|
`,
|
1293
1313
|
},
|
1294
1314
|
{
|
1295
1315
|
title: 'Correct',
|
1296
|
-
usage: [{ types: 'PascalCase',
|
1316
|
+
usage: [{ types: 'PascalCase', FieldDefinition: 'camelCase' }],
|
1297
1317
|
code: /* GraphQL */ `
|
1298
1318
|
type User {
|
1299
1319
|
firstName: String
|
1300
1320
|
}
|
1321
|
+
`,
|
1322
|
+
},
|
1323
|
+
{
|
1324
|
+
title: 'Correct',
|
1325
|
+
usage: [{ FragmentDefinition: { style: 'PascalCase', forbiddenSuffixes: ['Fragment'] } }],
|
1326
|
+
code: /* GraphQL */ `
|
1327
|
+
fragment UserFields on User {
|
1328
|
+
# ...
|
1329
|
+
}
|
1330
|
+
`,
|
1331
|
+
},
|
1332
|
+
{
|
1333
|
+
title: 'Correct',
|
1334
|
+
usage: [{ 'FieldDefinition[parent.name.value=Query]': { forbiddenPrefixes: ['get'] } }],
|
1335
|
+
code: /* GraphQL */ `
|
1336
|
+
type Query {
|
1337
|
+
users: [User!]!
|
1338
|
+
}
|
1301
1339
|
`,
|
1302
1340
|
},
|
1303
1341
|
],
|
@@ -1305,7 +1343,10 @@ const rule$4 = {
|
|
1305
1343
|
schema: [
|
1306
1344
|
{
|
1307
1345
|
types: 'PascalCase',
|
1308
|
-
|
1346
|
+
FieldDefinition: 'camelCase',
|
1347
|
+
InputValueDefinition: 'camelCase',
|
1348
|
+
Argument: 'camelCase',
|
1349
|
+
DirectiveDefinition: 'camelCase',
|
1309
1350
|
EnumValueDefinition: 'UPPER_CASE',
|
1310
1351
|
'FieldDefinition[parent.name.value=Query]': {
|
1311
1352
|
forbiddenPrefixes: ['query', 'get'],
|
@@ -1323,7 +1364,6 @@ const rule$4 = {
|
|
1323
1364
|
],
|
1324
1365
|
operations: [
|
1325
1366
|
{
|
1326
|
-
Argument: 'camelCase',
|
1327
1367
|
VariableDefinition: 'camelCase',
|
1328
1368
|
OperationDefinition: {
|
1329
1369
|
style: 'PascalCase',
|
@@ -1373,22 +1413,10 @@ const rule$4 = {
|
|
1373
1413
|
type: 'object',
|
1374
1414
|
additionalProperties: false,
|
1375
1415
|
properties: {
|
1376
|
-
allowLeadingUnderscore: {
|
1377
|
-
type: 'boolean',
|
1378
|
-
default: false,
|
1379
|
-
},
|
1380
|
-
allowTrailingUnderscore: {
|
1381
|
-
type: 'boolean',
|
1382
|
-
default: false,
|
1383
|
-
},
|
1384
1416
|
types: {
|
1385
1417
|
...schemaOption$1,
|
1386
1418
|
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1387
1419
|
},
|
1388
|
-
fields: {
|
1389
|
-
...schemaOption$1,
|
1390
|
-
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1391
|
-
},
|
1392
1420
|
...Object.fromEntries(ALLOWED_KINDS.map(kind => [
|
1393
1421
|
kind,
|
1394
1422
|
{
|
@@ -1396,6 +1424,14 @@ const rule$4 = {
|
|
1396
1424
|
description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`,
|
1397
1425
|
},
|
1398
1426
|
])),
|
1427
|
+
allowLeadingUnderscore: {
|
1428
|
+
type: 'boolean',
|
1429
|
+
default: false,
|
1430
|
+
},
|
1431
|
+
allowTrailingUnderscore: {
|
1432
|
+
type: 'boolean',
|
1433
|
+
default: false,
|
1434
|
+
},
|
1399
1435
|
},
|
1400
1436
|
patternProperties: {
|
1401
1437
|
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
@@ -1412,12 +1448,9 @@ const rule$4 = {
|
|
1412
1448
|
},
|
1413
1449
|
create(context) {
|
1414
1450
|
const options = context.options[0] || {};
|
1415
|
-
const { allowLeadingUnderscore, allowTrailingUnderscore, types,
|
1451
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
1416
1452
|
function normalisePropertyOption(kind) {
|
1417
|
-
|
1418
|
-
if (!style) {
|
1419
|
-
style = TYPES_KINDS.includes(kind) ? types : fields;
|
1420
|
-
}
|
1453
|
+
const style = restOptions[kind] || types;
|
1421
1454
|
return typeof style === 'object' ? style : { style };
|
1422
1455
|
}
|
1423
1456
|
const checkNode = (selector) => (node) => {
|
@@ -1480,7 +1513,7 @@ const rule$4 = {
|
|
1480
1513
|
if (!allowTrailingUnderscore) {
|
1481
1514
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1482
1515
|
}
|
1483
|
-
const selectors = new Set([types && TYPES_KINDS,
|
1516
|
+
const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1484
1517
|
for (const selector of selectors) {
|
1485
1518
|
listeners[selector] = checkNode(selector);
|
1486
1519
|
}
|
@@ -2548,6 +2581,7 @@ const rule$h = {
|
|
2548
2581
|
[Kind.DIRECTIVE_DEFINITION]: true,
|
2549
2582
|
},
|
2550
2583
|
],
|
2584
|
+
recommended: true,
|
2551
2585
|
},
|
2552
2586
|
type: 'suggestion',
|
2553
2587
|
messages: {
|
package/package.json
CHANGED
package/rules/index.d.ts
CHANGED
@@ -44,13 +44,6 @@ export declare const rules: {
|
|
44
44
|
forbiddenPrefixes?: string[];
|
45
45
|
forbiddenSuffixes?: string[];
|
46
46
|
};
|
47
|
-
fields?: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
48
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
49
|
-
suffix?: string;
|
50
|
-
prefix?: string;
|
51
|
-
forbiddenPrefixes?: string[];
|
52
|
-
forbiddenSuffixes?: string[];
|
53
|
-
};
|
54
47
|
} & {
|
55
48
|
[x: `OperationDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
56
49
|
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|