@graphql-eslint/eslint-plugin 4.3.0 → 4.3.1-alpha-20241207204625-6a4230707a78900a6339b03afe904b9dd6c31561

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/cjs/cache.js +6 -2
  2. package/cjs/configs/operations-all.js +2 -2
  3. package/cjs/configs/schema-all.js +2 -2
  4. package/cjs/configs/schema-recommended.js +1 -1
  5. package/cjs/documents.js +13 -7
  6. package/cjs/estree-converter/converter.js +17 -8
  7. package/cjs/estree-converter/utils.js +22 -9
  8. package/cjs/graphql-config.js +13 -6
  9. package/cjs/index.d.cts +18 -4
  10. package/cjs/meta.js +1 -1
  11. package/cjs/parser.js +36 -9
  12. package/cjs/processor.js +48 -20
  13. package/cjs/rules/alphabetize/index.js +99 -47
  14. package/cjs/rules/description-style/index.js +10 -6
  15. package/cjs/rules/graphql-js-validation.js +142 -108
  16. package/cjs/rules/index.d.cts +18 -4
  17. package/cjs/rules/input-name/index.js +51 -38
  18. package/cjs/rules/lone-executable-definition/index.js +15 -6
  19. package/cjs/rules/match-document-filename/index.d.cts +4 -3
  20. package/cjs/rules/match-document-filename/index.js +63 -37
  21. package/cjs/rules/naming-convention/index.d.cts +6 -10
  22. package/cjs/rules/naming-convention/index.js +146 -57
  23. package/cjs/rules/no-anonymous-operations/index.js +8 -5
  24. package/cjs/rules/no-deprecated/index.js +27 -13
  25. package/cjs/rules/no-duplicate-fields/index.js +15 -8
  26. package/cjs/rules/no-hashtag-description/index.js +18 -10
  27. package/cjs/rules/no-one-place-fragments/index.js +17 -10
  28. package/cjs/rules/no-root-type/index.js +15 -8
  29. package/cjs/rules/no-scalar-result-type-on-mutation/index.js +20 -12
  30. package/cjs/rules/no-typename-prefix/index.js +25 -21
  31. package/cjs/rules/no-unreachable-types/index.js +34 -17
  32. package/cjs/rules/no-unused-fields/index.js +56 -30
  33. package/cjs/rules/relay-arguments/index.js +31 -13
  34. package/cjs/rules/relay-connection-types/index.js +31 -9
  35. package/cjs/rules/relay-edge-types/index.js +84 -41
  36. package/cjs/rules/relay-page-info/index.js +31 -14
  37. package/cjs/rules/require-deprecation-date/index.js +20 -9
  38. package/cjs/rules/require-deprecation-reason/index.js +8 -5
  39. package/cjs/rules/require-description/index.d.cts +79 -13
  40. package/cjs/rules/require-description/index.js +67 -49
  41. package/cjs/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
  42. package/cjs/rules/require-import-fragment/index.js +20 -11
  43. package/cjs/rules/require-nullable-fields-with-oneof/index.js +12 -5
  44. package/cjs/rules/require-nullable-result-in-root/index.js +32 -27
  45. package/cjs/rules/require-selections/index.js +88 -46
  46. package/cjs/rules/require-type-pattern-with-oneof/index.js +14 -10
  47. package/cjs/rules/selection-set-depth/index.js +19 -10
  48. package/cjs/rules/strict-id-in-types/index.js +32 -19
  49. package/cjs/rules/unique-enum-value-names/index.js +4 -3
  50. package/cjs/rules/unique-fragment-name/index.js +25 -18
  51. package/cjs/rules/unique-operation-name/index.js +5 -5
  52. package/cjs/schema.js +14 -8
  53. package/cjs/siblings.js +60 -32
  54. package/cjs/utils.js +23 -9
  55. package/esm/cache.js +6 -2
  56. package/esm/configs/operations-all.js +2 -2
  57. package/esm/configs/schema-all.js +2 -2
  58. package/esm/configs/schema-recommended.js +1 -1
  59. package/esm/documents.js +13 -7
  60. package/esm/estree-converter/converter.js +17 -8
  61. package/esm/estree-converter/utils.js +22 -9
  62. package/esm/graphql-config.js +13 -6
  63. package/esm/index.d.ts +19 -5
  64. package/esm/meta.js +1 -1
  65. package/esm/parser.js +36 -9
  66. package/esm/processor.js +48 -20
  67. package/esm/rules/alphabetize/index.js +99 -47
  68. package/esm/rules/description-style/index.js +10 -6
  69. package/esm/rules/graphql-js-validation.js +142 -108
  70. package/esm/rules/index.d.ts +19 -5
  71. package/esm/rules/input-name/index.js +51 -38
  72. package/esm/rules/lone-executable-definition/index.js +15 -6
  73. package/esm/rules/match-document-filename/index.d.ts +4 -3
  74. package/esm/rules/match-document-filename/index.js +63 -37
  75. package/esm/rules/naming-convention/index.d.ts +6 -10
  76. package/esm/rules/naming-convention/index.js +146 -57
  77. package/esm/rules/no-anonymous-operations/index.js +8 -5
  78. package/esm/rules/no-deprecated/index.js +27 -13
  79. package/esm/rules/no-duplicate-fields/index.js +15 -8
  80. package/esm/rules/no-hashtag-description/index.js +18 -10
  81. package/esm/rules/no-one-place-fragments/index.js +17 -10
  82. package/esm/rules/no-root-type/index.js +15 -8
  83. package/esm/rules/no-scalar-result-type-on-mutation/index.js +20 -12
  84. package/esm/rules/no-typename-prefix/index.js +25 -21
  85. package/esm/rules/no-unreachable-types/index.js +34 -17
  86. package/esm/rules/no-unused-fields/index.js +56 -30
  87. package/esm/rules/relay-arguments/index.js +31 -13
  88. package/esm/rules/relay-connection-types/index.js +31 -9
  89. package/esm/rules/relay-edge-types/index.js +84 -41
  90. package/esm/rules/relay-page-info/index.js +31 -14
  91. package/esm/rules/require-deprecation-date/index.js +20 -9
  92. package/esm/rules/require-deprecation-reason/index.js +8 -5
  93. package/esm/rules/require-description/index.d.ts +79 -13
  94. package/esm/rules/require-description/index.js +67 -49
  95. package/esm/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
  96. package/esm/rules/require-import-fragment/index.js +20 -11
  97. package/esm/rules/require-nullable-fields-with-oneof/index.js +12 -5
  98. package/esm/rules/require-nullable-result-in-root/index.js +32 -27
  99. package/esm/rules/require-selections/index.js +88 -46
  100. package/esm/rules/require-type-pattern-with-oneof/index.js +14 -10
  101. package/esm/rules/selection-set-depth/index.js +19 -10
  102. package/esm/rules/strict-id-in-types/index.js +32 -19
  103. package/esm/rules/unique-enum-value-names/index.js +4 -3
  104. package/esm/rules/unique-fragment-name/index.js +25 -18
  105. package/esm/rules/unique-operation-name/index.js +5 -5
  106. package/esm/schema.js +15 -8
  107. package/esm/siblings.js +60 -32
  108. package/esm/utils.js +23 -9
  109. package/index.browser.js +1838 -1135
  110. package/package.json +1 -1
@@ -24,26 +24,33 @@ const KindToDisplayName = {
24
24
  [Kind.OPERATION_DEFINITION]: "Operation",
25
25
  [Kind.FRAGMENT_DEFINITION]: "Fragment",
26
26
  [Kind.VARIABLE_DEFINITION]: "Variable"
27
- }, StyleToRegex = {
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
- }, ALLOWED_KINDS = Object.keys(KindToDisplayName).sort(), ALLOWED_STYLES = Object.keys(StyleToRegex), schemaOption = {
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
- }, descriptionPrefixesSuffixes = (name) => `> [!WARNING]
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}\`](#${name.toLowerCase()}-array) instead.`, schema = {
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: !1,
51
+ additionalProperties: false,
45
52
  properties: {
46
- style: { enum: ALLOWED_STYLES },
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
- requiredPatterns: {
57
- ...ARRAY_DEFAULT_OPTIONS,
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
  ...ARRAY_DEFAULT_OPTIONS,
65
- description: descriptionPrefixesSuffixes("forbiddenPatterns")
69
+ description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
66
70
  },
67
71
  forbiddenSuffixes: {
68
72
  ...ARRAY_DEFAULT_OPTIONS,
69
- description: descriptionPrefixesSuffixes("forbiddenPatterns")
73
+ description: descriptionPrefixesSuffixes("forbiddenPatterns", "forbiddenpatterns-array")
70
74
  },
71
75
  requiredPrefixes: {
72
76
  ...ARRAY_DEFAULT_OPTIONS,
73
- description: descriptionPrefixesSuffixes("requiredPatterns")
77
+ description: descriptionPrefixesSuffixes("requiredPattern", "requiredpattern-object")
74
78
  },
75
79
  requiredSuffixes: {
76
80
  ...ARRAY_DEFAULT_OPTIONS,
77
- description: descriptionPrefixesSuffixes("requiredPatterns")
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: !1,
94
+ additionalProperties: false,
91
95
  properties: {
92
96
  types: {
93
97
  ...schemaOption,
94
98
  description: `Includes:
95
- ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
96
- `)}`
99
+ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join("\n")}`
97
100
  },
98
101
  ...Object.fromEntries(
99
102
  ALLOWED_KINDS.map((kind) => [
@@ -108,11 +111,11 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
108
111
  ),
109
112
  allowLeadingUnderscore: {
110
113
  type: "boolean",
111
- default: !1
114
+ default: false
112
115
  },
113
116
  allowTrailingUnderscore: {
114
117
  type: "boolean",
115
- default: !1
118
+ default: false
116
119
  }
117
120
  },
118
121
  patternProperties: {
@@ -124,16 +127,16 @@ ${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
- }, rule = {
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: !0,
139
+ recommended: true,
137
140
  url: "https://the-guild.dev/graphql/eslint/rules/naming-convention",
138
141
  examples: [
139
142
  {
@@ -267,6 +270,30 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
267
270
  }
268
271
  `
269
272
  )
273
+ },
274
+ {
275
+ title: "Correct (Relay fragment convention `<module_name>_<property_name>`)",
276
+ usage: [
277
+ {
278
+ FragmentDefinition: {
279
+ style: "PascalCase",
280
+ requiredPattern: /_(?<camelCase>.+?)$/
281
+ }
282
+ }
283
+ ],
284
+ code: (
285
+ /* GraphQL */
286
+ `
287
+ # schema
288
+ type User {
289
+ # ...
290
+ }
291
+ # operations
292
+ fragment UserFields_data on User {
293
+ # ...
294
+ }
295
+ `
296
+ )
270
297
  }
271
298
  ],
272
299
  configOptions: {
@@ -325,14 +352,16 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
325
352
  ]
326
353
  }
327
354
  },
328
- hasSuggestions: !0,
355
+ hasSuggestions: true,
329
356
  schema
330
357
  },
331
358
  create(context) {
332
- const options = context.options[0] || {}, { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options, ignoredNodes = /* @__PURE__ */ new Set();
359
+ const options = context.options[0] || {};
360
+ const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
361
+ const ignoredNodes = /* @__PURE__ */ new Set();
333
362
  function normalisePropertyOption(kind) {
334
363
  const style = restOptions[kind] || types;
335
- return typeof style == "object" ? style : { style };
364
+ return typeof style === "object" ? style : { style };
336
365
  }
337
366
  function report(node, message, suggestedNames) {
338
367
  context.report({
@@ -346,8 +375,9 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
346
375
  }
347
376
  const checkNode = (selector) => (n) => {
348
377
  const { name: node } = n.kind === Kind.VARIABLE_DEFINITION ? n.variable : n;
349
- if (!node)
378
+ if (!node) {
350
379
  return;
380
+ }
351
381
  const {
352
382
  prefix,
353
383
  suffix,
@@ -358,12 +388,18 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
358
388
  requiredPrefixes,
359
389
  requiredSuffixes,
360
390
  forbiddenPatterns,
361
- requiredPatterns
362
- } = normalisePropertyOption(selector), nodeName = node.value, error = getError();
391
+ requiredPattern
392
+ } = normalisePropertyOption(selector);
393
+ const nodeName = node.value;
394
+ const error = getError();
363
395
  if (error) {
364
- const { errorMessage, renameToNames } = error, [leadingUnderscores] = nodeName.match(/^_*/), [trailingUnderscores] = nodeName.match(/_*$/), suggestedNames = renameToNames.map(
396
+ const { errorMessage, renameToNames } = error;
397
+ const [leadingUnderscores] = nodeName.match(/^_*/);
398
+ const [trailingUnderscores] = nodeName.match(/_*$/);
399
+ const suggestedNames = renameToNames.map(
365
400
  (renameToName) => leadingUnderscores + renameToName + trailingUnderscores
366
- ), name = displayNodeName(n);
401
+ );
402
+ const name = displayNodeName(n);
367
403
  report(
368
404
  node,
369
405
  `${name[0].toUpperCase()}${name.slice(1)} should ${errorMessage}`,
@@ -371,80 +407,133 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
371
407
  );
372
408
  }
373
409
  function getError() {
374
- const name = nodeName.replace(/(^_+)|(_+$)/g, "");
410
+ let name = nodeName;
411
+ if (allowLeadingUnderscore) name = name.replace(/^_+/, "");
412
+ if (allowTrailingUnderscore) name = name.replace(/_+$/, "");
375
413
  if (ignorePattern && new RegExp(ignorePattern, "u").test(name)) {
376
- "name" in n && ignoredNodes.add(n.name);
414
+ if ("name" in n) {
415
+ ignoredNodes.add(n.name);
416
+ }
377
417
  return;
378
418
  }
379
- if (prefix && !name.startsWith(prefix))
419
+ if (prefix && !name.startsWith(prefix)) {
380
420
  return {
381
421
  errorMessage: `have "${prefix}" prefix`,
382
422
  renameToNames: [prefix + name]
383
423
  };
384
- if (suffix && !name.endsWith(suffix))
424
+ }
425
+ if (suffix && !name.endsWith(suffix)) {
385
426
  return {
386
427
  errorMessage: `have "${suffix}" suffix`,
387
428
  renameToNames: [name + suffix]
388
429
  };
430
+ }
431
+ if (requiredPattern) {
432
+ if (requiredPattern.source.includes("(?<")) {
433
+ try {
434
+ name = name.replace(requiredPattern, (originalString, ...args) => {
435
+ const groups = args.at(-1);
436
+ for (const [styleName, value] of Object.entries(groups)) {
437
+ if (!(styleName in StyleToRegex)) {
438
+ throw new Error("Invalid case style in `requiredPatterns` option");
439
+ }
440
+ if (value === convertCase(styleName, value)) {
441
+ return "";
442
+ }
443
+ throw new Error(`contain the required pattern: ${requiredPattern}`);
444
+ }
445
+ return originalString;
446
+ });
447
+ if (name === nodeName) {
448
+ throw new Error(`contain the required pattern: ${requiredPattern}`);
449
+ }
450
+ } catch (error2) {
451
+ return {
452
+ errorMessage: error2.message,
453
+ renameToNames: []
454
+ };
455
+ }
456
+ } else if (!requiredPattern.test(name)) {
457
+ return {
458
+ errorMessage: `contain the required pattern: ${requiredPattern}`,
459
+ renameToNames: []
460
+ };
461
+ }
462
+ }
389
463
  const forbidden = forbiddenPatterns?.find((pattern) => pattern.test(name));
390
- if (forbidden)
464
+ if (forbidden) {
391
465
  return {
392
466
  errorMessage: `not contain the forbidden pattern "${forbidden}"`,
393
467
  renameToNames: [name.replace(forbidden, "")]
394
468
  };
395
- if (requiredPatterns && !requiredPatterns.some((pattern) => pattern.test(name)))
396
- return {
397
- errorMessage: `contain the required pattern: ${englishJoinWords(requiredPatterns.map((re) => re.source))}`,
398
- renameToNames: []
399
- };
469
+ }
400
470
  const forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
401
- if (forbiddenPrefix)
471
+ if (forbiddenPrefix) {
402
472
  return {
403
473
  errorMessage: `not have "${forbiddenPrefix}" prefix`,
404
474
  renameToNames: [name.replace(new RegExp(`^${forbiddenPrefix}`), "")]
405
475
  };
476
+ }
406
477
  const forbiddenSuffix = forbiddenSuffixes?.find((suffix2) => name.endsWith(suffix2));
407
- if (forbiddenSuffix)
478
+ if (forbiddenSuffix) {
408
479
  return {
409
480
  errorMessage: `not have "${forbiddenSuffix}" suffix`,
410
481
  renameToNames: [name.replace(new RegExp(`${forbiddenSuffix}$`), "")]
411
482
  };
412
- if (requiredPrefixes && !requiredPrefixes.some((requiredPrefix) => name.startsWith(requiredPrefix)))
483
+ }
484
+ if (requiredPrefixes && !requiredPrefixes.some((requiredPrefix) => name.startsWith(requiredPrefix))) {
413
485
  return {
414
486
  errorMessage: `have one of the following prefixes: ${englishJoinWords(
415
487
  requiredPrefixes
416
488
  )}`,
417
489
  renameToNames: style ? requiredPrefixes.map((prefix2) => convertCase(style, `${prefix2} ${name}`)) : requiredPrefixes.map((prefix2) => `${prefix2}${name}`)
418
490
  };
419
- if (requiredSuffixes && !requiredSuffixes.some((requiredSuffix) => name.endsWith(requiredSuffix)))
491
+ }
492
+ if (requiredSuffixes && !requiredSuffixes.some((requiredSuffix) => name.endsWith(requiredSuffix))) {
420
493
  return {
421
494
  errorMessage: `have one of the following suffixes: ${englishJoinWords(
422
495
  requiredSuffixes
423
496
  )}`,
424
497
  renameToNames: style ? requiredSuffixes.map((suffix2) => convertCase(style, `${name} ${suffix2}`)) : requiredSuffixes.map((suffix2) => `${name}${suffix2}`)
425
498
  };
426
- if (!style)
499
+ }
500
+ if (!style) {
427
501
  return;
428
- if (!StyleToRegex[style].test(name))
502
+ }
503
+ const caseRegex = StyleToRegex[style];
504
+ if (!caseRegex.test(name)) {
429
505
  return {
430
506
  errorMessage: `be in ${style} format`,
431
507
  renameToNames: [convertCase(style, name)]
432
508
  };
509
+ }
433
510
  }
434
- }, checkUnderscore = (isLeading) => (node) => {
435
- if (ignoredNodes.has(node) || node.parent.kind === "Field" && node.parent.alias !== node)
511
+ };
512
+ const checkUnderscore = (isLeading) => (node) => {
513
+ if (ignoredNodes.has(node)) {
436
514
  return;
515
+ }
516
+ if (node.parent.kind === "Field" && node.parent.alias !== node) {
517
+ return;
518
+ }
437
519
  const suggestedName = node.value.replace(isLeading ? /^_+/ : /_+$/, "");
438
520
  report(node, `${isLeading ? "Leading" : "Trailing"} underscores are not allowed`, [
439
521
  suggestedName
440
522
  ]);
441
- }, listeners = {};
442
- allowLeadingUnderscore || (listeners["Name[value=/^_/]"] = checkUnderscore(!0)), allowTrailingUnderscore || (listeners["Name[value=/_$/]"] = checkUnderscore(!1));
523
+ };
524
+ const listeners = {};
525
+ if (!allowLeadingUnderscore) {
526
+ listeners["Name[value=/^_/]"] = checkUnderscore(true);
527
+ }
528
+ if (!allowTrailingUnderscore) {
529
+ listeners["Name[value=/_$/]"] = checkUnderscore(false);
530
+ }
443
531
  const selectors = new Set(
444
532
  [types && TYPES_KINDS, Object.keys(restOptions)].filter((v) => !!v).flat()
445
533
  );
446
- for (const selector of selectors)
534
+ for (const selector of selectors) {
447
535
  listeners[selector] = checkNode(selector);
536
+ }
448
537
  return listeners;
449
538
  }
450
539
  };
@@ -1,13 +1,14 @@
1
1
  import { Kind } from "graphql";
2
2
  import { getLocation } from "../../utils.js";
3
- const RULE_ID = "no-anonymous-operations", rule = {
3
+ const RULE_ID = "no-anonymous-operations";
4
+ const rule = {
4
5
  meta: {
5
6
  type: "suggestion",
6
- hasSuggestions: !0,
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: !0,
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 = {
42
43
  create(context) {
43
44
  return {
44
45
  "OperationDefinition[name=undefined]"(node) {
45
- const [firstSelection] = node.selectionSet.selections, suggestedName = firstSelection.kind === Kind.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
46
+ const [firstSelection] = node.selectionSet.selections;
47
+ const suggestedName = firstSelection.kind === Kind.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
46
48
  context.report({
47
49
  loc: getLocation(node.loc.start, node.operation),
48
50
  messageId: RULE_ID,
@@ -53,7 +55,8 @@ const RULE_ID = "no-anonymous-operations", rule = {
53
55
  {
54
56
  desc: `Rename to \`${suggestedName}\``,
55
57
  fix(fixer) {
56
- const hasQueryKeyword = context.getSourceCode().getText({ range: [node.range[0], node.range[0] + 1] }) !== "{";
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
  import { displayNodeName, requireGraphQLSchema } from "../../utils.js";
2
- const RULE_ID = "no-deprecated", rule = {
2
+ const RULE_ID = "no-deprecated";
3
+ const rule = {
3
4
  meta: {
4
5
  type: "suggestion",
5
- hasSuggestions: !0,
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: !0,
11
+ requiresSchema: true,
11
12
  examples: [
12
13
  {
13
14
  title: "Incorrect (field)",
@@ -79,7 +80,7 @@ const RULE_ID = "no-deprecated", rule = {
79
80
  )
80
81
  }
81
82
  ],
82
- recommended: !0
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 = {
107
108
  }
108
109
  return {
109
110
  EnumValue(node) {
110
- const reason = node.typeInfo().enumValue?.deprecationReason;
111
- reason && report(node, reason);
111
+ const typeInfo = node.typeInfo();
112
+ const reason = typeInfo.enumValue?.deprecationReason;
113
+ if (reason) {
114
+ report(node, reason);
115
+ }
112
116
  },
113
117
  Field(node) {
114
- const reason = node.typeInfo().fieldDef?.deprecationReason;
115
- reason && report(node, reason);
118
+ const typeInfo = node.typeInfo();
119
+ const reason = typeInfo.fieldDef?.deprecationReason;
120
+ if (reason) {
121
+ report(node, reason);
122
+ }
116
123
  },
117
124
  Argument(node) {
118
- const reason = node.typeInfo().argument?.deprecationReason;
119
- reason && report(node, reason);
125
+ const typeInfo = node.typeInfo();
126
+ const reason = typeInfo.argument?.deprecationReason;
127
+ if (reason) {
128
+ report(node, reason);
129
+ }
120
130
  },
121
131
  ObjectValue(node) {
122
132
  const { inputType } = node.typeInfo();
123
- if (inputType && "getFields" in 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, reason = fields[fieldName].deprecationReason;
127
- reason && report(field, 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
  import { Kind } from "graphql";
2
- const RULE_ID = "no-duplicate-fields", rule = {
2
+ const RULE_ID = "no-duplicate-fields";
3
+ const rule = {
3
4
  meta: {
4
5
  type: "suggestion",
5
- hasSuggestions: !0,
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: !0,
11
+ recommended: true,
11
12
  examples: [
12
13
  {
13
14
  title: "Incorrect",
@@ -88,24 +89,30 @@ const RULE_ID = "no-duplicate-fields", 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 === Kind.FIELD && checkNode(set, selection.alias || selection.name);
111
+ for (const selection of node.selections) {
112
+ if (selection.kind === Kind.FIELD) {
113
+ checkNode(set, selection.alias || selection.name);
114
+ }
115
+ }
109
116
  }
110
117
  };
111
118
  }
@@ -1,9 +1,10 @@
1
1
  import { TokenKind } from "graphql";
2
2
  import { getNodeName } from "../../utils.js";
3
- const RULE_ID = "HASHTAG_COMMENT", rule = {
3
+ const RULE_ID = "HASHTAG_COMMENT";
4
+ const rule = {
4
5
  meta: {
5
6
  type: "suggestion",
6
- hasSuggestions: !0,
7
+ hasSuggestions: true,
7
8
  schema: [],
8
9
  messages: {
9
10
  [RULE_ID]: 'Unexpected GraphQL descriptions as hashtag `#` for {{ nodeName }}.\nPrefer using `"""` for multiline, or `"` for a single line description.'
@@ -56,21 +57,27 @@ const RULE_ID = "HASHTAG_COMMENT", rule = {
56
57
  )
57
58
  }
58
59
  ],
59
- recommended: !0
60
+ recommended: true
60
61
  }
61
62
  },
62
63
  create(context) {
64
+ const selector = "Document[definitions.0.kind!=/^(OperationDefinition|FragmentDefinition)$/]";
63
65
  return {
64
- ["Document[definitions.0.kind!=/^(OperationDefinition|FragmentDefinition)$/]"](node) {
65
- let token = node.rawNode().loc.startToken;
66
- for (; token; ) {
66
+ [selector](node) {
67
+ const rawNode = node.rawNode();
68
+ let token = rawNode.loc.startToken;
69
+ while (token) {
67
70
  const { kind, prev, next, value, line, column } = token;
68
71
  if (kind === TokenKind.COMMENT && prev && next) {
69
- const isEslintComment = value.trimStart().startsWith("eslint"), linesAfter = next.line - line;
72
+ const isEslintComment = value.trimStart().startsWith("eslint");
73
+ const linesAfter = next.line - line;
70
74
  if (!isEslintComment && line !== prev.line && next.kind === TokenKind.NAME && linesAfter < 2) {
71
- const sourceCode = context.getSourceCode(), { tokens } = sourceCode.ast, t = tokens.find(
75
+ const sourceCode = context.getSourceCode();
76
+ const { tokens } = sourceCode.ast;
77
+ const t = tokens.find(
72
78
  (token2) => token2.loc.start.line === next.line && token2.loc.start.column === next.column - 1
73
- ), nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
79
+ );
80
+ const nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
74
81
  context.report({
75
82
  messageId: RULE_ID,
76
83
  data: {
@@ -92,8 +99,9 @@ const RULE_ID = "HASHTAG_COMMENT", rule = {
92
99
  });
93
100
  }
94
101
  }
95
- if (!next)
102
+ if (!next) {
96
103
  break;
104
+ }
97
105
  token = next;
98
106
  }
99
107
  }
@@ -1,7 +1,8 @@
1
1
  import { relative } from "node:path";
2
2
  import { visit } from "graphql";
3
3
  import { CWD, requireGraphQLOperations } from "../../utils.js";
4
- const RULE_ID = "no-one-place-fragments", rule = {
4
+ const RULE_ID = "no-one-place-fragments";
5
+ const rule = {
5
6
  meta: {
6
7
  type: "suggestion",
7
8
  docs: {
@@ -47,7 +48,7 @@ const RULE_ID = "no-one-place-fragments", rule = {
47
48
  )
48
49
  }
49
50
  ],
50
- requiresSiblings: !0
51
+ requiresSiblings: true
51
52
  },
52
53
  messages: {
53
54
  [RULE_ID]: 'Fragment `{{fragmentName}}` used only once. Inline him in "{{filePath}}".'
@@ -55,24 +56,30 @@ const RULE_ID = "no-one-place-fragments", rule = {
55
56
  schema: []
56
57
  },
57
58
  create(context) {
58
- const operations = requireGraphQLOperations(RULE_ID, context), allDocuments = [...operations.getOperations(), ...operations.getFragments()], usedFragmentsMap = /* @__PURE__ */ Object.create(null);
59
+ const operations = requireGraphQLOperations(RULE_ID, context);
60
+ const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
61
+ const usedFragmentsMap = /* @__PURE__ */ Object.create(null);
59
62
  for (const { document, filePath } of allDocuments) {
60
63
  const relativeFilePath = relative(CWD, filePath);
61
64
  visit(document, {
62
65
  FragmentSpread({ name }) {
63
66
  const spreadName = name.value;
64
- usedFragmentsMap[spreadName] ||= [], usedFragmentsMap[spreadName].push(relativeFilePath);
67
+ usedFragmentsMap[spreadName] ||= [];
68
+ usedFragmentsMap[spreadName].push(relativeFilePath);
65
69
  }
66
70
  });
67
71
  }
68
72
  return {
69
73
  "FragmentDefinition > Name"(node) {
70
- const fragmentName = node.value, fragmentUsage = usedFragmentsMap[fragmentName];
71
- fragmentUsage.length === 1 && context.report({
72
- node,
73
- messageId: RULE_ID,
74
- data: { fragmentName, filePath: fragmentUsage[0] }
75
- });
74
+ const fragmentName = node.value;
75
+ const fragmentUsage = usedFragmentsMap[fragmentName];
76
+ if (fragmentUsage.length === 1) {
77
+ context.report({
78
+ node,
79
+ messageId: RULE_ID,
80
+ data: { fragmentName, filePath: fragmentUsage[0] }
81
+ });
82
+ }
76
83
  }
77
84
  };
78
85
  }