@graphql-eslint/eslint-plugin 3.16.2-alpha-20230322145450-ffe6eec → 3.17.0-alpha-20230323123320-43244a5

Sign up to get free protection for your applications and to get access to all the features.
@@ -185,7 +185,7 @@ exports.rule = {
185
185
  },
186
186
  },
187
187
  messages: {
188
- [RULE_ID]: '`{{ currName }}` should be before {{ prevName }}.',
188
+ [RULE_ID]: '{{ currNode }} should be before {{ prevNode }}',
189
189
  },
190
190
  schema,
191
191
  },
@@ -277,8 +277,8 @@ exports.rule = {
277
277
  node: ('alias' in currNode && currNode.alias) || currNode.name,
278
278
  messageId: RULE_ID,
279
279
  data: {
280
- currName,
281
- prevName: prevName ? `\`${prevName}\`` : (0, lodash_lowercase_1.default)(prevNode.kind),
280
+ currNode: (0, utils_js_1.displayNodeName)(currNode),
281
+ prevNode: prevName ? (0, utils_js_1.displayNodeName)(prevNode) : (0, lodash_lowercase_1.default)(prevNode.kind),
282
282
  },
283
283
  *fix(fixer) {
284
284
  const prevRange = getRangeWithComments(prevNode);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rule = void 0;
4
+ const utils_js_1 = require("../utils.js");
4
5
  const schema = {
5
6
  type: 'array',
6
7
  maxItems: 1,
@@ -57,7 +58,7 @@ exports.rule = {
57
58
  [`.description[type=StringValue][block!=${isBlock}]`](node) {
58
59
  context.report({
59
60
  loc: isBlock ? node.loc : node.loc.start,
60
- message: `Unexpected ${isBlock ? 'inline' : 'block'} description.`,
61
+ message: `Unexpected ${isBlock ? 'inline' : 'block'} description for ${(0, utils_js_1.getNodeName)(node.parent)}`,
61
62
  suggest: [
62
63
  {
63
64
  desc: `Change to ${isBlock ? 'block' : 'inline'} style description`,
@@ -89,11 +89,12 @@ exports.rule = {
89
89
  false;
90
90
  const listeners = {
91
91
  'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
92
- if (shouldCheckType(node.parent.parent.parent)) {
92
+ const fieldDef = node.parent.parent;
93
+ if (shouldCheckType(fieldDef.parent)) {
93
94
  const inputName = node.value;
94
95
  context.report({
95
96
  node,
96
- message: `Input \`${inputName}\` should be called \`input\`.`,
97
+ message: `Input "${inputName}" should be named "input" for "${fieldDef.parent.name.value}.${fieldDef.name.value}"`,
97
98
  suggest: [
98
99
  {
99
100
  desc: 'Rename to `input`',
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rule = void 0;
4
4
  const graphql_1 = require("graphql");
5
+ const utils_js_1 = require("../utils.js");
5
6
  exports.rule = {
6
7
  meta: {
7
8
  type: 'suggestion',
@@ -47,7 +48,7 @@ exports.rule = {
47
48
  const enumName = duplicate.name.value;
48
49
  context.report({
49
50
  node: duplicate.name,
50
- message: `Case-insensitive enum values duplicates are not allowed! Found: \`${enumName}\`.`,
51
+ message: `Unexpected case-insensitive enum values duplicates for ${(0, utils_js_1.getNodeName)(duplicate)}`,
51
52
  suggest: [
52
53
  {
53
54
  desc: `Remove \`${enumName}\` enum value`,
@@ -1,15 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rule = void 0;
3
+ exports.rule = exports.RULE_ID = void 0;
4
4
  const graphql_1 = require("graphql");
5
- const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
5
+ const utils_js_1 = require("../utils.js");
6
+ exports.RULE_ID = 'HASHTAG_COMMENT';
6
7
  exports.rule = {
7
8
  meta: {
8
9
  type: 'suggestion',
9
10
  hasSuggestions: true,
10
11
  schema: [],
11
12
  messages: {
12
- [HASHTAG_COMMENT]: 'Using hashtag `#` for adding GraphQL descriptions is not allowed. Prefer using `"""` for multiline, or `"` for a single line description.',
13
+ [exports.RULE_ID]: 'Unexpected GraphQL descriptions as hashtag `#` for {{ nodeName }}.\nPrefer using `"""` for multiline, or `"` for a single line description.',
13
14
  },
14
15
  docs: {
15
16
  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.',
@@ -69,8 +70,15 @@ exports.rule = {
69
70
  line !== prev.line &&
70
71
  next.kind === graphql_1.TokenKind.NAME &&
71
72
  linesAfter < 2) {
73
+ const sourceCode = context.getSourceCode();
74
+ const { tokens } = sourceCode.ast;
75
+ const t = tokens.find(token => token.loc.start.line === next.line && token.loc.start.column === next.column - 1);
76
+ const nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
72
77
  context.report({
73
- messageId: HASHTAG_COMMENT,
78
+ messageId: exports.RULE_ID,
79
+ data: {
80
+ nodeName: (0, utils_js_1.getNodeName)('name' in nextNode ? nextNode : nextNode.parent),
81
+ },
74
82
  loc: {
75
83
  line,
76
84
  column: column - 1,
@@ -49,9 +49,13 @@ exports.rule = {
49
49
  const typeName = node.value;
50
50
  const graphQLType = schema.getType(typeName);
51
51
  if ((0, graphql_1.isScalarType)(graphQLType)) {
52
+ let fieldDef = node.parent;
53
+ while (fieldDef.kind !== graphql_1.Kind.FIELD_DEFINITION) {
54
+ fieldDef = fieldDef.parent;
55
+ }
52
56
  context.report({
53
57
  node,
54
- message: `Unexpected scalar result type \`${typeName}\`.`,
58
+ message: `Unexpected scalar result type \`${typeName}\` for ${(0, utils_js_1.getNodeName)(fieldDef)}`,
55
59
  suggest: [
56
60
  {
57
61
  desc: `Remove \`${typeName}\``,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rule = void 0;
4
4
  const index_js_1 = require("../estree-converter/index.js");
5
+ const utils_js_1 = require("../utils.js");
5
6
  // eslint-disable-next-line unicorn/better-regex
6
7
  const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
7
8
  const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
@@ -61,10 +62,10 @@ exports.rule = {
61
62
  ],
62
63
  },
63
64
  messages: {
64
- [MESSAGE_REQUIRE_DATE]: 'Directive "@deprecated" must have a deletion date',
65
- [MESSAGE_INVALID_FORMAT]: 'Deletion date must be in format "DD/MM/YYYY"',
66
- [MESSAGE_INVALID_DATE]: 'Invalid "{{ deletionDate }}" deletion date',
67
- [MESSAGE_CAN_BE_REMOVED]: '"{{ nodeName }}" сan be removed',
65
+ [MESSAGE_REQUIRE_DATE]: 'Directive "@deprecated" must have a deletion date for {{ nodeName }}',
66
+ [MESSAGE_INVALID_FORMAT]: 'Deletion date must be in format "DD/MM/YYYY" for {{ nodeName }}',
67
+ [MESSAGE_INVALID_DATE]: 'Invalid "{{ deletionDate }}" deletion date for {{ nodeName }}',
68
+ [MESSAGE_CAN_BE_REMOVED]: '{{ nodeName }} сan be removed',
68
69
  },
69
70
  schema,
70
71
  },
@@ -78,13 +79,20 @@ exports.rule = {
78
79
  context.report({
79
80
  node: node.name,
80
81
  messageId: MESSAGE_REQUIRE_DATE,
82
+ data: {
83
+ nodeName: (0, utils_js_1.getNodeName)(node.parent),
84
+ },
81
85
  });
82
86
  return;
83
87
  }
84
88
  const deletionDate = (0, index_js_1.valueFromNode)(deletionDateNode.value);
85
89
  const isValidDate = DATE_REGEX.test(deletionDate);
86
90
  if (!isValidDate) {
87
- context.report({ node: deletionDateNode.value, messageId: MESSAGE_INVALID_FORMAT });
91
+ context.report({
92
+ node: deletionDateNode.value,
93
+ messageId: MESSAGE_INVALID_FORMAT,
94
+ data: { nodeName: (0, utils_js_1.getNodeName)(node.parent) },
95
+ });
88
96
  return;
89
97
  }
90
98
  let [day, month, year] = deletionDate.split('/');
@@ -97,6 +105,7 @@ exports.rule = {
97
105
  messageId: MESSAGE_INVALID_DATE,
98
106
  data: {
99
107
  deletionDate,
108
+ nodeName: (0, utils_js_1.getNodeName)(node.parent),
100
109
  },
101
110
  });
102
111
  return;
@@ -108,7 +117,7 @@ exports.rule = {
108
117
  context.report({
109
118
  node: parent.name,
110
119
  messageId: MESSAGE_CAN_BE_REMOVED,
111
- data: { nodeName },
120
+ data: { nodeName: (0, utils_js_1.getNodeName)(parent) },
112
121
  suggest: [
113
122
  {
114
123
  desc: `Remove \`${nodeName}\``,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rule = void 0;
4
4
  const graphql_1 = require("graphql");
5
+ const utils_js_1 = require("../utils.js");
5
6
  const RULE_ID = 'require-nullable-fields-with-oneof';
6
7
  exports.rule = {
7
8
  meta: {
@@ -32,7 +33,7 @@ exports.rule = {
32
33
  ],
33
34
  },
34
35
  messages: {
35
- [RULE_ID]: 'Field `{{fieldName}}` must be nullable.',
36
+ [RULE_ID]: '{{ nodeName }} must be nullable when "@oneOf" is in use',
36
37
  },
37
38
  schema: [],
38
39
  },
@@ -51,7 +52,7 @@ exports.rule = {
51
52
  context.report({
52
53
  node: field.name,
53
54
  messageId: RULE_ID,
54
- data: { fieldName: field.name.value },
55
+ data: { nodeName: (0, utils_js_1.getNodeName)(field) },
55
56
  });
56
57
  }
57
58
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rule = void 0;
4
+ const utils_js_1 = require("../utils.js");
4
5
  const RULE_ID = 'require-type-pattern-with-oneof';
5
6
  exports.rule = {
6
7
  meta: {
@@ -34,7 +35,7 @@ exports.rule = {
34
35
  ],
35
36
  },
36
37
  messages: {
37
- [RULE_ID]: 'Type `{{typeName}}` should have `{{fieldName}}` field.',
38
+ [RULE_ID]: '{{ nodeName }} is defined as output with "@oneOf" and must be defined with "{{ fieldName }}" field',
38
39
  },
39
40
  schema: [],
40
41
  },
@@ -49,7 +50,7 @@ exports.rule = {
49
50
  node: parent.name,
50
51
  messageId: RULE_ID,
51
52
  data: {
52
- typeName: parent.name.value,
53
+ nodeName: (0, utils_js_1.displayNodeName)(parent),
53
54
  fieldName,
54
55
  },
55
56
  });
@@ -153,7 +153,9 @@ exports.rule = {
153
153
  const pluralTypesSuffix = options.acceptedIdTypes.length > 1 ? 's' : '';
154
154
  context.report({
155
155
  node: node.name,
156
- message: `${typeName} must have exactly one non-nullable unique identifier. Accepted name${pluralNamesSuffix}: ${(0, utils_js_1.englishJoinWords)(options.acceptedIdNames)}. Accepted type${pluralTypesSuffix}: ${(0, utils_js_1.englishJoinWords)(options.acceptedIdTypes)}.`,
156
+ message: `${(0, utils_js_1.displayNodeName)(node)} must have exactly one non-nullable unique identifier.
157
+ Accepted name${pluralNamesSuffix}: ${(0, utils_js_1.englishJoinWords)(options.acceptedIdNames)}.
158
+ Accepted type${pluralTypesSuffix}: ${(0, utils_js_1.englishJoinWords)(options.acceptedIdTypes)}.`,
157
159
  });
158
160
  }
159
161
  },
package/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNodeName = exports.truthy = exports.englishJoinWords = exports.ARRAY_DEFAULT_OPTIONS = exports.REPORT_ON_FIRST_CHARACTER = exports.getLocation = exports.convertCase = exports.camelCase = exports.pascalCase = exports.TYPES_KINDS = exports.getTypeName = exports.IS_BROWSER = exports.CWD = exports.VIRTUAL_DOCUMENT_REGEX = exports.normalizePath = exports.logger = exports.requireGraphQLSchemaFromContext = exports.requireSiblingsOperations = void 0;
3
+ exports.getNodeName = exports.displayNodeName = exports.truthy = exports.englishJoinWords = exports.ARRAY_DEFAULT_OPTIONS = exports.REPORT_ON_FIRST_CHARACTER = exports.getLocation = exports.convertCase = exports.camelCase = exports.pascalCase = exports.TYPES_KINDS = exports.getTypeName = exports.CWD = exports.VIRTUAL_DOCUMENT_REGEX = exports.normalizePath = exports.logger = exports.requireGraphQLSchemaFromContext = exports.requireSiblingsOperations = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
6
  const graphql_1 = require("graphql");
@@ -33,7 +33,6 @@ const normalizePath = (path) => (path || '').replace(/\\/g, '/');
33
33
  exports.normalizePath = normalizePath;
34
34
  exports.VIRTUAL_DOCUMENT_REGEX = /\/\d+_document.graphql$/;
35
35
  exports.CWD = process.cwd();
36
- exports.IS_BROWSER = typeof window !== 'undefined';
37
36
  const getTypeName = (node) => 'type' in node ? (0, exports.getTypeName)(node.type) : 'name' in node && node.name ? node.name.value : '';
38
37
  exports.getTypeName = getTypeName;
39
38
  exports.TYPES_KINDS = [
@@ -98,19 +97,34 @@ function truthy(value) {
98
97
  return !!value;
99
98
  }
100
99
  exports.truthy = truthy;
100
+ const DisplayNodeNameMap = {
101
+ [graphql_1.Kind.OBJECT_TYPE_DEFINITION]: 'type',
102
+ [graphql_1.Kind.OBJECT_TYPE_EXTENSION]: 'type',
103
+ [graphql_1.Kind.INTERFACE_TYPE_DEFINITION]: 'interface',
104
+ [graphql_1.Kind.INTERFACE_TYPE_EXTENSION]: 'interface',
105
+ [graphql_1.Kind.ENUM_TYPE_DEFINITION]: 'enum',
106
+ [graphql_1.Kind.ENUM_TYPE_EXTENSION]: 'enum',
107
+ [graphql_1.Kind.SCALAR_TYPE_DEFINITION]: 'scalar',
108
+ [graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
109
+ [graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION]: 'input',
110
+ [graphql_1.Kind.UNION_TYPE_DEFINITION]: 'union',
111
+ [graphql_1.Kind.UNION_TYPE_EXTENSION]: 'union',
112
+ [graphql_1.Kind.DIRECTIVE_DEFINITION]: 'directive',
113
+ [graphql_1.Kind.FIELD_DEFINITION]: 'field',
114
+ [graphql_1.Kind.ENUM_VALUE_DEFINITION]: 'value',
115
+ [graphql_1.Kind.INPUT_VALUE_DEFINITION]: 'value',
116
+ [graphql_1.Kind.ARGUMENT]: 'argument',
117
+ [graphql_1.Kind.VARIABLE]: 'variable',
118
+ [graphql_1.Kind.FRAGMENT_DEFINITION]: 'fragment',
119
+ [graphql_1.Kind.OPERATION_DEFINITION]: 'operation',
120
+ [graphql_1.Kind.FIELD]: 'field',
121
+ };
122
+ function displayNodeName(node) {
123
+ var _a, _b;
124
+ return `${node.kind === graphql_1.Kind.OPERATION_DEFINITION ? node.operation : DisplayNodeNameMap[node.kind]} "${('alias' in node && ((_a = node.alias) === null || _a === void 0 ? void 0 : _a.value)) || ('name' in node && ((_b = node.name) === null || _b === void 0 ? void 0 : _b.value))}"`;
125
+ }
126
+ exports.displayNodeName = displayNodeName;
101
127
  function getNodeName(node) {
102
- const DisplayNodeNameMap = {
103
- [graphql_1.Kind.OBJECT_TYPE_DEFINITION]: 'type',
104
- [graphql_1.Kind.INTERFACE_TYPE_DEFINITION]: 'interface',
105
- [graphql_1.Kind.ENUM_TYPE_DEFINITION]: 'enum',
106
- [graphql_1.Kind.SCALAR_TYPE_DEFINITION]: 'scalar',
107
- [graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
108
- [graphql_1.Kind.UNION_TYPE_DEFINITION]: 'union',
109
- [graphql_1.Kind.DIRECTIVE_DEFINITION]: 'directive',
110
- [graphql_1.Kind.FIELD_DEFINITION]: 'field',
111
- [graphql_1.Kind.ENUM_VALUE_DEFINITION]: 'value',
112
- [graphql_1.Kind.INPUT_VALUE_DEFINITION]: 'value',
113
- };
114
128
  switch (node.kind) {
115
129
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
116
130
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
@@ -119,13 +133,13 @@ function getNodeName(node) {
119
133
  case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
120
134
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
121
135
  case graphql_1.Kind.DIRECTIVE_DEFINITION:
122
- return `${DisplayNodeNameMap[node.kind]} "${node.name.value}"`;
136
+ return displayNodeName(node);
123
137
  case graphql_1.Kind.FIELD_DEFINITION:
124
138
  case graphql_1.Kind.INPUT_VALUE_DEFINITION:
125
139
  case graphql_1.Kind.ENUM_VALUE_DEFINITION:
126
- return `${DisplayNodeNameMap[node.kind]} "${node.name.value}" in ${DisplayNodeNameMap[node.parent.kind]} "${node.parent.name.value}"`;
140
+ return `${displayNodeName(node)} in ${displayNodeName(node.parent)}`;
127
141
  case graphql_1.Kind.OPERATION_DEFINITION:
128
- return node.name ? `${node.operation} "${node.name.value}"` : node.operation;
142
+ return node.name ? displayNodeName(node) : node.operation;
129
143
  }
130
144
  return '';
131
145
  }
@@ -1,6 +1,6 @@
1
1
  import { Kind, } from 'graphql';
2
2
  import lowerCase from 'lodash.lowercase';
3
- import { ARRAY_DEFAULT_OPTIONS, truthy } from '../utils.js';
3
+ import { ARRAY_DEFAULT_OPTIONS, displayNodeName, truthy } from '../utils.js';
4
4
  const RULE_ID = 'alphabetize';
5
5
  const fieldsEnum = [
6
6
  Kind.OBJECT_TYPE_DEFINITION,
@@ -181,7 +181,7 @@ export const rule = {
181
181
  },
182
182
  },
183
183
  messages: {
184
- [RULE_ID]: '`{{ currName }}` should be before {{ prevName }}.',
184
+ [RULE_ID]: '{{ currNode }} should be before {{ prevNode }}',
185
185
  },
186
186
  schema,
187
187
  },
@@ -273,8 +273,8 @@ export const rule = {
273
273
  node: ('alias' in currNode && currNode.alias) || currNode.name,
274
274
  messageId: RULE_ID,
275
275
  data: {
276
- currName,
277
- prevName: prevName ? `\`${prevName}\`` : lowerCase(prevNode.kind),
276
+ currNode: displayNodeName(currNode),
277
+ prevNode: prevName ? displayNodeName(prevNode) : lowerCase(prevNode.kind),
278
278
  },
279
279
  *fix(fixer) {
280
280
  const prevRange = getRangeWithComments(prevNode);
@@ -1,3 +1,4 @@
1
+ import { getNodeName } from '../utils.js';
1
2
  const schema = {
2
3
  type: 'array',
3
4
  maxItems: 1,
@@ -54,7 +55,7 @@ export const rule = {
54
55
  [`.description[type=StringValue][block!=${isBlock}]`](node) {
55
56
  context.report({
56
57
  loc: isBlock ? node.loc : node.loc.start,
57
- message: `Unexpected ${isBlock ? 'inline' : 'block'} description.`,
58
+ message: `Unexpected ${isBlock ? 'inline' : 'block'} description for ${getNodeName(node.parent)}`,
58
59
  suggest: [
59
60
  {
60
61
  desc: `Change to ${isBlock ? 'block' : 'inline'} style description`,
@@ -86,11 +86,12 @@ export const rule = {
86
86
  false;
87
87
  const listeners = {
88
88
  'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
89
- if (shouldCheckType(node.parent.parent.parent)) {
89
+ const fieldDef = node.parent.parent;
90
+ if (shouldCheckType(fieldDef.parent)) {
90
91
  const inputName = node.value;
91
92
  context.report({
92
93
  node,
93
- message: `Input \`${inputName}\` should be called \`input\`.`,
94
+ message: `Input "${inputName}" should be named "input" for "${fieldDef.parent.name.value}.${fieldDef.name.value}"`,
94
95
  suggest: [
95
96
  {
96
97
  desc: 'Rename to `input`',
@@ -1,4 +1,5 @@
1
1
  import { Kind } from 'graphql';
2
+ import { getNodeName } from '../utils.js';
2
3
  export const rule = {
3
4
  meta: {
4
5
  type: 'suggestion',
@@ -44,7 +45,7 @@ export const rule = {
44
45
  const enumName = duplicate.name.value;
45
46
  context.report({
46
47
  node: duplicate.name,
47
- message: `Case-insensitive enum values duplicates are not allowed! Found: \`${enumName}\`.`,
48
+ message: `Unexpected case-insensitive enum values duplicates for ${getNodeName(duplicate)}`,
48
49
  suggest: [
49
50
  {
50
51
  desc: `Remove \`${enumName}\` enum value`,
@@ -1,12 +1,13 @@
1
1
  import { TokenKind } from 'graphql';
2
- const HASHTAG_COMMENT = 'HASHTAG_COMMENT';
2
+ import { getNodeName } from '../utils.js';
3
+ export const RULE_ID = 'HASHTAG_COMMENT';
3
4
  export const rule = {
4
5
  meta: {
5
6
  type: 'suggestion',
6
7
  hasSuggestions: true,
7
8
  schema: [],
8
9
  messages: {
9
- [HASHTAG_COMMENT]: 'Using hashtag `#` for adding GraphQL descriptions is not allowed. Prefer using `"""` for multiline, or `"` for a single line description.',
10
+ [RULE_ID]: 'Unexpected GraphQL descriptions as hashtag `#` for {{ nodeName }}.\nPrefer using `"""` for multiline, or `"` for a single line description.',
10
11
  },
11
12
  docs: {
12
13
  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.',
@@ -66,8 +67,15 @@ export const rule = {
66
67
  line !== prev.line &&
67
68
  next.kind === TokenKind.NAME &&
68
69
  linesAfter < 2) {
70
+ const sourceCode = context.getSourceCode();
71
+ const { tokens } = sourceCode.ast;
72
+ const t = tokens.find(token => token.loc.start.line === next.line && token.loc.start.column === next.column - 1);
73
+ const nextNode = sourceCode.getNodeByRangeIndex(t.range[1] + 1);
69
74
  context.report({
70
- messageId: HASHTAG_COMMENT,
75
+ messageId: RULE_ID,
76
+ data: {
77
+ nodeName: getNodeName('name' in nextNode ? nextNode : nextNode.parent),
78
+ },
71
79
  loc: {
72
80
  line,
73
81
  column: column - 1,
@@ -1,5 +1,5 @@
1
- import { isScalarType } from 'graphql';
2
- import { requireGraphQLSchemaFromContext } from '../utils.js';
1
+ import { isScalarType, Kind } from 'graphql';
2
+ import { getNodeName, requireGraphQLSchemaFromContext } from '../utils.js';
3
3
  const RULE_ID = 'no-scalar-result-type-on-mutation';
4
4
  export const rule = {
5
5
  meta: {
@@ -46,9 +46,13 @@ export const rule = {
46
46
  const typeName = node.value;
47
47
  const graphQLType = schema.getType(typeName);
48
48
  if (isScalarType(graphQLType)) {
49
+ let fieldDef = node.parent;
50
+ while (fieldDef.kind !== Kind.FIELD_DEFINITION) {
51
+ fieldDef = fieldDef.parent;
52
+ }
49
53
  context.report({
50
54
  node,
51
- message: `Unexpected scalar result type \`${typeName}\`.`,
55
+ message: `Unexpected scalar result type \`${typeName}\` for ${getNodeName(fieldDef)}`,
52
56
  suggest: [
53
57
  {
54
58
  desc: `Remove \`${typeName}\``,
@@ -1,4 +1,5 @@
1
1
  import { valueFromNode } from '../estree-converter/index.js';
2
+ import { getNodeName } from '../utils.js';
2
3
  // eslint-disable-next-line unicorn/better-regex
3
4
  const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
4
5
  const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
@@ -58,10 +59,10 @@ export const rule = {
58
59
  ],
59
60
  },
60
61
  messages: {
61
- [MESSAGE_REQUIRE_DATE]: 'Directive "@deprecated" must have a deletion date',
62
- [MESSAGE_INVALID_FORMAT]: 'Deletion date must be in format "DD/MM/YYYY"',
63
- [MESSAGE_INVALID_DATE]: 'Invalid "{{ deletionDate }}" deletion date',
64
- [MESSAGE_CAN_BE_REMOVED]: '"{{ nodeName }}" сan be removed',
62
+ [MESSAGE_REQUIRE_DATE]: 'Directive "@deprecated" must have a deletion date for {{ nodeName }}',
63
+ [MESSAGE_INVALID_FORMAT]: 'Deletion date must be in format "DD/MM/YYYY" for {{ nodeName }}',
64
+ [MESSAGE_INVALID_DATE]: 'Invalid "{{ deletionDate }}" deletion date for {{ nodeName }}',
65
+ [MESSAGE_CAN_BE_REMOVED]: '{{ nodeName }} сan be removed',
65
66
  },
66
67
  schema,
67
68
  },
@@ -75,13 +76,20 @@ export const rule = {
75
76
  context.report({
76
77
  node: node.name,
77
78
  messageId: MESSAGE_REQUIRE_DATE,
79
+ data: {
80
+ nodeName: getNodeName(node.parent),
81
+ },
78
82
  });
79
83
  return;
80
84
  }
81
85
  const deletionDate = valueFromNode(deletionDateNode.value);
82
86
  const isValidDate = DATE_REGEX.test(deletionDate);
83
87
  if (!isValidDate) {
84
- context.report({ node: deletionDateNode.value, messageId: MESSAGE_INVALID_FORMAT });
88
+ context.report({
89
+ node: deletionDateNode.value,
90
+ messageId: MESSAGE_INVALID_FORMAT,
91
+ data: { nodeName: getNodeName(node.parent) },
92
+ });
85
93
  return;
86
94
  }
87
95
  let [day, month, year] = deletionDate.split('/');
@@ -94,6 +102,7 @@ export const rule = {
94
102
  messageId: MESSAGE_INVALID_DATE,
95
103
  data: {
96
104
  deletionDate,
105
+ nodeName: getNodeName(node.parent),
97
106
  },
98
107
  });
99
108
  return;
@@ -105,7 +114,7 @@ export const rule = {
105
114
  context.report({
106
115
  node: parent.name,
107
116
  messageId: MESSAGE_CAN_BE_REMOVED,
108
- data: { nodeName },
117
+ data: { nodeName: getNodeName(parent) },
109
118
  suggest: [
110
119
  {
111
120
  desc: `Remove \`${nodeName}\``,
@@ -1,4 +1,5 @@
1
1
  import { Kind } from 'graphql';
2
+ import { getNodeName } from '../utils.js';
2
3
  const RULE_ID = 'require-nullable-fields-with-oneof';
3
4
  export const rule = {
4
5
  meta: {
@@ -29,7 +30,7 @@ export const rule = {
29
30
  ],
30
31
  },
31
32
  messages: {
32
- [RULE_ID]: 'Field `{{fieldName}}` must be nullable.',
33
+ [RULE_ID]: '{{ nodeName }} must be nullable when "@oneOf" is in use',
33
34
  },
34
35
  schema: [],
35
36
  },
@@ -48,7 +49,7 @@ export const rule = {
48
49
  context.report({
49
50
  node: field.name,
50
51
  messageId: RULE_ID,
51
- data: { fieldName: field.name.value },
52
+ data: { nodeName: getNodeName(field) },
52
53
  });
53
54
  }
54
55
  }
@@ -1,3 +1,4 @@
1
+ import { displayNodeName } from '../utils.js';
1
2
  const RULE_ID = 'require-type-pattern-with-oneof';
2
3
  export const rule = {
3
4
  meta: {
@@ -31,7 +32,7 @@ export const rule = {
31
32
  ],
32
33
  },
33
34
  messages: {
34
- [RULE_ID]: 'Type `{{typeName}}` should have `{{fieldName}}` field.',
35
+ [RULE_ID]: '{{ nodeName }} is defined as output with "@oneOf" and must be defined with "{{ fieldName }}" field',
35
36
  },
36
37
  schema: [],
37
38
  },
@@ -46,7 +47,7 @@ export const rule = {
46
47
  node: parent.name,
47
48
  messageId: RULE_ID,
48
49
  data: {
49
- typeName: parent.name.value,
50
+ nodeName: displayNodeName(parent),
50
51
  fieldName,
51
52
  },
52
53
  });
@@ -1,5 +1,5 @@
1
1
  import { Kind } from 'graphql';
2
- import { ARRAY_DEFAULT_OPTIONS, englishJoinWords, requireGraphQLSchemaFromContext, truthy, } from '../utils.js';
2
+ import { ARRAY_DEFAULT_OPTIONS, displayNodeName, englishJoinWords, requireGraphQLSchemaFromContext, truthy, } from '../utils.js';
3
3
  const RULE_ID = 'strict-id-in-types';
4
4
  const schema = {
5
5
  type: 'array',
@@ -150,7 +150,9 @@ export const rule = {
150
150
  const pluralTypesSuffix = options.acceptedIdTypes.length > 1 ? 's' : '';
151
151
  context.report({
152
152
  node: node.name,
153
- message: `${typeName} must have exactly one non-nullable unique identifier. Accepted name${pluralNamesSuffix}: ${englishJoinWords(options.acceptedIdNames)}. Accepted type${pluralTypesSuffix}: ${englishJoinWords(options.acceptedIdTypes)}.`,
153
+ message: `${displayNodeName(node)} must have exactly one non-nullable unique identifier.
154
+ Accepted name${pluralNamesSuffix}: ${englishJoinWords(options.acceptedIdNames)}.
155
+ Accepted type${pluralTypesSuffix}: ${englishJoinWords(options.acceptedIdTypes)}.`,
154
156
  });
155
157
  }
156
158
  },
package/esm/utils.js CHANGED
@@ -26,7 +26,6 @@ export const logger = {
26
26
  export const normalizePath = (path) => (path || '').replace(/\\/g, '/');
27
27
  export const VIRTUAL_DOCUMENT_REGEX = /\/\d+_document.graphql$/;
28
28
  export const CWD = process.cwd();
29
- export const IS_BROWSER = typeof window !== 'undefined';
30
29
  export const getTypeName = (node) => 'type' in node ? getTypeName(node.type) : 'name' in node && node.name ? node.name.value : '';
31
30
  export const TYPES_KINDS = [
32
31
  Kind.OBJECT_TYPE_DEFINITION,
@@ -84,19 +83,33 @@ export const englishJoinWords = (words) => new Intl.ListFormat('en-US', { type:
84
83
  export function truthy(value) {
85
84
  return !!value;
86
85
  }
86
+ const DisplayNodeNameMap = {
87
+ [Kind.OBJECT_TYPE_DEFINITION]: 'type',
88
+ [Kind.OBJECT_TYPE_EXTENSION]: 'type',
89
+ [Kind.INTERFACE_TYPE_DEFINITION]: 'interface',
90
+ [Kind.INTERFACE_TYPE_EXTENSION]: 'interface',
91
+ [Kind.ENUM_TYPE_DEFINITION]: 'enum',
92
+ [Kind.ENUM_TYPE_EXTENSION]: 'enum',
93
+ [Kind.SCALAR_TYPE_DEFINITION]: 'scalar',
94
+ [Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
95
+ [Kind.INPUT_OBJECT_TYPE_EXTENSION]: 'input',
96
+ [Kind.UNION_TYPE_DEFINITION]: 'union',
97
+ [Kind.UNION_TYPE_EXTENSION]: 'union',
98
+ [Kind.DIRECTIVE_DEFINITION]: 'directive',
99
+ [Kind.FIELD_DEFINITION]: 'field',
100
+ [Kind.ENUM_VALUE_DEFINITION]: 'value',
101
+ [Kind.INPUT_VALUE_DEFINITION]: 'value',
102
+ [Kind.ARGUMENT]: 'argument',
103
+ [Kind.VARIABLE]: 'variable',
104
+ [Kind.FRAGMENT_DEFINITION]: 'fragment',
105
+ [Kind.OPERATION_DEFINITION]: 'operation',
106
+ [Kind.FIELD]: 'field',
107
+ };
108
+ export function displayNodeName(node) {
109
+ var _a, _b;
110
+ return `${node.kind === Kind.OPERATION_DEFINITION ? node.operation : DisplayNodeNameMap[node.kind]} "${('alias' in node && ((_a = node.alias) === null || _a === void 0 ? void 0 : _a.value)) || ('name' in node && ((_b = node.name) === null || _b === void 0 ? void 0 : _b.value))}"`;
111
+ }
87
112
  export function getNodeName(node) {
88
- const DisplayNodeNameMap = {
89
- [Kind.OBJECT_TYPE_DEFINITION]: 'type',
90
- [Kind.INTERFACE_TYPE_DEFINITION]: 'interface',
91
- [Kind.ENUM_TYPE_DEFINITION]: 'enum',
92
- [Kind.SCALAR_TYPE_DEFINITION]: 'scalar',
93
- [Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
94
- [Kind.UNION_TYPE_DEFINITION]: 'union',
95
- [Kind.DIRECTIVE_DEFINITION]: 'directive',
96
- [Kind.FIELD_DEFINITION]: 'field',
97
- [Kind.ENUM_VALUE_DEFINITION]: 'value',
98
- [Kind.INPUT_VALUE_DEFINITION]: 'value',
99
- };
100
113
  switch (node.kind) {
101
114
  case Kind.OBJECT_TYPE_DEFINITION:
102
115
  case Kind.INTERFACE_TYPE_DEFINITION:
@@ -105,13 +118,13 @@ export function getNodeName(node) {
105
118
  case Kind.INPUT_OBJECT_TYPE_DEFINITION:
106
119
  case Kind.UNION_TYPE_DEFINITION:
107
120
  case Kind.DIRECTIVE_DEFINITION:
108
- return `${DisplayNodeNameMap[node.kind]} "${node.name.value}"`;
121
+ return displayNodeName(node);
109
122
  case Kind.FIELD_DEFINITION:
110
123
  case Kind.INPUT_VALUE_DEFINITION:
111
124
  case Kind.ENUM_VALUE_DEFINITION:
112
- return `${DisplayNodeNameMap[node.kind]} "${node.name.value}" in ${DisplayNodeNameMap[node.parent.kind]} "${node.parent.name.value}"`;
125
+ return `${displayNodeName(node)} in ${displayNodeName(node.parent)}`;
113
126
  case Kind.OPERATION_DEFINITION:
114
- return node.name ? `${node.operation} "${node.name.value}"` : node.operation;
127
+ return node.name ? displayNodeName(node) : node.operation;
115
128
  }
116
129
  return '';
117
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.16.2-alpha-20230322145450-ffe6eec",
3
+ "version": "3.17.0-alpha-20230323123320-43244a5",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -1,2 +1,3 @@
1
1
  import { GraphQLESLintRule } from '../types.cjs';
2
+ export declare const RULE_ID = "HASHTAG_COMMENT";
2
3
  export declare const rule: GraphQLESLintRule;
@@ -1,2 +1,3 @@
1
1
  import { GraphQLESLintRule } from '../types.js';
2
+ export declare const RULE_ID = "HASHTAG_COMMENT";
2
3
  export declare const rule: GraphQLESLintRule;
@@ -13,7 +13,6 @@ export declare const logger: {
13
13
  export declare const normalizePath: (path: string) => string;
14
14
  export declare const VIRTUAL_DOCUMENT_REGEX: RegExp;
15
15
  export declare const CWD: string;
16
- export declare const IS_BROWSER: boolean;
17
16
  export declare const getTypeName: (node: ASTNode) => string;
18
17
  export declare const TYPES_KINDS: readonly [Kind.OBJECT_TYPE_DEFINITION, Kind.INTERFACE_TYPE_DEFINITION, Kind.ENUM_TYPE_DEFINITION, Kind.SCALAR_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.UNION_TYPE_DEFINITION];
19
18
  export type CaseStyle = 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' | 'UPPER_CASE';
@@ -36,5 +35,6 @@ export declare const ARRAY_DEFAULT_OPTIONS: {
36
35
  export declare const englishJoinWords: (words: string[]) => string;
37
36
  type Truthy<T> = T extends '' | 0 | false | null | undefined ? never : T;
38
37
  export declare function truthy<T>(value: T): value is Truthy<T>;
38
+ export declare function displayNodeName(node: GraphQLESTreeNode<ASTNode>): string;
39
39
  export declare function getNodeName(node: GraphQLESTreeNode<ASTNode>): string;
40
40
  export {};
@@ -13,7 +13,6 @@ export declare const logger: {
13
13
  export declare const normalizePath: (path: string) => string;
14
14
  export declare const VIRTUAL_DOCUMENT_REGEX: RegExp;
15
15
  export declare const CWD: string;
16
- export declare const IS_BROWSER: boolean;
17
16
  export declare const getTypeName: (node: ASTNode) => string;
18
17
  export declare const TYPES_KINDS: readonly [Kind.OBJECT_TYPE_DEFINITION, Kind.INTERFACE_TYPE_DEFINITION, Kind.ENUM_TYPE_DEFINITION, Kind.SCALAR_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.UNION_TYPE_DEFINITION];
19
18
  export type CaseStyle = 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' | 'UPPER_CASE';
@@ -36,5 +35,6 @@ export declare const ARRAY_DEFAULT_OPTIONS: {
36
35
  export declare const englishJoinWords: (words: string[]) => string;
37
36
  type Truthy<T> = T extends '' | 0 | false | null | undefined ? never : T;
38
37
  export declare function truthy<T>(value: T): value is Truthy<T>;
38
+ export declare function displayNodeName(node: GraphQLESTreeNode<ASTNode>): string;
39
39
  export declare function getNodeName(node: GraphQLESTreeNode<ASTNode>): string;
40
40
  export {};