@graphql-eslint/eslint-plugin 3.14.0-alpha-20221221142641-4e1a924 → 3.14.0-alpha-20221222124206-b82954b

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 (231) hide show
  1. package/README.md +309 -0
  2. package/cjs/cache.js +30 -0
  3. package/cjs/configs/base.js +7 -0
  4. package/cjs/configs/index.js +16 -0
  5. package/cjs/configs/operations-all.js +31 -0
  6. package/cjs/configs/operations-recommended.js +56 -0
  7. package/cjs/configs/relay.js +12 -0
  8. package/cjs/configs/schema-all.js +23 -0
  9. package/cjs/configs/schema-recommended.js +52 -0
  10. package/cjs/documents.js +149 -0
  11. package/cjs/estree-converter/converter.js +62 -0
  12. package/cjs/estree-converter/index.js +6 -0
  13. package/cjs/estree-converter/types.js +2 -0
  14. package/cjs/estree-converter/utils.js +109 -0
  15. package/cjs/graphql-config.js +55 -0
  16. package/cjs/index.js +17 -0
  17. package/cjs/parser.js +61 -0
  18. package/cjs/processor.js +78 -0
  19. package/cjs/rules/alphabetize.js +348 -0
  20. package/cjs/rules/description-style.js +78 -0
  21. package/cjs/rules/graphql-js-validation.js +499 -0
  22. package/cjs/rules/index.js +68 -0
  23. package/cjs/rules/input-name.js +136 -0
  24. package/cjs/rules/lone-executable-definition.js +88 -0
  25. package/cjs/rules/match-document-filename.js +235 -0
  26. package/cjs/rules/naming-convention.js +310 -0
  27. package/cjs/rules/no-anonymous-operations.js +67 -0
  28. package/cjs/rules/no-case-insensitive-enum-values-duplicates.js +61 -0
  29. package/cjs/rules/no-deprecated.js +124 -0
  30. package/cjs/rules/no-duplicate-fields.js +112 -0
  31. package/cjs/rules/no-hashtag-description.js +89 -0
  32. package/cjs/rules/no-root-type.js +86 -0
  33. package/cjs/rules/no-scalar-result-type-on-mutation.js +66 -0
  34. package/cjs/rules/no-typename-prefix.js +65 -0
  35. package/cjs/rules/no-unreachable-types.js +158 -0
  36. package/cjs/rules/no-unused-fields.js +130 -0
  37. package/cjs/rules/relay-arguments.js +121 -0
  38. package/cjs/rules/relay-connection-types.js +107 -0
  39. package/cjs/rules/relay-edge-types.js +189 -0
  40. package/cjs/rules/relay-page-info.js +100 -0
  41. package/cjs/rules/require-deprecation-date.js +123 -0
  42. package/cjs/rules/require-deprecation-reason.js +56 -0
  43. package/cjs/rules/require-description.js +193 -0
  44. package/cjs/rules/require-field-of-type-query-in-mutation-result.js +72 -0
  45. package/cjs/rules/require-id-when-available.js +199 -0
  46. package/cjs/rules/selection-set-depth.js +135 -0
  47. package/cjs/rules/strict-id-in-types.js +162 -0
  48. package/cjs/rules/unique-fragment-name.js +90 -0
  49. package/cjs/rules/unique-operation-name.js +65 -0
  50. package/cjs/schema.js +42 -0
  51. package/cjs/testkit.js +183 -0
  52. package/cjs/types.js +2 -0
  53. package/cjs/utils.js +96 -0
  54. package/docs/README.md +82 -0
  55. package/docs/custom-rules.md +184 -0
  56. package/docs/deprecated-rules.md +24 -0
  57. package/docs/parser-options.md +95 -0
  58. package/docs/parser.md +67 -0
  59. package/docs/rules/alphabetize.md +194 -0
  60. package/docs/rules/description-style.md +57 -0
  61. package/docs/rules/executable-definitions.md +20 -0
  62. package/docs/rules/fields-on-correct-type.md +23 -0
  63. package/docs/rules/fragments-on-composite-type.md +20 -0
  64. package/docs/rules/input-name.md +80 -0
  65. package/docs/rules/known-argument-names.md +23 -0
  66. package/docs/rules/known-directives.md +48 -0
  67. package/docs/rules/known-fragment-names.md +72 -0
  68. package/docs/rules/known-type-names.md +24 -0
  69. package/docs/rules/lone-anonymous-operation.md +20 -0
  70. package/docs/rules/lone-executable-definition.md +59 -0
  71. package/docs/rules/lone-schema-definition.md +19 -0
  72. package/docs/rules/match-document-filename.md +181 -0
  73. package/docs/rules/naming-convention.md +320 -0
  74. package/docs/rules/no-anonymous-operations.md +43 -0
  75. package/docs/rules/no-case-insensitive-enum-values-duplicates.md +46 -0
  76. package/docs/rules/no-deprecated.md +88 -0
  77. package/docs/rules/no-duplicate-fields.md +69 -0
  78. package/docs/rules/no-fragment-cycles.md +19 -0
  79. package/docs/rules/no-hashtag-description.md +62 -0
  80. package/docs/rules/no-root-type.md +55 -0
  81. package/docs/rules/no-scalar-result-type-on-mutation.md +39 -0
  82. package/docs/rules/no-typename-prefix.md +42 -0
  83. package/docs/rules/no-undefined-variables.md +20 -0
  84. package/docs/rules/no-unreachable-types.md +52 -0
  85. package/docs/rules/no-unused-fields.md +64 -0
  86. package/docs/rules/no-unused-fragments.md +20 -0
  87. package/docs/rules/no-unused-variables.md +20 -0
  88. package/docs/rules/one-field-subscriptions.md +19 -0
  89. package/docs/rules/overlapping-fields-can-be-merged.md +20 -0
  90. package/docs/rules/possible-fragment-spread.md +21 -0
  91. package/docs/rules/possible-type-extension.md +19 -0
  92. package/docs/rules/provided-required-arguments.md +21 -0
  93. package/docs/rules/relay-arguments.md +59 -0
  94. package/docs/rules/relay-connection-types.md +43 -0
  95. package/docs/rules/relay-edge-types.md +60 -0
  96. package/docs/rules/relay-page-info.md +34 -0
  97. package/docs/rules/require-deprecation-date.md +59 -0
  98. package/docs/rules/require-deprecation-reason.md +49 -0
  99. package/docs/rules/require-description.md +147 -0
  100. package/docs/rules/require-field-of-type-query-in-mutation-result.md +50 -0
  101. package/docs/rules/require-id-when-available.md +91 -0
  102. package/docs/rules/scalar-leafs.md +23 -0
  103. package/docs/rules/selection-set-depth.md +86 -0
  104. package/docs/rules/strict-id-in-types.md +129 -0
  105. package/docs/rules/unique-argument-names.md +19 -0
  106. package/docs/rules/unique-directive-names-per-location.md +21 -0
  107. package/docs/rules/unique-directive-names.md +19 -0
  108. package/docs/rules/unique-enum-value-names.md +16 -0
  109. package/docs/rules/unique-field-definition-names.md +19 -0
  110. package/docs/rules/unique-fragment-name.md +52 -0
  111. package/docs/rules/unique-input-field-names.md +19 -0
  112. package/docs/rules/unique-operation-name.md +56 -0
  113. package/docs/rules/unique-operation-types.md +19 -0
  114. package/docs/rules/unique-type-names.md +19 -0
  115. package/docs/rules/unique-variable-names.md +19 -0
  116. package/docs/rules/value-literals-of-correct-type.md +22 -0
  117. package/docs/rules/variables-are-input-types.md +20 -0
  118. package/docs/rules/variables-in-allowed-position.md +19 -0
  119. package/package.json +8 -11
  120. package/{cache.d.ts → typings/cache.d.cts} +0 -0
  121. package/typings/cache.d.ts +10 -0
  122. package/typings/configs/base.d.cts +5 -0
  123. package/typings/configs/base.d.ts +5 -0
  124. package/typings/configs/index.d.cts +139 -0
  125. package/typings/configs/index.d.ts +139 -0
  126. package/typings/configs/operations-all.d.cts +20 -0
  127. package/typings/configs/operations-all.d.ts +20 -0
  128. package/typings/configs/operations-recommended.d.cts +50 -0
  129. package/typings/configs/operations-recommended.d.ts +50 -0
  130. package/typings/configs/relay.d.cts +10 -0
  131. package/typings/configs/relay.d.ts +10 -0
  132. package/typings/configs/schema-all.d.cts +15 -0
  133. package/typings/configs/schema-all.d.ts +15 -0
  134. package/typings/configs/schema-recommended.d.cts +47 -0
  135. package/typings/configs/schema-recommended.d.ts +47 -0
  136. package/{documents.d.ts → typings/documents.d.cts} +0 -0
  137. package/typings/documents.d.ts +21 -0
  138. package/{estree-converter/converter.d.ts → typings/estree-converter/converter.d.cts} +0 -0
  139. package/typings/estree-converter/converter.d.ts +3 -0
  140. package/{estree-converter/index.d.ts → typings/estree-converter/index.d.cts} +0 -0
  141. package/typings/estree-converter/index.d.ts +3 -0
  142. package/{estree-converter/types.d.ts → typings/estree-converter/types.d.cts} +0 -0
  143. package/typings/estree-converter/types.d.ts +40 -0
  144. package/{estree-converter/utils.d.ts → typings/estree-converter/utils.d.cts} +0 -0
  145. package/typings/estree-converter/utils.d.ts +13 -0
  146. package/{graphql-config.d.ts → typings/graphql-config.d.cts} +0 -0
  147. package/typings/graphql-config.d.ts +4 -0
  148. package/typings/index.d.cts +9 -0
  149. package/{index.d.ts → typings/index.d.ts} +1 -5
  150. package/{parser.d.ts → typings/parser.d.cts} +0 -0
  151. package/typings/parser.d.ts +2 -0
  152. package/{processor.d.ts → typings/processor.d.cts} +0 -0
  153. package/typings/processor.d.ts +6 -0
  154. package/{rules/alphabetize.d.ts → typings/rules/alphabetize.d.cts} +0 -0
  155. package/typings/rules/alphabetize.d.ts +76 -0
  156. package/{rules/description-style.d.ts → typings/rules/description-style.d.cts} +0 -0
  157. package/typings/rules/description-style.d.ts +20 -0
  158. package/{rules/graphql-js-validation.d.ts → typings/rules/graphql-js-validation.d.cts} +0 -0
  159. package/typings/rules/graphql-js-validation.d.ts +2 -0
  160. package/{rules/index.d.ts → typings/rules/index.d.cts} +0 -0
  161. package/typings/rules/index.d.ts +104 -0
  162. package/{rules/input-name.d.ts → typings/rules/input-name.d.cts} +0 -0
  163. package/typings/rules/input-name.d.ts +35 -0
  164. package/{rules/lone-executable-definition.d.ts → typings/rules/lone-executable-definition.d.cts} +0 -0
  165. package/typings/rules/lone-executable-definition.d.ts +26 -0
  166. package/{rules/match-document-filename.d.ts → typings/rules/match-document-filename.d.cts} +0 -0
  167. package/typings/rules/match-document-filename.d.ts +72 -0
  168. package/{rules/naming-convention.d.ts → typings/rules/naming-convention.d.cts} +0 -0
  169. package/typings/rules/naming-convention.d.ts +83 -0
  170. package/{rules/no-anonymous-operations.d.ts → typings/rules/no-anonymous-operations.d.cts} +0 -0
  171. package/{rules/no-case-insensitive-enum-values-duplicates.d.ts → typings/rules/no-anonymous-operations.d.ts} +0 -0
  172. package/{rules/no-hashtag-description.d.ts → typings/rules/no-case-insensitive-enum-values-duplicates.d.cts} +0 -0
  173. package/{rules/no-scalar-result-type-on-mutation.d.ts → typings/rules/no-case-insensitive-enum-values-duplicates.d.ts} +0 -0
  174. package/{rules/no-deprecated.d.ts → typings/rules/no-deprecated.d.cts} +0 -0
  175. package/typings/rules/no-deprecated.d.ts +2 -0
  176. package/{rules/no-duplicate-fields.d.ts → typings/rules/no-duplicate-fields.d.cts} +0 -0
  177. package/{rules/relay-page-info.d.ts → typings/rules/no-duplicate-fields.d.ts} +0 -0
  178. package/{rules/no-typename-prefix.d.ts → typings/rules/no-hashtag-description.d.cts} +0 -0
  179. package/{rules/no-unreachable-types.d.ts → typings/rules/no-hashtag-description.d.ts} +0 -0
  180. package/{rules/no-root-type.d.ts → typings/rules/no-root-type.d.cts} +0 -0
  181. package/typings/rules/no-root-type.d.ts +25 -0
  182. package/{rules/no-unused-fields.d.ts → typings/rules/no-scalar-result-type-on-mutation.d.cts} +0 -0
  183. package/{rules/unique-operation-name.d.ts → typings/rules/no-scalar-result-type-on-mutation.d.ts} +0 -0
  184. package/typings/rules/no-typename-prefix.d.cts +2 -0
  185. package/typings/rules/no-typename-prefix.d.ts +2 -0
  186. package/typings/rules/no-unreachable-types.d.cts +2 -0
  187. package/typings/rules/no-unreachable-types.d.ts +2 -0
  188. package/typings/rules/no-unused-fields.d.cts +2 -0
  189. package/typings/rules/no-unused-fields.d.ts +2 -0
  190. package/{rules/relay-arguments.d.ts → typings/rules/relay-arguments.d.cts} +0 -0
  191. package/typings/rules/relay-arguments.d.ts +21 -0
  192. package/{rules/relay-connection-types.d.ts → typings/rules/relay-connection-types.d.cts} +0 -0
  193. package/typings/rules/relay-connection-types.d.ts +4 -0
  194. package/{rules/relay-edge-types.d.ts → typings/rules/relay-edge-types.d.cts} +0 -0
  195. package/typings/rules/relay-edge-types.d.ts +31 -0
  196. package/{rules/require-deprecation-reason.d.ts → typings/rules/relay-page-info.d.cts} +0 -0
  197. package/{rules/require-field-of-type-query-in-mutation-result.d.ts → typings/rules/relay-page-info.d.ts} +0 -0
  198. package/{rules/require-deprecation-date.d.ts → typings/rules/require-deprecation-date.d.cts} +0 -0
  199. package/typings/rules/require-deprecation-date.d.ts +18 -0
  200. package/typings/rules/require-deprecation-reason.d.cts +2 -0
  201. package/typings/rules/require-deprecation-reason.d.ts +2 -0
  202. package/{rules/require-description.d.ts → typings/rules/require-description.d.cts} +0 -0
  203. package/typings/rules/require-description.d.ts +14 -0
  204. package/typings/rules/require-field-of-type-query-in-mutation-result.d.cts +2 -0
  205. package/typings/rules/require-field-of-type-query-in-mutation-result.d.ts +2 -0
  206. package/{rules/require-id-when-available.d.ts → typings/rules/require-id-when-available.d.cts} +0 -0
  207. package/typings/rules/require-id-when-available.d.ts +36 -0
  208. package/{rules/selection-set-depth.d.ts → typings/rules/selection-set-depth.d.cts} +0 -0
  209. package/typings/rules/selection-set-depth.d.ts +28 -0
  210. package/{rules/strict-id-in-types.d.ts → typings/rules/strict-id-in-types.d.cts} +0 -0
  211. package/typings/rules/strict-id-in-types.d.ts +57 -0
  212. package/{rules/unique-fragment-name.d.ts → typings/rules/unique-fragment-name.d.cts} +0 -0
  213. package/typings/rules/unique-fragment-name.d.ts +5 -0
  214. package/typings/rules/unique-operation-name.d.cts +2 -0
  215. package/typings/rules/unique-operation-name.d.ts +2 -0
  216. package/{schema.d.ts → typings/schema.d.cts} +0 -0
  217. package/typings/schema.d.ts +3 -0
  218. package/{testkit.d.ts → typings/testkit.d.cts} +0 -0
  219. package/typings/testkit.d.ts +27 -0
  220. package/{types.d.ts → typings/types.d.cts} +0 -0
  221. package/typings/types.d.ts +81 -0
  222. package/{utils.d.ts → typings/utils.d.cts} +0 -0
  223. package/typings/utils.d.ts +34 -0
  224. package/configs/base.json +0 -4
  225. package/configs/operations-all.json +0 -25
  226. package/configs/operations-recommended.json +0 -50
  227. package/configs/relay.json +0 -9
  228. package/configs/schema-all.json +0 -17
  229. package/configs/schema-recommended.json +0 -49
  230. package/index.js +0 -4995
  231. package/index.mjs +0 -4983
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
6
+ exports.rule = {
7
+ meta: {
8
+ type: 'suggestion',
9
+ hasSuggestions: true,
10
+ schema: [],
11
+ messages: {
12
+ [HASHTAG_COMMENT]: 'Using hashtag `#` for adding GraphQL descriptions is not allowed. Prefer using `"""` for multiline, or `"` for a single line description.',
13
+ },
14
+ docs: {
15
+ description: 'Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.\nAllows to use hashtag for comments, as long as it\'s not attached to an AST definition.',
16
+ category: 'Schema',
17
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/no-hashtag-description.md',
18
+ examples: [
19
+ {
20
+ title: 'Incorrect',
21
+ code: /* GraphQL */ `
22
+ # Represents a user
23
+ type User {
24
+ id: ID!
25
+ name: String
26
+ }
27
+ `,
28
+ },
29
+ {
30
+ title: 'Correct',
31
+ code: /* GraphQL */ `
32
+ " Represents a user "
33
+ type User {
34
+ id: ID!
35
+ name: String
36
+ }
37
+ `,
38
+ },
39
+ {
40
+ title: 'Correct',
41
+ code: /* GraphQL */ `
42
+ # This file defines the basic User type.
43
+ # This comment is valid because it's not attached specifically to an AST object.
44
+
45
+ " Represents a user "
46
+ type User {
47
+ id: ID! # This one is also valid, since it comes after the AST object
48
+ name: String
49
+ }
50
+ `,
51
+ },
52
+ ],
53
+ recommended: true,
54
+ },
55
+ },
56
+ create(context) {
57
+ const selector = 'Document[definitions.0.kind!=/^(OperationDefinition|FragmentDefinition)$/]';
58
+ return {
59
+ [selector](node) {
60
+ const rawNode = node.rawNode();
61
+ let token = rawNode.loc.startToken;
62
+ while (token) {
63
+ const { kind, prev, next, value, line, column } = token;
64
+ if (kind === graphql_1.TokenKind.COMMENT && prev && next) {
65
+ const isEslintComment = value.trimStart().startsWith('eslint');
66
+ const linesAfter = next.line - line;
67
+ if (!isEslintComment &&
68
+ line !== prev.line &&
69
+ next.kind === graphql_1.TokenKind.NAME &&
70
+ linesAfter < 2) {
71
+ context.report({
72
+ messageId: HASHTAG_COMMENT,
73
+ loc: {
74
+ line,
75
+ column: column - 1,
76
+ },
77
+ suggest: ['"""', '"'].map(descriptionSyntax => ({
78
+ desc: `Replace with \`${descriptionSyntax}\` description syntax`,
79
+ fix: fixer => fixer.replaceTextRange([token.start, token.end], [descriptionSyntax, value.trim(), descriptionSyntax].join('')),
80
+ })),
81
+ });
82
+ }
83
+ }
84
+ token = next;
85
+ }
86
+ },
87
+ };
88
+ },
89
+ };
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const utils_1 = require("../utils");
5
+ const schema = {
6
+ type: 'array',
7
+ minItems: 1,
8
+ maxItems: 1,
9
+ items: {
10
+ type: 'object',
11
+ additionalProperties: false,
12
+ required: ['disallow'],
13
+ properties: {
14
+ disallow: {
15
+ ...utils_1.ARRAY_DEFAULT_OPTIONS,
16
+ items: {
17
+ enum: ['mutation', 'subscription'],
18
+ },
19
+ },
20
+ },
21
+ },
22
+ };
23
+ exports.rule = {
24
+ meta: {
25
+ type: 'suggestion',
26
+ hasSuggestions: true,
27
+ docs: {
28
+ category: 'Schema',
29
+ description: 'Disallow using root types `mutation` and/or `subscription`.',
30
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/no-root-type.md',
31
+ requiresSchema: true,
32
+ isDisabledForAllConfig: true,
33
+ examples: [
34
+ {
35
+ title: 'Incorrect',
36
+ usage: [{ disallow: ['mutation', 'subscription'] }],
37
+ code: /* GraphQL */ `
38
+ type Mutation {
39
+ createUser(input: CreateUserInput!): User!
40
+ }
41
+ `,
42
+ },
43
+ {
44
+ title: 'Correct',
45
+ usage: [{ disallow: ['mutation', 'subscription'] }],
46
+ code: /* GraphQL */ `
47
+ type Query {
48
+ users: [User!]!
49
+ }
50
+ `,
51
+ },
52
+ ],
53
+ },
54
+ schema,
55
+ },
56
+ create(context) {
57
+ const schema = (0, utils_1.requireGraphQLSchemaFromContext)('no-root-type', context);
58
+ const disallow = new Set(context.options[0].disallow);
59
+ const rootTypeNames = [
60
+ disallow.has('mutation') && schema.getMutationType(),
61
+ disallow.has('subscription') && schema.getSubscriptionType(),
62
+ ]
63
+ .filter(Boolean)
64
+ .map(type => type.name)
65
+ .join('|');
66
+ if (!rootTypeNames) {
67
+ return {};
68
+ }
69
+ const selector = `:matches(ObjectTypeDefinition, ObjectTypeExtension) > .name[value=/^(${rootTypeNames})$/]`;
70
+ return {
71
+ [selector](node) {
72
+ const typeName = node.value;
73
+ context.report({
74
+ node,
75
+ message: `Root type \`${typeName}\` is forbidden.`,
76
+ suggest: [
77
+ {
78
+ desc: `Remove \`${typeName}\` type`,
79
+ fix: fixer => fixer.remove(node.parent),
80
+ },
81
+ ],
82
+ });
83
+ },
84
+ };
85
+ },
86
+ };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const utils_1 = require("../utils");
6
+ const RULE_ID = 'no-scalar-result-type-on-mutation';
7
+ exports.rule = {
8
+ meta: {
9
+ type: 'suggestion',
10
+ hasSuggestions: true,
11
+ docs: {
12
+ category: 'Schema',
13
+ description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
14
+ url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
15
+ requiresSchema: true,
16
+ examples: [
17
+ {
18
+ title: 'Incorrect',
19
+ code: /* GraphQL */ `
20
+ type Mutation {
21
+ createUser: Boolean
22
+ }
23
+ `,
24
+ },
25
+ {
26
+ title: 'Correct',
27
+ code: /* GraphQL */ `
28
+ type Mutation {
29
+ createUser: User!
30
+ }
31
+ `,
32
+ },
33
+ ],
34
+ },
35
+ schema: [],
36
+ },
37
+ create(context) {
38
+ const schema = (0, utils_1.requireGraphQLSchemaFromContext)(RULE_ID, context);
39
+ const mutationType = schema.getMutationType();
40
+ if (!mutationType) {
41
+ return {};
42
+ }
43
+ const selector = [
44
+ `:matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=${mutationType.name}]`,
45
+ '> FieldDefinition > .gqlType Name',
46
+ ].join(' ');
47
+ return {
48
+ [selector](node) {
49
+ const typeName = node.value;
50
+ const graphQLType = schema.getType(typeName);
51
+ if ((0, graphql_1.isScalarType)(graphQLType)) {
52
+ context.report({
53
+ node,
54
+ message: `Unexpected scalar result type \`${typeName}\`.`,
55
+ suggest: [
56
+ {
57
+ desc: `Remove \`${typeName}\``,
58
+ fix: fixer => fixer.remove(node),
59
+ },
60
+ ],
61
+ });
62
+ }
63
+ },
64
+ };
65
+ },
66
+ };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const NO_TYPENAME_PREFIX = 'NO_TYPENAME_PREFIX';
5
+ exports.rule = {
6
+ meta: {
7
+ type: 'suggestion',
8
+ hasSuggestions: true,
9
+ docs: {
10
+ category: 'Schema',
11
+ description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
12
+ recommended: true,
13
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/no-typename-prefix.md',
14
+ examples: [
15
+ {
16
+ title: 'Incorrect',
17
+ code: /* GraphQL */ `
18
+ type User {
19
+ userId: ID!
20
+ }
21
+ `,
22
+ },
23
+ {
24
+ title: 'Correct',
25
+ code: /* GraphQL */ `
26
+ type User {
27
+ id: ID!
28
+ }
29
+ `,
30
+ },
31
+ ],
32
+ },
33
+ messages: {
34
+ [NO_TYPENAME_PREFIX]: 'Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"',
35
+ },
36
+ schema: [],
37
+ },
38
+ create(context) {
39
+ return {
40
+ 'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
41
+ const typeName = node.name.value;
42
+ const lowerTypeName = typeName.toLowerCase();
43
+ for (const field of node.fields) {
44
+ const fieldName = field.name.value;
45
+ if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
46
+ context.report({
47
+ data: {
48
+ fieldName,
49
+ typeName,
50
+ },
51
+ messageId: NO_TYPENAME_PREFIX,
52
+ node: field.name,
53
+ suggest: [
54
+ {
55
+ desc: `Remove \`${fieldName.slice(0, typeName.length)}\` prefix`,
56
+ fix: fixer => fixer.replaceText(field.name, fieldName.replace(new RegExp(`^${typeName}`, 'i'), '')),
57
+ },
58
+ ],
59
+ });
60
+ }
61
+ }
62
+ },
63
+ };
64
+ },
65
+ };
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const graphql_1 = require("graphql");
6
+ const lodash_lowercase_1 = tslib_1.__importDefault(require("lodash.lowercase"));
7
+ const utils_1 = require("../utils");
8
+ const RULE_ID = 'no-unreachable-types';
9
+ const KINDS = [
10
+ graphql_1.Kind.DIRECTIVE_DEFINITION,
11
+ graphql_1.Kind.OBJECT_TYPE_DEFINITION,
12
+ graphql_1.Kind.OBJECT_TYPE_EXTENSION,
13
+ graphql_1.Kind.INTERFACE_TYPE_DEFINITION,
14
+ graphql_1.Kind.INTERFACE_TYPE_EXTENSION,
15
+ graphql_1.Kind.SCALAR_TYPE_DEFINITION,
16
+ graphql_1.Kind.SCALAR_TYPE_EXTENSION,
17
+ graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION,
18
+ graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION,
19
+ graphql_1.Kind.UNION_TYPE_DEFINITION,
20
+ graphql_1.Kind.UNION_TYPE_EXTENSION,
21
+ graphql_1.Kind.ENUM_TYPE_DEFINITION,
22
+ graphql_1.Kind.ENUM_TYPE_EXTENSION,
23
+ ];
24
+ let reachableTypesCache;
25
+ const RequestDirectiveLocations = new Set([
26
+ graphql_1.DirectiveLocation.QUERY,
27
+ graphql_1.DirectiveLocation.MUTATION,
28
+ graphql_1.DirectiveLocation.SUBSCRIPTION,
29
+ graphql_1.DirectiveLocation.FIELD,
30
+ graphql_1.DirectiveLocation.FRAGMENT_DEFINITION,
31
+ graphql_1.DirectiveLocation.FRAGMENT_SPREAD,
32
+ graphql_1.DirectiveLocation.INLINE_FRAGMENT,
33
+ graphql_1.DirectiveLocation.VARIABLE_DEFINITION,
34
+ ]);
35
+ function getReachableTypes(schema) {
36
+ // We don't want cache reachableTypes on test environment
37
+ // Otherwise reachableTypes will be same for all tests
38
+ if (process.env.NODE_ENV !== 'test' && reachableTypesCache) {
39
+ return reachableTypesCache;
40
+ }
41
+ const reachableTypes = new Set();
42
+ const collect = (node) => {
43
+ const typeName = (0, utils_1.getTypeName)(node);
44
+ if (reachableTypes.has(typeName)) {
45
+ return;
46
+ }
47
+ reachableTypes.add(typeName);
48
+ const type = schema.getType(typeName) || schema.getDirective(typeName);
49
+ if ((0, graphql_1.isInterfaceType)(type)) {
50
+ const { objects, interfaces } = schema.getImplementations(type);
51
+ for (const { astNode } of [...objects, ...interfaces]) {
52
+ (0, graphql_1.visit)(astNode, visitor);
53
+ }
54
+ }
55
+ else if (type.astNode) {
56
+ // astNode can be undefined for ID, String, Boolean
57
+ (0, graphql_1.visit)(type.astNode, visitor);
58
+ }
59
+ };
60
+ const visitor = {
61
+ InterfaceTypeDefinition: collect,
62
+ ObjectTypeDefinition: collect,
63
+ InputValueDefinition: collect,
64
+ UnionTypeDefinition: collect,
65
+ FieldDefinition: collect,
66
+ Directive: collect,
67
+ NamedType: collect,
68
+ };
69
+ for (const type of [
70
+ schema,
71
+ schema.getQueryType(),
72
+ schema.getMutationType(),
73
+ schema.getSubscriptionType(),
74
+ ]) {
75
+ // if schema don't have Query type, schema.astNode will be undefined
76
+ if (type === null || type === void 0 ? void 0 : type.astNode) {
77
+ (0, graphql_1.visit)(type.astNode, visitor);
78
+ }
79
+ }
80
+ for (const node of schema.getDirectives()) {
81
+ if (node.locations.some(location => RequestDirectiveLocations.has(location))) {
82
+ reachableTypes.add(node.name);
83
+ }
84
+ }
85
+ reachableTypesCache = reachableTypes;
86
+ return reachableTypesCache;
87
+ }
88
+ exports.rule = {
89
+ meta: {
90
+ messages: {
91
+ [RULE_ID]: '{{ type }} `{{ typeName }}` is unreachable.',
92
+ },
93
+ docs: {
94
+ description: 'Requires all types to be reachable at some level by root level fields.',
95
+ category: 'Schema',
96
+ url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
97
+ requiresSchema: true,
98
+ examples: [
99
+ {
100
+ title: 'Incorrect',
101
+ code: /* GraphQL */ `
102
+ type User {
103
+ id: ID!
104
+ name: String
105
+ }
106
+
107
+ type Query {
108
+ me: String
109
+ }
110
+ `,
111
+ },
112
+ {
113
+ title: 'Correct',
114
+ code: /* GraphQL */ `
115
+ type User {
116
+ id: ID!
117
+ name: String
118
+ }
119
+
120
+ type Query {
121
+ me: User
122
+ }
123
+ `,
124
+ },
125
+ ],
126
+ recommended: true,
127
+ },
128
+ type: 'suggestion',
129
+ schema: [],
130
+ hasSuggestions: true,
131
+ },
132
+ create(context) {
133
+ const schema = (0, utils_1.requireGraphQLSchemaFromContext)(RULE_ID, context);
134
+ const reachableTypes = getReachableTypes(schema);
135
+ return {
136
+ [`:matches(${KINDS}) > .name`](node) {
137
+ const typeName = node.value;
138
+ if (!reachableTypes.has(typeName)) {
139
+ const type = (0, lodash_lowercase_1.default)(node.parent.kind.replace(/(Extension|Definition)$/, ''));
140
+ context.report({
141
+ node,
142
+ messageId: RULE_ID,
143
+ data: {
144
+ type: type[0].toUpperCase() + type.slice(1),
145
+ typeName,
146
+ },
147
+ suggest: [
148
+ {
149
+ desc: `Remove \`${typeName}\``,
150
+ fix: fixer => fixer.remove(node.parent),
151
+ },
152
+ ],
153
+ });
154
+ }
155
+ },
156
+ };
157
+ },
158
+ };
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const utils_1 = require("../utils");
6
+ const RULE_ID = 'no-unused-fields';
7
+ let usedFieldsCache;
8
+ function getUsedFields(schema, operations) {
9
+ // We don't want cache usedFields on test environment
10
+ // Otherwise usedFields will be same for all tests
11
+ if (process.env.NODE_ENV !== 'test' && usedFieldsCache) {
12
+ return usedFieldsCache;
13
+ }
14
+ const usedFields = Object.create(null);
15
+ const typeInfo = new graphql_1.TypeInfo(schema);
16
+ const visitor = (0, graphql_1.visitWithTypeInfo)(typeInfo, {
17
+ Field(node) {
18
+ var _a;
19
+ const fieldDef = typeInfo.getFieldDef();
20
+ if (!fieldDef) {
21
+ // skip visiting this node if field is not defined in schema
22
+ return false;
23
+ }
24
+ const parentTypeName = typeInfo.getParentType().name;
25
+ const fieldName = node.name.value;
26
+ (_a = usedFields[parentTypeName]) !== null && _a !== void 0 ? _a : (usedFields[parentTypeName] = new Set());
27
+ usedFields[parentTypeName].add(fieldName);
28
+ },
29
+ });
30
+ const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
31
+ for (const { document } of allDocuments) {
32
+ (0, graphql_1.visit)(document, visitor);
33
+ }
34
+ usedFieldsCache = usedFields;
35
+ return usedFieldsCache;
36
+ }
37
+ exports.rule = {
38
+ meta: {
39
+ messages: {
40
+ [RULE_ID]: 'Field "{{fieldName}}" is unused',
41
+ },
42
+ docs: {
43
+ description: 'Requires all fields to be used at some level by siblings operations.',
44
+ category: 'Schema',
45
+ url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
46
+ requiresSiblings: true,
47
+ requiresSchema: true,
48
+ isDisabledForAllConfig: true,
49
+ examples: [
50
+ {
51
+ title: 'Incorrect',
52
+ code: /* GraphQL */ `
53
+ type User {
54
+ id: ID!
55
+ name: String
56
+ someUnusedField: String
57
+ }
58
+
59
+ type Query {
60
+ me: User
61
+ }
62
+
63
+ query {
64
+ me {
65
+ id
66
+ name
67
+ }
68
+ }
69
+ `,
70
+ },
71
+ {
72
+ title: 'Correct',
73
+ code: /* GraphQL */ `
74
+ type User {
75
+ id: ID!
76
+ name: String
77
+ }
78
+
79
+ type Query {
80
+ me: User
81
+ }
82
+
83
+ query {
84
+ me {
85
+ id
86
+ name
87
+ }
88
+ }
89
+ `,
90
+ },
91
+ ],
92
+ },
93
+ type: 'suggestion',
94
+ schema: [],
95
+ hasSuggestions: true,
96
+ },
97
+ create(context) {
98
+ const schema = (0, utils_1.requireGraphQLSchemaFromContext)(RULE_ID, context);
99
+ const siblingsOperations = (0, utils_1.requireSiblingsOperations)(RULE_ID, context);
100
+ const usedFields = getUsedFields(schema, siblingsOperations);
101
+ return {
102
+ FieldDefinition(node) {
103
+ var _a;
104
+ const fieldName = node.name.value;
105
+ const parentTypeName = node.parent.name.value;
106
+ const isUsed = (_a = usedFields[parentTypeName]) === null || _a === void 0 ? void 0 : _a.has(fieldName);
107
+ if (isUsed) {
108
+ return;
109
+ }
110
+ context.report({
111
+ node: node.name,
112
+ messageId: RULE_ID,
113
+ data: { fieldName },
114
+ suggest: [
115
+ {
116
+ desc: `Remove \`${fieldName}\` field`,
117
+ fix(fixer) {
118
+ const sourceCode = context.getSourceCode();
119
+ const tokenBefore = sourceCode.getTokenBefore(node);
120
+ const tokenAfter = sourceCode.getTokenAfter(node);
121
+ const isEmptyType = tokenBefore.type === '{' && tokenAfter.type === '}';
122
+ return fixer.remove((isEmptyType ? node.parent : node));
123
+ },
124
+ },
125
+ ],
126
+ });
127
+ },
128
+ };
129
+ },
130
+ };