@graphql-eslint/eslint-plugin 4.3.0 → 4.3.1-alpha-20241209185034-de2d7397da8c26620a8930dd12b6dff42e43f537
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/{index.browser.js → browser.js} +1756 -1104
- 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/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/input-name/index.js +51 -38
- package/cjs/rules/lone-executable-definition/index.js +15 -6
- package/cjs/rules/match-document-filename/index.js +57 -32
- package/cjs/rules/naming-convention/index.js +76 -37
- 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.js +60 -42
- 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/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/input-name/index.js +51 -38
- package/esm/rules/lone-executable-definition/index.js +15 -6
- package/esm/rules/match-document-filename/index.js +57 -32
- package/esm/rules/naming-convention/index.js +76 -37
- 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.js +60 -42
- 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/package.json +11 -1
@@ -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-20241209185034-de2d7397da8c26620a8930dd12b6dff42e43f537";
|
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,16 +2111,20 @@ 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 schema5 = {
|
1680
2128
|
definitions: {
|
1681
2129
|
asString: {
|
1682
2130
|
enum: CASE_STYLES,
|
@@ -1684,7 +2132,7 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1684
2132
|
},
|
1685
2133
|
asObject: {
|
1686
2134
|
type: "object",
|
1687
|
-
additionalProperties:
|
2135
|
+
additionalProperties: false,
|
1688
2136
|
minProperties: 1,
|
1689
2137
|
properties: {
|
1690
2138
|
style: { enum: CASE_STYLES },
|
@@ -1698,7 +2146,7 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1698
2146
|
maxItems: 1,
|
1699
2147
|
items: {
|
1700
2148
|
type: "object",
|
1701
|
-
additionalProperties:
|
2149
|
+
additionalProperties: false,
|
1702
2150
|
minProperties: 1,
|
1703
2151
|
properties: {
|
1704
2152
|
fileExtension: { enum: [".gql", ".graphql"] },
|
@@ -1708,7 +2156,8 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1708
2156
|
fragment: schemaOption
|
1709
2157
|
}
|
1710
2158
|
}
|
1711
|
-
}
|
2159
|
+
};
|
2160
|
+
var rule5 = {
|
1712
2161
|
meta: {
|
1713
2162
|
type: "suggestion",
|
1714
2163
|
docs: {
|
@@ -1846,47 +2295,69 @@ var MATCH_EXTENSION = "MATCH_EXTENSION", MATCH_STYLE = "MATCH_STYLE", CASE_STYLE
|
|
1846
2295
|
schema: schema5
|
1847
2296
|
},
|
1848
2297
|
create(context) {
|
1849
|
-
|
2298
|
+
const options = context.options[0] || {
|
1850
2299
|
fileExtension: null
|
1851
|
-
}
|
1852
|
-
|
2300
|
+
};
|
2301
|
+
const filePath = context.filename;
|
2302
|
+
const isVirtualFile = VIRTUAL_DOCUMENT_REGEX.test(filePath);
|
2303
|
+
if (isVirtualFile) {
|
1853
2304
|
return {};
|
1854
|
-
|
2305
|
+
}
|
2306
|
+
const fileExtension = extname(filePath);
|
2307
|
+
const filename = basename(filePath, fileExtension);
|
1855
2308
|
return {
|
1856
2309
|
Document(documentNode) {
|
1857
|
-
options.fileExtension && options.fileExtension !== fileExtension
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
2310
|
+
if (options.fileExtension && options.fileExtension !== fileExtension) {
|
2311
|
+
context.report({
|
2312
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
2313
|
+
messageId: MATCH_EXTENSION,
|
2314
|
+
data: {
|
2315
|
+
fileExtension,
|
2316
|
+
expectedFileExtension: options.fileExtension
|
2317
|
+
}
|
2318
|
+
});
|
2319
|
+
}
|
2320
|
+
const firstOperation = documentNode.definitions.find(
|
1866
2321
|
(n) => n.kind === Kind7.OPERATION_DEFINITION
|
1867
|
-
)
|
2322
|
+
);
|
2323
|
+
const firstFragment = documentNode.definitions.find(
|
1868
2324
|
(n) => n.kind === Kind7.FRAGMENT_DEFINITION
|
1869
|
-
)
|
1870
|
-
|
2325
|
+
);
|
2326
|
+
const node = firstOperation || firstFragment;
|
2327
|
+
if (!node) {
|
1871
2328
|
return;
|
1872
|
-
|
1873
|
-
|
2329
|
+
}
|
2330
|
+
const docName = node.name?.value;
|
2331
|
+
if (!docName) {
|
1874
2332
|
return;
|
1875
|
-
|
1876
|
-
|
2333
|
+
}
|
2334
|
+
const docType = "operation" in node ? node.operation : "fragment";
|
2335
|
+
let option = options[docType];
|
2336
|
+
if (!option) {
|
1877
2337
|
return;
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
2338
|
+
}
|
2339
|
+
if (typeof option === "string") {
|
2340
|
+
option = { style: option };
|
2341
|
+
}
|
2342
|
+
const expectedExtension = options.fileExtension || fileExtension;
|
2343
|
+
let expectedFilename = option.prefix || "";
|
2344
|
+
if (option.style) {
|
2345
|
+
expectedFilename += option.style === "matchDocumentStyle" ? docName : convertCase(option.style, docName);
|
2346
|
+
} else {
|
2347
|
+
expectedFilename += filename;
|
2348
|
+
}
|
2349
|
+
expectedFilename += (option.suffix || "") + expectedExtension;
|
2350
|
+
const filenameWithExtension = filename + expectedExtension;
|
2351
|
+
if (expectedFilename !== filenameWithExtension) {
|
2352
|
+
context.report({
|
2353
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
2354
|
+
messageId: MATCH_STYLE,
|
2355
|
+
data: {
|
2356
|
+
expectedFilename,
|
2357
|
+
filename: filenameWithExtension
|
2358
|
+
}
|
2359
|
+
});
|
2360
|
+
}
|
1890
2361
|
}
|
1891
2362
|
};
|
1892
2363
|
}
|
@@ -1912,16 +2383,22 @@ var KindToDisplayName = {
|
|
1912
2383
|
[Kind8.OPERATION_DEFINITION]: "Operation",
|
1913
2384
|
[Kind8.FRAGMENT_DEFINITION]: "Fragment",
|
1914
2385
|
[Kind8.VARIABLE_DEFINITION]: "Variable"
|
1915
|
-
}
|
2386
|
+
};
|
2387
|
+
var StyleToRegex = {
|
1916
2388
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
1917
2389
|
PascalCase: /^[A-Z][\dA-Za-z]*$/,
|
1918
2390
|
snake_case: /^[a-z][\d_a-z]*[\da-z]*$/,
|
1919
2391
|
UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]*$/
|
1920
|
-
}
|
2392
|
+
};
|
2393
|
+
var ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
|
2394
|
+
var ALLOWED_STYLES = Object.keys(StyleToRegex);
|
2395
|
+
var schemaOption2 = {
|
1921
2396
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asObject" }]
|
1922
|
-
}
|
2397
|
+
};
|
2398
|
+
var descriptionPrefixesSuffixes = (name) => `> [!WARNING]
|
1923
2399
|
>
|
1924
|
-
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${name.toLowerCase()}-array) instead
|
2400
|
+
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${name.toLowerCase()}-array) instead.`;
|
2401
|
+
var schema6 = {
|
1925
2402
|
definitions: {
|
1926
2403
|
asString: {
|
1927
2404
|
enum: ALLOWED_STYLES,
|
@@ -1929,7 +2406,7 @@ var KindToDisplayName = {
|
|
1929
2406
|
},
|
1930
2407
|
asObject: {
|
1931
2408
|
type: "object",
|
1932
|
-
additionalProperties:
|
2409
|
+
additionalProperties: false,
|
1933
2410
|
properties: {
|
1934
2411
|
style: { enum: ALLOWED_STYLES },
|
1935
2412
|
prefix: { type: "string" },
|
@@ -1975,13 +2452,12 @@ var KindToDisplayName = {
|
|
1975
2452
|
maxItems: 1,
|
1976
2453
|
items: {
|
1977
2454
|
type: "object",
|
1978
|
-
additionalProperties:
|
2455
|
+
additionalProperties: false,
|
1979
2456
|
properties: {
|
1980
2457
|
types: {
|
1981
2458
|
...schemaOption2,
|
1982
2459
|
description: `Includes:
|
1983
|
-
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
1984
|
-
`)}`
|
2460
|
+
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
|
1985
2461
|
},
|
1986
2462
|
...Object.fromEntries(
|
1987
2463
|
ALLOWED_KINDS.map((kind) => [
|
@@ -1996,11 +2472,11 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
1996
2472
|
),
|
1997
2473
|
allowLeadingUnderscore: {
|
1998
2474
|
type: "boolean",
|
1999
|
-
default:
|
2475
|
+
default: false
|
2000
2476
|
},
|
2001
2477
|
allowTrailingUnderscore: {
|
2002
2478
|
type: "boolean",
|
2003
|
-
default:
|
2479
|
+
default: false
|
2004
2480
|
}
|
2005
2481
|
},
|
2006
2482
|
patternProperties: {
|
@@ -2012,16 +2488,16 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2012
2488
|
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.",
|
2013
2489
|
">",
|
2014
2490
|
"> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`."
|
2015
|
-
].join(
|
2016
|
-
`)
|
2491
|
+
].join("\n")
|
2017
2492
|
}
|
2018
|
-
}
|
2493
|
+
};
|
2494
|
+
var rule6 = {
|
2019
2495
|
meta: {
|
2020
2496
|
type: "suggestion",
|
2021
2497
|
docs: {
|
2022
2498
|
description: "Require names to follow specified conventions.",
|
2023
2499
|
category: ["Schema", "Operations"],
|
2024
|
-
recommended:
|
2500
|
+
recommended: true,
|
2025
2501
|
url: "https://the-guild.dev/graphql/eslint/rules/naming-convention",
|
2026
2502
|
examples: [
|
2027
2503
|
{
|
@@ -2213,14 +2689,16 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2213
2689
|
]
|
2214
2690
|
}
|
2215
2691
|
},
|
2216
|
-
hasSuggestions:
|
2692
|
+
hasSuggestions: true,
|
2217
2693
|
schema: schema6
|
2218
2694
|
},
|
2219
2695
|
create(context) {
|
2220
|
-
|
2696
|
+
const options = context.options[0] || {};
|
2697
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
2698
|
+
const ignoredNodes = /* @__PURE__ */ new Set();
|
2221
2699
|
function normalisePropertyOption(kind) {
|
2222
|
-
|
2223
|
-
return typeof style
|
2700
|
+
const style = restOptions[kind] || types;
|
2701
|
+
return typeof style === "object" ? style : { style };
|
2224
2702
|
}
|
2225
2703
|
function report(node, message, suggestedNames) {
|
2226
2704
|
context.report({
|
@@ -2232,11 +2710,12 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2232
2710
|
}))
|
2233
2711
|
});
|
2234
2712
|
}
|
2235
|
-
|
2236
|
-
|
2237
|
-
if (!node)
|
2713
|
+
const checkNode2 = (selector) => (n) => {
|
2714
|
+
const { name: node } = n.kind === Kind8.VARIABLE_DEFINITION ? n.variable : n;
|
2715
|
+
if (!node) {
|
2238
2716
|
return;
|
2239
|
-
|
2717
|
+
}
|
2718
|
+
const {
|
2240
2719
|
prefix,
|
2241
2720
|
suffix,
|
2242
2721
|
forbiddenPrefixes,
|
@@ -2247,11 +2726,17 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2247
2726
|
requiredSuffixes,
|
2248
2727
|
forbiddenPatterns,
|
2249
2728
|
requiredPatterns
|
2250
|
-
} = normalisePropertyOption(selector)
|
2729
|
+
} = normalisePropertyOption(selector);
|
2730
|
+
const nodeName = node.value;
|
2731
|
+
const error = getError();
|
2251
2732
|
if (error) {
|
2252
|
-
|
2733
|
+
const { errorMessage, renameToNames } = error;
|
2734
|
+
const [leadingUnderscores] = nodeName.match(/^_*/);
|
2735
|
+
const [trailingUnderscores] = nodeName.match(/_*$/);
|
2736
|
+
const suggestedNames = renameToNames.map(
|
2253
2737
|
(renameToName) => leadingUnderscores + renameToName + trailingUnderscores
|
2254
|
-
)
|
2738
|
+
);
|
2739
|
+
const name = displayNodeName(n);
|
2255
2740
|
report(
|
2256
2741
|
node,
|
2257
2742
|
`${name[0].toUpperCase()}${name.slice(1)} should ${errorMessage}`,
|
@@ -2259,94 +2744,120 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2259
2744
|
);
|
2260
2745
|
}
|
2261
2746
|
function getError() {
|
2262
|
-
|
2747
|
+
const name = nodeName.replace(/(^_+)|(_+$)/g, "");
|
2263
2748
|
if (ignorePattern && new RegExp(ignorePattern, "u").test(name)) {
|
2264
|
-
"name" in n
|
2749
|
+
if ("name" in n) {
|
2750
|
+
ignoredNodes.add(n.name);
|
2751
|
+
}
|
2265
2752
|
return;
|
2266
2753
|
}
|
2267
|
-
if (prefix && !name.startsWith(prefix))
|
2754
|
+
if (prefix && !name.startsWith(prefix)) {
|
2268
2755
|
return {
|
2269
2756
|
errorMessage: `have "${prefix}" prefix`,
|
2270
2757
|
renameToNames: [prefix + name]
|
2271
2758
|
};
|
2272
|
-
|
2759
|
+
}
|
2760
|
+
if (suffix && !name.endsWith(suffix)) {
|
2273
2761
|
return {
|
2274
2762
|
errorMessage: `have "${suffix}" suffix`,
|
2275
2763
|
renameToNames: [name + suffix]
|
2276
2764
|
};
|
2277
|
-
|
2278
|
-
|
2765
|
+
}
|
2766
|
+
const forbidden = forbiddenPatterns?.find((pattern) => pattern.test(name));
|
2767
|
+
if (forbidden) {
|
2279
2768
|
return {
|
2280
2769
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
2281
2770
|
renameToNames: [name.replace(forbidden, "")]
|
2282
2771
|
};
|
2283
|
-
|
2772
|
+
}
|
2773
|
+
if (requiredPatterns && !requiredPatterns.some((pattern) => pattern.test(name))) {
|
2284
2774
|
return {
|
2285
2775
|
errorMessage: `contain the required pattern: ${englishJoinWords(requiredPatterns.map((re) => re.source))}`,
|
2286
2776
|
renameToNames: []
|
2287
2777
|
};
|
2288
|
-
|
2289
|
-
|
2778
|
+
}
|
2779
|
+
const forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
|
2780
|
+
if (forbiddenPrefix) {
|
2290
2781
|
return {
|
2291
2782
|
errorMessage: `not have "${forbiddenPrefix}" prefix`,
|
2292
2783
|
renameToNames: [name.replace(new RegExp(`^${forbiddenPrefix}`), "")]
|
2293
2784
|
};
|
2294
|
-
|
2295
|
-
|
2785
|
+
}
|
2786
|
+
const forbiddenSuffix = forbiddenSuffixes?.find((suffix2) => name.endsWith(suffix2));
|
2787
|
+
if (forbiddenSuffix) {
|
2296
2788
|
return {
|
2297
2789
|
errorMessage: `not have "${forbiddenSuffix}" suffix`,
|
2298
2790
|
renameToNames: [name.replace(new RegExp(`${forbiddenSuffix}$`), "")]
|
2299
2791
|
};
|
2300
|
-
|
2792
|
+
}
|
2793
|
+
if (requiredPrefixes && !requiredPrefixes.some((requiredPrefix) => name.startsWith(requiredPrefix))) {
|
2301
2794
|
return {
|
2302
2795
|
errorMessage: `have one of the following prefixes: ${englishJoinWords(
|
2303
2796
|
requiredPrefixes
|
2304
2797
|
)}`,
|
2305
2798
|
renameToNames: style ? requiredPrefixes.map((prefix2) => convertCase(style, `${prefix2} ${name}`)) : requiredPrefixes.map((prefix2) => `${prefix2}${name}`)
|
2306
2799
|
};
|
2307
|
-
|
2800
|
+
}
|
2801
|
+
if (requiredSuffixes && !requiredSuffixes.some((requiredSuffix) => name.endsWith(requiredSuffix))) {
|
2308
2802
|
return {
|
2309
2803
|
errorMessage: `have one of the following suffixes: ${englishJoinWords(
|
2310
2804
|
requiredSuffixes
|
2311
2805
|
)}`,
|
2312
2806
|
renameToNames: style ? requiredSuffixes.map((suffix2) => convertCase(style, `${name} ${suffix2}`)) : requiredSuffixes.map((suffix2) => `${name}${suffix2}`)
|
2313
2807
|
};
|
2314
|
-
|
2808
|
+
}
|
2809
|
+
if (!style) {
|
2315
2810
|
return;
|
2316
|
-
|
2811
|
+
}
|
2812
|
+
const caseRegex = StyleToRegex[style];
|
2813
|
+
if (!caseRegex.test(name)) {
|
2317
2814
|
return {
|
2318
2815
|
errorMessage: `be in ${style} format`,
|
2319
2816
|
renameToNames: [convertCase(style, name)]
|
2320
2817
|
};
|
2818
|
+
}
|
2819
|
+
}
|
2820
|
+
};
|
2821
|
+
const checkUnderscore = (isLeading) => (node) => {
|
2822
|
+
if (ignoredNodes.has(node)) {
|
2823
|
+
return;
|
2321
2824
|
}
|
2322
|
-
|
2323
|
-
if (ignoredNodes.has(node) || node.parent.kind === "Field" && node.parent.alias !== node)
|
2825
|
+
if (node.parent.kind === "Field" && node.parent.alias !== node) {
|
2324
2826
|
return;
|
2325
|
-
|
2827
|
+
}
|
2828
|
+
const suggestedName = node.value.replace(isLeading ? /^_+/ : /_+$/, "");
|
2326
2829
|
report(node, `${isLeading ? "Leading" : "Trailing"} underscores are not allowed`, [
|
2327
2830
|
suggestedName
|
2328
2831
|
]);
|
2329
|
-
}
|
2330
|
-
|
2331
|
-
|
2832
|
+
};
|
2833
|
+
const listeners = {};
|
2834
|
+
if (!allowLeadingUnderscore) {
|
2835
|
+
listeners["Name[value=/^_/]"] = checkUnderscore(true);
|
2836
|
+
}
|
2837
|
+
if (!allowTrailingUnderscore) {
|
2838
|
+
listeners["Name[value=/_$/]"] = checkUnderscore(false);
|
2839
|
+
}
|
2840
|
+
const selectors = new Set(
|
2332
2841
|
[types && TYPES_KINDS, Object.keys(restOptions)].filter((v) => !!v).flat()
|
2333
2842
|
);
|
2334
|
-
for (
|
2843
|
+
for (const selector of selectors) {
|
2335
2844
|
listeners[selector] = checkNode2(selector);
|
2845
|
+
}
|
2336
2846
|
return listeners;
|
2337
2847
|
}
|
2338
2848
|
};
|
2339
2849
|
|
2340
2850
|
// src/rules/no-anonymous-operations/index.ts
|
2341
2851
|
import { Kind as Kind9 } from "graphql";
|
2342
|
-
var RULE_ID3 = "no-anonymous-operations"
|
2852
|
+
var RULE_ID3 = "no-anonymous-operations";
|
2853
|
+
var rule7 = {
|
2343
2854
|
meta: {
|
2344
2855
|
type: "suggestion",
|
2345
|
-
hasSuggestions:
|
2856
|
+
hasSuggestions: true,
|
2346
2857
|
docs: {
|
2347
2858
|
category: "Operations",
|
2348
2859
|
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:
|
2860
|
+
recommended: true,
|
2350
2861
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID3}`,
|
2351
2862
|
examples: [
|
2352
2863
|
{
|
@@ -2381,7 +2892,8 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2381
2892
|
create(context) {
|
2382
2893
|
return {
|
2383
2894
|
"OperationDefinition[name=undefined]"(node) {
|
2384
|
-
|
2895
|
+
const [firstSelection] = node.selectionSet.selections;
|
2896
|
+
const suggestedName = firstSelection.kind === Kind9.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
|
2385
2897
|
context.report({
|
2386
2898
|
loc: getLocation(node.loc.start, node.operation),
|
2387
2899
|
messageId: RULE_ID3,
|
@@ -2392,7 +2904,8 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2392
2904
|
{
|
2393
2905
|
desc: `Rename to \`${suggestedName}\``,
|
2394
2906
|
fix(fixer) {
|
2395
|
-
|
2907
|
+
const sourceCode = context.getSourceCode();
|
2908
|
+
const hasQueryKeyword = sourceCode.getText({ range: [node.range[0], node.range[0] + 1] }) !== "{";
|
2396
2909
|
return fixer.insertTextAfterRange(
|
2397
2910
|
[node.range[0], node.range[0] + (hasQueryKeyword ? node.operation.length : 0)],
|
2398
2911
|
`${hasQueryKeyword ? "" : "query"} ${suggestedName}${hasQueryKeyword ? "" : " "}`
|
@@ -2407,15 +2920,16 @@ var RULE_ID3 = "no-anonymous-operations", rule7 = {
|
|
2407
2920
|
};
|
2408
2921
|
|
2409
2922
|
// src/rules/no-deprecated/index.ts
|
2410
|
-
var RULE_ID4 = "no-deprecated"
|
2923
|
+
var RULE_ID4 = "no-deprecated";
|
2924
|
+
var rule8 = {
|
2411
2925
|
meta: {
|
2412
2926
|
type: "suggestion",
|
2413
|
-
hasSuggestions:
|
2927
|
+
hasSuggestions: true,
|
2414
2928
|
docs: {
|
2415
2929
|
category: "Operations",
|
2416
2930
|
description: "Enforce that deprecated fields or enum values are not in use by operations.",
|
2417
2931
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID4}`,
|
2418
|
-
requiresSchema:
|
2932
|
+
requiresSchema: true,
|
2419
2933
|
examples: [
|
2420
2934
|
{
|
2421
2935
|
title: "Incorrect (field)",
|
@@ -2487,7 +3001,7 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2487
3001
|
)
|
2488
3002
|
}
|
2489
3003
|
],
|
2490
|
-
recommended:
|
3004
|
+
recommended: true
|
2491
3005
|
},
|
2492
3006
|
messages: {
|
2493
3007
|
[RULE_ID4]: "{{ type }} is marked as deprecated in your GraphQL schema (reason: {{ reason }})"
|
@@ -2497,7 +3011,7 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2497
3011
|
create(context) {
|
2498
3012
|
requireGraphQLSchema(RULE_ID4, context);
|
2499
3013
|
function report(node, reason) {
|
2500
|
-
|
3014
|
+
const nodeType = displayNodeName(node);
|
2501
3015
|
context.report({
|
2502
3016
|
node,
|
2503
3017
|
messageId: RULE_ID4,
|
@@ -2515,24 +3029,37 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2515
3029
|
}
|
2516
3030
|
return {
|
2517
3031
|
EnumValue(node) {
|
2518
|
-
|
2519
|
-
reason
|
3032
|
+
const typeInfo = node.typeInfo();
|
3033
|
+
const reason = typeInfo.enumValue?.deprecationReason;
|
3034
|
+
if (reason) {
|
3035
|
+
report(node, reason);
|
3036
|
+
}
|
2520
3037
|
},
|
2521
3038
|
Field(node) {
|
2522
|
-
|
2523
|
-
reason
|
3039
|
+
const typeInfo = node.typeInfo();
|
3040
|
+
const reason = typeInfo.fieldDef?.deprecationReason;
|
3041
|
+
if (reason) {
|
3042
|
+
report(node, reason);
|
3043
|
+
}
|
2524
3044
|
},
|
2525
3045
|
Argument(node) {
|
2526
|
-
|
2527
|
-
reason
|
3046
|
+
const typeInfo = node.typeInfo();
|
3047
|
+
const reason = typeInfo.argument?.deprecationReason;
|
3048
|
+
if (reason) {
|
3049
|
+
report(node, reason);
|
3050
|
+
}
|
2528
3051
|
},
|
2529
3052
|
ObjectValue(node) {
|
2530
|
-
|
2531
|
-
if (inputType
|
2532
|
-
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
3053
|
+
const { inputType } = node.typeInfo();
|
3054
|
+
if (!inputType) return;
|
3055
|
+
if ("getFields" in inputType) {
|
3056
|
+
const fields = inputType.getFields();
|
3057
|
+
for (const field of node.fields) {
|
3058
|
+
const fieldName = field.name.value;
|
3059
|
+
const reason = fields[fieldName].deprecationReason;
|
3060
|
+
if (reason) {
|
3061
|
+
report(field, reason);
|
3062
|
+
}
|
2536
3063
|
}
|
2537
3064
|
}
|
2538
3065
|
}
|
@@ -2542,15 +3069,16 @@ var RULE_ID4 = "no-deprecated", rule8 = {
|
|
2542
3069
|
|
2543
3070
|
// src/rules/no-duplicate-fields/index.ts
|
2544
3071
|
import { Kind as Kind10 } from "graphql";
|
2545
|
-
var RULE_ID5 = "no-duplicate-fields"
|
3072
|
+
var RULE_ID5 = "no-duplicate-fields";
|
3073
|
+
var rule9 = {
|
2546
3074
|
meta: {
|
2547
3075
|
type: "suggestion",
|
2548
|
-
hasSuggestions:
|
3076
|
+
hasSuggestions: true,
|
2549
3077
|
docs: {
|
2550
3078
|
description: "Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.",
|
2551
3079
|
category: "Operations",
|
2552
3080
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID5}`,
|
2553
|
-
recommended:
|
3081
|
+
recommended: true,
|
2554
3082
|
examples: [
|
2555
3083
|
{
|
2556
3084
|
title: "Incorrect",
|
@@ -2610,9 +3138,9 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2610
3138
|
},
|
2611
3139
|
create(context) {
|
2612
3140
|
function checkNode2(usedFields, node) {
|
2613
|
-
|
3141
|
+
const fieldName = node.value;
|
2614
3142
|
if (usedFields.has(fieldName)) {
|
2615
|
-
|
3143
|
+
const { parent } = node;
|
2616
3144
|
context.report({
|
2617
3145
|
node,
|
2618
3146
|
messageId: RULE_ID5,
|
@@ -2631,24 +3159,30 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2631
3159
|
}
|
2632
3160
|
]
|
2633
3161
|
});
|
2634
|
-
} else
|
3162
|
+
} else {
|
2635
3163
|
usedFields.add(fieldName);
|
3164
|
+
}
|
2636
3165
|
}
|
2637
3166
|
return {
|
2638
3167
|
OperationDefinition(node) {
|
2639
|
-
|
2640
|
-
for (
|
3168
|
+
const set = /* @__PURE__ */ new Set();
|
3169
|
+
for (const varDef of node.variableDefinitions || []) {
|
2641
3170
|
checkNode2(set, varDef.variable.name);
|
3171
|
+
}
|
2642
3172
|
},
|
2643
3173
|
Field(node) {
|
2644
|
-
|
2645
|
-
for (
|
3174
|
+
const set = /* @__PURE__ */ new Set();
|
3175
|
+
for (const arg of node.arguments || []) {
|
2646
3176
|
checkNode2(set, arg.name);
|
3177
|
+
}
|
2647
3178
|
},
|
2648
3179
|
SelectionSet(node) {
|
2649
|
-
|
2650
|
-
for (
|
2651
|
-
selection.kind === Kind10.FIELD
|
3180
|
+
const set = /* @__PURE__ */ new Set();
|
3181
|
+
for (const selection of node.selections) {
|
3182
|
+
if (selection.kind === Kind10.FIELD) {
|
3183
|
+
checkNode2(set, selection.alias || selection.name);
|
3184
|
+
}
|
3185
|
+
}
|
2652
3186
|
}
|
2653
3187
|
};
|
2654
3188
|
}
|
@@ -2656,10 +3190,11 @@ var RULE_ID5 = "no-duplicate-fields", rule9 = {
|
|
2656
3190
|
|
2657
3191
|
// src/rules/no-hashtag-description/index.ts
|
2658
3192
|
import { TokenKind as TokenKind2 } from "graphql";
|
2659
|
-
var RULE_ID6 = "HASHTAG_COMMENT"
|
3193
|
+
var RULE_ID6 = "HASHTAG_COMMENT";
|
3194
|
+
var rule10 = {
|
2660
3195
|
meta: {
|
2661
3196
|
type: "suggestion",
|
2662
|
-
hasSuggestions:
|
3197
|
+
hasSuggestions: true,
|
2663
3198
|
schema: [],
|
2664
3199
|
messages: {
|
2665
3200
|
[RULE_ID6]: 'Unexpected GraphQL descriptions as hashtag `#` for {{ nodeName }}.\nPrefer using `"""` for multiline, or `"` for a single line description.'
|
@@ -2712,21 +3247,27 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2712
3247
|
)
|
2713
3248
|
}
|
2714
3249
|
],
|
2715
|
-
recommended:
|
3250
|
+
recommended: true
|
2716
3251
|
}
|
2717
3252
|
},
|
2718
3253
|
create(context) {
|
3254
|
+
const selector = "Document[definitions.0.kind!=/^(OperationDefinition|FragmentDefinition)$/]";
|
2719
3255
|
return {
|
2720
|
-
[
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
3256
|
+
[selector](node) {
|
3257
|
+
const rawNode = node.rawNode();
|
3258
|
+
let token = rawNode.loc.startToken;
|
3259
|
+
while (token) {
|
3260
|
+
const { kind, prev, next, value, line, column } = token;
|
2724
3261
|
if (kind === TokenKind2.COMMENT && prev && next) {
|
2725
|
-
|
3262
|
+
const isEslintComment = value.trimStart().startsWith("eslint");
|
3263
|
+
const linesAfter = next.line - line;
|
2726
3264
|
if (!isEslintComment && line !== prev.line && next.kind === TokenKind2.NAME && linesAfter < 2) {
|
2727
|
-
|
3265
|
+
const sourceCode = context.getSourceCode();
|
3266
|
+
const { tokens } = sourceCode.ast;
|
3267
|
+
const t = tokens.find(
|
2728
3268
|
(token2) => token2.loc.start.line === next.line && token2.loc.start.column === next.column - 1
|
2729
|
-
)
|
3269
|
+
);
|
3270
|
+
const nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
|
2730
3271
|
context.report({
|
2731
3272
|
messageId: RULE_ID6,
|
2732
3273
|
data: {
|
@@ -2748,8 +3289,9 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2748
3289
|
});
|
2749
3290
|
}
|
2750
3291
|
}
|
2751
|
-
if (!next)
|
3292
|
+
if (!next) {
|
2752
3293
|
break;
|
3294
|
+
}
|
2753
3295
|
token = next;
|
2754
3296
|
}
|
2755
3297
|
}
|
@@ -2760,7 +3302,8 @@ var RULE_ID6 = "HASHTAG_COMMENT", rule10 = {
|
|
2760
3302
|
// src/rules/no-one-place-fragments/index.ts
|
2761
3303
|
import { relative } from "node:path";
|
2762
3304
|
import { visit as visit4 } from "graphql";
|
2763
|
-
var RULE_ID7 = "no-one-place-fragments"
|
3305
|
+
var RULE_ID7 = "no-one-place-fragments";
|
3306
|
+
var rule11 = {
|
2764
3307
|
meta: {
|
2765
3308
|
type: "suggestion",
|
2766
3309
|
docs: {
|
@@ -2806,7 +3349,7 @@ var RULE_ID7 = "no-one-place-fragments", rule11 = {
|
|
2806
3349
|
)
|
2807
3350
|
}
|
2808
3351
|
],
|
2809
|
-
requiresSiblings:
|
3352
|
+
requiresSiblings: true
|
2810
3353
|
},
|
2811
3354
|
messages: {
|
2812
3355
|
[RULE_ID7]: 'Fragment `{{fragmentName}}` used only once. Inline him in "{{filePath}}".'
|
@@ -2814,24 +3357,30 @@ var RULE_ID7 = "no-one-place-fragments", rule11 = {
|
|
2814
3357
|
schema: []
|
2815
3358
|
},
|
2816
3359
|
create(context) {
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
3360
|
+
const operations = requireGraphQLOperations(RULE_ID7, context);
|
3361
|
+
const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
|
3362
|
+
const usedFragmentsMap = /* @__PURE__ */ Object.create(null);
|
3363
|
+
for (const { document, filePath } of allDocuments) {
|
3364
|
+
const relativeFilePath = relative(CWD, filePath);
|
2820
3365
|
visit4(document, {
|
2821
3366
|
FragmentSpread({ name }) {
|
2822
|
-
|
2823
|
-
usedFragmentsMap[spreadName] ||= []
|
3367
|
+
const spreadName = name.value;
|
3368
|
+
usedFragmentsMap[spreadName] ||= [];
|
3369
|
+
usedFragmentsMap[spreadName].push(relativeFilePath);
|
2824
3370
|
}
|
2825
3371
|
});
|
2826
3372
|
}
|
2827
3373
|
return {
|
2828
3374
|
"FragmentDefinition > Name"(node) {
|
2829
|
-
|
2830
|
-
fragmentUsage
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
3375
|
+
const fragmentName = node.value;
|
3376
|
+
const fragmentUsage = usedFragmentsMap[fragmentName];
|
3377
|
+
if (fragmentUsage.length === 1) {
|
3378
|
+
context.report({
|
3379
|
+
node,
|
3380
|
+
messageId: RULE_ID7,
|
3381
|
+
data: { fragmentName, filePath: fragmentUsage[0] }
|
3382
|
+
});
|
3383
|
+
}
|
2835
3384
|
}
|
2836
3385
|
};
|
2837
3386
|
}
|
@@ -2844,7 +3393,7 @@ var schema7 = {
|
|
2844
3393
|
maxItems: 1,
|
2845
3394
|
items: {
|
2846
3395
|
type: "object",
|
2847
|
-
additionalProperties:
|
3396
|
+
additionalProperties: false,
|
2848
3397
|
required: ["disallow"],
|
2849
3398
|
properties: {
|
2850
3399
|
disallow: {
|
@@ -2855,15 +3404,16 @@ var schema7 = {
|
|
2855
3404
|
}
|
2856
3405
|
}
|
2857
3406
|
}
|
2858
|
-
}
|
3407
|
+
};
|
3408
|
+
var rule12 = {
|
2859
3409
|
meta: {
|
2860
3410
|
type: "suggestion",
|
2861
|
-
hasSuggestions:
|
3411
|
+
hasSuggestions: true,
|
2862
3412
|
docs: {
|
2863
3413
|
category: "Schema",
|
2864
3414
|
description: "Disallow using root types `mutation` and/or `subscription`.",
|
2865
3415
|
url: "https://the-guild.dev/graphql/eslint/rules/no-root-type",
|
2866
|
-
requiresSchema:
|
3416
|
+
requiresSchema: true,
|
2867
3417
|
examples: [
|
2868
3418
|
{
|
2869
3419
|
title: "Incorrect",
|
@@ -2895,13 +3445,19 @@ var schema7 = {
|
|
2895
3445
|
schema: schema7
|
2896
3446
|
},
|
2897
3447
|
create(context) {
|
2898
|
-
|
3448
|
+
const schema16 = requireGraphQLSchema("no-root-type", context);
|
3449
|
+
const disallow = new Set(context.options[0].disallow);
|
3450
|
+
const rootTypeNames = [
|
2899
3451
|
disallow.has("mutation") && schema16.getMutationType(),
|
2900
3452
|
disallow.has("subscription") && schema16.getSubscriptionType()
|
2901
3453
|
].filter((v) => !!v).map((type) => type.name).join("|");
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
3454
|
+
if (!rootTypeNames) {
|
3455
|
+
return {};
|
3456
|
+
}
|
3457
|
+
const selector = `:matches(ObjectTypeDefinition, ObjectTypeExtension) > .name[value=/^(${rootTypeNames})$/]`;
|
3458
|
+
return {
|
3459
|
+
[selector](node) {
|
3460
|
+
const typeName = node.value;
|
2905
3461
|
context.report({
|
2906
3462
|
node,
|
2907
3463
|
message: `Root type \`${typeName}\` is forbidden.`,
|
@@ -2913,21 +3469,22 @@ var schema7 = {
|
|
2913
3469
|
]
|
2914
3470
|
});
|
2915
3471
|
}
|
2916
|
-
}
|
3472
|
+
};
|
2917
3473
|
}
|
2918
3474
|
};
|
2919
3475
|
|
2920
3476
|
// src/rules/no-scalar-result-type-on-mutation/index.ts
|
2921
3477
|
import { isScalarType, Kind as Kind11 } from "graphql";
|
2922
|
-
var RULE_ID8 = "no-scalar-result-type-on-mutation"
|
3478
|
+
var RULE_ID8 = "no-scalar-result-type-on-mutation";
|
3479
|
+
var rule13 = {
|
2923
3480
|
meta: {
|
2924
3481
|
type: "suggestion",
|
2925
|
-
hasSuggestions:
|
3482
|
+
hasSuggestions: true,
|
2926
3483
|
docs: {
|
2927
3484
|
category: "Schema",
|
2928
3485
|
description: "Avoid scalar result type on mutation type to make sure to return a valid state.",
|
2929
3486
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID8}`,
|
2930
|
-
requiresSchema:
|
3487
|
+
requiresSchema: true,
|
2931
3488
|
examples: [
|
2932
3489
|
{
|
2933
3490
|
title: "Incorrect",
|
@@ -2956,17 +3513,24 @@ var RULE_ID8 = "no-scalar-result-type-on-mutation", rule13 = {
|
|
2956
3513
|
schema: []
|
2957
3514
|
},
|
2958
3515
|
create(context) {
|
2959
|
-
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
2963
|
-
|
2964
|
-
|
2965
|
-
|
3516
|
+
const schema16 = requireGraphQLSchema(RULE_ID8, context);
|
3517
|
+
const mutationType = schema16.getMutationType();
|
3518
|
+
if (!mutationType) {
|
3519
|
+
return {};
|
3520
|
+
}
|
3521
|
+
const selector = [
|
3522
|
+
`:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}]`,
|
3523
|
+
"> FieldDefinition > .gqlType Name"
|
3524
|
+
].join(" ");
|
3525
|
+
return {
|
3526
|
+
[selector](node) {
|
3527
|
+
const typeName = node.value;
|
3528
|
+
const graphQLType = schema16.getType(typeName);
|
2966
3529
|
if (isScalarType(graphQLType)) {
|
2967
3530
|
let fieldDef = node.parent;
|
2968
|
-
|
3531
|
+
while (fieldDef.kind !== Kind11.FIELD_DEFINITION) {
|
2969
3532
|
fieldDef = fieldDef.parent;
|
3533
|
+
}
|
2970
3534
|
context.report({
|
2971
3535
|
node,
|
2972
3536
|
message: `Unexpected scalar result type \`${typeName}\` for ${getNodeName(fieldDef)}`,
|
@@ -2979,19 +3543,20 @@ var RULE_ID8 = "no-scalar-result-type-on-mutation", rule13 = {
|
|
2979
3543
|
});
|
2980
3544
|
}
|
2981
3545
|
}
|
2982
|
-
}
|
3546
|
+
};
|
2983
3547
|
}
|
2984
3548
|
};
|
2985
3549
|
|
2986
3550
|
// src/rules/no-typename-prefix/index.ts
|
2987
|
-
var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX"
|
3551
|
+
var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX";
|
3552
|
+
var rule14 = {
|
2988
3553
|
meta: {
|
2989
3554
|
type: "suggestion",
|
2990
|
-
hasSuggestions:
|
3555
|
+
hasSuggestions: true,
|
2991
3556
|
docs: {
|
2992
3557
|
category: "Schema",
|
2993
3558
|
description: "Enforces users to avoid using the type name in a field name while defining your schema.",
|
2994
|
-
recommended:
|
3559
|
+
recommended: true,
|
2995
3560
|
url: "https://the-guild.dev/graphql/eslint/rules/no-typename-prefix",
|
2996
3561
|
examples: [
|
2997
3562
|
{
|
@@ -3026,26 +3591,29 @@ var NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX", rule14 = {
|
|
3026
3591
|
create(context) {
|
3027
3592
|
return {
|
3028
3593
|
"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
|
-
|
3594
|
+
const typeName = node.name.value;
|
3595
|
+
const lowerTypeName = typeName.toLowerCase();
|
3596
|
+
for (const field of node.fields || []) {
|
3597
|
+
const fieldName = field.name.value;
|
3598
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
3599
|
+
context.report({
|
3600
|
+
data: {
|
3601
|
+
fieldName,
|
3602
|
+
typeName
|
3603
|
+
},
|
3604
|
+
messageId: NO_TYPENAME_PREFIX,
|
3605
|
+
node: field.name,
|
3606
|
+
suggest: [
|
3607
|
+
{
|
3608
|
+
desc: `Remove \`${fieldName.slice(0, typeName.length)}\` prefix`,
|
3609
|
+
fix: (fixer) => fixer.replaceText(
|
3610
|
+
field.name,
|
3611
|
+
fieldName.replace(new RegExp(`^${typeName}`, "i"), "")
|
3612
|
+
)
|
3613
|
+
}
|
3614
|
+
]
|
3615
|
+
});
|
3616
|
+
}
|
3049
3617
|
}
|
3050
3618
|
}
|
3051
3619
|
};
|
@@ -3061,7 +3629,8 @@ import {
|
|
3061
3629
|
visit as visit5
|
3062
3630
|
} from "graphql";
|
3063
3631
|
import lowerCase3 from "lodash.lowercase";
|
3064
|
-
var RULE_ID9 = "no-unreachable-types"
|
3632
|
+
var RULE_ID9 = "no-unreachable-types";
|
3633
|
+
var KINDS = [
|
3065
3634
|
Kind12.DIRECTIVE_DEFINITION,
|
3066
3635
|
Kind12.OBJECT_TYPE_DEFINITION,
|
3067
3636
|
Kind12.OBJECT_TYPE_EXTENSION,
|
@@ -3075,7 +3644,9 @@ var RULE_ID9 = "no-unreachable-types", KINDS = [
|
|
3075
3644
|
Kind12.UNION_TYPE_EXTENSION,
|
3076
3645
|
Kind12.ENUM_TYPE_DEFINITION,
|
3077
3646
|
Kind12.ENUM_TYPE_EXTENSION
|
3078
|
-
]
|
3647
|
+
];
|
3648
|
+
var reachableTypesCache = new ModuleCache();
|
3649
|
+
var RequestDirectiveLocations = /* @__PURE__ */ new Set([
|
3079
3650
|
DirectiveLocation.QUERY,
|
3080
3651
|
DirectiveLocation.MUTATION,
|
3081
3652
|
DirectiveLocation.SUBSCRIPTION,
|
@@ -3086,21 +3657,28 @@ var RULE_ID9 = "no-unreachable-types", KINDS = [
|
|
3086
3657
|
DirectiveLocation.VARIABLE_DEFINITION
|
3087
3658
|
]);
|
3088
3659
|
function getReachableTypes(schema16) {
|
3089
|
-
|
3090
|
-
if (cachedValue)
|
3660
|
+
const cachedValue = reachableTypesCache.get(schema16);
|
3661
|
+
if (cachedValue) {
|
3091
3662
|
return cachedValue;
|
3092
|
-
|
3093
|
-
|
3094
|
-
|
3663
|
+
}
|
3664
|
+
const reachableTypes = /* @__PURE__ */ new Set();
|
3665
|
+
const collect = (node) => {
|
3666
|
+
const typeName = getTypeName(node);
|
3667
|
+
if (reachableTypes.has(typeName)) {
|
3095
3668
|
return;
|
3669
|
+
}
|
3096
3670
|
reachableTypes.add(typeName);
|
3097
|
-
|
3671
|
+
const type = schema16.getType(typeName) || schema16.getDirective(typeName);
|
3098
3672
|
if (isInterfaceType(type)) {
|
3099
|
-
|
3100
|
-
for (
|
3673
|
+
const { objects, interfaces } = schema16.getImplementations(type);
|
3674
|
+
for (const { astNode } of [...objects, ...interfaces]) {
|
3101
3675
|
visit5(astNode, visitor);
|
3102
|
-
|
3103
|
-
|
3676
|
+
}
|
3677
|
+
} else if (type?.astNode) {
|
3678
|
+
visit5(type.astNode, visitor);
|
3679
|
+
}
|
3680
|
+
};
|
3681
|
+
const visitor = {
|
3104
3682
|
InterfaceTypeDefinition: collect,
|
3105
3683
|
ObjectTypeDefinition: collect,
|
3106
3684
|
InputValueDefinition: collect,
|
@@ -3109,21 +3687,27 @@ function getReachableTypes(schema16) {
|
|
3109
3687
|
Directive: collect,
|
3110
3688
|
NamedType: collect
|
3111
3689
|
};
|
3112
|
-
for (
|
3690
|
+
for (const type of [
|
3113
3691
|
schema16,
|
3114
3692
|
// visiting SchemaDefinition node
|
3115
3693
|
schema16.getQueryType(),
|
3116
3694
|
schema16.getMutationType(),
|
3117
3695
|
schema16.getSubscriptionType()
|
3118
|
-
])
|
3119
|
-
|
3120
|
-
|
3696
|
+
]) {
|
3697
|
+
if (type?.astNode) {
|
3698
|
+
visit5(type.astNode, visitor);
|
3699
|
+
}
|
3700
|
+
}
|
3701
|
+
for (const node of schema16.getDirectives()) {
|
3121
3702
|
if (node.locations.some((location) => RequestDirectiveLocations.has(location))) {
|
3122
3703
|
reachableTypes.add(node.name);
|
3123
|
-
for (
|
3704
|
+
for (const arg of node.args) {
|
3124
3705
|
reachableTypes.add(getNamedType(arg.type).name);
|
3706
|
+
}
|
3125
3707
|
}
|
3126
|
-
|
3708
|
+
}
|
3709
|
+
reachableTypesCache.set(schema16, reachableTypes);
|
3710
|
+
return reachableTypes;
|
3127
3711
|
}
|
3128
3712
|
var rule15 = {
|
3129
3713
|
meta: {
|
@@ -3134,7 +3718,7 @@ var rule15 = {
|
|
3134
3718
|
description: "Requires all types to be reachable at some level by root level fields.",
|
3135
3719
|
category: "Schema",
|
3136
3720
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID9}`,
|
3137
|
-
requiresSchema:
|
3721
|
+
requiresSchema: true,
|
3138
3722
|
examples: [
|
3139
3723
|
{
|
3140
3724
|
title: "Incorrect",
|
@@ -3169,19 +3753,20 @@ var rule15 = {
|
|
3169
3753
|
)
|
3170
3754
|
}
|
3171
3755
|
],
|
3172
|
-
recommended:
|
3756
|
+
recommended: true
|
3173
3757
|
},
|
3174
3758
|
type: "suggestion",
|
3175
3759
|
schema: [],
|
3176
|
-
hasSuggestions:
|
3760
|
+
hasSuggestions: true
|
3177
3761
|
},
|
3178
3762
|
create(context) {
|
3179
|
-
|
3763
|
+
const schema16 = requireGraphQLSchema(RULE_ID9, context);
|
3764
|
+
const reachableTypes = getReachableTypes(schema16);
|
3180
3765
|
return {
|
3181
3766
|
[`:matches(${KINDS}) > .name`](node) {
|
3182
|
-
|
3767
|
+
const typeName = node.value;
|
3183
3768
|
if (!reachableTypes.has(typeName)) {
|
3184
|
-
|
3769
|
+
const type = lowerCase3(node.parent.kind.replace(/(Extension|Definition)$/, ""));
|
3185
3770
|
context.report({
|
3186
3771
|
node,
|
3187
3772
|
messageId: RULE_ID9,
|
@@ -3204,7 +3789,8 @@ var rule15 = {
|
|
3204
3789
|
|
3205
3790
|
// src/rules/no-unused-fields/index.ts
|
3206
3791
|
import { TypeInfo as TypeInfo2, visit as visit6, visitWithTypeInfo as visitWithTypeInfo2 } from "graphql";
|
3207
|
-
var RULE_ID10 = "no-unused-fields"
|
3792
|
+
var RULE_ID10 = "no-unused-fields";
|
3793
|
+
var RELAY_SCHEMA = (
|
3208
3794
|
/* GraphQL */
|
3209
3795
|
`
|
3210
3796
|
# Root Query Type
|
@@ -3245,7 +3831,8 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3245
3831
|
endCursor: String
|
3246
3832
|
}
|
3247
3833
|
`
|
3248
|
-
)
|
3834
|
+
);
|
3835
|
+
var RELAY_QUERY = (
|
3249
3836
|
/* GraphQL */
|
3250
3837
|
`
|
3251
3838
|
query {
|
@@ -3263,20 +3850,22 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3263
3850
|
}
|
3264
3851
|
}
|
3265
3852
|
`
|
3266
|
-
)
|
3853
|
+
);
|
3854
|
+
var RELAY_DEFAULT_IGNORED_FIELD_SELECTORS = [
|
3267
3855
|
"[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]",
|
3268
3856
|
"[parent.name.value=/Edge$/][name.value=cursor]",
|
3269
3857
|
"[parent.name.value=/Connection$/][name.value=pageInfo]"
|
3270
|
-
]
|
3858
|
+
];
|
3859
|
+
var schema8 = {
|
3271
3860
|
type: "array",
|
3272
3861
|
maxItems: 1,
|
3273
3862
|
items: {
|
3274
3863
|
type: "object",
|
3275
|
-
additionalProperties:
|
3864
|
+
additionalProperties: false,
|
3276
3865
|
properties: {
|
3277
3866
|
ignoredFieldSelectors: {
|
3278
3867
|
type: "array",
|
3279
|
-
uniqueItems:
|
3868
|
+
uniqueItems: true,
|
3280
3869
|
minItems: 1,
|
3281
3870
|
description: [
|
3282
3871
|
"Fields that will be ignored and are allowed to be unused.",
|
@@ -3286,8 +3875,7 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3286
3875
|
JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
|
3287
3876
|
"```",
|
3288
3877
|
eslintSelectorsTip
|
3289
|
-
].join(
|
3290
|
-
`),
|
3878
|
+
].join("\n"),
|
3291
3879
|
items: {
|
3292
3880
|
type: "string",
|
3293
3881
|
pattern: "^\\[(.+)]$"
|
@@ -3295,22 +3883,33 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3295
3883
|
}
|
3296
3884
|
}
|
3297
3885
|
}
|
3298
|
-
}
|
3886
|
+
};
|
3887
|
+
var usedFieldsCache = new ModuleCache();
|
3299
3888
|
function getUsedFields(schema16, operations) {
|
3300
|
-
|
3301
|
-
if (cachedValue)
|
3889
|
+
const cachedValue = usedFieldsCache.get(schema16);
|
3890
|
+
if (cachedValue) {
|
3302
3891
|
return cachedValue;
|
3303
|
-
|
3892
|
+
}
|
3893
|
+
const usedFields = /* @__PURE__ */ Object.create(null);
|
3894
|
+
const typeInfo = new TypeInfo2(schema16);
|
3895
|
+
const visitor = visitWithTypeInfo2(typeInfo, {
|
3304
3896
|
Field(node) {
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3897
|
+
const fieldDef = typeInfo.getFieldDef();
|
3898
|
+
if (!fieldDef) {
|
3899
|
+
return false;
|
3900
|
+
}
|
3901
|
+
const parentTypeName = typeInfo.getParentType().name;
|
3902
|
+
const fieldName = node.name.value;
|
3903
|
+
usedFields[parentTypeName] ??= /* @__PURE__ */ new Set();
|
3904
|
+
usedFields[parentTypeName].add(fieldName);
|
3309
3905
|
}
|
3310
|
-
})
|
3311
|
-
|
3906
|
+
});
|
3907
|
+
const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
|
3908
|
+
for (const { document } of allDocuments) {
|
3312
3909
|
visit6(document, visitor);
|
3313
|
-
|
3910
|
+
}
|
3911
|
+
usedFieldsCache.set(schema16, usedFields);
|
3912
|
+
return usedFields;
|
3314
3913
|
}
|
3315
3914
|
var rule16 = {
|
3316
3915
|
meta: {
|
@@ -3321,10 +3920,10 @@ var rule16 = {
|
|
3321
3920
|
description: "Requires all fields to be used at some level by siblings operations.",
|
3322
3921
|
category: "Schema",
|
3323
3922
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID10}`,
|
3324
|
-
requiresSiblings:
|
3325
|
-
requiresSchema:
|
3923
|
+
requiresSiblings: true,
|
3924
|
+
requiresSchema: true,
|
3326
3925
|
// Requires documents to be set
|
3327
|
-
isDisabledForAllConfig:
|
3926
|
+
isDisabledForAllConfig: true,
|
3328
3927
|
examples: [
|
3329
3928
|
{
|
3330
3929
|
title: "Incorrect",
|
@@ -3391,17 +3990,26 @@ var rule16 = {
|
|
3391
3990
|
},
|
3392
3991
|
type: "suggestion",
|
3393
3992
|
schema: schema8,
|
3394
|
-
hasSuggestions:
|
3993
|
+
hasSuggestions: true
|
3395
3994
|
},
|
3396
3995
|
create(context) {
|
3397
|
-
|
3996
|
+
const schema16 = requireGraphQLSchema(RULE_ID10, context);
|
3997
|
+
const siblingsOperations = requireGraphQLOperations(RULE_ID10, context);
|
3998
|
+
const usedFields = getUsedFields(schema16, siblingsOperations);
|
3999
|
+
const { ignoredFieldSelectors } = context.options[0] || {};
|
4000
|
+
const selector = (ignoredFieldSelectors || []).reduce(
|
4001
|
+
(acc, selector2) => `${acc}:not(${selector2})`,
|
4002
|
+
"FieldDefinition"
|
4003
|
+
);
|
3398
4004
|
return {
|
3399
|
-
[(
|
3400
|
-
|
3401
|
-
|
3402
|
-
|
3403
|
-
|
3404
|
-
|
4005
|
+
[selector](node) {
|
4006
|
+
const fieldName = node.name.value;
|
4007
|
+
const parentTypeName = node.parent.name.value;
|
4008
|
+
const isUsed = usedFields[parentTypeName]?.has(fieldName);
|
4009
|
+
if (isUsed) {
|
4010
|
+
return;
|
4011
|
+
}
|
4012
|
+
context.report({
|
3405
4013
|
node: node.name,
|
3406
4014
|
messageId: RULE_ID10,
|
3407
4015
|
data: { fieldName },
|
@@ -3409,7 +4017,10 @@ var rule16 = {
|
|
3409
4017
|
{
|
3410
4018
|
desc: `Remove \`${fieldName}\` field`,
|
3411
4019
|
fix(fixer) {
|
3412
|
-
|
4020
|
+
const sourceCode = context.getSourceCode();
|
4021
|
+
const tokenBefore = sourceCode.getTokenBefore(node);
|
4022
|
+
const tokenAfter = sourceCode.getTokenAfter(node);
|
4023
|
+
const isEmptyType = tokenBefore.type === "{" && tokenAfter.type === "}";
|
3413
4024
|
return fixer.remove(isEmptyType ? node.parent : node);
|
3414
4025
|
}
|
3415
4026
|
}
|
@@ -3422,22 +4033,25 @@ var rule16 = {
|
|
3422
4033
|
|
3423
4034
|
// src/rules/relay-arguments/index.ts
|
3424
4035
|
import { isScalarType as isScalarType2, Kind as Kind13 } from "graphql";
|
3425
|
-
var RULE_ID11 = "relay-arguments"
|
4036
|
+
var RULE_ID11 = "relay-arguments";
|
4037
|
+
var MISSING_ARGUMENTS = "MISSING_ARGUMENTS";
|
4038
|
+
var schema9 = {
|
3426
4039
|
type: "array",
|
3427
4040
|
maxItems: 1,
|
3428
4041
|
items: {
|
3429
4042
|
type: "object",
|
3430
|
-
additionalProperties:
|
4043
|
+
additionalProperties: false,
|
3431
4044
|
minProperties: 1,
|
3432
4045
|
properties: {
|
3433
4046
|
includeBoth: {
|
3434
4047
|
type: "boolean",
|
3435
|
-
default:
|
4048
|
+
default: true,
|
3436
4049
|
description: "Enforce including both forward and backward pagination arguments"
|
3437
4050
|
}
|
3438
4051
|
}
|
3439
4052
|
}
|
3440
|
-
}
|
4053
|
+
};
|
4054
|
+
var rule17 = {
|
3441
4055
|
meta: {
|
3442
4056
|
type: "problem",
|
3443
4057
|
docs: {
|
@@ -3456,8 +4070,7 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3456
4070
|
"",
|
3457
4071
|
"- `last` takes a non-negative integer",
|
3458
4072
|
"- `before` takes the Cursor type"
|
3459
|
-
].join(
|
3460
|
-
`),
|
4073
|
+
].join("\n"),
|
3461
4074
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID11}`,
|
3462
4075
|
examples: [
|
3463
4076
|
{
|
@@ -3483,7 +4096,7 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3483
4096
|
)
|
3484
4097
|
}
|
3485
4098
|
],
|
3486
|
-
isDisabledForAllConfig:
|
4099
|
+
isDisabledForAllConfig: true
|
3487
4100
|
},
|
3488
4101
|
messages: {
|
3489
4102
|
[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 +4104,19 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3491
4104
|
schema: schema9
|
3492
4105
|
},
|
3493
4106
|
create(context) {
|
3494
|
-
|
4107
|
+
const schema16 = requireGraphQLSchema(RULE_ID11, context);
|
4108
|
+
const { includeBoth = true } = context.options[0] || {};
|
3495
4109
|
return {
|
3496
4110
|
"FieldDefinition > .gqlType Name[value=/Connection$/]"(node) {
|
3497
4111
|
let fieldNode = node.parent;
|
3498
|
-
|
4112
|
+
while (fieldNode.kind !== Kind13.FIELD_DEFINITION) {
|
3499
4113
|
fieldNode = fieldNode.parent;
|
3500
|
-
|
4114
|
+
}
|
4115
|
+
const args = Object.fromEntries(
|
3501
4116
|
fieldNode.arguments?.map((argument) => [argument.name.value, argument]) || []
|
3502
|
-
)
|
4117
|
+
);
|
4118
|
+
const hasForwardPagination = !!(args.first && args.after);
|
4119
|
+
const hasBackwardPagination = !!(args.last && args.before);
|
3503
4120
|
if (!hasForwardPagination && !hasBackwardPagination) {
|
3504
4121
|
context.report({
|
3505
4122
|
node: fieldNode.name,
|
@@ -3508,16 +4125,29 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3508
4125
|
return;
|
3509
4126
|
}
|
3510
4127
|
function checkField(typeName, argumentName) {
|
3511
|
-
|
3512
|
-
|
3513
|
-
|
4128
|
+
const argument = args[argumentName];
|
4129
|
+
const hasArgument = !!argument;
|
4130
|
+
let type = argument;
|
4131
|
+
if (hasArgument && type.gqlType.kind === Kind13.NON_NULL_TYPE) {
|
4132
|
+
type = type.gqlType;
|
4133
|
+
}
|
4134
|
+
const isAllowedNonNullType = hasArgument && type.gqlType.kind === Kind13.NAMED_TYPE && (type.gqlType.name.value === typeName || typeName === "String" && isScalarType2(schema16.getType(type.gqlType.name.value)));
|
4135
|
+
if (!isAllowedNonNullType) {
|
4136
|
+
const returnType = typeName === "String" ? "String or Scalar" : typeName;
|
3514
4137
|
context.report({
|
3515
4138
|
node: (argument || fieldNode).name,
|
3516
4139
|
message: hasArgument ? `Argument \`${argumentName}\` must return ${returnType}.` : `Field \`${fieldNode.name.value}\` must contain an argument \`${argumentName}\`, that return ${returnType}.`
|
3517
4140
|
});
|
3518
4141
|
}
|
3519
4142
|
}
|
3520
|
-
(includeBoth || args.first || args.after)
|
4143
|
+
if (includeBoth || args.first || args.after) {
|
4144
|
+
checkField("Int", "first");
|
4145
|
+
checkField("String", "after");
|
4146
|
+
}
|
4147
|
+
if (includeBoth || args.last || args.before) {
|
4148
|
+
checkField("Int", "last");
|
4149
|
+
checkField("String", "before");
|
4150
|
+
}
|
3521
4151
|
}
|
3522
4152
|
};
|
3523
4153
|
}
|
@@ -3525,7 +4155,13 @@ var RULE_ID11 = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
|
|
3525
4155
|
|
3526
4156
|
// src/rules/relay-connection-types/index.ts
|
3527
4157
|
import { Kind as Kind14 } from "graphql";
|
3528
|
-
var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE"
|
4158
|
+
var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE";
|
4159
|
+
var MUST_CONTAIN_FIELD_EDGES = "MUST_CONTAIN_FIELD_EDGES";
|
4160
|
+
var MUST_CONTAIN_FIELD_PAGE_INFO = "MUST_CONTAIN_FIELD_PAGE_INFO";
|
4161
|
+
var MUST_HAVE_CONNECTION_SUFFIX = "MUST_HAVE_CONNECTION_SUFFIX";
|
4162
|
+
var EDGES_FIELD_MUST_RETURN_LIST_TYPE = "EDGES_FIELD_MUST_RETURN_LIST_TYPE";
|
4163
|
+
var PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE = "PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE";
|
4164
|
+
var NON_OBJECT_TYPES = [
|
3529
4165
|
Kind14.SCALAR_TYPE_DEFINITION,
|
3530
4166
|
Kind14.UNION_TYPE_DEFINITION,
|
3531
4167
|
Kind14.UNION_TYPE_EXTENSION,
|
@@ -3535,7 +4171,11 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3535
4171
|
Kind14.ENUM_TYPE_EXTENSION,
|
3536
4172
|
Kind14.INTERFACE_TYPE_DEFINITION,
|
3537
4173
|
Kind14.INTERFACE_TYPE_EXTENSION
|
3538
|
-
]
|
4174
|
+
];
|
4175
|
+
var notConnectionTypesSelector = `:matches(${NON_OBJECT_TYPES})[name.value=/Connection$/] > .name`;
|
4176
|
+
var hasEdgesField = (node) => node.fields?.some((field) => field.name.value === "edges");
|
4177
|
+
var hasPageInfoField = (node) => node.fields?.some((field) => field.name.value === "pageInfo");
|
4178
|
+
var rule18 = {
|
3539
4179
|
meta: {
|
3540
4180
|
type: "problem",
|
3541
4181
|
docs: {
|
@@ -3547,10 +4187,9 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3547
4187
|
"- Connection type must be an Object type",
|
3548
4188
|
"- Connection type must contain a field `edges` that return a list type that wraps an edge type",
|
3549
4189
|
"- Connection type must contain a field `pageInfo` that return a non-null `PageInfo` Object type"
|
3550
|
-
].join(
|
3551
|
-
`),
|
4190
|
+
].join("\n"),
|
3552
4191
|
url: "https://the-guild.dev/graphql/eslint/rules/relay-connection-types",
|
3553
|
-
isDisabledForAllConfig:
|
4192
|
+
isDisabledForAllConfig: true,
|
3554
4193
|
examples: [
|
3555
4194
|
{
|
3556
4195
|
title: "Incorrect",
|
@@ -3595,16 +4234,29 @@ var MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUS
|
|
3595
4234
|
context.report({ node, messageId: MUST_BE_OBJECT_TYPE });
|
3596
4235
|
},
|
3597
4236
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value!=/Connection$/]"(node) {
|
3598
|
-
hasEdgesField(node) && hasPageInfoField(node)
|
4237
|
+
if (hasEdgesField(node) && hasPageInfoField(node)) {
|
4238
|
+
context.report({ node: node.name, messageId: MUST_HAVE_CONNECTION_SUFFIX });
|
4239
|
+
}
|
3599
4240
|
},
|
3600
4241
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/]"(node) {
|
3601
|
-
hasEdgesField(node)
|
4242
|
+
if (!hasEdgesField(node)) {
|
4243
|
+
context.report({ node: node.name, messageId: MUST_CONTAIN_FIELD_EDGES });
|
4244
|
+
}
|
4245
|
+
if (!hasPageInfoField(node)) {
|
4246
|
+
context.report({ node: node.name, messageId: MUST_CONTAIN_FIELD_PAGE_INFO });
|
4247
|
+
}
|
3602
4248
|
},
|
3603
4249
|
":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
|
4250
|
+
const isListType2 = node.kind === Kind14.LIST_TYPE || node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.LIST_TYPE;
|
4251
|
+
if (!isListType2) {
|
4252
|
+
context.report({ node, messageId: EDGES_FIELD_MUST_RETURN_LIST_TYPE });
|
4253
|
+
}
|
3605
4254
|
},
|
3606
4255
|
":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"
|
4256
|
+
const isNonNullPageInfoType = node.kind === Kind14.NON_NULL_TYPE && node.gqlType.kind === Kind14.NAMED_TYPE && node.gqlType.name.value === "PageInfo";
|
4257
|
+
if (!isNonNullPageInfoType) {
|
4258
|
+
context.report({ node, messageId: PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE });
|
4259
|
+
}
|
3608
4260
|
}
|
3609
4261
|
};
|
3610
4262
|
}
|
@@ -3618,49 +4270,66 @@ import {
|
|
3618
4270
|
visit as visit7
|
3619
4271
|
} from "graphql";
|
3620
4272
|
import { getDocumentNodeFromSchema } from "@graphql-tools/utils";
|
3621
|
-
var RULE_ID12 = "relay-edge-types"
|
4273
|
+
var RULE_ID12 = "relay-edge-types";
|
4274
|
+
var MESSAGE_MUST_BE_OBJECT_TYPE = "MESSAGE_MUST_BE_OBJECT_TYPE";
|
4275
|
+
var MESSAGE_MISSING_EDGE_SUFFIX = "MESSAGE_MISSING_EDGE_SUFFIX";
|
4276
|
+
var MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE = "MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE";
|
4277
|
+
var MESSAGE_SHOULD_IMPLEMENTS_NODE = "MESSAGE_SHOULD_IMPLEMENTS_NODE";
|
4278
|
+
var edgeTypesCache;
|
3622
4279
|
function getEdgeTypes(schema16) {
|
3623
|
-
if (edgeTypesCache)
|
4280
|
+
if (edgeTypesCache) {
|
3624
4281
|
return edgeTypesCache;
|
3625
|
-
|
4282
|
+
}
|
4283
|
+
const edgeTypes = /* @__PURE__ */ new Set();
|
4284
|
+
const visitor = {
|
3626
4285
|
ObjectTypeDefinition(node) {
|
3627
|
-
|
4286
|
+
const typeName = node.name.value;
|
4287
|
+
const hasConnectionSuffix = typeName.endsWith("Connection");
|
4288
|
+
if (!hasConnectionSuffix) {
|
3628
4289
|
return;
|
3629
|
-
|
4290
|
+
}
|
4291
|
+
const edges = node.fields?.find((field) => field.name.value === "edges");
|
3630
4292
|
if (edges) {
|
3631
|
-
|
3632
|
-
|
4293
|
+
const edgesTypeName = getTypeName(edges);
|
4294
|
+
const edgesType = schema16.getType(edgesTypeName);
|
4295
|
+
if (isObjectType2(edgesType)) {
|
4296
|
+
edgeTypes.add(edgesTypeName);
|
4297
|
+
}
|
3633
4298
|
}
|
3634
4299
|
}
|
3635
|
-
}
|
3636
|
-
|
4300
|
+
};
|
4301
|
+
const astNode = getDocumentNodeFromSchema(schema16);
|
4302
|
+
visit7(astNode, visitor);
|
4303
|
+
edgeTypesCache = edgeTypes;
|
4304
|
+
return edgeTypesCache;
|
3637
4305
|
}
|
3638
4306
|
var schema10 = {
|
3639
4307
|
type: "array",
|
3640
4308
|
maxItems: 1,
|
3641
4309
|
items: {
|
3642
4310
|
type: "object",
|
3643
|
-
additionalProperties:
|
4311
|
+
additionalProperties: false,
|
3644
4312
|
minProperties: 1,
|
3645
4313
|
properties: {
|
3646
4314
|
withEdgeSuffix: {
|
3647
4315
|
type: "boolean",
|
3648
|
-
default:
|
4316
|
+
default: true,
|
3649
4317
|
description: 'Edge type name must end in "Edge".'
|
3650
4318
|
},
|
3651
4319
|
shouldImplementNode: {
|
3652
4320
|
type: "boolean",
|
3653
|
-
default:
|
4321
|
+
default: true,
|
3654
4322
|
description: "Edge type's field `node` must implement `Node` interface."
|
3655
4323
|
},
|
3656
4324
|
listTypeCanWrapOnlyEdgeType: {
|
3657
4325
|
type: "boolean",
|
3658
|
-
default:
|
4326
|
+
default: true,
|
3659
4327
|
description: "A list type should only wrap an edge type."
|
3660
4328
|
}
|
3661
4329
|
}
|
3662
4330
|
}
|
3663
|
-
}
|
4331
|
+
};
|
4332
|
+
var rule19 = {
|
3664
4333
|
meta: {
|
3665
4334
|
type: "problem",
|
3666
4335
|
docs: {
|
@@ -3675,11 +4344,10 @@ var schema10 = {
|
|
3675
4344
|
'- Edge type name must end in "Edge" _(optional)_',
|
3676
4345
|
"- Edge type's field `node` must implement `Node` interface _(optional)_",
|
3677
4346
|
"- A list type should only wrap an edge type _(optional)_"
|
3678
|
-
].join(
|
3679
|
-
`),
|
4347
|
+
].join("\n"),
|
3680
4348
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID12}`,
|
3681
|
-
isDisabledForAllConfig:
|
3682
|
-
requiresSchema:
|
4349
|
+
isDisabledForAllConfig: true,
|
4350
|
+
requiresSchema: true,
|
3683
4351
|
examples: [
|
3684
4352
|
{
|
3685
4353
|
title: "Correct",
|
@@ -3704,28 +4372,40 @@ var schema10 = {
|
|
3704
4372
|
schema: schema10
|
3705
4373
|
},
|
3706
4374
|
create(context) {
|
3707
|
-
|
3708
|
-
|
3709
|
-
|
3710
|
-
|
4375
|
+
const schema16 = requireGraphQLSchema(RULE_ID12, context);
|
4376
|
+
const edgeTypes = getEdgeTypes(schema16);
|
4377
|
+
const options = {
|
4378
|
+
withEdgeSuffix: true,
|
4379
|
+
shouldImplementNode: true,
|
4380
|
+
listTypeCanWrapOnlyEdgeType: true,
|
3711
4381
|
...context.options[0]
|
3712
|
-
}
|
3713
|
-
|
3714
|
-
|
4382
|
+
};
|
4383
|
+
const isNamedOrNonNullNamed = (node) => node.kind === Kind15.NAMED_TYPE || node.kind === Kind15.NON_NULL_TYPE && node.gqlType.kind === Kind15.NAMED_TYPE;
|
4384
|
+
const checkNodeField = (node) => {
|
4385
|
+
const nodeField = node.fields?.find((field) => field.name.value === "node");
|
4386
|
+
const message = "return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types.";
|
4387
|
+
if (!nodeField) {
|
3715
4388
|
context.report({
|
3716
4389
|
node: node.name,
|
3717
4390
|
message: `Edge type must contain a field \`node\` that ${message}`
|
3718
4391
|
});
|
3719
|
-
else if (!isNamedOrNonNullNamed(nodeField.gqlType))
|
4392
|
+
} else if (!isNamedOrNonNullNamed(nodeField.gqlType)) {
|
3720
4393
|
context.report({ node: nodeField.name, message: `Field \`node\` must ${message}` });
|
3721
|
-
else if (options.shouldImplementNode) {
|
3722
|
-
|
3723
|
-
|
4394
|
+
} else if (options.shouldImplementNode) {
|
4395
|
+
const nodeReturnTypeName = getTypeName(nodeField.gqlType.rawNode());
|
4396
|
+
const type = schema16.getType(nodeReturnTypeName);
|
4397
|
+
if (!isObjectType2(type)) {
|
3724
4398
|
return;
|
3725
|
-
|
4399
|
+
}
|
4400
|
+
const implementsNode = type.astNode.interfaces?.some((n) => n.name.value === "Node");
|
4401
|
+
if (!implementsNode) {
|
4402
|
+
context.report({ node: node.name, messageId: MESSAGE_SHOULD_IMPLEMENTS_NODE });
|
4403
|
+
}
|
3726
4404
|
}
|
3727
|
-
}
|
3728
|
-
|
4405
|
+
};
|
4406
|
+
const checkCursorField = (node) => {
|
4407
|
+
const cursorField = node.fields?.find((field) => field.name.value === "cursor");
|
4408
|
+
const message = "return either a String, Scalar, or a non-null wrapper wrapper around one of those types.";
|
3729
4409
|
if (!cursorField) {
|
3730
4410
|
context.report({
|
3731
4411
|
node: node.name,
|
@@ -3733,30 +4413,51 @@ var schema10 = {
|
|
3733
4413
|
});
|
3734
4414
|
return;
|
3735
4415
|
}
|
3736
|
-
|
3737
|
-
(!isNamedOrNonNullNamed(cursorField.gqlType) || typeName !== "String" && !isScalarType3(schema16.getType(typeName)))
|
3738
|
-
|
4416
|
+
const typeName = getTypeName(cursorField.rawNode());
|
4417
|
+
if (!isNamedOrNonNullNamed(cursorField.gqlType) || typeName !== "String" && !isScalarType3(schema16.getType(typeName))) {
|
4418
|
+
context.report({ node: cursorField.name, message: `Field \`cursor\` must ${message}` });
|
4419
|
+
}
|
4420
|
+
};
|
4421
|
+
const listeners = {
|
3739
4422
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=edges] > .gqlType Name"(node) {
|
3740
|
-
|
3741
|
-
isObjectType2(type)
|
4423
|
+
const type = schema16.getType(node.value);
|
4424
|
+
if (!isObjectType2(type)) {
|
4425
|
+
context.report({ node, messageId: MESSAGE_MUST_BE_OBJECT_TYPE });
|
4426
|
+
}
|
3742
4427
|
},
|
3743
4428
|
":matches(ObjectTypeDefinition, ObjectTypeExtension)"(node) {
|
3744
|
-
|
3745
|
-
edgeTypes.has(typeName)
|
4429
|
+
const typeName = node.name.value;
|
4430
|
+
if (edgeTypes.has(typeName)) {
|
4431
|
+
checkNodeField(node);
|
4432
|
+
checkCursorField(node);
|
4433
|
+
if (options.withEdgeSuffix && !typeName.endsWith("Edge")) {
|
4434
|
+
context.report({ node: node.name, messageId: MESSAGE_MISSING_EDGE_SUFFIX });
|
4435
|
+
}
|
4436
|
+
}
|
3746
4437
|
}
|
3747
4438
|
};
|
3748
|
-
|
3749
|
-
|
3750
|
-
|
3751
|
-
|
3752
|
-
|
3753
|
-
|
4439
|
+
if (options.listTypeCanWrapOnlyEdgeType) {
|
4440
|
+
listeners["FieldDefinition > .gqlType"] = (node) => {
|
4441
|
+
if (node.kind === Kind15.LIST_TYPE || node.kind === Kind15.NON_NULL_TYPE && node.gqlType.kind === Kind15.LIST_TYPE) {
|
4442
|
+
const typeName = getTypeName(node.rawNode());
|
4443
|
+
if (!edgeTypes.has(typeName)) {
|
4444
|
+
context.report({ node, messageId: MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE });
|
4445
|
+
}
|
4446
|
+
}
|
4447
|
+
};
|
4448
|
+
}
|
4449
|
+
return listeners;
|
3754
4450
|
}
|
3755
4451
|
};
|
3756
4452
|
|
3757
4453
|
// src/rules/relay-page-info/index.ts
|
3758
4454
|
import { isScalarType as isScalarType4, Kind as Kind16 } from "graphql";
|
3759
|
-
var RULE_ID13 = "relay-page-info"
|
4455
|
+
var RULE_ID13 = "relay-page-info";
|
4456
|
+
var MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST";
|
4457
|
+
var MESSAGE_MUST_BE_OBJECT_TYPE2 = "MESSAGE_MUST_BE_OBJECT_TYPE";
|
4458
|
+
var notPageInfoTypesSelector = `:matches(${NON_OBJECT_TYPES})[name.value=PageInfo] > .name`;
|
4459
|
+
var hasPageInfoChecked = false;
|
4460
|
+
var rule20 = {
|
3760
4461
|
meta: {
|
3761
4462
|
type: "problem",
|
3762
4463
|
docs: {
|
@@ -3767,8 +4468,7 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3767
4468
|
"- `PageInfo` must be an Object type",
|
3768
4469
|
"- `PageInfo` must contain fields `hasPreviousPage` and `hasNextPage`, that return non-null Boolean",
|
3769
4470
|
"- `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
|
-
`),
|
4471
|
+
].join("\n"),
|
3772
4472
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID13}`,
|
3773
4473
|
examples: [
|
3774
4474
|
{
|
@@ -3786,8 +4486,8 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3786
4486
|
)
|
3787
4487
|
}
|
3788
4488
|
],
|
3789
|
-
isDisabledForAllConfig:
|
3790
|
-
requiresSchema:
|
4489
|
+
isDisabledForAllConfig: true,
|
4490
|
+
requiresSchema: true
|
3791
4491
|
},
|
3792
4492
|
messages: {
|
3793
4493
|
[MESSAGE_MUST_EXIST]: "The server must provide a `PageInfo` object.",
|
@@ -3796,54 +4496,76 @@ var RULE_ID13 = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", ME
|
|
3796
4496
|
schema: []
|
3797
4497
|
},
|
3798
4498
|
create(context) {
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
4499
|
+
const schema16 = requireGraphQLSchema(RULE_ID13, context);
|
4500
|
+
if (!hasPageInfoChecked) {
|
4501
|
+
const pageInfoType = schema16.getType("PageInfo");
|
4502
|
+
if (!pageInfoType) {
|
4503
|
+
context.report({
|
4504
|
+
loc: REPORT_ON_FIRST_CHARACTER,
|
4505
|
+
messageId: MESSAGE_MUST_EXIST
|
4506
|
+
});
|
4507
|
+
}
|
4508
|
+
hasPageInfoChecked = true;
|
4509
|
+
}
|
4510
|
+
return {
|
3804
4511
|
[notPageInfoTypesSelector](node) {
|
3805
4512
|
context.report({ node, messageId: MESSAGE_MUST_BE_OBJECT_TYPE2 });
|
3806
4513
|
},
|
3807
4514
|
"ObjectTypeDefinition[name.value=PageInfo]"(node) {
|
3808
|
-
|
4515
|
+
const fieldMap = Object.fromEntries(
|
3809
4516
|
node.fields?.map((field) => [field.name.value, field]) || []
|
3810
|
-
)
|
3811
|
-
|
4517
|
+
);
|
4518
|
+
const checkField = (fieldName, typeName) => {
|
4519
|
+
const field = fieldMap[fieldName];
|
4520
|
+
let isAllowedType = false;
|
3812
4521
|
if (field) {
|
3813
|
-
|
3814
|
-
typeName === "Boolean"
|
4522
|
+
const type = field.gqlType;
|
4523
|
+
if (typeName === "Boolean") {
|
4524
|
+
isAllowedType = type.kind === Kind16.NON_NULL_TYPE && type.gqlType.kind === Kind16.NAMED_TYPE && type.gqlType.name.value === "Boolean";
|
4525
|
+
} else if (type.kind === Kind16.NAMED_TYPE) {
|
4526
|
+
isAllowedType = type.name.value === "String" || isScalarType4(schema16.getType(type.name.value));
|
4527
|
+
}
|
3815
4528
|
}
|
3816
4529
|
if (!isAllowedType) {
|
3817
|
-
|
4530
|
+
const returnType = typeName === "Boolean" ? "non-null Boolean" : "either String or Scalar, which can be null if there are no results";
|
3818
4531
|
context.report({
|
3819
4532
|
node: field ? field.name : node.name,
|
3820
4533
|
message: field ? `Field \`${fieldName}\` must return ${returnType}.` : `\`PageInfo\` must contain a field \`${fieldName}\`, that return ${returnType}.`
|
3821
4534
|
});
|
3822
4535
|
}
|
3823
4536
|
};
|
3824
|
-
checkField("hasPreviousPage", "Boolean")
|
4537
|
+
checkField("hasPreviousPage", "Boolean");
|
4538
|
+
checkField("hasNextPage", "Boolean");
|
4539
|
+
checkField("startCursor", "String");
|
4540
|
+
checkField("endCursor", "String");
|
3825
4541
|
}
|
3826
4542
|
};
|
3827
4543
|
}
|
3828
4544
|
};
|
3829
4545
|
|
3830
4546
|
// src/rules/require-deprecation-date/index.ts
|
3831
|
-
var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}
|
4547
|
+
var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
|
4548
|
+
var MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIRE_DATE";
|
4549
|
+
var MESSAGE_INVALID_FORMAT = "MESSAGE_INVALID_FORMAT";
|
4550
|
+
var MESSAGE_INVALID_DATE = "MESSAGE_INVALID_DATE";
|
4551
|
+
var MESSAGE_CAN_BE_REMOVED = "MESSAGE_CAN_BE_REMOVED";
|
4552
|
+
var schema11 = {
|
3832
4553
|
type: "array",
|
3833
4554
|
maxItems: 1,
|
3834
4555
|
items: {
|
3835
4556
|
type: "object",
|
3836
|
-
additionalProperties:
|
4557
|
+
additionalProperties: false,
|
3837
4558
|
properties: {
|
3838
4559
|
argumentName: {
|
3839
4560
|
type: "string"
|
3840
4561
|
}
|
3841
4562
|
}
|
3842
4563
|
}
|
3843
|
-
}
|
4564
|
+
};
|
4565
|
+
var rule21 = {
|
3844
4566
|
meta: {
|
3845
4567
|
type: "suggestion",
|
3846
|
-
hasSuggestions:
|
4568
|
+
hasSuggestions: true,
|
3847
4569
|
docs: {
|
3848
4570
|
category: "Schema",
|
3849
4571
|
description: "Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.",
|
@@ -3899,7 +4621,8 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3899
4621
|
create(context) {
|
3900
4622
|
return {
|
3901
4623
|
"Directive[name.value=deprecated]"(node) {
|
3902
|
-
|
4624
|
+
const argName = context.options[0]?.argumentName || "deletionDate";
|
4625
|
+
const deletionDateNode = node.arguments?.find((arg) => arg.name.value === argName);
|
3903
4626
|
if (!deletionDateNode) {
|
3904
4627
|
context.report({
|
3905
4628
|
node: node.name,
|
@@ -3910,8 +4633,9 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3910
4633
|
});
|
3911
4634
|
return;
|
3912
4635
|
}
|
3913
|
-
|
3914
|
-
|
4636
|
+
const deletionDate = valueFromNode(deletionDateNode.value);
|
4637
|
+
const isValidDate = DATE_REGEX.test(deletionDate);
|
4638
|
+
if (!isValidDate) {
|
3915
4639
|
context.report({
|
3916
4640
|
node: deletionDateNode.value,
|
3917
4641
|
messageId: MESSAGE_INVALID_FORMAT,
|
@@ -3920,8 +4644,9 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3920
4644
|
return;
|
3921
4645
|
}
|
3922
4646
|
let [day, month, year] = deletionDate.split("/");
|
3923
|
-
day = day.padStart(2, "0")
|
3924
|
-
|
4647
|
+
day = day.padStart(2, "0");
|
4648
|
+
month = month.padStart(2, "0");
|
4649
|
+
const deletionDateInMS = Date.parse(`${year}-${month}-${day}`);
|
3925
4650
|
if (Number.isNaN(deletionDateInMS)) {
|
3926
4651
|
context.report({
|
3927
4652
|
node: deletionDateNode.value,
|
@@ -3933,8 +4658,10 @@ var DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIR
|
|
3933
4658
|
});
|
3934
4659
|
return;
|
3935
4660
|
}
|
3936
|
-
|
3937
|
-
|
4661
|
+
const canRemove = Date.now() > deletionDateInMS;
|
4662
|
+
if (canRemove) {
|
4663
|
+
const { parent } = node;
|
4664
|
+
const nodeName = parent.name.value;
|
3938
4665
|
context.report({
|
3939
4666
|
node: parent.name,
|
3940
4667
|
messageId: MESSAGE_CAN_BE_REMOVED,
|
@@ -3959,7 +4686,7 @@ var rule22 = {
|
|
3959
4686
|
description: "Require all deprecation directives to specify a reason.",
|
3960
4687
|
category: "Schema",
|
3961
4688
|
url: "https://the-guild.dev/graphql/eslint/rules/require-deprecation-reason",
|
3962
|
-
recommended:
|
4689
|
+
recommended: true,
|
3963
4690
|
examples: [
|
3964
4691
|
{
|
3965
4692
|
title: "Incorrect",
|
@@ -4002,13 +4729,16 @@ var rule22 = {
|
|
4002
4729
|
create(context) {
|
4003
4730
|
return {
|
4004
4731
|
"Directive[name.value=deprecated]"(node) {
|
4005
|
-
|
4732
|
+
const reasonArgument = node.arguments?.find(
|
4006
4733
|
(arg) => arg.name.value === "reason"
|
4007
4734
|
);
|
4008
|
-
reasonArgument && String(valueFromNode(reasonArgument.value)).trim()
|
4009
|
-
|
4010
|
-
|
4011
|
-
|
4735
|
+
const value = reasonArgument && String(valueFromNode(reasonArgument.value)).trim();
|
4736
|
+
if (!value) {
|
4737
|
+
context.report({
|
4738
|
+
node: node.name,
|
4739
|
+
message: `Deprecation reason is required for ${getNodeName(node.parent)}.`
|
4740
|
+
});
|
4741
|
+
}
|
4012
4742
|
}
|
4013
4743
|
};
|
4014
4744
|
}
|
@@ -4017,57 +4747,60 @@ var rule22 = {
|
|
4017
4747
|
// src/rules/require-description/index.ts
|
4018
4748
|
import { Kind as Kind17, TokenKind as TokenKind3 } from "graphql";
|
4019
4749
|
import { getRootTypeNames } from "@graphql-tools/utils";
|
4020
|
-
var RULE_ID14 = "require-description"
|
4750
|
+
var RULE_ID14 = "require-description";
|
4751
|
+
var ALLOWED_KINDS2 = [
|
4021
4752
|
...TYPES_KINDS,
|
4022
4753
|
Kind17.DIRECTIVE_DEFINITION,
|
4023
4754
|
Kind17.FIELD_DEFINITION,
|
4024
4755
|
Kind17.INPUT_VALUE_DEFINITION,
|
4025
4756
|
Kind17.ENUM_VALUE_DEFINITION,
|
4026
4757
|
Kind17.OPERATION_DEFINITION
|
4027
|
-
]
|
4758
|
+
];
|
4759
|
+
var schema12 = {
|
4028
4760
|
type: "array",
|
4029
4761
|
minItems: 1,
|
4030
4762
|
maxItems: 1,
|
4031
4763
|
items: {
|
4032
4764
|
type: "object",
|
4033
|
-
additionalProperties:
|
4765
|
+
additionalProperties: false,
|
4034
4766
|
minProperties: 1,
|
4035
4767
|
properties: {
|
4036
4768
|
types: {
|
4037
4769
|
type: "boolean",
|
4038
|
-
enum: [
|
4770
|
+
enum: [true],
|
4039
4771
|
description: `Includes:
|
4040
|
-
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
4041
|
-
`)}`
|
4772
|
+
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
|
4042
4773
|
},
|
4043
4774
|
rootField: {
|
4044
4775
|
type: "boolean",
|
4045
|
-
enum: [
|
4776
|
+
enum: [true],
|
4046
4777
|
description: "Definitions within `Query`, `Mutation`, and `Subscription` root types."
|
4047
4778
|
},
|
4048
4779
|
ignoredSelectors: {
|
4049
4780
|
...ARRAY_DEFAULT_OPTIONS,
|
4050
|
-
description: ["Ignore specific selectors", eslintSelectorsTip].join(
|
4051
|
-
`)
|
4781
|
+
description: ["Ignore specific selectors", eslintSelectorsTip].join("\n")
|
4052
4782
|
},
|
4053
4783
|
...Object.fromEntries(
|
4054
4784
|
[...ALLOWED_KINDS2].sort().map((kind) => {
|
4055
4785
|
let description = `> [!NOTE]
|
4056
4786
|
>
|
4057
4787
|
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
4058
|
-
|
4059
|
-
|
4060
|
-
|
4061
|
-
|
4062
|
-
|
4063
|
-
|
4064
|
-
|
4065
|
-
|
4788
|
+
if (kind === Kind17.OPERATION_DEFINITION) {
|
4789
|
+
description += [
|
4790
|
+
"",
|
4791
|
+
"",
|
4792
|
+
"> [!WARNING]",
|
4793
|
+
">",
|
4794
|
+
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
4795
|
+
].join("\n");
|
4796
|
+
}
|
4797
|
+
return [kind, { type: "boolean", description }];
|
4066
4798
|
})
|
4067
4799
|
)
|
4068
4800
|
}
|
4069
4801
|
}
|
4070
|
-
}
|
4802
|
+
};
|
4803
|
+
var rule23 = {
|
4071
4804
|
meta: {
|
4072
4805
|
docs: {
|
4073
4806
|
category: "Schema",
|
@@ -4076,7 +4809,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4076
4809
|
examples: [
|
4077
4810
|
{
|
4078
4811
|
title: "Incorrect",
|
4079
|
-
usage: [{ types:
|
4812
|
+
usage: [{ types: true, FieldDefinition: true }],
|
4080
4813
|
code: (
|
4081
4814
|
/* GraphQL */
|
4082
4815
|
`
|
@@ -4088,7 +4821,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4088
4821
|
},
|
4089
4822
|
{
|
4090
4823
|
title: "Correct",
|
4091
|
-
usage: [{ types:
|
4824
|
+
usage: [{ types: true, FieldDefinition: true }],
|
4092
4825
|
code: (
|
4093
4826
|
/* GraphQL */
|
4094
4827
|
`
|
@@ -4106,7 +4839,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4106
4839
|
},
|
4107
4840
|
{
|
4108
4841
|
title: "Correct",
|
4109
|
-
usage: [{ OperationDefinition:
|
4842
|
+
usage: [{ OperationDefinition: true }],
|
4110
4843
|
code: (
|
4111
4844
|
/* GraphQL */
|
4112
4845
|
`
|
@@ -4119,7 +4852,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4119
4852
|
},
|
4120
4853
|
{
|
4121
4854
|
title: "Correct",
|
4122
|
-
usage: [{ rootField:
|
4855
|
+
usage: [{ rootField: true }],
|
4123
4856
|
code: (
|
4124
4857
|
/* GraphQL */
|
4125
4858
|
`
|
@@ -4167,12 +4900,12 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4167
4900
|
],
|
4168
4901
|
configOptions: [
|
4169
4902
|
{
|
4170
|
-
types:
|
4171
|
-
[Kind17.DIRECTIVE_DEFINITION]:
|
4172
|
-
rootField:
|
4903
|
+
types: true,
|
4904
|
+
[Kind17.DIRECTIVE_DEFINITION]: true,
|
4905
|
+
rootField: true
|
4173
4906
|
}
|
4174
4907
|
],
|
4175
|
-
recommended:
|
4908
|
+
recommended: true
|
4176
4909
|
},
|
4177
4910
|
type: "suggestion",
|
4178
4911
|
messages: {
|
@@ -4181,11 +4914,18 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4181
4914
|
schema: schema12
|
4182
4915
|
},
|
4183
4916
|
create(context) {
|
4184
|
-
|
4185
|
-
|
4186
|
-
|
4917
|
+
const { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {};
|
4918
|
+
const kinds = new Set(types ? TYPES_KINDS : []);
|
4919
|
+
for (const [kind, isEnabled] of Object.entries(restOptions)) {
|
4920
|
+
if (isEnabled) {
|
4921
|
+
kinds.add(kind);
|
4922
|
+
} else {
|
4923
|
+
kinds.delete(kind);
|
4924
|
+
}
|
4925
|
+
}
|
4187
4926
|
if (rootField) {
|
4188
|
-
|
4927
|
+
const schema16 = requireGraphQLSchema(RULE_ID14, context);
|
4928
|
+
const rootTypeNames = getRootTypeNames(schema16);
|
4189
4929
|
kinds.add(
|
4190
4930
|
`:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/^(${[
|
4191
4931
|
...rootTypeNames
|
@@ -4193,26 +4933,35 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4193
4933
|
);
|
4194
4934
|
}
|
4195
4935
|
let selector = `:matches(${[...kinds]})`;
|
4196
|
-
for (
|
4936
|
+
for (const str of ignoredSelectors) {
|
4197
4937
|
selector += `:not(${str})`;
|
4938
|
+
}
|
4198
4939
|
return {
|
4199
4940
|
[selector](node) {
|
4200
|
-
let description = ""
|
4941
|
+
let description = "";
|
4942
|
+
const isOperation = node.kind === Kind17.OPERATION_DEFINITION;
|
4201
4943
|
if (isOperation) {
|
4202
|
-
|
4944
|
+
const rawNode = node.rawNode();
|
4945
|
+
const { prev, line } = rawNode.loc.startToken;
|
4203
4946
|
if (prev?.kind === TokenKind3.COMMENT) {
|
4204
|
-
|
4205
|
-
|
4947
|
+
const value = prev.value.trim();
|
4948
|
+
const linesBefore = line - prev.line;
|
4949
|
+
if (!value.startsWith("eslint") && linesBefore === 1) {
|
4950
|
+
description = value;
|
4951
|
+
}
|
4206
4952
|
}
|
4207
|
-
} else
|
4953
|
+
} else {
|
4208
4954
|
description = node.description?.value.trim() || "";
|
4209
|
-
|
4210
|
-
|
4211
|
-
|
4212
|
-
|
4213
|
-
|
4214
|
-
|
4215
|
-
|
4955
|
+
}
|
4956
|
+
if (description.length === 0) {
|
4957
|
+
context.report({
|
4958
|
+
loc: isOperation ? getLocation(node.loc.start, node.operation) : node.name.loc,
|
4959
|
+
messageId: RULE_ID14,
|
4960
|
+
data: {
|
4961
|
+
nodeName: getNodeName(node)
|
4962
|
+
}
|
4963
|
+
});
|
4964
|
+
}
|
4216
4965
|
}
|
4217
4966
|
};
|
4218
4967
|
}
|
@@ -4220,14 +4969,15 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4220
4969
|
|
4221
4970
|
// src/rules/require-field-of-type-query-in-mutation-result/index.ts
|
4222
4971
|
import { isObjectType as isObjectType3 } from "graphql";
|
4223
|
-
var RULE_ID15 = "require-field-of-type-query-in-mutation-result"
|
4972
|
+
var RULE_ID15 = "require-field-of-type-query-in-mutation-result";
|
4973
|
+
var rule24 = {
|
4224
4974
|
meta: {
|
4225
4975
|
type: "suggestion",
|
4226
4976
|
docs: {
|
4227
4977
|
category: "Schema",
|
4228
4978
|
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
4979
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID15}`,
|
4230
|
-
requiresSchema:
|
4980
|
+
requiresSchema: true,
|
4231
4981
|
examples: [
|
4232
4982
|
{
|
4233
4983
|
title: "Incorrect",
|
@@ -4267,16 +5017,26 @@ var RULE_ID15 = "require-field-of-type-query-in-mutation-result", rule24 = {
|
|
4267
5017
|
schema: []
|
4268
5018
|
},
|
4269
5019
|
create(context) {
|
4270
|
-
|
4271
|
-
|
4272
|
-
|
4273
|
-
|
5020
|
+
const schema16 = requireGraphQLSchema(RULE_ID15, context);
|
5021
|
+
const mutationType = schema16.getMutationType();
|
5022
|
+
const queryType = schema16.getQueryType();
|
5023
|
+
if (!mutationType || !queryType) {
|
5024
|
+
return {};
|
5025
|
+
}
|
5026
|
+
const selector = `:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}] > FieldDefinition > .gqlType Name`;
|
5027
|
+
return {
|
5028
|
+
[selector](node) {
|
5029
|
+
const typeName = node.value;
|
5030
|
+
const graphQLType = schema16.getType(typeName);
|
4274
5031
|
if (isObjectType3(graphQLType)) {
|
4275
|
-
|
4276
|
-
fields?.some((field) => getTypeName(field) === queryType.name)
|
4277
|
-
|
4278
|
-
|
4279
|
-
|
5032
|
+
const { fields } = graphQLType.astNode;
|
5033
|
+
const hasQueryType = fields?.some((field) => getTypeName(field) === queryType.name);
|
5034
|
+
if (!hasQueryType) {
|
5035
|
+
context.report({
|
5036
|
+
node,
|
5037
|
+
message: `Mutation result type "${graphQLType.name}" must contain field of type "${queryType.name}"`
|
5038
|
+
});
|
5039
|
+
}
|
4280
5040
|
}
|
4281
5041
|
}
|
4282
5042
|
};
|
@@ -4285,7 +5045,9 @@ var RULE_ID15 = "require-field-of-type-query-in-mutation-result", rule24 = {
|
|
4285
5045
|
|
4286
5046
|
// src/rules/require-import-fragment/index.ts
|
4287
5047
|
import path from "node:path";
|
4288
|
-
var RULE_ID16 = "require-import-fragment"
|
5048
|
+
var RULE_ID16 = "require-import-fragment";
|
5049
|
+
var SUGGESTION_ID = "add-import-expression";
|
5050
|
+
var rule25 = {
|
4289
5051
|
meta: {
|
4290
5052
|
type: "suggestion",
|
4291
5053
|
docs: {
|
@@ -4349,9 +5111,9 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4349
5111
|
)
|
4350
5112
|
}
|
4351
5113
|
],
|
4352
|
-
requiresSiblings:
|
5114
|
+
requiresSiblings: true
|
4353
5115
|
},
|
4354
|
-
hasSuggestions:
|
5116
|
+
hasSuggestions: true,
|
4355
5117
|
messages: {
|
4356
5118
|
[RULE_ID16]: 'Expected "{{fragmentName}}" fragment to be imported.',
|
4357
5119
|
[SUGGESTION_ID]: 'Add import expression for "{{fragmentName}}".'
|
@@ -4359,25 +5121,32 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4359
5121
|
schema: []
|
4360
5122
|
},
|
4361
5123
|
create(context) {
|
4362
|
-
|
5124
|
+
const comments = context.getSourceCode().getAllComments();
|
5125
|
+
const siblings = requireGraphQLOperations(RULE_ID16, context);
|
5126
|
+
const filePath = context.filename;
|
4363
5127
|
return {
|
4364
5128
|
"FragmentSpread > .name"(node) {
|
4365
|
-
|
4366
|
-
|
4367
|
-
|
5129
|
+
const fragmentName = node.value;
|
5130
|
+
const fragmentsFromSiblings = siblings.getFragment(fragmentName);
|
5131
|
+
for (const comment of comments) {
|
5132
|
+
if (comment.type !== "Line") continue;
|
5133
|
+
const isPossibleImported = new RegExp(
|
4368
5134
|
`^\\s*import\\s+(${fragmentName}\\s+from\\s+)?['"]`
|
4369
|
-
).test(comment.value)
|
4370
|
-
|
5135
|
+
).test(comment.value);
|
5136
|
+
if (!isPossibleImported) continue;
|
5137
|
+
const extractedImportPath = comment.value.match(/(["'])((?:\1|.)*?)\1/)?.[2];
|
4371
5138
|
if (!extractedImportPath) continue;
|
4372
|
-
|
4373
|
-
|
5139
|
+
const importPath = path.join(filePath, "..", extractedImportPath);
|
5140
|
+
const hasInSiblings = fragmentsFromSiblings.some(
|
4374
5141
|
(source) => source.filePath === importPath
|
4375
|
-
)
|
5142
|
+
);
|
5143
|
+
if (hasInSiblings) return;
|
4376
5144
|
}
|
4377
|
-
|
5145
|
+
const fragmentInSameFile = fragmentsFromSiblings.some(
|
4378
5146
|
(source) => source.filePath === filePath
|
4379
|
-
)
|
4380
|
-
|
5147
|
+
);
|
5148
|
+
if (fragmentInSameFile) return;
|
5149
|
+
const suggestedFilePaths = fragmentsFromSiblings.length ? fragmentsFromSiblings.map(
|
4381
5150
|
(o) => (
|
4382
5151
|
// Use always forward slash for suggested import path
|
4383
5152
|
slash(path.relative(path.dirname(filePath), o.filePath))
|
@@ -4404,7 +5173,8 @@ var RULE_ID16 = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
|
|
4404
5173
|
|
4405
5174
|
// src/rules/require-nullable-fields-with-oneof/index.ts
|
4406
5175
|
import { Kind as Kind18 } from "graphql";
|
4407
|
-
var RULE_ID17 = "require-nullable-fields-with-oneof"
|
5176
|
+
var RULE_ID17 = "require-nullable-fields-with-oneof";
|
5177
|
+
var rule26 = {
|
4408
5178
|
meta: {
|
4409
5179
|
type: "suggestion",
|
4410
5180
|
docs: {
|
@@ -4446,16 +5216,22 @@ var RULE_ID17 = "require-nullable-fields-with-oneof", rule26 = {
|
|
4446
5216
|
create(context) {
|
4447
5217
|
return {
|
4448
5218
|
"Directive[name.value=oneOf]"({ parent }) {
|
4449
|
-
|
5219
|
+
const isTypeOrInput = [
|
4450
5220
|
Kind18.OBJECT_TYPE_DEFINITION,
|
4451
5221
|
Kind18.INPUT_OBJECT_TYPE_DEFINITION
|
4452
|
-
].includes(parent.kind)
|
4453
|
-
|
4454
|
-
|
5222
|
+
].includes(parent.kind);
|
5223
|
+
if (!isTypeOrInput) {
|
5224
|
+
return;
|
5225
|
+
}
|
5226
|
+
for (const field of parent.fields || []) {
|
5227
|
+
if (field.gqlType.kind === Kind18.NON_NULL_TYPE) {
|
5228
|
+
context.report({
|
4455
5229
|
node: field.name,
|
4456
5230
|
messageId: RULE_ID17,
|
4457
5231
|
data: { nodeName: getNodeName(field) }
|
4458
5232
|
});
|
5233
|
+
}
|
5234
|
+
}
|
4459
5235
|
}
|
4460
5236
|
};
|
4461
5237
|
}
|
@@ -4463,15 +5239,16 @@ var RULE_ID17 = "require-nullable-fields-with-oneof", rule26 = {
|
|
4463
5239
|
|
4464
5240
|
// src/rules/require-nullable-result-in-root/index.ts
|
4465
5241
|
import { Kind as Kind19 } from "graphql";
|
4466
|
-
var RULE_ID18 = "require-nullable-result-in-root"
|
5242
|
+
var RULE_ID18 = "require-nullable-result-in-root";
|
5243
|
+
var rule27 = {
|
4467
5244
|
meta: {
|
4468
5245
|
type: "suggestion",
|
4469
|
-
hasSuggestions:
|
5246
|
+
hasSuggestions: true,
|
4470
5247
|
docs: {
|
4471
5248
|
category: "Schema",
|
4472
5249
|
description: "Require nullable fields in root types.",
|
4473
5250
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID18}`,
|
4474
|
-
requiresSchema:
|
5251
|
+
requiresSchema: true,
|
4475
5252
|
examples: [
|
4476
5253
|
{
|
4477
5254
|
title: "Incorrect",
|
@@ -4505,34 +5282,38 @@ var RULE_ID18 = "require-nullable-result-in-root", rule27 = {
|
|
4505
5282
|
schema: []
|
4506
5283
|
},
|
4507
5284
|
create(context) {
|
4508
|
-
|
5285
|
+
const schema16 = requireGraphQLSchema(RULE_ID18, context);
|
5286
|
+
const rootTypeNames = new Set(
|
4509
5287
|
[schema16.getQueryType(), schema16.getMutationType()].filter((v) => !!v).map((type) => type.name)
|
4510
|
-
)
|
5288
|
+
);
|
5289
|
+
const sourceCode = context.getSourceCode();
|
4511
5290
|
return {
|
4512
5291
|
"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
|
-
|
5292
|
+
if (!rootTypeNames.has(node.name.value)) return;
|
5293
|
+
for (const field of node.fields || []) {
|
5294
|
+
if (field.gqlType.type !== Kind19.NON_NULL_TYPE || field.gqlType.gqlType.type !== Kind19.NAMED_TYPE)
|
5295
|
+
continue;
|
5296
|
+
const name = field.gqlType.gqlType.name.value;
|
5297
|
+
const type = schema16.getType(name);
|
5298
|
+
const resultType = type?.astNode ? getNodeName(type.astNode) : type?.name;
|
5299
|
+
context.report({
|
5300
|
+
node: field.gqlType,
|
5301
|
+
messageId: RULE_ID18,
|
5302
|
+
data: {
|
5303
|
+
resultType: resultType || "",
|
5304
|
+
rootType: getNodeName(node)
|
5305
|
+
},
|
5306
|
+
suggest: [
|
5307
|
+
{
|
5308
|
+
desc: `Make ${resultType} nullable`,
|
5309
|
+
fix(fixer) {
|
5310
|
+
const text = sourceCode.getText(field.gqlType);
|
5311
|
+
return fixer.replaceText(field.gqlType, text.replace("!", ""));
|
4532
5312
|
}
|
4533
|
-
|
4534
|
-
|
4535
|
-
}
|
5313
|
+
}
|
5314
|
+
]
|
5315
|
+
});
|
5316
|
+
}
|
4536
5317
|
}
|
4537
5318
|
};
|
4538
5319
|
}
|
@@ -4549,7 +5330,9 @@ import {
|
|
4549
5330
|
visitWithTypeInfo as visitWithTypeInfo3
|
4550
5331
|
} from "graphql";
|
4551
5332
|
import { asArray } from "@graphql-tools/utils";
|
4552
|
-
var RULE_ID19 = "require-selections"
|
5333
|
+
var RULE_ID19 = "require-selections";
|
5334
|
+
var DEFAULT_ID_FIELD_NAME = "id";
|
5335
|
+
var schema13 = {
|
4553
5336
|
definitions: {
|
4554
5337
|
asString: {
|
4555
5338
|
type: "string"
|
@@ -4560,7 +5343,7 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4560
5343
|
maxItems: 1,
|
4561
5344
|
items: {
|
4562
5345
|
type: "object",
|
4563
|
-
additionalProperties:
|
5346
|
+
additionalProperties: false,
|
4564
5347
|
properties: {
|
4565
5348
|
fieldName: {
|
4566
5349
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asArray" }],
|
@@ -4572,16 +5355,17 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4572
5355
|
}
|
4573
5356
|
}
|
4574
5357
|
}
|
4575
|
-
}
|
5358
|
+
};
|
5359
|
+
var rule28 = {
|
4576
5360
|
meta: {
|
4577
5361
|
type: "suggestion",
|
4578
|
-
hasSuggestions:
|
5362
|
+
hasSuggestions: true,
|
4579
5363
|
docs: {
|
4580
5364
|
category: "Operations",
|
4581
5365
|
description: "Enforce selecting specific fields when they are available on the GraphQL type.",
|
4582
5366
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID19}`,
|
4583
|
-
requiresSchema:
|
4584
|
-
requiresSiblings:
|
5367
|
+
requiresSchema: true,
|
5368
|
+
requiresSiblings: true,
|
4585
5369
|
examples: [
|
4586
5370
|
{
|
4587
5371
|
title: "Incorrect",
|
@@ -4632,87 +5416,120 @@ var RULE_ID19 = "require-selections", DEFAULT_ID_FIELD_NAME = "id", schema13 = {
|
|
4632
5416
|
)
|
4633
5417
|
}
|
4634
5418
|
],
|
4635
|
-
recommended:
|
5419
|
+
recommended: true,
|
4636
5420
|
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
5421
|
},
|
4638
5422
|
messages: {
|
4639
|
-
[RULE_ID19]:
|
4640
|
-
Include it in your selection set{{ addition }}.`
|
5423
|
+
[RULE_ID19]: "Field{{ pluralSuffix }} {{ fieldName }} must be selected when it's available on a type.\nInclude it in your selection set{{ addition }}."
|
4641
5424
|
},
|
4642
5425
|
schema: schema13
|
4643
5426
|
},
|
4644
5427
|
create(context) {
|
4645
|
-
|
5428
|
+
const schema16 = requireGraphQLSchema(RULE_ID19, context);
|
5429
|
+
const siblings = requireGraphQLOperations(RULE_ID19, context);
|
5430
|
+
const { fieldName = DEFAULT_ID_FIELD_NAME, requireAllFields } = context.options[0] || {};
|
5431
|
+
const idNames = asArray(fieldName);
|
5432
|
+
const selector = "SelectionSet[parent.kind!=/(^OperationDefinition|InlineFragment)$/]";
|
5433
|
+
const typeInfo = new TypeInfo3(schema16);
|
4646
5434
|
function checkFragments(node) {
|
4647
|
-
for (
|
4648
|
-
if (selection.kind !== Kind20.FRAGMENT_SPREAD)
|
5435
|
+
for (const selection of node.selections) {
|
5436
|
+
if (selection.kind !== Kind20.FRAGMENT_SPREAD) {
|
4649
5437
|
continue;
|
4650
|
-
|
4651
|
-
|
5438
|
+
}
|
5439
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
5440
|
+
if (!foundSpread) {
|
4652
5441
|
continue;
|
4653
|
-
|
5442
|
+
}
|
5443
|
+
const checkedFragmentSpreads = /* @__PURE__ */ new Set();
|
5444
|
+
const visitor = visitWithTypeInfo3(typeInfo, {
|
4654
5445
|
SelectionSet(node2, key, _parent) {
|
4655
|
-
|
4656
|
-
parent.kind === Kind20.FRAGMENT_DEFINITION
|
4657
|
-
|
4658
|
-
|
4659
|
-
|
4660
|
-
|
4661
|
-
|
4662
|
-
|
5446
|
+
const parent = _parent;
|
5447
|
+
if (parent.kind === Kind20.FRAGMENT_DEFINITION) {
|
5448
|
+
checkedFragmentSpreads.add(parent.name.value);
|
5449
|
+
} else if (parent.kind !== Kind20.INLINE_FRAGMENT) {
|
5450
|
+
checkSelections(
|
5451
|
+
node2,
|
5452
|
+
typeInfo.getType(),
|
5453
|
+
selection.loc.start,
|
5454
|
+
parent,
|
5455
|
+
checkedFragmentSpreads
|
5456
|
+
);
|
5457
|
+
}
|
4663
5458
|
}
|
4664
5459
|
});
|
4665
5460
|
visit8(foundSpread.document, visitor);
|
4666
5461
|
}
|
4667
5462
|
}
|
4668
5463
|
function checkSelections(node, type, loc, parent, checkedFragmentSpreads = /* @__PURE__ */ new Set()) {
|
4669
|
-
|
4670
|
-
if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType)
|
5464
|
+
const rawType = getBaseType(type);
|
5465
|
+
if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType) {
|
4671
5466
|
checkFields(rawType);
|
4672
|
-
else if (rawType instanceof GraphQLUnionType)
|
4673
|
-
for (
|
4674
|
-
|
5467
|
+
} else if (rawType instanceof GraphQLUnionType) {
|
5468
|
+
for (const selection of node.selections) {
|
5469
|
+
const types = rawType.getTypes();
|
4675
5470
|
if (selection.kind === Kind20.INLINE_FRAGMENT) {
|
4676
|
-
|
4677
|
-
|
5471
|
+
const t = types.find((t2) => t2.name === selection.typeCondition.name.value);
|
5472
|
+
if (t) {
|
5473
|
+
checkFields(t);
|
5474
|
+
}
|
4678
5475
|
} else if (selection.kind === Kind20.FRAGMENT_SPREAD) {
|
4679
|
-
|
5476
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
4680
5477
|
if (!foundSpread) return;
|
4681
|
-
|
4682
|
-
|
5478
|
+
const fragmentSpread = foundSpread.document;
|
5479
|
+
const t = fragmentSpread.typeCondition.name.value === rawType.name ? rawType : types.find((t2) => t2.name === fragmentSpread.typeCondition.name.value);
|
5480
|
+
checkedFragmentSpreads.add(fragmentSpread.name.value);
|
5481
|
+
checkSelections(fragmentSpread.selectionSet, t, loc, parent, checkedFragmentSpreads);
|
4683
5482
|
}
|
4684
5483
|
}
|
5484
|
+
}
|
4685
5485
|
function checkFields(rawType2) {
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
|
4690
|
-
|
4691
|
-
|
4692
|
-
|
5486
|
+
const fields = rawType2.getFields();
|
5487
|
+
const hasIdFieldInType = idNames.some((name) => fields[name]);
|
5488
|
+
if (!hasIdFieldInType) {
|
5489
|
+
return;
|
5490
|
+
}
|
5491
|
+
checkFragments(node);
|
5492
|
+
if (requireAllFields) {
|
5493
|
+
for (const idName of idNames) {
|
5494
|
+
report([idName]);
|
5495
|
+
}
|
5496
|
+
} else {
|
5497
|
+
report(idNames);
|
5498
|
+
}
|
4693
5499
|
}
|
4694
5500
|
function report(idNames2) {
|
4695
5501
|
function hasIdField({ selections }) {
|
4696
5502
|
return selections.some((selection) => {
|
4697
|
-
if (selection.kind === Kind20.FIELD)
|
4698
|
-
|
4699
|
-
|
5503
|
+
if (selection.kind === Kind20.FIELD) {
|
5504
|
+
if (selection.alias && idNames2.includes(selection.alias.value)) {
|
5505
|
+
return true;
|
5506
|
+
}
|
5507
|
+
return idNames2.includes(selection.name.value);
|
5508
|
+
}
|
5509
|
+
if (selection.kind === Kind20.INLINE_FRAGMENT) {
|
4700
5510
|
return hasIdField(selection.selectionSet);
|
5511
|
+
}
|
4701
5512
|
if (selection.kind === Kind20.FRAGMENT_SPREAD) {
|
4702
|
-
|
5513
|
+
const [foundSpread] = siblings.getFragment(selection.name.value);
|
4703
5514
|
if (foundSpread) {
|
4704
|
-
|
4705
|
-
|
5515
|
+
const fragmentSpread = foundSpread.document;
|
5516
|
+
checkedFragmentSpreads.add(fragmentSpread.name.value);
|
5517
|
+
return hasIdField(fragmentSpread.selectionSet);
|
4706
5518
|
}
|
4707
5519
|
}
|
4708
|
-
return
|
5520
|
+
return false;
|
4709
5521
|
});
|
4710
5522
|
}
|
4711
|
-
|
5523
|
+
const hasId = hasIdField(node);
|
5524
|
+
if (hasId) {
|
4712
5525
|
return;
|
4713
|
-
|
5526
|
+
}
|
5527
|
+
const fieldName2 = englishJoinWords(
|
4714
5528
|
idNames2.map((name) => `\`${(parent.alias || parent.name).value}.${name}\``)
|
4715
|
-
)
|
5529
|
+
);
|
5530
|
+
const pluralSuffix = idNames2.length > 1 ? "s" : "";
|
5531
|
+
const addition = checkedFragmentSpreads.size === 0 ? "" : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? "s" : ""} ${englishJoinWords([...checkedFragmentSpreads].map((name) => `\`${name}\``))}`;
|
5532
|
+
const problem = {
|
4716
5533
|
loc,
|
4717
5534
|
messageId: RULE_ID19,
|
4718
5535
|
data: {
|
@@ -4721,26 +5538,33 @@ Include it in your selection set{{ addition }}.`
|
|
4721
5538
|
addition
|
4722
5539
|
}
|
4723
5540
|
};
|
4724
|
-
"type" in node
|
4725
|
-
|
4726
|
-
|
4727
|
-
|
4728
|
-
|
4729
|
-
|
4730
|
-
|
5541
|
+
if ("type" in node) {
|
5542
|
+
problem.suggest = idNames2.map((idName) => ({
|
5543
|
+
desc: `Add \`${idName}\` selection`,
|
5544
|
+
fix: (fixer) => {
|
5545
|
+
let insertNode = node.selections[0];
|
5546
|
+
insertNode = insertNode.kind === Kind20.INLINE_FRAGMENT ? insertNode.selectionSet.selections[0] : insertNode;
|
5547
|
+
return fixer.insertTextBefore(insertNode, `${idName} `);
|
5548
|
+
}
|
5549
|
+
}));
|
5550
|
+
}
|
5551
|
+
context.report(problem);
|
4731
5552
|
}
|
4732
5553
|
}
|
4733
5554
|
return {
|
4734
5555
|
[selector](node) {
|
4735
|
-
|
4736
|
-
|
5556
|
+
const typeInfo2 = node.typeInfo();
|
5557
|
+
if (typeInfo2.gqlType) {
|
5558
|
+
checkSelections(node, typeInfo2.gqlType, node.loc.start, node.parent);
|
5559
|
+
}
|
4737
5560
|
}
|
4738
5561
|
};
|
4739
5562
|
}
|
4740
5563
|
};
|
4741
5564
|
|
4742
5565
|
// src/rules/require-type-pattern-with-oneof/index.ts
|
4743
|
-
var RULE_ID20 = "require-type-pattern-with-oneof"
|
5566
|
+
var RULE_ID20 = "require-type-pattern-with-oneof";
|
5567
|
+
var rule29 = {
|
4744
5568
|
meta: {
|
4745
5569
|
type: "suggestion",
|
4746
5570
|
docs: {
|
@@ -4784,16 +5608,19 @@ var RULE_ID20 = "require-type-pattern-with-oneof", rule29 = {
|
|
4784
5608
|
"Directive[name.value=oneOf][parent.kind=ObjectTypeDefinition]"({
|
4785
5609
|
parent
|
4786
5610
|
}) {
|
4787
|
-
|
4788
|
-
for (
|
4789
|
-
parent.fields?.some((field) => field.name.value === fieldName)
|
4790
|
-
|
4791
|
-
|
4792
|
-
|
4793
|
-
|
4794
|
-
|
4795
|
-
|
4796
|
-
|
5611
|
+
const requiredFields = ["error", "ok"];
|
5612
|
+
for (const fieldName of requiredFields) {
|
5613
|
+
if (!parent.fields?.some((field) => field.name.value === fieldName)) {
|
5614
|
+
context.report({
|
5615
|
+
node: parent.name,
|
5616
|
+
messageId: RULE_ID20,
|
5617
|
+
data: {
|
5618
|
+
nodeName: displayNodeName(parent),
|
5619
|
+
fieldName
|
5620
|
+
}
|
5621
|
+
});
|
5622
|
+
}
|
5623
|
+
}
|
4797
5624
|
}
|
4798
5625
|
};
|
4799
5626
|
}
|
@@ -4802,13 +5629,14 @@ var RULE_ID20 = "require-type-pattern-with-oneof", rule29 = {
|
|
4802
5629
|
// src/rules/selection-set-depth/index.ts
|
4803
5630
|
import { Kind as Kind21 } from "graphql";
|
4804
5631
|
import depthLimit from "graphql-depth-limit";
|
4805
|
-
var RULE_ID21 = "selection-set-depth"
|
5632
|
+
var RULE_ID21 = "selection-set-depth";
|
5633
|
+
var schema14 = {
|
4806
5634
|
type: "array",
|
4807
5635
|
minItems: 1,
|
4808
5636
|
maxItems: 1,
|
4809
5637
|
items: {
|
4810
5638
|
type: "object",
|
4811
|
-
additionalProperties:
|
5639
|
+
additionalProperties: false,
|
4812
5640
|
required: ["maxDepth"],
|
4813
5641
|
properties: {
|
4814
5642
|
maxDepth: {
|
@@ -4817,15 +5645,16 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4817
5645
|
ignore: ARRAY_DEFAULT_OPTIONS
|
4818
5646
|
}
|
4819
5647
|
}
|
4820
|
-
}
|
5648
|
+
};
|
5649
|
+
var rule30 = {
|
4821
5650
|
meta: {
|
4822
5651
|
type: "suggestion",
|
4823
|
-
hasSuggestions:
|
5652
|
+
hasSuggestions: true,
|
4824
5653
|
docs: {
|
4825
5654
|
category: "Operations",
|
4826
5655
|
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
5656
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID21}`,
|
4828
|
-
requiresSiblings:
|
5657
|
+
requiresSiblings: true,
|
4829
5658
|
examples: [
|
4830
5659
|
{
|
4831
5660
|
title: "Incorrect",
|
@@ -4867,7 +5696,7 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4867
5696
|
`
|
4868
5697
|
}
|
4869
5698
|
],
|
4870
|
-
recommended:
|
5699
|
+
recommended: true,
|
4871
5700
|
configOptions: [{ maxDepth: 7 }]
|
4872
5701
|
},
|
4873
5702
|
schema: schema14
|
@@ -4881,18 +5710,23 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4881
5710
|
`Rule "${RULE_ID21}" works best with siblings operations loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info`
|
4882
5711
|
);
|
4883
5712
|
}
|
4884
|
-
|
5713
|
+
const { maxDepth, ignore = [] } = context.options[0];
|
5714
|
+
const checkFn = depthLimit(maxDepth, { ignore });
|
4885
5715
|
return {
|
4886
5716
|
"OperationDefinition, FragmentDefinition"(node) {
|
4887
5717
|
try {
|
4888
|
-
|
5718
|
+
const rawNode = node.rawNode();
|
5719
|
+
const fragmentsInUse = siblings ? siblings.getFragmentsInUse(rawNode) : [];
|
5720
|
+
const document = {
|
4889
5721
|
kind: Kind21.DOCUMENT,
|
4890
5722
|
definitions: [rawNode, ...fragmentsInUse]
|
4891
5723
|
};
|
4892
5724
|
checkFn({
|
4893
5725
|
getDocument: () => document,
|
4894
5726
|
reportError(error) {
|
4895
|
-
|
5727
|
+
const { line, column } = error.locations[0];
|
5728
|
+
const ancestors = context.sourceCode.getAncestors(node);
|
5729
|
+
const token = ancestors[0].tokens.find(
|
4896
5730
|
(token2) => token2.loc.start.line === line && token2.loc.start.column === column - 1
|
4897
5731
|
);
|
4898
5732
|
context.report({
|
@@ -4907,7 +5741,9 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4907
5741
|
{
|
4908
5742
|
desc: "Remove selections",
|
4909
5743
|
fix(fixer) {
|
4910
|
-
|
5744
|
+
const sourceCode = context.getSourceCode();
|
5745
|
+
const foundNode = sourceCode.getNodeByRangeIndex(token.range[0]);
|
5746
|
+
const parentNode = foundNode.parent.parent;
|
4911
5747
|
return fixer.remove(
|
4912
5748
|
foundNode.kind === "Name" ? parentNode.parent : parentNode
|
4913
5749
|
);
|
@@ -4931,12 +5767,13 @@ var RULE_ID21 = "selection-set-depth", schema14 = {
|
|
4931
5767
|
|
4932
5768
|
// src/rules/strict-id-in-types/index.ts
|
4933
5769
|
import { Kind as Kind22 } from "graphql";
|
4934
|
-
var RULE_ID22 = "strict-id-in-types"
|
5770
|
+
var RULE_ID22 = "strict-id-in-types";
|
5771
|
+
var schema15 = {
|
4935
5772
|
type: "array",
|
4936
5773
|
maxItems: 1,
|
4937
5774
|
items: {
|
4938
5775
|
type: "object",
|
4939
|
-
additionalProperties:
|
5776
|
+
additionalProperties: false,
|
4940
5777
|
properties: {
|
4941
5778
|
acceptedIdNames: {
|
4942
5779
|
...ARRAY_DEFAULT_OPTIONS,
|
@@ -4948,7 +5785,7 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
4948
5785
|
},
|
4949
5786
|
exceptions: {
|
4950
5787
|
type: "object",
|
4951
|
-
additionalProperties:
|
5788
|
+
additionalProperties: false,
|
4952
5789
|
properties: {
|
4953
5790
|
types: {
|
4954
5791
|
...ARRAY_DEFAULT_OPTIONS,
|
@@ -4962,15 +5799,16 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
4962
5799
|
}
|
4963
5800
|
}
|
4964
5801
|
}
|
4965
|
-
}
|
5802
|
+
};
|
5803
|
+
var rule31 = {
|
4966
5804
|
meta: {
|
4967
5805
|
type: "suggestion",
|
4968
5806
|
docs: {
|
4969
5807
|
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
5808
|
category: "Schema",
|
4971
|
-
recommended:
|
5809
|
+
recommended: true,
|
4972
5810
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID22}`,
|
4973
|
-
requiresSchema:
|
5811
|
+
requiresSchema: true,
|
4974
5812
|
examples: [
|
4975
5813
|
{
|
4976
5814
|
title: "Incorrect",
|
@@ -5042,26 +5880,38 @@ var RULE_ID22 = "strict-id-in-types", schema15 = {
|
|
5042
5880
|
schema: schema15
|
5043
5881
|
},
|
5044
5882
|
create(context) {
|
5045
|
-
|
5883
|
+
const options = {
|
5046
5884
|
acceptedIdNames: ["id"],
|
5047
5885
|
acceptedIdTypes: ["ID"],
|
5048
5886
|
exceptions: {},
|
5049
5887
|
...context.options[0]
|
5050
|
-
}
|
5888
|
+
};
|
5889
|
+
const schema16 = requireGraphQLSchema(RULE_ID22, context);
|
5890
|
+
const rootTypeNames = [
|
5891
|
+
schema16.getQueryType(),
|
5892
|
+
schema16.getMutationType(),
|
5893
|
+
schema16.getSubscriptionType()
|
5894
|
+
].filter((v) => !!v).map((type) => type.name);
|
5895
|
+
const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join("|")})$/]`;
|
5051
5896
|
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)))
|
5897
|
+
[selector](node) {
|
5898
|
+
const typeName = node.name.value;
|
5899
|
+
const shouldIgnoreNode = options.exceptions.types?.includes(typeName) || options.exceptions.suffixes?.some((suffix) => typeName.endsWith(suffix));
|
5900
|
+
if (shouldIgnoreNode) {
|
5059
5901
|
return;
|
5060
|
-
|
5061
|
-
|
5062
|
-
|
5063
|
-
|
5064
|
-
let
|
5902
|
+
}
|
5903
|
+
const validIds = node.fields?.filter((field) => {
|
5904
|
+
const fieldNode = field.rawNode();
|
5905
|
+
const isValidIdName = options.acceptedIdNames.includes(fieldNode.name.value);
|
5906
|
+
let isValidIdType = false;
|
5907
|
+
if (fieldNode.type.kind === Kind22.NON_NULL_TYPE && fieldNode.type.type.kind === Kind22.NAMED_TYPE) {
|
5908
|
+
isValidIdType = options.acceptedIdTypes.includes(fieldNode.type.type.name.value);
|
5909
|
+
}
|
5910
|
+
return isValidIdName && isValidIdType;
|
5911
|
+
});
|
5912
|
+
if (validIds?.length !== 1) {
|
5913
|
+
const pluralNamesSuffix = options.acceptedIdNames.length > 1 ? "s" : "";
|
5914
|
+
const pluralTypesSuffix = options.acceptedIdTypes.length > 1 ? "s" : "";
|
5065
5915
|
context.report({
|
5066
5916
|
node: node.name,
|
5067
5917
|
message: `${displayNodeName(node)} must have exactly one non-nullable unique identifier.
|
@@ -5079,11 +5929,11 @@ import { Kind as Kind23 } from "graphql";
|
|
5079
5929
|
var rule32 = {
|
5080
5930
|
meta: {
|
5081
5931
|
type: "suggestion",
|
5082
|
-
hasSuggestions:
|
5932
|
+
hasSuggestions: true,
|
5083
5933
|
docs: {
|
5084
5934
|
url: "https://the-guild.dev/graphql/eslint/rules/unique-enum-value-names",
|
5085
5935
|
category: "Schema",
|
5086
|
-
recommended:
|
5936
|
+
recommended: true,
|
5087
5937
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.
|
5088
5938
|
> This rule disallows case-insensitive enum values duplicates too.`,
|
5089
5939
|
examples: [
|
@@ -5118,13 +5968,14 @@ var rule32 = {
|
|
5118
5968
|
schema: []
|
5119
5969
|
},
|
5120
5970
|
create(context) {
|
5971
|
+
const selector = [Kind23.ENUM_TYPE_DEFINITION, Kind23.ENUM_TYPE_EXTENSION].join(",");
|
5121
5972
|
return {
|
5122
|
-
[
|
5123
|
-
|
5973
|
+
[selector](node) {
|
5974
|
+
const duplicates = node.values?.filter(
|
5124
5975
|
(item, index, array) => array.findIndex((v) => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !== index
|
5125
5976
|
);
|
5126
|
-
for (
|
5127
|
-
|
5977
|
+
for (const duplicate of duplicates || []) {
|
5978
|
+
const enumName = duplicate.name.value;
|
5128
5979
|
context.report({
|
5129
5980
|
node: duplicate.name,
|
5130
5981
|
message: `Unexpected case-insensitive enum values duplicates for ${getNodeName(
|
@@ -5146,30 +5997,38 @@ var rule32 = {
|
|
5146
5997
|
// src/rules/unique-fragment-name/index.ts
|
5147
5998
|
import { relative as relative2 } from "node:path";
|
5148
5999
|
import { Kind as Kind24 } from "graphql";
|
5149
|
-
var RULE_ID23 = "unique-fragment-name"
|
5150
|
-
|
5151
|
-
|
6000
|
+
var RULE_ID23 = "unique-fragment-name";
|
6001
|
+
var checkNode = (context, node, ruleId) => {
|
6002
|
+
const documentName = node.name.value;
|
6003
|
+
const siblings = requireGraphQLOperations(ruleId, context);
|
6004
|
+
const siblingDocuments = node.kind === Kind24.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
|
6005
|
+
const filepath = context.filename;
|
6006
|
+
const conflictingDocuments = siblingDocuments.filter((f) => {
|
6007
|
+
const isSameName = f.document.name?.value === documentName;
|
6008
|
+
const isSamePath = slash(f.filePath) === slash(filepath);
|
5152
6009
|
return isSameName && !isSamePath;
|
5153
6010
|
});
|
5154
|
-
conflictingDocuments.length > 0
|
5155
|
-
|
5156
|
-
|
5157
|
-
|
5158
|
-
|
5159
|
-
`)
|
5160
|
-
|
5161
|
-
|
5162
|
-
|
5163
|
-
|
5164
|
-
}
|
6011
|
+
if (conflictingDocuments.length > 0) {
|
6012
|
+
context.report({
|
6013
|
+
messageId: ruleId,
|
6014
|
+
data: {
|
6015
|
+
documentName,
|
6016
|
+
summary: conflictingDocuments.map((f) => ` ${relative2(CWD, f.filePath.replace(VIRTUAL_DOCUMENT_REGEX, ""))}`).join("\n")
|
6017
|
+
},
|
6018
|
+
// @ts-expect-error name will exist
|
6019
|
+
node: node.name
|
6020
|
+
});
|
6021
|
+
}
|
6022
|
+
};
|
6023
|
+
var rule33 = {
|
5165
6024
|
meta: {
|
5166
6025
|
type: "suggestion",
|
5167
6026
|
docs: {
|
5168
6027
|
category: "Operations",
|
5169
6028
|
description: "Enforce unique fragment names across your project.",
|
5170
6029
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID23}`,
|
5171
|
-
requiresSiblings:
|
5172
|
-
recommended:
|
6030
|
+
requiresSiblings: true,
|
6031
|
+
recommended: true,
|
5173
6032
|
examples: [
|
5174
6033
|
{
|
5175
6034
|
title: "Incorrect",
|
@@ -5212,8 +6071,7 @@ var RULE_ID23 = "unique-fragment-name", checkNode = (context, node, ruleId) => {
|
|
5212
6071
|
]
|
5213
6072
|
},
|
5214
6073
|
messages: {
|
5215
|
-
[RULE_ID23]:
|
5216
|
-
{{ summary }}`
|
6074
|
+
[RULE_ID23]: 'Fragment named "{{ documentName }}" already defined in:\n{{ summary }}'
|
5217
6075
|
},
|
5218
6076
|
schema: []
|
5219
6077
|
},
|
@@ -5227,15 +6085,16 @@ var RULE_ID23 = "unique-fragment-name", checkNode = (context, node, ruleId) => {
|
|
5227
6085
|
};
|
5228
6086
|
|
5229
6087
|
// src/rules/unique-operation-name/index.ts
|
5230
|
-
var RULE_ID24 = "unique-operation-name"
|
6088
|
+
var RULE_ID24 = "unique-operation-name";
|
6089
|
+
var rule34 = {
|
5231
6090
|
meta: {
|
5232
6091
|
type: "suggestion",
|
5233
6092
|
docs: {
|
5234
6093
|
category: "Operations",
|
5235
6094
|
description: "Enforce unique operation names across your project.",
|
5236
6095
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID24}`,
|
5237
|
-
requiresSiblings:
|
5238
|
-
recommended:
|
6096
|
+
requiresSiblings: true,
|
6097
|
+
recommended: true,
|
5239
6098
|
examples: [
|
5240
6099
|
{
|
5241
6100
|
title: "Incorrect",
|
@@ -5282,8 +6141,7 @@ var RULE_ID24 = "unique-operation-name", rule34 = {
|
|
5282
6141
|
]
|
5283
6142
|
},
|
5284
6143
|
messages: {
|
5285
|
-
[RULE_ID24]:
|
5286
|
-
{{ summary }}`
|
6144
|
+
[RULE_ID24]: 'Operation named "{{ documentName }}" already defined in:\n{{ summary }}'
|
5287
6145
|
},
|
5288
6146
|
schema: []
|
5289
6147
|
},
|
@@ -5335,227 +6193,21 @@ var rules = {
|
|
5335
6193
|
"unique-operation-name": rule34
|
5336
6194
|
};
|
5337
6195
|
|
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
|
-
}
|
6196
|
+
// src/index.ts
|
6197
|
+
var processors = { graphql: processor };
|
6198
|
+
var src_default = {
|
6199
|
+
parser,
|
6200
|
+
processor,
|
6201
|
+
rules,
|
6202
|
+
configs
|
5556
6203
|
};
|
5557
6204
|
export {
|
5558
6205
|
configs,
|
6206
|
+
src_default as default,
|
6207
|
+
parseForESLint,
|
5559
6208
|
parser,
|
6209
|
+
processors,
|
6210
|
+
requireGraphQLOperations,
|
6211
|
+
requireGraphQLSchema,
|
5560
6212
|
rules
|
5561
6213
|
};
|