@graphql-eslint/eslint-plugin 2.3.0 → 2.3.2-alpha-13a11c2.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 (65) hide show
  1. package/README.md +1 -1
  2. package/docs/README.md +1 -1
  3. package/docs/custom-rules.md +3 -3
  4. package/docs/rules/alphabetize.md +6 -1
  5. package/docs/rules/avoid-duplicate-fields.md +6 -1
  6. package/docs/rules/avoid-operation-name-prefix.md +5 -1
  7. package/docs/rules/avoid-scalar-result-type-on-mutation.md +6 -1
  8. package/docs/rules/avoid-typename-prefix.md +6 -1
  9. package/docs/rules/description-style.md +6 -1
  10. package/docs/rules/executable-definitions.md +6 -1
  11. package/docs/rules/fields-on-correct-type.md +6 -1
  12. package/docs/rules/fragments-on-composite-type.md +6 -1
  13. package/docs/rules/input-name.md +6 -1
  14. package/docs/rules/known-argument-names.md +6 -1
  15. package/docs/rules/known-directives.md +6 -1
  16. package/docs/rules/known-fragment-names.md +6 -1
  17. package/docs/rules/known-type-names.md +6 -1
  18. package/docs/rules/lone-anonymous-operation.md +6 -1
  19. package/docs/rules/lone-schema-definition.md +6 -1
  20. package/docs/rules/match-document-filename.md +6 -1
  21. package/docs/rules/naming-convention.md +6 -1
  22. package/docs/rules/no-anonymous-operations.md +6 -1
  23. package/docs/rules/no-case-insensitive-enum-values-duplicates.md +5 -1
  24. package/docs/rules/no-deprecated.md +6 -1
  25. package/docs/rules/no-fragment-cycles.md +6 -1
  26. package/docs/rules/no-hashtag-description.md +6 -1
  27. package/docs/rules/no-operation-name-suffix.md +5 -1
  28. package/docs/rules/no-undefined-variables.md +6 -1
  29. package/docs/rules/no-unreachable-types.md +6 -1
  30. package/docs/rules/no-unused-fields.md +6 -1
  31. package/docs/rules/no-unused-fragments.md +6 -1
  32. package/docs/rules/no-unused-variables.md +6 -1
  33. package/docs/rules/one-field-subscriptions.md +6 -1
  34. package/docs/rules/overlapping-fields-can-be-merged.md +6 -1
  35. package/docs/rules/possible-fragment-spread.md +6 -1
  36. package/docs/rules/possible-type-extension.md +6 -1
  37. package/docs/rules/provided-required-arguments.md +6 -1
  38. package/docs/rules/require-deprecation-date.md +6 -1
  39. package/docs/rules/require-deprecation-reason.md +6 -1
  40. package/docs/rules/require-description.md +6 -1
  41. package/docs/rules/require-field-of-type-query-in-mutation-result.md +6 -1
  42. package/docs/rules/require-id-when-available.md +6 -1
  43. package/docs/rules/scalar-leafs.md +6 -1
  44. package/docs/rules/selection-set-depth.md +6 -1
  45. package/docs/rules/strict-id-in-types.md +6 -1
  46. package/docs/rules/unique-argument-names.md +6 -1
  47. package/docs/rules/unique-directive-names-per-location.md +6 -1
  48. package/docs/rules/unique-directive-names.md +6 -1
  49. package/docs/rules/unique-enum-value-names.md +6 -1
  50. package/docs/rules/unique-field-definition-names.md +6 -1
  51. package/docs/rules/unique-fragment-name.md +6 -1
  52. package/docs/rules/unique-input-field-names.md +6 -1
  53. package/docs/rules/unique-operation-name.md +6 -1
  54. package/docs/rules/unique-operation-types.md +6 -1
  55. package/docs/rules/unique-type-names.md +6 -1
  56. package/docs/rules/unique-variable-names.md +6 -1
  57. package/docs/rules/value-literals-of-correct-type.md +6 -1
  58. package/docs/rules/variables-are-input-types.md +6 -1
  59. package/docs/rules/variables-in-allowed-position.md +6 -1
  60. package/index.js +183 -58
  61. package/index.mjs +183 -58
  62. package/package.json +1 -1
  63. package/testkit.d.ts +5 -3
  64. package/types.d.ts +2 -0
  65. package/utils.d.ts +4 -0
@@ -43,4 +43,9 @@ fragment AllUserFields on User {
43
43
  fragment UserFields on User {
44
44
  id
45
45
  }
46
- ```
46
+ ```
47
+
48
+ ## Resources
49
+
50
+ - [Rule source](../../packages/plugin/src/rules/unique-fragment-name.ts)
51
+ - [Test source](../../packages/plugin/tests/unique-fragment-name.spec.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL input object value is only valid if all supplied fields are uniquely named.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueInputFieldNamesRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueInputFieldNamesRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueInputFieldNamesRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/UniqueInputFieldNamesRule-test.ts)
@@ -47,4 +47,9 @@ query me {
47
47
  id
48
48
  }
49
49
  }
50
- ```
50
+ ```
51
+
52
+ ## Resources
53
+
54
+ - [Rule source](../../packages/plugin/src/rules/unique-operation-name.ts)
55
+ - [Test source](../../packages/plugin/tests/unique-operation-name.spec.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL document is only valid if it has only one type per operation.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueOperationTypesRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueOperationTypesRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueOperationTypesRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/UniqueOperationTypesRule-test.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL document is only valid if all defined types have unique names.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueTypeNamesRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueTypeNamesRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueTypeNamesRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/UniqueTypeNamesRule-test.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL operation is only valid if all its variables are uniquely named.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueVariableNamesRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueVariableNamesRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/UniqueVariableNamesRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/UniqueVariableNamesRule-test.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL document is only valid if all value literals are of the type expected at their position.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/ValuesOfCorrectTypeRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/ValuesOfCorrectTypeRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/ValuesOfCorrectTypeRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesAreInputTypesRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesAreInputTypesRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesAreInputTypesRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/VariablesAreInputTypesRule-test.ts)
@@ -9,4 +9,9 @@
9
9
 
10
10
  Variables passed to field arguments conform to type.
11
11
 
12
- > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesInAllowedPositionRule.ts).
12
+ > This rule is a wrapper around a `graphql-js` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesInAllowedPositionRule.ts).
13
+
14
+ ## Resources
15
+
16
+ - [Rule source](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/VariablesInAllowedPositionRule.ts)
17
+ - [Test source](https://github.com/graphql/graphql-js/tree/main/src/validation/__tests__/VariablesInAllowedPositionRule-test.ts)
package/index.js CHANGED
@@ -15,6 +15,8 @@ const depthLimit = _interopDefault(require('graphql-depth-limit'));
15
15
  const graphqlTagPluck = require('@graphql-tools/graphql-tag-pluck');
16
16
  const graphqlConfig$1 = require('graphql-config');
17
17
  const codeFileLoader = require('@graphql-tools/code-file-loader');
18
+ const eslint = require('eslint');
19
+ const codeFrame = require('@babel/code-frame');
18
20
 
19
21
  /*
20
22
  * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
@@ -242,6 +244,24 @@ const convertCase = (style, str) => {
242
244
  return lowerCase(str).replace(/ /g, '-');
243
245
  }
244
246
  };
247
+ function getLocation(loc, fieldName = '', offset) {
248
+ const { start } = loc;
249
+ /*
250
+ * ESLint has 0-based column number
251
+ * https://eslint.org/docs/developer-guide/working-with-rules#contextreport
252
+ */
253
+ const { offsetStart = 1, offsetEnd = 1 } = offset !== null && offset !== void 0 ? offset : {};
254
+ return {
255
+ start: {
256
+ line: start.line,
257
+ column: start.column - offsetStart,
258
+ },
259
+ end: {
260
+ line: start.line,
261
+ column: start.column - offsetEnd + fieldName.length,
262
+ },
263
+ };
264
+ }
245
265
 
246
266
  function extractRuleName(stack) {
247
267
  const match = (stack || '').match(/validation[/\\\\]rules[/\\\\](.*?)\.js:/) || [];
@@ -292,6 +312,7 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
292
312
  meta: {
293
313
  docs: {
294
314
  ...docs,
315
+ graphQLJSRuleName: ruleName,
295
316
  category: 'Validation',
296
317
  recommended: true,
297
318
  requiresSchema,
@@ -656,10 +677,7 @@ const rule = {
656
677
  line: start.line,
657
678
  column: start.column - (isVariableNode ? 2 : 1),
658
679
  },
659
- end: {
660
- line: end.line,
661
- column: end.column,
662
- },
680
+ end,
663
681
  },
664
682
  messageId: ALPHABETIZE,
665
683
  data: isVariableNode
@@ -790,6 +808,7 @@ const rule$1 = {
790
808
  messages: {
791
809
  [AVOID_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times.`,
792
810
  },
811
+ schema: [],
793
812
  },
794
813
  create(context) {
795
814
  return {
@@ -909,15 +928,16 @@ const rule$2 = {
909
928
  const testKeyword = caseSensitive ? keyword : keyword.toLowerCase();
910
929
  const testName = caseSensitive ? node.name.value : node.name.value.toLowerCase();
911
930
  if (testName.startsWith(testKeyword)) {
931
+ const { start } = node.name.loc;
912
932
  context.report({
913
933
  loc: {
914
934
  start: {
915
- line: node.name.loc.start.line,
916
- column: node.name.loc.start.column - 1,
935
+ line: start.line,
936
+ column: start.column - 1,
917
937
  },
918
938
  end: {
919
- line: node.name.loc.start.line,
920
- column: node.name.loc.start.column + testKeyword.length - 1,
939
+ line: start.line,
940
+ column: start.column - 1 + testKeyword.length,
921
941
  },
922
942
  },
923
943
  data: {
@@ -960,6 +980,7 @@ const rule$3 = {
960
980
  },
961
981
  ],
962
982
  },
983
+ schema: [],
963
984
  },
964
985
  create(context) {
965
986
  const schema = requireGraphQLSchemaFromContext('avoid-scalar-result-type-on-mutation', context);
@@ -967,16 +988,20 @@ const rule$3 = {
967
988
  if (!mutationType) {
968
989
  return {};
969
990
  }
970
- const selector = `:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}] > ${graphql.Kind.FIELD_DEFINITION}`;
991
+ const selector = [
992
+ `:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})[name.value=${mutationType.name}]`,
993
+ '>',
994
+ graphql.Kind.FIELD_DEFINITION,
995
+ graphql.Kind.NAMED_TYPE,
996
+ ].join(' ');
971
997
  return {
972
998
  [selector](node) {
973
- const rawNode = node.rawNode();
974
- const typeName = getTypeName(rawNode);
999
+ const typeName = node.name.value;
975
1000
  const graphQLType = schema.getType(typeName);
976
1001
  if (graphql.isScalarType(graphQLType)) {
977
1002
  context.report({
978
- node,
979
- message: `Unexpected scalar result type "${typeName}".`,
1003
+ loc: getLocation(node.loc, typeName),
1004
+ message: `Unexpected scalar result type "${typeName}"`,
980
1005
  });
981
1006
  }
982
1007
  },
@@ -1015,22 +1040,33 @@ const rule$4 = {
1015
1040
  messages: {
1016
1041
  [AVOID_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
1017
1042
  },
1043
+ schema: [],
1018
1044
  },
1019
1045
  create(context) {
1020
1046
  return {
1021
1047
  'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
1022
1048
  const typeName = node.name.value;
1023
- const lowerTypeName = (typeName || '').toLowerCase();
1049
+ const lowerTypeName = typeName.toLowerCase();
1024
1050
  for (const field of node.fields) {
1025
- const fieldName = field.name.value || '';
1026
- if (fieldName && lowerTypeName && fieldName.toLowerCase().startsWith(lowerTypeName)) {
1051
+ const fieldName = field.name.value;
1052
+ if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
1053
+ const { start } = field.loc;
1027
1054
  context.report({
1028
- node: field.name,
1029
1055
  data: {
1030
1056
  fieldName,
1031
1057
  typeName,
1032
1058
  },
1033
1059
  messageId: AVOID_TYPENAME_PREFIX,
1060
+ loc: {
1061
+ start: {
1062
+ line: start.line,
1063
+ column: start.column - 1,
1064
+ },
1065
+ end: {
1066
+ line: start.line,
1067
+ column: start.column - 1 + lowerTypeName.length,
1068
+ },
1069
+ },
1034
1070
  });
1035
1071
  }
1036
1072
  }
@@ -1177,10 +1213,11 @@ const rule$6 = {
1177
1213
  const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
1178
1214
  const listeners = {
1179
1215
  'FieldDefinition > InputValueDefinition': node => {
1180
- if (node.name.value !== 'input' && shouldCheckType(node.parent.parent)) {
1216
+ const name = node.name.value;
1217
+ if (name !== 'input' && shouldCheckType(node.parent.parent)) {
1181
1218
  context.report({
1182
- node: node.name,
1183
- message: `Input "${node.name.value}" should be called "input"`,
1219
+ loc: getLocation(node.loc, name),
1220
+ message: `Input "${name}" should be called "input"`,
1184
1221
  });
1185
1222
  }
1186
1223
  },
@@ -1197,11 +1234,12 @@ const rule$6 = {
1197
1234
  const inputValueNode = findInputType(node);
1198
1235
  if (shouldCheckType(inputValueNode.parent.parent)) {
1199
1236
  const mutationName = `${inputValueNode.parent.name.value}Input`;
1237
+ const name = node.name.value;
1200
1238
  if ((options.caseSensitiveInputType && node.name.value !== mutationName) ||
1201
- node.name.value.toLowerCase() !== mutationName.toLowerCase()) {
1239
+ name.toLowerCase() !== mutationName.toLowerCase()) {
1202
1240
  context.report({
1203
- node,
1204
- message: `InputType "${node.name.value}" name should be "${mutationName}"`,
1241
+ loc: getLocation(node.loc, name),
1242
+ message: `InputType "${name}" name should be "${mutationName}"`,
1205
1243
  });
1206
1244
  }
1207
1245
  }
@@ -1358,7 +1396,8 @@ const rule$7 = {
1358
1396
  var _a;
1359
1397
  if (options.fileExtension && options.fileExtension !== fileExtension) {
1360
1398
  context.report({
1361
- node: documentNode,
1399
+ // Report on first character
1400
+ loc: { column: 0, line: 1 },
1362
1401
  messageId: MATCH_EXTENSION,
1363
1402
  data: {
1364
1403
  fileExtension,
@@ -1390,7 +1429,8 @@ const rule$7 = {
1390
1429
  const filenameWithExtension = filename + expectedExtension;
1391
1430
  if (expectedFilename !== filenameWithExtension) {
1392
1431
  context.report({
1393
- node: documentNode,
1432
+ // Report on first character
1433
+ loc: { column: 0, line: 1 },
1394
1434
  messageId: MATCH_STYLE,
1395
1435
  data: {
1396
1436
  expectedFilename,
@@ -1728,20 +1768,24 @@ const rule$9 = {
1728
1768
  messages: {
1729
1769
  [NO_ANONYMOUS_OPERATIONS]: `Anonymous GraphQL operations are forbidden. Please make sure to name your {{ operation }}!`,
1730
1770
  },
1771
+ schema: [],
1731
1772
  },
1732
1773
  create(context) {
1733
1774
  return {
1734
1775
  OperationDefinition(node) {
1735
- if (node && (!node.name || node.name.value === '')) {
1776
+ var _a;
1777
+ const isAnonymous = (((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '').length === 0;
1778
+ if (isAnonymous) {
1779
+ const { start } = node.loc;
1736
1780
  context.report({
1737
1781
  loc: {
1738
1782
  start: {
1739
- column: node.loc.start.column - 1,
1740
- line: node.loc.start.line,
1783
+ column: start.column - 1,
1784
+ line: start.line,
1741
1785
  },
1742
1786
  end: {
1743
- column: node.loc.start.column + node.operation.length,
1744
- line: node.loc.start.line,
1787
+ column: start.column - 1 + node.operation.length,
1788
+ line: start.line,
1745
1789
  },
1746
1790
  },
1747
1791
  data: {
@@ -1791,6 +1835,7 @@ const rule$a = {
1791
1835
  messages: {
1792
1836
  [ERROR_MESSAGE_ID]: `Case-insensitive enum values duplicates are not allowed! Found: "{{ found }}"`,
1793
1837
  },
1838
+ schema: [],
1794
1839
  },
1795
1840
  create(context) {
1796
1841
  return {
@@ -1885,6 +1930,7 @@ const rule$b = {
1885
1930
  messages: {
1886
1931
  [NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
1887
1932
  },
1933
+ schema: [],
1888
1934
  },
1889
1935
  create(context) {
1890
1936
  return {
@@ -1971,6 +2017,7 @@ const rule$c = {
1971
2017
  ],
1972
2018
  },
1973
2019
  type: 'suggestion',
2020
+ schema: [],
1974
2021
  },
1975
2022
  create(context) {
1976
2023
  return {
@@ -2031,15 +2078,28 @@ const rule$d = {
2031
2078
  messages: {
2032
2079
  [NO_OPERATION_NAME_SUFFIX]: `Unnecessary "{{ invalidSuffix }}" suffix in your operation name!`,
2033
2080
  },
2081
+ schema: [],
2034
2082
  },
2035
2083
  create(context) {
2036
2084
  return {
2037
2085
  'OperationDefinition, FragmentDefinition'(node) {
2038
- if (node && node.name && node.name.value !== '') {
2039
- const invalidSuffix = (node.type === 'OperationDefinition' ? node.operation : 'fragment').toLowerCase();
2040
- if (node.name.value.toLowerCase().endsWith(invalidSuffix)) {
2086
+ var _a;
2087
+ const name = ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '';
2088
+ if (name.length > 0) {
2089
+ const invalidSuffix = 'operation' in node ? node.operation : 'fragment';
2090
+ if (name.toLowerCase().endsWith(invalidSuffix)) {
2091
+ const { start, end } = node.name.loc;
2041
2092
  context.report({
2042
- node: node.name,
2093
+ loc: {
2094
+ start: {
2095
+ column: start.column - 1 + name.length - invalidSuffix.length,
2096
+ line: start.line,
2097
+ },
2098
+ end: {
2099
+ column: end.column - 1 + name.length,
2100
+ line: end.line,
2101
+ },
2102
+ },
2043
2103
  data: {
2044
2104
  invalidSuffix,
2045
2105
  },
@@ -2096,6 +2156,7 @@ const rule$e = {
2096
2156
  },
2097
2157
  fixable: 'code',
2098
2158
  type: 'suggestion',
2159
+ schema: [],
2099
2160
  },
2100
2161
  create(context) {
2101
2162
  const reachableTypes = requireReachableTypesFromContext(RULE_NAME, context);
@@ -2187,6 +2248,7 @@ const rule$f = {
2187
2248
  },
2188
2249
  fixable: 'code',
2189
2250
  type: 'suggestion',
2251
+ schema: [],
2190
2252
  },
2191
2253
  create(context) {
2192
2254
  const usedFields = requireUsedFieldsFromContext(RULE_NAME$1, context);
@@ -2452,6 +2514,7 @@ const rule$h = {
2452
2514
  ],
2453
2515
  },
2454
2516
  type: 'suggestion',
2517
+ schema: [],
2455
2518
  },
2456
2519
  create(context) {
2457
2520
  return {
@@ -2488,15 +2551,18 @@ const DESCRIBABLE_NODES = [
2488
2551
  function verifyRule(context, node) {
2489
2552
  if (node) {
2490
2553
  if (!node.description || !node.description.value || node.description.value.trim().length === 0) {
2554
+ const { start, end } = ('name' in node ? node.name : node).loc;
2491
2555
  context.report({
2492
2556
  loc: {
2493
2557
  start: {
2494
- line: node.loc.start.line,
2495
- column: node.loc.start.column - 1,
2558
+ line: start.line,
2559
+ column: start.column - 1,
2496
2560
  },
2497
2561
  end: {
2498
- line: node.loc.end.line,
2499
- column: node.loc.end.column,
2562
+ line: end.line,
2563
+ column:
2564
+ // node.name don't exist on SchemaDefinition
2565
+ 'name' in node ? end.column - 1 + node.name.value.length : end.column,
2500
2566
  },
2501
2567
  },
2502
2568
  messageId: REQUIRE_DESCRIPTION_ERROR,
@@ -2610,6 +2676,7 @@ const rule$j = {
2610
2676
  },
2611
2677
  ],
2612
2678
  },
2679
+ schema: [],
2613
2680
  },
2614
2681
  create(context) {
2615
2682
  const schema = requireGraphQLSchemaFromContext(RULE_NAME$2, context);
@@ -3146,11 +3213,7 @@ const rule$m = {
3146
3213
  const RULE_NAME$3 = 'unique-fragment-name';
3147
3214
  const UNIQUE_FRAGMENT_NAME = 'UNIQUE_FRAGMENT_NAME';
3148
3215
  const checkNode = (context, node, ruleName, messageId) => {
3149
- var _a;
3150
- const documentName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value;
3151
- if (!documentName) {
3152
- return;
3153
- }
3216
+ const documentName = node.name.value;
3154
3217
  const siblings = requireSiblingsOperations(ruleName, context);
3155
3218
  const siblingDocuments = node.kind === graphql.Kind.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
3156
3219
  const filepath = context.getFilename();
@@ -3161,7 +3224,6 @@ const checkNode = (context, node, ruleName, messageId) => {
3161
3224
  return isSameName && !isSamePath;
3162
3225
  });
3163
3226
  if (conflictingDocuments.length > 0) {
3164
- const { start, end } = node.name.loc;
3165
3227
  context.report({
3166
3228
  messageId,
3167
3229
  data: {
@@ -3170,16 +3232,7 @@ const checkNode = (context, node, ruleName, messageId) => {
3170
3232
  .map(f => `\t${path.relative(process.cwd(), getOnDiskFilepath(f.filePath))}`)
3171
3233
  .join('\n'),
3172
3234
  },
3173
- loc: {
3174
- start: {
3175
- line: start.line,
3176
- column: start.column - 1,
3177
- },
3178
- end: {
3179
- line: end.line,
3180
- column: end.column - 1,
3181
- },
3182
- },
3235
+ loc: getLocation(node.name.loc, documentName),
3183
3236
  });
3184
3237
  }
3185
3238
  };
@@ -3229,6 +3282,7 @@ const rule$n = {
3229
3282
  messages: {
3230
3283
  [UNIQUE_FRAGMENT_NAME]: 'Fragment named "{{ documentName }}" already defined in:\n{{ summary }}',
3231
3284
  },
3285
+ schema: [],
3232
3286
  },
3233
3287
  create(context) {
3234
3288
  return {
@@ -3291,10 +3345,11 @@ const rule$o = {
3291
3345
  messages: {
3292
3346
  [UNIQUE_OPERATION_NAME]: 'Operation named "{{ documentName }}" already defined in:\n{{ summary }}',
3293
3347
  },
3348
+ schema: [],
3294
3349
  },
3295
3350
  create(context) {
3296
3351
  return {
3297
- OperationDefinition(node) {
3352
+ 'OperationDefinition[name!=undefined]'(node) {
3298
3353
  checkNode(context, node, RULE_NAME$4, UNIQUE_OPERATION_NAME);
3299
3354
  },
3300
3355
  };
@@ -3724,23 +3779,93 @@ function parseForESLint(code, options = {}) {
3724
3779
  }
3725
3780
  }
3726
3781
 
3727
- class GraphQLRuleTester extends require('eslint').RuleTester {
3782
+ class GraphQLRuleTester extends eslint.RuleTester {
3728
3783
  constructor(parserOptions = {}) {
3729
- super({
3784
+ const config = {
3730
3785
  parser: require.resolve('@graphql-eslint/eslint-plugin'),
3731
3786
  parserOptions: {
3732
3787
  ...parserOptions,
3733
3788
  skipGraphQLConfig: true,
3734
3789
  },
3735
- });
3790
+ };
3791
+ super(config);
3792
+ this.config = config;
3736
3793
  }
3737
3794
  fromMockFile(path$1) {
3738
3795
  return fs.readFileSync(path.resolve(__dirname, `../tests/mocks/${path$1}`), 'utf-8');
3739
3796
  }
3740
3797
  runGraphQLTests(name, rule, tests) {
3741
3798
  super.run(name, rule, tests);
3799
+ // Skip snapshot testing if `expect` variable is not defined
3800
+ if (typeof expect === 'undefined') {
3801
+ return;
3802
+ }
3803
+ const linter = new eslint.Linter();
3804
+ linter.defineRule(name, rule);
3805
+ for (const testCase of tests.invalid) {
3806
+ const verifyConfig = getVerifyConfig(name, this.config, testCase);
3807
+ defineParser(linter, verifyConfig.parser);
3808
+ const { code, filename } = testCase;
3809
+ const messages = linter.verify(code, verifyConfig, { filename });
3810
+ for (const message of messages) {
3811
+ if (message.fatal) {
3812
+ throw new Error(message.message);
3813
+ }
3814
+ const messageForSnapshot = visualizeEslintMessage(code, message);
3815
+ // eslint-disable-next-line no-undef
3816
+ expect(messageForSnapshot).toMatchSnapshot();
3817
+ }
3818
+ }
3742
3819
  }
3743
3820
  }
3821
+ function getVerifyConfig(ruleId, testerConfig, testCase) {
3822
+ const { options, parserOptions, parser = testerConfig.parser } = testCase;
3823
+ return {
3824
+ ...testerConfig,
3825
+ parser,
3826
+ parserOptions: {
3827
+ ...testerConfig.parserOptions,
3828
+ ...parserOptions,
3829
+ },
3830
+ rules: {
3831
+ [ruleId]: ['error', ...(Array.isArray(options) ? options : [])],
3832
+ },
3833
+ };
3834
+ }
3835
+ const parsers = new WeakMap();
3836
+ function defineParser(linter, parser) {
3837
+ if (!parser) {
3838
+ return;
3839
+ }
3840
+ if (!parsers.has(linter)) {
3841
+ parsers.set(linter, new Set());
3842
+ }
3843
+ const defined = parsers.get(linter);
3844
+ if (!defined.has(parser)) {
3845
+ defined.add(parser);
3846
+ linter.defineParser(parser, require(parser));
3847
+ }
3848
+ }
3849
+ function visualizeEslintMessage(text, result) {
3850
+ const { line, column, endLine, endColumn, message } = result;
3851
+ const location = {
3852
+ start: {
3853
+ line,
3854
+ column,
3855
+ },
3856
+ };
3857
+ if (typeof endLine === 'number' && typeof endColumn === 'number') {
3858
+ location.end = {
3859
+ line: endLine,
3860
+ column: endColumn,
3861
+ };
3862
+ }
3863
+ return codeFrame.codeFrameColumns(text, location, {
3864
+ linesAbove: Number.POSITIVE_INFINITY,
3865
+ linesBelow: Number.POSITIVE_INFINITY,
3866
+ message,
3867
+ });
3868
+ }
3744
3869
 
3745
3870
  exports.GraphQLRuleTester = GraphQLRuleTester;
3746
3871
  exports.configs = configs;