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

Sign up to get free protection for your applications and to get access to all the features.
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,