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

Sign up to get free protection for your applications and to get access to all the features.
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,133 @@
1
+ import { Kind, } from 'graphql';
2
+ const schema = {
3
+ type: 'array',
4
+ maxItems: 1,
5
+ items: {
6
+ type: 'object',
7
+ additionalProperties: false,
8
+ properties: {
9
+ checkInputType: {
10
+ type: 'boolean',
11
+ default: false,
12
+ description: 'Check that the input type name follows the convention <mutationName>Input',
13
+ },
14
+ caseSensitiveInputType: {
15
+ type: 'boolean',
16
+ default: true,
17
+ description: 'Allow for case discrepancies in the input type name',
18
+ },
19
+ checkQueries: {
20
+ type: 'boolean',
21
+ default: false,
22
+ description: 'Apply the rule to Queries',
23
+ },
24
+ checkMutations: {
25
+ type: 'boolean',
26
+ default: true,
27
+ description: 'Apply the rule to Mutations',
28
+ },
29
+ },
30
+ },
31
+ };
32
+ const isObjectType = (node) => [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
33
+ const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
34
+ const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
35
+ export const rule = {
36
+ meta: {
37
+ type: 'suggestion',
38
+ hasSuggestions: true,
39
+ docs: {
40
+ description: 'Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".\nUsing the same name for all input parameters will make your schemas easier to consume and more predictable. Using the same name as mutation for InputType will make it easier to find mutations that InputType belongs to.',
41
+ category: 'Schema',
42
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/input-name.md',
43
+ examples: [
44
+ {
45
+ title: 'Incorrect',
46
+ usage: [{ checkInputType: true }],
47
+ code: /* GraphQL */ `
48
+ type Mutation {
49
+ SetMessage(message: InputMessage): String
50
+ }
51
+ `,
52
+ },
53
+ {
54
+ title: 'Correct (with checkInputType)',
55
+ usage: [{ checkInputType: true }],
56
+ code: /* GraphQL */ `
57
+ type Mutation {
58
+ SetMessage(input: SetMessageInput): String
59
+ }
60
+ `,
61
+ },
62
+ {
63
+ title: 'Correct (without checkInputType)',
64
+ usage: [{ checkInputType: false }],
65
+ code: /* GraphQL */ `
66
+ type Mutation {
67
+ SetMessage(input: AnyInputTypeName): String
68
+ }
69
+ `,
70
+ },
71
+ ],
72
+ },
73
+ schema,
74
+ },
75
+ create(context) {
76
+ const options = {
77
+ checkInputType: false,
78
+ caseSensitiveInputType: true,
79
+ checkQueries: false,
80
+ checkMutations: true,
81
+ ...context.options[0],
82
+ };
83
+ const shouldCheckType = node => (options.checkMutations && isMutationType(node)) ||
84
+ (options.checkQueries && isQueryType(node));
85
+ const listeners = {
86
+ 'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
87
+ if (shouldCheckType(node.parent.parent.parent)) {
88
+ const inputName = node.value;
89
+ context.report({
90
+ node,
91
+ message: `Input \`${inputName}\` should be called \`input\`.`,
92
+ suggest: [
93
+ {
94
+ desc: 'Rename to `input`',
95
+ fix: fixer => fixer.replaceText(node, 'input'),
96
+ },
97
+ ],
98
+ });
99
+ }
100
+ },
101
+ };
102
+ if (options.checkInputType) {
103
+ listeners['FieldDefinition > InputValueDefinition NamedType'] = (node) => {
104
+ const findInputType = item => {
105
+ let currentNode = item;
106
+ while (currentNode.type !== Kind.INPUT_VALUE_DEFINITION) {
107
+ currentNode = currentNode.parent;
108
+ }
109
+ return currentNode;
110
+ };
111
+ const inputValueNode = findInputType(node);
112
+ if (shouldCheckType(inputValueNode.parent.parent)) {
113
+ const mutationName = `${inputValueNode.parent.name.value}Input`;
114
+ const name = node.name.value;
115
+ if ((options.caseSensitiveInputType && node.name.value !== mutationName) ||
116
+ name.toLowerCase() !== mutationName.toLowerCase()) {
117
+ context.report({
118
+ node: node.name,
119
+ message: `Input type \`${name}\` name should be \`${mutationName}\`.`,
120
+ suggest: [
121
+ {
122
+ desc: `Rename to \`${mutationName}\``,
123
+ fix: fixer => fixer.replaceText(node, mutationName),
124
+ },
125
+ ],
126
+ });
127
+ }
128
+ }
129
+ };
130
+ }
131
+ return listeners;
132
+ },
133
+ };
@@ -0,0 +1,85 @@
1
+ import { ARRAY_DEFAULT_OPTIONS, pascalCase, getLocation } from '../utils.js';
2
+ const RULE_ID = 'lone-executable-definition';
3
+ const definitionTypes = ['fragment', 'query', 'mutation', 'subscription'];
4
+ const schema = {
5
+ type: 'array',
6
+ maxItems: 1,
7
+ items: {
8
+ type: 'object',
9
+ minProperties: 1,
10
+ additionalProperties: false,
11
+ properties: {
12
+ ignore: {
13
+ ...ARRAY_DEFAULT_OPTIONS,
14
+ maxItems: 3,
15
+ items: {
16
+ enum: definitionTypes,
17
+ },
18
+ description: 'Allow certain definitions to be placed alongside others.',
19
+ },
20
+ },
21
+ },
22
+ };
23
+ export const rule = {
24
+ meta: {
25
+ type: 'suggestion',
26
+ docs: {
27
+ category: 'Operations',
28
+ description: 'Require all queries, mutations, subscriptions and fragments to be located in separate files.',
29
+ url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
30
+ examples: [
31
+ {
32
+ title: 'Incorrect',
33
+ code: /* GraphQL */ `
34
+ query Foo {
35
+ id
36
+ }
37
+ fragment Bar on Baz {
38
+ id
39
+ }
40
+ `,
41
+ },
42
+ {
43
+ title: 'Correct',
44
+ code: /* GraphQL */ `
45
+ query Foo {
46
+ id
47
+ }
48
+ `,
49
+ },
50
+ ],
51
+ },
52
+ messages: {
53
+ [RULE_ID]: '{{name}} should be in a separate file.',
54
+ },
55
+ schema,
56
+ },
57
+ create(context) {
58
+ var _a;
59
+ const ignore = new Set(((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.ignore) || []);
60
+ const definitions = [];
61
+ return {
62
+ ':matches(OperationDefinition, FragmentDefinition)'(node) {
63
+ const type = 'operation' in node ? node.operation : 'fragment';
64
+ if (!ignore.has(type)) {
65
+ definitions.push({ type, node });
66
+ }
67
+ },
68
+ 'Program:exit'() {
69
+ var _a, _b;
70
+ for (const { node, type } of definitions.slice(1) /* ignore first definition */) {
71
+ let name = pascalCase(type);
72
+ const definitionName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value;
73
+ if (definitionName) {
74
+ name += ` "${definitionName}"`;
75
+ }
76
+ context.report({
77
+ loc: ((_b = node.name) === null || _b === void 0 ? void 0 : _b.loc) || getLocation(node.loc.start, type),
78
+ messageId: RULE_ID,
79
+ data: { name },
80
+ });
81
+ }
82
+ },
83
+ };
84
+ },
85
+ };
@@ -0,0 +1,232 @@
1
+ import { basename, extname } from 'path';
2
+ import { existsSync } from 'fs';
3
+ import { Kind } from 'graphql';
4
+ import { convertCase, REPORT_ON_FIRST_CHARACTER } from '../utils.js';
5
+ const MATCH_EXTENSION = 'MATCH_EXTENSION';
6
+ const MATCH_STYLE = 'MATCH_STYLE';
7
+ const CASE_STYLES = [
8
+ 'camelCase',
9
+ 'PascalCase',
10
+ 'snake_case',
11
+ 'UPPER_CASE',
12
+ 'kebab-case',
13
+ 'matchDocumentStyle',
14
+ ];
15
+ const schemaOption = {
16
+ oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
17
+ };
18
+ const schema = {
19
+ definitions: {
20
+ asString: {
21
+ enum: CASE_STYLES,
22
+ description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
23
+ },
24
+ asObject: {
25
+ type: 'object',
26
+ additionalProperties: false,
27
+ minProperties: 1,
28
+ properties: {
29
+ style: { enum: CASE_STYLES },
30
+ suffix: { type: 'string' },
31
+ prefix: { type: 'string' },
32
+ },
33
+ },
34
+ },
35
+ type: 'array',
36
+ minItems: 1,
37
+ maxItems: 1,
38
+ items: {
39
+ type: 'object',
40
+ additionalProperties: false,
41
+ minProperties: 1,
42
+ properties: {
43
+ fileExtension: { enum: ['.gql', '.graphql'] },
44
+ query: schemaOption,
45
+ mutation: schemaOption,
46
+ subscription: schemaOption,
47
+ fragment: schemaOption,
48
+ },
49
+ },
50
+ };
51
+ export const rule = {
52
+ meta: {
53
+ type: 'suggestion',
54
+ docs: {
55
+ category: 'Operations',
56
+ description: 'This rule allows you to enforce that the file name should match the operation name.',
57
+ url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/match-document-filename.md',
58
+ examples: [
59
+ {
60
+ title: 'Correct',
61
+ usage: [{ fileExtension: '.gql' }],
62
+ code: /* GraphQL */ `
63
+ # user.gql
64
+ type User {
65
+ id: ID!
66
+ }
67
+ `,
68
+ },
69
+ {
70
+ title: 'Correct',
71
+ usage: [{ query: 'snake_case' }],
72
+ code: /* GraphQL */ `
73
+ # user_by_id.gql
74
+ query UserById {
75
+ userById(id: 5) {
76
+ id
77
+ name
78
+ fullName
79
+ }
80
+ }
81
+ `,
82
+ },
83
+ {
84
+ title: 'Correct',
85
+ usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
86
+ code: /* GraphQL */ `
87
+ # user-fields.fragment.gql
88
+ fragment user_fields on User {
89
+ id
90
+ email
91
+ }
92
+ `,
93
+ },
94
+ {
95
+ title: 'Correct',
96
+ usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
97
+ code: /* GraphQL */ `
98
+ # DeleteUserMutation.gql
99
+ mutation DELETE_USER {
100
+ deleteUser(id: 5)
101
+ }
102
+ `,
103
+ },
104
+ {
105
+ title: 'Incorrect',
106
+ usage: [{ fileExtension: '.graphql' }],
107
+ code: /* GraphQL */ `
108
+ # post.gql
109
+ type Post {
110
+ id: ID!
111
+ }
112
+ `,
113
+ },
114
+ {
115
+ title: 'Incorrect',
116
+ usage: [{ query: 'PascalCase' }],
117
+ code: /* GraphQL */ `
118
+ # user-by-id.gql
119
+ query UserById {
120
+ userById(id: 5) {
121
+ id
122
+ name
123
+ fullName
124
+ }
125
+ }
126
+ `,
127
+ },
128
+ {
129
+ title: 'Correct',
130
+ usage: [{ fragment: { style: 'kebab-case', prefix: 'mutation.' } }],
131
+ code: /* GraphQL */ `
132
+ # mutation.add-alert.graphql
133
+ mutation addAlert {
134
+ foo
135
+ }
136
+ `,
137
+ },
138
+ {
139
+ title: 'Correct',
140
+ usage: [{ fragment: { prefix: 'query.' } }],
141
+ code: /* GraphQL */ `
142
+ # query.me.graphql
143
+ query me {
144
+ foo
145
+ }
146
+ `,
147
+ },
148
+ ],
149
+ configOptions: [
150
+ {
151
+ query: 'kebab-case',
152
+ mutation: 'kebab-case',
153
+ subscription: 'kebab-case',
154
+ fragment: 'kebab-case',
155
+ },
156
+ ],
157
+ },
158
+ messages: {
159
+ [MATCH_EXTENSION]: 'File extension "{{ fileExtension }}" don\'t match extension "{{ expectedFileExtension }}"',
160
+ [MATCH_STYLE]: 'Unexpected filename "{{ filename }}". Rename it to "{{ expectedFilename }}"',
161
+ },
162
+ schema,
163
+ },
164
+ create(context) {
165
+ const options = context.options[0] || {
166
+ fileExtension: null,
167
+ };
168
+ const filePath = context.getFilename();
169
+ const isVirtualFile = !existsSync(filePath);
170
+ if (process.env.NODE_ENV !== 'test' && isVirtualFile) {
171
+ // Skip validation for code files
172
+ return {};
173
+ }
174
+ const fileExtension = extname(filePath);
175
+ const filename = basename(filePath, fileExtension);
176
+ return {
177
+ Document(documentNode) {
178
+ var _a;
179
+ if (options.fileExtension && options.fileExtension !== fileExtension) {
180
+ context.report({
181
+ loc: REPORT_ON_FIRST_CHARACTER,
182
+ messageId: MATCH_EXTENSION,
183
+ data: {
184
+ fileExtension,
185
+ expectedFileExtension: options.fileExtension,
186
+ },
187
+ });
188
+ }
189
+ const firstOperation = documentNode.definitions.find(n => n.kind === Kind.OPERATION_DEFINITION);
190
+ const firstFragment = documentNode.definitions.find(n => n.kind === Kind.FRAGMENT_DEFINITION);
191
+ const node = firstOperation || firstFragment;
192
+ if (!node) {
193
+ return;
194
+ }
195
+ const docName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value;
196
+ if (!docName) {
197
+ return;
198
+ }
199
+ const docType = 'operation' in node ? node.operation : 'fragment';
200
+ let option = options[docType];
201
+ if (!option) {
202
+ // Config not provided
203
+ return;
204
+ }
205
+ if (typeof option === 'string') {
206
+ option = { style: option };
207
+ }
208
+ const expectedExtension = options.fileExtension || fileExtension;
209
+ let expectedFilename = option.prefix || '';
210
+ if (option.style) {
211
+ expectedFilename +=
212
+ option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
213
+ }
214
+ else {
215
+ expectedFilename += filename;
216
+ }
217
+ expectedFilename += (option.suffix || '') + expectedExtension;
218
+ const filenameWithExtension = filename + expectedExtension;
219
+ if (expectedFilename !== filenameWithExtension) {
220
+ context.report({
221
+ loc: REPORT_ON_FIRST_CHARACTER,
222
+ messageId: MATCH_STYLE,
223
+ data: {
224
+ expectedFilename,
225
+ filename: filenameWithExtension,
226
+ },
227
+ });
228
+ }
229
+ },
230
+ };
231
+ },
232
+ };