@graphql-eslint/eslint-plugin 3.14.0-alpha-20221222211539-5e993f5 → 3.14.0-alpha-20221223011223-bd3e820

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 (185) hide show
  1. package/cjs/configs/index.js +10 -10
  2. package/cjs/documents.js +5 -5
  3. package/cjs/estree-converter/converter.js +2 -2
  4. package/cjs/estree-converter/index.js +3 -3
  5. package/cjs/estree-converter/utils.js +2 -2
  6. package/cjs/flat-configs.js +36 -0
  7. package/cjs/index.js +16 -14
  8. package/cjs/parser.js +13 -13
  9. package/cjs/processor.js +2 -2
  10. package/cjs/rules/alphabetize.js +7 -7
  11. package/cjs/rules/graphql-js-validation.js +9 -9
  12. package/cjs/rules/index.js +66 -66
  13. package/cjs/rules/lone-executable-definition.js +4 -4
  14. package/cjs/rules/match-document-filename.js +4 -4
  15. package/cjs/rules/naming-convention.js +6 -6
  16. package/cjs/rules/no-anonymous-operations.js +2 -2
  17. package/cjs/rules/no-deprecated.js +2 -2
  18. package/cjs/rules/no-one-place-fragments.js +3 -4
  19. package/cjs/rules/no-root-type.js +3 -3
  20. package/cjs/rules/no-scalar-result-type-on-mutation.js +2 -2
  21. package/cjs/rules/no-unreachable-types.js +3 -3
  22. package/cjs/rules/no-unused-fields.js +3 -3
  23. package/cjs/rules/relay-arguments.js +2 -2
  24. package/cjs/rules/relay-edge-types.js +6 -6
  25. package/cjs/rules/relay-page-info.js +5 -5
  26. package/cjs/rules/require-deprecation-date.js +2 -2
  27. package/cjs/rules/require-deprecation-reason.js +2 -2
  28. package/cjs/rules/require-description.js +8 -8
  29. package/cjs/rules/require-field-of-type-query-in-mutation-result.js +3 -3
  30. package/cjs/rules/require-id-when-available.js +8 -8
  31. package/cjs/rules/selection-set-depth.js +5 -5
  32. package/cjs/rules/strict-id-in-types.js +7 -7
  33. package/cjs/rules/unique-fragment-name.js +4 -4
  34. package/cjs/rules/unique-operation-name.js +2 -2
  35. package/cjs/schema.js +2 -2
  36. package/esm/cache.js +25 -0
  37. package/esm/configs/base.js +4 -0
  38. package/esm/configs/index.js +12 -0
  39. package/esm/configs/operations-all.js +29 -0
  40. package/esm/configs/operations-recommended.js +53 -0
  41. package/esm/configs/relay.js +9 -0
  42. package/esm/configs/schema-all.js +22 -0
  43. package/esm/configs/schema-recommended.js +49 -0
  44. package/esm/documents.js +144 -0
  45. package/esm/estree-converter/converter.js +58 -0
  46. package/esm/estree-converter/index.js +3 -0
  47. package/esm/estree-converter/types.js +1 -0
  48. package/esm/estree-converter/utils.js +102 -0
  49. package/esm/flat-configs.js +33 -0
  50. package/esm/graphql-config.js +49 -0
  51. package/esm/index.js +9 -0
  52. package/esm/package.json +1 -0
  53. package/esm/parser.js +56 -0
  54. package/esm/processor.js +75 -0
  55. package/esm/rules/alphabetize.js +344 -0
  56. package/esm/rules/description-style.js +75 -0
  57. package/esm/rules/graphql-js-validation.js +498 -0
  58. package/esm/rules/index.js +71 -0
  59. package/esm/rules/input-name.js +133 -0
  60. package/esm/rules/lone-executable-definition.js +85 -0
  61. package/esm/rules/match-document-filename.js +232 -0
  62. package/esm/rules/naming-convention.js +307 -0
  63. package/esm/rules/no-anonymous-operations.js +64 -0
  64. package/esm/rules/no-case-insensitive-enum-values-duplicates.js +58 -0
  65. package/esm/rules/no-deprecated.js +121 -0
  66. package/esm/rules/no-duplicate-fields.js +109 -0
  67. package/esm/rules/no-hashtag-description.js +86 -0
  68. package/esm/rules/no-one-place-fragments.js +80 -0
  69. package/esm/rules/no-root-type.js +83 -0
  70. package/esm/rules/no-scalar-result-type-on-mutation.js +63 -0
  71. package/esm/rules/no-typename-prefix.js +62 -0
  72. package/esm/rules/no-unreachable-types.js +154 -0
  73. package/esm/rules/no-unused-fields.js +127 -0
  74. package/esm/rules/relay-arguments.js +118 -0
  75. package/esm/rules/relay-connection-types.js +104 -0
  76. package/esm/rules/relay-edge-types.js +186 -0
  77. package/esm/rules/relay-page-info.js +97 -0
  78. package/esm/rules/require-deprecation-date.js +120 -0
  79. package/esm/rules/require-deprecation-reason.js +53 -0
  80. package/esm/rules/require-description.js +190 -0
  81. package/esm/rules/require-field-of-type-query-in-mutation-result.js +69 -0
  82. package/esm/rules/require-id-when-available.js +196 -0
  83. package/esm/rules/require-nullable-fields-with-oneof.js +58 -0
  84. package/esm/rules/require-type-pattern-with-oneof.js +57 -0
  85. package/esm/rules/selection-set-depth.js +131 -0
  86. package/esm/rules/strict-id-in-types.js +159 -0
  87. package/esm/rules/unique-fragment-name.js +86 -0
  88. package/esm/rules/unique-operation-name.js +62 -0
  89. package/esm/schema.js +37 -0
  90. package/esm/testkit.js +181 -0
  91. package/esm/types.js +1 -0
  92. package/esm/utils.js +83 -0
  93. package/package.json +10 -1
  94. package/typings/estree-converter/converter.d.cts +1 -1
  95. package/typings/estree-converter/converter.d.ts +1 -1
  96. package/typings/estree-converter/index.d.cts +3 -3
  97. package/typings/estree-converter/index.d.ts +3 -3
  98. package/typings/estree-converter/types.d.cts +3 -3
  99. package/typings/estree-converter/types.d.ts +3 -3
  100. package/typings/estree-converter/utils.d.cts +2 -2
  101. package/typings/estree-converter/utils.d.ts +2 -2
  102. package/typings/flat-configs.d.cts +248 -0
  103. package/typings/flat-configs.d.ts +248 -0
  104. package/typings/graphql-config.d.cts +1 -1
  105. package/typings/graphql-config.d.ts +1 -1
  106. package/typings/index.d.cts +8 -7
  107. package/typings/index.d.ts +8 -7
  108. package/typings/parser.d.cts +1 -1
  109. package/typings/parser.d.ts +1 -1
  110. package/typings/rules/alphabetize.d.cts +1 -1
  111. package/typings/rules/alphabetize.d.ts +1 -1
  112. package/typings/rules/description-style.d.cts +1 -1
  113. package/typings/rules/description-style.d.ts +1 -1
  114. package/typings/rules/graphql-js-validation.d.cts +1 -1
  115. package/typings/rules/graphql-js-validation.d.ts +1 -1
  116. package/typings/rules/index.d.cts +45 -45
  117. package/typings/rules/index.d.ts +45 -45
  118. package/typings/rules/input-name.d.cts +1 -1
  119. package/typings/rules/input-name.d.ts +1 -1
  120. package/typings/rules/lone-executable-definition.d.cts +1 -1
  121. package/typings/rules/lone-executable-definition.d.ts +1 -1
  122. package/typings/rules/match-document-filename.d.cts +2 -2
  123. package/typings/rules/match-document-filename.d.ts +2 -2
  124. package/typings/rules/naming-convention.d.cts +1 -1
  125. package/typings/rules/naming-convention.d.ts +1 -1
  126. package/typings/rules/no-anonymous-operations.d.cts +1 -1
  127. package/typings/rules/no-anonymous-operations.d.ts +1 -1
  128. package/typings/rules/no-case-insensitive-enum-values-duplicates.d.cts +1 -1
  129. package/typings/rules/no-case-insensitive-enum-values-duplicates.d.ts +1 -1
  130. package/typings/rules/no-deprecated.d.cts +1 -1
  131. package/typings/rules/no-deprecated.d.ts +1 -1
  132. package/typings/rules/no-duplicate-fields.d.cts +1 -1
  133. package/typings/rules/no-duplicate-fields.d.ts +1 -1
  134. package/typings/rules/no-hashtag-description.d.cts +1 -1
  135. package/typings/rules/no-hashtag-description.d.ts +1 -1
  136. package/typings/rules/no-one-place-fragments.d.cts +1 -1
  137. package/typings/rules/no-one-place-fragments.d.ts +1 -1
  138. package/typings/rules/no-root-type.d.cts +1 -1
  139. package/typings/rules/no-root-type.d.ts +1 -1
  140. package/typings/rules/no-scalar-result-type-on-mutation.d.cts +1 -1
  141. package/typings/rules/no-scalar-result-type-on-mutation.d.ts +1 -1
  142. package/typings/rules/no-typename-prefix.d.cts +1 -1
  143. package/typings/rules/no-typename-prefix.d.ts +1 -1
  144. package/typings/rules/no-unreachable-types.d.cts +1 -1
  145. package/typings/rules/no-unreachable-types.d.ts +1 -1
  146. package/typings/rules/no-unused-fields.d.cts +1 -1
  147. package/typings/rules/no-unused-fields.d.ts +1 -1
  148. package/typings/rules/relay-arguments.d.cts +1 -1
  149. package/typings/rules/relay-arguments.d.ts +1 -1
  150. package/typings/rules/relay-connection-types.d.cts +1 -1
  151. package/typings/rules/relay-connection-types.d.ts +1 -1
  152. package/typings/rules/relay-edge-types.d.cts +1 -1
  153. package/typings/rules/relay-edge-types.d.ts +1 -1
  154. package/typings/rules/relay-page-info.d.cts +1 -1
  155. package/typings/rules/relay-page-info.d.ts +1 -1
  156. package/typings/rules/require-deprecation-date.d.cts +1 -1
  157. package/typings/rules/require-deprecation-date.d.ts +1 -1
  158. package/typings/rules/require-deprecation-reason.d.cts +1 -1
  159. package/typings/rules/require-deprecation-reason.d.ts +1 -1
  160. package/typings/rules/require-description.d.cts +1 -1
  161. package/typings/rules/require-description.d.ts +1 -1
  162. package/typings/rules/require-field-of-type-query-in-mutation-result.d.cts +1 -1
  163. package/typings/rules/require-field-of-type-query-in-mutation-result.d.ts +1 -1
  164. package/typings/rules/require-id-when-available.d.cts +1 -1
  165. package/typings/rules/require-id-when-available.d.ts +1 -1
  166. package/typings/rules/require-nullable-fields-with-oneof.d.cts +1 -1
  167. package/typings/rules/require-nullable-fields-with-oneof.d.ts +1 -1
  168. package/typings/rules/require-type-pattern-with-oneof.d.cts +1 -1
  169. package/typings/rules/require-type-pattern-with-oneof.d.ts +1 -1
  170. package/typings/rules/selection-set-depth.d.cts +1 -1
  171. package/typings/rules/selection-set-depth.d.ts +1 -1
  172. package/typings/rules/strict-id-in-types.d.cts +1 -1
  173. package/typings/rules/strict-id-in-types.d.ts +1 -1
  174. package/typings/rules/unique-fragment-name.d.cts +2 -2
  175. package/typings/rules/unique-fragment-name.d.ts +2 -2
  176. package/typings/rules/unique-operation-name.d.cts +1 -1
  177. package/typings/rules/unique-operation-name.d.ts +1 -1
  178. package/typings/schema.d.cts +1 -1
  179. package/typings/schema.d.ts +1 -1
  180. package/typings/testkit.d.cts +3 -3
  181. package/typings/testkit.d.ts +3 -3
  182. package/typings/types.d.cts +2 -2
  183. package/typings/types.d.ts +2 -2
  184. package/typings/utils.d.cts +2 -2
  185. package/typings/utils.d.ts +2 -2
@@ -0,0 +1,29 @@
1
+ /*
2
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
3
+ */
4
+ export default {
5
+ extends: ['./configs/base', './configs/operations-recommended'],
6
+ rules: {
7
+ '@graphql-eslint/alphabetize': [
8
+ 'error',
9
+ {
10
+ selections: ['OperationDefinition', 'FragmentDefinition'],
11
+ variables: ['OperationDefinition'],
12
+ arguments: ['Field', 'Directive'],
13
+ },
14
+ ],
15
+ '@graphql-eslint/lone-executable-definition': 'error',
16
+ '@graphql-eslint/match-document-filename': [
17
+ 'error',
18
+ {
19
+ query: 'kebab-case',
20
+ mutation: 'kebab-case',
21
+ subscription: 'kebab-case',
22
+ fragment: 'kebab-case',
23
+ },
24
+ ],
25
+ '@graphql-eslint/no-one-place-fragments': 'error',
26
+ '@graphql-eslint/unique-fragment-name': 'error',
27
+ '@graphql-eslint/unique-operation-name': 'error',
28
+ },
29
+ };
@@ -0,0 +1,53 @@
1
+ /*
2
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
3
+ */
4
+ export default {
5
+ extends: './configs/base',
6
+ rules: {
7
+ '@graphql-eslint/executable-definitions': 'error',
8
+ '@graphql-eslint/fields-on-correct-type': 'error',
9
+ '@graphql-eslint/fragments-on-composite-type': 'error',
10
+ '@graphql-eslint/known-argument-names': 'error',
11
+ '@graphql-eslint/known-directives': 'error',
12
+ '@graphql-eslint/known-fragment-names': 'error',
13
+ '@graphql-eslint/known-type-names': 'error',
14
+ '@graphql-eslint/lone-anonymous-operation': 'error',
15
+ '@graphql-eslint/naming-convention': [
16
+ 'error',
17
+ {
18
+ VariableDefinition: 'camelCase',
19
+ OperationDefinition: {
20
+ style: 'PascalCase',
21
+ forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
22
+ forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
23
+ },
24
+ FragmentDefinition: {
25
+ style: 'PascalCase',
26
+ forbiddenPrefixes: ['Fragment'],
27
+ forbiddenSuffixes: ['Fragment'],
28
+ },
29
+ },
30
+ ],
31
+ '@graphql-eslint/no-anonymous-operations': 'error',
32
+ '@graphql-eslint/no-deprecated': 'error',
33
+ '@graphql-eslint/no-duplicate-fields': 'error',
34
+ '@graphql-eslint/no-fragment-cycles': 'error',
35
+ '@graphql-eslint/no-undefined-variables': 'error',
36
+ '@graphql-eslint/no-unused-fragments': 'error',
37
+ '@graphql-eslint/no-unused-variables': 'error',
38
+ '@graphql-eslint/one-field-subscriptions': 'error',
39
+ '@graphql-eslint/overlapping-fields-can-be-merged': 'error',
40
+ '@graphql-eslint/possible-fragment-spread': 'error',
41
+ '@graphql-eslint/provided-required-arguments': 'error',
42
+ '@graphql-eslint/require-id-when-available': 'error',
43
+ '@graphql-eslint/scalar-leafs': 'error',
44
+ '@graphql-eslint/selection-set-depth': ['error', { maxDepth: 7 }],
45
+ '@graphql-eslint/unique-argument-names': 'error',
46
+ '@graphql-eslint/unique-directive-names-per-location': 'error',
47
+ '@graphql-eslint/unique-input-field-names': 'error',
48
+ '@graphql-eslint/unique-variable-names': 'error',
49
+ '@graphql-eslint/value-literals-of-correct-type': 'error',
50
+ '@graphql-eslint/variables-are-input-types': 'error',
51
+ '@graphql-eslint/variables-in-allowed-position': 'error',
52
+ },
53
+ };
@@ -0,0 +1,9 @@
1
+ export default {
2
+ extends: './configs/base',
3
+ rules: {
4
+ '@graphql-eslint/relay-arguments': 'error',
5
+ '@graphql-eslint/relay-connection-types': 'error',
6
+ '@graphql-eslint/relay-edge-types': 'error',
7
+ '@graphql-eslint/relay-page-info': 'error',
8
+ },
9
+ };
@@ -0,0 +1,22 @@
1
+ /*
2
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
3
+ */
4
+ export default {
5
+ extends: ['./configs/base', './configs/schema-recommended'],
6
+ rules: {
7
+ '@graphql-eslint/alphabetize': [
8
+ 'error',
9
+ {
10
+ fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
11
+ values: ['EnumTypeDefinition'],
12
+ arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
13
+ },
14
+ ],
15
+ '@graphql-eslint/input-name': 'error',
16
+ '@graphql-eslint/no-scalar-result-type-on-mutation': 'error',
17
+ '@graphql-eslint/require-deprecation-date': 'error',
18
+ '@graphql-eslint/require-field-of-type-query-in-mutation-result': 'error',
19
+ '@graphql-eslint/require-nullable-fields-with-oneof': 'error',
20
+ '@graphql-eslint/require-type-pattern-with-oneof': 'error',
21
+ },
22
+ };
@@ -0,0 +1,49 @@
1
+ /*
2
+ * 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
3
+ */
4
+ export default {
5
+ extends: './configs/base',
6
+ rules: {
7
+ '@graphql-eslint/description-style': 'error',
8
+ '@graphql-eslint/known-argument-names': 'error',
9
+ '@graphql-eslint/known-directives': 'error',
10
+ '@graphql-eslint/known-type-names': 'error',
11
+ '@graphql-eslint/lone-schema-definition': 'error',
12
+ '@graphql-eslint/naming-convention': [
13
+ 'error',
14
+ {
15
+ types: 'PascalCase',
16
+ FieldDefinition: 'camelCase',
17
+ InputValueDefinition: 'camelCase',
18
+ Argument: 'camelCase',
19
+ DirectiveDefinition: 'camelCase',
20
+ EnumValueDefinition: 'UPPER_CASE',
21
+ 'FieldDefinition[parent.name.value=Query]': {
22
+ forbiddenPrefixes: ['query', 'get'],
23
+ forbiddenSuffixes: ['Query'],
24
+ },
25
+ 'FieldDefinition[parent.name.value=Mutation]': {
26
+ forbiddenPrefixes: ['mutation'],
27
+ forbiddenSuffixes: ['Mutation'],
28
+ },
29
+ 'FieldDefinition[parent.name.value=Subscription]': {
30
+ forbiddenPrefixes: ['subscription'],
31
+ forbiddenSuffixes: ['Subscription'],
32
+ },
33
+ },
34
+ ],
35
+ '@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
36
+ '@graphql-eslint/no-hashtag-description': 'error',
37
+ '@graphql-eslint/no-typename-prefix': 'error',
38
+ '@graphql-eslint/no-unreachable-types': 'error',
39
+ '@graphql-eslint/provided-required-arguments': 'error',
40
+ '@graphql-eslint/require-deprecation-reason': 'error',
41
+ '@graphql-eslint/require-description': ['error', { types: true, DirectiveDefinition: true }],
42
+ '@graphql-eslint/strict-id-in-types': 'error',
43
+ '@graphql-eslint/unique-directive-names': 'error',
44
+ '@graphql-eslint/unique-directive-names-per-location': 'error',
45
+ '@graphql-eslint/unique-field-definition-names': 'error',
46
+ '@graphql-eslint/unique-operation-types': 'error',
47
+ '@graphql-eslint/unique-type-names': 'error',
48
+ },
49
+ };
@@ -0,0 +1,144 @@
1
+ import { resolve } from 'path';
2
+ import { Kind, visit, } from 'graphql';
3
+ import debugFactory from 'debug';
4
+ import fg from 'fast-glob';
5
+ import { logger } from './utils.js';
6
+ import { ModuleCache } from './cache.js';
7
+ const debug = debugFactory('graphql-eslint:operations');
8
+ const handleVirtualPath = (documents) => {
9
+ const filepathMap = Object.create(null);
10
+ return documents.map(source => {
11
+ var _a;
12
+ const { location } = source;
13
+ if (['.gql', '.graphql'].some(extension => location.endsWith(extension))) {
14
+ return source;
15
+ }
16
+ (_a = filepathMap[location]) !== null && _a !== void 0 ? _a : (filepathMap[location] = -1);
17
+ const index = (filepathMap[location] += 1);
18
+ return {
19
+ ...source,
20
+ location: resolve(location, `${index}_document.graphql`),
21
+ };
22
+ });
23
+ };
24
+ const operationsCache = new ModuleCache();
25
+ const siblingOperationsCache = new Map();
26
+ const getSiblings = (project) => {
27
+ const documentsKey = project.documents;
28
+ if (!documentsKey) {
29
+ return [];
30
+ }
31
+ let siblings = operationsCache.get(documentsKey);
32
+ if (!siblings) {
33
+ debug('Loading operations from %o', project.documents);
34
+ const documents = project.loadDocumentsSync(project.documents, {
35
+ skipGraphQLImport: true,
36
+ pluckConfig: project.extensions.pluckConfig,
37
+ });
38
+ if (debug.enabled) {
39
+ debug('Loaded %d operations', documents.length);
40
+ const operationsPaths = fg.sync(project.documents, { absolute: true });
41
+ debug('Operations pointers %O', operationsPaths);
42
+ }
43
+ siblings = handleVirtualPath(documents);
44
+ operationsCache.set(documentsKey, siblings);
45
+ }
46
+ return siblings;
47
+ };
48
+ export function getDocuments(project) {
49
+ const siblings = getSiblings(project);
50
+ if (siblings.length === 0) {
51
+ let printed = false;
52
+ const noopWarn = () => {
53
+ if (!printed) {
54
+ logger.warn('getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!');
55
+ printed = true;
56
+ }
57
+ return [];
58
+ };
59
+ return {
60
+ available: false,
61
+ getFragment: noopWarn,
62
+ getFragments: noopWarn,
63
+ getFragmentByType: noopWarn,
64
+ getFragmentsInUse: noopWarn,
65
+ getOperation: noopWarn,
66
+ getOperations: noopWarn,
67
+ getOperationByType: noopWarn,
68
+ };
69
+ }
70
+ // Since the siblings array is cached, we can use it as cache key.
71
+ // We should get the same array reference each time we get
72
+ // to this point for the same graphql project
73
+ if (siblingOperationsCache.has(siblings)) {
74
+ return siblingOperationsCache.get(siblings);
75
+ }
76
+ let fragmentsCache = null;
77
+ const getFragments = () => {
78
+ if (fragmentsCache === null) {
79
+ const result = [];
80
+ for (const source of siblings) {
81
+ for (const definition of source.document.definitions) {
82
+ if (definition.kind === Kind.FRAGMENT_DEFINITION) {
83
+ result.push({
84
+ filePath: source.location,
85
+ document: definition,
86
+ });
87
+ }
88
+ }
89
+ }
90
+ fragmentsCache = result;
91
+ }
92
+ return fragmentsCache;
93
+ };
94
+ let cachedOperations = null;
95
+ const getOperations = () => {
96
+ if (cachedOperations === null) {
97
+ const result = [];
98
+ for (const source of siblings) {
99
+ for (const definition of source.document.definitions) {
100
+ if (definition.kind === Kind.OPERATION_DEFINITION) {
101
+ result.push({
102
+ filePath: source.location,
103
+ document: definition,
104
+ });
105
+ }
106
+ }
107
+ }
108
+ cachedOperations = result;
109
+ }
110
+ return cachedOperations;
111
+ };
112
+ const getFragment = (name) => getFragments().filter(f => { var _a; return ((_a = f.document.name) === null || _a === void 0 ? void 0 : _a.value) === name; });
113
+ const collectFragments = (selectable, recursive, collected = new Map()) => {
114
+ visit(selectable, {
115
+ FragmentSpread(spread) {
116
+ const fragmentName = spread.name.value;
117
+ const [fragment] = getFragment(fragmentName);
118
+ if (!fragment) {
119
+ logger.warn(`Unable to locate fragment named "${fragmentName}", please make sure it's loaded using "parserOptions.operations"`);
120
+ return;
121
+ }
122
+ if (!collected.has(fragmentName)) {
123
+ collected.set(fragmentName, fragment.document);
124
+ if (recursive) {
125
+ collectFragments(fragment.document, recursive, collected);
126
+ }
127
+ }
128
+ },
129
+ });
130
+ return collected;
131
+ };
132
+ const siblingOperations = {
133
+ available: true,
134
+ getFragment,
135
+ getFragments,
136
+ getFragmentByType: typeName => getFragments().filter(f => { var _a, _b; return ((_b = (_a = f.document.typeCondition) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value) === typeName; }),
137
+ getFragmentsInUse: (selectable, recursive = true) => Array.from(collectFragments(selectable, recursive).values()),
138
+ getOperation: name => getOperations().filter(o => { var _a; return ((_a = o.document.name) === null || _a === void 0 ? void 0 : _a.value) === name; }),
139
+ getOperations,
140
+ getOperationByType: type => getOperations().filter(o => o.document.operation === type),
141
+ };
142
+ siblingOperationsCache.set(siblings, siblingOperations);
143
+ return siblingOperations;
144
+ }
@@ -0,0 +1,58 @@
1
+ import { TypeInfo, visit, visitWithTypeInfo, Kind, } from 'graphql';
2
+ import { convertLocation } from './utils.js';
3
+ export function convertToESTree(node, schema) {
4
+ const typeInfo = schema ? new TypeInfo(schema) : null;
5
+ const visitor = {
6
+ leave(node, key, parent) {
7
+ const leadingComments = 'description' in node && node.description
8
+ ? [
9
+ {
10
+ type: node.description.block ? 'Block' : 'Line',
11
+ value: node.description.value,
12
+ },
13
+ ]
14
+ : [];
15
+ const calculatedTypeInfo = typeInfo
16
+ ? {
17
+ argument: typeInfo.getArgument(),
18
+ defaultValue: typeInfo.getDefaultValue(),
19
+ directive: typeInfo.getDirective(),
20
+ enumValue: typeInfo.getEnumValue(),
21
+ fieldDef: typeInfo.getFieldDef(),
22
+ inputType: typeInfo.getInputType(),
23
+ parentInputType: typeInfo.getParentInputType(),
24
+ parentType: typeInfo.getParentType(),
25
+ gqlType: typeInfo.getType(),
26
+ }
27
+ : {};
28
+ const rawNode = () => {
29
+ if (parent && key !== undefined) {
30
+ return parent[key];
31
+ }
32
+ return node.kind === Kind.DOCUMENT
33
+ ? {
34
+ ...node,
35
+ definitions: node.definitions.map(definition => definition.rawNode()),
36
+ }
37
+ : node;
38
+ };
39
+ const commonFields = {
40
+ ...node,
41
+ type: node.kind,
42
+ loc: convertLocation(node.loc),
43
+ range: [node.loc.start, node.loc.end],
44
+ leadingComments,
45
+ // Use function to prevent RangeError: Maximum call stack size exceeded
46
+ typeInfo: () => calculatedTypeInfo,
47
+ rawNode,
48
+ };
49
+ return 'type' in node
50
+ ? {
51
+ ...commonFields,
52
+ gqlType: node.type,
53
+ }
54
+ : commonFields;
55
+ },
56
+ };
57
+ return visit(node, typeInfo ? visitWithTypeInfo(typeInfo, visitor) : visitor);
58
+ }
@@ -0,0 +1,3 @@
1
+ export * from './converter.js';
2
+ export * from './types.js';
3
+ export * from './utils.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ import { createRequire } from 'module';
2
+ const require = createRequire(import.meta.url);
3
+ import { TokenKind, isNonNullType, isListType, Source, } from 'graphql';
4
+ import { valueFromASTUntyped } from 'graphql/utilities/valueFromASTUntyped.js';
5
+ export const valueFromNode = (...args) => {
6
+ return valueFromASTUntyped(...args);
7
+ };
8
+ export function getBaseType(type) {
9
+ if (isNonNullType(type) || isListType(type)) {
10
+ return getBaseType(type.ofType);
11
+ }
12
+ return type;
13
+ }
14
+ export function convertToken(token, type) {
15
+ const { line, column, end, start, value } = token;
16
+ return {
17
+ type,
18
+ value,
19
+ /*
20
+ * ESLint has 0-based column number
21
+ * https://eslint.org/docs/developer-guide/working-with-rules#contextreport
22
+ */
23
+ loc: {
24
+ start: {
25
+ line,
26
+ column: column - 1,
27
+ },
28
+ end: {
29
+ line,
30
+ column: column - 1 + (end - start),
31
+ },
32
+ },
33
+ range: [start, end],
34
+ };
35
+ }
36
+ function getLexer(source) {
37
+ // GraphQL v14
38
+ const gqlLanguage = require('graphql/language');
39
+ if (gqlLanguage && gqlLanguage.createLexer) {
40
+ return gqlLanguage.createLexer(source, {});
41
+ }
42
+ // GraphQL v15
43
+ const { Lexer: LexerCls } = require('graphql');
44
+ if (LexerCls && typeof LexerCls === 'function') {
45
+ return new LexerCls(source);
46
+ }
47
+ throw new Error('Unsupported GraphQL version! Please make sure to use GraphQL v14 or newer!');
48
+ }
49
+ export function extractTokens(filePath, code) {
50
+ const source = new Source(code, filePath);
51
+ const lexer = getLexer(source);
52
+ const tokens = [];
53
+ let token = lexer.advance();
54
+ while (token && token.kind !== TokenKind.EOF) {
55
+ const result = convertToken(token, token.kind);
56
+ tokens.push(result);
57
+ token = lexer.advance();
58
+ }
59
+ return tokens;
60
+ }
61
+ export function extractComments(loc) {
62
+ if (!loc) {
63
+ return [];
64
+ }
65
+ const comments = [];
66
+ let token = loc.startToken;
67
+ while (token) {
68
+ if (token.kind === TokenKind.COMMENT) {
69
+ const comment = convertToken(token,
70
+ // `eslint-disable` directive works only with `Block` type comment
71
+ token.value.trimStart().startsWith('eslint') ? 'Block' : 'Line');
72
+ comments.push(comment);
73
+ }
74
+ token = token.next;
75
+ }
76
+ return comments;
77
+ }
78
+ export function convertLocation(location) {
79
+ const { startToken, endToken, source, start, end } = location;
80
+ /*
81
+ * ESLint has 0-based column number
82
+ * https://eslint.org/docs/developer-guide/working-with-rules#contextreport
83
+ */
84
+ const loc = {
85
+ start: {
86
+ /*
87
+ * Kind.Document has startToken: { line: 0, column: 0 }, we set line as 1 and column as 0
88
+ */
89
+ line: startToken.line === 0 ? 1 : startToken.line,
90
+ column: startToken.column === 0 ? 0 : startToken.column - 1,
91
+ },
92
+ end: {
93
+ line: endToken.line,
94
+ column: endToken.column - 1,
95
+ },
96
+ source: source.body,
97
+ };
98
+ if (loc.start.column === loc.end.column) {
99
+ loc.end.column += end - start;
100
+ }
101
+ return loc;
102
+ }
@@ -0,0 +1,33 @@
1
+ import { parseForESLint } from './parser.js';
2
+ import { configs } from './configs/index.js';
3
+ const languageOptions = {
4
+ parser: { parseForESLint },
5
+ };
6
+ export const flatConfigs = {
7
+ 'operations-all': {
8
+ languageOptions,
9
+ rules: {
10
+ ...configs['operations-recommended'].rules,
11
+ ...configs['operations-all'].rules,
12
+ },
13
+ },
14
+ 'operations-recommended': {
15
+ languageOptions,
16
+ rules: configs['operations-recommended'].rules,
17
+ },
18
+ relay: {
19
+ languageOptions,
20
+ rules: configs.relay.rules,
21
+ },
22
+ 'schema-all': {
23
+ languageOptions,
24
+ rules: {
25
+ ...configs['schema-recommended'].rules,
26
+ ...configs['schema-all'].rules,
27
+ },
28
+ },
29
+ 'schema-recommended': {
30
+ languageOptions,
31
+ rules: configs['schema-recommended'].rules,
32
+ },
33
+ };
@@ -0,0 +1,49 @@
1
+ import { dirname } from 'path';
2
+ import debugFactory from 'debug';
3
+ import { GraphQLConfig, loadConfigSync } from 'graphql-config';
4
+ import { CodeFileLoader } from '@graphql-tools/code-file-loader';
5
+ const debug = debugFactory('graphql-eslint:graphql-config');
6
+ let graphQLConfig;
7
+ export function loadOnDiskGraphQLConfig(filePath) {
8
+ return loadConfigSync({
9
+ // load config relative to the file being linted
10
+ rootDir: dirname(filePath),
11
+ throwOnEmpty: false,
12
+ throwOnMissing: false,
13
+ extensions: [codeFileLoaderExtension],
14
+ });
15
+ }
16
+ export function loadGraphQLConfig(options) {
17
+ // We don't want cache config on test environment
18
+ // Otherwise schema and documents will be same for all tests
19
+ if (process.env.NODE_ENV !== 'test' && graphQLConfig) {
20
+ return graphQLConfig;
21
+ }
22
+ const onDiskConfig = !options.skipGraphQLConfig && loadOnDiskGraphQLConfig(options.filePath);
23
+ debug('options.skipGraphQLConfig: %o', options.skipGraphQLConfig);
24
+ if (onDiskConfig) {
25
+ debug('Graphql-config path %o', onDiskConfig.filepath);
26
+ }
27
+ const configOptions = options.projects
28
+ ? { projects: options.projects }
29
+ : {
30
+ schema: (options.schema || ''),
31
+ documents: options.documents || options.operations,
32
+ extensions: options.extensions,
33
+ include: options.include,
34
+ exclude: options.exclude,
35
+ };
36
+ graphQLConfig =
37
+ onDiskConfig ||
38
+ new GraphQLConfig({
39
+ config: configOptions,
40
+ filepath: 'virtual-config',
41
+ }, [codeFileLoaderExtension]);
42
+ return graphQLConfig;
43
+ }
44
+ const codeFileLoaderExtension = api => {
45
+ const { schema, documents } = api.loaders;
46
+ schema.register(new CodeFileLoader());
47
+ documents.register(new CodeFileLoader());
48
+ return { name: 'graphql-eslint-loaders' };
49
+ };
package/esm/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import { processor } from './processor.js';
2
+ export { rules } from './rules/index.js';
3
+ export { parseForESLint } from './parser.js';
4
+ export * from './testkit.js';
5
+ export * from './types.js';
6
+ export { requireGraphQLSchemaFromContext, requireSiblingsOperations } from './utils.js';
7
+ export const processors = { graphql: processor };
8
+ export { configs } from './configs/index.js';
9
+ export { flatConfigs } from './flat-configs.js';
@@ -0,0 +1 @@
1
+ { "type": "module" }
package/esm/parser.js ADDED
@@ -0,0 +1,56 @@
1
+ import { parseGraphQLSDL } from '@graphql-tools/utils';
2
+ import { GraphQLError, GraphQLSchema } from 'graphql';
3
+ import debugFactory from 'debug';
4
+ import { convertToESTree, extractComments, extractTokens } from './estree-converter/index.js';
5
+ import { getSchema } from './schema.js';
6
+ import { getDocuments } from './documents.js';
7
+ import { loadGraphQLConfig } from './graphql-config.js';
8
+ import { CWD, VIRTUAL_DOCUMENT_REGEX } from './utils.js';
9
+ const debug = debugFactory('graphql-eslint:parser');
10
+ debug('cwd %o', CWD);
11
+ export function parseForESLint(code, options) {
12
+ try {
13
+ const { filePath } = options;
14
+ // First parse code from file, in case of syntax error do not try load schema,
15
+ // documents or even graphql-config instance
16
+ const { document } = parseGraphQLSDL(filePath, code, {
17
+ ...options.graphQLParserOptions,
18
+ noLocation: false,
19
+ });
20
+ const gqlConfig = loadGraphQLConfig(options);
21
+ const realFilepath = filePath.replace(VIRTUAL_DOCUMENT_REGEX, '');
22
+ const project = gqlConfig.getProjectForFile(realFilepath);
23
+ const schema = getSchema(project, options.schemaOptions);
24
+ const rootTree = convertToESTree(document, schema instanceof GraphQLSchema ? schema : null);
25
+ return {
26
+ services: {
27
+ schema,
28
+ siblingOperations: getDocuments(project),
29
+ },
30
+ ast: {
31
+ comments: extractComments(document.loc),
32
+ tokens: extractTokens(filePath, code),
33
+ loc: rootTree.loc,
34
+ range: rootTree.range,
35
+ type: 'Program',
36
+ sourceType: 'script',
37
+ body: [rootTree],
38
+ },
39
+ };
40
+ }
41
+ catch (error) {
42
+ error.message = `[graphql-eslint] ${error.message}`;
43
+ // In case of GraphQL parser error, we report it to ESLint as a parser error that matches the requirements
44
+ // of ESLint. This will make sure to display it correctly in IDEs and lint results.
45
+ if (error instanceof GraphQLError) {
46
+ const eslintError = {
47
+ index: error.positions[0],
48
+ lineNumber: error.locations[0].line,
49
+ column: error.locations[0].column - 1,
50
+ message: error.message,
51
+ };
52
+ throw eslintError;
53
+ }
54
+ throw error;
55
+ }
56
+ }