@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,75 @@
1
+ import { gqlPluckFromCodeStringSync, } from '@graphql-tools/graphql-tag-pluck';
2
+ import { asArray } from '@graphql-tools/utils';
3
+ import { loadOnDiskGraphQLConfig } from './graphql-config.js';
4
+ const blocksMap = new Map();
5
+ let onDiskConfig;
6
+ let onDiskConfigLoaded = false;
7
+ const RELEVANT_KEYWORDS = ['gql', 'graphql', 'GraphQL'];
8
+ export const processor = {
9
+ supportsAutofix: true,
10
+ preprocess(code, filePath) {
11
+ if (!onDiskConfigLoaded) {
12
+ onDiskConfig = loadOnDiskGraphQLConfig(filePath);
13
+ onDiskConfigLoaded = true;
14
+ }
15
+ let keywords = RELEVANT_KEYWORDS;
16
+ const pluckConfig = onDiskConfig === null || onDiskConfig === void 0 ? void 0 : onDiskConfig.getProjectForFile(filePath).extensions.pluckConfig;
17
+ if (pluckConfig) {
18
+ const { modules = [], globalGqlIdentifierName = ['gql', 'graphql'], gqlMagicComment = 'GraphQL', } = pluckConfig;
19
+ keywords = [
20
+ ...new Set([
21
+ ...modules.map(({ identifier }) => identifier),
22
+ ...asArray(globalGqlIdentifierName),
23
+ gqlMagicComment,
24
+ ].filter(Boolean)),
25
+ ];
26
+ }
27
+ if (keywords.every(keyword => !code.includes(keyword))) {
28
+ return [code];
29
+ }
30
+ try {
31
+ const sources = gqlPluckFromCodeStringSync(filePath, code, {
32
+ skipIndent: true,
33
+ ...pluckConfig,
34
+ });
35
+ const isSvelte = filePath.endsWith('.svelte');
36
+ const blocks = sources.map(item => ({
37
+ filename: 'document.graphql',
38
+ text: item.body,
39
+ lineOffset: item.locationOffset.line - (isSvelte ? 3 : 1),
40
+ // @ts-expect-error -- `index` field exist but show ts error
41
+ offset: item.locationOffset.index + (isSvelte ? -52 : 1),
42
+ }));
43
+ blocksMap.set(filePath, blocks);
44
+ return [...blocks, code /* source code must be provided and be last */];
45
+ }
46
+ catch (_a) {
47
+ // in case of parsing error return code as is
48
+ return [code];
49
+ }
50
+ },
51
+ postprocess(messages, filePath) {
52
+ const blocks = blocksMap.get(filePath) || [];
53
+ for (let i = 0; i < blocks.length; i += 1) {
54
+ const { lineOffset, offset } = blocks[i];
55
+ for (const message of messages[i]) {
56
+ message.line += lineOffset;
57
+ // endLine can not exist if only `loc: { start, column }` was provided to context.report
58
+ if (typeof message.endLine === 'number') {
59
+ message.endLine += lineOffset;
60
+ }
61
+ if (message.fix) {
62
+ message.fix.range[0] += offset;
63
+ message.fix.range[1] += offset;
64
+ }
65
+ for (const suggestion of message.suggestions || []) {
66
+ suggestion.fix.range[0] += offset;
67
+ suggestion.fix.range[1] += offset;
68
+ }
69
+ }
70
+ }
71
+ const result = messages.flat();
72
+ // sort eslint/graphql-eslint messages by line/column
73
+ return result.sort((a, b) => a.line - b.line || a.column - b.column);
74
+ },
75
+ };
@@ -0,0 +1,344 @@
1
+ import { Kind, } from 'graphql';
2
+ import lowerCase from 'lodash.lowercase';
3
+ import { ARRAY_DEFAULT_OPTIONS } from '../utils.js';
4
+ const RULE_ID = 'alphabetize';
5
+ const fieldsEnum = [
6
+ Kind.OBJECT_TYPE_DEFINITION,
7
+ Kind.INTERFACE_TYPE_DEFINITION,
8
+ Kind.INPUT_OBJECT_TYPE_DEFINITION,
9
+ ];
10
+ const valuesEnum = [Kind.ENUM_TYPE_DEFINITION];
11
+ const selectionsEnum = [
12
+ Kind.OPERATION_DEFINITION,
13
+ Kind.FRAGMENT_DEFINITION,
14
+ ];
15
+ const variablesEnum = [Kind.OPERATION_DEFINITION];
16
+ const argumentsEnum = [
17
+ Kind.FIELD_DEFINITION,
18
+ Kind.FIELD,
19
+ Kind.DIRECTIVE_DEFINITION,
20
+ Kind.DIRECTIVE,
21
+ ];
22
+ const schema = {
23
+ type: 'array',
24
+ minItems: 1,
25
+ maxItems: 1,
26
+ items: {
27
+ type: 'object',
28
+ additionalProperties: false,
29
+ minProperties: 1,
30
+ properties: {
31
+ fields: {
32
+ ...ARRAY_DEFAULT_OPTIONS,
33
+ items: {
34
+ enum: fieldsEnum,
35
+ },
36
+ description: 'Fields of `type`, `interface`, and `input`.',
37
+ },
38
+ values: {
39
+ ...ARRAY_DEFAULT_OPTIONS,
40
+ items: {
41
+ enum: valuesEnum,
42
+ },
43
+ description: 'Values of `enum`.',
44
+ },
45
+ selections: {
46
+ ...ARRAY_DEFAULT_OPTIONS,
47
+ items: {
48
+ enum: selectionsEnum,
49
+ },
50
+ description: 'Selections of `fragment` and operations `query`, `mutation` and `subscription`.',
51
+ },
52
+ variables: {
53
+ ...ARRAY_DEFAULT_OPTIONS,
54
+ items: {
55
+ enum: variablesEnum,
56
+ },
57
+ description: 'Variables of operations `query`, `mutation` and `subscription`.',
58
+ },
59
+ arguments: {
60
+ ...ARRAY_DEFAULT_OPTIONS,
61
+ items: {
62
+ enum: argumentsEnum,
63
+ },
64
+ description: 'Arguments of fields and directives.',
65
+ },
66
+ definitions: {
67
+ type: 'boolean',
68
+ description: 'Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `directive`.',
69
+ default: false,
70
+ },
71
+ groups: {
72
+ ...ARRAY_DEFAULT_OPTIONS,
73
+ minItems: 2,
74
+ description: "Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt']` where `*` says for everything else.",
75
+ },
76
+ },
77
+ },
78
+ };
79
+ export const rule = {
80
+ meta: {
81
+ type: 'suggestion',
82
+ fixable: 'code',
83
+ docs: {
84
+ category: ['Schema', 'Operations'],
85
+ description: 'Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.',
86
+ url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
87
+ examples: [
88
+ {
89
+ title: 'Incorrect',
90
+ usage: [{ fields: [Kind.OBJECT_TYPE_DEFINITION] }],
91
+ code: /* GraphQL */ `
92
+ type User {
93
+ password: String
94
+ firstName: String! # should be before "password"
95
+ age: Int # should be before "firstName"
96
+ lastName: String!
97
+ }
98
+ `,
99
+ },
100
+ {
101
+ title: 'Correct',
102
+ usage: [{ fields: [Kind.OBJECT_TYPE_DEFINITION] }],
103
+ code: /* GraphQL */ `
104
+ type User {
105
+ age: Int
106
+ firstName: String!
107
+ lastName: String!
108
+ password: String
109
+ }
110
+ `,
111
+ },
112
+ {
113
+ title: 'Incorrect',
114
+ usage: [{ values: [Kind.ENUM_TYPE_DEFINITION] }],
115
+ code: /* GraphQL */ `
116
+ enum Role {
117
+ SUPER_ADMIN
118
+ ADMIN # should be before "SUPER_ADMIN"
119
+ USER
120
+ GOD # should be before "USER"
121
+ }
122
+ `,
123
+ },
124
+ {
125
+ title: 'Correct',
126
+ usage: [{ values: [Kind.ENUM_TYPE_DEFINITION] }],
127
+ code: /* GraphQL */ `
128
+ enum Role {
129
+ ADMIN
130
+ GOD
131
+ SUPER_ADMIN
132
+ USER
133
+ }
134
+ `,
135
+ },
136
+ {
137
+ title: 'Incorrect',
138
+ usage: [{ selections: [Kind.OPERATION_DEFINITION] }],
139
+ code: /* GraphQL */ `
140
+ query {
141
+ me {
142
+ firstName
143
+ lastName
144
+ email # should be before "lastName"
145
+ }
146
+ }
147
+ `,
148
+ },
149
+ {
150
+ title: 'Correct',
151
+ usage: [{ selections: [Kind.OPERATION_DEFINITION] }],
152
+ code: /* GraphQL */ `
153
+ query {
154
+ me {
155
+ email
156
+ firstName
157
+ lastName
158
+ }
159
+ }
160
+ `,
161
+ },
162
+ ],
163
+ configOptions: {
164
+ schema: [
165
+ {
166
+ fields: fieldsEnum,
167
+ values: valuesEnum,
168
+ arguments: argumentsEnum,
169
+ // TODO: add in graphql-eslint v4
170
+ // definitions: true,
171
+ // groups: ['id', '*', 'createdAt', 'updatedAt']
172
+ },
173
+ ],
174
+ operations: [
175
+ {
176
+ selections: selectionsEnum,
177
+ variables: variablesEnum,
178
+ arguments: [Kind.FIELD, Kind.DIRECTIVE],
179
+ },
180
+ ],
181
+ },
182
+ },
183
+ messages: {
184
+ [RULE_ID]: '`{{ currName }}` should be before {{ prevName }}.',
185
+ },
186
+ schema,
187
+ },
188
+ create(context) {
189
+ var _a, _b, _c, _d, _e;
190
+ const sourceCode = context.getSourceCode();
191
+ function isNodeAndCommentOnSameLine(node, comment) {
192
+ return node.loc.end.line === comment.loc.start.line;
193
+ }
194
+ function getBeforeComments(node) {
195
+ const commentsBefore = sourceCode.getCommentsBefore(node);
196
+ if (commentsBefore.length === 0) {
197
+ return [];
198
+ }
199
+ const tokenBefore = sourceCode.getTokenBefore(node);
200
+ if (tokenBefore) {
201
+ return commentsBefore.filter(comment => !isNodeAndCommentOnSameLine(tokenBefore, comment));
202
+ }
203
+ const filteredComments = [];
204
+ const nodeLine = node.loc.start.line;
205
+ // Break on comment that not attached to node
206
+ for (let i = commentsBefore.length - 1; i >= 0; i -= 1) {
207
+ const comment = commentsBefore[i];
208
+ if (nodeLine - comment.loc.start.line - filteredComments.length > 1) {
209
+ break;
210
+ }
211
+ filteredComments.unshift(comment);
212
+ }
213
+ return filteredComments;
214
+ }
215
+ function getRangeWithComments(node) {
216
+ if (node.kind === Kind.VARIABLE) {
217
+ node = node.parent;
218
+ }
219
+ const [firstBeforeComment] = getBeforeComments(node);
220
+ const [firstAfterComment] = sourceCode.getCommentsAfter(node);
221
+ const from = firstBeforeComment || node;
222
+ const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment)
223
+ ? firstAfterComment
224
+ : node;
225
+ return [from.range[0], to.range[1]];
226
+ }
227
+ function checkNodes(nodes) {
228
+ var _a, _b, _c, _d;
229
+ // Starts from 1, ignore nodes.length <= 1
230
+ for (let i = 1; i < nodes.length; i += 1) {
231
+ const currNode = nodes[i];
232
+ const currName = ('alias' in currNode && ((_a = currNode.alias) === null || _a === void 0 ? void 0 : _a.value)) ||
233
+ ('name' in currNode && ((_b = currNode.name) === null || _b === void 0 ? void 0 : _b.value));
234
+ if (!currName) {
235
+ // we don't move unnamed current nodes
236
+ continue;
237
+ }
238
+ const prevNode = nodes[i - 1];
239
+ const prevName = ('alias' in prevNode && ((_c = prevNode.alias) === null || _c === void 0 ? void 0 : _c.value)) ||
240
+ ('name' in prevNode && ((_d = prevNode.name) === null || _d === void 0 ? void 0 : _d.value));
241
+ if (prevName) {
242
+ // Compare with lexicographic order
243
+ const compareResult = prevName.localeCompare(currName);
244
+ const { groups } = opts;
245
+ let shouldSortByGroup = false;
246
+ if (groups === null || groups === void 0 ? void 0 : groups.length) {
247
+ if (!groups.includes('*')) {
248
+ throw new Error('`groups` option should contain `*` string.');
249
+ }
250
+ let indexForPrev = groups.indexOf(prevName);
251
+ if (indexForPrev === -1)
252
+ indexForPrev = groups.indexOf('*');
253
+ let indexForCurr = groups.indexOf(currName);
254
+ if (indexForCurr === -1)
255
+ indexForCurr = groups.indexOf('*');
256
+ shouldSortByGroup = indexForPrev - indexForCurr > 0;
257
+ if (indexForPrev < indexForCurr) {
258
+ continue;
259
+ }
260
+ }
261
+ const shouldSort = compareResult === 1;
262
+ if (!shouldSortByGroup && !shouldSort) {
263
+ const isSameName = compareResult === 0;
264
+ if (!isSameName ||
265
+ !prevNode.kind.endsWith('Extension') ||
266
+ currNode.kind.endsWith('Extension')) {
267
+ continue;
268
+ }
269
+ }
270
+ }
271
+ context.report({
272
+ node: ('alias' in currNode && currNode.alias) || currNode.name,
273
+ messageId: RULE_ID,
274
+ data: {
275
+ currName,
276
+ prevName: prevName ? `\`${prevName}\`` : lowerCase(prevNode.kind),
277
+ },
278
+ *fix(fixer) {
279
+ const prevRange = getRangeWithComments(prevNode);
280
+ const currRange = getRangeWithComments(currNode);
281
+ yield fixer.replaceTextRange(prevRange, sourceCode.getText({ range: currRange }));
282
+ yield fixer.replaceTextRange(currRange, sourceCode.getText({ range: prevRange }));
283
+ },
284
+ });
285
+ }
286
+ }
287
+ const opts = context.options[0];
288
+ const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
289
+ const listeners = {};
290
+ const kinds = [
291
+ fields.has(Kind.OBJECT_TYPE_DEFINITION) && [
292
+ Kind.OBJECT_TYPE_DEFINITION,
293
+ Kind.OBJECT_TYPE_EXTENSION,
294
+ ],
295
+ fields.has(Kind.INTERFACE_TYPE_DEFINITION) && [
296
+ Kind.INTERFACE_TYPE_DEFINITION,
297
+ Kind.INTERFACE_TYPE_EXTENSION,
298
+ ],
299
+ fields.has(Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
300
+ Kind.INPUT_OBJECT_TYPE_DEFINITION,
301
+ Kind.INPUT_OBJECT_TYPE_EXTENSION,
302
+ ],
303
+ ]
304
+ .filter(Boolean)
305
+ .flat();
306
+ const fieldsSelector = kinds.join(',');
307
+ const hasEnumValues = ((_b = opts.values) === null || _b === void 0 ? void 0 : _b[0]) === Kind.ENUM_TYPE_DEFINITION;
308
+ const selectionsSelector = (_c = opts.selections) === null || _c === void 0 ? void 0 : _c.join(',');
309
+ const hasVariables = ((_d = opts.variables) === null || _d === void 0 ? void 0 : _d[0]) === Kind.OPERATION_DEFINITION;
310
+ const argumentsSelector = (_e = opts.arguments) === null || _e === void 0 ? void 0 : _e.join(',');
311
+ if (fieldsSelector) {
312
+ listeners[fieldsSelector] = (node) => {
313
+ checkNodes(node.fields);
314
+ };
315
+ }
316
+ if (hasEnumValues) {
317
+ const enumValuesSelector = [Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION].join(',');
318
+ listeners[enumValuesSelector] = (node) => {
319
+ checkNodes(node.values);
320
+ };
321
+ }
322
+ if (selectionsSelector) {
323
+ listeners[`:matches(${selectionsSelector}) SelectionSet`] = (node) => {
324
+ checkNodes(node.selections);
325
+ };
326
+ }
327
+ if (hasVariables) {
328
+ listeners.OperationDefinition = (node) => {
329
+ checkNodes(node.variableDefinitions.map(varDef => varDef.variable));
330
+ };
331
+ }
332
+ if (argumentsSelector) {
333
+ listeners[argumentsSelector] = (node) => {
334
+ checkNodes(node.arguments);
335
+ };
336
+ }
337
+ if (opts.definitions) {
338
+ listeners.Document = node => {
339
+ checkNodes(node.definitions);
340
+ };
341
+ }
342
+ return listeners;
343
+ },
344
+ };
@@ -0,0 +1,75 @@
1
+ const schema = {
2
+ type: 'array',
3
+ maxItems: 1,
4
+ items: {
5
+ type: 'object',
6
+ additionalProperties: false,
7
+ minProperties: 1,
8
+ properties: {
9
+ style: {
10
+ enum: ['block', 'inline'],
11
+ default: 'block',
12
+ },
13
+ },
14
+ },
15
+ };
16
+ export const rule = {
17
+ meta: {
18
+ type: 'suggestion',
19
+ hasSuggestions: true,
20
+ docs: {
21
+ examples: [
22
+ {
23
+ title: 'Incorrect',
24
+ usage: [{ style: 'inline' }],
25
+ code: /* GraphQL */ `
26
+ """ Description """
27
+ type someTypeName {
28
+ # ...
29
+ }
30
+ `,
31
+ },
32
+ {
33
+ title: 'Correct',
34
+ usage: [{ style: 'inline' }],
35
+ code: /* GraphQL */ `
36
+ " Description "
37
+ type someTypeName {
38
+ # ...
39
+ }
40
+ `,
41
+ },
42
+ ],
43
+ description: 'Require all comments to follow the same style (either block or inline).',
44
+ category: 'Schema',
45
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/description-style.md',
46
+ recommended: true,
47
+ },
48
+ schema,
49
+ },
50
+ create(context) {
51
+ const { style = 'block' } = context.options[0] || {};
52
+ const isBlock = style === 'block';
53
+ return {
54
+ [`.description[type=StringValue][block!=${isBlock}]`](node) {
55
+ context.report({
56
+ loc: isBlock ? node.loc : node.loc.start,
57
+ message: `Unexpected ${isBlock ? 'inline' : 'block'} description.`,
58
+ suggest: [
59
+ {
60
+ desc: `Change to ${isBlock ? 'block' : 'inline'} style description`,
61
+ fix(fixer) {
62
+ const sourceCode = context.getSourceCode();
63
+ const originalText = sourceCode.getText(node);
64
+ const newText = isBlock
65
+ ? originalText.replace(/(^")|("$)/g, '"""')
66
+ : originalText.replace(/(^""")|("""$)/g, '"').replace(/\s+/g, ' ');
67
+ return fixer.replaceText(node, newText);
68
+ },
69
+ },
70
+ ],
71
+ });
72
+ },
73
+ };
74
+ },
75
+ };