@graphql-eslint/eslint-plugin 4.0.0-alpha.8 → 4.0.0

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 (136) hide show
  1. package/cjs/cache.js +1 -2
  2. package/cjs/configs/index.d.cts +427 -10
  3. package/cjs/configs/index.js +1 -2
  4. package/cjs/configs/operations-all.d.cts +8 -8
  5. package/cjs/configs/operations-all.js +30 -33
  6. package/cjs/configs/operations-recommended.d.cts +35 -35
  7. package/cjs/configs/operations-recommended.js +56 -59
  8. package/cjs/configs/schema-all.d.cts +12 -12
  9. package/cjs/configs/schema-all.js +26 -29
  10. package/cjs/configs/schema-recommended.d.cts +23 -23
  11. package/cjs/configs/schema-recommended.js +70 -73
  12. package/cjs/configs/schema-relay.d.cts +5 -5
  13. package/cjs/configs/schema-relay.js +14 -17
  14. package/cjs/documents.js +8 -4
  15. package/cjs/estree-converter/converter.js +1 -2
  16. package/cjs/estree-converter/utils.js +1 -2
  17. package/cjs/graphql-config.d.cts +6 -1
  18. package/cjs/graphql-config.js +9 -3
  19. package/cjs/index.d.cts +436 -16
  20. package/cjs/index.js +2 -3
  21. package/cjs/meta.js +1 -2
  22. package/cjs/parser.js +2 -6
  23. package/cjs/processor.js +5 -2
  24. package/cjs/rules/alphabetize/index.js +1 -2
  25. package/cjs/rules/description-style/index.js +1 -2
  26. package/cjs/rules/graphql-js-validation.js +4 -5
  27. package/cjs/rules/index.d.cts +6 -4
  28. package/cjs/rules/index.js +1 -2
  29. package/cjs/rules/input-name/index.js +1 -2
  30. package/cjs/rules/lone-executable-definition/index.js +1 -2
  31. package/cjs/rules/match-document-filename/index.js +1 -2
  32. package/cjs/rules/naming-convention/index.js +4 -3
  33. package/cjs/rules/no-anonymous-operations/index.js +1 -2
  34. package/cjs/rules/no-deprecated/index.js +20 -8
  35. package/cjs/rules/no-duplicate-fields/index.js +1 -2
  36. package/cjs/rules/no-hashtag-description/index.js +1 -2
  37. package/cjs/rules/no-one-place-fragments/index.js +2 -3
  38. package/cjs/rules/no-root-type/index.js +2 -3
  39. package/cjs/rules/no-scalar-result-type-on-mutation/index.js +2 -3
  40. package/cjs/rules/no-typename-prefix/index.js +1 -2
  41. package/cjs/rules/no-unreachable-types/index.js +4 -6
  42. package/cjs/rules/no-unused-fields/index.d.cts +24 -3
  43. package/cjs/rules/no-unused-fields/index.js +119 -10
  44. package/cjs/rules/relay-arguments/index.js +2 -3
  45. package/cjs/rules/relay-connection-types/index.js +1 -2
  46. package/cjs/rules/relay-edge-types/index.js +2 -3
  47. package/cjs/rules/relay-page-info/index.js +2 -3
  48. package/cjs/rules/require-deprecation-date/index.js +1 -2
  49. package/cjs/rules/require-deprecation-reason/index.js +1 -2
  50. package/cjs/rules/require-description/index.js +2 -8
  51. package/cjs/rules/require-field-of-type-query-in-mutation-result/index.js +2 -3
  52. package/cjs/rules/require-import-fragment/index.js +9 -5
  53. package/cjs/rules/require-nullable-fields-with-oneof/index.js +1 -2
  54. package/cjs/rules/require-nullable-result-in-root/index.js +2 -3
  55. package/cjs/rules/require-selections/index.js +14 -8
  56. package/cjs/rules/require-type-pattern-with-oneof/index.js +1 -2
  57. package/cjs/rules/selection-set-depth/index.js +4 -5
  58. package/cjs/rules/strict-id-in-types/index.js +2 -3
  59. package/cjs/rules/unique-enum-value-names/index.js +1 -2
  60. package/cjs/rules/unique-fragment-name/index.js +2 -3
  61. package/cjs/rules/unique-operation-name/index.js +1 -2
  62. package/cjs/schema.js +1 -2
  63. package/cjs/siblings.js +1 -2
  64. package/cjs/types.d.cts +1 -0
  65. package/cjs/utils.d.cts +4 -4
  66. package/cjs/utils.js +8 -9
  67. package/esm/cache.js +0 -1
  68. package/esm/configs/index.d.ts +427 -10
  69. package/esm/configs/index.js +0 -1
  70. package/esm/configs/operations-all.d.ts +7 -7
  71. package/esm/configs/operations-all.js +28 -33
  72. package/esm/configs/operations-recommended.d.ts +34 -34
  73. package/esm/configs/operations-recommended.js +54 -59
  74. package/esm/configs/schema-all.d.ts +11 -11
  75. package/esm/configs/schema-all.js +24 -29
  76. package/esm/configs/schema-recommended.d.ts +22 -22
  77. package/esm/configs/schema-recommended.js +68 -73
  78. package/esm/configs/schema-relay.d.ts +4 -4
  79. package/esm/configs/schema-relay.js +12 -17
  80. package/esm/documents.js +8 -4
  81. package/esm/estree-converter/converter.js +0 -1
  82. package/esm/estree-converter/utils.js +0 -1
  83. package/esm/graphql-config.d.ts +6 -1
  84. package/esm/graphql-config.js +8 -2
  85. package/esm/index.d.ts +436 -16
  86. package/esm/index.js +3 -4
  87. package/esm/meta.js +1 -2
  88. package/esm/parser.js +3 -7
  89. package/esm/processor.js +4 -1
  90. package/esm/rules/alphabetize/index.js +0 -1
  91. package/esm/rules/description-style/index.js +0 -1
  92. package/esm/rules/graphql-js-validation.js +5 -6
  93. package/esm/rules/index.d.ts +6 -4
  94. package/esm/rules/index.js +0 -1
  95. package/esm/rules/input-name/index.js +0 -1
  96. package/esm/rules/lone-executable-definition/index.js +0 -1
  97. package/esm/rules/match-document-filename/index.js +0 -1
  98. package/esm/rules/naming-convention/index.js +3 -2
  99. package/esm/rules/no-anonymous-operations/index.js +0 -1
  100. package/esm/rules/no-deprecated/index.js +20 -8
  101. package/esm/rules/no-duplicate-fields/index.js +0 -1
  102. package/esm/rules/no-hashtag-description/index.js +0 -1
  103. package/esm/rules/no-one-place-fragments/index.js +2 -3
  104. package/esm/rules/no-root-type/index.js +2 -3
  105. package/esm/rules/no-scalar-result-type-on-mutation/index.js +2 -3
  106. package/esm/rules/no-typename-prefix/index.js +0 -1
  107. package/esm/rules/no-unreachable-types/index.js +5 -7
  108. package/esm/rules/no-unused-fields/index.d.ts +24 -3
  109. package/esm/rules/no-unused-fields/index.js +119 -10
  110. package/esm/rules/relay-arguments/index.js +2 -3
  111. package/esm/rules/relay-connection-types/index.js +0 -1
  112. package/esm/rules/relay-edge-types/index.js +2 -3
  113. package/esm/rules/relay-page-info/index.js +2 -3
  114. package/esm/rules/require-deprecation-date/index.js +0 -1
  115. package/esm/rules/require-deprecation-reason/index.js +0 -1
  116. package/esm/rules/require-description/index.js +2 -8
  117. package/esm/rules/require-field-of-type-query-in-mutation-result/index.js +2 -3
  118. package/esm/rules/require-import-fragment/index.js +9 -5
  119. package/esm/rules/require-nullable-fields-with-oneof/index.js +0 -1
  120. package/esm/rules/require-nullable-result-in-root/index.js +2 -3
  121. package/esm/rules/require-selections/index.js +15 -9
  122. package/esm/rules/require-type-pattern-with-oneof/index.js +0 -1
  123. package/esm/rules/selection-set-depth/index.js +4 -5
  124. package/esm/rules/strict-id-in-types/index.js +2 -3
  125. package/esm/rules/unique-enum-value-names/index.js +0 -1
  126. package/esm/rules/unique-fragment-name/index.js +2 -3
  127. package/esm/rules/unique-operation-name/index.js +0 -1
  128. package/esm/schema.js +0 -1
  129. package/esm/siblings.js +0 -1
  130. package/esm/types.d.ts +1 -0
  131. package/esm/utils.d.ts +4 -4
  132. package/esm/utils.js +8 -9
  133. package/index.browser.js +514 -426
  134. package/package.json +2 -2
  135. package/cjs/chunk-UIAXBAMD.js +0 -8
  136. package/esm/chunk-UIAXBAMD.js +0 -8
@@ -38,17 +38,17 @@ declare const rules: {
38
38
  suffix?: string | undefined;
39
39
  prefix?: string | undefined;
40
40
  } | undefined;
41
- mutation?: (CaseStyle | "matchDocumentStyle") | {
41
+ query?: (CaseStyle | "matchDocumentStyle") | {
42
42
  style?: (CaseStyle | "matchDocumentStyle") | undefined;
43
43
  suffix?: string | undefined;
44
44
  prefix?: string | undefined;
45
45
  } | undefined;
46
- subscription?: (CaseStyle | "matchDocumentStyle") | {
46
+ mutation?: (CaseStyle | "matchDocumentStyle") | {
47
47
  style?: (CaseStyle | "matchDocumentStyle") | undefined;
48
48
  suffix?: string | undefined;
49
49
  prefix?: string | undefined;
50
50
  } | undefined;
51
- query?: (CaseStyle | "matchDocumentStyle") | {
51
+ subscription?: (CaseStyle | "matchDocumentStyle") | {
52
52
  style?: (CaseStyle | "matchDocumentStyle") | undefined;
53
53
  suffix?: string | undefined;
54
54
  prefix?: string | undefined;
@@ -81,7 +81,9 @@ declare const rules: {
81
81
  'no-scalar-result-type-on-mutation': GraphQLESLintRule;
82
82
  'no-typename-prefix': GraphQLESLintRule;
83
83
  'no-unreachable-types': GraphQLESLintRule;
84
- 'no-unused-fields': GraphQLESLintRule;
84
+ 'no-unused-fields': GraphQLESLintRule<{
85
+ ignoredFieldSelectors?: string[] | undefined;
86
+ }[]>;
85
87
  'relay-arguments': GraphQLESLintRule<{
86
88
  includeBoth: boolean;
87
89
  }[], true>;
@@ -1,4 +1,3 @@
1
- import "../chunk-UIAXBAMD.js";
2
1
  import { rule as alphabetize } from "./alphabetize/index.js";
3
2
  import { rule as descriptionStyle } from "./description-style/index.js";
4
3
  import { GRAPHQL_JS_VALIDATIONS } from "./graphql-js-validation.js";
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import {
3
2
  Kind
4
3
  } from "graphql";
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { OperationTypeNode } from "graphql";
3
2
  import { ARRAY_DEFAULT_OPTIONS, getLocation, pascalCase } from "../../utils.js";
4
3
  const RULE_ID = "lone-executable-definition", definitionTypes = ["fragment", ...Object.values(OperationTypeNode)], schema = {
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { basename, extname } from "node:path";
3
2
  import { Kind } from "graphql";
4
3
  import {
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
2
  import {
4
3
  ARRAY_DEFAULT_OPTIONS,
@@ -384,12 +383,14 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
384
383
  };
385
384
  }
386
385
  }, checkUnderscore = (isLeading) => (node) => {
386
+ if (node.parent.kind === "Field" && node.parent.alias !== node)
387
+ return;
387
388
  const suggestedName = node.value.replace(isLeading ? /^_+/ : /_+$/, "");
388
389
  report(node, `${isLeading ? "Leading" : "Trailing"} underscores are not allowed`, [
389
390
  suggestedName
390
391
  ]);
391
392
  }, listeners = {};
392
- allowLeadingUnderscore || (listeners["Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])"] = checkUnderscore(!0)), allowTrailingUnderscore || (listeners["Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])"] = checkUnderscore(!1));
393
+ allowLeadingUnderscore || (listeners["Name[value=/^_/]"] = checkUnderscore(!0)), allowTrailingUnderscore || (listeners["Name[value=/_$/]"] = checkUnderscore(!1));
393
394
  const selectors = new Set(
394
395
  [types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(truthy)
395
396
  );
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
2
  import { getLocation } from "../../utils.js";
4
3
  const RULE_ID = "no-anonymous-operations", rule = {
@@ -1,6 +1,4 @@
1
- import "../../chunk-UIAXBAMD.js";
2
- import { Kind } from "graphql";
3
- import { requireGraphQLSchemaFromContext } from "../../utils.js";
1
+ import { displayNodeName, requireGraphQLSchema } from "../../utils.js";
4
2
  const RULE_ID = "no-deprecated", rule = {
5
3
  meta: {
6
4
  type: "suggestion",
@@ -84,24 +82,24 @@ const RULE_ID = "no-deprecated", rule = {
84
82
  recommended: !0
85
83
  },
86
84
  messages: {
87
- [RULE_ID]: "This {{ type }} is marked as deprecated in your GraphQL schema (reason: {{ reason }})"
85
+ [RULE_ID]: "{{ type }} is marked as deprecated in your GraphQL schema (reason: {{ reason }})"
88
86
  },
89
87
  schema: []
90
88
  },
91
89
  create(context) {
92
- requireGraphQLSchemaFromContext(RULE_ID, context);
90
+ requireGraphQLSchema(RULE_ID, context);
93
91
  function report(node, reason) {
94
- const nodeName = node.kind === Kind.ENUM ? node.value : node.name.value, nodeType = node.kind === Kind.ENUM ? "enum value" : "field";
92
+ const nodeType = displayNodeName(node);
95
93
  context.report({
96
94
  node,
97
95
  messageId: RULE_ID,
98
96
  data: {
99
- type: nodeType,
97
+ type: nodeType[0].toUpperCase() + nodeType.slice(1),
100
98
  reason
101
99
  },
102
100
  suggest: [
103
101
  {
104
- desc: `Remove \`${nodeName}\` ${nodeType}`,
102
+ desc: `Remove ${nodeType}`,
105
103
  fix: (fixer) => fixer.remove(node)
106
104
  }
107
105
  ]
@@ -115,6 +113,20 @@ const RULE_ID = "no-deprecated", rule = {
115
113
  Field(node) {
116
114
  const reason = node.typeInfo().fieldDef?.deprecationReason;
117
115
  reason && report(node, reason);
116
+ },
117
+ Argument(node) {
118
+ const reason = node.typeInfo().argument?.deprecationReason;
119
+ reason && report(node, reason);
120
+ },
121
+ ObjectValue(node) {
122
+ const { inputType } = node.typeInfo();
123
+ if (inputType && "getFields" in inputType) {
124
+ const fields = inputType.getFields();
125
+ for (const field of node.fields) {
126
+ const fieldName = field.name.value, reason = fields[fieldName].deprecationReason;
127
+ reason && report(field, reason);
128
+ }
129
+ }
118
130
  }
119
131
  };
120
132
  }
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
2
  const RULE_ID = "no-duplicate-fields", rule = {
4
3
  meta: {
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { TokenKind } from "graphql";
3
2
  import { getNodeName } from "../../utils.js";
4
3
  const RULE_ID = "HASHTAG_COMMENT", rule = {
@@ -1,7 +1,6 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { relative } from "node:path";
3
2
  import { visit } from "graphql";
4
- import { CWD, requireSiblingsOperations } from "../../utils.js";
3
+ import { CWD, requireGraphQLOperations } from "../../utils.js";
5
4
  const RULE_ID = "no-one-place-fragments", rule = {
6
5
  meta: {
7
6
  type: "suggestion",
@@ -56,7 +55,7 @@ const RULE_ID = "no-one-place-fragments", rule = {
56
55
  schema: []
57
56
  },
58
57
  create(context) {
59
- const operations = requireSiblingsOperations(RULE_ID, context), allDocuments = [...operations.getOperations(), ...operations.getFragments()], usedFragmentsMap = /* @__PURE__ */ Object.create(null);
58
+ const operations = requireGraphQLOperations(RULE_ID, context), allDocuments = [...operations.getOperations(), ...operations.getFragments()], usedFragmentsMap = /* @__PURE__ */ Object.create(null);
60
59
  for (const { document, filePath } of allDocuments) {
61
60
  const relativeFilePath = relative(CWD, filePath);
62
61
  visit(document, {
@@ -1,5 +1,4 @@
1
- import "../../chunk-UIAXBAMD.js";
2
- import { ARRAY_DEFAULT_OPTIONS, requireGraphQLSchemaFromContext, truthy } from "../../utils.js";
1
+ import { ARRAY_DEFAULT_OPTIONS, requireGraphQLSchema, truthy } from "../../utils.js";
3
2
  const schema = {
4
3
  type: "array",
5
4
  minItems: 1,
@@ -57,7 +56,7 @@ const schema = {
57
56
  schema
58
57
  },
59
58
  create(context) {
60
- const schema2 = requireGraphQLSchemaFromContext("no-root-type", context), disallow = new Set(context.options[0].disallow), rootTypeNames = [
59
+ const schema2 = requireGraphQLSchema("no-root-type", context), disallow = new Set(context.options[0].disallow), rootTypeNames = [
61
60
  disallow.has("mutation") && schema2.getMutationType(),
62
61
  disallow.has("subscription") && schema2.getSubscriptionType()
63
62
  ].filter(truthy).map((type) => type.name).join("|");
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { isScalarType, Kind } from "graphql";
3
- import { getNodeName, requireGraphQLSchemaFromContext } from "../../utils.js";
2
+ import { getNodeName, requireGraphQLSchema } from "../../utils.js";
4
3
  const RULE_ID = "no-scalar-result-type-on-mutation", rule = {
5
4
  meta: {
6
5
  type: "suggestion",
@@ -38,7 +37,7 @@ const RULE_ID = "no-scalar-result-type-on-mutation", rule = {
38
37
  schema: []
39
38
  },
40
39
  create(context) {
41
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context), mutationType = schema.getMutationType();
40
+ const schema = requireGraphQLSchema(RULE_ID, context), mutationType = schema.getMutationType();
42
41
  return mutationType ? {
43
42
  [[
44
43
  `:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}]`,
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  const NO_TYPENAME_PREFIX = "NO_TYPENAME_PREFIX", rule = {
3
2
  meta: {
4
3
  type: "suggestion",
@@ -1,13 +1,13 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import {
3
2
  DirectiveLocation,
3
+ getNamedType,
4
4
  isInterfaceType,
5
5
  Kind,
6
6
  visit
7
7
  } from "graphql";
8
8
  import lowerCase from "lodash.lowercase";
9
9
  import { ModuleCache } from "../../cache.js";
10
- import { getTypeName, requireGraphQLSchemaFromContext } from "../../utils.js";
10
+ import { getTypeName, requireGraphQLSchema } from "../../utils.js";
11
11
  const RULE_ID = "no-unreachable-types", KINDS = [
12
12
  Kind.DIRECTIVE_DEFINITION,
13
13
  Kind.OBJECT_TYPE_DEFINITION,
@@ -67,10 +67,8 @@ function getReachableTypes(schema) {
67
67
  for (const node of schema.getDirectives())
68
68
  if (node.locations.some((location) => RequestDirectiveLocations.has(location))) {
69
69
  reachableTypes.add(node.name);
70
- for (const arg of node.args) {
71
- const argTypeName = "name" in arg.type && arg.type.name;
72
- argTypeName && reachableTypes.add(argTypeName);
73
- }
70
+ for (const arg of node.args)
71
+ reachableTypes.add(getNamedType(arg.type).name);
74
72
  }
75
73
  return reachableTypesCache.set(schema, reachableTypes), reachableTypes;
76
74
  }
@@ -125,7 +123,7 @@ const rule = {
125
123
  hasSuggestions: !0
126
124
  },
127
125
  create(context) {
128
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context), reachableTypes = getReachableTypes(schema);
126
+ const schema = requireGraphQLSchema(RULE_ID, context), reachableTypes = getReachableTypes(schema);
129
127
  return {
130
128
  [`:matches(${KINDS}) > .name`](node) {
131
129
  const typeName = node.value;
@@ -1,13 +1,34 @@
1
+ import { FromSchema } from 'json-schema-to-ts';
1
2
  import { GraphQLESLintRule } from '../../types.js';
2
3
  import 'eslint';
3
4
  import 'estree';
4
5
  import 'graphql';
5
6
  import 'graphql-config';
6
- import 'json-schema-to-ts';
7
7
  import '../../estree-converter/types.js';
8
8
  import '../../siblings.js';
9
9
  import '@graphql-tools/utils';
10
10
 
11
- declare const rule: GraphQLESLintRule;
11
+ declare const schema: {
12
+ readonly type: "array";
13
+ readonly maxItems: 1;
14
+ readonly items: {
15
+ readonly type: "object";
16
+ readonly additionalProperties: false;
17
+ readonly properties: {
18
+ readonly ignoredFieldSelectors: {
19
+ readonly type: "array";
20
+ readonly uniqueItems: true;
21
+ readonly minItems: 1;
22
+ readonly description: string;
23
+ readonly items: {
24
+ readonly type: "string";
25
+ readonly pattern: "^\\[(.+)]$";
26
+ };
27
+ };
28
+ };
29
+ };
30
+ };
31
+ type RuleOptions = FromSchema<typeof schema>;
32
+ declare const rule: GraphQLESLintRule<RuleOptions>;
12
33
 
13
- export { rule };
34
+ export { type RuleOptions, rule };
@@ -1,13 +1,105 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { TypeInfo, visit, visitWithTypeInfo } from "graphql";
3
2
  import { ModuleCache } from "../../cache.js";
4
- import { requireGraphQLSchemaFromContext, requireSiblingsOperations } from "../../utils.js";
5
- const RULE_ID = "no-unused-fields", usedFieldsCache = new ModuleCache();
6
- function getUsedFields(schema, operations) {
7
- const cachedValue = usedFieldsCache.get(schema);
3
+ import { requireGraphQLOperations, requireGraphQLSchema } from "../../utils.js";
4
+ const RULE_ID = "no-unused-fields", RELAY_SCHEMA = (
5
+ /* GraphQL */
6
+ `
7
+ # Root Query Type
8
+ type Query {
9
+ user: User
10
+ }
11
+
12
+ # User Type
13
+ type User {
14
+ id: ID!
15
+ name: String!
16
+ friends(first: Int, after: String): FriendConnection!
17
+ }
18
+
19
+ # FriendConnection Type (Relay Connection)
20
+ type FriendConnection {
21
+ edges: [FriendEdge]
22
+ pageInfo: PageInfo!
23
+ }
24
+
25
+ # FriendEdge Type
26
+ type FriendEdge {
27
+ cursor: String!
28
+ node: Friend!
29
+ }
30
+
31
+ # Friend Type
32
+ type Friend {
33
+ id: ID!
34
+ name: String!
35
+ }
36
+
37
+ # PageInfo Type (Relay Pagination)
38
+ type PageInfo {
39
+ hasPreviousPage: Boolean!
40
+ hasNextPage: Boolean!
41
+ startCursor: String
42
+ endCursor: String
43
+ }
44
+ `
45
+ ), RELAY_QUERY = (
46
+ /* GraphQL */
47
+ `
48
+ query {
49
+ user {
50
+ id
51
+ name
52
+ friends(first: 10) {
53
+ edges {
54
+ node {
55
+ id
56
+ name
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ `
63
+ ), RELAY_DEFAULT_IGNORED_FIELD_SELECTORS = [
64
+ "[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]",
65
+ "[parent.name.value=/Edge$/][name.value=cursor]",
66
+ "[parent.name.value=/Connection$/][name.value=pageInfo]"
67
+ ], schema = {
68
+ type: "array",
69
+ maxItems: 1,
70
+ items: {
71
+ type: "object",
72
+ additionalProperties: !1,
73
+ properties: {
74
+ ignoredFieldSelectors: {
75
+ type: "array",
76
+ uniqueItems: !0,
77
+ minItems: 1,
78
+ description: [
79
+ "Fields that will be ignored and are allowed to be unused.",
80
+ "",
81
+ "E.g. The following selector will ignore all the relay pagination fields for every connection exposed in the schema:",
82
+ "```json",
83
+ JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
84
+ "```",
85
+ "",
86
+ "> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).",
87
+ "> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector."
88
+ ].join(`
89
+ `),
90
+ items: {
91
+ type: "string",
92
+ pattern: "^\\[(.+)]$"
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }, usedFieldsCache = new ModuleCache();
98
+ function getUsedFields(schema2, operations) {
99
+ const cachedValue = usedFieldsCache.get(schema2);
8
100
  if (process.env.NODE_ENV !== "test" && cachedValue)
9
101
  return cachedValue;
10
- const usedFields = /* @__PURE__ */ Object.create(null), typeInfo = new TypeInfo(schema), visitor = visitWithTypeInfo(typeInfo, {
102
+ const usedFields = /* @__PURE__ */ Object.create(null), typeInfo = new TypeInfo(schema2), visitor = visitWithTypeInfo(typeInfo, {
11
103
  Field(node) {
12
104
  if (!typeInfo.getFieldDef())
13
105
  return !1;
@@ -17,7 +109,7 @@ function getUsedFields(schema, operations) {
17
109
  }), allDocuments = [...operations.getOperations(), ...operations.getFragments()];
18
110
  for (const { document } of allDocuments)
19
111
  visit(document, visitor);
20
- return usedFieldsCache.set(schema, usedFields), usedFields;
112
+ return usedFieldsCache.set(schema2, usedFields), usedFields;
21
113
  }
22
114
  const rule = {
23
115
  meta: {
@@ -79,17 +171,34 @@ const rule = {
79
171
  }
80
172
  `
81
173
  )
174
+ },
175
+ {
176
+ title: "Correct (ignoring fields)",
177
+ usage: [{ ignoredFieldSelectors: RELAY_DEFAULT_IGNORED_FIELD_SELECTORS }],
178
+ code: (
179
+ /* GraphQL */
180
+ `
181
+ ### 1\uFE0F\u20E3 YOUR SCHEMA
182
+ ${RELAY_SCHEMA}
183
+
184
+ ### 2\uFE0F\u20E3 YOUR QUERY
185
+ ${RELAY_QUERY}
186
+ `
187
+ )
82
188
  }
83
189
  ]
84
190
  },
85
191
  type: "suggestion",
86
- schema: [],
192
+ schema,
87
193
  hasSuggestions: !0
88
194
  },
89
195
  create(context) {
90
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context), siblingsOperations = requireSiblingsOperations(RULE_ID, context), usedFields = getUsedFields(schema, siblingsOperations);
196
+ const schema2 = requireGraphQLSchema(RULE_ID, context), siblingsOperations = requireGraphQLOperations(RULE_ID, context), usedFields = getUsedFields(schema2, siblingsOperations), { ignoredFieldSelectors } = context.options[0] || {};
91
197
  return {
92
- FieldDefinition(node) {
198
+ [(ignoredFieldSelectors || []).reduce(
199
+ (acc, selector2) => `${acc}:not(${selector2})`,
200
+ "FieldDefinition"
201
+ )](node) {
93
202
  const fieldName = node.name.value, parentTypeName = node.parent.name.value;
94
203
  usedFields[parentTypeName]?.has(fieldName) || context.report({
95
204
  node: node.name,
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { isScalarType, Kind } from "graphql";
3
- import { requireGraphQLSchemaFromContext } from "../../utils.js";
2
+ import { requireGraphQLSchema } from "../../utils.js";
4
3
  const RULE_ID = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", schema = {
5
4
  type: "array",
6
5
  maxItems: 1,
@@ -70,7 +69,7 @@ const RULE_ID = "relay-arguments", MISSING_ARGUMENTS = "MISSING_ARGUMENTS", sche
70
69
  schema
71
70
  },
72
71
  create(context) {
73
- const schema2 = requireGraphQLSchemaFromContext(RULE_ID, context), { includeBoth = !0 } = context.options[0] || {};
72
+ const schema2 = requireGraphQLSchema(RULE_ID, context), { includeBoth = !0 } = context.options[0] || {};
74
73
  return {
75
74
  "FieldDefinition > .gqlType Name[value=/Connection$/]"(node) {
76
75
  let fieldNode = node.parent;
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
2
  const MUST_BE_OBJECT_TYPE = "MUST_BE_OBJECT_TYPE", MUST_CONTAIN_FIELD_EDGES = "MUST_CONTAIN_FIELD_EDGES", MUST_CONTAIN_FIELD_PAGE_INFO = "MUST_CONTAIN_FIELD_PAGE_INFO", MUST_HAVE_CONNECTION_SUFFIX = "MUST_HAVE_CONNECTION_SUFFIX", EDGES_FIELD_MUST_RETURN_LIST_TYPE = "EDGES_FIELD_MUST_RETURN_LIST_TYPE", PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE = "PAGE_INFO_FIELD_MUST_RETURN_NON_NULL_TYPE", NON_OBJECT_TYPES = [
4
3
  Kind.SCALAR_TYPE_DEFINITION,
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import {
3
2
  isObjectType,
4
3
  isScalarType,
@@ -6,7 +5,7 @@ import {
6
5
  visit
7
6
  } from "graphql";
8
7
  import { getDocumentNodeFromSchema } from "@graphql-tools/utils";
9
- import { getTypeName, requireGraphQLSchemaFromContext } from "../../utils.js";
8
+ import { getTypeName, requireGraphQLSchema } from "../../utils.js";
10
9
  const RULE_ID = "relay-edge-types", MESSAGE_MUST_BE_OBJECT_TYPE = "MESSAGE_MUST_BE_OBJECT_TYPE", MESSAGE_MISSING_EDGE_SUFFIX = "MESSAGE_MISSING_EDGE_SUFFIX", MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE = "MESSAGE_LIST_TYPE_ONLY_EDGE_TYPE", MESSAGE_SHOULD_IMPLEMENTS_NODE = "MESSAGE_SHOULD_IMPLEMENTS_NODE";
11
10
  let edgeTypesCache;
12
11
  function getEdgeTypes(schema2) {
@@ -94,7 +93,7 @@ const schema = {
94
93
  schema
95
94
  },
96
95
  create(context) {
97
- const schema2 = requireGraphQLSchemaFromContext(RULE_ID, context), edgeTypes = getEdgeTypes(schema2), options = {
96
+ const schema2 = requireGraphQLSchema(RULE_ID, context), edgeTypes = getEdgeTypes(schema2), options = {
98
97
  withEdgeSuffix: !0,
99
98
  shouldImplementNode: !0,
100
99
  listTypeCanWrapOnlyEdgeType: !0,
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { isScalarType, Kind } from "graphql";
3
- import { REPORT_ON_FIRST_CHARACTER, requireGraphQLSchemaFromContext } from "../../utils.js";
2
+ import { REPORT_ON_FIRST_CHARACTER, requireGraphQLSchema } from "../../utils.js";
4
3
  import { NON_OBJECT_TYPES } from "../relay-connection-types/index.js";
5
4
  const RULE_ID = "relay-page-info", MESSAGE_MUST_EXIST = "MESSAGE_MUST_EXIST", MESSAGE_MUST_BE_OBJECT_TYPE = "MESSAGE_MUST_BE_OBJECT_TYPE", notPageInfoTypesSelector = `:matches(${NON_OBJECT_TYPES})[name.value=PageInfo] > .name`;
6
5
  let hasPageInfoChecked = !1;
@@ -44,7 +43,7 @@ const rule = {
44
43
  schema: []
45
44
  },
46
45
  create(context) {
47
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context);
46
+ const schema = requireGraphQLSchema(RULE_ID, context);
48
47
  return (process.env.NODE_ENV === "test" || !hasPageInfoChecked) && (schema.getType("PageInfo") || context.report({
49
48
  loc: REPORT_ON_FIRST_CHARACTER,
50
49
  messageId: MESSAGE_MUST_EXIST
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { valueFromNode } from "../../estree-converter/index.js";
3
2
  import { getNodeName } from "../../utils.js";
4
3
  const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/, MESSAGE_REQUIRE_DATE = "MESSAGE_REQUIRE_DATE", MESSAGE_INVALID_FORMAT = "MESSAGE_INVALID_FORMAT", MESSAGE_INVALID_DATE = "MESSAGE_INVALID_DATE", MESSAGE_CAN_BE_REMOVED = "MESSAGE_CAN_BE_REMOVED", schema = {
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { valueFromNode } from "../../estree-converter/index.js";
3
2
  import { getNodeName } from "../../utils.js";
4
3
  const rule = {
@@ -1,12 +1,6 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind, TokenKind } from "graphql";
3
2
  import { getRootTypeNames } from "@graphql-tools/utils";
4
- import {
5
- getLocation,
6
- getNodeName,
7
- requireGraphQLSchemaFromContext,
8
- TYPES_KINDS
9
- } from "../../utils.js";
3
+ import { getLocation, getNodeName, requireGraphQLSchema, TYPES_KINDS } from "../../utils.js";
10
4
  const RULE_ID = "require-description", ALLOWED_KINDS = [
11
5
  ...TYPES_KINDS,
12
6
  Kind.DIRECTIVE_DEFINITION,
@@ -129,7 +123,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
129
123
  for (const [kind, isEnabled] of Object.entries(restOptions))
130
124
  isEnabled ? kinds.add(kind) : kinds.delete(kind);
131
125
  if (rootField) {
132
- const schema2 = requireGraphQLSchemaFromContext(RULE_ID, context), rootTypeNames = getRootTypeNames(schema2);
126
+ const schema2 = requireGraphQLSchema(RULE_ID, context), rootTypeNames = getRootTypeNames(schema2);
133
127
  kinds.add(
134
128
  `:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/^(${[
135
129
  ...rootTypeNames
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { isObjectType } from "graphql";
3
- import { getTypeName, requireGraphQLSchemaFromContext } from "../../utils.js";
2
+ import { getTypeName, requireGraphQLSchema } from "../../utils.js";
4
3
  const RULE_ID = "require-field-of-type-query-in-mutation-result", rule = {
5
4
  meta: {
6
5
  type: "suggestion",
@@ -48,7 +47,7 @@ const RULE_ID = "require-field-of-type-query-in-mutation-result", rule = {
48
47
  schema: []
49
48
  },
50
49
  create(context) {
51
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context), mutationType = schema.getMutationType(), queryType = schema.getQueryType();
50
+ const schema = requireGraphQLSchema(RULE_ID, context), mutationType = schema.getMutationType(), queryType = schema.getQueryType();
52
51
  return !mutationType || !queryType ? {} : {
53
52
  [`:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}] > FieldDefinition > .gqlType Name`](node) {
54
53
  const typeName = node.value, graphQLType = schema.getType(typeName);
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import path from "node:path";
3
- import { requireSiblingsOperations } from "../../utils.js";
2
+ import { requireGraphQLOperations, slash } from "../../utils.js";
4
3
  const RULE_ID = "require-import-fragment", SUGGESTION_ID = "add-import-expression", rule = {
5
4
  meta: {
6
5
  type: "suggestion",
@@ -75,7 +74,7 @@ const RULE_ID = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
75
74
  schema: []
76
75
  },
77
76
  create(context) {
78
- const comments = context.getSourceCode().getAllComments(), siblings = requireSiblingsOperations(RULE_ID, context), filePath = context.filename;
77
+ const comments = context.getSourceCode().getAllComments(), siblings = requireGraphQLOperations(RULE_ID, context), filePath = context.filename;
79
78
  return {
80
79
  "FragmentSpread > .name"(node) {
81
80
  const fragmentName = node.value, fragmentsFromSiblings = siblings.getFragment(fragmentName);
@@ -85,7 +84,7 @@ const RULE_ID = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
85
84
  ).test(comment.value)) continue;
86
85
  const extractedImportPath = comment.value.match(/(["'])((?:\1|.)*?)\1/)?.[2];
87
86
  if (!extractedImportPath) continue;
88
- const importPath = path.join(path.dirname(filePath), extractedImportPath);
87
+ const importPath = path.join(filePath, "..", extractedImportPath);
89
88
  if (fragmentsFromSiblings.some(
90
89
  (source) => source.filePath === importPath
91
90
  )) return;
@@ -93,7 +92,12 @@ const RULE_ID = "require-import-fragment", SUGGESTION_ID = "add-import-expressio
93
92
  if (fragmentsFromSiblings.some(
94
93
  (source) => source.filePath === filePath
95
94
  )) return;
96
- const suggestedFilePaths = fragmentsFromSiblings.length ? fragmentsFromSiblings.map((o) => path.relative(path.dirname(filePath), o.filePath)) : ["CHANGE_ME.graphql"];
95
+ const suggestedFilePaths = fragmentsFromSiblings.length ? fragmentsFromSiblings.map(
96
+ (o) => (
97
+ // Use always forward slash for suggested import path
98
+ slash(path.relative(path.dirname(filePath), o.filePath))
99
+ )
100
+ ) : ["CHANGE_ME.graphql"];
97
101
  context.report({
98
102
  node,
99
103
  messageId: RULE_ID,
@@ -1,4 +1,3 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
2
  import { getNodeName } from "../../utils.js";
4
3
  const RULE_ID = "require-nullable-fields-with-oneof", rule = {
@@ -1,6 +1,5 @@
1
- import "../../chunk-UIAXBAMD.js";
2
1
  import { Kind } from "graphql";
3
- import { getNodeName, requireGraphQLSchemaFromContext, truthy } from "../../utils.js";
2
+ import { getNodeName, requireGraphQLSchema, truthy } from "../../utils.js";
4
3
  const RULE_ID = "require-nullable-result-in-root", rule = {
5
4
  meta: {
6
5
  type: "suggestion",
@@ -43,7 +42,7 @@ const RULE_ID = "require-nullable-result-in-root", rule = {
43
42
  schema: []
44
43
  },
45
44
  create(context) {
46
- const schema = requireGraphQLSchemaFromContext(RULE_ID, context), rootTypeNames = new Set(
45
+ const schema = requireGraphQLSchema(RULE_ID, context), rootTypeNames = new Set(
47
46
  [schema.getQueryType(), schema.getMutationType()].filter(truthy).map((type) => type.name)
48
47
  ), sourceCode = context.getSourceCode();
49
48
  return {