@graphql-eslint/eslint-plugin 4.3.0 → 4.3.1-alpha-20241207204625-6a4230707a78900a6339b03afe904b9dd6c31561
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/cjs/cache.js +6 -2
- package/cjs/configs/operations-all.js +2 -2
- package/cjs/configs/schema-all.js +2 -2
- package/cjs/configs/schema-recommended.js +1 -1
- package/cjs/documents.js +13 -7
- package/cjs/estree-converter/converter.js +17 -8
- package/cjs/estree-converter/utils.js +22 -9
- package/cjs/graphql-config.js +13 -6
- package/cjs/index.d.cts +18 -4
- package/cjs/meta.js +1 -1
- package/cjs/parser.js +36 -9
- package/cjs/processor.js +48 -20
- package/cjs/rules/alphabetize/index.js +99 -47
- package/cjs/rules/description-style/index.js +10 -6
- package/cjs/rules/graphql-js-validation.js +142 -108
- package/cjs/rules/index.d.cts +18 -4
- package/cjs/rules/input-name/index.js +51 -38
- package/cjs/rules/lone-executable-definition/index.js +15 -6
- package/cjs/rules/match-document-filename/index.d.cts +4 -3
- package/cjs/rules/match-document-filename/index.js +63 -37
- package/cjs/rules/naming-convention/index.d.cts +6 -10
- package/cjs/rules/naming-convention/index.js +146 -57
- package/cjs/rules/no-anonymous-operations/index.js +8 -5
- package/cjs/rules/no-deprecated/index.js +27 -13
- package/cjs/rules/no-duplicate-fields/index.js +15 -8
- package/cjs/rules/no-hashtag-description/index.js +18 -10
- package/cjs/rules/no-one-place-fragments/index.js +17 -10
- package/cjs/rules/no-root-type/index.js +15 -8
- package/cjs/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/cjs/rules/no-typename-prefix/index.js +25 -21
- package/cjs/rules/no-unreachable-types/index.js +34 -17
- package/cjs/rules/no-unused-fields/index.js +56 -30
- package/cjs/rules/relay-arguments/index.js +31 -13
- package/cjs/rules/relay-connection-types/index.js +31 -9
- package/cjs/rules/relay-edge-types/index.js +84 -41
- package/cjs/rules/relay-page-info/index.js +31 -14
- package/cjs/rules/require-deprecation-date/index.js +20 -9
- package/cjs/rules/require-deprecation-reason/index.js +8 -5
- package/cjs/rules/require-description/index.d.cts +79 -13
- package/cjs/rules/require-description/index.js +67 -49
- package/cjs/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/cjs/rules/require-import-fragment/index.js +20 -11
- package/cjs/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/cjs/rules/require-nullable-result-in-root/index.js +32 -27
- package/cjs/rules/require-selections/index.js +88 -46
- package/cjs/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/cjs/rules/selection-set-depth/index.js +19 -10
- package/cjs/rules/strict-id-in-types/index.js +32 -19
- package/cjs/rules/unique-enum-value-names/index.js +4 -3
- package/cjs/rules/unique-fragment-name/index.js +25 -18
- package/cjs/rules/unique-operation-name/index.js +5 -5
- package/cjs/schema.js +14 -8
- package/cjs/siblings.js +60 -32
- package/cjs/utils.js +23 -9
- package/esm/cache.js +6 -2
- package/esm/configs/operations-all.js +2 -2
- package/esm/configs/schema-all.js +2 -2
- package/esm/configs/schema-recommended.js +1 -1
- package/esm/documents.js +13 -7
- package/esm/estree-converter/converter.js +17 -8
- package/esm/estree-converter/utils.js +22 -9
- package/esm/graphql-config.js +13 -6
- package/esm/index.d.ts +19 -5
- package/esm/meta.js +1 -1
- package/esm/parser.js +36 -9
- package/esm/processor.js +48 -20
- package/esm/rules/alphabetize/index.js +99 -47
- package/esm/rules/description-style/index.js +10 -6
- package/esm/rules/graphql-js-validation.js +142 -108
- package/esm/rules/index.d.ts +19 -5
- package/esm/rules/input-name/index.js +51 -38
- package/esm/rules/lone-executable-definition/index.js +15 -6
- package/esm/rules/match-document-filename/index.d.ts +4 -3
- package/esm/rules/match-document-filename/index.js +63 -37
- package/esm/rules/naming-convention/index.d.ts +6 -10
- package/esm/rules/naming-convention/index.js +146 -57
- package/esm/rules/no-anonymous-operations/index.js +8 -5
- package/esm/rules/no-deprecated/index.js +27 -13
- package/esm/rules/no-duplicate-fields/index.js +15 -8
- package/esm/rules/no-hashtag-description/index.js +18 -10
- package/esm/rules/no-one-place-fragments/index.js +17 -10
- package/esm/rules/no-root-type/index.js +15 -8
- package/esm/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/esm/rules/no-typename-prefix/index.js +25 -21
- package/esm/rules/no-unreachable-types/index.js +34 -17
- package/esm/rules/no-unused-fields/index.js +56 -30
- package/esm/rules/relay-arguments/index.js +31 -13
- package/esm/rules/relay-connection-types/index.js +31 -9
- package/esm/rules/relay-edge-types/index.js +84 -41
- package/esm/rules/relay-page-info/index.js +31 -14
- package/esm/rules/require-deprecation-date/index.js +20 -9
- package/esm/rules/require-deprecation-reason/index.js +8 -5
- package/esm/rules/require-description/index.d.ts +79 -13
- package/esm/rules/require-description/index.js +67 -49
- package/esm/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/esm/rules/require-import-fragment/index.js +20 -11
- package/esm/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/esm/rules/require-nullable-result-in-root/index.js +32 -27
- package/esm/rules/require-selections/index.js +88 -46
- package/esm/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/esm/rules/selection-set-depth/index.js +19 -10
- package/esm/rules/strict-id-in-types/index.js +32 -19
- package/esm/rules/unique-enum-value-names/index.js +4 -3
- package/esm/rules/unique-fragment-name/index.js +25 -18
- package/esm/rules/unique-operation-name/index.js +5 -5
- package/esm/schema.js +15 -8
- package/esm/siblings.js +60 -32
- package/esm/utils.js +23 -9
- package/index.browser.js +1838 -1135
- package/package.json +1 -1
package/index.browser.js
CHANGED
@@ -1,3 +1,223 @@
|
|
1
|
+
// src/configs/operations-all.ts
|
2
|
+
var operations_all_default = {
|
3
|
+
extends: "./configs/operations-recommended",
|
4
|
+
rules: {
|
5
|
+
"@graphql-eslint/alphabetize": [
|
6
|
+
"error",
|
7
|
+
{
|
8
|
+
definitions: true,
|
9
|
+
selections: ["OperationDefinition", "FragmentDefinition"],
|
10
|
+
variables: true,
|
11
|
+
arguments: ["Field", "Directive"],
|
12
|
+
groups: ["...", "id", "*", "{"]
|
13
|
+
}
|
14
|
+
],
|
15
|
+
"@graphql-eslint/lone-executable-definition": "error",
|
16
|
+
"@graphql-eslint/match-document-filename": [
|
17
|
+
"error",
|
18
|
+
{
|
19
|
+
query: "kebab-case",
|
20
|
+
mutation: "kebab-case",
|
21
|
+
subscription: "kebab-case",
|
22
|
+
fragment: "kebab-case"
|
23
|
+
}
|
24
|
+
],
|
25
|
+
"@graphql-eslint/no-one-place-fragments": "error",
|
26
|
+
"@graphql-eslint/require-import-fragment": "error"
|
27
|
+
}
|
28
|
+
};
|
29
|
+
|
30
|
+
// src/configs/operations-recommended.ts
|
31
|
+
var operations_recommended_default = {
|
32
|
+
parser: "@graphql-eslint/eslint-plugin",
|
33
|
+
plugins: ["@graphql-eslint"],
|
34
|
+
rules: {
|
35
|
+
"@graphql-eslint/executable-definitions": "error",
|
36
|
+
"@graphql-eslint/fields-on-correct-type": "error",
|
37
|
+
"@graphql-eslint/fragments-on-composite-type": "error",
|
38
|
+
"@graphql-eslint/known-argument-names": "error",
|
39
|
+
"@graphql-eslint/known-directives": "error",
|
40
|
+
"@graphql-eslint/known-fragment-names": "error",
|
41
|
+
"@graphql-eslint/known-type-names": "error",
|
42
|
+
"@graphql-eslint/lone-anonymous-operation": "error",
|
43
|
+
"@graphql-eslint/naming-convention": [
|
44
|
+
"error",
|
45
|
+
{
|
46
|
+
VariableDefinition: "camelCase",
|
47
|
+
OperationDefinition: {
|
48
|
+
style: "PascalCase",
|
49
|
+
forbiddenPrefixes: ["Query", "Mutation", "Subscription", "Get"],
|
50
|
+
forbiddenSuffixes: ["Query", "Mutation", "Subscription"]
|
51
|
+
},
|
52
|
+
FragmentDefinition: {
|
53
|
+
style: "PascalCase",
|
54
|
+
forbiddenPrefixes: ["Fragment"],
|
55
|
+
forbiddenSuffixes: ["Fragment"]
|
56
|
+
}
|
57
|
+
}
|
58
|
+
],
|
59
|
+
"@graphql-eslint/no-anonymous-operations": "error",
|
60
|
+
"@graphql-eslint/no-deprecated": "error",
|
61
|
+
"@graphql-eslint/no-duplicate-fields": "error",
|
62
|
+
"@graphql-eslint/no-fragment-cycles": "error",
|
63
|
+
"@graphql-eslint/no-undefined-variables": "error",
|
64
|
+
"@graphql-eslint/no-unused-fragments": "error",
|
65
|
+
"@graphql-eslint/no-unused-variables": "error",
|
66
|
+
"@graphql-eslint/one-field-subscriptions": "error",
|
67
|
+
"@graphql-eslint/overlapping-fields-can-be-merged": "error",
|
68
|
+
"@graphql-eslint/possible-fragment-spread": "error",
|
69
|
+
"@graphql-eslint/provided-required-arguments": "error",
|
70
|
+
"@graphql-eslint/require-selections": "error",
|
71
|
+
"@graphql-eslint/scalar-leafs": "error",
|
72
|
+
"@graphql-eslint/selection-set-depth": ["error", { maxDepth: 7 }],
|
73
|
+
"@graphql-eslint/unique-argument-names": "error",
|
74
|
+
"@graphql-eslint/unique-directive-names-per-location": "error",
|
75
|
+
"@graphql-eslint/unique-fragment-name": "error",
|
76
|
+
"@graphql-eslint/unique-input-field-names": "error",
|
77
|
+
"@graphql-eslint/unique-operation-name": "error",
|
78
|
+
"@graphql-eslint/unique-variable-names": "error",
|
79
|
+
"@graphql-eslint/value-literals-of-correct-type": "error",
|
80
|
+
"@graphql-eslint/variables-are-input-types": "error",
|
81
|
+
"@graphql-eslint/variables-in-allowed-position": "error"
|
82
|
+
}
|
83
|
+
};
|
84
|
+
|
85
|
+
// src/configs/schema-all.ts
|
86
|
+
var schema_all_default = {
|
87
|
+
extends: "./configs/schema-recommended",
|
88
|
+
rules: {
|
89
|
+
"@graphql-eslint/alphabetize": [
|
90
|
+
"error",
|
91
|
+
{
|
92
|
+
definitions: true,
|
93
|
+
fields: ["ObjectTypeDefinition", "InterfaceTypeDefinition", "InputObjectTypeDefinition"],
|
94
|
+
values: true,
|
95
|
+
arguments: ["FieldDefinition", "Field", "DirectiveDefinition", "Directive"],
|
96
|
+
groups: ["id", "*", "createdAt", "updatedAt"]
|
97
|
+
}
|
98
|
+
],
|
99
|
+
"@graphql-eslint/input-name": "error",
|
100
|
+
"@graphql-eslint/no-root-type": ["error", { disallow: ["mutation", "subscription"] }],
|
101
|
+
"@graphql-eslint/no-scalar-result-type-on-mutation": "error",
|
102
|
+
"@graphql-eslint/require-deprecation-date": "error",
|
103
|
+
"@graphql-eslint/require-field-of-type-query-in-mutation-result": "error",
|
104
|
+
"@graphql-eslint/require-nullable-fields-with-oneof": "error",
|
105
|
+
"@graphql-eslint/require-nullable-result-in-root": "error",
|
106
|
+
"@graphql-eslint/require-type-pattern-with-oneof": "error"
|
107
|
+
}
|
108
|
+
};
|
109
|
+
|
110
|
+
// src/configs/schema-recommended.ts
|
111
|
+
var schema_recommended_default = {
|
112
|
+
parser: "@graphql-eslint/eslint-plugin",
|
113
|
+
plugins: ["@graphql-eslint"],
|
114
|
+
rules: {
|
115
|
+
"@graphql-eslint/description-style": "error",
|
116
|
+
"@graphql-eslint/known-argument-names": "error",
|
117
|
+
"@graphql-eslint/known-directives": "error",
|
118
|
+
"@graphql-eslint/known-type-names": "error",
|
119
|
+
"@graphql-eslint/lone-schema-definition": "error",
|
120
|
+
"@graphql-eslint/naming-convention": [
|
121
|
+
"error",
|
122
|
+
{
|
123
|
+
types: "PascalCase",
|
124
|
+
FieldDefinition: "camelCase",
|
125
|
+
InputValueDefinition: "camelCase",
|
126
|
+
Argument: "camelCase",
|
127
|
+
DirectiveDefinition: "camelCase",
|
128
|
+
EnumValueDefinition: "UPPER_CASE",
|
129
|
+
"FieldDefinition[parent.name.value=Query]": {
|
130
|
+
forbiddenPrefixes: ["query", "get"],
|
131
|
+
forbiddenSuffixes: ["Query"]
|
132
|
+
},
|
133
|
+
"FieldDefinition[parent.name.value=Mutation]": {
|
134
|
+
forbiddenPrefixes: ["mutation"],
|
135
|
+
forbiddenSuffixes: ["Mutation"]
|
136
|
+
},
|
137
|
+
"FieldDefinition[parent.name.value=Subscription]": {
|
138
|
+
forbiddenPrefixes: ["subscription"],
|
139
|
+
forbiddenSuffixes: ["Subscription"]
|
140
|
+
},
|
141
|
+
"EnumTypeDefinition,EnumTypeExtension": {
|
142
|
+
forbiddenPrefixes: ["Enum"],
|
143
|
+
forbiddenSuffixes: ["Enum"]
|
144
|
+
},
|
145
|
+
"InterfaceTypeDefinition,InterfaceTypeExtension": {
|
146
|
+
forbiddenPrefixes: ["Interface"],
|
147
|
+
forbiddenSuffixes: ["Interface"]
|
148
|
+
},
|
149
|
+
"UnionTypeDefinition,UnionTypeExtension": {
|
150
|
+
forbiddenPrefixes: ["Union"],
|
151
|
+
forbiddenSuffixes: ["Union"]
|
152
|
+
},
|
153
|
+
"ObjectTypeDefinition,ObjectTypeExtension": {
|
154
|
+
forbiddenPrefixes: ["Type"],
|
155
|
+
forbiddenSuffixes: ["Type"]
|
156
|
+
}
|
157
|
+
}
|
158
|
+
],
|
159
|
+
"@graphql-eslint/no-hashtag-description": "error",
|
160
|
+
"@graphql-eslint/no-typename-prefix": "error",
|
161
|
+
"@graphql-eslint/no-unreachable-types": "error",
|
162
|
+
"@graphql-eslint/possible-type-extension": "error",
|
163
|
+
"@graphql-eslint/provided-required-arguments": "error",
|
164
|
+
"@graphql-eslint/require-deprecation-reason": "error",
|
165
|
+
"@graphql-eslint/require-description": [
|
166
|
+
"error",
|
167
|
+
{ types: true, DirectiveDefinition: true, rootField: true }
|
168
|
+
],
|
169
|
+
"@graphql-eslint/strict-id-in-types": "error",
|
170
|
+
"@graphql-eslint/unique-directive-names": "error",
|
171
|
+
"@graphql-eslint/unique-directive-names-per-location": "error",
|
172
|
+
"@graphql-eslint/unique-enum-value-names": "error",
|
173
|
+
"@graphql-eslint/unique-field-definition-names": "error",
|
174
|
+
"@graphql-eslint/unique-operation-types": "error",
|
175
|
+
"@graphql-eslint/unique-type-names": "error"
|
176
|
+
}
|
177
|
+
};
|
178
|
+
|
179
|
+
// src/configs/schema-relay.ts
|
180
|
+
var schema_relay_default = {
|
181
|
+
parser: "@graphql-eslint/eslint-plugin",
|
182
|
+
plugins: ["@graphql-eslint"],
|
183
|
+
rules: {
|
184
|
+
"@graphql-eslint/relay-arguments": "error",
|
185
|
+
"@graphql-eslint/relay-connection-types": "error",
|
186
|
+
"@graphql-eslint/relay-edge-types": "error",
|
187
|
+
"@graphql-eslint/relay-page-info": "error"
|
188
|
+
}
|
189
|
+
};
|
190
|
+
|
191
|
+
// src/configs/index.ts
|
192
|
+
var configs = {
|
193
|
+
"schema-recommended": schema_recommended_default,
|
194
|
+
"schema-all": schema_all_default,
|
195
|
+
"schema-relay": schema_relay_default,
|
196
|
+
"operations-recommended": operations_recommended_default,
|
197
|
+
"operations-all": operations_all_default,
|
198
|
+
"flat/schema-recommended": {
|
199
|
+
rules: schema_recommended_default.rules
|
200
|
+
},
|
201
|
+
"flat/schema-all": {
|
202
|
+
rules: {
|
203
|
+
...schema_recommended_default.rules,
|
204
|
+
...schema_all_default.rules
|
205
|
+
}
|
206
|
+
},
|
207
|
+
"flat/schema-relay": {
|
208
|
+
rules: schema_relay_default.rules
|
209
|
+
},
|
210
|
+
"flat/operations-recommended": {
|
211
|
+
rules: operations_recommended_default.rules
|
212
|
+
},
|
213
|
+
"flat/operations-all": {
|
214
|
+
rules: {
|
215
|
+
...operations_recommended_default.rules,
|
216
|
+
...operations_all_default.rules
|
217
|
+
}
|
218
|
+
}
|
219
|
+
};
|
220
|
+
|
1
221
|
// src/parser.ts
|
2
222
|
import debugFactory2 from "debug";
|
3
223
|
import { buildSchema, GraphQLError } from "graphql";
|
@@ -5,14 +225,28 @@ import { parseGraphQLSDL } from "@graphql-tools/utils";
|
|
5
225
|
|
6
226
|
// src/cache.ts
|
7
227
|
import debugFactory from "debug";
|
8
|
-
var log = debugFactory("graphql-eslint:ModuleCache")
|
228
|
+
var log = debugFactory("graphql-eslint:ModuleCache");
|
229
|
+
var ModuleCache = class {
|
9
230
|
map = /* @__PURE__ */ new Map();
|
10
231
|
set(cacheKey, result) {
|
232
|
+
if (true) return;
|
233
|
+
this.map.set(cacheKey, { lastSeen: process.hrtime(), result });
|
234
|
+
log("setting entry for", cacheKey);
|
11
235
|
}
|
12
236
|
get(cacheKey, settings = {
|
13
237
|
lifetime: 10
|
14
238
|
/* seconds */
|
15
239
|
}) {
|
240
|
+
if (true) return;
|
241
|
+
const value = this.map.get(cacheKey);
|
242
|
+
if (!value) {
|
243
|
+
log("cache miss for", cacheKey);
|
244
|
+
return;
|
245
|
+
}
|
246
|
+
const { lastSeen, result } = value;
|
247
|
+
if (process.env.NODE || process.hrtime(lastSeen)[0] < settings.lifetime) {
|
248
|
+
return result;
|
249
|
+
}
|
16
250
|
}
|
17
251
|
};
|
18
252
|
|
@@ -33,12 +267,17 @@ import {
|
|
33
267
|
TokenKind
|
34
268
|
} from "graphql";
|
35
269
|
import { valueFromASTUntyped } from "graphql/utilities/valueFromASTUntyped.js";
|
36
|
-
var valueFromNode = (...args) =>
|
270
|
+
var valueFromNode = (...args) => {
|
271
|
+
return valueFromASTUntyped(...args);
|
272
|
+
};
|
37
273
|
function getBaseType(type) {
|
38
|
-
|
274
|
+
if (isNonNullType(type) || isListType(type)) {
|
275
|
+
return getBaseType(type.ofType);
|
276
|
+
}
|
277
|
+
return type;
|
39
278
|
}
|
40
279
|
function convertToken(token, type) {
|
41
|
-
|
280
|
+
const { line, column, end, start, value } = token;
|
42
281
|
return {
|
43
282
|
type,
|
44
283
|
value,
|
@@ -60,20 +299,26 @@ function convertToken(token, type) {
|
|
60
299
|
};
|
61
300
|
}
|
62
301
|
function extractTokens(filePath, code) {
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
302
|
+
const source = new Source(code, filePath);
|
303
|
+
const lexer = new Lexer(source);
|
304
|
+
const tokens = [];
|
305
|
+
let token = lexer.advance();
|
306
|
+
while (token && token.kind !== TokenKind.EOF) {
|
307
|
+
const result = convertToken(token, token.kind);
|
308
|
+
tokens.push(result);
|
309
|
+
token = lexer.advance();
|
67
310
|
}
|
68
311
|
return tokens;
|
69
312
|
}
|
70
313
|
function extractComments(loc) {
|
71
|
-
if (!loc)
|
314
|
+
if (!loc) {
|
72
315
|
return [];
|
73
|
-
|
74
|
-
|
316
|
+
}
|
317
|
+
const comments = [];
|
318
|
+
let token = loc.startToken;
|
319
|
+
while (token) {
|
75
320
|
if (token.kind === TokenKind.COMMENT) {
|
76
|
-
|
321
|
+
const comment = convertToken(
|
77
322
|
token,
|
78
323
|
// `eslint-disable` directive works only with `Block` type comment
|
79
324
|
token.value.trimStart().startsWith("eslint") ? "Block" : "Line"
|
@@ -85,7 +330,8 @@ function extractComments(loc) {
|
|
85
330
|
return comments;
|
86
331
|
}
|
87
332
|
function convertLocation(location) {
|
88
|
-
|
333
|
+
const { startToken, endToken, source, start, end } = location;
|
334
|
+
const loc = {
|
89
335
|
start: {
|
90
336
|
/*
|
91
337
|
* Kind.Document has startToken: { line: 0, column: 0 }, we set line as 1 and column as 0
|
@@ -99,19 +345,24 @@ function convertLocation(location) {
|
|
99
345
|
},
|
100
346
|
source: source.body
|
101
347
|
};
|
102
|
-
|
348
|
+
if (loc.start.column === loc.end.column) {
|
349
|
+
loc.end.column += end - start;
|
350
|
+
}
|
351
|
+
return loc;
|
103
352
|
}
|
104
353
|
|
105
354
|
// src/estree-converter/converter.ts
|
106
355
|
function convertToESTree(node, schema16) {
|
107
|
-
|
356
|
+
const typeInfo = schema16 && new TypeInfo(schema16);
|
357
|
+
const visitor = {
|
108
358
|
leave(node2, key, parent) {
|
109
|
-
|
359
|
+
const leadingComments = "description" in node2 && node2.description ? [
|
110
360
|
{
|
111
361
|
type: node2.description.block ? "Block" : "Line",
|
112
362
|
value: node2.description.value
|
113
363
|
}
|
114
|
-
] : []
|
364
|
+
] : [];
|
365
|
+
const calculatedTypeInfo = typeInfo ? {
|
115
366
|
argument: typeInfo.getArgument(),
|
116
367
|
defaultValue: typeInfo.getDefaultValue(),
|
117
368
|
directive: typeInfo.getDirective(),
|
@@ -121,12 +372,19 @@ function convertToESTree(node, schema16) {
|
|
121
372
|
parentInputType: typeInfo.getParentInputType(),
|
122
373
|
parentType: typeInfo.getParentType(),
|
123
374
|
gqlType: typeInfo.getType()
|
124
|
-
} : {}
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
375
|
+
} : {};
|
376
|
+
const rawNode = () => {
|
377
|
+
if (parent && key !== void 0) {
|
378
|
+
return parent[key];
|
379
|
+
}
|
380
|
+
return node2.kind === Kind.DOCUMENT ? {
|
381
|
+
...node2,
|
382
|
+
definitions: node2.definitions.map(
|
383
|
+
(definition) => definition.rawNode()
|
384
|
+
)
|
385
|
+
} : node2;
|
386
|
+
};
|
387
|
+
const commonFields = {
|
130
388
|
...node2,
|
131
389
|
type: node2.kind,
|
132
390
|
loc: convertLocation(node2.loc),
|
@@ -150,7 +408,7 @@ function convertToESTree(node, schema16) {
|
|
150
408
|
}
|
151
409
|
|
152
410
|
// src/meta.ts
|
153
|
-
var version = "4.3.
|
411
|
+
var version = "4.3.1-alpha-20241207204625-6a4230707a78900a6339b03afe904b9dd6c31561";
|
154
412
|
|
155
413
|
// src/siblings.ts
|
156
414
|
import {
|
@@ -162,25 +420,28 @@ import {
|
|
162
420
|
import { Kind as Kind2 } from "graphql";
|
163
421
|
import lowerCase from "lodash.lowercase";
|
164
422
|
function requireGraphQLOperations(ruleId, context) {
|
165
|
-
|
166
|
-
if (!siblingOperations.available)
|
423
|
+
const { siblingOperations } = context.sourceCode.parserServices;
|
424
|
+
if (!siblingOperations.available) {
|
167
425
|
throw new Error(
|
168
426
|
`Rule \`${ruleId}\` requires graphql-config \`documents\` field to be set and loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info`
|
169
427
|
);
|
428
|
+
}
|
170
429
|
return siblingOperations;
|
171
430
|
}
|
172
431
|
function requireGraphQLSchema(ruleId, context) {
|
173
|
-
|
174
|
-
if (!schema16)
|
432
|
+
const { schema: schema16 } = context.sourceCode.parserServices;
|
433
|
+
if (!schema16) {
|
175
434
|
throw new Error(
|
176
435
|
`Rule \`${ruleId}\` requires graphql-config \`schema\` field to be set and loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-schema for more info`
|
177
436
|
);
|
437
|
+
}
|
178
438
|
return schema16;
|
179
439
|
}
|
180
440
|
var chalk = {
|
181
441
|
red: (str) => `\x1B[31m${str}\x1B[39m`,
|
182
442
|
yellow: (str) => `\x1B[33m${str}\x1B[39m`
|
183
|
-
}
|
443
|
+
};
|
444
|
+
var logger = {
|
184
445
|
error: (...args) => (
|
185
446
|
// eslint-disable-next-line no-console
|
186
447
|
console.error(chalk.red("error"), "[graphql-eslint]", ...args)
|
@@ -189,17 +450,25 @@ var chalk = {
|
|
189
450
|
// eslint-disable-next-line no-console
|
190
451
|
console.warn(chalk.yellow("warning"), "[graphql-eslint]", ...args)
|
191
452
|
)
|
192
|
-
}
|
453
|
+
};
|
454
|
+
var slash = (path2) => path2.replaceAll("\\", "/");
|
455
|
+
var VIRTUAL_DOCUMENT_REGEX = /[/\\]\d+_document.graphql$/;
|
456
|
+
var CWD = process.cwd();
|
457
|
+
var getTypeName = (node) => "type" in node ? getTypeName(node.type) : "name" in node && node.name ? node.name.value : "";
|
458
|
+
var TYPES_KINDS = [
|
193
459
|
Kind2.OBJECT_TYPE_DEFINITION,
|
194
460
|
Kind2.INTERFACE_TYPE_DEFINITION,
|
195
461
|
Kind2.ENUM_TYPE_DEFINITION,
|
196
462
|
Kind2.SCALAR_TYPE_DEFINITION,
|
197
463
|
Kind2.INPUT_OBJECT_TYPE_DEFINITION,
|
198
464
|
Kind2.UNION_TYPE_DEFINITION
|
199
|
-
]
|
200
|
-
|
465
|
+
];
|
466
|
+
var pascalCase = (str) => lowerCase(str).split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
467
|
+
var camelCase = (str) => {
|
468
|
+
const result = pascalCase(str);
|
201
469
|
return result.charAt(0).toLowerCase() + result.slice(1);
|
202
|
-
}
|
470
|
+
};
|
471
|
+
var convertCase = (style, str) => {
|
203
472
|
switch (style) {
|
204
473
|
case "camelCase":
|
205
474
|
return camelCase(str);
|
@@ -214,7 +483,7 @@ var chalk = {
|
|
214
483
|
}
|
215
484
|
};
|
216
485
|
function getLocation(start, fieldName = "") {
|
217
|
-
|
486
|
+
const { line, column } = start;
|
218
487
|
return {
|
219
488
|
start: {
|
220
489
|
line,
|
@@ -226,14 +495,17 @@ function getLocation(start, fieldName = "") {
|
|
226
495
|
}
|
227
496
|
};
|
228
497
|
}
|
229
|
-
var REPORT_ON_FIRST_CHARACTER = { column: 0, line: 1 }
|
498
|
+
var REPORT_ON_FIRST_CHARACTER = { column: 0, line: 1 };
|
499
|
+
var ARRAY_DEFAULT_OPTIONS = {
|
230
500
|
type: "array",
|
231
|
-
uniqueItems:
|
501
|
+
uniqueItems: true,
|
232
502
|
minItems: 1,
|
233
503
|
items: {
|
234
504
|
type: "string"
|
235
505
|
}
|
236
|
-
}
|
506
|
+
};
|
507
|
+
var englishJoinWords = (words) => new Intl.ListFormat("en-US", { type: "disjunction" }).format(words);
|
508
|
+
var DisplayNodeNameMap = {
|
237
509
|
[Kind2.ARGUMENT]: "argument",
|
238
510
|
[Kind2.BOOLEAN]: "boolean",
|
239
511
|
[Kind2.DIRECTIVE_DEFINITION]: "directive",
|
@@ -310,11 +582,18 @@ var eslintSelectorsTip = `> [!TIP]
|
|
310
582
|
var siblingOperationsCache = /* @__PURE__ */ new Map();
|
311
583
|
function getSiblings(documents) {
|
312
584
|
if (documents.length === 0) {
|
313
|
-
let printed =
|
314
|
-
|
315
|
-
|
585
|
+
let printed = false;
|
586
|
+
const noopWarn = () => {
|
587
|
+
if (!printed) {
|
588
|
+
logger.warn(
|
589
|
+
"getSiblingOperations was called without any operations. Make sure to set graphql-config `documents` field to make this feature available! See https://the-guild.dev/graphql/config/docs/user/documents for more info"
|
590
|
+
);
|
591
|
+
printed = true;
|
592
|
+
}
|
593
|
+
return [];
|
594
|
+
};
|
316
595
|
return {
|
317
|
-
available:
|
596
|
+
available: false,
|
318
597
|
getFragment: noopWarn,
|
319
598
|
getFragments: noopWarn,
|
320
599
|
getFragmentByType: noopWarn,
|
@@ -324,55 +603,80 @@ function getSiblings(documents) {
|
|
324
603
|
getOperationByType: noopWarn
|
325
604
|
};
|
326
605
|
}
|
327
|
-
|
328
|
-
if (value)
|
606
|
+
const value = siblingOperationsCache.get(documents);
|
607
|
+
if (value) {
|
329
608
|
return value;
|
330
|
-
|
609
|
+
}
|
610
|
+
let fragmentsCache = null;
|
611
|
+
const getFragments = () => {
|
331
612
|
if (fragmentsCache === null) {
|
332
|
-
|
333
|
-
for (
|
334
|
-
for (
|
335
|
-
definition.kind === Kind3.FRAGMENT_DEFINITION
|
336
|
-
|
337
|
-
|
338
|
-
|
613
|
+
const result = [];
|
614
|
+
for (const source of documents) {
|
615
|
+
for (const definition of source.document?.definitions || []) {
|
616
|
+
if (definition.kind === Kind3.FRAGMENT_DEFINITION) {
|
617
|
+
result.push({
|
618
|
+
filePath: source.location,
|
619
|
+
document: definition
|
620
|
+
});
|
621
|
+
}
|
622
|
+
}
|
623
|
+
}
|
339
624
|
fragmentsCache = result;
|
340
625
|
}
|
341
626
|
return fragmentsCache;
|
342
|
-
}
|
627
|
+
};
|
628
|
+
let cachedOperations = null;
|
629
|
+
const getOperations = () => {
|
343
630
|
if (cachedOperations === null) {
|
344
|
-
|
345
|
-
for (
|
346
|
-
for (
|
347
|
-
definition.kind === Kind3.OPERATION_DEFINITION
|
348
|
-
|
349
|
-
|
350
|
-
|
631
|
+
const result = [];
|
632
|
+
for (const source of documents) {
|
633
|
+
for (const definition of source.document?.definitions || []) {
|
634
|
+
if (definition.kind === Kind3.OPERATION_DEFINITION) {
|
635
|
+
result.push({
|
636
|
+
filePath: source.location,
|
637
|
+
document: definition
|
638
|
+
});
|
639
|
+
}
|
640
|
+
}
|
641
|
+
}
|
351
642
|
cachedOperations = result;
|
352
643
|
}
|
353
644
|
return cachedOperations;
|
354
|
-
}
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
);
|
361
|
-
|
645
|
+
};
|
646
|
+
const getFragment = (name) => getFragments().filter((f) => f.document.name.value === name);
|
647
|
+
const collectFragments = (selectable, recursive, collected = /* @__PURE__ */ new Map()) => {
|
648
|
+
visit2(selectable, {
|
649
|
+
FragmentSpread(spread) {
|
650
|
+
const fragmentName = spread.name.value;
|
651
|
+
const [fragment] = getFragment(fragmentName);
|
652
|
+
if (!fragment) {
|
653
|
+
logger.warn(
|
654
|
+
`Unable to locate fragment named "${fragmentName}", please make sure it's loaded using "parserOptions.operations"`
|
655
|
+
);
|
656
|
+
return;
|
657
|
+
}
|
658
|
+
if (!collected.has(fragmentName)) {
|
659
|
+
collected.set(fragmentName, fragment.document);
|
660
|
+
if (recursive) {
|
661
|
+
collectFragments(fragment.document, recursive, collected);
|
662
|
+
}
|
663
|
+
}
|
362
664
|
}
|
363
|
-
|
364
|
-
|
365
|
-
}
|
366
|
-
|
665
|
+
});
|
666
|
+
return collected;
|
667
|
+
};
|
668
|
+
const siblingOperations = {
|
669
|
+
available: true,
|
367
670
|
getFragment,
|
368
671
|
getFragments,
|
369
672
|
getFragmentByType: (typeName) => getFragments().filter((f) => f.document.typeCondition.name.value === typeName),
|
370
|
-
getFragmentsInUse: (selectable, recursive =
|
673
|
+
getFragmentsInUse: (selectable, recursive = true) => Array.from(collectFragments(selectable, recursive).values()),
|
371
674
|
getOperation: (name) => getOperations().filter((o) => o.document.name?.value === name),
|
372
675
|
getOperations,
|
373
676
|
getOperationByType: (type) => getOperations().filter((o) => o.document.operation === type)
|
374
677
|
};
|
375
|
-
|
678
|
+
siblingOperationsCache.set(documents, siblingOperations);
|
679
|
+
return siblingOperations;
|
376
680
|
}
|
377
681
|
|
378
682
|
// src/parser.ts
|
@@ -391,26 +695,44 @@ var LEGACY_PARSER_OPTIONS_KEYS = [
|
|
391
695
|
"operations"
|
392
696
|
];
|
393
697
|
function parseForESLint(code, options) {
|
394
|
-
for (
|
395
|
-
if (key in options)
|
698
|
+
for (const key of LEGACY_PARSER_OPTIONS_KEYS) {
|
699
|
+
if (key in options) {
|
396
700
|
throw new Error(
|
397
701
|
`\`parserOptions.${key}\` was removed in graphql-eslint@4. Use physical graphql-config for setting schema and documents or \`parserOptions.graphQLConfig\` for programmatic usage.`
|
398
702
|
);
|
703
|
+
}
|
704
|
+
}
|
399
705
|
try {
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
)
|
407
|
-
|
706
|
+
const { filePath } = options;
|
707
|
+
const { document } = parseGraphQLSDL(filePath, code, { noLocation: false });
|
708
|
+
let project;
|
709
|
+
let schema16, documents;
|
710
|
+
if (false) {
|
711
|
+
const gqlConfig = loadGraphQLConfig(options);
|
712
|
+
project = gqlConfig.getProjectForFile(getFirstExistingPath(filePath));
|
713
|
+
documents = getDocuments(project);
|
714
|
+
} else {
|
715
|
+
documents = [
|
716
|
+
parseGraphQLSDL(
|
717
|
+
"operation.graphql",
|
718
|
+
options.graphQLConfig.documents,
|
719
|
+
{ noLocation: true }
|
720
|
+
)
|
721
|
+
];
|
722
|
+
}
|
408
723
|
try {
|
409
|
-
|
724
|
+
if (false) {
|
725
|
+
schema16 = getSchema(project);
|
726
|
+
} else {
|
727
|
+
schema16 = buildSchema(options.graphQLConfig.schema);
|
728
|
+
}
|
410
729
|
} catch (error) {
|
411
|
-
|
730
|
+
if (error instanceof Error) {
|
731
|
+
error.message = `Error while loading schema: ${error.message}`;
|
732
|
+
}
|
733
|
+
throw error;
|
412
734
|
}
|
413
|
-
|
735
|
+
const rootTree = convertToESTree(document, schema16);
|
414
736
|
return {
|
415
737
|
services: {
|
416
738
|
schema: schema16,
|
@@ -427,9 +749,12 @@ function parseForESLint(code, options) {
|
|
427
749
|
}
|
428
750
|
};
|
429
751
|
} catch (error) {
|
430
|
-
if (error instanceof Error
|
431
|
-
|
432
|
-
|
752
|
+
if (error instanceof Error) {
|
753
|
+
error.message = `[graphql-eslint] ${error.message}`;
|
754
|
+
}
|
755
|
+
if (error instanceof GraphQLError) {
|
756
|
+
const location = error.locations?.[0];
|
757
|
+
const eslintError = {
|
433
758
|
index: error.positions?.[0],
|
434
759
|
...location && {
|
435
760
|
lineNumber: location.line,
|
@@ -437,6 +762,7 @@ function parseForESLint(code, options) {
|
|
437
762
|
},
|
438
763
|
message: error.message
|
439
764
|
};
|
765
|
+
throw eslintError;
|
440
766
|
}
|
441
767
|
throw error;
|
442
768
|
}
|
@@ -449,30 +775,37 @@ var parser = {
|
|
449
775
|
}
|
450
776
|
};
|
451
777
|
|
778
|
+
// src/processor.ts
|
779
|
+
var processor = {};
|
780
|
+
|
452
781
|
// src/rules/alphabetize/index.ts
|
453
782
|
import {
|
454
783
|
Kind as Kind4
|
455
784
|
} from "graphql";
|
456
785
|
import lowerCase2 from "lodash.lowercase";
|
457
|
-
var RULE_ID = "alphabetize"
|
786
|
+
var RULE_ID = "alphabetize";
|
787
|
+
var fieldsEnum = [
|
458
788
|
Kind4.OBJECT_TYPE_DEFINITION,
|
459
789
|
Kind4.INTERFACE_TYPE_DEFINITION,
|
460
790
|
Kind4.INPUT_OBJECT_TYPE_DEFINITION
|
461
|
-
]
|
791
|
+
];
|
792
|
+
var selectionsEnum = [
|
462
793
|
Kind4.OPERATION_DEFINITION,
|
463
794
|
Kind4.FRAGMENT_DEFINITION
|
464
|
-
]
|
795
|
+
];
|
796
|
+
var argumentsEnum = [
|
465
797
|
Kind4.FIELD_DEFINITION,
|
466
798
|
Kind4.FIELD,
|
467
799
|
Kind4.DIRECTIVE_DEFINITION,
|
468
800
|
Kind4.DIRECTIVE
|
469
|
-
]
|
801
|
+
];
|
802
|
+
var schema = {
|
470
803
|
type: "array",
|
471
804
|
minItems: 1,
|
472
805
|
maxItems: 1,
|
473
806
|
items: {
|
474
807
|
type: "object",
|
475
|
-
additionalProperties:
|
808
|
+
additionalProperties: false,
|
476
809
|
minProperties: 1,
|
477
810
|
properties: {
|
478
811
|
fields: {
|
@@ -517,12 +850,12 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
517
850
|
"- `id` stands for field with name `id`",
|
518
851
|
"- `*` stands for everything else",
|
519
852
|
"- `{` stands for fields `selection set`"
|
520
|
-
].join(
|
521
|
-
`)
|
853
|
+
].join("\n")
|
522
854
|
}
|
523
855
|
}
|
524
856
|
}
|
525
|
-
}
|
857
|
+
};
|
858
|
+
var rule = {
|
526
859
|
meta: {
|
527
860
|
type: "suggestion",
|
528
861
|
fixable: "code",
|
@@ -563,7 +896,7 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
563
896
|
},
|
564
897
|
{
|
565
898
|
title: "Incorrect",
|
566
|
-
usage: [{ values:
|
899
|
+
usage: [{ values: true }],
|
567
900
|
code: (
|
568
901
|
/* GraphQL */
|
569
902
|
`
|
@@ -578,7 +911,7 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
578
911
|
},
|
579
912
|
{
|
580
913
|
title: "Correct",
|
581
|
-
usage: [{ values:
|
914
|
+
usage: [{ values: true }],
|
582
915
|
code: (
|
583
916
|
/* GraphQL */
|
584
917
|
`
|
@@ -627,18 +960,18 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
627
960
|
configOptions: {
|
628
961
|
schema: [
|
629
962
|
{
|
630
|
-
definitions:
|
963
|
+
definitions: true,
|
631
964
|
fields: fieldsEnum,
|
632
|
-
values:
|
965
|
+
values: true,
|
633
966
|
arguments: argumentsEnum,
|
634
967
|
groups: ["id", "*", "createdAt", "updatedAt"]
|
635
968
|
}
|
636
969
|
],
|
637
970
|
operations: [
|
638
971
|
{
|
639
|
-
definitions:
|
972
|
+
definitions: true,
|
640
973
|
selections: selectionsEnum,
|
641
|
-
variables:
|
974
|
+
variables: true,
|
642
975
|
arguments: [Kind4.FIELD, Kind4.DIRECTIVE],
|
643
976
|
groups: ["...", "id", "*", "{"]
|
644
977
|
}
|
@@ -651,48 +984,71 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
651
984
|
schema
|
652
985
|
},
|
653
986
|
create(context) {
|
654
|
-
|
987
|
+
const sourceCode = context.getSourceCode();
|
655
988
|
function isNodeAndCommentOnSameLine(node, comment) {
|
656
989
|
return node.loc.end.line === comment.loc.start.line;
|
657
990
|
}
|
658
991
|
function getBeforeComments(node) {
|
659
|
-
|
660
|
-
if (commentsBefore.length === 0)
|
992
|
+
const commentsBefore = sourceCode.getCommentsBefore(node);
|
993
|
+
if (commentsBefore.length === 0) {
|
661
994
|
return [];
|
662
|
-
|
663
|
-
|
995
|
+
}
|
996
|
+
const tokenBefore = sourceCode.getTokenBefore(node);
|
997
|
+
if (tokenBefore) {
|
664
998
|
return commentsBefore.filter((comment) => !isNodeAndCommentOnSameLine(tokenBefore, comment));
|
665
|
-
|
999
|
+
}
|
1000
|
+
const filteredComments = [];
|
1001
|
+
const nodeLine = node.loc.start.line;
|
666
1002
|
for (let i = commentsBefore.length - 1; i >= 0; i -= 1) {
|
667
|
-
|
668
|
-
if (nodeLine - comment.loc.start.line - filteredComments.length > 1)
|
1003
|
+
const comment = commentsBefore[i];
|
1004
|
+
if (nodeLine - comment.loc.start.line - filteredComments.length > 1) {
|
669
1005
|
break;
|
1006
|
+
}
|
670
1007
|
filteredComments.unshift(comment);
|
671
1008
|
}
|
672
1009
|
return filteredComments;
|
673
1010
|
}
|
674
1011
|
function getRangeWithComments(node) {
|
675
|
-
node.kind === Kind4.VARIABLE
|
676
|
-
|
1012
|
+
if (node.kind === Kind4.VARIABLE) {
|
1013
|
+
node = node.parent;
|
1014
|
+
}
|
1015
|
+
const [firstBeforeComment] = getBeforeComments(node);
|
1016
|
+
const [firstAfterComment] = sourceCode.getCommentsAfter(node);
|
1017
|
+
const from = firstBeforeComment || node;
|
1018
|
+
const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment) ? firstAfterComment : node;
|
677
1019
|
return [from.range[0], to.range[1]];
|
678
1020
|
}
|
679
1021
|
function checkNodes(nodes = []) {
|
680
1022
|
for (let i = 1; i < nodes.length; i += 1) {
|
681
|
-
|
682
|
-
|
1023
|
+
const currNode = nodes[i];
|
1024
|
+
const currName = getName(currNode);
|
1025
|
+
if (!currName) {
|
683
1026
|
continue;
|
684
|
-
|
1027
|
+
}
|
1028
|
+
const prevNode = nodes[i - 1];
|
1029
|
+
const prevName = getName(prevNode);
|
685
1030
|
if (prevName) {
|
686
|
-
|
1031
|
+
const compareResult = prevName.localeCompare(currName);
|
1032
|
+
const { groups } = opts;
|
1033
|
+
let shouldSortByGroup = false;
|
687
1034
|
if (groups?.length) {
|
688
|
-
if (!groups.includes("*"))
|
1035
|
+
if (!groups.includes("*")) {
|
689
1036
|
throw new Error("`groups` option should contain `*` string.");
|
690
|
-
|
691
|
-
|
1037
|
+
}
|
1038
|
+
const indexForPrev = getIndex({ node: prevNode, groups });
|
1039
|
+
const indexForCurr = getIndex({ node: currNode, groups });
|
1040
|
+
shouldSortByGroup = indexForPrev - indexForCurr > 0;
|
1041
|
+
if (indexForPrev < indexForCurr) {
|
692
1042
|
continue;
|
1043
|
+
}
|
1044
|
+
}
|
1045
|
+
const shouldSort = compareResult === 1;
|
1046
|
+
if (!shouldSortByGroup && !shouldSort) {
|
1047
|
+
const isSameName = compareResult === 0;
|
1048
|
+
if (!isSameName || !prevNode.kind.endsWith("Extension") || currNode.kind.endsWith("Extension")) {
|
1049
|
+
continue;
|
1050
|
+
}
|
693
1051
|
}
|
694
|
-
if (!shouldSortByGroup && !(compareResult === 1) && (!(compareResult === 0) || !prevNode.kind.endsWith("Extension") || currNode.kind.endsWith("Extension")))
|
695
|
-
continue;
|
696
1052
|
}
|
697
1053
|
context.report({
|
698
1054
|
// @ts-expect-error can't be undefined
|
@@ -703,11 +1059,13 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
703
1059
|
prevNode: prevName ? displayNodeName(prevNode) : lowerCase2(prevNode.kind)
|
704
1060
|
},
|
705
1061
|
*fix(fixer) {
|
706
|
-
|
1062
|
+
const prevRange = getRangeWithComments(prevNode);
|
1063
|
+
const currRange = getRangeWithComments(currNode);
|
707
1064
|
yield fixer.replaceTextRange(
|
708
1065
|
prevRange,
|
709
1066
|
sourceCode.getText({ range: currRange })
|
710
|
-
)
|
1067
|
+
);
|
1068
|
+
yield fixer.replaceTextRange(
|
711
1069
|
currRange,
|
712
1070
|
sourceCode.getText({ range: prevRange })
|
713
1071
|
);
|
@@ -715,7 +1073,10 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
715
1073
|
});
|
716
1074
|
}
|
717
1075
|
}
|
718
|
-
|
1076
|
+
const opts = context.options[0];
|
1077
|
+
const fields = new Set(opts.fields ?? []);
|
1078
|
+
const listeners = {};
|
1079
|
+
const kinds = [
|
719
1080
|
fields.has(Kind4.OBJECT_TYPE_DEFINITION) && [
|
720
1081
|
Kind4.OBJECT_TYPE_DEFINITION,
|
721
1082
|
Kind4.OBJECT_TYPE_EXTENSION
|
@@ -728,24 +1089,42 @@ var RULE_ID = "alphabetize", fieldsEnum = [
|
|
728
1089
|
Kind4.INPUT_OBJECT_TYPE_DEFINITION,
|
729
1090
|
Kind4.INPUT_OBJECT_TYPE_EXTENSION
|
730
1091
|
]
|
731
|
-
].filter((v) => !!v).flat()
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
1092
|
+
].filter((v) => !!v).flat();
|
1093
|
+
const fieldsSelector = kinds.join(",");
|
1094
|
+
const selectionsSelector = opts.selections?.join(",");
|
1095
|
+
const argumentsSelector = opts.arguments?.join(",");
|
1096
|
+
if (fieldsSelector) {
|
1097
|
+
listeners[fieldsSelector] = (node) => {
|
1098
|
+
checkNodes(node.fields);
|
1099
|
+
};
|
1100
|
+
}
|
1101
|
+
if (opts.values) {
|
1102
|
+
const enumValuesSelector = [Kind4.ENUM_TYPE_DEFINITION, Kind4.ENUM_TYPE_EXTENSION].join(",");
|
736
1103
|
listeners[enumValuesSelector] = (node) => {
|
737
1104
|
checkNodes(node.values);
|
738
1105
|
};
|
739
1106
|
}
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
}
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
1107
|
+
if (selectionsSelector) {
|
1108
|
+
listeners[`:matches(${selectionsSelector}) SelectionSet`] = (node) => {
|
1109
|
+
checkNodes(node.selections);
|
1110
|
+
};
|
1111
|
+
}
|
1112
|
+
if (opts.variables) {
|
1113
|
+
listeners.OperationDefinition = (node) => {
|
1114
|
+
checkNodes(node.variableDefinitions?.map((varDef) => varDef.variable));
|
1115
|
+
};
|
1116
|
+
}
|
1117
|
+
if (argumentsSelector) {
|
1118
|
+
listeners[argumentsSelector] = (node) => {
|
1119
|
+
checkNodes(node.arguments);
|
1120
|
+
};
|
1121
|
+
}
|
1122
|
+
if (opts.definitions) {
|
1123
|
+
listeners.Document = (node) => {
|
1124
|
+
checkNodes(node.definitions);
|
1125
|
+
};
|
1126
|
+
}
|
1127
|
+
return listeners;
|
749
1128
|
}
|
750
1129
|
};
|
751
1130
|
function getIndex({
|
@@ -753,7 +1132,10 @@ function getIndex({
|
|
753
1132
|
groups
|
754
1133
|
}) {
|
755
1134
|
let index = groups.indexOf(getName(node));
|
756
|
-
|
1135
|
+
if (index === -1 && "selectionSet" in node && node.selectionSet) index = groups.indexOf("{");
|
1136
|
+
if (index === -1 && node.kind === Kind4.FRAGMENT_SPREAD) index = groups.indexOf("...");
|
1137
|
+
if (index === -1) index = groups.indexOf("*");
|
1138
|
+
return index;
|
757
1139
|
}
|
758
1140
|
function getName(node) {
|
759
1141
|
return "alias" in node && node.alias?.value || //
|
@@ -766,7 +1148,7 @@ var schema2 = {
|
|
766
1148
|
maxItems: 1,
|
767
1149
|
items: {
|
768
1150
|
type: "object",
|
769
|
-
additionalProperties:
|
1151
|
+
additionalProperties: false,
|
770
1152
|
minProperties: 1,
|
771
1153
|
properties: {
|
772
1154
|
style: {
|
@@ -775,10 +1157,11 @@ var schema2 = {
|
|
775
1157
|
}
|
776
1158
|
}
|
777
1159
|
}
|
778
|
-
}
|
1160
|
+
};
|
1161
|
+
var rule2 = {
|
779
1162
|
meta: {
|
780
1163
|
type: "suggestion",
|
781
|
-
hasSuggestions:
|
1164
|
+
hasSuggestions: true,
|
782
1165
|
docs: {
|
783
1166
|
examples: [
|
784
1167
|
{
|
@@ -811,12 +1194,13 @@ var schema2 = {
|
|
811
1194
|
description: "Require all comments to follow the same style (either block or inline).",
|
812
1195
|
category: "Schema",
|
813
1196
|
url: "https://the-guild.dev/graphql/eslint/rules/description-style",
|
814
|
-
recommended:
|
1197
|
+
recommended: true
|
815
1198
|
},
|
816
1199
|
schema: schema2
|
817
1200
|
},
|
818
1201
|
create(context) {
|
819
|
-
|
1202
|
+
const { style = "block" } = context.options[0] || {};
|
1203
|
+
const isBlock = style === "block";
|
820
1204
|
return {
|
821
1205
|
[`.description[type=StringValue][block!=${isBlock}]`](node) {
|
822
1206
|
context.report({
|
@@ -828,7 +1212,9 @@ var schema2 = {
|
|
828
1212
|
{
|
829
1213
|
desc: `Change to ${isBlock ? "block" : "inline"} style description`,
|
830
1214
|
fix(fixer) {
|
831
|
-
|
1215
|
+
const sourceCode = context.getSourceCode();
|
1216
|
+
const originalText = sourceCode.getText(node);
|
1217
|
+
const newText = isBlock ? originalText.replace(/(^")|("$)/g, '"""') : originalText.replace(/(^""")|("""$)/g, '"').replace(/\s+/g, " ");
|
832
1218
|
return fixer.replaceText(node, newText);
|
833
1219
|
}
|
834
1220
|
}
|
@@ -885,60 +1271,77 @@ function validateDocument({
|
|
885
1271
|
rule: rule35,
|
886
1272
|
hasDidYouMeanSuggestions
|
887
1273
|
}) {
|
888
|
-
if (documentNode.definitions.length
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
desc: `Rename to \`${name}\``,
|
908
|
-
fix: (fixer) => fixer.replaceText(token, name)
|
909
|
-
};
|
910
|
-
}) : []
|
911
|
-
});
|
1274
|
+
if (documentNode.definitions.length === 0) {
|
1275
|
+
return;
|
1276
|
+
}
|
1277
|
+
try {
|
1278
|
+
const validationErrors = schema16 ? validate(schema16, documentNode, [rule35]) : validateSDL(documentNode, null, [rule35]);
|
1279
|
+
for (const error of validationErrors) {
|
1280
|
+
const { line, column } = error.locations[0];
|
1281
|
+
const sourceCode = context.getSourceCode();
|
1282
|
+
const { tokens } = sourceCode.ast;
|
1283
|
+
const token = tokens.find(
|
1284
|
+
(token2) => token2.loc.start.line === line && token2.loc.start.column === column - 1
|
1285
|
+
);
|
1286
|
+
let loc = {
|
1287
|
+
line,
|
1288
|
+
column: column - 1
|
1289
|
+
};
|
1290
|
+
if (token) {
|
1291
|
+
loc = // if cursor on `@` symbol than use next node
|
1292
|
+
token.type === "@" ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc : token.loc;
|
912
1293
|
}
|
913
|
-
|
1294
|
+
const didYouMeanContent = error.message.match(/Did you mean (?<content>.*)\?$/)?.groups.content;
|
1295
|
+
const matches = didYouMeanContent ? [...didYouMeanContent.matchAll(/"(?<name>[^"]*)"/g)] : [];
|
914
1296
|
context.report({
|
915
|
-
loc
|
916
|
-
message: error.message
|
1297
|
+
loc,
|
1298
|
+
message: error.message,
|
1299
|
+
suggest: hasDidYouMeanSuggestions ? matches.map((match) => {
|
1300
|
+
const { name } = match.groups;
|
1301
|
+
return {
|
1302
|
+
desc: `Rename to \`${name}\``,
|
1303
|
+
fix: (fixer) => fixer.replaceText(token, name)
|
1304
|
+
};
|
1305
|
+
}) : []
|
917
1306
|
});
|
918
1307
|
}
|
1308
|
+
} catch (error) {
|
1309
|
+
context.report({
|
1310
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
1311
|
+
message: error.message
|
1312
|
+
});
|
1313
|
+
}
|
919
1314
|
}
|
920
1315
|
var getFragmentDefsAndFragmentSpreads = (node) => {
|
921
|
-
|
922
|
-
|
1316
|
+
const fragmentDefs = /* @__PURE__ */ new Set();
|
1317
|
+
const fragmentSpreads = /* @__PURE__ */ new Set();
|
1318
|
+
const visitor = {
|
923
1319
|
FragmentDefinition(node2) {
|
924
1320
|
fragmentDefs.add(node2.name.value);
|
925
1321
|
},
|
926
1322
|
FragmentSpread(node2) {
|
927
1323
|
fragmentSpreads.add(node2.name.value);
|
928
1324
|
}
|
929
|
-
}
|
930
|
-
|
931
|
-
|
1325
|
+
};
|
1326
|
+
visit3(node, visitor);
|
1327
|
+
return { fragmentDefs, fragmentSpreads };
|
1328
|
+
};
|
1329
|
+
var getMissingFragments = (node) => {
|
1330
|
+
const { fragmentDefs, fragmentSpreads } = getFragmentDefsAndFragmentSpreads(node);
|
932
1331
|
return [...fragmentSpreads].filter((name) => !fragmentDefs.has(name));
|
933
|
-
}
|
934
|
-
|
1332
|
+
};
|
1333
|
+
var handleMissingFragments = ({ ruleId, context, node }) => {
|
1334
|
+
const missingFragments = getMissingFragments(node);
|
935
1335
|
if (missingFragments.length > 0) {
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
foundFragment
|
1336
|
+
const siblings = requireGraphQLOperations(ruleId, context);
|
1337
|
+
const fragmentsToAdd = [];
|
1338
|
+
for (const fragmentName of missingFragments) {
|
1339
|
+
const [foundFragment] = siblings.getFragment(fragmentName).map((source) => source.document);
|
1340
|
+
if (foundFragment) {
|
1341
|
+
fragmentsToAdd.push(foundFragment);
|
1342
|
+
}
|
940
1343
|
}
|
941
|
-
if (fragmentsToAdd.length > 0)
|
1344
|
+
if (fragmentsToAdd.length > 0) {
|
942
1345
|
return handleMissingFragments({
|
943
1346
|
ruleId,
|
944
1347
|
context,
|
@@ -947,44 +1350,50 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
947
1350
|
definitions: [...node.definitions, ...fragmentsToAdd]
|
948
1351
|
}
|
949
1352
|
});
|
1353
|
+
}
|
950
1354
|
}
|
951
1355
|
return node;
|
952
|
-
}
|
1356
|
+
};
|
1357
|
+
var validationToRule = ({
|
953
1358
|
ruleId,
|
954
1359
|
rule: rule35,
|
955
1360
|
getDocumentNode,
|
956
1361
|
schema: schema16 = [],
|
957
1362
|
hasDidYouMeanSuggestions
|
958
|
-
}, docs) =>
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
1363
|
+
}, docs) => {
|
1364
|
+
return {
|
1365
|
+
[ruleId]: {
|
1366
|
+
meta: {
|
1367
|
+
docs: {
|
1368
|
+
recommended: true,
|
1369
|
+
...docs,
|
1370
|
+
graphQLJSRuleName: rule35.name,
|
1371
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${ruleId}`,
|
1372
|
+
description: `${docs.description}
|
967
1373
|
> This rule is a wrapper around a \`graphql-js\` validation function.`
|
1374
|
+
},
|
1375
|
+
schema: schema16,
|
1376
|
+
hasSuggestions: hasDidYouMeanSuggestions
|
968
1377
|
},
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
};
|
1378
|
+
create(context) {
|
1379
|
+
return {
|
1380
|
+
Document(node) {
|
1381
|
+
const schema17 = docs.requiresSchema ? requireGraphQLSchema(ruleId, context) : null;
|
1382
|
+
const documentNode = getDocumentNode ? getDocumentNode({ ruleId, context, node: node.rawNode() }) : node.rawNode();
|
1383
|
+
validateDocument({
|
1384
|
+
context,
|
1385
|
+
schema: schema17,
|
1386
|
+
documentNode,
|
1387
|
+
rule: rule35,
|
1388
|
+
hasDidYouMeanSuggestions
|
1389
|
+
});
|
1390
|
+
}
|
1391
|
+
};
|
1392
|
+
}
|
985
1393
|
}
|
986
|
-
}
|
987
|
-
}
|
1394
|
+
};
|
1395
|
+
};
|
1396
|
+
var GRAPHQL_JS_VALIDATIONS = Object.assign(
|
988
1397
|
{},
|
989
1398
|
validationToRule(
|
990
1399
|
{
|
@@ -994,19 +1403,19 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
994
1403
|
{
|
995
1404
|
category: "Operations",
|
996
1405
|
description: "A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.",
|
997
|
-
requiresSchema:
|
1406
|
+
requiresSchema: true
|
998
1407
|
}
|
999
1408
|
),
|
1000
1409
|
validationToRule(
|
1001
1410
|
{
|
1002
1411
|
ruleId: "fields-on-correct-type",
|
1003
1412
|
rule: FieldsOnCorrectTypeRule,
|
1004
|
-
hasDidYouMeanSuggestions:
|
1413
|
+
hasDidYouMeanSuggestions: true
|
1005
1414
|
},
|
1006
1415
|
{
|
1007
1416
|
category: "Operations",
|
1008
1417
|
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`.",
|
1009
|
-
requiresSchema:
|
1418
|
+
requiresSchema: true
|
1010
1419
|
}
|
1011
1420
|
),
|
1012
1421
|
validationToRule(
|
@@ -1017,19 +1426,19 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1017
1426
|
{
|
1018
1427
|
category: "Operations",
|
1019
1428
|
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.",
|
1020
|
-
requiresSchema:
|
1429
|
+
requiresSchema: true
|
1021
1430
|
}
|
1022
1431
|
),
|
1023
1432
|
validationToRule(
|
1024
1433
|
{
|
1025
1434
|
ruleId: "known-argument-names",
|
1026
1435
|
rule: KnownArgumentNamesRule,
|
1027
|
-
hasDidYouMeanSuggestions:
|
1436
|
+
hasDidYouMeanSuggestions: true
|
1028
1437
|
},
|
1029
1438
|
{
|
1030
1439
|
category: ["Schema", "Operations"],
|
1031
1440
|
description: "A GraphQL field is only valid if all supplied arguments are defined by that field.",
|
1032
|
-
requiresSchema:
|
1441
|
+
requiresSchema: true
|
1033
1442
|
}
|
1034
1443
|
),
|
1035
1444
|
validationToRule(
|
@@ -1037,10 +1446,11 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1037
1446
|
ruleId: "known-directives",
|
1038
1447
|
rule: KnownDirectivesRule,
|
1039
1448
|
getDocumentNode({ context, node: documentNode }) {
|
1040
|
-
|
1041
|
-
if (ignoreClientDirectives.length === 0)
|
1449
|
+
const { ignoreClientDirectives = [] } = context.options[0] || {};
|
1450
|
+
if (ignoreClientDirectives.length === 0) {
|
1042
1451
|
return documentNode;
|
1043
|
-
|
1452
|
+
}
|
1453
|
+
const filterDirectives = (node) => ({
|
1044
1454
|
...node,
|
1045
1455
|
directives: node.directives?.filter(
|
1046
1456
|
(directive) => !ignoreClientDirectives.includes(directive.name.value)
|
@@ -1056,7 +1466,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1056
1466
|
maxItems: 1,
|
1057
1467
|
items: {
|
1058
1468
|
type: "object",
|
1059
|
-
additionalProperties:
|
1469
|
+
additionalProperties: false,
|
1060
1470
|
required: ["ignoreClientDirectives"],
|
1061
1471
|
properties: {
|
1062
1472
|
ignoreClientDirectives: ARRAY_DEFAULT_OPTIONS
|
@@ -1067,7 +1477,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1067
1477
|
{
|
1068
1478
|
category: ["Schema", "Operations"],
|
1069
1479
|
description: "A GraphQL document is only valid if all `@directive`s are known by the schema and legally positioned.",
|
1070
|
-
requiresSchema:
|
1480
|
+
requiresSchema: true,
|
1071
1481
|
examples: [
|
1072
1482
|
{
|
1073
1483
|
title: "Valid",
|
@@ -1095,8 +1505,8 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1095
1505
|
{
|
1096
1506
|
category: "Operations",
|
1097
1507
|
description: "A GraphQL document is only valid if all `...Fragment` fragment spreads refer to fragments defined in the same document.",
|
1098
|
-
requiresSchema:
|
1099
|
-
requiresSiblings:
|
1508
|
+
requiresSchema: true,
|
1509
|
+
requiresSiblings: true,
|
1100
1510
|
examples: [
|
1101
1511
|
{
|
1102
1512
|
title: "Incorrect",
|
@@ -1158,12 +1568,12 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1158
1568
|
{
|
1159
1569
|
ruleId: "known-type-names",
|
1160
1570
|
rule: KnownTypeNamesRule,
|
1161
|
-
hasDidYouMeanSuggestions:
|
1571
|
+
hasDidYouMeanSuggestions: true
|
1162
1572
|
},
|
1163
1573
|
{
|
1164
1574
|
category: ["Schema", "Operations"],
|
1165
1575
|
description: "A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.",
|
1166
|
-
requiresSchema:
|
1576
|
+
requiresSchema: true
|
1167
1577
|
}
|
1168
1578
|
),
|
1169
1579
|
validationToRule(
|
@@ -1174,7 +1584,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1174
1584
|
{
|
1175
1585
|
category: "Operations",
|
1176
1586
|
description: "A GraphQL document that contains an anonymous operation (the `query` short-hand) is only valid if it contains only that one operation definition.",
|
1177
|
-
requiresSchema:
|
1587
|
+
requiresSchema: true
|
1178
1588
|
}
|
1179
1589
|
),
|
1180
1590
|
validationToRule(
|
@@ -1195,7 +1605,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1195
1605
|
{
|
1196
1606
|
category: "Operations",
|
1197
1607
|
description: "A GraphQL fragment is only valid when it does not have cycles in fragments usage.",
|
1198
|
-
requiresSchema:
|
1608
|
+
requiresSchema: true
|
1199
1609
|
}
|
1200
1610
|
),
|
1201
1611
|
validationToRule(
|
@@ -1207,8 +1617,8 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1207
1617
|
{
|
1208
1618
|
category: "Operations",
|
1209
1619
|
description: "A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.",
|
1210
|
-
requiresSchema:
|
1211
|
-
requiresSiblings:
|
1620
|
+
requiresSchema: true,
|
1621
|
+
requiresSiblings: true
|
1212
1622
|
}
|
1213
1623
|
),
|
1214
1624
|
validationToRule(
|
@@ -1216,25 +1626,36 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1216
1626
|
ruleId: "no-unused-fragments",
|
1217
1627
|
rule: NoUnusedFragmentsRule,
|
1218
1628
|
getDocumentNode: ({ ruleId, context, node }) => {
|
1219
|
-
|
1629
|
+
const siblings = requireGraphQLOperations(ruleId, context);
|
1630
|
+
const FilePathToDocumentsMap = [
|
1220
1631
|
...siblings.getOperations(),
|
1221
1632
|
...siblings.getFragments()
|
1222
|
-
].reduce((map, { filePath, document }) =>
|
1223
|
-
|
1224
|
-
|
1633
|
+
].reduce((map, { filePath, document }) => {
|
1634
|
+
map[filePath] ??= [];
|
1635
|
+
map[filePath].push(document);
|
1636
|
+
return map;
|
1637
|
+
}, /* @__PURE__ */ Object.create(null));
|
1638
|
+
const getParentNode = (currentFilePath, node2) => {
|
1639
|
+
const { fragmentDefs } = getFragmentDefsAndFragmentSpreads(node2);
|
1640
|
+
if (fragmentDefs.size === 0) {
|
1225
1641
|
return node2;
|
1642
|
+
}
|
1226
1643
|
delete FilePathToDocumentsMap[currentFilePath];
|
1227
|
-
for (
|
1228
|
-
|
1644
|
+
for (const [filePath, documents] of Object.entries(FilePathToDocumentsMap)) {
|
1645
|
+
const missingFragments = getMissingFragments({
|
1229
1646
|
kind: Kind5.DOCUMENT,
|
1230
1647
|
definitions: documents
|
1231
|
-
})
|
1648
|
+
});
|
1649
|
+
const isCurrentFileImportFragment = missingFragments.some(
|
1232
1650
|
(fragment) => fragmentDefs.has(fragment)
|
1233
|
-
)
|
1651
|
+
);
|
1652
|
+
if (isCurrentFileImportFragment) {
|
1234
1653
|
return getParentNode(filePath, {
|
1235
1654
|
kind: Kind5.DOCUMENT,
|
1236
1655
|
definitions: [...node2.definitions, ...documents]
|
1237
1656
|
});
|
1657
|
+
}
|
1658
|
+
}
|
1238
1659
|
return node2;
|
1239
1660
|
};
|
1240
1661
|
return getParentNode(context.filename, node);
|
@@ -1243,8 +1664,8 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1243
1664
|
{
|
1244
1665
|
category: "Operations",
|
1245
1666
|
description: "A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.",
|
1246
|
-
requiresSchema:
|
1247
|
-
requiresSiblings:
|
1667
|
+
requiresSchema: true,
|
1668
|
+
requiresSiblings: true
|
1248
1669
|
}
|
1249
1670
|
),
|
1250
1671
|
validationToRule(
|
@@ -1256,8 +1677,8 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1256
1677
|
{
|
1257
1678
|
category: "Operations",
|
1258
1679
|
description: "A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.",
|
1259
|
-
requiresSchema:
|
1260
|
-
requiresSiblings:
|
1680
|
+
requiresSchema: true,
|
1681
|
+
requiresSiblings: true
|
1261
1682
|
}
|
1262
1683
|
),
|
1263
1684
|
validationToRule(
|
@@ -1268,7 +1689,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1268
1689
|
{
|
1269
1690
|
category: "Operations",
|
1270
1691
|
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.",
|
1271
|
-
requiresSchema:
|
1692
|
+
requiresSchema: true
|
1272
1693
|
}
|
1273
1694
|
),
|
1274
1695
|
validationToRule(
|
@@ -1279,20 +1700,20 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1279
1700
|
{
|
1280
1701
|
category: "Operations",
|
1281
1702
|
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.",
|
1282
|
-
requiresSchema:
|
1703
|
+
requiresSchema: true
|
1283
1704
|
}
|
1284
1705
|
),
|
1285
1706
|
validationToRule(
|
1286
1707
|
{
|
1287
1708
|
ruleId: "possible-type-extension",
|
1288
1709
|
rule: PossibleTypeExtensionsRule,
|
1289
|
-
hasDidYouMeanSuggestions:
|
1710
|
+
hasDidYouMeanSuggestions: true
|
1290
1711
|
},
|
1291
1712
|
{
|
1292
1713
|
category: "Schema",
|
1293
1714
|
description: "A type extension is only valid if the type is defined and has the same kind.",
|
1294
|
-
recommended:
|
1295
|
-
requiresSchema:
|
1715
|
+
recommended: true,
|
1716
|
+
requiresSchema: true
|
1296
1717
|
}
|
1297
1718
|
),
|
1298
1719
|
validationToRule(
|
@@ -1303,19 +1724,19 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1303
1724
|
{
|
1304
1725
|
category: ["Schema", "Operations"],
|
1305
1726
|
description: "A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.",
|
1306
|
-
requiresSchema:
|
1727
|
+
requiresSchema: true
|
1307
1728
|
}
|
1308
1729
|
),
|
1309
1730
|
validationToRule(
|
1310
1731
|
{
|
1311
1732
|
ruleId: "scalar-leafs",
|
1312
1733
|
rule: ScalarLeafsRule,
|
1313
|
-
hasDidYouMeanSuggestions:
|
1734
|
+
hasDidYouMeanSuggestions: true
|
1314
1735
|
},
|
1315
1736
|
{
|
1316
1737
|
category: "Operations",
|
1317
1738
|
description: "A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.",
|
1318
|
-
requiresSchema:
|
1739
|
+
requiresSchema: true
|
1319
1740
|
}
|
1320
1741
|
),
|
1321
1742
|
validationToRule(
|
@@ -1326,7 +1747,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1326
1747
|
{
|
1327
1748
|
category: "Operations",
|
1328
1749
|
description: "A GraphQL subscription is valid only if it contains a single root field.",
|
1329
|
-
requiresSchema:
|
1750
|
+
requiresSchema: true
|
1330
1751
|
}
|
1331
1752
|
),
|
1332
1753
|
validationToRule(
|
@@ -1337,7 +1758,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1337
1758
|
{
|
1338
1759
|
category: "Operations",
|
1339
1760
|
description: "A GraphQL field or directive is only valid if all supplied arguments are uniquely named.",
|
1340
|
-
requiresSchema:
|
1761
|
+
requiresSchema: true
|
1341
1762
|
}
|
1342
1763
|
),
|
1343
1764
|
validationToRule(
|
@@ -1358,7 +1779,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1358
1779
|
{
|
1359
1780
|
category: ["Schema", "Operations"],
|
1360
1781
|
description: "A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.",
|
1361
|
-
requiresSchema:
|
1782
|
+
requiresSchema: true
|
1362
1783
|
}
|
1363
1784
|
),
|
1364
1785
|
validationToRule(
|
@@ -1409,19 +1830,19 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1409
1830
|
{
|
1410
1831
|
category: "Operations",
|
1411
1832
|
description: "A GraphQL operation is only valid if all its variables are uniquely named.",
|
1412
|
-
requiresSchema:
|
1833
|
+
requiresSchema: true
|
1413
1834
|
}
|
1414
1835
|
),
|
1415
1836
|
validationToRule(
|
1416
1837
|
{
|
1417
1838
|
ruleId: "value-literals-of-correct-type",
|
1418
1839
|
rule: ValuesOfCorrectTypeRule,
|
1419
|
-
hasDidYouMeanSuggestions:
|
1840
|
+
hasDidYouMeanSuggestions: true
|
1420
1841
|
},
|
1421
1842
|
{
|
1422
1843
|
category: "Operations",
|
1423
1844
|
description: "A GraphQL document is only valid if all value literals are of the type expected at their position.",
|
1424
|
-
requiresSchema:
|
1845
|
+
requiresSchema: true
|
1425
1846
|
}
|
1426
1847
|
),
|
1427
1848
|
validationToRule(
|
@@ -1432,7 +1853,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1432
1853
|
{
|
1433
1854
|
category: "Operations",
|
1434
1855
|
description: "A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).",
|
1435
|
-
requiresSchema:
|
1856
|
+
requiresSchema: true
|
1436
1857
|
}
|
1437
1858
|
),
|
1438
1859
|
validationToRule(
|
@@ -1443,7 +1864,7 @@ var getFragmentDefsAndFragmentSpreads = (node) => {
|
|
1443
1864
|
{
|
1444
1865
|
category: "Operations",
|
1445
1866
|
description: "Variables passed to field arguments conform to type.",
|
1446
|
-
requiresSchema:
|
1867
|
+
requiresSchema: true
|
1447
1868
|
}
|
1448
1869
|
)
|
1449
1870
|
);
|
@@ -1457,46 +1878,49 @@ var schema3 = {
|
|
1457
1878
|
maxItems: 1,
|
1458
1879
|
items: {
|
1459
1880
|
type: "object",
|
1460
|
-
additionalProperties:
|
1881
|
+
additionalProperties: false,
|
1461
1882
|
properties: {
|
1462
1883
|
checkInputType: {
|
1463
1884
|
type: "boolean",
|
1464
|
-
default:
|
1885
|
+
default: false,
|
1465
1886
|
description: "Check that the input type name follows the convention \\<mutationName>Input"
|
1466
1887
|
},
|
1467
1888
|
caseSensitiveInputType: {
|
1468
1889
|
type: "boolean",
|
1469
|
-
default:
|
1890
|
+
default: true,
|
1470
1891
|
description: "Allow for case discrepancies in the input type name"
|
1471
1892
|
},
|
1472
1893
|
checkQueries: {
|
1473
1894
|
type: "boolean",
|
1474
|
-
default:
|
1895
|
+
default: false,
|
1475
1896
|
description: "Apply the rule to Queries"
|
1476
1897
|
},
|
1477
1898
|
checkMutations: {
|
1478
1899
|
type: "boolean",
|
1479
|
-
default:
|
1900
|
+
default: true,
|
1480
1901
|
description: "Apply the rule to Mutations"
|
1481
1902
|
}
|
1482
1903
|
}
|
1483
1904
|
}
|
1484
|
-
}
|
1905
|
+
};
|
1906
|
+
var isObjectType = (node) => (
|
1485
1907
|
// TODO: remove `as any` when drop support of graphql@15
|
1486
1908
|
[Kind6.OBJECT_TYPE_DEFINITION, Kind6.OBJECT_TYPE_EXTENSION].includes(node.type)
|
1487
|
-
)
|
1909
|
+
);
|
1910
|
+
var isQueryType = (node) => isObjectType(node) && node.name.value === "Query";
|
1911
|
+
var isMutationType = (node) => isObjectType(node) && node.name.value === "Mutation";
|
1912
|
+
var rule3 = {
|
1488
1913
|
meta: {
|
1489
1914
|
type: "suggestion",
|
1490
|
-
hasSuggestions:
|
1915
|
+
hasSuggestions: true,
|
1491
1916
|
docs: {
|
1492
|
-
description:
|
1493
|
-
Using 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.`,
|
1917
|
+
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.',
|
1494
1918
|
category: "Schema",
|
1495
1919
|
url: "https://the-guild.dev/graphql/eslint/rules/input-name",
|
1496
1920
|
examples: [
|
1497
1921
|
{
|
1498
1922
|
title: "Incorrect",
|
1499
|
-
usage: [{ checkInputType:
|
1923
|
+
usage: [{ checkInputType: true }],
|
1500
1924
|
code: (
|
1501
1925
|
/* GraphQL */
|
1502
1926
|
`
|
@@ -1508,7 +1932,7 @@ Using the same name for all input parameters will make your schemas easier to co
|
|
1508
1932
|
},
|
1509
1933
|
{
|
1510
1934
|
title: "Correct (with `checkInputType`)",
|
1511
|
-
usage: [{ checkInputType:
|
1935
|
+
usage: [{ checkInputType: true }],
|
1512
1936
|
code: (
|
1513
1937
|
/* GraphQL */
|
1514
1938
|
`
|
@@ -1520,7 +1944,7 @@ Using the same name for all input parameters will make your schemas easier to co
|
|
1520
1944
|
},
|
1521
1945
|
{
|
1522
1946
|
title: "Correct (without `checkInputType`)",
|
1523
|
-
usage: [{ checkInputType:
|
1947
|
+
usage: [{ checkInputType: false }],
|
1524
1948
|
code: (
|
1525
1949
|
/* GraphQL */
|
1526
1950
|
`
|
@@ -1535,16 +1959,18 @@ Using the same name for all input parameters will make your schemas easier to co
|
|
1535
1959
|
schema: schema3
|
1536
1960
|
},
|
1537
1961
|
create(context) {
|
1538
|
-
|
1539
|
-
checkInputType:
|
1540
|
-
caseSensitiveInputType:
|
1541
|
-
checkMutations:
|
1962
|
+
const options = {
|
1963
|
+
checkInputType: false,
|
1964
|
+
caseSensitiveInputType: true,
|
1965
|
+
checkMutations: true,
|
1542
1966
|
...context.options[0]
|
1543
|
-
}
|
1967
|
+
};
|
1968
|
+
const shouldCheckType = (node) => options.checkMutations && isMutationType(node) || options.checkQueries && isQueryType(node) || false;
|
1969
|
+
const listeners = {
|
1544
1970
|
"FieldDefinition > InputValueDefinition[name.value!=input] > Name"(node) {
|
1545
|
-
|
1971
|
+
const fieldDef = node.parent.parent;
|
1546
1972
|
if (shouldCheckType(fieldDef.parent)) {
|
1547
|
-
|
1973
|
+
const inputName = node.value;
|
1548
1974
|
context.report({
|
1549
1975
|
node,
|
1550
1976
|
message: `Input "${inputName}" should be named "input" for "${fieldDef.parent.name.value}.${fieldDef.name.value}"`,
|
@@ -1558,39 +1984,49 @@ Using the same name for all input parameters will make your schemas easier to co
|
|
1558
1984
|
}
|
1559
1985
|
}
|
1560
1986
|
};
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
currentNode
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1987
|
+
if (options.checkInputType) {
|
1988
|
+
listeners["FieldDefinition > InputValueDefinition NamedType"] = (node) => {
|
1989
|
+
const findInputType = (item) => {
|
1990
|
+
let currentNode = item;
|
1991
|
+
while (currentNode.type !== Kind6.INPUT_VALUE_DEFINITION) {
|
1992
|
+
currentNode = currentNode.parent;
|
1993
|
+
}
|
1994
|
+
return currentNode;
|
1995
|
+
};
|
1996
|
+
const inputValueNode = findInputType(node);
|
1997
|
+
if (shouldCheckType(inputValueNode.parent.parent)) {
|
1998
|
+
const mutationName = `${inputValueNode.parent.name.value}Input`;
|
1999
|
+
const name = node.name.value;
|
2000
|
+
if (options.caseSensitiveInputType && node.name.value !== mutationName || name.toLowerCase() !== mutationName.toLowerCase()) {
|
2001
|
+
context.report({
|
2002
|
+
node: node.name,
|
2003
|
+
message: `Input type \`${name}\` name should be \`${mutationName}\`.`,
|
2004
|
+
suggest: [
|
2005
|
+
{
|
2006
|
+
desc: `Rename to \`${mutationName}\``,
|
2007
|
+
fix: (fixer) => fixer.replaceText(node, mutationName)
|
2008
|
+
}
|
2009
|
+
]
|
2010
|
+
});
|
2011
|
+
}
|
2012
|
+
}
|
2013
|
+
};
|
2014
|
+
}
|
2015
|
+
return listeners;
|
1582
2016
|
}
|
1583
2017
|
};
|
1584
2018
|
|
1585
2019
|
// src/rules/lone-executable-definition/index.ts
|
1586
2020
|
import { OperationTypeNode as OperationTypeNode2 } from "graphql";
|
1587
|
-
var RULE_ID2 = "lone-executable-definition"
|
2021
|
+
var RULE_ID2 = "lone-executable-definition";
|
2022
|
+
var definitionTypes = ["fragment", ...Object.values(OperationTypeNode2)];
|
2023
|
+
var schema4 = {
|
1588
2024
|
type: "array",
|
1589
2025
|
maxItems: 1,
|
1590
2026
|
items: {
|
1591
2027
|
type: "object",
|
1592
2028
|
minProperties: 1,
|
1593
|
-
additionalProperties:
|
2029
|
+
additionalProperties: false,
|
1594
2030
|
properties: {
|
1595
2031
|
ignore: {
|
1596
2032
|
...ARRAY_DEFAULT_OPTIONS,
|
@@ -1603,7 +2039,8 @@ var RULE_ID2 = "lone-executable-definition", definitionTypes = ["fragment", ...O
|
|
1603
2039
|
}
|
1604
2040
|
}
|
1605
2041
|
}
|
1606
|
-
}
|
2042
|
+
};
|
2043
|
+
var rule4 = {
|
1607
2044
|
meta: {
|
1608
2045
|
type: "suggestion",
|
1609
2046
|
docs: {
|
@@ -1644,16 +2081,23 @@ var RULE_ID2 = "lone-executable-definition", definitionTypes = ["fragment", ...O
|
|
1644
2081
|
schema: schema4
|
1645
2082
|
},
|
1646
2083
|
create(context) {
|
1647
|
-
|
2084
|
+
const ignore = new Set(context.options[0]?.ignore || []);
|
2085
|
+
const definitions = [];
|
1648
2086
|
return {
|
1649
2087
|
":matches(OperationDefinition, FragmentDefinition)"(node) {
|
1650
|
-
|
1651
|
-
ignore.has(type)
|
2088
|
+
const type = "operation" in node ? node.operation : "fragment";
|
2089
|
+
if (!ignore.has(type)) {
|
2090
|
+
definitions.push({ type, node });
|
2091
|
+
}
|
1652
2092
|
},
|
1653
2093
|
"Document:exit"() {
|
1654
|
-
for (
|
1655
|
-
let name = pascalCase(type)
|
1656
|
-
definitionName
|
2094
|
+
for (const { node, type } of definitions.slice(1)) {
|
2095
|
+
let name = pascalCase(type);
|
2096
|
+
const definitionName = node.name?.value;
|
2097
|
+
if (definitionName) {
|
2098
|
+
name += ` "${definitionName}"`;
|
2099
|
+
}
|
2100
|
+
context.report({
|
1657
2101
|
loc: node.name?.loc || getLocation(node.loc.start, type),
|
1658
2102
|
messageId: RULE_ID2,
|
1659
2103
|
data: { name }
|
@@ -1667,27 +2111,32 @@ var RULE_ID2 = "lone-executable-definition", definitionTypes = ["fragment", ...O
|
|
1667
2111
|
// src/rules/match-document-filename/index.ts
|
1668
2112
|
import { basename, extname } from "node:path";
|
1669
2113
|
import { Kind as Kind7 } from "graphql";
|
1670
|
-
var MATCH_EXTENSION = "MATCH_EXTENSION"
|
2114
|
+
var MATCH_EXTENSION = "MATCH_EXTENSION";
|
2115
|
+
var MATCH_STYLE = "MATCH_STYLE";
|
2116
|
+
var CASE_STYLES = [
|
1671
2117
|
"camelCase",
|
1672
2118
|
"PascalCase",
|
1673
2119
|
"snake_case",
|
1674
2120
|
"UPPER_CASE",
|
1675
2121
|
"kebab-case",
|
1676
2122
|
"matchDocumentStyle"
|
1677
|
-
]
|
2123
|
+
];
|
2124
|
+
var schemaOption = {
|
1678
2125
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asObject" }]
|
1679
|
-
}
|
2126
|
+
};
|
2127
|
+
var caseSchema = {
|
2128
|
+
enum: CASE_STYLES,
|
2129
|
+
description: `One of: ${CASE_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
2130
|
+
};
|
2131
|
+
var schema5 = {
|
1680
2132
|
definitions: {
|
1681
|
-
asString:
|
1682
|
-
enum: CASE_STYLES,
|
1683
|
-
description: `One of: ${CASE_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
1684
|
-
},
|
2133
|
+
asString: caseSchema,
|
1685
2134
|
asObject: {
|
1686
2135
|
type: "object",
|
1687
|
-
additionalProperties:
|
2136
|
+
additionalProperties: false,
|
1688
2137
|
minProperties: 1,
|
1689
2138
|
properties: {
|
1690
|
-
style:
|
2139
|
+
style: caseSchema,
|
1691
2140
|
suffix: { type: "string" },
|
1692
2141
|
prefix: { type: "string" }
|
1693
2142
|
}
|
@@ -1698,7 +2147,7 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1698
2147
|
maxItems: 1,
|
1699
2148
|
items: {
|
1700
2149
|
type: "object",
|
1701
|
-
additionalProperties:
|
2150
|
+
additionalProperties: false,
|
1702
2151
|
minProperties: 1,
|
1703
2152
|
properties: {
|
1704
2153
|
fileExtension: { enum: [".gql", ".graphql"] },
|
@@ -1708,7 +2157,8 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1708
2157
|
fragment: schemaOption
|
1709
2158
|
}
|
1710
2159
|
}
|
1711
|
-
}
|
2160
|
+
};
|
2161
|
+
var rule5 = {
|
1712
2162
|
meta: {
|
1713
2163
|
type: "suggestion",
|
1714
2164
|
docs: {
|
@@ -1846,47 +2296,69 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1846
2296
|
schema: schema5
|
1847
2297
|
},
|
1848
2298
|
create(context) {
|
1849
|
-
|
2299
|
+
const options = context.options[0] || {
|
1850
2300
|
fileExtension: null
|
1851
|
-
}
|
1852
|
-
|
2301
|
+
};
|
2302
|
+
const filePath = context.filename;
|
2303
|
+
const isVirtualFile = VIRTUAL_DOCUMENT_REGEX.test(filePath);
|
2304
|
+
if (isVirtualFile) {
|
1853
2305
|
return {};
|
1854
|
-
|
2306
|
+
}
|
2307
|
+
const fileExtension = extname(filePath);
|
2308
|
+
const filename = basename(filePath, fileExtension);
|
1855
2309
|
return {
|
1856
2310
|
Document(documentNode) {
|
1857
|
-
options.fileExtension && options.fileExtension !== fileExtension
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
2311
|
+
if (options.fileExtension && options.fileExtension !== fileExtension) {
|
2312
|
+
context.report({
|
2313
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
2314
|
+
messageId: MATCH_EXTENSION,
|
2315
|
+
data: {
|
2316
|
+
fileExtension,
|
2317
|
+
expectedFileExtension: options.fileExtension
|
2318
|
+
}
|
2319
|
+
});
|
2320
|
+
}
|
2321
|
+
const firstOperation = documentNode.definitions.find(
|
1866
2322
|
(n) => n.kind === Kind7.OPERATION_DEFINITION
|
1867
|
-
)
|
2323
|
+
);
|
2324
|
+
const firstFragment = documentNode.definitions.find(
|
1868
2325
|
(n) => n.kind === Kind7.FRAGMENT_DEFINITION
|
1869
|
-
)
|
1870
|
-
|
2326
|
+
);
|
2327
|
+
const node = firstOperation || firstFragment;
|
2328
|
+
if (!node) {
|
1871
2329
|
return;
|
1872
|
-
|
1873
|
-
|
2330
|
+
}
|
2331
|
+
const docName = node.name?.value;
|
2332
|
+
if (!docName) {
|
1874
2333
|
return;
|
1875
|
-
|
1876
|
-
|
2334
|
+
}
|
2335
|
+
const docType = "operation" in node ? node.operation : "fragment";
|
2336
|
+
let option = options[docType];
|
2337
|
+
if (!option) {
|
1877
2338
|
return;
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
2339
|
+
}
|
2340
|
+
if (typeof option === "string") {
|
2341
|
+
option = { style: option };
|
2342
|
+
}
|
2343
|
+
const expectedExtension = options.fileExtension || fileExtension;
|
2344
|
+
let expectedFilename = option.prefix || "";
|
2345
|
+
if (option.style) {
|
2346
|
+
expectedFilename += option.style === "matchDocumentStyle" ? docName : convertCase(option.style, docName);
|
2347
|
+
} else {
|
2348
|
+
expectedFilename += filename;
|
2349
|
+
}
|
2350
|
+
expectedFilename += (option.suffix || "") + expectedExtension;
|
2351
|
+
const filenameWithExtension = filename + expectedExtension;
|
2352
|
+
if (expectedFilename !== filenameWithExtension) {
|
2353
|
+
context.report({
|
2354
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
2355
|
+
messageId: MATCH_STYLE,
|
2356
|
+
data: {
|
2357
|
+
expectedFilename,
|
2358
|
+
filename: filenameWithExtension
|
2359
|
+
}
|
2360
|
+
});
|
2361
|
+
}
|
1890
2362
|
}
|
1891
2363
|
};
|
1892
2364
|
}
|
@@ -1912,26 +2384,33 @@ var KindToDisplayName = {
|
|
1912
2384
|
[Kind8.OPERATION_DEFINITION]: "Operation",
|
1913
2385
|
[Kind8.FRAGMENT_DEFINITION]: "Fragment",
|
1914
2386
|
[Kind8.VARIABLE_DEFINITION]: "Variable"
|
1915
|
-
}
|
2387
|
+
};
|
2388
|
+
var StyleToRegex = {
|
1916
2389
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
1917
2390
|
PascalCase: /^[A-Z][\dA-Za-z]*$/,
|
1918
2391
|
snake_case: /^[a-z][\d_a-z]*[\da-z]*$/,
|
1919
2392
|
UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]*$/
|
1920
|
-
}
|
2393
|
+
};
|
2394
|
+
var ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
|
2395
|
+
var ALLOWED_STYLES = Object.keys(StyleToRegex);
|
2396
|
+
var schemaOption2 = {
|
1921
2397
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asObject" }]
|
1922
|
-
}
|
2398
|
+
};
|
2399
|
+
var descriptionPrefixesSuffixes = (name, id) => `> [!WARNING]
|
1923
2400
|
>
|
1924
|
-
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${
|
2401
|
+
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${id}) instead.`;
|
2402
|
+
var caseSchema2 = {
|
2403
|
+
enum: ALLOWED_STYLES,
|
2404
|
+
description: `One of: ${ALLOWED_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
2405
|
+
};
|
2406
|
+
var schema6 = {
|
1925
2407
|
definitions: {
|
1926
|
-
asString:
|
1927
|
-
enum: ALLOWED_STYLES,
|
1928
|
-
description: `One of: ${ALLOWED_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
1929
|
-
},
|
2408
|
+
asString: caseSchema2,
|
1930
2409
|
asObject: {
|
1931
2410
|
type: "object",
|
1932
|
-
additionalProperties:
|
2411
|
+
additionalProperties: false,
|
1933
2412
|
properties: {
|
1934
|
-
style:
|
2413
|
+
style: caseSchema2,
|
1935
2414
|
prefix: { type: "string" },
|
1936
2415
|
suffix: { type: "string" },
|
1937
2416
|
forbiddenPatterns: {
|
@@ -1941,28 +2420,25 @@ var KindToDisplayName = {
|
|
1941
2420
|
},
|
1942
2421
|
description: "Should be of instance of `RegEx`"
|
1943
2422
|
},
|
1944
|
-
|
1945
|
-
|
1946
|
-
items: {
|
1947
|
-
type: "object"
|
1948
|
-
},
|
2423
|
+
requiredPattern: {
|
2424
|
+
type: "object",
|
1949
2425
|
description: "Should be of instance of `RegEx`"
|
1950
2426
|
},
|
1951
2427
|
forbiddenPrefixes: {
|
1952
2428
|
...ARRAY_DEFAULT_OPTIONS,
|
1953
|
-
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
2429
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
|
1954
2430
|
},
|
1955
2431
|
forbiddenSuffixes: {
|
1956
2432
|
...ARRAY_DEFAULT_OPTIONS,
|
1957
|
-
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
2433
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
|
1958
2434
|
},
|
1959
2435
|
requiredPrefixes: {
|
1960
2436
|
...ARRAY_DEFAULT_OPTIONS,
|
1961
|
-
description: descriptionPrefixesSuffixes("
|
2437
|
+
description: descriptionPrefixesSuffixes("requiredPattern", "requiredpattern-object")
|
1962
2438
|
},
|
1963
2439
|
requiredSuffixes: {
|
1964
2440
|
...ARRAY_DEFAULT_OPTIONS,
|
1965
|
-
description: descriptionPrefixesSuffixes("
|
2441
|
+
description: descriptionPrefixesSuffixes("requiredPattern", "requiredpattern-object")
|
1966
2442
|
},
|
1967
2443
|
ignorePattern: {
|
1968
2444
|
type: "string",
|
@@ -1975,13 +2451,12 @@ var KindToDisplayName = {
|
|
1975
2451
|
maxItems: 1,
|
1976
2452
|
items: {
|
1977
2453
|
type: "object",
|
1978
|
-
additionalProperties:
|
2454
|
+
additionalProperties: false,
|
1979
2455
|
properties: {
|
1980
2456
|
types: {
|
1981
2457
|
...schemaOption2,
|
1982
2458
|
description: `Includes:
|
1983
|
-
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
1984
|
-
`)}`
|
2459
|
+
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
|
1985
2460
|
},
|
1986
2461
|
...Object.fromEntries(
|
1987
2462
|
ALLOWED_KINDS.map((kind) => [
|
@@ -1996,11 +2471,11 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
1996
2471
|
),
|
1997
2472
|
allowLeadingUnderscore: {
|
1998
2473
|
type: "boolean",
|
1999
|
-
default:
|
2474
|
+
default: false
|
2000
2475
|
},
|
2001
2476
|
allowTrailingUnderscore: {
|
2002
2477
|
type: "boolean",
|
2003
|
-
default:
|
2478
|
+
default: false
|
2004
2479
|
}
|
2005
2480
|
},
|
2006
2481
|
patternProperties: {
|
@@ -2012,16 +2487,16 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2012
2487
|
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.",
|
2013
2488
|
">",
|
2014
2489
|
"> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`."
|
2015
|
-
].join(
|
2016
|
-
`)
|
2490
|
+
].join("\n")
|
2017
2491
|
}
|
2018
|
-
}
|
2492
|
+
};
|
2493
|
+
var rule6 = {
|
2019
2494
|
meta: {
|
2020
2495
|
type: "suggestion",
|
2021
2496
|
docs: {
|
2022
2497
|
description: "Require names to follow specified conventions.",
|
2023
2498
|
category: ["Schema", "Operations"],
|
2024
|
-
recommended:
|
2499
|
+
recommended: true,
|
2025
2500
|
url: "https://the-guild.dev/graphql/eslint/rules/naming-convention",
|
2026
2501
|
examples: [
|
2027
2502
|
{
|
@@ -2155,6 +2630,30 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2155
2630
|
}
|
2156
2631
|
`
|
2157
2632
|
)
|
2633
|
+
},
|
2634
|
+
{
|
2635
|
+
title: "Correct (Relay fragment convention `<module_name>_<property_name>`)",
|
2636
|
+
usage: [
|
2637
|
+
{
|
2638
|
+
FragmentDefinition: {
|
2639
|
+
style: "PascalCase",
|
2640
|
+
requiredPattern: /_(?<camelCase>.+?)$/
|
2641
|
+
}
|
2642
|
+
}
|
2643
|
+
],
|
2644
|
+
code: (
|
2645
|
+
/* GraphQL */
|
2646
|
+
`
|
2647
|
+
# schema
|
2648
|
+
type User {
|
2649
|
+
# ...
|
2650
|
+
}
|
2651
|
+
# operations
|
2652
|
+
fragment UserFields_data on User {
|
2653
|
+
# ...
|
2654
|
+
}
|
2655
|
+
`
|
2656
|
+
)
|
2158
2657
|
}
|
2159
2658
|
],
|
2160
2659
|
configOptions: {
|
@@ -2213,14 +2712,16 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2213
2712
|
]
|
2214
2713
|
}
|
2215
2714
|
},
|
2216
|
-
hasSuggestions:
|
2715
|
+
hasSuggestions: true,
|
2217
2716
|
schema: schema6
|
2218
2717
|
},
|
2219
2718
|
create(context) {
|
2220
|
-
|
2719
|
+
const options = context.options[0] || {};
|
2720
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
2721
|
+
const ignoredNodes = /* @__PURE__ */ new Set();
|
2221
2722
|
function normalisePropertyOption(kind) {
|
2222
|
-
|
2223
|
-
return typeof style
|
2723
|
+
const style = restOptions[kind] || types;
|
2724
|
+
return typeof style === "object" ? style : { style };
|
2224
2725
|
}
|
2225
2726
|
function report(node, message, suggestedNames) {
|
2226
2727
|
context.report({
|
@@ -2232,11 +2733,12 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2232
2733
|
}))
|
2233
2734
|
});
|
2234
2735
|
}
|
2235
|
-
|
2236
|
-
|
2237
|
-
if (!node)
|
2736
|
+
const checkNode2 = (selector) => (n) => {
|
2737
|
+
const { name: node } = n.kind === Kind8.VARIABLE_DEFINITION ? n.variable : n;
|
2738
|
+
if (!node) {
|
2238
2739
|
return;
|
2239
|
-
|
2740
|
+
}
|
2741
|
+
const {
|
2240
2742
|
prefix,
|
2241
2743
|
suffix,
|
2242
2744
|
forbiddenPrefixes,
|
@@ -2246,12 +2748,18 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2246
2748
|
requiredPrefixes,
|
2247
2749
|
requiredSuffixes,
|
2248
2750
|
forbiddenPatterns,
|
2249
|
-
|
2250
|
-
} = normalisePropertyOption(selector)
|
2751
|
+
requiredPattern
|
2752
|
+
} = normalisePropertyOption(selector);
|
2753
|
+
const nodeName = node.value;
|
2754
|
+
const error = getError();
|
2251
2755
|
if (error) {
|
2252
|
-
|
2756
|
+
const { errorMessage, renameToNames } = error;
|
2757
|
+
const [leadingUnderscores] = nodeName.match(/^_*/);
|
2758
|
+
const [trailingUnderscores] = nodeName.match(/_*$/);
|
2759
|
+
const suggestedNames = renameToNames.map(
|
2253
2760
|
(renameToName) => leadingUnderscores + renameToName + trailingUnderscores
|
2254
|
-
)
|
2761
|
+
);
|
2762
|
+
const name = displayNodeName(n);
|
2255
2763
|
report(
|
2256
2764
|
node,
|
2257
2765
|
`${name[0].toUpperCase()}${name.slice(1)} should ${errorMessage}`,
|
@@ -2259,94 +2767,148 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2259
2767
|
);
|
2260
2768
|
}
|
2261
2769
|
function getError() {
|
2262
|
-
let name = nodeName
|
2770
|
+
let name = nodeName;
|
2771
|
+
if (allowLeadingUnderscore) name = name.replace(/^_+/, "");
|
2772
|
+
if (allowTrailingUnderscore) name = name.replace(/_+$/, "");
|
2263
2773
|
if (ignorePattern && new RegExp(ignorePattern, "u").test(name)) {
|
2264
|
-
"name" in n
|
2774
|
+
if ("name" in n) {
|
2775
|
+
ignoredNodes.add(n.name);
|
2776
|
+
}
|
2265
2777
|
return;
|
2266
2778
|
}
|
2267
|
-
if (prefix && !name.startsWith(prefix))
|
2779
|
+
if (prefix && !name.startsWith(prefix)) {
|
2268
2780
|
return {
|
2269
2781
|
errorMessage: `have "${prefix}" prefix`,
|
2270
2782
|
renameToNames: [prefix + name]
|
2271
2783
|
};
|
2272
|
-
|
2784
|
+
}
|
2785
|
+
if (suffix && !name.endsWith(suffix)) {
|
2273
2786
|
return {
|
2274
2787
|
errorMessage: `have "${suffix}" suffix`,
|
2275
2788
|
renameToNames: [name + suffix]
|
2276
2789
|
};
|
2277
|
-
|
2278
|
-
if (
|
2790
|
+
}
|
2791
|
+
if (requiredPattern) {
|
2792
|
+
if (requiredPattern.source.includes("(?<")) {
|
2793
|
+
try {
|
2794
|
+
name = name.replace(requiredPattern, (originalString, ...args) => {
|
2795
|
+
const groups = args.at(-1);
|
2796
|
+
for (const [styleName, value] of Object.entries(groups)) {
|
2797
|
+
if (!(styleName in StyleToRegex)) {
|
2798
|
+
throw new Error("Invalid case style in `requiredPatterns` option");
|
2799
|
+
}
|
2800
|
+
if (value === convertCase(styleName, value)) {
|
2801
|
+
return "";
|
2802
|
+
}
|
2803
|
+
throw new Error(`contain the required pattern: ${requiredPattern}`);
|
2804
|
+
}
|
2805
|
+
return originalString;
|
2806
|
+
});
|
2807
|
+
if (name === nodeName) {
|
2808
|
+
throw new Error(`contain the required pattern: ${requiredPattern}`);
|
2809
|
+
}
|
2810
|
+
} catch (error2) {
|
2811
|
+
return {
|
2812
|
+
errorMessage: error2.message,
|
2813
|
+
renameToNames: []
|
2814
|
+
};
|
2815
|
+
}
|
2816
|
+
} else if (!requiredPattern.test(name)) {
|
2817
|
+
return {
|
2818
|
+
errorMessage: `contain the required pattern: ${requiredPattern}`,
|
2819
|
+
renameToNames: []
|
2820
|
+
};
|
2821
|
+
}
|
2822
|
+
}
|
2823
|
+
const forbidden = forbiddenPatterns?.find((pattern) => pattern.test(name));
|
2824
|
+
if (forbidden) {
|
2279
2825
|
return {
|
2280
2826
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
2281
2827
|
renameToNames: [name.replace(forbidden, "")]
|
2282
2828
|
};
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
renameToNames: []
|
2287
|
-
};
|
2288
|
-
let forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
|
2289
|
-
if (forbiddenPrefix)
|
2829
|
+
}
|
2830
|
+
const forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
|
2831
|
+
if (forbiddenPrefix) {
|
2290
2832
|
return {
|
2291
2833
|
errorMessage: `not have "${forbiddenPrefix}" prefix`,
|
2292
2834
|
renameToNames: [name.replace(new RegExp(`^${forbiddenPrefix}`), "")]
|
2293
2835
|
};
|
2294
|
-
|
2295
|
-
|
2836
|
+
}
|
2837
|
+
const forbiddenSuffix = forbiddenSuffixes?.find((suffix2) => name.endsWith(suffix2));
|
2838
|
+
if (forbiddenSuffix) {
|
2296
2839
|
return {
|
2297
2840
|
errorMessage: `not have "${forbiddenSuffix}" suffix`,
|
2298
2841
|
renameToNames: [name.replace(new RegExp(`${forbiddenSuffix}$`), "")]
|
2299
2842
|
};
|
2300
|
-
|
2843
|
+
}
|
2844
|
+
if (requiredPrefixes && !requiredPrefixes.some((requiredPrefix) => name.startsWith(requiredPrefix))) {
|
2301
2845
|
return {
|
2302
2846
|
errorMessage: `have one of the following prefixes: ${englishJoinWords(
|
2303
2847
|
requiredPrefixes
|
2304
2848
|
)}`,
|
2305
2849
|
renameToNames: style ? requiredPrefixes.map((prefix2) => convertCase(style, `${prefix2} ${name}`)) : requiredPrefixes.map((prefix2) => `${prefix2}${name}`)
|
2306
2850
|
};
|
2307
|
-
|
2851
|
+
}
|
2852
|
+
if (requiredSuffixes && !requiredSuffixes.some((requiredSuffix) => name.endsWith(requiredSuffix))) {
|
2308
2853
|
return {
|
2309
2854
|
errorMessage: `have one of the following suffixes: ${englishJoinWords(
|
2310
2855
|
requiredSuffixes
|
2311
2856
|
)}`,
|
2312
2857
|
renameToNames: style ? requiredSuffixes.map((suffix2) => convertCase(style, `${name} ${suffix2}`)) : requiredSuffixes.map((suffix2) => `${name}${suffix2}`)
|
2313
2858
|
};
|
2314
|
-
|
2859
|
+
}
|
2860
|
+
if (!style) {
|
2315
2861
|
return;
|
2316
|
-
|
2862
|
+
}
|
2863
|
+
const caseRegex = StyleToRegex[style];
|
2864
|
+
if (!caseRegex.test(name)) {
|
2317
2865
|
return {
|
2318
2866
|
errorMessage: `be in ${style} format`,
|
2319
2867
|
renameToNames: [convertCase(style, name)]
|
2320
2868
|
};
|
2869
|
+
}
|
2870
|
+
}
|
2871
|
+
};
|
2872
|
+
const checkUnderscore = (isLeading) => (node) => {
|
2873
|
+
if (ignoredNodes.has(node)) {
|
2874
|
+
return;
|
2321
2875
|
}
|
2322
|
-
|
2323
|
-
if (ignoredNodes.has(node) || node.parent.kind === "Field" && node.parent.alias !== node)
|
2876
|
+
if (node.parent.kind === "Field" && node.parent.alias !== node) {
|
2324
2877
|
return;
|
2325
|
-
|
2878
|
+
}
|
2879
|
+
const suggestedName = node.value.replace(isLeading ? /^_+/ : /_+$/, "");
|
2326
2880
|
report(node, `${isLeading ? "Leading" : "Trailing"} underscores are not allowed`, [
|
2327
2881
|
suggestedName
|
2328
2882
|
]);
|
2329
|
-
}
|
2330
|
-
|
2331
|
-
|
2883
|
+
};
|
2884
|
+
const listeners = {};
|
2885
|
+
if (!allowLeadingUnderscore) {
|
2886
|
+
listeners["Name[value=/^_/]"] = checkUnderscore(true);
|
2887
|
+
}
|
2888
|
+
if (!allowTrailingUnderscore) {
|
2889
|
+
listeners["Name[value=/_$/]"] = checkUnderscore(false);
|
2890
|
+
}
|
2891
|
+
const selectors = new Set(
|
2332
2892
|
[types && TYPES_KINDS, Object.keys(restOptions)].filter((v) => !!v).flat()
|
2333
2893
|
);
|
2334
|
-
for (
|
2894
|
+
for (const selector of selectors) {
|
2335
2895
|
listeners[selector] = checkNode2(selector);
|
2896
|
+
}
|
2336
2897
|
return listeners;
|
2337
2898
|
}
|
2338
2899
|
};
|
2339
2900
|
|
2340
2901
|
// src/rules/no-anonymous-operations/index.ts
|
2341
2902
|
import { Kind as Kind9 } from "graphql";
|
2342
|
-
var RULE_ID3 = "no-anonymous-operations"
|
2903
|
+
var RULE_ID3 = "no-anonymous-operations";
|
2904
|
+
var rule7 = {
|
2343
2905
|
meta: {
|
2344
2906
|
type: "suggestion",
|
2345
|
-
hasSuggestions:
|
2907
|
+
hasSuggestions: true,
|
2346
2908
|
docs: {
|
2347
2909
|
category: "Operations",
|
2348
2910
|
description: "Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.",
|
2349
|
-
recommended:
|
2911
|
+
recommended: true,
|
2350
2912
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID3}`,
|
2351
2913
|
examples: [
|
2352
2914
|
{
|
@@ -2381,7 +2943,8 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2381
2943
|
create(context) {
|
2382
2944
|
return {
|
2383
2945
|
"OperationDefinition[name=undefined]"(node) {
|
2384
|
-
|
2946
|
+
const [firstSelection] = node.selectionSet.selections;
|
2947
|
+
const suggestedName = firstSelection.kind === Kind9.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
|
2385
2948
|
context.report({
|
2386
2949
|
loc: getLocation(node.loc.start, node.operation),
|
2387
2950
|
messageId: RULE_ID3,
|
@@ -2392,7 +2955,8 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2392
2955
|
{
|
2393
2956
|
desc: `Rename to \`${suggestedName}\``,
|
2394
2957
|
fix(fixer) {
|
2395
|
-
|
2958
|
+
const sourceCode = context.getSourceCode();
|
2959
|
+
const hasQueryKeyword = sourceCode.getText({ range: [node.range[0], node.range[0] + 1] }) !== "{";
|
2396
2960
|
return fixer.insertTextAfterRange(
|
2397
2961
|
[node.range[0], node.range[0] + (hasQueryKeyword ? node.operation.length : 0)],
|
2398
2962
|
`${hasQueryKeyword ? "" : "query"} ${suggestedName}${hasQueryKeyword ? "" : " "}`
|
@@ -2407,15 +2971,16 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2407
2971
|
};
|
2408
2972
|
|
2409
2973
|
// src/rules/no-deprecated/index.ts
|
2410
|
-
var RULE_ID4 = "no-deprecated"
|
2974
|
+
var RULE_ID4 = "no-deprecated";
|
2975
|
+
var rule8 = {
|
2411
2976
|
meta: {
|
2412
2977
|
type: "suggestion",
|
2413
|
-
hasSuggestions:
|
2978
|
+
hasSuggestions: true,
|
2414
2979
|
docs: {
|
2415
2980
|
category: "Operations",
|
2416
2981
|
description: "Enforce that deprecated fields or enum values are not in use by operations.",
|
2417
2982
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID4}`,
|
2418
|
-
requiresSchema:
|
2983
|
+
requiresSchema: true,
|
2419
2984
|
examples: [
|
2420
2985
|
{
|
2421
2986
|
title: "Incorrect (field)",
|
@@ -2487,7 +3052,7 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2487
3052
|
)
|
2488
3053
|
}
|
2489
3054
|
],
|
2490
|
-
recommended:
|
3055
|
+
recommended: true
|
2491
3056
|
},
|
2492
3057
|
messages: {
|
2493
3058
|
[RULE_ID4]: "{{ type }} is marked as deprecated in your GraphQL schema (reason: {{ reason }})"
|
@@ -2497,7 +3062,7 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2497
3062
|
create(context) {
|
2498
3063
|
requireGraphQLSchema(RULE_ID4, context);
|
2499
3064
|
function report(node, reason) {
|
2500
|
-
|
3065
|
+
const nodeType = displayNodeName(node);
|
2501
3066
|
context.report({
|
2502
3067
|
node,
|
2503
3068
|
messageId: RULE_ID4,
|
@@ -2515,24 +3080,37 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2515
3080
|
}
|
2516
3081
|
return {
|
2517
3082
|
EnumValue(node) {
|
2518
|
-
|
2519
|
-
reason
|
3083
|
+
const typeInfo = node.typeInfo();
|
3084
|
+
const reason = typeInfo.enumValue?.deprecationReason;
|
3085
|
+
if (reason) {
|
3086
|
+
report(node, reason);
|
3087
|
+
}
|
2520
3088
|
},
|
2521
3089
|
Field(node) {
|
2522
|
-
|
2523
|
-
reason
|
3090
|
+
const typeInfo = node.typeInfo();
|
3091
|
+
const reason = typeInfo.fieldDef?.deprecationReason;
|
3092
|
+
if (reason) {
|
3093
|
+
report(node, reason);
|
3094
|
+
}
|
2524
3095
|
},
|
2525
3096
|
Argument(node) {
|
2526
|
-
|
2527
|
-
reason
|
3097
|
+
const typeInfo = node.typeInfo();
|
3098
|
+
const reason = typeInfo.argument?.deprecationReason;
|
3099
|
+
if (reason) {
|
3100
|
+
report(node, reason);
|
3101
|
+
}
|
2528
3102
|
},
|
2529
3103
|
ObjectValue(node) {
|
2530
|
-
|
2531
|
-
if (inputType
|
2532
|
-
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
3104
|
+
const { inputType } = node.typeInfo();
|
3105
|
+
if (!inputType) return;
|
3106
|
+
if ("getFields" in inputType) {
|
3107
|
+
const fields = inputType.getFields();
|
3108
|
+
for (const field of node.fields) {
|
3109
|
+
const fieldName = field.name.value;
|
3110
|
+
const reason = fields[fieldName].deprecationReason;
|
3111
|
+
if (reason) {
|
3112
|
+
report(field, reason);
|
3113
|
+
}
|
2536
3114
|
}
|
2537
3115
|
}
|
2538
3116
|
}
|
@@ -2542,15 +3120,16 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2542
3120
|
|
2543
3121
|
// src/rules/no-duplicate-fields/index.ts
|
2544
3122
|
import { Kind as Kind10 } from "graphql";
|
2545
|
-
var RULE_ID5 = "no-duplicate-fields"
|
3123
|
+
var RULE_ID5 = "no-duplicate-fields";
|
3124
|
+
var rule9 = {
|
2546
3125
|
meta: {
|
2547
3126
|
type: "suggestion",
|
2548
|
-
hasSuggestions:
|
3127
|
+
hasSuggestions: true,
|
2549
3128
|
docs: {
|
2550
3129
|
description: "Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.",
|
2551
3130
|
category: "Operations",
|
2552
3131
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID5}`,
|
2553
|
-
recommended:
|
3132
|
+
recommended: true,
|
2554
3133
|
examples: [
|
2555
3134
|
{
|
2556
3135
|
title: "Incorrect",
|
@@ -2610,9 +3189,9 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2610
3189
|
},
|
2611
3190
|
create(context) {
|
2612
3191
|
function checkNode2(usedFields, node) {
|
2613
|
-
|
3192
|
+
const fieldName = node.value;
|
2614
3193
|
if (usedFields.has(fieldName)) {
|
2615
|
-
|
3194
|
+
const { parent } = node;
|
2616
3195
|
context.report({
|
2617
3196
|
node,
|
2618
3197
|
messageId: RULE_ID5,
|
@@ -2631,24 +3210,30 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2631
3210
|
}
|
2632
3211
|
]
|
2633
3212
|
});
|
2634
|
-
} else
|
3213
|
+
} else {
|
2635
3214
|
usedFields.add(fieldName);
|
3215
|
+
}
|
2636
3216
|
}
|
2637
3217
|
return {
|
2638
3218
|
OperationDefinition(node) {
|
2639
|
-
|
2640
|
-
for (
|
3219
|
+
const set = /* @__PURE__ */ new Set();
|
3220
|
+
for (const varDef of node.variableDefinitions || []) {
|
2641
3221
|
checkNode2(set, varDef.variable.name);
|
3222
|
+
}
|
2642
3223
|
},
|
2643
3224
|
Field(node) {
|
2644
|
-
|
2645
|
-
for (
|
3225
|
+
const set = /* @__PURE__ */ new Set();
|
3226
|
+
for (const arg of node.arguments || []) {
|
2646
3227
|
checkNode2(set, arg.name);
|
3228
|
+
}
|
2647
3229
|
},
|
2648
3230
|
SelectionSet(node) {
|
2649
|
-
|
2650
|
-
for (
|
2651
|
-
selection.kind === Kind10.FIELD
|
3231
|
+
const set = /* @__PURE__ */ new Set();
|
3232
|
+
for (const selection of node.selections) {
|
3233
|
+
if (selection.kind === Kind10.FIELD) {
|
3234
|
+
checkNode2(set, selection.alias || selection.name);
|
3235
|
+
}
|
3236
|
+
}
|
2652
3237
|
}
|
2653
3238
|
};
|
2654
3239
|
}
|
@@ -2656,10 +3241,11 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2656
3241
|
|
2657
3242
|
// src/rules/no-hashtag-description/index.ts
|
2658
3243
|
import { TokenKind as TokenKind2 } from "graphql";
|
2659
|
-
var RULE_ID6 = "HASHTAG_COMMENT"
|
3244
|
+
var RULE_ID6 = "HASHTAG_COMMENT";
|
3245
|
+
var rule10 = {
|
2660
3246
|
meta: {
|
2661
3247
|
type: "suggestion",
|
2662
|
-
hasSuggestions:
|
3248
|
+
hasSuggestions: true,
|
2663
3249
|
schema: [],
|
2664
3250
|
messages: {
|
2665
3251
|
[RULE_ID6]: 'Unexpected GraphQL descriptions as hashtag `#` for {{ nodeName }}.\nPrefer using `"""` for multiline, or `"` for a single line description.'
|
@@ -2712,21 +3298,27 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2712
3298
|
)
|
2713
3299
|
}
|
2714
3300
|
],
|
2715
|
-
recommended:
|
3301
|
+
recommended: true
|
2716
3302
|
}
|
2717
3303
|
},
|
2718
3304
|
create(context) {
|
3305
|
+
const selector = "Document[definitions.0.kind!=/^(OperationDefinition|FragmentDefinition)$/]";
|
2719
3306
|
return {
|
2720
|
-
[
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
3307
|
+
[selector](node) {
|
3308
|
+
const rawNode = node.rawNode();
|
3309
|
+
let token = rawNode.loc.startToken;
|
3310
|
+
while (token) {
|
3311
|
+
const { kind, prev, next, value, line, column } = token;
|
2724
3312
|
if (kind === TokenKind2.COMMENT && prev && next) {
|
2725
|
-
|
3313
|
+
const isEslintComment = value.trimStart().startsWith("eslint");
|
3314
|
+
const linesAfter = next.line - line;
|
2726
3315
|
if (!isEslintComment && line !== prev.line && next.kind === TokenKind2.NAME && linesAfter < 2) {
|
2727
|
-
|
3316
|
+
const sourceCode = context.getSourceCode();
|
3317
|
+
const { tokens } = sourceCode.ast;
|
3318
|
+
const t = tokens.find(
|
2728
3319
|
(token2) => token2.loc.start.line === next.line && token2.loc.start.column === next.column - 1
|
2729
|
-
)
|
3320
|
+
);
|
3321
|
+
const nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
|
2730
3322
|
context.report({
|
2731
3323
|
messageId: RULE_ID6,
|
2732
3324
|
data: {
|
@@ -2748,8 +3340,9 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2748
3340
|
});
|
2749
3341
|
}
|
2750
3342
|
}
|
2751
|
-
if (!next)
|
3343
|
+
if (!next) {
|
2752
3344
|
break;
|
3345
|
+
}
|
2753
3346
|
token = next;
|
2754
3347
|
}
|
2755
3348
|
}
|
@@ -2760,7 +3353,8 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2760
3353
|
// src/rules/no-one-place-fragments/index.ts
|
2761
3354
|
import { relative } from "node:path";
|
2762
3355
|
import { visit as visit4 } from "graphql";
|
2763
|
-
var RULE_ID7 = "no-one-place-fragments"
|
3356
|
+
var RULE_ID7 = "no-one-place-fragments";
|
3357
|
+
var rule11 = {
|
2764
3358
|
meta: {
|
2765
3359
|
type: "suggestion",
|
2766
3360
|
docs: {
|
@@ -2806,7 +3400,7 @@ var RULE_ID7 = "no-one-place-fragments", rule11 = {
|
|
2806
3400
|
)
|
2807
3401
|
}
|
2808
3402
|
],
|
2809
|
-
requiresSiblings:
|
3403
|
+
requiresSiblings: true
|
2810
3404
|
},
|
2811
3405
|
messages: {
|
2812
3406
|
[RULE_ID7]: 'Fragment `{{fragmentName}}` used only once. Inline him in "{{filePath}}".'
|
@@ -2814,24 +3408,30 @@ var RULE_ID7 = "no-one-place-fragments", rule11 = {
|
|
2814
3408
|
schema: []
|
2815
3409
|
},
|
2816
3410
|
create(context) {
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
3411
|
+
const operations = requireGraphQLOperations(RULE_ID7, context);
|
3412
|
+
const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
|
3413
|
+
const usedFragmentsMap = /* @__PURE__ */ Object.create(null);
|
3414
|
+
for (const { document, filePath } of allDocuments) {
|
3415
|
+
const relativeFilePath = relative(CWD, filePath);
|
2820
3416
|
visit4(document, {
|
2821
3417
|
FragmentSpread({ name }) {
|
2822
|
-
|
2823
|
-
usedFragmentsMap[spreadName] ||= []
|
3418
|
+
const spreadName = name.value;
|
3419
|
+
usedFragmentsMap[spreadName] ||= [];
|
3420
|
+
usedFragmentsMap[spreadName].push(relativeFilePath);
|
2824
3421
|
}
|
2825
3422
|
});
|
2826
3423
|
}
|
2827
3424
|
return {
|
2828
3425
|
"FragmentDefinition > Name"(node) {
|
2829
|
-
|
2830
|
-
fragmentUsage
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
3426
|
+
const fragmentName = node.value;
|
3427
|
+
const fragmentUsage = usedFragmentsMap[fragmentName];
|
3428
|
+
if (fragmentUsage.length === 1) {
|
3429
|
+
context.report({
|
3430
|
+
node,
|
3431
|
+
messageId: RULE_ID7,
|
3432
|
+
data: { fragmentName, filePath: fragmentUsage[0] }
|
3433
|
+
});
|
3434
|
+
}
|
2835
3435
|
}
|
2836
3436
|
};
|
2837
3437
|
}
|
@@ -2844,7 +3444,7 @@ var schema7 = {
|
|
2844
3444
|
maxItems: 1,
|
2845
3445
|
items: {
|
2846
3446
|
type: "object",
|
2847
|
-
additionalProperties:
|
3447
|
+
additionalProperties: false,
|
2848
3448
|
required: ["disallow"],
|
2849
3449
|
properties: {
|
2850
3450
|
disallow: {
|
@@ -2855,15 +3455,16 @@ var schema7 = {
|
|
2855
3455
|
}
|
2856
3456
|
}
|
2857
3457
|
}
|
2858
|
-
}
|
3458
|
+
};
|
3459
|
+
var rule12 = {
|
2859
3460
|
meta: {
|
2860
3461
|
type: "suggestion",
|
2861
|
-
hasSuggestions:
|
3462
|
+
hasSuggestions: true,
|
2862
3463
|
docs: {
|
2863
3464
|
category: "Schema",
|
2864
3465
|
description: "Disallow using root types `mutation` and/or `subscription`.",
|
2865
3466
|
url: "https://the-guild.dev/graphql/eslint/rules/no-root-type",
|
2866
|
-
requiresSchema:
|
3467
|
+
requiresSchema: true,
|
2867
3468
|
examples: [
|
2868
3469
|
{
|
2869
3470
|
title: "Incorrect",
|
@@ -2895,13 +3496,19 @@ var schema7 = {
|
|
2895
3496
|
schema: schema7
|
2896
3497
|
},
|
2897
3498
|
create(context) {
|
2898
|
-
|
3499
|
+
const schema16 = requireGraphQLSchema("no-root-type", context);
|
3500
|
+
const disallow = new Set(context.options[0].disallow);
|
3501
|
+
const rootTypeNames = [
|
2899
3502
|
disallow.has("mutation") && schema16.getMutationType(),
|
2900
3503
|
disallow.has("subscription") && schema16.getSubscriptionType()
|
2901
3504
|
].filter((v) => !!v).map((type) => type.name).join("|");
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
3505
|
+
if (!rootTypeNames) {
|
3506
|
+
return {};
|
3507
|
+
}
|
3508
|
+
const selector = `:matches(ObjectTypeDefinition, ObjectTypeExtension) > .name[value=/^(${rootTypeNames})$/]`;
|
3509
|
+
return {
|
3510
|
+
[selector](node) {
|
3511
|
+
const typeName = node.value;
|
2905
3512
|
context.report({
|
2906
3513
|
node,
|
2907
3514
|
message: `Root type \`${typeName}\` is forbidden.`,
|
@@ -2913,21 +3520,22 @@ var schema7 = {
|
|
2913
3520
|
]
|
2914
3521
|
});
|
2915
3522
|
}
|
2916
|
-
}
|
3523
|
+
};
|
2917
3524
|
}
|
2918
3525
|
};
|
2919
3526
|
|
2920
3527
|
// src/rules/no-scalar-result-type-on-mutation/index.ts
|
2921
3528
|
import { isScalarType, Kind as Kind11 } from "graphql";
|
2922
|
-
var RULE_ID8 = "no-scalar-result-type-on-mutation"
|
3529
|
+
var RULE_ID8 = "no-scalar-result-type-on-mutation";
|
3530
|
+
var rule13 = {
|
2923
3531
|
meta: {
|
2924
3532
|
type: "suggestion",
|
2925
|
-
hasSuggestions:
|
3533
|
+
hasSuggestions: true,
|
2926
3534
|
docs: {
|
2927
3535
|
category: "Schema",
|
2928
3536
|
description: "Avoid scalar result type on mutation type to make sure to return a valid state.",
|
2929
3537
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID8}`,
|
2930
|
-
requiresSchema:
|
3538
|
+
requiresSchema: true,
|
2931
3539
|
examples: [
|
2932
3540
|
{
|
2933
3541
|
title: "Incorrect",
|
@@ -2956,17 +3564,24 @@ var RULE_ID8 = "no-scalar-result-type-on-mutation", rule13 = {
|
|
2956
3564
|
schema: []
|
2957
3565
|
},
|
2958
3566
|
create(context) {
|
2959
|
-
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
2963
|
-
|
2964
|
-
|
2965
|
-
|
3567
|
+
const schema16 = requireGraphQLSchema(RULE_ID8, context);
|
3568
|
+
const mutationType = schema16.getMutationType();
|
3569
|
+
if (!mutationType) {
|
3570
|
+
return {};
|
3571
|
+
}
|
3572
|
+
const selector = [
|
3573
|
+
`:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}]`,
|
3574
|
+
"> FieldDefinition > .gqlType Name"
|
3575
|
+
].join(" ");
|
3576
|
+
return {
|
3577
|
+
[selector](node) {
|
3578
|
+
const typeName = node.value;
|
3579
|
+
const graphQLType = schema16.getType(typeName);
|
2966
3580
|
if (isScalarType(graphQLType)) {
|
2967
3581
|
let fieldDef = node.parent;
|
2968
|
-
|
3582
|
+
while (fieldDef.kind !== Kind11.FIELD_DEFINITION) {
|
2969
3583
|
fieldDef = fieldDef.parent;
|
3584
|
+
}
|
2970
3585
|
context.report({
|
2971
3586
|
node,
|
2972
3587
|
message: `Unexpected scalar result type \`${typeName}\` for ${getNodeName(fieldDef)}`,
|
@@ -2979,19 +3594,20 @@ var RULE_ID8 = "no-scalar-result-type-on-mutation", rule13 = {
|
|
2979
3594
|
});
|
2980
3595
|
}
|
2981
3596
|
}
|
2982
|
-
}
|
3597
|
+
};
|
2983
3598
|
}
|
2984
3599
|
};
|
2985
3600
|
|
2986
3601
|
// src/rules/no-typename-prefix/index.ts
|
2987
|
-
var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX"
|
3602
|
+
var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX";
|
3603
|
+
var rule14 = {
|
2988
3604
|
meta: {
|
2989
3605
|
type: "suggestion",
|
2990
|
-
hasSuggestions:
|
3606
|
+
hasSuggestions: true,
|
2991
3607
|
docs: {
|
2992
3608
|
category: "Schema",
|
2993
3609
|
description: "Enforces users to avoid using the type name in a field name while defining your schema.",
|
2994
|
-
recommended:
|
3610
|
+
recommended: true,
|
2995
3611
|
url: "https://the-guild.dev/graphql/eslint/rules/no-typename-prefix",
|
2996
3612
|
examples: [
|
2997
3613
|
{
|
@@ -3026,26 +3642,29 @@ var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX", rule14 = {
|
|
3026
3642
|
create(context) {
|
3027
3643
|
return {
|
3028
3644
|
"ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension"(node) {
|
3029
|
-
|
3030
|
-
|
3031
|
-
|
3032
|
-
fieldName
|
3033
|
-
|
3034
|
-
|
3035
|
-
|
3036
|
-
|
3037
|
-
|
3038
|
-
|
3039
|
-
|
3040
|
-
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3046
|
-
|
3047
|
-
|
3048
|
-
|
3645
|
+
const typeName = node.name.value;
|
3646
|
+
const lowerTypeName = typeName.toLowerCase();
|
3647
|
+
for (const field of node.fields || []) {
|
3648
|
+
const fieldName = field.name.value;
|
3649
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
3650
|
+
context.report({
|
3651
|
+
data: {
|
3652
|
+
fieldName,
|
3653
|
+
typeName
|
3654
|
+
},
|
3655
|
+
messageId: NO_TYPENAME_PREFIX,
|
3656
|
+
node: field.name,
|
3657
|
+
suggest: [
|
3658
|
+
{
|
3659
|
+
desc: `Remove \`${fieldName.slice(0, typeName.length)}\` prefix`,
|
3660
|
+
fix: (fixer) => fixer.replaceText(
|
3661
|
+
field.name,
|
3662
|
+
fieldName.replace(new RegExp(`^${typeName}`, "i"), "")
|
3663
|
+
)
|
3664
|
+
}
|
3665
|
+
]
|
3666
|
+
});
|
3667
|
+
}
|
3049
3668
|
}
|
3050
3669
|
}
|
3051
3670
|
};
|
@@ -3061,7 +3680,8 @@ import {
|
|
3061
3680
|
visit as visit5
|
3062
3681
|
} from "graphql";
|
3063
3682
|
import lowerCase3 from "lodash.lowercase";
|
3064
|
-
var RULE_ID9 = "no-unreachable-types"
|
3683
|
+
var RULE_ID9 = "no-unreachable-types";
|
3684
|
+
var KINDS = [
|
3065
3685
|
Kind12.DIRECTIVE_DEFINITION,
|
3066
3686
|
Kind12.OBJECT_TYPE_DEFINITION,
|
3067
3687
|
Kind12.OBJECT_TYPE_EXTENSION,
|
@@ -3075,7 +3695,9 @@ var RULE_ID9 = "no-unreachable-types", KINDS = [
|
|
3075
3695
|
Kind12.UNION_TYPE_EXTENSION,
|
3076
3696
|
Kind12.ENUM_TYPE_DEFINITION,
|
3077
3697
|
Kind12.ENUM_TYPE_EXTENSION
|
3078
|
-
]
|
3698
|
+
];
|
3699
|
+
var reachableTypesCache = new ModuleCache();
|
3700
|
+
var RequestDirectiveLocations = /* @__PURE__ */ new Set([
|
3079
3701
|
DirectiveLocation.QUERY,
|
3080
3702
|
DirectiveLocation.MUTATION,
|
3081
3703
|
DirectiveLocation.SUBSCRIPTION,
|
@@ -3086,21 +3708,28 @@ var RULE_ID9 = "no-unreachable-types", KINDS = [
|
|
3086
3708
|
DirectiveLocation.VARIABLE_DEFINITION
|
3087
3709
|
]);
|
3088
3710
|
function getReachableTypes(schema16) {
|
3089
|
-
|
3090
|
-
if (cachedValue)
|
3711
|
+
const cachedValue = reachableTypesCache.get(schema16);
|
3712
|
+
if (cachedValue) {
|
3091
3713
|
return cachedValue;
|
3092
|
-
|
3093
|
-
|
3094
|
-
|
3714
|
+
}
|
3715
|
+
const reachableTypes = /* @__PURE__ */ new Set();
|
3716
|
+
const collect = (node) => {
|
3717
|
+
const typeName = getTypeName(node);
|
3718
|
+
if (reachableTypes.has(typeName)) {
|
3095
3719
|
return;
|
3720
|
+
}
|
3096
3721
|
reachableTypes.add(typeName);
|
3097
|
-
|
3722
|
+
const type = schema16.getType(typeName) || schema16.getDirective(typeName);
|
3098
3723
|
if (isInterfaceType(type)) {
|
3099
|
-
|
3100
|
-
for (
|
3724
|
+
const { objects, interfaces } = schema16.getImplementations(type);
|
3725
|
+
for (const { astNode } of [...objects, ...interfaces]) {
|
3101
3726
|
visit5(astNode, visitor);
|
3102
|
-
|
3103
|
-
|
3727
|
+
}
|
3728
|
+
} else if (type?.astNode) {
|
3729
|
+
visit5(type.astNode, visitor);
|
3730
|
+
}
|
3731
|
+
};
|
3732
|
+
const visitor = {
|
3104
3733
|
InterfaceTypeDefinition: collect,
|
3105
3734
|
ObjectTypeDefinition: collect,
|
3106
3735
|
InputValueDefinition: collect,
|
@@ -3109,21 +3738,27 @@ function getReachableTypes(schema16) {
|
|
3109
3738
|
Directive: collect,
|
3110
3739
|
NamedType: collect
|
3111
3740
|
};
|
3112
|
-
for (
|
3741
|
+
for (const type of [
|
3113
3742
|
schema16,
|
3114
3743
|
// visiting SchemaDefinition node
|
3115
3744
|
schema16.getQueryType(),
|
3116
3745
|
schema16.getMutationType(),
|
3117
3746
|
schema16.getSubscriptionType()
|
3118
|
-
])
|
3119
|
-
|
3120
|
-
|
3747
|
+
]) {
|
3748
|
+
if (type?.astNode) {
|
3749
|
+
visit5(type.astNode, visitor);
|
3750
|
+
}
|
3751
|
+
}
|
3752
|
+
for (const node of schema16.getDirectives()) {
|
3121
3753
|
if (node.locations.some((location) => RequestDirectiveLocations.has(location))) {
|
3122
3754
|
reachableTypes.add(node.name);
|
3123
|
-
for (
|
3755
|
+
for (const arg of node.args) {
|
3124
3756
|
reachableTypes.add(getNamedType(arg.type).name);
|
3757
|
+
}
|
3125
3758
|
}
|
3126
|
-
|
3759
|
+
}
|
3760
|
+
reachableTypesCache.set(schema16, reachableTypes);
|
3761
|
+
return reachableTypes;
|
3127
3762
|
}
|
3128
3763
|
var rule15 = {
|
3129
3764
|
meta: {
|
@@ -3134,7 +3769,7 @@ var rule15 = {
|
|
3134
3769
|
description: "Requires all types to be reachable at some level by root level fields.",
|
3135
3770
|
category: "Schema",
|
3136
3771
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID9}`,
|
3137
|
-
requiresSchema:
|
3772
|
+
requiresSchema: true,
|
3138
3773
|
examples: [
|
3139
3774
|
{
|
3140
3775
|
title: "Incorrect",
|
@@ -3169,19 +3804,20 @@ var rule15 = {
|
|
3169
3804
|
)
|
3170
3805
|
}
|
3171
3806
|
],
|
3172
|
-
recommended:
|
3807
|
+
recommended: true
|
3173
3808
|
},
|
3174
3809
|
type: "suggestion",
|
3175
3810
|
schema: [],
|
3176
|
-
hasSuggestions:
|
3811
|
+
hasSuggestions: true
|
3177
3812
|
},
|
3178
3813
|
create(context) {
|
3179
|
-
|
3814
|
+
const schema16 = requireGraphQLSchema(RULE_ID9, context);
|
3815
|
+
const reachableTypes = getReachableTypes(schema16);
|
3180
3816
|
return {
|
3181
3817
|
[`:matches(${KINDS}) > .name`](node) {
|
3182
|
-
|
3818
|
+
const typeName = node.value;
|
3183
3819
|
if (!reachableTypes.has(typeName)) {
|
3184
|
-
|
3820
|
+
const type = lowerCase3(node.parent.kind.replace(/(Extension|Definition)$/, ""));
|
3185
3821
|
context.report({
|
3186
3822
|
node,
|
3187
3823
|
messageId: RULE_ID9,
|
@@ -3204,7 +3840,8 @@ var rule15 = {
|
|
3204
3840
|
|
3205
3841
|
// src/rules/no-unused-fields/index.ts
|
3206
3842
|
import { TypeInfo as TypeInfo2, visit as visit6, visitWithTypeInfo as visitWithTypeInfo2 } from "graphql";
|
3207
|
-
var RULE_ID10 = "no-unused-fields"
|
3843
|
+
var RULE_ID10 = "no-unused-fields";
|
3844
|
+
var RELAY_SCHEMA = (
|
3208
3845
|
/* GraphQL */
|
3209
3846
|
`
|
3210
3847
|
# Root Query Type
|
@@ -3245,7 +3882,8 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3245
3882
|
endCursor: String
|
3246
3883
|
}
|
3247
3884
|
`
|
3248
|
-
)
|
3885
|
+
);
|
3886
|
+
var RELAY_QUERY = (
|
3249
3887
|
/* GraphQL */
|
3250
3888
|
`
|
3251
3889
|
query {
|
@@ -3263,20 +3901,22 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3263
3901
|
}
|
3264
3902
|
}
|
3265
3903
|
`
|
3266
|
-
)
|
3904
|
+
);
|
3905
|
+
var RELAY_DEFAULT_IGNORED_FIELD_SELECTORS = [
|
3267
3906
|
"[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]",
|
3268
3907
|
"[parent.name.value=/Edge$/][name.value=cursor]",
|
3269
3908
|
"[parent.name.value=/Connection$/][name.value=pageInfo]"
|
3270
|
-
]
|
3909
|
+
];
|
3910
|
+
var schema8 = {
|
3271
3911
|
type: "array",
|
3272
3912
|
maxItems: 1,
|
3273
3913
|
items: {
|
3274
3914
|
type: "object",
|
3275
|
-
additionalProperties:
|
3915
|
+
additionalProperties: false,
|
3276
3916
|
properties: {
|
3277
3917
|
ignoredFieldSelectors: {
|
3278
3918
|
type: "array",
|
3279
|
-
uniqueItems:
|
3919
|
+
uniqueItems: true,
|
3280
3920
|
minItems: 1,
|
3281
3921
|
description: [
|
3282
3922
|
"Fields that will be ignored and are allowed to be unused.",
|
@@ -3286,8 +3926,7 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3286
3926
|
JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
|
3287
3927
|
"```",
|
3288
3928
|
eslintSelectorsTip
|
3289
|
-
].join(
|
3290
|
-
`),
|
3929
|
+
].join("\n"),
|
3291
3930
|
items: {
|
3292
3931
|
type: "string",
|
3293
3932
|
pattern: "^\\[(.+)]$"
|
@@ -3295,22 +3934,33 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3295
3934
|
}
|
3296
3935
|
}
|
3297
3936
|
}
|
3298
|
-
}
|
3937
|
+
};
|
3938
|
+
var usedFieldsCache = new ModuleCache();
|
3299
3939
|
function getUsedFields(schema16, operations) {
|
3300
|
-
|
3301
|
-
if (cachedValue)
|
3940
|
+
const cachedValue = usedFieldsCache.get(schema16);
|
3941
|
+
if (cachedValue) {
|
3302
3942
|
return cachedValue;
|
3303
|
-
|
3943
|
+
}
|
3944
|
+
const usedFields = /* @__PURE__ */ Object.create(null);
|
3945
|
+
const typeInfo = new TypeInfo2(schema16);
|
3946
|
+
const visitor = visitWithTypeInfo2(typeInfo, {
|
3304
3947
|
Field(node) {
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3948
|
+
const fieldDef = typeInfo.getFieldDef();
|
3949
|
+
if (!fieldDef) {
|
3950
|
+
return false;
|
3951
|
+
}
|
3952
|
+
const parentTypeName = typeInfo.getParentType().name;
|
3953
|
+
const fieldName = node.name.value;
|
3954
|
+
usedFields[parentTypeName] ??= /* @__PURE__ */ new Set();
|
3955
|
+
usedFields[parentTypeName].add(fieldName);
|
3309
3956
|
}
|
3310
|
-
})
|
3311
|
-
|
3957
|
+
});
|
3958
|
+
const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
|
3959
|
+
for (const { document } of allDocuments) {
|
3312
3960
|
visit6(document, visitor);
|
3313
|
-
|
3961
|
+
}
|
3962
|
+
usedFieldsCache.set(schema16, usedFields);
|
3963
|
+
return usedFields;
|
3314
3964
|
}
|
3315
3965
|
var rule16 = {
|
3316
3966
|
meta: {
|
@@ -3321,10 +3971,10 @@ var rule16 = {
|
|
3321
3971
|
description: "Requires all fields to be used at some level by siblings operations.",
|
3322
3972
|
category: "Schema",
|
3323
3973
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID10}`,
|
3324
|
-
requiresSiblings:
|
3325
|
-
requiresSchema:
|
3974
|
+
requiresSiblings: true,
|
3975
|
+
requiresSchema: true,
|
3326
3976
|
// Requires documents to be set
|
3327
|
-
isDisabledForAllConfig:
|
3977
|
+
isDisabledForAllConfig: true,
|
3328
3978
|
examples: [
|
3329
3979
|
{
|
3330
3980
|
title: "Incorrect",
|
@@ -3391,17 +4041,26 @@ var rule16 = {
|
|
3391
4041
|
},
|
3392
4042
|
type: "suggestion",
|
3393
4043
|
schema: schema8,
|
3394
|
-
hasSuggestions:
|
4044
|
+
hasSuggestions: true
|
3395
4045
|
},
|
3396
4046
|
create(context) {
|
3397
|
-
|
4047
|
+
const schema16 = requireGraphQLSchema(RULE_ID10, context);
|
4048
|
+
const siblingsOperations = requireGraphQLOperations(RULE_ID10, context);
|
4049
|
+
const usedFields = getUsedFields(schema16, siblingsOperations);
|
4050
|
+
const { ignoredFieldSelectors } = context.options[0] || {};
|
4051
|
+
const selector = (ignoredFieldSelectors || []).reduce(
|
4052
|
+
(acc, selector2) => `${acc}:not(${selector2})`,
|
4053
|
+
"FieldDefinition"
|
4054
|
+
);
|
3398
4055
|
return {
|
3399
|
-
[(
|
3400
|
-
|
3401
|
-
|
3402
|
-
|
3403
|
-
|
3404
|
-
|
4056
|
+
[selector](node) {
|
4057
|
+
const fieldName = node.name.value;
|
4058
|
+
const parentTypeName = node.parent.name.value;
|
4059
|
+
const isUsed = usedFields[parentTypeName]?.has(fieldName);
|
4060
|
+
if (isUsed) {
|
4061
|
+
return;
|
4062
|
+
}
|
4063
|
+
context.report({
|
3405
4064
|
node: node.name,
|
3406
4065
|
messageId: RULE_ID10,
|
3407
4066
|
data: { fieldName },
|
@@ -3409,7 +4068,10 @@ var rule16 = {
|
|
3409
4068
|
{
|
3410
4069
|
desc: `Remove \`${fieldName}\` field`,
|
3411
4070
|
fix(fixer) {
|
3412
|
-
|
4071
|
+
const sourceCode = context.getSourceCode();
|
4072
|
+
const tokenBefore = sourceCode.getTokenBefore(node);
|
4073
|
+
const tokenAfter = sourceCode.getTokenAfter(node);
|
4074
|
+
const isEmptyType = tokenBefore.type === "{" && tokenAfter.type === "}";
|
3413
4075
|
return fixer.remove(isEmptyType ? node.parent : node);
|
3414
4076
|
}
|
3415
4077
|
}
|
@@ -3422,22 +4084,25 @@ var rule16 = {
|
|
3422
4084
|
|
3423
4085
|
// src/rules/relay-arguments/index.ts
|
3424
4086
|
import { isScalarType as isScalarType2, Kind as Kind13 } from "graphql";
|
3425
|
-
var RULE_ID11 = "relay-arguments"
|
4087
|
+
var RULE_ID11 = "relay-arguments";
|
4088
|
+
var MISSING_ARGUMENTS = "MISSING_ARGUMENTS";
|
4089
|
+
var schema9 = {
|
3426
4090
|
type: "array",
|
3427
4091
|
maxItems: 1,
|
3428
4092
|
items: {
|
3429
4093
|
type: "object",
|
3430
|
-
additionalProperties:
|
4094
|
+
additionalProperties: false,
|
3431
4095
|
minProperties: 1,
|
3432
4096
|
properties: {
|
3433
4097
|
includeBoth: {
|
3434
4098
|
type: "boolean",
|
3435
|
-
default:
|
4099
|
+
default: true,
|
3436
4100
|
description: "Enforce including both forward and backward pagination arguments"
|
3437
4101
|
}
|
3438
4102
|
}
|
3439
4103
|
}
|
3440
|
-
}
|
4104
|
+
};
|
4105
|
+
var rule17 = {
|
3441
4106
|
meta: {
|
3442
4107
|
type: "problem",
|
3443
4108
|
docs: {
|
@@ -3456,8 +4121,7 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3456
4121
|
"",
|
3457
4122
|
"- `last` takes a non-negative integer",
|
3458
4123
|
"- `before` takes the Cursor type"
|
3459
|
-
].join(
|
3460
|
-
`),
|
4124
|
+
].join("\n"),
|
3461
4125
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID11}`,
|
3462
4126
|
examples: [
|
3463
4127
|
{
|
@@ -3483,7 +4147,7 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3483
4147
|
)
|
3484
4148
|
}
|
3485
4149
|
],
|
3486
|
-
isDisabledForAllConfig:
|
4150
|
+
isDisabledForAllConfig: true
|
3487
4151
|
},
|
3488
4152
|
messages: {
|
3489
4153
|
[MISSING_ARGUMENTS]: "A field that returns a Connection type must include forward pagination arguments (`first` and `after`), backward pagination arguments (`last` and `before`), or both."
|
@@ -3491,15 +4155,19 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3491
4155
|
schema: schema9
|
3492
4156
|
},
|
3493
4157
|
create(context) {
|
3494
|
-
|
4158
|
+
const schema16 = requireGraphQLSchema(RULE_ID11, context);
|
4159
|
+
const { includeBoth = true } = context.options[0] || {};
|
3495
4160
|
return {
|
3496
4161
|
"FieldDefinition > .gqlType Name[value=/Connection$/]"(node) {
|
3497
4162
|
let fieldNode = node.parent;
|
3498
|
-
|
4163
|
+
while (fieldNode.kind !== Kind13.FIELD_DEFINITION) {
|
3499
4164
|
fieldNode = fieldNode.parent;
|
3500
|
-
|
4165
|
+
}
|
4166
|
+
const args = Object.fromEntries(
|
3501
4167
|
fieldNode.arguments?.map((argument) => [argument.name.value, argument]) || []
|
3502
|
-
)
|
4168
|
+
);
|
4169
|
+
const hasForwardPagination = !!(args.first && args.after);
|
4170
|
+
const hasBackwardPagination = !!(args.last && args.before);
|
3503
4171
|
if (!hasForwardPagination && !hasBackwardPagination) {
|
3504
4172
|
context.report({
|
3505
4173
|
node: fieldNode.name,
|
@@ -3508,16 +4176,29 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3508
4176
|
return;
|
3509
4177
|
}
|
3510
4178
|
function checkField(typeName, argumentName) {
|
3511
|
-
|
3512
|
-
|
3513
|
-
|
4179
|
+
const argument = args[argumentName];
|
4180
|
+
const hasArgument = !!argument;
|
4181
|
+
let type = argument;
|
4182
|
+
if (hasArgument && type.gqlType.kind === Kind13.NON_NULL_TYPE) {
|
4183
|
+
type = type.gqlType;
|
4184
|
+
}
|
4185
|
+
const isAllowedNonNullType = hasArgument && type.gqlType.kind === Kind13.NAMED_TYPE && (type.gqlType.name.value === typeName || typeName === "String" && isScalarType2(schema16.getType(type.gqlType.name.value)));
|
4186
|
+
if (!isAllowedNonNullType) {
|
4187
|
+
const returnType = typeName === "String" ? "String or Scalar" : typeName;
|
3514
4188
|
context.report({
|
3515
4189
|
node: (argument || fieldNode).name,
|
3516
4190
|
message: hasArgument ? `Argument \`${argumentName}\` must return ${returnType}.` : `Field \`${fieldNode.name.value}\` must contain an argument \`${argumentName}\`, that return ${returnType}.`
|
3517
4191
|
});
|
3518
4192
|
}
|
3519
4193
|
}
|
3520
|
-
(includeBoth || args.first || args.after)
|
4194
|
+
if (includeBoth || args.first || args.after) {
|
4195
|
+
checkField("Int", "first");
|
4196
|
+
checkField("String", "after");
|
4197
|
+
}
|
4198
|
+
if (includeBoth || args.last || args.before) {
|
4199
|
+
checkField("Int", "last");
|
4200
|
+
checkField("String", "before");
|
4201
|
+
}
|
3521
4202
|
}
|
3522
4203
|
};
|
3523
4204
|
}
|
@@ -3525,7 +4206,13 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3525
4206
|
|
3526
4207
|
// src/rules/relay-connection-types/index.ts
|
3527
4208
|
import { Kind as Kind14 } from "graphql";
|
3528
|
-
var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE"
|
4209
|
+
var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE";
|
4210
|
+
var MUST_CONTAIN_FIELD_EDGES = "MUST_CONTAIN_FIELD_EDGES";
|
4211
|
+
var MUST_CONTAIN_FIELD_PAGE_INFO = "MUST_CONTAIN_FIELD_PAGE_INFO";
|
4212
|
+
var MUST_HAVE_CONNECTION_SUFFIX = "MUST_HAVE_CONNECTION_SUFFIX";
|
4213
|
+
var EDGES_FIELD_MUST_RETURN_LIST_TYPE = "EDGES_FIELD_MUST_RETURN_LIST_TYPE";
|
4214
|
+
var PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE = "PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE";
|
4215
|
+
var NON_OBJECT_TYPES = [
|
3529
4216
|
Kind14.SCALAR_TYPE_DEFINITION,
|
3530
4217
|
Kind14.UNION_TYPE_DEFINITION,
|
3531
4218
|
Kind14.UNION_TYPE_EXTENSION,
|
@@ -3535,7 +4222,11 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3535
4222
|
Kind14.ENUM_TYPE_EXTENSION,
|
3536
4223
|
Kind14.INTERFACE_TYPE_DEFINITION,
|
3537
4224
|
Kind14.INTERFACE_TYPE_EXTENSION
|
3538
|
-
]
|
4225
|
+
];
|
4226
|
+
var notConnectionTypesSelector = `:matches(${NON_OBJECT_TYPES})[name.value=/Connection$/] > .name`;
|
4227
|
+
var hasEdgesField = (node) => node.fields?.some((field) => field.name.value === "edges");
|
4228
|
+
var hasPageInfoField = (node) => node.fields?.some((field) => field.name.value === "pageInfo");
|
4229
|
+
var rule18 = {
|
3539
4230
|
meta: {
|
3540
4231
|
type: "problem",
|
3541
4232
|
docs: {
|
@@ -3547,10 +4238,9 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3547
4238
|
"- Connection type must be an Object type",
|
3548
4239
|
"- Connection type must contain a field `edges` that return a list type that wraps an edge type",
|
3549
4240
|
"- Connection type must contain a field `pageInfo` that return a non-null `PageInfo` Object type"
|
3550
|
-
].join(
|
3551
|
-
`),
|
4241
|
+
].join("\n"),
|
3552
4242
|
url: "https://the-guild.dev/graphql/eslint/rules/relay-connection-types",
|
3553
|
-
isDisabledForAllConfig:
|
4243
|
+
isDisabledForAllConfig: true,
|
3554
4244
|
examples: [
|
3555
4245
|
{
|
3556
4246
|
title: "Incorrect",
|
@@ -3595,16 +4285,29 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3595
4285
|
context.report({ node, messageId: MUST_BE_OBJECT_TYPE });
|
3596
4286
|
},
|
3597
4287
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value!=/Connection$/]"(node) {
|
3598
|
-
hasEdgesField(node) && hasPageInfoField(node)
|
4288
|
+
if (hasEdgesField(node) && hasPageInfoField(node)) {
|
4289
|
+
context.report({ node: node.name, messageId: MUST_HAVE_CONNECTION_SUFFIX });
|
4290
|
+
}
|
3599
4291
|
},
|
3600
4292
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/]"(node) {
|
3601
|
-
hasEdgesField(node)
|
4293
|
+
if (!hasEdgesField(node)) {
|
4294
|
+
context.report({ node: node.name, messageId: MUST_CONTAIN_FIELD_EDGES });
|
4295
|
+
}
|
4296
|
+
if (!hasPageInfoField(node)) {
|
4297
|
+
context.report({ node: node.name, messageId: MUST_CONTAIN_FIELD_PAGE_INFO });
|
4298
|
+
}
|
3602
4299
|
},
|
3603
4300
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=edges] > .gqlType"(node) {
|
3604
|
-
node.kind === Kind14.LIST_TYPE || node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.LIST_TYPE
|
4301
|
+
const isListType2 = node.kind === Kind14.LIST_TYPE || node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.LIST_TYPE;
|
4302
|
+
if (!isListType2) {
|
4303
|
+
context.report({ node, messageId: EDGES_FIELD_MUST_RETURN_LIST_TYPE });
|
4304
|
+
}
|
3605
4305
|
},
|
3606
4306
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=pageInfo] > .gqlType"(node) {
|
3607
|
-
node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.NAMED_TYPE && node.gqlType.name.value === "PageInfo"
|
4307
|
+
const isNonNullPageInfoType = node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.NAMED_TYPE && node.gqlType.name.value === "PageInfo";
|
4308
|
+
if (!isNonNullPageInfoType) {
|
4309
|
+
context.report({ node, messageId: PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE });
|
4310
|
+
}
|
3608
4311
|
}
|
3609
4312
|
};
|
3610
4313
|
}
|
@@ -3618,49 +4321,66 @@ import {
|
|
3618
4321
|
visit as visit7
|
3619
4322
|
} from "graphql";
|
3620
4323
|
import { getDocumentNodeFromSchema } from "@graphql-tools/utils";
|
3621
|
-
var RULE_ID12 = "relay-edge-types"
|
4324
|
+
var RULE_ID12 = "relay-edge-types";
|
4325
|
+
var MESSAGE_MUST_BE_OBJECT_TYPE = "MESSAGE_MUST_BE_OBJECT_TYPE";
|
4326
|
+
var MESSAGE_MISSING_EDGE_SUFFIX = "MESSAGE_MISSING_EDGE_SUFFIX";
|
4327
|
+
var MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE = "MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE";
|
4328
|
+
var MESSAGE_SHOULD_IMPLEMENTS_NODE = "MESSAGE_SHOULD_IMPLEMENTS_NODE";
|
4329
|
+
var edgeTypesCache;
|
3622
4330
|
function getEdgeTypes(schema16) {
|
3623
|
-
if (edgeTypesCache)
|
4331
|
+
if (edgeTypesCache) {
|
3624
4332
|
return edgeTypesCache;
|
3625
|
-
|
4333
|
+
}
|
4334
|
+
const edgeTypes = /* @__PURE__ */ new Set();
|
4335
|
+
const visitor = {
|
3626
4336
|
ObjectTypeDefinition(node) {
|
3627
|
-
|
4337
|
+
const typeName = node.name.value;
|
4338
|
+
const hasConnectionSuffix = typeName.endsWith("Connection");
|
4339
|
+
if (!hasConnectionSuffix) {
|
3628
4340
|
return;
|
3629
|
-
|
4341
|
+
}
|
4342
|
+
const edges = node.fields?.find((field) => field.name.value === "edges");
|
3630
4343
|
if (edges) {
|
3631
|
-
|
3632
|
-
|
4344
|
+
const edgesTypeName = getTypeName(edges);
|
4345
|
+
const edgesType = schema16.getType(edgesTypeName);
|
4346
|
+
if (isObjectType2(edgesType)) {
|
4347
|
+
edgeTypes.add(edgesTypeName);
|
4348
|
+
}
|
3633
4349
|
}
|
3634
4350
|
}
|
3635
|
-
}
|
3636
|
-
|
4351
|
+
};
|
4352
|
+
const astNode = getDocumentNodeFromSchema(schema16);
|
4353
|
+
visit7(astNode, visitor);
|
4354
|
+
edgeTypesCache = edgeTypes;
|
4355
|
+
return edgeTypesCache;
|
3637
4356
|
}
|
3638
4357
|
var schema10 = {
|
3639
4358
|
type: "array",
|
3640
4359
|
maxItems: 1,
|
3641
4360
|
items: {
|
3642
4361
|
type: "object",
|
3643
|
-
additionalProperties:
|
4362
|
+
additionalProperties: false,
|
3644
4363
|
minProperties: 1,
|
3645
4364
|
properties: {
|
3646
4365
|
withEdgeSuffix: {
|
3647
4366
|
type: "boolean",
|
3648
|
-
default:
|
4367
|
+
default: true,
|
3649
4368
|
description: 'Edge type name must end in "Edge".'
|
3650
4369
|
},
|
3651
4370
|
shouldImplementNode: {
|
3652
4371
|
type: "boolean",
|
3653
|
-
default:
|
4372
|
+
default: true,
|
3654
4373
|
description: "Edge type's field `node` must implement `Node` interface."
|
3655
4374
|
},
|
3656
4375
|
listTypeCanWrapOnlyEdgeType: {
|
3657
4376
|
type: "boolean",
|
3658
|
-
default:
|
4377
|
+
default: true,
|
3659
4378
|
description: "A list type should only wrap an edge type."
|
3660
4379
|
}
|
3661
4380
|
}
|
3662
4381
|
}
|
3663
|
-
}
|
4382
|
+
};
|
4383
|
+
var rule19 = {
|
3664
4384
|
meta: {
|
3665
4385
|
type: "problem",
|
3666
4386
|
docs: {
|
@@ -3675,11 +4395,10 @@ var schema10 = {
|
|
3675
4395
|
'- Edge type name must end in "Edge" _(optional)_',
|
3676
4396
|
"- Edge type's field `node` must implement `Node` interface _(optional)_",
|
3677
4397
|
"- A list type should only wrap an edge type _(optional)_"
|
3678
|
-
].join(
|
3679
|
-
`),
|
4398
|
+
].join("\n"),
|
3680
4399
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID12}`,
|
3681
|
-
isDisabledForAllConfig:
|
3682
|
-
requiresSchema:
|
4400
|
+
isDisabledForAllConfig: true,
|
4401
|
+
requiresSchema: true,
|
3683
4402
|
examples: [
|
3684
4403
|
{
|
3685
4404
|
title: "Correct",
|
@@ -3704,28 +4423,40 @@ var schema10 = {
|
|
3704
4423
|
schema: schema10
|
3705
4424
|
},
|
3706
4425
|
create(context) {
|
3707
|
-
|
3708
|
-
|
3709
|
-
|
3710
|
-
|
4426
|
+
const schema16 = requireGraphQLSchema(RULE_ID12, context);
|
4427
|
+
const edgeTypes = getEdgeTypes(schema16);
|
4428
|
+
const options = {
|
4429
|
+
withEdgeSuffix: true,
|
4430
|
+
shouldImplementNode: true,
|
4431
|
+
listTypeCanWrapOnlyEdgeType: true,
|
3711
4432
|
...context.options[0]
|
3712
|
-
}
|
3713
|
-
|
3714
|
-
|
4433
|
+
};
|
4434
|
+
const isNamedOrNonNullNamed = (node) => node.kind === Kind15.NAMED_TYPE || node.kind === Kind15.NON_NULL_TYPE && node.gqlType.kind === Kind15.NAMED_TYPE;
|
4435
|
+
const checkNodeField = (node) => {
|
4436
|
+
const nodeField = node.fields?.find((field) => field.name.value === "node");
|
4437
|
+
const message = "return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types.";
|
4438
|
+
if (!nodeField) {
|
3715
4439
|
context.report({
|
3716
4440
|
node: node.name,
|
3717
4441
|
message: `Edge type must contain a field \`node\` that ${message}`
|
3718
4442
|
});
|
3719
|
-
else if (!isNamedOrNonNullNamed(nodeField.gqlType))
|
4443
|
+
} else if (!isNamedOrNonNullNamed(nodeField.gqlType)) {
|
3720
4444
|
context.report({ node: nodeField.name, message: `Field \`node\` must ${message}` });
|
3721
|
-
else if (options.shouldImplementNode) {
|
3722
|
-
|
3723
|
-
|
4445
|
+
} else if (options.shouldImplementNode) {
|
4446
|
+
const nodeReturnTypeName = getTypeName(nodeField.gqlType.rawNode());
|
4447
|
+
const type = schema16.getType(nodeReturnTypeName);
|
4448
|
+
if (!isObjectType2(type)) {
|
3724
4449
|
return;
|
3725
|
-
|
4450
|
+
}
|
4451
|
+
const implementsNode = type.astNode.interfaces?.some((n) => n.name.value === "Node");
|
4452
|
+
if (!implementsNode) {
|
4453
|
+
context.report({ node: node.name, messageId: MESSAGE_SHOULD_IMPLEMENTS_NODE });
|
4454
|
+
}
|
3726
4455
|
}
|
3727
|
-
}
|
3728
|
-
|
4456
|
+
};
|
4457
|
+
const checkCursorField = (node) => {
|
4458
|
+
const cursorField = node.fields?.find((field) => field.name.value === "cursor");
|
4459
|
+
const message = "return either a String, Scalar, or a non-null wrapper wrapper around one of those types.";
|
3729
4460
|
if (!cursorField) {
|
3730
4461
|
context.report({
|
3731
4462
|
node: node.name,
|
@@ -3733,30 +4464,51 @@ var schema10 = {
|
|
3733
4464
|
});
|
3734
4465
|
return;
|
3735
4466
|
}
|
3736
|
-
|
3737
|
-
(!isNamedOrNonNullNamed(cursorField.gqlType) || typeName !== "String" && !isScalarType3(schema16.getType(typeName)))
|
3738
|
-
|
4467
|
+
const typeName = getTypeName(cursorField.rawNode());
|
4468
|
+
if (!isNamedOrNonNullNamed(cursorField.gqlType) || typeName !== "String" && !isScalarType3(schema16.getType(typeName))) {
|
4469
|
+
context.report({ node: cursorField.name, message: `Field \`cursor\` must ${message}` });
|
4470
|
+
}
|
4471
|
+
};
|
4472
|
+
const listeners = {
|
3739
4473
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=edges] > .gqlType Name"(node) {
|
3740
|
-
|
3741
|
-
isObjectType2(type)
|
4474
|
+
const type = schema16.getType(node.value);
|
4475
|
+
if (!isObjectType2(type)) {
|
4476
|
+
context.report({ node, messageId: MESSAGE_MUST_BE_OBJECT_TYPE });
|
4477
|
+
}
|
3742
4478
|
},
|
3743
4479
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)"(node) {
|
3744
|
-
|
3745
|
-
edgeTypes.has(typeName)
|
4480
|
+
const typeName = node.name.value;
|
4481
|
+
if (edgeTypes.has(typeName)) {
|
4482
|
+
checkNodeField(node);
|
4483
|
+
checkCursorField(node);
|
4484
|
+
if (options.withEdgeSuffix && !typeName.endsWith("Edge")) {
|
4485
|
+
context.report({ node: node.name, messageId: MESSAGE_MISSING_EDGE_SUFFIX });
|
4486
|
+
}
|
4487
|
+
}
|
3746
4488
|
}
|
3747
4489
|
};
|
3748
|
-
|
3749
|
-
|
3750
|
-
|
3751
|
-
|
3752
|
-
|
3753
|
-
|
4490
|
+
if (options.listTypeCanWrapOnlyEdgeType) {
|
4491
|
+
listeners["FieldDefinition > .gqlType"] = (node) => {
|
4492
|
+
if (node.kind === Kind15.LIST_TYPE || node.kind === Kind15.NON_NULL_TYPE && node.gqlType.kind === Kind15.LIST_TYPE) {
|
4493
|
+
const typeName = getTypeName(node.rawNode());
|
4494
|
+
if (!edgeTypes.has(typeName)) {
|
4495
|
+
context.report({ node, messageId: MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE });
|
4496
|
+
}
|
4497
|
+
}
|
4498
|
+
};
|
4499
|
+
}
|
4500
|
+
return listeners;
|
3754
4501
|
}
|
3755
4502
|
};
|
3756
4503
|
|
3757
4504
|
// src/rules/relay-page-info/index.ts
|
3758
4505
|
import { isScalarType as isScalarType4, Kind as Kind16 } from "graphql";
|
3759
|
-
var RULE_ID13 = "relay-page-info"
|
4506
|
+
var RULE_ID13 = "relay-page-info";
|
4507
|
+
var MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST";
|
4508
|
+
var MESSAGE_MUST_BE_OBJECT_TYPE2 = "MESSAGE_MUST_BE_OBJECT_TYPE";
|
4509
|
+
var notPageInfoTypesSelector = `:matches(${NON_OBJECT_TYPES})[name.value=PageInfo] > .name`;
|
4510
|
+
var hasPageInfoChecked = false;
|
4511
|
+
var rule20 = {
|
3760
4512
|
meta: {
|
3761
4513
|
type: "problem",
|
3762
4514
|
docs: {
|
@@ -3767,8 +4519,7 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3767
4519
|
"- `PageInfo` must be an Object type",
|
3768
4520
|
"- `PageInfo` must contain fields `hasPreviousPage` and `hasNextPage`, that return non-null Boolean",
|
3769
4521
|
"- `PageInfo` must contain fields `startCursor` and `endCursor`, that return either String or Scalar, which can be null if there are no results"
|
3770
|
-
].join(
|
3771
|
-
`),
|
4522
|
+
].join("\n"),
|
3772
4523
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID13}`,
|
3773
4524
|
examples: [
|
3774
4525
|
{
|
@@ -3786,8 +4537,8 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3786
4537
|
)
|
3787
4538
|
}
|
3788
4539
|
],
|
3789
|
-
isDisabledForAllConfig:
|
3790
|
-
requiresSchema:
|
4540
|
+
isDisabledForAllConfig: true,
|
4541
|
+
requiresSchema: true
|
3791
4542
|
},
|
3792
4543
|
messages: {
|
3793
4544
|
[MESSAGE_MUST_EXIST]: "The server must provide a `PageInfo` object.",
|
@@ -3796,54 +4547,76 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3796
4547
|
schema: []
|
3797
4548
|
},
|
3798
4549
|
create(context) {
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
4550
|
+
const schema16 = requireGraphQLSchema(RULE_ID13, context);
|
4551
|
+
if (!hasPageInfoChecked) {
|
4552
|
+
const pageInfoType = schema16.getType("PageInfo");
|
4553
|
+
if (!pageInfoType) {
|
4554
|
+
context.report({
|
4555
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
4556
|
+
messageId: MESSAGE_MUST_EXIST
|
4557
|
+
});
|
4558
|
+
}
|
4559
|
+
hasPageInfoChecked = true;
|
4560
|
+
}
|
4561
|
+
return {
|
3804
4562
|
[notPageInfoTypesSelector](node) {
|
3805
4563
|
context.report({ node, messageId: MESSAGE_MUST_BE_OBJECT_TYPE2 });
|
3806
4564
|
},
|
3807
4565
|
"ObjectTypeDefinition[name.value=PageInfo]"(node) {
|
3808
|
-
|
4566
|
+
const fieldMap = Object.fromEntries(
|
3809
4567
|
node.fields?.map((field) => [field.name.value, field]) || []
|
3810
|
-
)
|
3811
|
-
|
4568
|
+
);
|
4569
|
+
const checkField = (fieldName, typeName) => {
|
4570
|
+
const field = fieldMap[fieldName];
|
4571
|
+
let isAllowedType = false;
|
3812
4572
|
if (field) {
|
3813
|
-
|
3814
|
-
typeName === "Boolean"
|
4573
|
+
const type = field.gqlType;
|
4574
|
+
if (typeName === "Boolean") {
|
4575
|
+
isAllowedType = type.kind === Kind16.NON_NULL_TYPE && type.gqlType.kind === Kind16.NAMED_TYPE && type.gqlType.name.value === "Boolean";
|
4576
|
+
} else if (type.kind === Kind16.NAMED_TYPE) {
|
4577
|
+
isAllowedType = type.name.value === "String" || isScalarType4(schema16.getType(type.name.value));
|
4578
|
+
}
|
3815
4579
|
}
|
3816
4580
|
if (!isAllowedType) {
|
3817
|
-
|
4581
|
+
const returnType = typeName === "Boolean" ? "non-null Boolean" : "either String or Scalar, which can be null if there are no results";
|
3818
4582
|
context.report({
|
3819
4583
|
node: field ? field.name : node.name,
|
3820
4584
|
message: field ? `Field \`${fieldName}\` must return ${returnType}.` : `\`PageInfo\` must contain a field \`${fieldName}\`, that return ${returnType}.`
|
3821
4585
|
});
|
3822
4586
|
}
|
3823
4587
|
};
|
3824
|
-
checkField("hasPreviousPage", "Boolean")
|
4588
|
+
checkField("hasPreviousPage", "Boolean");
|
4589
|
+
checkField("hasNextPage", "Boolean");
|
4590
|
+
checkField("startCursor", "String");
|
4591
|
+
checkField("endCursor", "String");
|
3825
4592
|
}
|
3826
4593
|
};
|
3827
4594
|
}
|
3828
4595
|
};
|
3829
4596
|
|
3830
4597
|
// src/rules/require-deprecation-date/index.ts
|
3831
|
-
var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}
|
4598
|
+
var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
|
4599
|
+
var MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIRE_DATE";
|
4600
|
+
var MESSAGE_INVALID_FORMAT = "MESSAGE_INVALID_FORMAT";
|
4601
|
+
var MESSAGE_INVALID_DATE = "MESSAGE_INVALID_DATE";
|
4602
|
+
var MESSAGE_CAN_BE_REMOVED = "MESSAGE_CAN_BE_REMOVED";
|
4603
|
+
var schema11 = {
|
3832
4604
|
type: "array",
|
3833
4605
|
maxItems: 1,
|
3834
4606
|
items: {
|
3835
4607
|
type: "object",
|
3836
|
-
additionalProperties:
|
4608
|
+
additionalProperties: false,
|
3837
4609
|
properties: {
|
3838
4610
|
argumentName: {
|
3839
4611
|
type: "string"
|
3840
4612
|
}
|
3841
4613
|
}
|
3842
4614
|
}
|
3843
|
-
}
|
4615
|
+
};
|
4616
|
+
var rule21 = {
|
3844
4617
|
meta: {
|
3845
4618
|
type: "suggestion",
|
3846
|
-
hasSuggestions:
|
4619
|
+
hasSuggestions: true,
|
3847
4620
|
docs: {
|
3848
4621
|
category: "Schema",
|
3849
4622
|
description: "Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.",
|
@@ -3899,7 +4672,8 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3899
4672
|
create(context) {
|
3900
4673
|
return {
|
3901
4674
|
"Directive[name.value=deprecated]"(node) {
|
3902
|
-
|
4675
|
+
const argName = context.options[0]?.argumentName || "deletionDate";
|
4676
|
+
const deletionDateNode = node.arguments?.find((arg) => arg.name.value === argName);
|
3903
4677
|
if (!deletionDateNode) {
|
3904
4678
|
context.report({
|
3905
4679
|
node: node.name,
|
@@ -3910,8 +4684,9 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3910
4684
|
});
|
3911
4685
|
return;
|
3912
4686
|
}
|
3913
|
-
|
3914
|
-
|
4687
|
+
const deletionDate = valueFromNode(deletionDateNode.value);
|
4688
|
+
const isValidDate = DATE_REGEX.test(deletionDate);
|
4689
|
+
if (!isValidDate) {
|
3915
4690
|
context.report({
|
3916
4691
|
node: deletionDateNode.value,
|
3917
4692
|
messageId: MESSAGE_INVALID_FORMAT,
|
@@ -3920,8 +4695,9 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3920
4695
|
return;
|
3921
4696
|
}
|
3922
4697
|
let [day, month, year] = deletionDate.split("/");
|
3923
|
-
day = day.padStart(2, "0")
|
3924
|
-
|
4698
|
+
day = day.padStart(2, "0");
|
4699
|
+
month = month.padStart(2, "0");
|
4700
|
+
const deletionDateInMS = Date.parse(`${year}-${month}-${day}`);
|
3925
4701
|
if (Number.isNaN(deletionDateInMS)) {
|
3926
4702
|
context.report({
|
3927
4703
|
node: deletionDateNode.value,
|
@@ -3933,8 +4709,10 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3933
4709
|
});
|
3934
4710
|
return;
|
3935
4711
|
}
|
3936
|
-
|
3937
|
-
|
4712
|
+
const canRemove = Date.now() > deletionDateInMS;
|
4713
|
+
if (canRemove) {
|
4714
|
+
const { parent } = node;
|
4715
|
+
const nodeName = parent.name.value;
|
3938
4716
|
context.report({
|
3939
4717
|
node: parent.name,
|
3940
4718
|
messageId: MESSAGE_CAN_BE_REMOVED,
|
@@ -3959,7 +4737,7 @@ var rule22 = {
|
|
3959
4737
|
description: "Require all deprecation directives to specify a reason.",
|
3960
4738
|
category: "Schema",
|
3961
4739
|
url: "https://the-guild.dev/graphql/eslint/rules/require-deprecation-reason",
|
3962
|
-
recommended:
|
4740
|
+
recommended: true,
|
3963
4741
|
examples: [
|
3964
4742
|
{
|
3965
4743
|
title: "Incorrect",
|
@@ -4002,13 +4780,16 @@ var rule22 = {
|
|
4002
4780
|
create(context) {
|
4003
4781
|
return {
|
4004
4782
|
"Directive[name.value=deprecated]"(node) {
|
4005
|
-
|
4783
|
+
const reasonArgument = node.arguments?.find(
|
4006
4784
|
(arg) => arg.name.value === "reason"
|
4007
4785
|
);
|
4008
|
-
reasonArgument && String(valueFromNode(reasonArgument.value)).trim()
|
4009
|
-
|
4010
|
-
|
4011
|
-
|
4786
|
+
const value = reasonArgument && String(valueFromNode(reasonArgument.value)).trim();
|
4787
|
+
if (!value) {
|
4788
|
+
context.report({
|
4789
|
+
node: node.name,
|
4790
|
+
message: `Deprecation reason is required for ${getNodeName(node.parent)}.`
|
4791
|
+
});
|
4792
|
+
}
|
4012
4793
|
}
|
4013
4794
|
};
|
4014
4795
|
}
|
@@ -4017,57 +4798,60 @@ var rule22 = {
|
|
4017
4798
|
// src/rules/require-description/index.ts
|
4018
4799
|
import { Kind as Kind17, TokenKind as TokenKind3 } from "graphql";
|
4019
4800
|
import { getRootTypeNames } from "@graphql-tools/utils";
|
4020
|
-
var RULE_ID14 = "require-description"
|
4801
|
+
var RULE_ID14 = "require-description";
|
4802
|
+
var ALLOWED_KINDS2 = [
|
4021
4803
|
...TYPES_KINDS,
|
4022
4804
|
Kind17.DIRECTIVE_DEFINITION,
|
4023
4805
|
Kind17.FIELD_DEFINITION,
|
4024
4806
|
Kind17.INPUT_VALUE_DEFINITION,
|
4025
4807
|
Kind17.ENUM_VALUE_DEFINITION,
|
4026
4808
|
Kind17.OPERATION_DEFINITION
|
4027
|
-
]
|
4809
|
+
];
|
4810
|
+
var entries = /* @__PURE__ */ Object.create(null);
|
4811
|
+
for (const kind of [...ALLOWED_KINDS2].sort()) {
|
4812
|
+
let description = `> [!NOTE]
|
4813
|
+
>
|
4814
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
4815
|
+
if (kind === Kind17.OPERATION_DEFINITION) {
|
4816
|
+
description += [
|
4817
|
+
"",
|
4818
|
+
"",
|
4819
|
+
"> [!WARNING]",
|
4820
|
+
">",
|
4821
|
+
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
4822
|
+
].join("\n");
|
4823
|
+
}
|
4824
|
+
entries[kind] = { type: "boolean", description };
|
4825
|
+
}
|
4826
|
+
var schema12 = {
|
4028
4827
|
type: "array",
|
4029
4828
|
minItems: 1,
|
4030
4829
|
maxItems: 1,
|
4031
4830
|
items: {
|
4032
4831
|
type: "object",
|
4033
|
-
additionalProperties:
|
4832
|
+
additionalProperties: false,
|
4034
4833
|
minProperties: 1,
|
4035
4834
|
properties: {
|
4036
4835
|
types: {
|
4037
4836
|
type: "boolean",
|
4038
|
-
enum: [
|
4837
|
+
enum: [true],
|
4039
4838
|
description: `Includes:
|
4040
|
-
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
4041
|
-
`)}`
|
4839
|
+
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
|
4042
4840
|
},
|
4043
4841
|
rootField: {
|
4044
4842
|
type: "boolean",
|
4045
|
-
enum: [
|
4843
|
+
enum: [true],
|
4046
4844
|
description: "Definitions within `Query`, `Mutation`, and `Subscription` root types."
|
4047
4845
|
},
|
4048
4846
|
ignoredSelectors: {
|
4049
4847
|
...ARRAY_DEFAULT_OPTIONS,
|
4050
|
-
description: ["Ignore specific selectors", eslintSelectorsTip].join(
|
4051
|
-
`)
|
4848
|
+
description: ["Ignore specific selectors", eslintSelectorsTip].join("\n")
|
4052
4849
|
},
|
4053
|
-
...
|
4054
|
-
[...ALLOWED_KINDS2].sort().map((kind) => {
|
4055
|
-
let description = `> [!NOTE]
|
4056
|
-
>
|
4057
|
-
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
4058
|
-
return kind === Kind17.OPERATION_DEFINITION && (description += [
|
4059
|
-
"",
|
4060
|
-
"",
|
4061
|
-
"> [!WARNING]",
|
4062
|
-
">",
|
4063
|
-
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
4064
|
-
].join(`
|
4065
|
-
`)), [kind, { type: "boolean", description }];
|
4066
|
-
})
|
4067
|
-
)
|
4850
|
+
...entries
|
4068
4851
|
}
|
4069
4852
|
}
|
4070
|
-
}
|
4853
|
+
};
|
4854
|
+
var rule23 = {
|
4071
4855
|
meta: {
|
4072
4856
|
docs: {
|
4073
4857
|
category: "Schema",
|
@@ -4076,7 +4860,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4076
4860
|
examples: [
|
4077
4861
|
{
|
4078
4862
|
title: "Incorrect",
|
4079
|
-
usage: [{ types:
|
4863
|
+
usage: [{ types: true, FieldDefinition: true }],
|
4080
4864
|
code: (
|
4081
4865
|
/* GraphQL */
|
4082
4866
|
`
|
@@ -4088,7 +4872,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4088
4872
|
},
|
4089
4873
|
{
|
4090
4874
|
title: "Correct",
|
4091
|
-
usage: [{ types:
|
4875
|
+
usage: [{ types: true, FieldDefinition: true }],
|
4092
4876
|
code: (
|
4093
4877
|
/* GraphQL */
|
4094
4878
|
`
|
@@ -4106,7 +4890,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4106
4890
|
},
|
4107
4891
|
{
|
4108
4892
|
title: "Correct",
|
4109
|
-
usage: [{ OperationDefinition:
|
4893
|
+
usage: [{ OperationDefinition: true }],
|
4110
4894
|
code: (
|
4111
4895
|
/* GraphQL */
|
4112
4896
|
`
|
@@ -4119,7 +4903,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4119
4903
|
},
|
4120
4904
|
{
|
4121
4905
|
title: "Correct",
|
4122
|
-
usage: [{ rootField:
|
4906
|
+
usage: [{ rootField: true }],
|
4123
4907
|
code: (
|
4124
4908
|
/* GraphQL */
|
4125
4909
|
`
|
@@ -4167,12 +4951,12 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4167
4951
|
],
|
4168
4952
|
configOptions: [
|
4169
4953
|
{
|
4170
|
-
types:
|
4171
|
-
[Kind17.DIRECTIVE_DEFINITION]:
|
4172
|
-
rootField:
|
4954
|
+
types: true,
|
4955
|
+
[Kind17.DIRECTIVE_DEFINITION]: true,
|
4956
|
+
rootField: true
|
4173
4957
|
}
|
4174
4958
|
],
|
4175
|
-
recommended:
|
4959
|
+
recommended: true
|
4176
4960
|
},
|
4177
4961
|
type: "suggestion",
|
4178
4962
|
messages: {
|
@@ -4181,11 +4965,18 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4181
4965
|
schema: schema12
|
4182
4966
|
},
|
4183
4967
|
create(context) {
|
4184
|
-
|
4185
|
-
|
4186
|
-
|
4968
|
+
const { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {};
|
4969
|
+
const kinds = new Set(types ? TYPES_KINDS : []);
|
4970
|
+
for (const [kind, isEnabled] of Object.entries(restOptions)) {
|
4971
|
+
if (isEnabled) {
|
4972
|
+
kinds.add(kind);
|
4973
|
+
} else {
|
4974
|
+
kinds.delete(kind);
|
4975
|
+
}
|
4976
|
+
}
|
4187
4977
|
if (rootField) {
|
4188
|
-
|
4978
|
+
const schema16 = requireGraphQLSchema(RULE_ID14, context);
|
4979
|
+
const rootTypeNames = getRootTypeNames(schema16);
|
4189
4980
|
kinds.add(
|
4190
4981
|
`:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/^(${[
|
4191
4982
|
...rootTypeNames
|
@@ -4193,26 +4984,35 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4193
4984
|
);
|
4194
4985
|
}
|
4195
4986
|
let selector = `:matches(${[...kinds]})`;
|
4196
|
-
for (
|
4987
|
+
for (const str of ignoredSelectors) {
|
4197
4988
|
selector += `:not(${str})`;
|
4989
|
+
}
|
4198
4990
|
return {
|
4199
4991
|
[selector](node) {
|
4200
|
-
let description = ""
|
4992
|
+
let description = "";
|
4993
|
+
const isOperation = node.kind === Kind17.OPERATION_DEFINITION;
|
4201
4994
|
if (isOperation) {
|
4202
|
-
|
4995
|
+
const rawNode = node.rawNode();
|
4996
|
+
const { prev, line } = rawNode.loc.startToken;
|
4203
4997
|
if (prev?.kind === TokenKind3.COMMENT) {
|
4204
|
-
|
4205
|
-
|
4998
|
+
const value = prev.value.trim();
|
4999
|
+
const linesBefore = line - prev.line;
|
5000
|
+
if (!value.startsWith("eslint") && linesBefore === 1) {
|
5001
|
+
description = value;
|
5002
|
+
}
|
4206
5003
|
}
|
4207
|
-
} else
|
5004
|
+
} else {
|
4208
5005
|
description = node.description?.value.trim() || "";
|
4209
|
-
|
4210
|
-
|
4211
|
-
|
4212
|
-
|
4213
|
-
|
4214
|
-
|
4215
|
-
|
5006
|
+
}
|
5007
|
+
if (description.length === 0) {
|
5008
|
+
context.report({
|
5009
|
+
loc: isOperation ? getLocation(node.loc.start, node.operation) : node.name.loc,
|
5010
|
+
messageId: RULE_ID14,
|
5011
|
+
data: {
|
5012
|
+
nodeName: getNodeName(node)
|
5013
|
+
}
|
5014
|
+
});
|
5015
|
+
}
|
4216
5016
|
}
|
4217
5017
|
};
|
4218
5018
|
}
|
@@ -4220,14 +5020,15 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4220
5020
|
|
4221
5021
|
// src/rules/require-field-of-type-query-in-mutation-result/index.ts
|
4222
5022
|
import { isObjectType as isObjectType3 } from "graphql";
|
4223
|
-
var RULE_ID15 = "require-field-of-type-query-in-mutation-result"
|
5023
|
+
var RULE_ID15 = "require-field-of-type-query-in-mutation-result";
|
5024
|
+
var rule24 = {
|
4224
5025
|
meta: {
|
4225
5026
|
type: "suggestion",
|
4226
5027
|
docs: {
|
4227
5028
|
category: "Schema",
|
4228
5029
|
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`.",
|
4229
5030
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID15}`,
|
4230
|
-
requiresSchema:
|
5031
|
+
requiresSchema: true,
|
4231
5032
|
examples: [
|
4232
5033
|
{
|
4233
5034
|
title: "Incorrect",
|
@@ -4267,16 +5068,26 @@ var RULE_ID15 = "require-field-of-type-query-in-mutation-result", rule24 = {
|
|
4267
5068
|
schema: []
|
4268
5069
|
},
|
4269
5070
|
create(context) {
|
4270
|
-
|
4271
|
-
|
4272
|
-
|
4273
|
-
|
5071
|
+
const schema16 = requireGraphQLSchema(RULE_ID15, context);
|
5072
|
+
const mutationType = schema16.getMutationType();
|
5073
|
+
const queryType = schema16.getQueryType();
|
5074
|
+
if (!mutationType || !queryType) {
|
5075
|
+
return {};
|
5076
|
+
}
|
5077
|
+
const selector = `:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}] > FieldDefinition > .gqlType Name`;
|
5078
|
+
return {
|
5079
|
+
[selector](node) {
|
5080
|
+
const typeName = node.value;
|
5081
|
+
const graphQLType = schema16.getType(typeName);
|
4274
5082
|
if (isObjectType3(graphQLType)) {
|
4275
|
-
|
4276
|
-
fields?.some((field) => getTypeName(field) === queryType.name)
|
4277
|
-
|
4278
|
-
|
4279
|
-
|
5083
|
+
const { fields } = graphQLType.astNode;
|
5084
|
+
const hasQueryType = fields?.some((field) => getTypeName(field) === queryType.name);
|
5085
|
+
if (!hasQueryType) {
|
5086
|
+
context.report({
|
5087
|
+
node,
|
5088
|
+
message: `Mutation result type "${graphQLType.name}" must contain field of type "${queryType.name}"`
|
5089
|
+
});
|
5090
|
+
}
|
4280
5091
|
}
|
4281
5092
|
}
|
4282
5093
|
};
|
@@ -4285,7 +5096,9 @@ var RULE_ID15 = "require-field-of-type-query-in-mutation-result", rule24 = {
|
|
4285
5096
|
|
4286
5097
|
// src/rules/require-import-fragment/index.ts
|
4287
5098
|
import path from "node:path";
|
4288
|
-
var RULE_ID16 = "require-import-fragment"
|
5099
|
+
var RULE_ID16 = "require-import-fragment";
|
5100
|
+
var SUGGESTION_ID = "add-import-expression";
|
5101
|
+
var rule25 = {
|
4289
5102
|
meta: {
|
4290
5103
|
type: "suggestion",
|
4291
5104
|
docs: {
|
@@ -4349,9 +5162,9 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4349
5162
|
)
|
4350
5163
|
}
|
4351
5164
|
],
|
4352
|
-
requiresSiblings:
|
5165
|
+
requiresSiblings: true
|
4353
5166
|
},
|
4354
|
-
hasSuggestions:
|
5167
|
+
hasSuggestions: true,
|
4355
5168
|
messages: {
|
4356
5169
|
[RULE_ID16]: 'Expected "{{fragmentName}}" fragment to be imported.',
|
4357
5170
|
[SUGGESTION_ID]: 'Add import expression for "{{fragmentName}}".'
|
@@ -4359,25 +5172,32 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4359
5172
|
schema: []
|
4360
5173
|
},
|
4361
5174
|
create(context) {
|
4362
|
-
|
5175
|
+
const comments = context.getSourceCode().getAllComments();
|
5176
|
+
const siblings = requireGraphQLOperations(RULE_ID16, context);
|
5177
|
+
const filePath = context.filename;
|
4363
5178
|
return {
|
4364
5179
|
"FragmentSpread > .name"(node) {
|
4365
|
-
|
4366
|
-
|
4367
|
-
|
5180
|
+
const fragmentName = node.value;
|
5181
|
+
const fragmentsFromSiblings = siblings.getFragment(fragmentName);
|
5182
|
+
for (const comment of comments) {
|
5183
|
+
if (comment.type !== "Line") continue;
|
5184
|
+
const isPossibleImported = new RegExp(
|
4368
5185
|
`^\\s*import\\s+(${fragmentName}\\s+from\\s+)?['"]`
|
4369
|
-
).test(comment.value)
|
4370
|
-
|
5186
|
+
).test(comment.value);
|
5187
|
+
if (!isPossibleImported) continue;
|
5188
|
+
const extractedImportPath = comment.value.match(/(["'])((?:\1|.)*?)\1/)?.[2];
|
4371
5189
|
if (!extractedImportPath) continue;
|
4372
|
-
|
4373
|
-
|
5190
|
+
const importPath = path.join(filePath, "..", extractedImportPath);
|
5191
|
+
const hasInSiblings = fragmentsFromSiblings.some(
|
4374
5192
|
(source) => source.filePath === importPath
|
4375
|
-
)
|
5193
|
+
);
|
5194
|
+
if (hasInSiblings) return;
|
4376
5195
|
}
|
4377
|
-
|
5196
|
+
const fragmentInSameFile = fragmentsFromSiblings.some(
|
4378
5197
|
(source) => source.filePath === filePath
|
4379
|
-
)
|
4380
|
-
|
5198
|
+
);
|
5199
|
+
if (fragmentInSameFile) return;
|
5200
|
+
const suggestedFilePaths = fragmentsFromSiblings.length ? fragmentsFromSiblings.map(
|
4381
5201
|
(o) => (
|
4382
5202
|
// Use always forward slash for suggested import path
|
4383
5203
|
slash(path.relative(path.dirname(filePath), o.filePath))
|
@@ -4404,7 +5224,8 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4404
5224
|
|
4405
5225
|
// src/rules/require-nullable-fields-with-oneof/index.ts
|
4406
5226
|
import { Kind as Kind18 } from "graphql";
|
4407
|
-
var RULE_ID17 = "require-nullable-fields-with-oneof"
|
5227
|
+
var RULE_ID17 = "require-nullable-fields-with-oneof";
|
5228
|
+
var rule26 = {
|
4408
5229
|
meta: {
|
4409
5230
|
type: "suggestion",
|
4410
5231
|
docs: {
|
@@ -4446,16 +5267,22 @@ var RULE_ID17 = "require-nullable-fields-with-oneof", rule26 = {
|
|
4446
5267
|
create(context) {
|
4447
5268
|
return {
|
4448
5269
|
"Directive[name.value=oneOf]"({ parent }) {
|
4449
|
-
|
5270
|
+
const isTypeOrInput = [
|
4450
5271
|
Kind18.OBJECT_TYPE_DEFINITION,
|
4451
5272
|
Kind18.INPUT_OBJECT_TYPE_DEFINITION
|
4452
|
-
].includes(parent.kind)
|
4453
|
-
|
4454
|
-
|
5273
|
+
].includes(parent.kind);
|
5274
|
+
if (!isTypeOrInput) {
|
5275
|
+
return;
|
5276
|
+
}
|
5277
|
+
for (const field of parent.fields || []) {
|
5278
|
+
if (field.gqlType.kind === Kind18.NON_NULL_TYPE) {
|
5279
|
+
context.report({
|
4455
5280
|
node: field.name,
|
4456
5281
|
messageId: RULE_ID17,
|
4457
5282
|
data: { nodeName: getNodeName(field) }
|
4458
5283
|
});
|
5284
|
+
}
|
5285
|
+
}
|
4459
5286
|
}
|
4460
5287
|
};
|
4461
5288
|
}
|
@@ -4463,15 +5290,16 @@ var RULE_ID17 = "require-nullable-fields-with-oneof", rule26 = {
|
|
4463
5290
|
|
4464
5291
|
// src/rules/require-nullable-result-in-root/index.ts
|
4465
5292
|
import { Kind as Kind19 } from "graphql";
|
4466
|
-
var RULE_ID18 = "require-nullable-result-in-root"
|
5293
|
+
var RULE_ID18 = "require-nullable-result-in-root";
|
5294
|
+
var rule27 = {
|
4467
5295
|
meta: {
|
4468
5296
|
type: "suggestion",
|
4469
|
-
hasSuggestions:
|
5297
|
+
hasSuggestions: true,
|
4470
5298
|
docs: {
|
4471
5299
|
category: "Schema",
|
4472
5300
|
description: "Require nullable fields in root types.",
|
4473
5301
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID18}`,
|
4474
|
-
requiresSchema:
|
5302
|
+
requiresSchema: true,
|
4475
5303
|
examples: [
|
4476
5304
|
{
|
4477
5305
|
title: "Incorrect",
|
@@ -4505,34 +5333,38 @@ var RULE_ID18 = "require-nullable-result-in-root", rule27 = {
|
|
4505
5333
|
schema: []
|
4506
5334
|
},
|
4507
5335
|
create(context) {
|
4508
|
-
|
5336
|
+
const schema16 = requireGraphQLSchema(RULE_ID18, context);
|
5337
|
+
const rootTypeNames = new Set(
|
4509
5338
|
[schema16.getQueryType(), schema16.getMutationType()].filter((v) => !!v).map((type) => type.name)
|
4510
|
-
)
|
5339
|
+
);
|
5340
|
+
const sourceCode = context.getSourceCode();
|
4511
5341
|
return {
|
4512
5342
|
"ObjectTypeDefinition,ObjectTypeExtension"(node) {
|
4513
|
-
if (rootTypeNames.has(node.name.value))
|
4514
|
-
|
4515
|
-
|
4516
|
-
|
4517
|
-
|
4518
|
-
|
4519
|
-
|
4520
|
-
|
4521
|
-
|
4522
|
-
|
4523
|
-
|
4524
|
-
|
4525
|
-
|
4526
|
-
|
4527
|
-
|
4528
|
-
|
4529
|
-
|
4530
|
-
|
4531
|
-
|
5343
|
+
if (!rootTypeNames.has(node.name.value)) return;
|
5344
|
+
for (const field of node.fields || []) {
|
5345
|
+
if (field.gqlType.type !== Kind19.NON_NULL_TYPE || field.gqlType.gqlType.type !== Kind19.NAMED_TYPE)
|
5346
|
+
continue;
|
5347
|
+
const name = field.gqlType.gqlType.name.value;
|
5348
|
+
const type = schema16.getType(name);
|
5349
|
+
const resultType = type?.astNode ? getNodeName(type.astNode) : type?.name;
|
5350
|
+
context.report({
|
5351
|
+
node: field.gqlType,
|
5352
|
+
messageId: RULE_ID18,
|
5353
|
+
data: {
|
5354
|
+
resultType: resultType || "",
|
5355
|
+
rootType: getNodeName(node)
|
5356
|
+
},
|
5357
|
+
suggest: [
|
5358
|
+
{
|
5359
|
+
desc: `Make ${resultType} nullable`,
|
5360
|
+
fix(fixer) {
|
5361
|
+
const text = sourceCode.getText(field.gqlType);
|
5362
|
+
return fixer.replaceText(field.gqlType, text.replace("!", ""));
|
4532
5363
|
}
|
4533
|
-
|
4534
|
-
|
4535
|
-
}
|
5364
|
+
}
|
5365
|
+
]
|
5366
|
+
});
|
5367
|
+
}
|
4536
5368
|
}
|
4537
5369
|
};
|
4538
5370
|
}
|
@@ -4549,7 +5381,9 @@ import {
|
|
4549
5381
|
visitWithTypeInfo as visitWithTypeInfo3
|
4550
5382
|
} from "graphql";
|
4551
5383
|
import { asArray } from "@graphql-tools/utils";
|
4552
|
-
var RULE_ID19 = "require-selections"
|
5384
|
+
var RULE_ID19 = "require-selections";
|
5385
|
+
var DEFAULT_ID_FIELD_NAME = "id";
|
5386
|
+
var schema13 = {
|
4553
5387
|
definitions: {
|
4554
5388
|
asString: {
|
4555
5389
|
type: "string"
|
@@ -4560,7 +5394,7 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4560
5394
|
maxItems: 1,
|
4561
5395
|
items: {
|
4562
5396
|
type: "object",
|
4563
|
-
additionalProperties:
|
5397
|
+
additionalProperties: false,
|
4564
5398
|
properties: {
|
4565
5399
|
fieldName: {
|
4566
5400
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asArray" }],
|
@@ -4572,16 +5406,17 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4572
5406
|
}
|
4573
5407
|
}
|
4574
5408
|
}
|
4575
|
-
}
|
5409
|
+
};
|
5410
|
+
var rule28 = {
|
4576
5411
|
meta: {
|
4577
5412
|
type: "suggestion",
|
4578
|
-
hasSuggestions:
|
5413
|
+
hasSuggestions: true,
|
4579
5414
|
docs: {
|
4580
5415
|
category: "Operations",
|
4581
5416
|
description: "Enforce selecting specific fields when they are available on the GraphQL type.",
|
4582
5417
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID19}`,
|
4583
|
-
requiresSchema:
|
4584
|
-
requiresSiblings:
|
5418
|
+
requiresSchema: true,
|
5419
|
+
requiresSiblings: true,
|
4585
5420
|
examples: [
|
4586
5421
|
{
|
4587
5422
|
title: "Incorrect",
|
@@ -4632,87 +5467,120 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4632
5467
|
)
|
4633
5468
|
}
|
4634
5469
|
],
|
4635
|
-
recommended:
|
5470
|
+
recommended: true,
|
4636
5471
|
whenNotToUseIt: "Relay Compiler automatically adds an `id` field to any type that has an `id` field, even if it hasn't been explicitly requested. Requesting a field that is not used directly in the code can conflict with another Relay rule: `relay/unused-fields`."
|
4637
5472
|
},
|
4638
5473
|
messages: {
|
4639
|
-
[RULE_ID19]:
|
4640
|
-
Include it in your selection set{{ addition }}.`
|
5474
|
+
[RULE_ID19]: "Field{{ pluralSuffix }} {{ fieldName }} must be selected when it's available on a type.\nInclude it in your selection set{{ addition }}."
|
4641
5475
|
},
|
4642
5476
|
schema: schema13
|
4643
5477
|
},
|
4644
5478
|
create(context) {
|
4645
|
-
|
5479
|
+
const schema16 = requireGraphQLSchema(RULE_ID19, context);
|
5480
|
+
const siblings = requireGraphQLOperations(RULE_ID19, context);
|
5481
|
+
const { fieldName = DEFAULT_ID_FIELD_NAME, requireAllFields } = context.options[0] || {};
|
5482
|
+
const idNames = asArray(fieldName);
|
5483
|
+
const selector = "SelectionSet[parent.kind!=/(^OperationDefinition|InlineFragment)$/]";
|
5484
|
+
const typeInfo = new TypeInfo3(schema16);
|
4646
5485
|
function checkFragments(node) {
|
4647
|
-
for (
|
4648
|
-
if (selection.kind !== Kind20.FRAGMENT_SPREAD)
|
5486
|
+
for (const selection of node.selections) {
|
5487
|
+
if (selection.kind !== Kind20.FRAGMENT_SPREAD) {
|
4649
5488
|
continue;
|
4650
|
-
|
4651
|
-
|
5489
|
+
}
|
5490
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
5491
|
+
if (!foundSpread) {
|
4652
5492
|
continue;
|
4653
|
-
|
5493
|
+
}
|
5494
|
+
const checkedFragmentSpreads = /* @__PURE__ */ new Set();
|
5495
|
+
const visitor = visitWithTypeInfo3(typeInfo, {
|
4654
5496
|
SelectionSet(node2, key, _parent) {
|
4655
|
-
|
4656
|
-
parent.kind === Kind20.FRAGMENT_DEFINITION
|
4657
|
-
|
4658
|
-
|
4659
|
-
|
4660
|
-
|
4661
|
-
|
4662
|
-
|
5497
|
+
const parent = _parent;
|
5498
|
+
if (parent.kind === Kind20.FRAGMENT_DEFINITION) {
|
5499
|
+
checkedFragmentSpreads.add(parent.name.value);
|
5500
|
+
} else if (parent.kind !== Kind20.INLINE_FRAGMENT) {
|
5501
|
+
checkSelections(
|
5502
|
+
node2,
|
5503
|
+
typeInfo.getType(),
|
5504
|
+
selection.loc.start,
|
5505
|
+
parent,
|
5506
|
+
checkedFragmentSpreads
|
5507
|
+
);
|
5508
|
+
}
|
4663
5509
|
}
|
4664
5510
|
});
|
4665
5511
|
visit8(foundSpread.document, visitor);
|
4666
5512
|
}
|
4667
5513
|
}
|
4668
5514
|
function checkSelections(node, type, loc, parent, checkedFragmentSpreads = /* @__PURE__ */ new Set()) {
|
4669
|
-
|
4670
|
-
if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType)
|
5515
|
+
const rawType = getBaseType(type);
|
5516
|
+
if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType) {
|
4671
5517
|
checkFields(rawType);
|
4672
|
-
else if (rawType instanceof GraphQLUnionType)
|
4673
|
-
for (
|
4674
|
-
|
5518
|
+
} else if (rawType instanceof GraphQLUnionType) {
|
5519
|
+
for (const selection of node.selections) {
|
5520
|
+
const types = rawType.getTypes();
|
4675
5521
|
if (selection.kind === Kind20.INLINE_FRAGMENT) {
|
4676
|
-
|
4677
|
-
|
5522
|
+
const t = types.find((t2) => t2.name === selection.typeCondition.name.value);
|
5523
|
+
if (t) {
|
5524
|
+
checkFields(t);
|
5525
|
+
}
|
4678
5526
|
} else if (selection.kind === Kind20.FRAGMENT_SPREAD) {
|
4679
|
-
|
5527
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
4680
5528
|
if (!foundSpread) return;
|
4681
|
-
|
4682
|
-
|
5529
|
+
const fragmentSpread = foundSpread.document;
|
5530
|
+
const t = fragmentSpread.typeCondition.name.value === rawType.name ? rawType : types.find((t2) => t2.name === fragmentSpread.typeCondition.name.value);
|
5531
|
+
checkedFragmentSpreads.add(fragmentSpread.name.value);
|
5532
|
+
checkSelections(fragmentSpread.selectionSet, t, loc, parent, checkedFragmentSpreads);
|
4683
5533
|
}
|
4684
5534
|
}
|
5535
|
+
}
|
4685
5536
|
function checkFields(rawType2) {
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
|
4690
|
-
|
4691
|
-
|
4692
|
-
|
5537
|
+
const fields = rawType2.getFields();
|
5538
|
+
const hasIdFieldInType = idNames.some((name) => fields[name]);
|
5539
|
+
if (!hasIdFieldInType) {
|
5540
|
+
return;
|
5541
|
+
}
|
5542
|
+
checkFragments(node);
|
5543
|
+
if (requireAllFields) {
|
5544
|
+
for (const idName of idNames) {
|
5545
|
+
report([idName]);
|
5546
|
+
}
|
5547
|
+
} else {
|
5548
|
+
report(idNames);
|
5549
|
+
}
|
4693
5550
|
}
|
4694
5551
|
function report(idNames2) {
|
4695
5552
|
function hasIdField({ selections }) {
|
4696
5553
|
return selections.some((selection) => {
|
4697
|
-
if (selection.kind === Kind20.FIELD)
|
4698
|
-
|
4699
|
-
|
5554
|
+
if (selection.kind === Kind20.FIELD) {
|
5555
|
+
if (selection.alias && idNames2.includes(selection.alias.value)) {
|
5556
|
+
return true;
|
5557
|
+
}
|
5558
|
+
return idNames2.includes(selection.name.value);
|
5559
|
+
}
|
5560
|
+
if (selection.kind === Kind20.INLINE_FRAGMENT) {
|
4700
5561
|
return hasIdField(selection.selectionSet);
|
5562
|
+
}
|
4701
5563
|
if (selection.kind === Kind20.FRAGMENT_SPREAD) {
|
4702
|
-
|
5564
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
4703
5565
|
if (foundSpread) {
|
4704
|
-
|
4705
|
-
|
5566
|
+
const fragmentSpread = foundSpread.document;
|
5567
|
+
checkedFragmentSpreads.add(fragmentSpread.name.value);
|
5568
|
+
return hasIdField(fragmentSpread.selectionSet);
|
4706
5569
|
}
|
4707
5570
|
}
|
4708
|
-
return
|
5571
|
+
return false;
|
4709
5572
|
});
|
4710
5573
|
}
|
4711
|
-
|
5574
|
+
const hasId = hasIdField(node);
|
5575
|
+
if (hasId) {
|
4712
5576
|
return;
|
4713
|
-
|
5577
|
+
}
|
5578
|
+
const fieldName2 = englishJoinWords(
|
4714
5579
|
idNames2.map((name) => `\`${(parent.alias || parent.name).value}.${name}\``)
|
4715
|
-
)
|
5580
|
+
);
|
5581
|
+
const pluralSuffix = idNames2.length > 1 ? "s" : "";
|
5582
|
+
const addition = checkedFragmentSpreads.size === 0 ? "" : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? "s" : ""} ${englishJoinWords([...checkedFragmentSpreads].map((name) => `\`${name}\``))}`;
|
5583
|
+
const problem = {
|
4716
5584
|
loc,
|
4717
5585
|
messageId: RULE_ID19,
|
4718
5586
|
data: {
|
@@ -4721,26 +5589,33 @@ Include it in your selection set{{ addition }}.`
|
|
4721
5589
|
addition
|
4722
5590
|
}
|
4723
5591
|
};
|
4724
|
-
"type" in node
|
4725
|
-
|
4726
|
-
|
4727
|
-
|
4728
|
-
|
4729
|
-
|
4730
|
-
|
5592
|
+
if ("type" in node) {
|
5593
|
+
problem.suggest = idNames2.map((idName) => ({
|
5594
|
+
desc: `Add \`${idName}\` selection`,
|
5595
|
+
fix: (fixer) => {
|
5596
|
+
let insertNode = node.selections[0];
|
5597
|
+
insertNode = insertNode.kind === Kind20.INLINE_FRAGMENT ? insertNode.selectionSet.selections[0] : insertNode;
|
5598
|
+
return fixer.insertTextBefore(insertNode, `${idName} `);
|
5599
|
+
}
|
5600
|
+
}));
|
5601
|
+
}
|
5602
|
+
context.report(problem);
|
4731
5603
|
}
|
4732
5604
|
}
|
4733
5605
|
return {
|
4734
5606
|
[selector](node) {
|
4735
|
-
|
4736
|
-
|
5607
|
+
const typeInfo2 = node.typeInfo();
|
5608
|
+
if (typeInfo2.gqlType) {
|
5609
|
+
checkSelections(node, typeInfo2.gqlType, node.loc.start, node.parent);
|
5610
|
+
}
|
4737
5611
|
}
|
4738
5612
|
};
|
4739
5613
|
}
|
4740
5614
|
};
|
4741
5615
|
|
4742
5616
|
// src/rules/require-type-pattern-with-oneof/index.ts
|
4743
|
-
var RULE_ID20 = "require-type-pattern-with-oneof"
|
5617
|
+
var RULE_ID20 = "require-type-pattern-with-oneof";
|
5618
|
+
var rule29 = {
|
4744
5619
|
meta: {
|
4745
5620
|
type: "suggestion",
|
4746
5621
|
docs: {
|
@@ -4784,16 +5659,19 @@ var RULE_ID20 = "require-type-pattern-with-oneof", rule29 = {
|
|
4784
5659
|
"Directive[name.value=oneOf][parent.kind=ObjectTypeDefinition]"({
|
4785
5660
|
parent
|
4786
5661
|
}) {
|
4787
|
-
|
4788
|
-
for (
|
4789
|
-
parent.fields?.some((field) => field.name.value === fieldName)
|
4790
|
-
|
4791
|
-
|
4792
|
-
|
4793
|
-
|
4794
|
-
|
4795
|
-
|
4796
|
-
|
5662
|
+
const requiredFields = ["error", "ok"];
|
5663
|
+
for (const fieldName of requiredFields) {
|
5664
|
+
if (!parent.fields?.some((field) => field.name.value === fieldName)) {
|
5665
|
+
context.report({
|
5666
|
+
node: parent.name,
|
5667
|
+
messageId: RULE_ID20,
|
5668
|
+
data: {
|
5669
|
+
nodeName: displayNodeName(parent),
|
5670
|
+
fieldName
|
5671
|
+
}
|
5672
|
+
});
|
5673
|
+
}
|
5674
|
+
}
|
4797
5675
|
}
|
4798
5676
|
};
|
4799
5677
|
}
|
@@ -4802,13 +5680,14 @@ var RULE_ID20 = "require-type-pattern-with-oneof", rule29 = {
|
|
4802
5680
|
// src/rules/selection-set-depth/index.ts
|
4803
5681
|
import { Kind as Kind21 } from "graphql";
|
4804
5682
|
import depthLimit from "graphql-depth-limit";
|
4805
|
-
var RULE_ID21 = "selection-set-depth"
|
5683
|
+
var RULE_ID21 = "selection-set-depth";
|
5684
|
+
var schema14 = {
|
4806
5685
|
type: "array",
|
4807
5686
|
minItems: 1,
|
4808
5687
|
maxItems: 1,
|
4809
5688
|
items: {
|
4810
5689
|
type: "object",
|
4811
|
-
additionalProperties:
|
5690
|
+
additionalProperties: false,
|
4812
5691
|
required: ["maxDepth"],
|
4813
5692
|
properties: {
|
4814
5693
|
maxDepth: {
|
@@ -4817,15 +5696,16 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4817
5696
|
ignore: ARRAY_DEFAULT_OPTIONS
|
4818
5697
|
}
|
4819
5698
|
}
|
4820
|
-
}
|
5699
|
+
};
|
5700
|
+
var rule30 = {
|
4821
5701
|
meta: {
|
4822
5702
|
type: "suggestion",
|
4823
|
-
hasSuggestions:
|
5703
|
+
hasSuggestions: true,
|
4824
5704
|
docs: {
|
4825
5705
|
category: "Operations",
|
4826
5706
|
description: "Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://npmjs.com/package/graphql-depth-limit).",
|
4827
5707
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID21}`,
|
4828
|
-
requiresSiblings:
|
5708
|
+
requiresSiblings: true,
|
4829
5709
|
examples: [
|
4830
5710
|
{
|
4831
5711
|
title: "Incorrect",
|
@@ -4867,7 +5747,7 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4867
5747
|
`
|
4868
5748
|
}
|
4869
5749
|
],
|
4870
|
-
recommended:
|
5750
|
+
recommended: true,
|
4871
5751
|
configOptions: [{ maxDepth: 7 }]
|
4872
5752
|
},
|
4873
5753
|
schema: schema14
|
@@ -4881,18 +5761,23 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4881
5761
|
`Rule "${RULE_ID21}" works best with siblings operations loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info`
|
4882
5762
|
);
|
4883
5763
|
}
|
4884
|
-
|
5764
|
+
const { maxDepth, ignore = [] } = context.options[0];
|
5765
|
+
const checkFn = depthLimit(maxDepth, { ignore });
|
4885
5766
|
return {
|
4886
5767
|
"OperationDefinition, FragmentDefinition"(node) {
|
4887
5768
|
try {
|
4888
|
-
|
5769
|
+
const rawNode = node.rawNode();
|
5770
|
+
const fragmentsInUse = siblings ? siblings.getFragmentsInUse(rawNode) : [];
|
5771
|
+
const document = {
|
4889
5772
|
kind: Kind21.DOCUMENT,
|
4890
5773
|
definitions: [rawNode, ...fragmentsInUse]
|
4891
5774
|
};
|
4892
5775
|
checkFn({
|
4893
5776
|
getDocument: () => document,
|
4894
5777
|
reportError(error) {
|
4895
|
-
|
5778
|
+
const { line, column } = error.locations[0];
|
5779
|
+
const ancestors = context.sourceCode.getAncestors(node);
|
5780
|
+
const token = ancestors[0].tokens.find(
|
4896
5781
|
(token2) => token2.loc.start.line === line && token2.loc.start.column === column - 1
|
4897
5782
|
);
|
4898
5783
|
context.report({
|
@@ -4907,7 +5792,9 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4907
5792
|
{
|
4908
5793
|
desc: "Remove selections",
|
4909
5794
|
fix(fixer) {
|
4910
|
-
|
5795
|
+
const sourceCode = context.getSourceCode();
|
5796
|
+
const foundNode = sourceCode.getNodeByRangeIndex(token.range[0]);
|
5797
|
+
const parentNode = foundNode.parent.parent;
|
4911
5798
|
return fixer.remove(
|
4912
5799
|
foundNode.kind === "Name" ? parentNode.parent : parentNode
|
4913
5800
|
);
|
@@ -4931,12 +5818,13 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4931
5818
|
|
4932
5819
|
// src/rules/strict-id-in-types/index.ts
|
4933
5820
|
import { Kind as Kind22 } from "graphql";
|
4934
|
-
var RULE_ID22 = "strict-id-in-types"
|
5821
|
+
var RULE_ID22 = "strict-id-in-types";
|
5822
|
+
var schema15 = {
|
4935
5823
|
type: "array",
|
4936
5824
|
maxItems: 1,
|
4937
5825
|
items: {
|
4938
5826
|
type: "object",
|
4939
|
-
additionalProperties:
|
5827
|
+
additionalProperties: false,
|
4940
5828
|
properties: {
|
4941
5829
|
acceptedIdNames: {
|
4942
5830
|
...ARRAY_DEFAULT_OPTIONS,
|
@@ -4948,7 +5836,7 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
4948
5836
|
},
|
4949
5837
|
exceptions: {
|
4950
5838
|
type: "object",
|
4951
|
-
additionalProperties:
|
5839
|
+
additionalProperties: false,
|
4952
5840
|
properties: {
|
4953
5841
|
types: {
|
4954
5842
|
...ARRAY_DEFAULT_OPTIONS,
|
@@ -4962,15 +5850,16 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
4962
5850
|
}
|
4963
5851
|
}
|
4964
5852
|
}
|
4965
|
-
}
|
5853
|
+
};
|
5854
|
+
var rule31 = {
|
4966
5855
|
meta: {
|
4967
5856
|
type: "suggestion",
|
4968
5857
|
docs: {
|
4969
5858
|
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.",
|
4970
5859
|
category: "Schema",
|
4971
|
-
recommended:
|
5860
|
+
recommended: true,
|
4972
5861
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID22}`,
|
4973
|
-
requiresSchema:
|
5862
|
+
requiresSchema: true,
|
4974
5863
|
examples: [
|
4975
5864
|
{
|
4976
5865
|
title: "Incorrect",
|
@@ -5042,26 +5931,38 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
5042
5931
|
schema: schema15
|
5043
5932
|
},
|
5044
5933
|
create(context) {
|
5045
|
-
|
5934
|
+
const options = {
|
5046
5935
|
acceptedIdNames: ["id"],
|
5047
5936
|
acceptedIdTypes: ["ID"],
|
5048
5937
|
exceptions: {},
|
5049
5938
|
...context.options[0]
|
5050
|
-
}
|
5939
|
+
};
|
5940
|
+
const schema16 = requireGraphQLSchema(RULE_ID22, context);
|
5941
|
+
const rootTypeNames = [
|
5942
|
+
schema16.getQueryType(),
|
5943
|
+
schema16.getMutationType(),
|
5944
|
+
schema16.getSubscriptionType()
|
5945
|
+
].filter((v) => !!v).map((type) => type.name);
|
5946
|
+
const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join("|")})$/]`;
|
5051
5947
|
return {
|
5052
|
-
[
|
5053
|
-
|
5054
|
-
|
5055
|
-
|
5056
|
-
].filter((v) => !!v).map((type) => type.name).join("|")})$/]`](node) {
|
5057
|
-
let typeName = node.name.value;
|
5058
|
-
if (options.exceptions.types?.includes(typeName) || options.exceptions.suffixes?.some((suffix) => typeName.endsWith(suffix)))
|
5948
|
+
[selector](node) {
|
5949
|
+
const typeName = node.name.value;
|
5950
|
+
const shouldIgnoreNode = options.exceptions.types?.includes(typeName) || options.exceptions.suffixes?.some((suffix) => typeName.endsWith(suffix));
|
5951
|
+
if (shouldIgnoreNode) {
|
5059
5952
|
return;
|
5060
|
-
|
5061
|
-
|
5062
|
-
|
5063
|
-
|
5064
|
-
let
|
5953
|
+
}
|
5954
|
+
const validIds = node.fields?.filter((field) => {
|
5955
|
+
const fieldNode = field.rawNode();
|
5956
|
+
const isValidIdName = options.acceptedIdNames.includes(fieldNode.name.value);
|
5957
|
+
let isValidIdType = false;
|
5958
|
+
if (fieldNode.type.kind === Kind22.NON_NULL_TYPE && fieldNode.type.type.kind === Kind22.NAMED_TYPE) {
|
5959
|
+
isValidIdType = options.acceptedIdTypes.includes(fieldNode.type.type.name.value);
|
5960
|
+
}
|
5961
|
+
return isValidIdName && isValidIdType;
|
5962
|
+
});
|
5963
|
+
if (validIds?.length !== 1) {
|
5964
|
+
const pluralNamesSuffix = options.acceptedIdNames.length > 1 ? "s" : "";
|
5965
|
+
const pluralTypesSuffix = options.acceptedIdTypes.length > 1 ? "s" : "";
|
5065
5966
|
context.report({
|
5066
5967
|
node: node.name,
|
5067
5968
|
message: `${displayNodeName(node)} must have exactly one non-nullable unique identifier.
|
@@ -5079,11 +5980,11 @@ import { Kind as Kind23 } from "graphql";
|
|
5079
5980
|
var rule32 = {
|
5080
5981
|
meta: {
|
5081
5982
|
type: "suggestion",
|
5082
|
-
hasSuggestions:
|
5983
|
+
hasSuggestions: true,
|
5083
5984
|
docs: {
|
5084
5985
|
url: "https://the-guild.dev/graphql/eslint/rules/unique-enum-value-names",
|
5085
5986
|
category: "Schema",
|
5086
|
-
recommended:
|
5987
|
+
recommended: true,
|
5087
5988
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.
|
5088
5989
|
> This rule disallows case-insensitive enum values duplicates too.`,
|
5089
5990
|
examples: [
|
@@ -5118,13 +6019,14 @@ var rule32 = {
|
|
5118
6019
|
schema: []
|
5119
6020
|
},
|
5120
6021
|
create(context) {
|
6022
|
+
const selector = [Kind23.ENUM_TYPE_DEFINITION, Kind23.ENUM_TYPE_EXTENSION].join(",");
|
5121
6023
|
return {
|
5122
|
-
[
|
5123
|
-
|
6024
|
+
[selector](node) {
|
6025
|
+
const duplicates = node.values?.filter(
|
5124
6026
|
(item, index, array) => array.findIndex((v) => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !== index
|
5125
6027
|
);
|
5126
|
-
for (
|
5127
|
-
|
6028
|
+
for (const duplicate of duplicates || []) {
|
6029
|
+
const enumName = duplicate.name.value;
|
5128
6030
|
context.report({
|
5129
6031
|
node: duplicate.name,
|
5130
6032
|
message: `Unexpected case-insensitive enum values duplicates for ${getNodeName(
|
@@ -5146,30 +6048,38 @@ var rule32 = {
|
|
5146
6048
|
// src/rules/unique-fragment-name/index.ts
|
5147
6049
|
import { relative as relative2 } from "node:path";
|
5148
6050
|
import { Kind as Kind24 } from "graphql";
|
5149
|
-
var RULE_ID23 = "unique-fragment-name"
|
5150
|
-
|
5151
|
-
|
6051
|
+
var RULE_ID23 = "unique-fragment-name";
|
6052
|
+
var checkNode = (context, node, ruleId) => {
|
6053
|
+
const documentName = node.name.value;
|
6054
|
+
const siblings = requireGraphQLOperations(ruleId, context);
|
6055
|
+
const siblingDocuments = node.kind === Kind24.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
|
6056
|
+
const filepath = context.filename;
|
6057
|
+
const conflictingDocuments = siblingDocuments.filter((f) => {
|
6058
|
+
const isSameName = f.document.name?.value === documentName;
|
6059
|
+
const isSamePath = slash(f.filePath) === slash(filepath);
|
5152
6060
|
return isSameName && !isSamePath;
|
5153
6061
|
});
|
5154
|
-
conflictingDocuments.length > 0
|
5155
|
-
|
5156
|
-
|
5157
|
-
|
5158
|
-
|
5159
|
-
`)
|
5160
|
-
|
5161
|
-
|
5162
|
-
|
5163
|
-
|
5164
|
-
}
|
6062
|
+
if (conflictingDocuments.length > 0) {
|
6063
|
+
context.report({
|
6064
|
+
messageId: ruleId,
|
6065
|
+
data: {
|
6066
|
+
documentName,
|
6067
|
+
summary: conflictingDocuments.map((f) => ` ${relative2(CWD, f.filePath.replace(VIRTUAL_DOCUMENT_REGEX, ""))}`).join("\n")
|
6068
|
+
},
|
6069
|
+
// @ts-expect-error name will exist
|
6070
|
+
node: node.name
|
6071
|
+
});
|
6072
|
+
}
|
6073
|
+
};
|
6074
|
+
var rule33 = {
|
5165
6075
|
meta: {
|
5166
6076
|
type: "suggestion",
|
5167
6077
|
docs: {
|
5168
6078
|
category: "Operations",
|
5169
6079
|
description: "Enforce unique fragment names across your project.",
|
5170
6080
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID23}`,
|
5171
|
-
requiresSiblings:
|
5172
|
-
recommended:
|
6081
|
+
requiresSiblings: true,
|
6082
|
+
recommended: true,
|
5173
6083
|
examples: [
|
5174
6084
|
{
|
5175
6085
|
title: "Incorrect",
|
@@ -5212,8 +6122,7 @@ var RULE_ID23 = "unique-fragment-name", checkNode = (context, node, ruleId) => {
|
|
5212
6122
|
]
|
5213
6123
|
},
|
5214
6124
|
messages: {
|
5215
|
-
[RULE_ID23]:
|
5216
|
-
{{ summary }}`
|
6125
|
+
[RULE_ID23]: 'Fragment named "{{ documentName }}" already defined in:\n{{ summary }}'
|
5217
6126
|
},
|
5218
6127
|
schema: []
|
5219
6128
|
},
|
@@ -5227,15 +6136,16 @@ var RULE_ID23 = "unique-fragment-name", checkNode = (context, node, ruleId) => {
|
|
5227
6136
|
};
|
5228
6137
|
|
5229
6138
|
// src/rules/unique-operation-name/index.ts
|
5230
|
-
var RULE_ID24 = "unique-operation-name"
|
6139
|
+
var RULE_ID24 = "unique-operation-name";
|
6140
|
+
var rule34 = {
|
5231
6141
|
meta: {
|
5232
6142
|
type: "suggestion",
|
5233
6143
|
docs: {
|
5234
6144
|
category: "Operations",
|
5235
6145
|
description: "Enforce unique operation names across your project.",
|
5236
6146
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID24}`,
|
5237
|
-
requiresSiblings:
|
5238
|
-
recommended:
|
6147
|
+
requiresSiblings: true,
|
6148
|
+
recommended: true,
|
5239
6149
|
examples: [
|
5240
6150
|
{
|
5241
6151
|
title: "Incorrect",
|
@@ -5282,8 +6192,7 @@ var RULE_ID24 = "unique-operation-name", rule34 = {
|
|
5282
6192
|
]
|
5283
6193
|
},
|
5284
6194
|
messages: {
|
5285
|
-
[RULE_ID24]:
|
5286
|
-
{{ summary }}`
|
6195
|
+
[RULE_ID24]: 'Operation named "{{ documentName }}" already defined in:\n{{ summary }}'
|
5287
6196
|
},
|
5288
6197
|
schema: []
|
5289
6198
|
},
|
@@ -5335,227 +6244,21 @@ var rules = {
|
|
5335
6244
|
"unique-operation-name": rule34
|
5336
6245
|
};
|
5337
6246
|
|
5338
|
-
// src/
|
5339
|
-
var
|
5340
|
-
|
5341
|
-
|
5342
|
-
|
5343
|
-
|
5344
|
-
|
5345
|
-
definitions: !0,
|
5346
|
-
selections: ["OperationDefinition", "FragmentDefinition"],
|
5347
|
-
variables: !0,
|
5348
|
-
arguments: ["Field", "Directive"],
|
5349
|
-
groups: ["...", "id", "*", "{"]
|
5350
|
-
}
|
5351
|
-
],
|
5352
|
-
"@graphql-eslint/lone-executable-definition": "error",
|
5353
|
-
"@graphql-eslint/match-document-filename": [
|
5354
|
-
"error",
|
5355
|
-
{
|
5356
|
-
query: "kebab-case",
|
5357
|
-
mutation: "kebab-case",
|
5358
|
-
subscription: "kebab-case",
|
5359
|
-
fragment: "kebab-case"
|
5360
|
-
}
|
5361
|
-
],
|
5362
|
-
"@graphql-eslint/no-one-place-fragments": "error",
|
5363
|
-
"@graphql-eslint/require-import-fragment": "error"
|
5364
|
-
}
|
5365
|
-
};
|
5366
|
-
|
5367
|
-
// src/configs/operations-recommended.ts
|
5368
|
-
var operations_recommended_default = {
|
5369
|
-
parser: "@graphql-eslint/eslint-plugin",
|
5370
|
-
plugins: ["@graphql-eslint"],
|
5371
|
-
rules: {
|
5372
|
-
"@graphql-eslint/executable-definitions": "error",
|
5373
|
-
"@graphql-eslint/fields-on-correct-type": "error",
|
5374
|
-
"@graphql-eslint/fragments-on-composite-type": "error",
|
5375
|
-
"@graphql-eslint/known-argument-names": "error",
|
5376
|
-
"@graphql-eslint/known-directives": "error",
|
5377
|
-
"@graphql-eslint/known-fragment-names": "error",
|
5378
|
-
"@graphql-eslint/known-type-names": "error",
|
5379
|
-
"@graphql-eslint/lone-anonymous-operation": "error",
|
5380
|
-
"@graphql-eslint/naming-convention": [
|
5381
|
-
"error",
|
5382
|
-
{
|
5383
|
-
VariableDefinition: "camelCase",
|
5384
|
-
OperationDefinition: {
|
5385
|
-
style: "PascalCase",
|
5386
|
-
forbiddenPrefixes: ["Query", "Mutation", "Subscription", "Get"],
|
5387
|
-
forbiddenSuffixes: ["Query", "Mutation", "Subscription"]
|
5388
|
-
},
|
5389
|
-
FragmentDefinition: {
|
5390
|
-
style: "PascalCase",
|
5391
|
-
forbiddenPrefixes: ["Fragment"],
|
5392
|
-
forbiddenSuffixes: ["Fragment"]
|
5393
|
-
}
|
5394
|
-
}
|
5395
|
-
],
|
5396
|
-
"@graphql-eslint/no-anonymous-operations": "error",
|
5397
|
-
"@graphql-eslint/no-deprecated": "error",
|
5398
|
-
"@graphql-eslint/no-duplicate-fields": "error",
|
5399
|
-
"@graphql-eslint/no-fragment-cycles": "error",
|
5400
|
-
"@graphql-eslint/no-undefined-variables": "error",
|
5401
|
-
"@graphql-eslint/no-unused-fragments": "error",
|
5402
|
-
"@graphql-eslint/no-unused-variables": "error",
|
5403
|
-
"@graphql-eslint/one-field-subscriptions": "error",
|
5404
|
-
"@graphql-eslint/overlapping-fields-can-be-merged": "error",
|
5405
|
-
"@graphql-eslint/possible-fragment-spread": "error",
|
5406
|
-
"@graphql-eslint/provided-required-arguments": "error",
|
5407
|
-
"@graphql-eslint/require-selections": "error",
|
5408
|
-
"@graphql-eslint/scalar-leafs": "error",
|
5409
|
-
"@graphql-eslint/selection-set-depth": ["error", { maxDepth: 7 }],
|
5410
|
-
"@graphql-eslint/unique-argument-names": "error",
|
5411
|
-
"@graphql-eslint/unique-directive-names-per-location": "error",
|
5412
|
-
"@graphql-eslint/unique-fragment-name": "error",
|
5413
|
-
"@graphql-eslint/unique-input-field-names": "error",
|
5414
|
-
"@graphql-eslint/unique-operation-name": "error",
|
5415
|
-
"@graphql-eslint/unique-variable-names": "error",
|
5416
|
-
"@graphql-eslint/value-literals-of-correct-type": "error",
|
5417
|
-
"@graphql-eslint/variables-are-input-types": "error",
|
5418
|
-
"@graphql-eslint/variables-in-allowed-position": "error"
|
5419
|
-
}
|
5420
|
-
};
|
5421
|
-
|
5422
|
-
// src/configs/schema-all.ts
|
5423
|
-
var schema_all_default = {
|
5424
|
-
extends: "./configs/schema-recommended",
|
5425
|
-
rules: {
|
5426
|
-
"@graphql-eslint/alphabetize": [
|
5427
|
-
"error",
|
5428
|
-
{
|
5429
|
-
definitions: !0,
|
5430
|
-
fields: ["ObjectTypeDefinition", "InterfaceTypeDefinition", "InputObjectTypeDefinition"],
|
5431
|
-
values: !0,
|
5432
|
-
arguments: ["FieldDefinition", "Field", "DirectiveDefinition", "Directive"],
|
5433
|
-
groups: ["id", "*", "createdAt", "updatedAt"]
|
5434
|
-
}
|
5435
|
-
],
|
5436
|
-
"@graphql-eslint/input-name": "error",
|
5437
|
-
"@graphql-eslint/no-root-type": ["error", { disallow: ["mutation", "subscription"] }],
|
5438
|
-
"@graphql-eslint/no-scalar-result-type-on-mutation": "error",
|
5439
|
-
"@graphql-eslint/require-deprecation-date": "error",
|
5440
|
-
"@graphql-eslint/require-field-of-type-query-in-mutation-result": "error",
|
5441
|
-
"@graphql-eslint/require-nullable-fields-with-oneof": "error",
|
5442
|
-
"@graphql-eslint/require-nullable-result-in-root": "error",
|
5443
|
-
"@graphql-eslint/require-type-pattern-with-oneof": "error"
|
5444
|
-
}
|
5445
|
-
};
|
5446
|
-
|
5447
|
-
// src/configs/schema-recommended.ts
|
5448
|
-
var schema_recommended_default = {
|
5449
|
-
parser: "@graphql-eslint/eslint-plugin",
|
5450
|
-
plugins: ["@graphql-eslint"],
|
5451
|
-
rules: {
|
5452
|
-
"@graphql-eslint/description-style": "error",
|
5453
|
-
"@graphql-eslint/known-argument-names": "error",
|
5454
|
-
"@graphql-eslint/known-directives": "error",
|
5455
|
-
"@graphql-eslint/known-type-names": "error",
|
5456
|
-
"@graphql-eslint/lone-schema-definition": "error",
|
5457
|
-
"@graphql-eslint/naming-convention": [
|
5458
|
-
"error",
|
5459
|
-
{
|
5460
|
-
types: "PascalCase",
|
5461
|
-
FieldDefinition: "camelCase",
|
5462
|
-
InputValueDefinition: "camelCase",
|
5463
|
-
Argument: "camelCase",
|
5464
|
-
DirectiveDefinition: "camelCase",
|
5465
|
-
EnumValueDefinition: "UPPER_CASE",
|
5466
|
-
"FieldDefinition[parent.name.value=Query]": {
|
5467
|
-
forbiddenPrefixes: ["query", "get"],
|
5468
|
-
forbiddenSuffixes: ["Query"]
|
5469
|
-
},
|
5470
|
-
"FieldDefinition[parent.name.value=Mutation]": {
|
5471
|
-
forbiddenPrefixes: ["mutation"],
|
5472
|
-
forbiddenSuffixes: ["Mutation"]
|
5473
|
-
},
|
5474
|
-
"FieldDefinition[parent.name.value=Subscription]": {
|
5475
|
-
forbiddenPrefixes: ["subscription"],
|
5476
|
-
forbiddenSuffixes: ["Subscription"]
|
5477
|
-
},
|
5478
|
-
"EnumTypeDefinition,EnumTypeExtension": {
|
5479
|
-
forbiddenPrefixes: ["Enum"],
|
5480
|
-
forbiddenSuffixes: ["Enum"]
|
5481
|
-
},
|
5482
|
-
"InterfaceTypeDefinition,InterfaceTypeExtension": {
|
5483
|
-
forbiddenPrefixes: ["Interface"],
|
5484
|
-
forbiddenSuffixes: ["Interface"]
|
5485
|
-
},
|
5486
|
-
"UnionTypeDefinition,UnionTypeExtension": {
|
5487
|
-
forbiddenPrefixes: ["Union"],
|
5488
|
-
forbiddenSuffixes: ["Union"]
|
5489
|
-
},
|
5490
|
-
"ObjectTypeDefinition,ObjectTypeExtension": {
|
5491
|
-
forbiddenPrefixes: ["Type"],
|
5492
|
-
forbiddenSuffixes: ["Type"]
|
5493
|
-
}
|
5494
|
-
}
|
5495
|
-
],
|
5496
|
-
"@graphql-eslint/no-hashtag-description": "error",
|
5497
|
-
"@graphql-eslint/no-typename-prefix": "error",
|
5498
|
-
"@graphql-eslint/no-unreachable-types": "error",
|
5499
|
-
"@graphql-eslint/possible-type-extension": "error",
|
5500
|
-
"@graphql-eslint/provided-required-arguments": "error",
|
5501
|
-
"@graphql-eslint/require-deprecation-reason": "error",
|
5502
|
-
"@graphql-eslint/require-description": [
|
5503
|
-
"error",
|
5504
|
-
{ types: !0, DirectiveDefinition: !0, rootField: !0 }
|
5505
|
-
],
|
5506
|
-
"@graphql-eslint/strict-id-in-types": "error",
|
5507
|
-
"@graphql-eslint/unique-directive-names": "error",
|
5508
|
-
"@graphql-eslint/unique-directive-names-per-location": "error",
|
5509
|
-
"@graphql-eslint/unique-enum-value-names": "error",
|
5510
|
-
"@graphql-eslint/unique-field-definition-names": "error",
|
5511
|
-
"@graphql-eslint/unique-operation-types": "error",
|
5512
|
-
"@graphql-eslint/unique-type-names": "error"
|
5513
|
-
}
|
5514
|
-
};
|
5515
|
-
|
5516
|
-
// src/configs/schema-relay.ts
|
5517
|
-
var schema_relay_default = {
|
5518
|
-
parser: "@graphql-eslint/eslint-plugin",
|
5519
|
-
plugins: ["@graphql-eslint"],
|
5520
|
-
rules: {
|
5521
|
-
"@graphql-eslint/relay-arguments": "error",
|
5522
|
-
"@graphql-eslint/relay-connection-types": "error",
|
5523
|
-
"@graphql-eslint/relay-edge-types": "error",
|
5524
|
-
"@graphql-eslint/relay-page-info": "error"
|
5525
|
-
}
|
5526
|
-
};
|
5527
|
-
|
5528
|
-
// src/configs/index.ts
|
5529
|
-
var configs = {
|
5530
|
-
"schema-recommended": schema_recommended_default,
|
5531
|
-
"schema-all": schema_all_default,
|
5532
|
-
"schema-relay": schema_relay_default,
|
5533
|
-
"operations-recommended": operations_recommended_default,
|
5534
|
-
"operations-all": operations_all_default,
|
5535
|
-
"flat/schema-recommended": {
|
5536
|
-
rules: schema_recommended_default.rules
|
5537
|
-
},
|
5538
|
-
"flat/schema-all": {
|
5539
|
-
rules: {
|
5540
|
-
...schema_recommended_default.rules,
|
5541
|
-
...schema_all_default.rules
|
5542
|
-
}
|
5543
|
-
},
|
5544
|
-
"flat/schema-relay": {
|
5545
|
-
rules: schema_relay_default.rules
|
5546
|
-
},
|
5547
|
-
"flat/operations-recommended": {
|
5548
|
-
rules: operations_recommended_default.rules
|
5549
|
-
},
|
5550
|
-
"flat/operations-all": {
|
5551
|
-
rules: {
|
5552
|
-
...operations_recommended_default.rules,
|
5553
|
-
...operations_all_default.rules
|
5554
|
-
}
|
5555
|
-
}
|
6247
|
+
// src/index.ts
|
6248
|
+
var processors = { graphql: processor };
|
6249
|
+
var src_default = {
|
6250
|
+
parser,
|
6251
|
+
processor,
|
6252
|
+
rules,
|
6253
|
+
configs
|
5556
6254
|
};
|
5557
6255
|
export {
|
5558
6256
|
configs,
|
6257
|
+
src_default as default,
|
6258
|
+
parseForESLint,
|
5559
6259
|
parser,
|
6260
|
+
processors,
|
6261
|
+
requireGraphQLOperations,
|
6262
|
+
requireGraphQLSchema,
|
5560
6263
|
rules
|
5561
6264
|
};
|