@graphql-eslint/eslint-plugin 4.3.0 → 4.4.0-alpha-20241207210859-41eb4549764dc0314b5bd4f257ea6667b178540e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/cache.js +6 -2
- package/cjs/configs/operations-all.js +2 -2
- package/cjs/configs/schema-all.js +2 -2
- package/cjs/configs/schema-recommended.js +1 -1
- package/cjs/documents.js +13 -7
- package/cjs/estree-converter/converter.js +17 -8
- package/cjs/estree-converter/utils.js +22 -9
- package/cjs/graphql-config.js +13 -6
- package/cjs/index.d.cts +18 -4
- package/cjs/meta.js +1 -1
- package/cjs/parser.js +36 -9
- package/cjs/processor.js +48 -20
- package/cjs/rules/alphabetize/index.js +99 -47
- package/cjs/rules/description-style/index.js +10 -6
- package/cjs/rules/graphql-js-validation.js +142 -108
- package/cjs/rules/index.d.cts +18 -4
- package/cjs/rules/input-name/index.js +51 -38
- package/cjs/rules/lone-executable-definition/index.js +15 -6
- package/cjs/rules/match-document-filename/index.d.cts +4 -3
- package/cjs/rules/match-document-filename/index.js +63 -37
- package/cjs/rules/naming-convention/index.d.cts +6 -10
- package/cjs/rules/naming-convention/index.js +179 -82
- package/cjs/rules/no-anonymous-operations/index.js +8 -5
- package/cjs/rules/no-deprecated/index.js +27 -13
- package/cjs/rules/no-duplicate-fields/index.js +15 -8
- package/cjs/rules/no-hashtag-description/index.js +18 -10
- package/cjs/rules/no-one-place-fragments/index.js +17 -10
- package/cjs/rules/no-root-type/index.js +15 -8
- package/cjs/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/cjs/rules/no-typename-prefix/index.js +25 -21
- package/cjs/rules/no-unreachable-types/index.js +34 -17
- package/cjs/rules/no-unused-fields/index.js +56 -30
- package/cjs/rules/relay-arguments/index.js +31 -13
- package/cjs/rules/relay-connection-types/index.js +31 -9
- package/cjs/rules/relay-edge-types/index.js +84 -41
- package/cjs/rules/relay-page-info/index.js +31 -14
- package/cjs/rules/require-deprecation-date/index.js +20 -9
- package/cjs/rules/require-deprecation-reason/index.js +8 -5
- package/cjs/rules/require-description/index.d.cts +79 -13
- package/cjs/rules/require-description/index.js +67 -49
- package/cjs/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/cjs/rules/require-import-fragment/index.js +20 -11
- package/cjs/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/cjs/rules/require-nullable-result-in-root/index.js +32 -27
- package/cjs/rules/require-selections/index.js +88 -46
- package/cjs/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/cjs/rules/selection-set-depth/index.js +19 -10
- package/cjs/rules/strict-id-in-types/index.js +32 -19
- package/cjs/rules/unique-enum-value-names/index.js +4 -3
- package/cjs/rules/unique-fragment-name/index.js +25 -18
- package/cjs/rules/unique-operation-name/index.js +5 -5
- package/cjs/schema.js +14 -8
- package/cjs/siblings.js +60 -32
- package/cjs/utils.js +23 -9
- package/esm/cache.js +6 -2
- package/esm/configs/operations-all.js +2 -2
- package/esm/configs/schema-all.js +2 -2
- package/esm/configs/schema-recommended.js +1 -1
- package/esm/documents.js +13 -7
- package/esm/estree-converter/converter.js +17 -8
- package/esm/estree-converter/utils.js +22 -9
- package/esm/graphql-config.js +13 -6
- package/esm/index.d.ts +18 -4
- package/esm/meta.js +1 -1
- package/esm/parser.js +36 -9
- package/esm/processor.js +48 -20
- package/esm/rules/alphabetize/index.js +99 -47
- package/esm/rules/description-style/index.js +10 -6
- package/esm/rules/graphql-js-validation.js +142 -108
- package/esm/rules/index.d.ts +18 -4
- package/esm/rules/input-name/index.js +51 -38
- package/esm/rules/lone-executable-definition/index.js +15 -6
- package/esm/rules/match-document-filename/index.d.ts +4 -3
- package/esm/rules/match-document-filename/index.js +63 -37
- package/esm/rules/naming-convention/index.d.ts +6 -10
- package/esm/rules/naming-convention/index.js +179 -82
- package/esm/rules/no-anonymous-operations/index.js +8 -5
- package/esm/rules/no-deprecated/index.js +27 -13
- package/esm/rules/no-duplicate-fields/index.js +15 -8
- package/esm/rules/no-hashtag-description/index.js +18 -10
- package/esm/rules/no-one-place-fragments/index.js +17 -10
- package/esm/rules/no-root-type/index.js +15 -8
- package/esm/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/esm/rules/no-typename-prefix/index.js +25 -21
- package/esm/rules/no-unreachable-types/index.js +34 -17
- package/esm/rules/no-unused-fields/index.js +56 -30
- package/esm/rules/relay-arguments/index.js +31 -13
- package/esm/rules/relay-connection-types/index.js +31 -9
- package/esm/rules/relay-edge-types/index.js +84 -41
- package/esm/rules/relay-page-info/index.js +31 -14
- package/esm/rules/require-deprecation-date/index.js +20 -9
- package/esm/rules/require-deprecation-reason/index.js +8 -5
- package/esm/rules/require-description/index.d.ts +79 -13
- package/esm/rules/require-description/index.js +67 -49
- package/esm/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/esm/rules/require-import-fragment/index.js +20 -11
- package/esm/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/esm/rules/require-nullable-result-in-root/index.js +32 -27
- package/esm/rules/require-selections/index.js +88 -46
- package/esm/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/esm/rules/selection-set-depth/index.js +19 -10
- package/esm/rules/strict-id-in-types/index.js +32 -19
- package/esm/rules/unique-enum-value-names/index.js +4 -3
- package/esm/rules/unique-fragment-name/index.js +25 -18
- package/esm/rules/unique-operation-name/index.js +5 -5
- package/esm/schema.js +15 -8
- package/esm/siblings.js +60 -32
- package/esm/utils.js +23 -9
- package/index.browser.js +1871 -1160
- package/package.json +1 -1
@@ -24,26 +24,33 @@ const KindToDisplayName = {
|
|
24
24
|
[_graphql.Kind.OPERATION_DEFINITION]: "Operation",
|
25
25
|
[_graphql.Kind.FRAGMENT_DEFINITION]: "Fragment",
|
26
26
|
[_graphql.Kind.VARIABLE_DEFINITION]: "Variable"
|
27
|
-
}
|
27
|
+
};
|
28
|
+
const StyleToRegex = {
|
28
29
|
camelCase: /^[a-z][\dA-Za-z]*$/,
|
29
30
|
PascalCase: /^[A-Z][\dA-Za-z]*$/,
|
30
31
|
snake_case: /^[a-z][\d_a-z]*[\da-z]*$/,
|
31
32
|
UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]*$/
|
32
|
-
}
|
33
|
+
};
|
34
|
+
const ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
|
35
|
+
const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
36
|
+
const schemaOption = {
|
33
37
|
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asObject" }]
|
34
|
-
}
|
38
|
+
};
|
39
|
+
const descriptionPrefixesSuffixes = (name, id) => `> [!WARNING]
|
35
40
|
>
|
36
|
-
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${
|
41
|
+
> This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${id}) instead.`;
|
42
|
+
const caseSchema = {
|
43
|
+
enum: ALLOWED_STYLES,
|
44
|
+
description: `One of: ${ALLOWED_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
45
|
+
};
|
46
|
+
const schema = {
|
37
47
|
definitions: {
|
38
|
-
asString:
|
39
|
-
enum: ALLOWED_STYLES,
|
40
|
-
description: `One of: ${ALLOWED_STYLES.map((t) => `\`${t}\``).join(", ")}`
|
41
|
-
},
|
48
|
+
asString: caseSchema,
|
42
49
|
asObject: {
|
43
50
|
type: "object",
|
44
|
-
additionalProperties:
|
51
|
+
additionalProperties: false,
|
45
52
|
properties: {
|
46
|
-
style:
|
53
|
+
style: caseSchema,
|
47
54
|
prefix: { type: "string" },
|
48
55
|
suffix: { type: "string" },
|
49
56
|
forbiddenPatterns: {
|
@@ -53,28 +60,25 @@ const KindToDisplayName = {
|
|
53
60
|
},
|
54
61
|
description: "Should be of instance of `RegEx`"
|
55
62
|
},
|
56
|
-
|
57
|
-
|
58
|
-
items: {
|
59
|
-
type: "object"
|
60
|
-
},
|
63
|
+
requiredPattern: {
|
64
|
+
type: "object",
|
61
65
|
description: "Should be of instance of `RegEx`"
|
62
66
|
},
|
63
67
|
forbiddenPrefixes: {
|
64
68
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
65
|
-
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
69
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
|
66
70
|
},
|
67
71
|
forbiddenSuffixes: {
|
68
72
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
69
|
-
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
73
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
|
70
74
|
},
|
71
75
|
requiredPrefixes: {
|
72
76
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
73
|
-
description: descriptionPrefixesSuffixes("
|
77
|
+
description: descriptionPrefixesSuffixes("requiredPattern", "requiredpattern-object")
|
74
78
|
},
|
75
79
|
requiredSuffixes: {
|
76
80
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
77
|
-
description: descriptionPrefixesSuffixes("
|
81
|
+
description: descriptionPrefixesSuffixes("requiredPattern", "requiredpattern-object")
|
78
82
|
},
|
79
83
|
ignorePattern: {
|
80
84
|
type: "string",
|
@@ -87,13 +91,12 @@ const KindToDisplayName = {
|
|
87
91
|
maxItems: 1,
|
88
92
|
items: {
|
89
93
|
type: "object",
|
90
|
-
additionalProperties:
|
94
|
+
additionalProperties: false,
|
91
95
|
properties: {
|
92
96
|
types: {
|
93
97
|
...schemaOption,
|
94
98
|
description: `Includes:
|
95
|
-
${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
96
|
-
`)}`
|
99
|
+
${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
|
97
100
|
},
|
98
101
|
...Object.fromEntries(
|
99
102
|
ALLOWED_KINDS.map((kind) => [
|
@@ -108,11 +111,11 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
108
111
|
),
|
109
112
|
allowLeadingUnderscore: {
|
110
113
|
type: "boolean",
|
111
|
-
default:
|
114
|
+
default: false
|
112
115
|
},
|
113
116
|
allowTrailingUnderscore: {
|
114
117
|
type: "boolean",
|
115
|
-
default:
|
118
|
+
default: false
|
116
119
|
}
|
117
120
|
},
|
118
121
|
patternProperties: {
|
@@ -124,16 +127,16 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
124
127
|
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.",
|
125
128
|
">",
|
126
129
|
"> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`."
|
127
|
-
].join(
|
128
|
-
`)
|
130
|
+
].join("\n")
|
129
131
|
}
|
130
|
-
}
|
132
|
+
};
|
133
|
+
const rule = {
|
131
134
|
meta: {
|
132
135
|
type: "suggestion",
|
133
136
|
docs: {
|
134
137
|
description: "Require names to follow specified conventions.",
|
135
138
|
category: ["Schema", "Operations"],
|
136
|
-
recommended:
|
139
|
+
recommended: true,
|
137
140
|
url: "https://the-guild.dev/graphql/eslint/rules/naming-convention",
|
138
141
|
examples: [
|
139
142
|
{
|
@@ -150,7 +153,14 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
150
153
|
},
|
151
154
|
{
|
152
155
|
title: "Incorrect",
|
153
|
-
usage: [
|
156
|
+
usage: [
|
157
|
+
{
|
158
|
+
FragmentDefinition: {
|
159
|
+
style: "PascalCase",
|
160
|
+
forbiddenPatterns: [/(^fragment)|(fragment$)/i]
|
161
|
+
}
|
162
|
+
}
|
163
|
+
],
|
154
164
|
code: (
|
155
165
|
/* GraphQL */
|
156
166
|
`
|
@@ -162,7 +172,7 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
162
172
|
},
|
163
173
|
{
|
164
174
|
title: "Incorrect",
|
165
|
-
usage: [{ "FieldDefinition[parent.name.value=Query]": {
|
175
|
+
usage: [{ "FieldDefinition[parent.name.value=Query]": { forbiddenPatterns: [/^get/i] } }],
|
166
176
|
code: (
|
167
177
|
/* GraphQL */
|
168
178
|
`
|
@@ -186,7 +196,14 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
186
196
|
},
|
187
197
|
{
|
188
198
|
title: "Correct",
|
189
|
-
usage: [
|
199
|
+
usage: [
|
200
|
+
{
|
201
|
+
FragmentDefinition: {
|
202
|
+
style: "PascalCase",
|
203
|
+
forbiddenPatterns: [/(^fragment)|(fragment$)/i]
|
204
|
+
}
|
205
|
+
}
|
206
|
+
],
|
190
207
|
code: (
|
191
208
|
/* GraphQL */
|
192
209
|
`
|
@@ -198,7 +215,7 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
198
215
|
},
|
199
216
|
{
|
200
217
|
title: "Correct",
|
201
|
-
usage: [{ "FieldDefinition[parent.name.value=Query]": {
|
218
|
+
usage: [{ "FieldDefinition[parent.name.value=Query]": { forbiddenPatterns: [/^get/i] } }],
|
202
219
|
code: (
|
203
220
|
/* GraphQL */
|
204
221
|
`
|
@@ -228,11 +245,11 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
228
245
|
{
|
229
246
|
"FieldDefinition[gqlType.name.value=Boolean]": {
|
230
247
|
style: "camelCase",
|
231
|
-
|
248
|
+
requiredPattern: /^(is|has)/
|
232
249
|
},
|
233
250
|
"FieldDefinition[gqlType.gqlType.name.value=Boolean]": {
|
234
251
|
style: "camelCase",
|
235
|
-
|
252
|
+
requiredPattern: /^(is|has)/
|
236
253
|
}
|
237
254
|
}
|
238
255
|
],
|
@@ -253,7 +270,7 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
253
270
|
{
|
254
271
|
"FieldDefinition[gqlType.gqlType.name.value=SensitiveSecret]": {
|
255
272
|
style: "camelCase",
|
256
|
-
|
273
|
+
requiredPattern: /SensitiveSecret$/
|
257
274
|
}
|
258
275
|
}
|
259
276
|
],
|
@@ -267,6 +284,30 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
267
284
|
}
|
268
285
|
`
|
269
286
|
)
|
287
|
+
},
|
288
|
+
{
|
289
|
+
title: "Correct (Relay fragment convention `<module_name>_<property_name>`)",
|
290
|
+
usage: [
|
291
|
+
{
|
292
|
+
FragmentDefinition: {
|
293
|
+
style: "PascalCase",
|
294
|
+
requiredPattern: /_(?<camelCase>.+?)$/
|
295
|
+
}
|
296
|
+
}
|
297
|
+
],
|
298
|
+
code: (
|
299
|
+
/* GraphQL */
|
300
|
+
`
|
301
|
+
# schema
|
302
|
+
type User {
|
303
|
+
# ...
|
304
|
+
}
|
305
|
+
# operations
|
306
|
+
fragment UserFields_data on User {
|
307
|
+
# ...
|
308
|
+
}
|
309
|
+
`
|
310
|
+
)
|
270
311
|
}
|
271
312
|
],
|
272
313
|
configOptions: {
|
@@ -279,32 +320,25 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
279
320
|
DirectiveDefinition: "camelCase",
|
280
321
|
EnumValueDefinition: "UPPER_CASE",
|
281
322
|
"FieldDefinition[parent.name.value=Query]": {
|
282
|
-
|
283
|
-
forbiddenSuffixes: ["Query"]
|
323
|
+
forbiddenPatterns: [/^(query|get)/i, /query$/i]
|
284
324
|
},
|
285
325
|
"FieldDefinition[parent.name.value=Mutation]": {
|
286
|
-
|
287
|
-
forbiddenSuffixes: ["Mutation"]
|
326
|
+
forbiddenPatterns: [/(^mutation)|(mutation$)/i]
|
288
327
|
},
|
289
328
|
"FieldDefinition[parent.name.value=Subscription]": {
|
290
|
-
|
291
|
-
forbiddenSuffixes: ["Subscription"]
|
329
|
+
forbiddenPatterns: [/(^subscription)|(subscription$)/i]
|
292
330
|
},
|
293
331
|
"EnumTypeDefinition,EnumTypeExtension": {
|
294
|
-
|
295
|
-
forbiddenSuffixes: ["Enum"]
|
332
|
+
forbiddenPatterns: [/(^enum)|(enum$)/i]
|
296
333
|
},
|
297
334
|
"InterfaceTypeDefinition,InterfaceTypeExtension": {
|
298
|
-
|
299
|
-
forbiddenSuffixes: ["Interface"]
|
335
|
+
forbiddenPatterns: [/(^interface)|(interface$)/i]
|
300
336
|
},
|
301
337
|
"UnionTypeDefinition,UnionTypeExtension": {
|
302
|
-
|
303
|
-
forbiddenSuffixes: ["Union"]
|
338
|
+
forbiddenPatterns: [/(^union)|(union$)/i]
|
304
339
|
},
|
305
340
|
"ObjectTypeDefinition,ObjectTypeExtension": {
|
306
|
-
|
307
|
-
forbiddenSuffixes: ["Type"]
|
341
|
+
forbiddenPatterns: [/(^type)|(type$)/i]
|
308
342
|
}
|
309
343
|
}
|
310
344
|
],
|
@@ -313,26 +347,29 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
313
347
|
VariableDefinition: "camelCase",
|
314
348
|
OperationDefinition: {
|
315
349
|
style: "PascalCase",
|
316
|
-
|
317
|
-
|
350
|
+
forbiddenPatterns: [
|
351
|
+
/^(query|mutation|subscription|get)/i,
|
352
|
+
/(query|mutation|subscription)$/i
|
353
|
+
]
|
318
354
|
},
|
319
355
|
FragmentDefinition: {
|
320
356
|
style: "PascalCase",
|
321
|
-
|
322
|
-
forbiddenSuffixes: ["Fragment"]
|
357
|
+
forbiddenPatterns: [/(^fragment)|(fragment$)/i]
|
323
358
|
}
|
324
359
|
}
|
325
360
|
]
|
326
361
|
}
|
327
362
|
},
|
328
|
-
hasSuggestions:
|
363
|
+
hasSuggestions: true,
|
329
364
|
schema
|
330
365
|
},
|
331
366
|
create(context) {
|
332
|
-
const options = context.options[0] || {}
|
367
|
+
const options = context.options[0] || {};
|
368
|
+
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
369
|
+
const ignoredNodes = /* @__PURE__ */ new Set();
|
333
370
|
function normalisePropertyOption(kind) {
|
334
371
|
const style = restOptions[kind] || types;
|
335
|
-
return typeof style
|
372
|
+
return typeof style === "object" ? style : { style };
|
336
373
|
}
|
337
374
|
function report(node, message, suggestedNames) {
|
338
375
|
context.report({
|
@@ -346,8 +383,9 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
346
383
|
}
|
347
384
|
const checkNode = (selector) => (n) => {
|
348
385
|
const { name: node } = n.kind === _graphql.Kind.VARIABLE_DEFINITION ? n.variable : n;
|
349
|
-
if (!node)
|
386
|
+
if (!node) {
|
350
387
|
return;
|
388
|
+
}
|
351
389
|
const {
|
352
390
|
prefix,
|
353
391
|
suffix,
|
@@ -358,12 +396,18 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
358
396
|
requiredPrefixes,
|
359
397
|
requiredSuffixes,
|
360
398
|
forbiddenPatterns,
|
361
|
-
|
362
|
-
} = normalisePropertyOption(selector)
|
399
|
+
requiredPattern
|
400
|
+
} = normalisePropertyOption(selector);
|
401
|
+
const nodeName = node.value;
|
402
|
+
const error = getError();
|
363
403
|
if (error) {
|
364
|
-
const { errorMessage, renameToNames } = error
|
404
|
+
const { errorMessage, renameToNames } = error;
|
405
|
+
const [leadingUnderscores] = nodeName.match(/^_*/);
|
406
|
+
const [trailingUnderscores] = nodeName.match(/_*$/);
|
407
|
+
const suggestedNames = renameToNames.map(
|
365
408
|
(renameToName) => leadingUnderscores + renameToName + trailingUnderscores
|
366
|
-
)
|
409
|
+
);
|
410
|
+
const name = _utilsjs.displayNodeName.call(void 0, n);
|
367
411
|
report(
|
368
412
|
node,
|
369
413
|
`${name[0].toUpperCase()}${name.slice(1)} should ${errorMessage}`,
|
@@ -371,80 +415,133 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
371
415
|
);
|
372
416
|
}
|
373
417
|
function getError() {
|
374
|
-
|
418
|
+
let name = nodeName;
|
419
|
+
if (allowLeadingUnderscore) name = name.replace(/^_+/, "");
|
420
|
+
if (allowTrailingUnderscore) name = name.replace(/_+$/, "");
|
375
421
|
if (ignorePattern && new RegExp(ignorePattern, "u").test(name)) {
|
376
|
-
"name" in n
|
422
|
+
if ("name" in n) {
|
423
|
+
ignoredNodes.add(n.name);
|
424
|
+
}
|
377
425
|
return;
|
378
426
|
}
|
379
|
-
if (prefix && !name.startsWith(prefix))
|
427
|
+
if (prefix && !name.startsWith(prefix)) {
|
380
428
|
return {
|
381
429
|
errorMessage: `have "${prefix}" prefix`,
|
382
430
|
renameToNames: [prefix + name]
|
383
431
|
};
|
384
|
-
|
432
|
+
}
|
433
|
+
if (suffix && !name.endsWith(suffix)) {
|
385
434
|
return {
|
386
435
|
errorMessage: `have "${suffix}" suffix`,
|
387
436
|
renameToNames: [name + suffix]
|
388
437
|
};
|
438
|
+
}
|
439
|
+
if (requiredPattern) {
|
440
|
+
if (requiredPattern.source.includes("(?<")) {
|
441
|
+
try {
|
442
|
+
name = name.replace(requiredPattern, (originalString, ...args) => {
|
443
|
+
const groups = args.at(-1);
|
444
|
+
for (const [styleName, value] of Object.entries(groups)) {
|
445
|
+
if (!(styleName in StyleToRegex)) {
|
446
|
+
throw new Error("Invalid case style in `requiredPatterns` option");
|
447
|
+
}
|
448
|
+
if (value === _utilsjs.convertCase.call(void 0, styleName, value)) {
|
449
|
+
return "";
|
450
|
+
}
|
451
|
+
throw new Error(`contain the required pattern: ${requiredPattern}`);
|
452
|
+
}
|
453
|
+
return originalString;
|
454
|
+
});
|
455
|
+
if (name === nodeName) {
|
456
|
+
throw new Error(`contain the required pattern: ${requiredPattern}`);
|
457
|
+
}
|
458
|
+
} catch (error2) {
|
459
|
+
return {
|
460
|
+
errorMessage: error2.message,
|
461
|
+
renameToNames: []
|
462
|
+
};
|
463
|
+
}
|
464
|
+
} else if (!requiredPattern.test(name)) {
|
465
|
+
return {
|
466
|
+
errorMessage: `contain the required pattern: ${requiredPattern}`,
|
467
|
+
renameToNames: []
|
468
|
+
};
|
469
|
+
}
|
470
|
+
}
|
389
471
|
const forbidden = _optionalChain([forbiddenPatterns, 'optionalAccess', _ => _.find, 'call', _2 => _2((pattern) => pattern.test(name))]);
|
390
|
-
if (forbidden)
|
472
|
+
if (forbidden) {
|
391
473
|
return {
|
392
474
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
393
475
|
renameToNames: [name.replace(forbidden, "")]
|
394
476
|
};
|
395
|
-
|
396
|
-
return {
|
397
|
-
errorMessage: `contain the required pattern: ${_utilsjs.englishJoinWords.call(void 0, requiredPatterns.map((re) => re.source))}`,
|
398
|
-
renameToNames: []
|
399
|
-
};
|
477
|
+
}
|
400
478
|
const forbiddenPrefix = _optionalChain([forbiddenPrefixes, 'optionalAccess', _3 => _3.find, 'call', _4 => _4((prefix2) => name.startsWith(prefix2))]);
|
401
|
-
if (forbiddenPrefix)
|
479
|
+
if (forbiddenPrefix) {
|
402
480
|
return {
|
403
481
|
errorMessage: `not have "${forbiddenPrefix}" prefix`,
|
404
482
|
renameToNames: [name.replace(new RegExp(`^${forbiddenPrefix}`), "")]
|
405
483
|
};
|
484
|
+
}
|
406
485
|
const forbiddenSuffix = _optionalChain([forbiddenSuffixes, 'optionalAccess', _5 => _5.find, 'call', _6 => _6((suffix2) => name.endsWith(suffix2))]);
|
407
|
-
if (forbiddenSuffix)
|
486
|
+
if (forbiddenSuffix) {
|
408
487
|
return {
|
409
488
|
errorMessage: `not have "${forbiddenSuffix}" suffix`,
|
410
489
|
renameToNames: [name.replace(new RegExp(`${forbiddenSuffix}$`), "")]
|
411
490
|
};
|
412
|
-
|
491
|
+
}
|
492
|
+
if (requiredPrefixes && !requiredPrefixes.some((requiredPrefix) => name.startsWith(requiredPrefix))) {
|
413
493
|
return {
|
414
494
|
errorMessage: `have one of the following prefixes: ${_utilsjs.englishJoinWords.call(void 0,
|
415
495
|
requiredPrefixes
|
416
496
|
)}`,
|
417
497
|
renameToNames: style ? requiredPrefixes.map((prefix2) => _utilsjs.convertCase.call(void 0, style, `${prefix2} ${name}`)) : requiredPrefixes.map((prefix2) => `${prefix2}${name}`)
|
418
498
|
};
|
419
|
-
|
499
|
+
}
|
500
|
+
if (requiredSuffixes && !requiredSuffixes.some((requiredSuffix) => name.endsWith(requiredSuffix))) {
|
420
501
|
return {
|
421
502
|
errorMessage: `have one of the following suffixes: ${_utilsjs.englishJoinWords.call(void 0,
|
422
503
|
requiredSuffixes
|
423
504
|
)}`,
|
424
505
|
renameToNames: style ? requiredSuffixes.map((suffix2) => _utilsjs.convertCase.call(void 0, style, `${name} ${suffix2}`)) : requiredSuffixes.map((suffix2) => `${name}${suffix2}`)
|
425
506
|
};
|
426
|
-
|
507
|
+
}
|
508
|
+
if (!style) {
|
427
509
|
return;
|
428
|
-
|
510
|
+
}
|
511
|
+
const caseRegex = StyleToRegex[style];
|
512
|
+
if (!caseRegex.test(name)) {
|
429
513
|
return {
|
430
514
|
errorMessage: `be in ${style} format`,
|
431
515
|
renameToNames: [_utilsjs.convertCase.call(void 0, style, name)]
|
432
516
|
};
|
517
|
+
}
|
518
|
+
}
|
519
|
+
};
|
520
|
+
const checkUnderscore = (isLeading) => (node) => {
|
521
|
+
if (ignoredNodes.has(node)) {
|
522
|
+
return;
|
433
523
|
}
|
434
|
-
|
435
|
-
if (ignoredNodes.has(node) || node.parent.kind === "Field" && node.parent.alias !== node)
|
524
|
+
if (node.parent.kind === "Field" && node.parent.alias !== node) {
|
436
525
|
return;
|
526
|
+
}
|
437
527
|
const suggestedName = node.value.replace(isLeading ? /^_+/ : /_+$/, "");
|
438
528
|
report(node, `${isLeading ? "Leading" : "Trailing"} underscores are not allowed`, [
|
439
529
|
suggestedName
|
440
530
|
]);
|
441
|
-
}
|
442
|
-
|
531
|
+
};
|
532
|
+
const listeners = {};
|
533
|
+
if (!allowLeadingUnderscore) {
|
534
|
+
listeners["Name[value=/^_/]"] = checkUnderscore(true);
|
535
|
+
}
|
536
|
+
if (!allowTrailingUnderscore) {
|
537
|
+
listeners["Name[value=/_$/]"] = checkUnderscore(false);
|
538
|
+
}
|
443
539
|
const selectors = new Set(
|
444
540
|
[types && _utilsjs.TYPES_KINDS, Object.keys(restOptions)].filter((v) => !!v).flat()
|
445
541
|
);
|
446
|
-
for (const selector of selectors)
|
542
|
+
for (const selector of selectors) {
|
447
543
|
listeners[selector] = checkNode(selector);
|
544
|
+
}
|
448
545
|
return listeners;
|
449
546
|
}
|
450
547
|
};
|
@@ -1,13 +1,14 @@
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _graphql = require('graphql');
|
2
2
|
var _utilsjs = require('../../utils.js');
|
3
|
-
const RULE_ID = "no-anonymous-operations"
|
3
|
+
const RULE_ID = "no-anonymous-operations";
|
4
|
+
const rule = {
|
4
5
|
meta: {
|
5
6
|
type: "suggestion",
|
6
|
-
hasSuggestions:
|
7
|
+
hasSuggestions: true,
|
7
8
|
docs: {
|
8
9
|
category: "Operations",
|
9
10
|
description: "Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.",
|
10
|
-
recommended:
|
11
|
+
recommended: true,
|
11
12
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
12
13
|
examples: [
|
13
14
|
{
|
@@ -42,7 +43,8 @@ const RULE_ID = "no-anonymous-operations", rule = exports.rule = {
|
|
42
43
|
create(context) {
|
43
44
|
return {
|
44
45
|
"OperationDefinition[name=undefined]"(node) {
|
45
|
-
const [firstSelection] = node.selectionSet.selections
|
46
|
+
const [firstSelection] = node.selectionSet.selections;
|
47
|
+
const suggestedName = firstSelection.kind === _graphql.Kind.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
|
46
48
|
context.report({
|
47
49
|
loc: _utilsjs.getLocation.call(void 0, node.loc.start, node.operation),
|
48
50
|
messageId: RULE_ID,
|
@@ -53,7 +55,8 @@ const RULE_ID = "no-anonymous-operations", rule = exports.rule = {
|
|
53
55
|
{
|
54
56
|
desc: `Rename to \`${suggestedName}\``,
|
55
57
|
fix(fixer) {
|
56
|
-
const
|
58
|
+
const sourceCode = context.getSourceCode();
|
59
|
+
const hasQueryKeyword = sourceCode.getText({ range: [node.range[0], node.range[0] + 1] }) !== "{";
|
57
60
|
return fixer.insertTextAfterRange(
|
58
61
|
[node.range[0], node.range[0] + (hasQueryKeyword ? node.operation.length : 0)],
|
59
62
|
`${hasQueryKeyword ? "" : "query"} ${suggestedName}${hasQueryKeyword ? "" : " "}`
|
@@ -1,13 +1,14 @@
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _utilsjs = require('../../utils.js');
|
2
|
-
const RULE_ID = "no-deprecated"
|
2
|
+
const RULE_ID = "no-deprecated";
|
3
|
+
const rule = {
|
3
4
|
meta: {
|
4
5
|
type: "suggestion",
|
5
|
-
hasSuggestions:
|
6
|
+
hasSuggestions: true,
|
6
7
|
docs: {
|
7
8
|
category: "Operations",
|
8
9
|
description: "Enforce that deprecated fields or enum values are not in use by operations.",
|
9
10
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
10
|
-
requiresSchema:
|
11
|
+
requiresSchema: true,
|
11
12
|
examples: [
|
12
13
|
{
|
13
14
|
title: "Incorrect (field)",
|
@@ -79,7 +80,7 @@ const RULE_ID = "no-deprecated", rule = exports.rule = {
|
|
79
80
|
)
|
80
81
|
}
|
81
82
|
],
|
82
|
-
recommended:
|
83
|
+
recommended: true
|
83
84
|
},
|
84
85
|
messages: {
|
85
86
|
[RULE_ID]: "{{ type }} is marked as deprecated in your GraphQL schema (reason: {{ reason }})"
|
@@ -107,24 +108,37 @@ const RULE_ID = "no-deprecated", rule = exports.rule = {
|
|
107
108
|
}
|
108
109
|
return {
|
109
110
|
EnumValue(node) {
|
110
|
-
const
|
111
|
-
reason
|
111
|
+
const typeInfo = node.typeInfo();
|
112
|
+
const reason = _optionalChain([typeInfo, 'access', _ => _.enumValue, 'optionalAccess', _2 => _2.deprecationReason]);
|
113
|
+
if (reason) {
|
114
|
+
report(node, reason);
|
115
|
+
}
|
112
116
|
},
|
113
117
|
Field(node) {
|
114
|
-
const
|
115
|
-
reason
|
118
|
+
const typeInfo = node.typeInfo();
|
119
|
+
const reason = _optionalChain([typeInfo, 'access', _3 => _3.fieldDef, 'optionalAccess', _4 => _4.deprecationReason]);
|
120
|
+
if (reason) {
|
121
|
+
report(node, reason);
|
122
|
+
}
|
116
123
|
},
|
117
124
|
Argument(node) {
|
118
|
-
const
|
119
|
-
reason
|
125
|
+
const typeInfo = node.typeInfo();
|
126
|
+
const reason = _optionalChain([typeInfo, 'access', _5 => _5.argument, 'optionalAccess', _6 => _6.deprecationReason]);
|
127
|
+
if (reason) {
|
128
|
+
report(node, reason);
|
129
|
+
}
|
120
130
|
},
|
121
131
|
ObjectValue(node) {
|
122
132
|
const { inputType } = node.typeInfo();
|
123
|
-
if (inputType
|
133
|
+
if (!inputType) return;
|
134
|
+
if ("getFields" in inputType) {
|
124
135
|
const fields = inputType.getFields();
|
125
136
|
for (const field of node.fields) {
|
126
|
-
const fieldName = field.name.value
|
127
|
-
reason
|
137
|
+
const fieldName = field.name.value;
|
138
|
+
const reason = fields[fieldName].deprecationReason;
|
139
|
+
if (reason) {
|
140
|
+
report(field, reason);
|
141
|
+
}
|
128
142
|
}
|
129
143
|
}
|
130
144
|
}
|
@@ -1,13 +1,14 @@
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _graphql = require('graphql');
|
2
|
-
const RULE_ID = "no-duplicate-fields"
|
2
|
+
const RULE_ID = "no-duplicate-fields";
|
3
|
+
const rule = {
|
3
4
|
meta: {
|
4
5
|
type: "suggestion",
|
5
|
-
hasSuggestions:
|
6
|
+
hasSuggestions: true,
|
6
7
|
docs: {
|
7
8
|
description: "Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.",
|
8
9
|
category: "Operations",
|
9
10
|
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
10
|
-
recommended:
|
11
|
+
recommended: true,
|
11
12
|
examples: [
|
12
13
|
{
|
13
14
|
title: "Incorrect",
|
@@ -88,24 +89,30 @@ const RULE_ID = "no-duplicate-fields", rule = exports.rule = {
|
|
88
89
|
}
|
89
90
|
]
|
90
91
|
});
|
91
|
-
} else
|
92
|
+
} else {
|
92
93
|
usedFields.add(fieldName);
|
94
|
+
}
|
93
95
|
}
|
94
96
|
return {
|
95
97
|
OperationDefinition(node) {
|
96
98
|
const set = /* @__PURE__ */ new Set();
|
97
|
-
for (const varDef of node.variableDefinitions || [])
|
99
|
+
for (const varDef of node.variableDefinitions || []) {
|
98
100
|
checkNode(set, varDef.variable.name);
|
101
|
+
}
|
99
102
|
},
|
100
103
|
Field(node) {
|
101
104
|
const set = /* @__PURE__ */ new Set();
|
102
|
-
for (const arg of node.arguments || [])
|
105
|
+
for (const arg of node.arguments || []) {
|
103
106
|
checkNode(set, arg.name);
|
107
|
+
}
|
104
108
|
},
|
105
109
|
SelectionSet(node) {
|
106
110
|
const set = /* @__PURE__ */ new Set();
|
107
|
-
for (const selection of node.selections)
|
108
|
-
selection.kind === _graphql.Kind.FIELD
|
111
|
+
for (const selection of node.selections) {
|
112
|
+
if (selection.kind === _graphql.Kind.FIELD) {
|
113
|
+
checkNode(set, selection.alias || selection.name);
|
114
|
+
}
|
115
|
+
}
|
109
116
|
}
|
110
117
|
};
|
111
118
|
}
|