@graphql-eslint/eslint-plugin 3.13.1 → 3.14.0-alpha-20221220000306-eefc8db

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 (88) hide show
  1. package/documents.d.ts +3 -3
  2. package/estree-converter/types.d.ts +8 -8
  3. package/estree-converter/utils.d.ts +1 -1
  4. package/index.js +215 -91
  5. package/index.mjs +215 -91
  6. package/package.json +1 -1
  7. package/processor.d.ts +1 -1
  8. package/rules/alphabetize.d.ts +1 -1
  9. package/rules/description-style.d.ts +1 -1
  10. package/rules/graphql-js-validation.d.ts +1 -1
  11. package/rules/input-name.d.ts +1 -1
  12. package/rules/match-document-filename.d.ts +3 -3
  13. package/rules/naming-convention.d.ts +5 -5
  14. package/rules/no-root-type.d.ts +1 -1
  15. package/rules/relay-arguments.d.ts +1 -1
  16. package/rules/relay-edge-types.d.ts +1 -1
  17. package/rules/require-description.d.ts +2 -2
  18. package/rules/require-id-when-available.d.ts +1 -1
  19. package/rules/selection-set-depth.d.ts +1 -1
  20. package/rules/strict-id-in-types.d.ts +1 -1
  21. package/testkit.d.ts +3 -3
  22. package/types.d.ts +15 -15
  23. package/utils.d.ts +1 -1
  24. package/README.md +0 -266
  25. package/docs/README.md +0 -76
  26. package/docs/custom-rules.md +0 -148
  27. package/docs/deprecated-rules.md +0 -21
  28. package/docs/parser-options.md +0 -85
  29. package/docs/parser.md +0 -49
  30. package/docs/rules/alphabetize.md +0 -178
  31. package/docs/rules/description-style.md +0 -54
  32. package/docs/rules/executable-definitions.md +0 -17
  33. package/docs/rules/fields-on-correct-type.md +0 -17
  34. package/docs/rules/fragments-on-composite-type.md +0 -17
  35. package/docs/rules/input-name.md +0 -76
  36. package/docs/rules/known-argument-names.md +0 -17
  37. package/docs/rules/known-directives.md +0 -44
  38. package/docs/rules/known-fragment-names.md +0 -69
  39. package/docs/rules/known-type-names.md +0 -17
  40. package/docs/rules/lone-anonymous-operation.md +0 -17
  41. package/docs/rules/lone-schema-definition.md +0 -17
  42. package/docs/rules/match-document-filename.md +0 -156
  43. package/docs/rules/naming-convention.md +0 -300
  44. package/docs/rules/no-anonymous-operations.md +0 -39
  45. package/docs/rules/no-case-insensitive-enum-values-duplicates.md +0 -43
  46. package/docs/rules/no-deprecated.md +0 -85
  47. package/docs/rules/no-duplicate-fields.md +0 -65
  48. package/docs/rules/no-fragment-cycles.md +0 -17
  49. package/docs/rules/no-hashtag-description.md +0 -59
  50. package/docs/rules/no-root-type.md +0 -53
  51. package/docs/rules/no-scalar-result-type-on-mutation.md +0 -37
  52. package/docs/rules/no-typename-prefix.md +0 -39
  53. package/docs/rules/no-undefined-variables.md +0 -17
  54. package/docs/rules/no-unreachable-types.md +0 -49
  55. package/docs/rules/no-unused-fields.md +0 -62
  56. package/docs/rules/no-unused-fragments.md +0 -17
  57. package/docs/rules/no-unused-variables.md +0 -17
  58. package/docs/rules/one-field-subscriptions.md +0 -17
  59. package/docs/rules/overlapping-fields-can-be-merged.md +0 -17
  60. package/docs/rules/possible-fragment-spread.md +0 -17
  61. package/docs/rules/possible-type-extension.md +0 -15
  62. package/docs/rules/provided-required-arguments.md +0 -17
  63. package/docs/rules/relay-arguments.md +0 -57
  64. package/docs/rules/relay-connection-types.md +0 -42
  65. package/docs/rules/relay-edge-types.md +0 -56
  66. package/docs/rules/relay-page-info.md +0 -32
  67. package/docs/rules/require-deprecation-date.md +0 -57
  68. package/docs/rules/require-deprecation-reason.md +0 -47
  69. package/docs/rules/require-description.md +0 -115
  70. package/docs/rules/require-field-of-type-query-in-mutation-result.md +0 -47
  71. package/docs/rules/require-id-when-available.md +0 -88
  72. package/docs/rules/scalar-leafs.md +0 -17
  73. package/docs/rules/selection-set-depth.md +0 -76
  74. package/docs/rules/strict-id-in-types.md +0 -130
  75. package/docs/rules/unique-argument-names.md +0 -17
  76. package/docs/rules/unique-directive-names-per-location.md +0 -17
  77. package/docs/rules/unique-directive-names.md +0 -17
  78. package/docs/rules/unique-enum-value-names.md +0 -15
  79. package/docs/rules/unique-field-definition-names.md +0 -17
  80. package/docs/rules/unique-fragment-name.md +0 -51
  81. package/docs/rules/unique-input-field-names.md +0 -17
  82. package/docs/rules/unique-operation-name.md +0 -55
  83. package/docs/rules/unique-operation-types.md +0 -17
  84. package/docs/rules/unique-type-names.md +0 -17
  85. package/docs/rules/unique-variable-names.md +0 -17
  86. package/docs/rules/value-literals-of-correct-type.md +0 -17
  87. package/docs/rules/variables-are-input-types.md +0 -17
  88. package/docs/rules/variables-in-allowed-position.md +0 -17
package/documents.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { FragmentDefinitionNode, OperationDefinitionNode, SelectionSetNode, OperationTypeNode } from 'graphql';
2
2
  import { GraphQLProjectConfig } from 'graphql-config';
3
- export declare type FragmentSource = {
3
+ export type FragmentSource = {
4
4
  filePath: string;
5
5
  document: FragmentDefinitionNode;
6
6
  };
7
- export declare type OperationSource = {
7
+ export type OperationSource = {
8
8
  filePath: string;
9
9
  document: OperationDefinitionNode;
10
10
  };
11
- export declare type SiblingOperations = {
11
+ export type SiblingOperations = {
12
12
  available: boolean;
13
13
  getFragment(fragmentName: string): FragmentSource[];
14
14
  getFragments(): FragmentSource[];
@@ -1,15 +1,15 @@
1
1
  import type { ASTNode, TypeInfo, TypeNode, DocumentNode, ExecutableDefinitionNode, NameNode, TypeDefinitionNode, FieldDefinitionNode, ObjectTypeExtensionNode, ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, SelectionSetNode, SelectionNode, DefinitionNode, TypeExtensionNode, DirectiveDefinitionNode, VariableNode, FieldNode, FragmentSpreadNode, EnumValueDefinitionNode, ArgumentNode, NamedTypeNode, EnumTypeDefinitionNode, EnumTypeExtensionNode, InputValueDefinitionNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InlineFragmentNode, VariableDefinitionNode, ListTypeNode, NonNullTypeNode, OperationTypeDefinitionNode } from 'graphql';
2
2
  import type { SourceLocation, Comment } from 'estree';
3
3
  import type { AST } from 'eslint';
4
- declare type SafeGraphQLType<T extends ASTNode> = T extends {
4
+ type SafeGraphQLType<T extends ASTNode> = T extends {
5
5
  type: TypeNode;
6
6
  } ? Omit<T, 'loc' | 'type'> & {
7
7
  gqlType: T['type'];
8
8
  } : Omit<T, 'loc'>;
9
- declare type Writeable<T> = {
9
+ type Writeable<T> = {
10
10
  -readonly [K in keyof T]: T[K];
11
11
  };
12
- export declare type TypeInformation = {
12
+ export type TypeInformation = {
13
13
  argument: ReturnType<TypeInfo['getArgument']>;
14
14
  defaultValue: ReturnType<TypeInfo['getDefaultValue']>;
15
15
  directive: ReturnType<TypeInfo['getDirective']>;
@@ -20,10 +20,10 @@ export declare type TypeInformation = {
20
20
  parentType: ReturnType<TypeInfo['getParentType']>;
21
21
  gqlType: ReturnType<TypeInfo['getType']>;
22
22
  };
23
- declare type NodeWithName = TypeDefinitionNode | TypeExtensionNode | ExecutableDefinitionNode | DirectiveDefinitionNode | FieldDefinitionNode | EnumValueDefinitionNode | FieldNode | FragmentSpreadNode | VariableNode | ArgumentNode | NamedTypeNode;
24
- declare type NodeWithType = FieldDefinitionNode | InputValueDefinitionNode | OperationTypeDefinitionNode | NonNullTypeNode | ListTypeNode | VariableDefinitionNode;
25
- declare type ParentNode<T> = T extends DocumentNode ? AST.Program : T extends DefinitionNode ? DocumentNode : T extends EnumValueDefinitionNode ? EnumTypeDefinitionNode | EnumTypeExtensionNode : T extends InputValueDefinitionNode ? InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode | FieldDefinitionNode | DirectiveDefinitionNode : T extends FieldDefinitionNode ? ObjectTypeDefinitionNode | ObjectTypeExtensionNode | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode : T extends SelectionSetNode ? ExecutableDefinitionNode | FieldNode | InlineFragmentNode : T extends SelectionNode ? SelectionSetNode : T extends TypeNode ? NodeWithType : T extends NameNode ? NodeWithName : unknown;
26
- declare type Node<T extends ASTNode, WithTypeInfo extends boolean> = Writeable<SafeGraphQLType<T>> & {
23
+ type NodeWithName = TypeDefinitionNode | TypeExtensionNode | ExecutableDefinitionNode | DirectiveDefinitionNode | FieldDefinitionNode | EnumValueDefinitionNode | FieldNode | FragmentSpreadNode | VariableNode | ArgumentNode | NamedTypeNode;
24
+ type NodeWithType = FieldDefinitionNode | InputValueDefinitionNode | OperationTypeDefinitionNode | NonNullTypeNode | ListTypeNode | VariableDefinitionNode;
25
+ type ParentNode<T> = T extends DocumentNode ? AST.Program : T extends DefinitionNode ? DocumentNode : T extends EnumValueDefinitionNode ? EnumTypeDefinitionNode | EnumTypeExtensionNode : T extends InputValueDefinitionNode ? InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode | FieldDefinitionNode | DirectiveDefinitionNode : T extends FieldDefinitionNode ? ObjectTypeDefinitionNode | ObjectTypeExtensionNode | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode : T extends SelectionSetNode ? ExecutableDefinitionNode | FieldNode | InlineFragmentNode : T extends SelectionNode ? SelectionSetNode : T extends TypeNode ? NodeWithType : T extends NameNode ? NodeWithName : unknown;
26
+ type Node<T extends ASTNode, WithTypeInfo extends boolean> = Writeable<SafeGraphQLType<T>> & {
27
27
  type: T['kind'];
28
28
  loc: SourceLocation;
29
29
  range: AST.Range;
@@ -32,7 +32,7 @@ declare type Node<T extends ASTNode, WithTypeInfo extends boolean> = Writeable<S
32
32
  rawNode: () => T;
33
33
  parent: ParentNode<T>;
34
34
  };
35
- export declare type GraphQLESTreeNode<T, W extends boolean = false> = T extends ASTNode ? {
35
+ export type GraphQLESTreeNode<T, W extends boolean = false> = T extends ASTNode ? {
36
36
  [K in keyof Node<T, W>]: Node<T, W>[K] extends ReadonlyArray<infer ArrayItem> ? GraphQLESTreeNode<ArrayItem, W>[] : GraphQLESTreeNode<Node<T, W>[K], W>;
37
37
  } : T extends AST.Program ? T & {
38
38
  parent: null;
@@ -3,7 +3,7 @@ import type { Comment, SourceLocation } from 'estree';
3
3
  import type { AST } from 'eslint';
4
4
  export declare const valueFromNode: (valueNode: import("graphql").ValueNode, variables?: import("graphql/jsutils/ObjMap").ObjMap<unknown>) => any;
5
5
  export declare function getBaseType(type: GraphQLOutputType): GraphQLNamedType;
6
- declare type TokenKindValue = '<SOF>' | '!' | '$' | '&' | '(' | ')' | '...' | ':' | '=' | '@' | '[' | ']' | '{' | '|' | '}' | 'Name' | 'Int' | 'Float' | 'String' | 'BlockString' | 'Comment';
6
+ type TokenKindValue = '<SOF>' | '!' | '$' | '&' | '(' | ')' | '...' | ':' | '=' | '@' | '[' | ']' | '{' | '|' | '}' | 'Name' | 'Int' | 'Float' | 'String' | 'BlockString' | 'Comment';
7
7
  export declare function convertToken<T extends 'Line' | 'Block' | TokenKindValue>(token: Token, type: T): Omit<AST.Token, 'type'> & {
8
8
  type: T;
9
9
  };
package/index.js CHANGED
@@ -221,7 +221,8 @@ const ARRAY_DEFAULT_OPTIONS = {
221
221
  };
222
222
  const englishJoinWords = words => new Intl.ListFormat('en-US', { type: 'disjunction' }).format(words);
223
223
 
224
- function validateDocument(context, schema = null, documentNode, rule) {
224
+ function validateDocument({ context, schema = null, documentNode, rule, hasDidYouMeanSuggestions, }) {
225
+ var _a;
225
226
  if (documentNode.definitions.length === 0) {
226
227
  return;
227
228
  }
@@ -245,9 +246,20 @@ function validateDocument(context, schema = null, documentNode, rule) {
245
246
  ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc
246
247
  : token.loc;
247
248
  }
249
+ const didYouMeanContent = (_a = error.message.match(/Did you mean (?<content>.*)\?$/)) === null || _a === void 0 ? void 0 : _a.groups.content;
250
+ const matches = didYouMeanContent ? [...didYouMeanContent.matchAll(/"(?<name>[^"]*)"/g)] : [];
248
251
  context.report({
249
252
  loc,
250
253
  message: error.message,
254
+ suggest: hasDidYouMeanSuggestions
255
+ ? matches.map(match => {
256
+ const { name } = match.groups;
257
+ return {
258
+ desc: `Rename to \`${name}\``,
259
+ fix: fixer => fixer.replaceText(token, name),
260
+ };
261
+ })
262
+ : [],
251
263
  });
252
264
  }
253
265
  }
@@ -301,7 +313,7 @@ const handleMissingFragments = ({ ruleId, context, node }) => {
301
313
  }
302
314
  return node;
303
315
  };
304
- const validationToRule = (ruleId, ruleName, docs, getDocumentNode, schema = []) => {
316
+ const validationToRule = ({ ruleId, ruleName, getDocumentNode, schema = [], hasDidYouMeanSuggestions, }, docs) => {
305
317
  let ruleFn = null;
306
318
  try {
307
319
  ruleFn = require(`graphql/validation/rules/${ruleName}Rule`)[`${ruleName}Rule`];
@@ -325,6 +337,7 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode, schema = [])
325
337
  description: `${docs.description}\n\n> This rule is a wrapper around a \`graphql-js\` validation function.`,
326
338
  },
327
339
  schema,
340
+ hasSuggestions: hasDidYouMeanSuggestions,
328
341
  },
329
342
  create(context) {
330
343
  if (!ruleFn) {
@@ -339,30 +352,79 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode, schema = [])
339
352
  const documentNode = getDocumentNode
340
353
  ? getDocumentNode({ ruleId, context, node: node.rawNode() })
341
354
  : node.rawNode();
342
- validateDocument(context, schema, documentNode, ruleFn);
355
+ validateDocument({
356
+ context,
357
+ schema,
358
+ documentNode,
359
+ rule: ruleFn,
360
+ hasDidYouMeanSuggestions,
361
+ });
343
362
  },
344
363
  };
345
364
  },
346
365
  },
347
366
  };
348
367
  };
349
- const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
368
+ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule({
369
+ ruleId: 'executable-definitions',
370
+ ruleName: 'ExecutableDefinitions',
371
+ }, {
350
372
  category: 'Operations',
351
373
  description: 'A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.',
352
374
  requiresSchema: true,
353
- }), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
375
+ }), validationToRule({
376
+ ruleId: 'fields-on-correct-type',
377
+ ruleName: 'FieldsOnCorrectType',
378
+ hasDidYouMeanSuggestions: true,
379
+ }, {
354
380
  category: 'Operations',
355
381
  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`.',
356
382
  requiresSchema: true,
357
- }), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
383
+ }), validationToRule({
384
+ ruleId: 'fragments-on-composite-type',
385
+ ruleName: 'FragmentsOnCompositeTypes',
386
+ }, {
358
387
  category: 'Operations',
359
388
  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.',
360
389
  requiresSchema: true,
361
- }), validationToRule('known-argument-names', 'KnownArgumentNames', {
390
+ }), validationToRule({
391
+ ruleId: 'known-argument-names',
392
+ ruleName: 'KnownArgumentNames',
393
+ hasDidYouMeanSuggestions: true,
394
+ }, {
362
395
  category: ['Schema', 'Operations'],
363
396
  description: 'A GraphQL field is only valid if all supplied arguments are defined by that field.',
364
397
  requiresSchema: true,
365
- }), validationToRule('known-directives', 'KnownDirectives', {
398
+ }), validationToRule({
399
+ ruleId: 'known-directives',
400
+ ruleName: 'KnownDirectives',
401
+ getDocumentNode({ context, node: documentNode }) {
402
+ const { ignoreClientDirectives = [] } = context.options[0] || {};
403
+ if (ignoreClientDirectives.length === 0) {
404
+ return documentNode;
405
+ }
406
+ const filterDirectives = (node) => ({
407
+ ...node,
408
+ directives: node.directives.filter(directive => !ignoreClientDirectives.includes(directive.name.value)),
409
+ });
410
+ return graphql.visit(documentNode, {
411
+ Field: filterDirectives,
412
+ OperationDefinition: filterDirectives,
413
+ });
414
+ },
415
+ schema: {
416
+ type: 'array',
417
+ maxItems: 1,
418
+ items: {
419
+ type: 'object',
420
+ additionalProperties: false,
421
+ required: ['ignoreClientDirectives'],
422
+ properties: {
423
+ ignoreClientDirectives: ARRAY_DEFAULT_OPTIONS,
424
+ },
425
+ },
426
+ },
427
+ }, {
366
428
  category: ['Schema', 'Operations'],
367
429
  description: 'A GraphQL document is only valid if all `@directive`s are known by the schema and legally positioned.',
368
430
  requiresSchema: true,
@@ -379,31 +441,11 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
379
441
  `,
380
442
  },
381
443
  ],
382
- }, ({ context, node: documentNode }) => {
383
- const { ignoreClientDirectives = [] } = context.options[0] || {};
384
- if (ignoreClientDirectives.length === 0) {
385
- return documentNode;
386
- }
387
- const filterDirectives = (node) => ({
388
- ...node,
389
- directives: node.directives.filter(directive => !ignoreClientDirectives.includes(directive.name.value)),
390
- });
391
- return graphql.visit(documentNode, {
392
- Field: filterDirectives,
393
- OperationDefinition: filterDirectives,
394
- });
444
+ }), validationToRule({
445
+ ruleId: 'known-fragment-names',
446
+ ruleName: 'KnownFragmentNames',
447
+ getDocumentNode: handleMissingFragments,
395
448
  }, {
396
- type: 'array',
397
- maxItems: 1,
398
- items: {
399
- type: 'object',
400
- additionalProperties: false,
401
- required: ['ignoreClientDirectives'],
402
- properties: {
403
- ignoreClientDirectives: ARRAY_DEFAULT_OPTIONS,
404
- },
405
- },
406
- }), validationToRule('known-fragment-names', 'KnownFragmentNames', {
407
449
  category: 'Operations',
408
450
  description: 'A GraphQL document is only valid if all `...Fragment` fragment spreads refer to fragments defined in the same document.',
409
451
  requiresSchema: true,
@@ -454,138 +496,220 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
454
496
  `,
455
497
  },
456
498
  ],
457
- }, handleMissingFragments), validationToRule('known-type-names', 'KnownTypeNames', {
499
+ }), validationToRule({
500
+ ruleId: 'known-type-names',
501
+ ruleName: 'KnownTypeNames',
502
+ hasDidYouMeanSuggestions: true,
503
+ }, {
458
504
  category: ['Schema', 'Operations'],
459
505
  description: 'A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.',
460
506
  requiresSchema: true,
461
- }), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
507
+ }), validationToRule({
508
+ ruleId: 'lone-anonymous-operation',
509
+ ruleName: 'LoneAnonymousOperation',
510
+ }, {
462
511
  category: 'Operations',
463
512
  description: 'A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.',
464
513
  requiresSchema: true,
465
- }), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
514
+ }), validationToRule({
515
+ ruleId: 'lone-schema-definition',
516
+ ruleName: 'LoneSchemaDefinition',
517
+ }, {
466
518
  category: 'Schema',
467
519
  description: 'A GraphQL document is only valid if it contains only one schema definition.',
468
- }), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
520
+ }), validationToRule({
521
+ ruleId: 'no-fragment-cycles',
522
+ ruleName: 'NoFragmentCycles',
523
+ }, {
469
524
  category: 'Operations',
470
525
  description: 'A GraphQL fragment is only valid when it does not have cycles in fragments usage.',
471
526
  requiresSchema: true,
472
- }), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
527
+ }), validationToRule({
528
+ ruleId: 'no-undefined-variables',
529
+ ruleName: 'NoUndefinedVariables',
530
+ getDocumentNode: handleMissingFragments,
531
+ }, {
473
532
  category: 'Operations',
474
533
  description: 'A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.',
475
534
  requiresSchema: true,
476
535
  requiresSiblings: true,
477
- }, handleMissingFragments), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
536
+ }), validationToRule({
537
+ ruleId: 'no-unused-fragments',
538
+ ruleName: 'NoUnusedFragments',
539
+ getDocumentNode: ({ ruleId, context, node }) => {
540
+ const siblings = requireSiblingsOperations(ruleId, context);
541
+ const FilePathToDocumentsMap = [
542
+ ...siblings.getOperations(),
543
+ ...siblings.getFragments(),
544
+ ].reduce((map, { filePath, document }) => {
545
+ var _a;
546
+ (_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
547
+ map[filePath].push(document);
548
+ return map;
549
+ }, Object.create(null));
550
+ const getParentNode = (currentFilePath, node) => {
551
+ const { fragmentDefs } = getFragmentDefsAndFragmentSpreads(node);
552
+ if (fragmentDefs.size === 0) {
553
+ return node;
554
+ }
555
+ // skip iteration over documents for current filepath
556
+ delete FilePathToDocumentsMap[currentFilePath];
557
+ for (const [filePath, documents] of Object.entries(FilePathToDocumentsMap)) {
558
+ const missingFragments = getMissingFragments({
559
+ kind: graphql.Kind.DOCUMENT,
560
+ definitions: documents,
561
+ });
562
+ const isCurrentFileImportFragment = missingFragments.some(fragment => fragmentDefs.has(fragment));
563
+ if (isCurrentFileImportFragment) {
564
+ return getParentNode(filePath, {
565
+ kind: graphql.Kind.DOCUMENT,
566
+ definitions: [...node.definitions, ...documents],
567
+ });
568
+ }
569
+ }
570
+ return node;
571
+ };
572
+ return getParentNode(context.getFilename(), node);
573
+ },
574
+ }, {
478
575
  category: 'Operations',
479
576
  description: 'A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.',
480
577
  requiresSchema: true,
481
578
  requiresSiblings: true,
482
- }, ({ ruleId, context, node }) => {
483
- const siblings = requireSiblingsOperations(ruleId, context);
484
- const FilePathToDocumentsMap = [
485
- ...siblings.getOperations(),
486
- ...siblings.getFragments(),
487
- ].reduce((map, { filePath, document }) => {
488
- var _a;
489
- (_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
490
- map[filePath].push(document);
491
- return map;
492
- }, Object.create(null));
493
- const getParentNode = (currentFilePath, node) => {
494
- const { fragmentDefs } = getFragmentDefsAndFragmentSpreads(node);
495
- if (fragmentDefs.size === 0) {
496
- return node;
497
- }
498
- // skip iteration over documents for current filepath
499
- delete FilePathToDocumentsMap[currentFilePath];
500
- for (const [filePath, documents] of Object.entries(FilePathToDocumentsMap)) {
501
- const missingFragments = getMissingFragments({
502
- kind: graphql.Kind.DOCUMENT,
503
- definitions: documents,
504
- });
505
- const isCurrentFileImportFragment = missingFragments.some(fragment => fragmentDefs.has(fragment));
506
- if (isCurrentFileImportFragment) {
507
- return getParentNode(filePath, {
508
- kind: graphql.Kind.DOCUMENT,
509
- definitions: [...node.definitions, ...documents],
510
- });
511
- }
512
- }
513
- return node;
514
- };
515
- return getParentNode(context.getFilename(), node);
516
- }), validationToRule('no-unused-variables', 'NoUnusedVariables', {
579
+ }), validationToRule({
580
+ ruleId: 'no-unused-variables',
581
+ ruleName: 'NoUnusedVariables',
582
+ getDocumentNode: handleMissingFragments,
583
+ }, {
517
584
  category: 'Operations',
518
585
  description: 'A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.',
519
586
  requiresSchema: true,
520
587
  requiresSiblings: true,
521
- }, handleMissingFragments), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
588
+ }), validationToRule({
589
+ ruleId: 'overlapping-fields-can-be-merged',
590
+ ruleName: 'OverlappingFieldsCanBeMerged',
591
+ }, {
522
592
  category: 'Operations',
523
593
  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.',
524
594
  requiresSchema: true,
525
- }), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
595
+ }), validationToRule({
596
+ ruleId: 'possible-fragment-spread',
597
+ ruleName: 'PossibleFragmentSpreads',
598
+ }, {
526
599
  category: 'Operations',
527
600
  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.',
528
601
  requiresSchema: true,
529
- }), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
602
+ }), validationToRule({
603
+ ruleId: 'possible-type-extension',
604
+ ruleName: 'PossibleTypeExtensions',
605
+ hasDidYouMeanSuggestions: true,
606
+ }, {
530
607
  category: 'Schema',
531
608
  description: 'A type extension is only valid if the type is defined and has the same kind.',
532
609
  // TODO: add in graphql-eslint v4
533
610
  recommended: false,
534
611
  requiresSchema: true,
535
612
  isDisabledForAllConfig: true,
536
- }), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
613
+ }), validationToRule({
614
+ ruleId: 'provided-required-arguments',
615
+ ruleName: 'ProvidedRequiredArguments',
616
+ }, {
537
617
  category: ['Schema', 'Operations'],
538
618
  description: 'A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.',
539
619
  requiresSchema: true,
540
- }), validationToRule('scalar-leafs', 'ScalarLeafs', {
620
+ }), validationToRule({
621
+ ruleId: 'scalar-leafs',
622
+ ruleName: 'ScalarLeafs',
623
+ hasDidYouMeanSuggestions: true,
624
+ }, {
541
625
  category: 'Operations',
542
626
  description: 'A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.',
543
627
  requiresSchema: true,
544
- }), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
628
+ }), validationToRule({
629
+ ruleId: 'one-field-subscriptions',
630
+ ruleName: 'SingleFieldSubscriptions',
631
+ }, {
545
632
  category: 'Operations',
546
633
  description: 'A GraphQL subscription is valid only if it contains a single root field.',
547
634
  requiresSchema: true,
548
- }), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
635
+ }), validationToRule({
636
+ ruleId: 'unique-argument-names',
637
+ ruleName: 'UniqueArgumentNames',
638
+ }, {
549
639
  category: 'Operations',
550
640
  description: 'A GraphQL field or directive is only valid if all supplied arguments are uniquely named.',
551
641
  requiresSchema: true,
552
- }), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
642
+ }), validationToRule({
643
+ ruleId: 'unique-directive-names',
644
+ ruleName: 'UniqueDirectiveNames',
645
+ }, {
553
646
  category: 'Schema',
554
647
  description: 'A GraphQL document is only valid if all defined directives have unique names.',
555
- }), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
648
+ }), validationToRule({
649
+ ruleId: 'unique-directive-names-per-location',
650
+ ruleName: 'UniqueDirectivesPerLocation',
651
+ }, {
556
652
  category: ['Schema', 'Operations'],
557
653
  description: 'A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.',
558
654
  requiresSchema: true,
559
- }), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
655
+ }), validationToRule({
656
+ ruleId: 'unique-enum-value-names',
657
+ ruleName: 'UniqueEnumValueNames',
658
+ }, {
560
659
  category: 'Schema',
561
660
  description: 'A GraphQL enum type is only valid if all its values are uniquely named.',
562
661
  recommended: false,
563
662
  isDisabledForAllConfig: true,
564
- }), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
663
+ }), validationToRule({
664
+ ruleId: 'unique-field-definition-names',
665
+ ruleName: 'UniqueFieldDefinitionNames',
666
+ }, {
565
667
  category: 'Schema',
566
668
  description: 'A GraphQL complex type is only valid if all its fields are uniquely named.',
567
- }), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
669
+ }), validationToRule({
670
+ ruleId: 'unique-input-field-names',
671
+ ruleName: 'UniqueInputFieldNames',
672
+ }, {
568
673
  category: 'Operations',
569
674
  description: 'A GraphQL input object value is only valid if all supplied fields are uniquely named.',
570
- }), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
675
+ }), validationToRule({
676
+ ruleId: 'unique-operation-types',
677
+ ruleName: 'UniqueOperationTypes',
678
+ }, {
571
679
  category: 'Schema',
572
680
  description: 'A GraphQL document is only valid if it has only one type per operation.',
573
- }), validationToRule('unique-type-names', 'UniqueTypeNames', {
681
+ }), validationToRule({
682
+ ruleId: 'unique-type-names',
683
+ ruleName: 'UniqueTypeNames',
684
+ }, {
574
685
  category: 'Schema',
575
686
  description: 'A GraphQL document is only valid if all defined types have unique names.',
576
- }), validationToRule('unique-variable-names', 'UniqueVariableNames', {
687
+ }), validationToRule({
688
+ ruleId: 'unique-variable-names',
689
+ ruleName: 'UniqueVariableNames',
690
+ }, {
577
691
  category: 'Operations',
578
692
  description: 'A GraphQL operation is only valid if all its variables are uniquely named.',
579
693
  requiresSchema: true,
580
- }), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
694
+ }), validationToRule({
695
+ ruleId: 'value-literals-of-correct-type',
696
+ ruleName: 'ValuesOfCorrectType',
697
+ hasDidYouMeanSuggestions: true,
698
+ }, {
581
699
  category: 'Operations',
582
700
  description: 'A GraphQL document is only valid if all value literals are of the type expected at their position.',
583
701
  requiresSchema: true,
584
- }), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
702
+ }), validationToRule({
703
+ ruleId: 'variables-are-input-types',
704
+ ruleName: 'VariablesAreInputTypes',
705
+ }, {
585
706
  category: 'Operations',
586
707
  description: 'A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).',
587
708
  requiresSchema: true,
588
- }), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
709
+ }), validationToRule({
710
+ ruleId: 'variables-in-allowed-position',
711
+ ruleName: 'VariablesInAllowedPosition',
712
+ }, {
589
713
  category: 'Operations',
590
714
  description: 'Variables passed to field arguments conform to type.',
591
715
  requiresSchema: true,