@graphql-eslint/eslint-plugin 3.14.3 → 3.14.4-alpha-20221229151835-f439b5b
Sign up to get free protection for your applications and to get access to all the features.
- package/cjs/cache.js +3 -2
- package/cjs/documents.js +8 -5
- package/cjs/estree-converter/converter.js +1 -1
- package/cjs/parser.js +4 -2
- package/cjs/processor.js +4 -2
- package/cjs/rules/alphabetize.js +5 -3
- package/cjs/rules/graphql-js-validation.js +9 -6
- package/cjs/rules/input-name.js +5 -4
- package/cjs/rules/naming-convention.js +2 -2
- package/cjs/rules/no-case-insensitive-enum-values-duplicates.js +3 -2
- package/cjs/rules/no-duplicate-fields.js +2 -2
- package/cjs/rules/no-hashtag-description.js +3 -0
- package/cjs/rules/no-root-type.js +1 -1
- package/cjs/rules/no-typename-prefix.js +1 -1
- package/cjs/rules/no-unreachable-types.js +1 -1
- package/cjs/rules/relay-arguments.js +2 -1
- package/cjs/rules/relay-connection-types.js +2 -2
- package/cjs/rules/relay-edge-types.js +7 -4
- package/cjs/rules/relay-page-info.js +2 -1
- package/cjs/rules/require-deprecation-date.js +2 -2
- package/cjs/rules/require-deprecation-reason.js +2 -1
- package/cjs/rules/require-description.js +1 -1
- package/cjs/rules/require-field-of-type-query-in-mutation-result.js +1 -1
- package/cjs/rules/require-id-when-available.js +2 -1
- package/cjs/rules/require-nullable-fields-with-oneof.js +2 -2
- package/cjs/rules/require-type-pattern-with-oneof.js +2 -1
- package/cjs/rules/strict-id-in-types.js +4 -4
- package/cjs/rules/unique-fragment-name.js +1 -0
- package/cjs/schema.js +3 -1
- package/cjs/testkit.js +4 -7
- package/cjs/utils.js +11 -5
- package/esm/cache.js +3 -2
- package/esm/documents.js +8 -5
- package/esm/estree-converter/converter.js +1 -1
- package/esm/graphql-config.js +1 -1
- package/esm/parser.js +4 -2
- package/esm/processor.js +5 -3
- package/esm/rules/alphabetize.js +6 -4
- package/esm/rules/graphql-js-validation.js +9 -6
- package/esm/rules/input-name.js +5 -4
- package/esm/rules/naming-convention.js +3 -3
- package/esm/rules/no-case-insensitive-enum-values-duplicates.js +3 -2
- package/esm/rules/no-duplicate-fields.js +2 -2
- package/esm/rules/no-hashtag-description.js +3 -0
- package/esm/rules/no-root-type.js +2 -2
- package/esm/rules/no-typename-prefix.js +1 -1
- package/esm/rules/no-unreachable-types.js +1 -1
- package/esm/rules/relay-arguments.js +2 -1
- package/esm/rules/relay-connection-types.js +2 -2
- package/esm/rules/relay-edge-types.js +7 -4
- package/esm/rules/relay-page-info.js +2 -1
- package/esm/rules/require-deprecation-date.js +2 -2
- package/esm/rules/require-deprecation-reason.js +2 -1
- package/esm/rules/require-description.js +1 -1
- package/esm/rules/require-field-of-type-query-in-mutation-result.js +1 -1
- package/esm/rules/require-id-when-available.js +2 -1
- package/esm/rules/require-nullable-fields-with-oneof.js +2 -2
- package/esm/rules/require-type-pattern-with-oneof.js +2 -1
- package/esm/rules/strict-id-in-types.js +5 -5
- package/esm/rules/unique-fragment-name.js +1 -0
- package/esm/schema.js +3 -1
- package/esm/testkit.js +4 -7
- package/esm/utils.js +9 -4
- package/package.json +1 -1
- package/typings/cache.d.cts +1 -1
- package/typings/cache.d.ts +1 -1
- package/typings/estree-converter/types.d.cts +4 -4
- package/typings/estree-converter/types.d.ts +4 -4
- package/typings/estree-converter/utils.d.cts +2 -2
- package/typings/estree-converter/utils.d.ts +2 -2
- package/typings/rules/index.d.cts +68 -68
- package/typings/rules/index.d.ts +68 -68
- package/typings/testkit.d.cts +6 -4
- package/typings/testkit.d.ts +6 -4
- package/typings/types.d.cts +4 -3
- package/typings/types.d.ts +4 -3
- package/typings/utils.d.cts +8 -5
- package/typings/utils.d.ts +8 -5
package/cjs/cache.js
CHANGED
@@ -15,11 +15,12 @@ class ModuleCache {
|
|
15
15
|
log('setting entry for', cacheKey);
|
16
16
|
}
|
17
17
|
get(cacheKey, settings = { lifetime: 10 /* seconds */ }) {
|
18
|
-
|
18
|
+
const value = this.map.get(cacheKey);
|
19
|
+
if (!value) {
|
19
20
|
log('cache miss for', cacheKey);
|
20
21
|
return;
|
21
22
|
}
|
22
|
-
const { lastSeen, result } =
|
23
|
+
const { lastSeen, result } = value;
|
23
24
|
// check freshness
|
24
25
|
if (process.env.NODE /* don't check for ESLint CLI */ ||
|
25
26
|
process.hrtime(lastSeen)[0] < settings.lifetime) {
|
package/cjs/documents.js
CHANGED
@@ -13,7 +13,7 @@ const handleVirtualPath = (documents) => {
|
|
13
13
|
const filepathMap = Object.create(null);
|
14
14
|
return documents.map(source => {
|
15
15
|
var _a;
|
16
|
-
const
|
16
|
+
const location = source.location;
|
17
17
|
if (['.gql', '.graphql'].some(extension => location.endsWith(extension))) {
|
18
18
|
return source;
|
19
19
|
}
|
@@ -74,15 +74,17 @@ function getDocuments(project) {
|
|
74
74
|
// Since the siblings array is cached, we can use it as cache key.
|
75
75
|
// We should get the same array reference each time we get
|
76
76
|
// to this point for the same graphql project
|
77
|
-
|
78
|
-
|
77
|
+
const value = siblingOperationsCache.get(siblings);
|
78
|
+
if (value) {
|
79
|
+
return value;
|
79
80
|
}
|
80
81
|
let fragmentsCache = null;
|
81
82
|
const getFragments = () => {
|
83
|
+
var _a;
|
82
84
|
if (fragmentsCache === null) {
|
83
85
|
const result = [];
|
84
86
|
for (const source of siblings) {
|
85
|
-
for (const definition of source.document.definitions) {
|
87
|
+
for (const definition of ((_a = source.document) === null || _a === void 0 ? void 0 : _a.definitions) || []) {
|
86
88
|
if (definition.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
|
87
89
|
result.push({
|
88
90
|
filePath: source.location,
|
@@ -97,10 +99,11 @@ function getDocuments(project) {
|
|
97
99
|
};
|
98
100
|
let cachedOperations = null;
|
99
101
|
const getOperations = () => {
|
102
|
+
var _a;
|
100
103
|
if (cachedOperations === null) {
|
101
104
|
const result = [];
|
102
105
|
for (const source of siblings) {
|
103
|
-
for (const definition of source.document.definitions) {
|
106
|
+
for (const definition of ((_a = source.document) === null || _a === void 0 ? void 0 : _a.definitions) || []) {
|
104
107
|
if (definition.kind === graphql_1.Kind.OPERATION_DEFINITION) {
|
105
108
|
result.push({
|
106
109
|
filePath: source.location,
|
@@ -4,7 +4,7 @@ exports.convertToESTree = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
5
5
|
const utils_js_1 = require("./utils.js");
|
6
6
|
function convertToESTree(node, schema) {
|
7
|
-
const typeInfo = schema
|
7
|
+
const typeInfo = schema && new graphql_1.TypeInfo(schema);
|
8
8
|
const visitor = {
|
9
9
|
leave(node, key, parent) {
|
10
10
|
const leadingComments = 'description' in node && node.description
|
package/cjs/parser.js
CHANGED
@@ -25,7 +25,7 @@ function parseForESLint(code, options) {
|
|
25
25
|
const realFilepath = filePath.replace(utils_js_1.VIRTUAL_DOCUMENT_REGEX, '');
|
26
26
|
const project = gqlConfig.getProjectForFile(realFilepath);
|
27
27
|
const schema = (0, schema_js_1.getSchema)(project, options.schemaOptions);
|
28
|
-
const rootTree = (0, index_js_1.convertToESTree)(document, schema instanceof graphql_1.GraphQLSchema ? schema :
|
28
|
+
const rootTree = (0, index_js_1.convertToESTree)(document, schema instanceof graphql_1.GraphQLSchema ? schema : undefined);
|
29
29
|
return {
|
30
30
|
services: {
|
31
31
|
schema,
|
@@ -43,7 +43,9 @@ function parseForESLint(code, options) {
|
|
43
43
|
};
|
44
44
|
}
|
45
45
|
catch (error) {
|
46
|
-
error
|
46
|
+
if (error instanceof Error) {
|
47
|
+
error.message = `[graphql-eslint] ${error.message}`;
|
48
|
+
}
|
47
49
|
// In case of GraphQL parser error, we report it to ESLint as a parser error that matches the requirements
|
48
50
|
// of ESLint. This will make sure to display it correctly in IDEs and lint results.
|
49
51
|
if (error instanceof graphql_1.GraphQLError) {
|
package/cjs/processor.js
CHANGED
@@ -26,7 +26,7 @@ exports.processor = {
|
|
26
26
|
...modules.map(({ identifier }) => identifier),
|
27
27
|
...(0, utils_1.asArray)(globalGqlIdentifierName),
|
28
28
|
gqlMagicComment,
|
29
|
-
].filter(
|
29
|
+
].filter(utils_js_1.truthy)),
|
30
30
|
];
|
31
31
|
}
|
32
32
|
if (keywords.every(keyword => !code.includes(keyword))) {
|
@@ -48,7 +48,9 @@ exports.processor = {
|
|
48
48
|
return [...blocks, code /* source code must be provided and be last */];
|
49
49
|
}
|
50
50
|
catch (error) {
|
51
|
-
error
|
51
|
+
if (error instanceof Error) {
|
52
|
+
error.message = `[graphql-eslint] Error while preprocessing "${(0, path_1.relative)(utils_js_1.CWD, filePath)}" file\n\n${error.message}`;
|
53
|
+
}
|
52
54
|
// eslint-disable-next-line no-console
|
53
55
|
console.error(error);
|
54
56
|
// in case of parsing error return code as is
|
package/cjs/rules/alphabetize.js
CHANGED
@@ -228,7 +228,7 @@ exports.rule = {
|
|
228
228
|
: node;
|
229
229
|
return [from.range[0], to.range[1]];
|
230
230
|
}
|
231
|
-
function checkNodes(nodes) {
|
231
|
+
function checkNodes(nodes = []) {
|
232
232
|
var _a, _b, _c, _d;
|
233
233
|
// Starts from 1, ignore nodes.length <= 1
|
234
234
|
for (let i = 1; i < nodes.length; i += 1) {
|
@@ -273,6 +273,7 @@ exports.rule = {
|
|
273
273
|
}
|
274
274
|
}
|
275
275
|
context.report({
|
276
|
+
// @ts-expect-error can't be undefined
|
276
277
|
node: ('alias' in currNode && currNode.alias) || currNode.name,
|
277
278
|
messageId: RULE_ID,
|
278
279
|
data: {
|
@@ -305,7 +306,7 @@ exports.rule = {
|
|
305
306
|
graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION,
|
306
307
|
],
|
307
308
|
]
|
308
|
-
.filter(
|
309
|
+
.filter(utils_js_1.truthy)
|
309
310
|
.flat();
|
310
311
|
const fieldsSelector = kinds.join(',');
|
311
312
|
const hasEnumValues = ((_b = opts.values) === null || _b === void 0 ? void 0 : _b[0]) === graphql_1.Kind.ENUM_TYPE_DEFINITION;
|
@@ -330,7 +331,8 @@ exports.rule = {
|
|
330
331
|
}
|
331
332
|
if (hasVariables) {
|
332
333
|
listeners.OperationDefinition = (node) => {
|
333
|
-
|
334
|
+
var _a;
|
335
|
+
checkNodes((_a = node.variableDefinitions) === null || _a === void 0 ? void 0 : _a.map(varDef => varDef.variable));
|
334
336
|
};
|
335
337
|
}
|
336
338
|
if (argumentsSelector) {
|
@@ -46,10 +46,10 @@ function validateDocument({ context, schema = null, documentNode, rule, hasDidYo
|
|
46
46
|
});
|
47
47
|
}
|
48
48
|
}
|
49
|
-
catch (
|
49
|
+
catch (error) {
|
50
50
|
context.report({
|
51
51
|
loc: utils_js_1.REPORT_ON_FIRST_CHARACTER,
|
52
|
-
message:
|
52
|
+
message: error.message,
|
53
53
|
});
|
54
54
|
}
|
55
55
|
}
|
@@ -186,10 +186,13 @@ exports.GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule({
|
|
186
186
|
if (ignoreClientDirectives.length === 0) {
|
187
187
|
return documentNode;
|
188
188
|
}
|
189
|
-
const filterDirectives = (node) =>
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
const filterDirectives = (node) => {
|
190
|
+
var _a;
|
191
|
+
return ({
|
192
|
+
...node,
|
193
|
+
directives: (_a = node.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => !ignoreClientDirectives.includes(directive.name.value)),
|
194
|
+
});
|
195
|
+
};
|
193
196
|
return (0, graphql_1.visit)(documentNode, {
|
194
197
|
Field: filterDirectives,
|
195
198
|
OperationDefinition: filterDirectives,
|
package/cjs/rules/input-name.js
CHANGED
@@ -79,12 +79,12 @@ exports.rule = {
|
|
79
79
|
const options = {
|
80
80
|
checkInputType: false,
|
81
81
|
caseSensitiveInputType: true,
|
82
|
-
checkQueries: false,
|
83
82
|
checkMutations: true,
|
84
83
|
...context.options[0],
|
85
84
|
};
|
86
|
-
const shouldCheckType = node => (options.checkMutations && isMutationType(node)) ||
|
87
|
-
(options.checkQueries && isQueryType(node))
|
85
|
+
const shouldCheckType = (node) => (options.checkMutations && isMutationType(node)) ||
|
86
|
+
(options.checkQueries && isQueryType(node)) ||
|
87
|
+
false;
|
88
88
|
const listeners = {
|
89
89
|
'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
|
90
90
|
if (shouldCheckType(node.parent.parent.parent)) {
|
@@ -104,9 +104,10 @@ exports.rule = {
|
|
104
104
|
};
|
105
105
|
if (options.checkInputType) {
|
106
106
|
listeners['FieldDefinition > InputValueDefinition NamedType'] = (node) => {
|
107
|
-
const findInputType = item => {
|
107
|
+
const findInputType = (item) => {
|
108
108
|
let currentNode = item;
|
109
109
|
while (currentNode.type !== graphql_1.Kind.INPUT_VALUE_DEFINITION) {
|
110
|
+
// @ts-expect-error TODO try fix type error
|
110
111
|
currentNode = currentNode.parent;
|
111
112
|
}
|
112
113
|
return currentNode;
|
@@ -215,7 +215,7 @@ exports.rule = {
|
|
215
215
|
const options = context.options[0] || {};
|
216
216
|
const { allowLeadingUnderscore, allowTrailingUnderscore, types, ...restOptions } = options;
|
217
217
|
function normalisePropertyOption(kind) {
|
218
|
-
const style = restOptions[kind] || types;
|
218
|
+
const style = (restOptions[kind] || types);
|
219
219
|
return typeof style === 'object' ? style : { style };
|
220
220
|
}
|
221
221
|
function report(node, message, suggestedName) {
|
@@ -301,7 +301,7 @@ exports.rule = {
|
|
301
301
|
if (!allowTrailingUnderscore) {
|
302
302
|
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore(false);
|
303
303
|
}
|
304
|
-
const selectors = new Set([types && utils_js_1.TYPES_KINDS, Object.keys(restOptions)].flat().filter(
|
304
|
+
const selectors = new Set([types && utils_js_1.TYPES_KINDS, Object.keys(restOptions)].flat().filter(utils_js_1.truthy));
|
305
305
|
for (const selector of selectors) {
|
306
306
|
listeners[selector] = checkNode(selector);
|
307
307
|
}
|
@@ -40,9 +40,10 @@ exports.rule = {
|
|
40
40
|
const selector = [graphql_1.Kind.ENUM_TYPE_DEFINITION, graphql_1.Kind.ENUM_TYPE_EXTENSION].join(',');
|
41
41
|
return {
|
42
42
|
[selector](node) {
|
43
|
-
|
43
|
+
var _a;
|
44
|
+
const duplicates = (_a = node.values) === null || _a === void 0 ? void 0 : _a.filter((item, index, array) => array.findIndex(v => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !==
|
44
45
|
index);
|
45
|
-
for (const duplicate of duplicates) {
|
46
|
+
for (const duplicate of duplicates || []) {
|
46
47
|
const enumName = duplicate.name.value;
|
47
48
|
context.report({
|
48
49
|
node: duplicate.name,
|
@@ -89,13 +89,13 @@ exports.rule = {
|
|
89
89
|
return {
|
90
90
|
OperationDefinition(node) {
|
91
91
|
const set = new Set();
|
92
|
-
for (const varDef of node.variableDefinitions) {
|
92
|
+
for (const varDef of node.variableDefinitions || []) {
|
93
93
|
checkNode(set, varDef.variable.name);
|
94
94
|
}
|
95
95
|
},
|
96
96
|
Field(node) {
|
97
97
|
const set = new Set();
|
98
|
-
for (const arg of node.arguments) {
|
98
|
+
for (const arg of node.arguments || []) {
|
99
99
|
checkNode(set, arg.name);
|
100
100
|
}
|
101
101
|
},
|
@@ -60,7 +60,7 @@ exports.rule = {
|
|
60
60
|
disallow.has('mutation') && schema.getMutationType(),
|
61
61
|
disallow.has('subscription') && schema.getSubscriptionType(),
|
62
62
|
]
|
63
|
-
.filter(
|
63
|
+
.filter(utils_js_1.truthy)
|
64
64
|
.map(type => type.name)
|
65
65
|
.join('|');
|
66
66
|
if (!rootTypeNames) {
|
@@ -40,7 +40,7 @@ exports.rule = {
|
|
40
40
|
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
41
41
|
const typeName = node.name.value;
|
42
42
|
const lowerTypeName = typeName.toLowerCase();
|
43
|
-
for (const field of node.fields) {
|
43
|
+
for (const field of node.fields || []) {
|
44
44
|
const fieldName = field.name.value;
|
45
45
|
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
46
46
|
context.report({
|
@@ -52,7 +52,7 @@ function getReachableTypes(schema) {
|
|
52
52
|
(0, graphql_1.visit)(astNode, visitor);
|
53
53
|
}
|
54
54
|
}
|
55
|
-
else if (type.astNode) {
|
55
|
+
else if (type === null || type === void 0 ? void 0 : type.astNode) {
|
56
56
|
// astNode can be undefined for ID, String, Boolean
|
57
57
|
(0, graphql_1.visit)(type.astNode, visitor);
|
58
58
|
}
|
@@ -72,11 +72,12 @@ exports.rule = {
|
|
72
72
|
const { includeBoth = true } = context.options[0] || {};
|
73
73
|
return {
|
74
74
|
'FieldDefinition > .gqlType Name[value=/Connection$/]'(node) {
|
75
|
+
var _a;
|
75
76
|
let fieldNode = node.parent;
|
76
77
|
while (fieldNode.kind !== graphql_1.Kind.FIELD_DEFINITION) {
|
77
78
|
fieldNode = fieldNode.parent;
|
78
79
|
}
|
79
|
-
const args = Object.fromEntries(fieldNode.arguments.map(argument => [argument.name.value, argument]));
|
80
|
+
const args = Object.fromEntries(((_a = fieldNode.arguments) === null || _a === void 0 ? void 0 : _a.map(argument => [argument.name.value, argument])) || []);
|
80
81
|
const hasForwardPagination = Boolean(args.first && args.after);
|
81
82
|
const hasBackwardPagination = Boolean(args.last && args.before);
|
82
83
|
if (!hasForwardPagination && !hasBackwardPagination) {
|
@@ -20,8 +20,8 @@ exports.NON_OBJECT_TYPES = [
|
|
20
20
|
graphql_1.Kind.INTERFACE_TYPE_EXTENSION,
|
21
21
|
];
|
22
22
|
const notConnectionTypesSelector = `:matches(${exports.NON_OBJECT_TYPES})[name.value=/Connection$/] > .name`;
|
23
|
-
const hasEdgesField = (node) => node.fields.some(field => field.name.value === 'edges');
|
24
|
-
const hasPageInfoField = (node) => node.fields.some(field => field.name.value === 'pageInfo');
|
23
|
+
const hasEdgesField = (node) => { var _a; return (_a = node.fields) === null || _a === void 0 ? void 0 : _a.some(field => field.name.value === 'edges'); };
|
24
|
+
const hasPageInfoField = (node) => { var _a; return (_a = node.fields) === null || _a === void 0 ? void 0 : _a.some(field => field.name.value === 'pageInfo'); };
|
25
25
|
exports.rule = {
|
26
26
|
meta: {
|
27
27
|
type: 'problem',
|
@@ -19,12 +19,13 @@ function getEdgeTypes(schema) {
|
|
19
19
|
const edgeTypes = new Set();
|
20
20
|
const visitor = {
|
21
21
|
ObjectTypeDefinition(node) {
|
22
|
+
var _a;
|
22
23
|
const typeName = node.name.value;
|
23
24
|
const hasConnectionSuffix = typeName.endsWith('Connection');
|
24
25
|
if (!hasConnectionSuffix) {
|
25
26
|
return;
|
26
27
|
}
|
27
|
-
const edges = node.fields.find(field => field.name.value === 'edges');
|
28
|
+
const edges = (_a = node.fields) === null || _a === void 0 ? void 0 : _a.find(field => field.name.value === 'edges');
|
28
29
|
if (edges) {
|
29
30
|
const edgesTypeName = (0, utils_js_1.getTypeName)(edges);
|
30
31
|
const edgesType = schema.getType(edgesTypeName);
|
@@ -116,7 +117,8 @@ exports.rule = {
|
|
116
117
|
const isNamedOrNonNullNamed = (node) => node.kind === graphql_1.Kind.NAMED_TYPE ||
|
117
118
|
(node.kind === graphql_1.Kind.NON_NULL_TYPE && node.gqlType.kind === graphql_1.Kind.NAMED_TYPE);
|
118
119
|
const checkNodeField = (node) => {
|
119
|
-
|
120
|
+
var _a, _b;
|
121
|
+
const nodeField = (_a = node.fields) === null || _a === void 0 ? void 0 : _a.find(field => field.name.value === 'node');
|
120
122
|
const message = 'return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types.';
|
121
123
|
if (!nodeField) {
|
122
124
|
context.report({
|
@@ -133,14 +135,15 @@ exports.rule = {
|
|
133
135
|
if (!(0, graphql_1.isObjectType)(type)) {
|
134
136
|
return;
|
135
137
|
}
|
136
|
-
const implementsNode = type.astNode.interfaces.some(n => n.name.value === 'Node');
|
138
|
+
const implementsNode = (_b = type.astNode.interfaces) === null || _b === void 0 ? void 0 : _b.some(n => n.name.value === 'Node');
|
137
139
|
if (!implementsNode) {
|
138
140
|
context.report({ node: node.name, messageId: MESSAGE_SHOULD_IMPLEMENTS_NODE });
|
139
141
|
}
|
140
142
|
}
|
141
143
|
};
|
142
144
|
const checkCursorField = (node) => {
|
143
|
-
|
145
|
+
var _a;
|
146
|
+
const cursorField = (_a = node.fields) === null || _a === void 0 ? void 0 : _a.find(field => field.name.value === 'cursor');
|
144
147
|
const message = 'return either a String, Scalar, or a non-null wrapper wrapper around one of those types.';
|
145
148
|
if (!cursorField) {
|
146
149
|
context.report({
|
@@ -61,7 +61,8 @@ exports.rule = {
|
|
61
61
|
context.report({ node, messageId: MESSAGE_MUST_BE_OBJECT_TYPE });
|
62
62
|
},
|
63
63
|
'ObjectTypeDefinition[name.value=PageInfo]'(node) {
|
64
|
-
|
64
|
+
var _a;
|
65
|
+
const fieldMap = Object.fromEntries(((_a = node.fields) === null || _a === void 0 ? void 0 : _a.map(field => [field.name.value, field])) || []);
|
65
66
|
const checkField = (fieldName, typeName) => {
|
66
67
|
const field = fieldMap[fieldName];
|
67
68
|
let isAllowedType = false;
|
@@ -71,9 +71,9 @@ exports.rule = {
|
|
71
71
|
create(context) {
|
72
72
|
return {
|
73
73
|
'Directive[name.value=deprecated]'(node) {
|
74
|
-
var _a;
|
74
|
+
var _a, _b;
|
75
75
|
const argName = ((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.argumentName) || 'deletionDate';
|
76
|
-
const deletionDateNode = node.arguments.find(arg => arg.name.value === argName);
|
76
|
+
const deletionDateNode = (_b = node.arguments) === null || _b === void 0 ? void 0 : _b.find(arg => arg.name.value === argName);
|
77
77
|
if (!deletionDateNode) {
|
78
78
|
context.report({
|
79
79
|
node: node.name,
|
@@ -42,7 +42,8 @@ exports.rule = {
|
|
42
42
|
create(context) {
|
43
43
|
return {
|
44
44
|
'Directive[name.value=deprecated]'(node) {
|
45
|
-
|
45
|
+
var _a;
|
46
|
+
const reasonArgument = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a.find(arg => arg.name.value === 'reason');
|
46
47
|
const value = reasonArgument && String((0, index_js_1.valueFromNode)(reasonArgument.value)).trim();
|
47
48
|
if (!value) {
|
48
49
|
context.report({
|
@@ -167,7 +167,7 @@ exports.rule = {
|
|
167
167
|
if (isOperation) {
|
168
168
|
const rawNode = node.rawNode();
|
169
169
|
const { prev, line } = rawNode.loc.startToken;
|
170
|
-
if (prev.kind === graphql_1.TokenKind.COMMENT) {
|
170
|
+
if ((prev === null || prev === void 0 ? void 0 : prev.kind) === graphql_1.TokenKind.COMMENT) {
|
171
171
|
const value = prev.value.trim();
|
172
172
|
const linesBefore = line - prev.line;
|
173
173
|
if (!value.startsWith('eslint') && linesBefore === 1) {
|
@@ -58,7 +58,7 @@ exports.rule = {
|
|
58
58
|
const graphQLType = schema.getType(typeName);
|
59
59
|
if ((0, graphql_1.isObjectType)(graphQLType)) {
|
60
60
|
const { fields } = graphQLType.astNode;
|
61
|
-
const hasQueryType = fields.some(field => (0, utils_js_1.getTypeName)(field) === queryType.name);
|
61
|
+
const hasQueryType = fields === null || fields === void 0 ? void 0 : fields.some(field => (0, utils_js_1.getTypeName)(field) === queryType.name);
|
62
62
|
if (!hasQueryType) {
|
63
63
|
context.report({
|
64
64
|
node,
|
@@ -108,7 +108,8 @@ exports.rule = {
|
|
108
108
|
}
|
109
109
|
const checkedFragmentSpreads = new Set();
|
110
110
|
const visitor = (0, graphql_1.visitWithTypeInfo)(typeInfo, {
|
111
|
-
SelectionSet(node, key,
|
111
|
+
SelectionSet(node, key, _parent) {
|
112
|
+
const parent = _parent;
|
112
113
|
if (parent.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
|
113
114
|
checkedFragmentSpreads.add(parent.name.value);
|
114
115
|
}
|
@@ -38,7 +38,7 @@ exports.rule = {
|
|
38
38
|
},
|
39
39
|
create(context) {
|
40
40
|
return {
|
41
|
-
'Directive[name.value=oneOf]'({ parent
|
41
|
+
'Directive[name.value=oneOf]'({ parent }) {
|
42
42
|
const isTypeOrInput = [
|
43
43
|
graphql_1.Kind.OBJECT_TYPE_DEFINITION,
|
44
44
|
graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
@@ -46,7 +46,7 @@ exports.rule = {
|
|
46
46
|
if (!isTypeOrInput) {
|
47
47
|
return;
|
48
48
|
}
|
49
|
-
for (const field of parent.fields) {
|
49
|
+
for (const field of parent.fields || []) {
|
50
50
|
if (field.gqlType.kind === graphql_1.Kind.NON_NULL_TYPE) {
|
51
51
|
context.report({
|
52
52
|
node: field.name,
|
@@ -41,9 +41,10 @@ exports.rule = {
|
|
41
41
|
create(context) {
|
42
42
|
return {
|
43
43
|
'Directive[name.value=oneOf][parent.kind=ObjectTypeDefinition]'({ parent, }) {
|
44
|
+
var _a;
|
44
45
|
const requiredFields = ['error', 'ok'];
|
45
46
|
for (const fieldName of requiredFields) {
|
46
|
-
if (!parent.fields.some(field => field.name.value === fieldName)) {
|
47
|
+
if (!((_a = parent.fields) === null || _a === void 0 ? void 0 : _a.some(field => field.name.value === fieldName))) {
|
47
48
|
context.report({
|
48
49
|
node: parent.name,
|
49
50
|
messageId: RULE_ID,
|
@@ -122,19 +122,19 @@ exports.rule = {
|
|
122
122
|
schema.getMutationType(),
|
123
123
|
schema.getSubscriptionType(),
|
124
124
|
]
|
125
|
-
.filter(
|
125
|
+
.filter(utils_js_1.truthy)
|
126
126
|
.map(type => type.name);
|
127
127
|
const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join('|')})$/]`;
|
128
128
|
return {
|
129
129
|
[selector](node) {
|
130
|
-
var _a, _b;
|
130
|
+
var _a, _b, _c;
|
131
131
|
const typeName = node.name.value;
|
132
132
|
const shouldIgnoreNode = ((_a = options.exceptions.types) === null || _a === void 0 ? void 0 : _a.includes(typeName)) ||
|
133
133
|
((_b = options.exceptions.suffixes) === null || _b === void 0 ? void 0 : _b.some(suffix => typeName.endsWith(suffix)));
|
134
134
|
if (shouldIgnoreNode) {
|
135
135
|
return;
|
136
136
|
}
|
137
|
-
const validIds = node.fields.filter(field => {
|
137
|
+
const validIds = (_c = node.fields) === null || _c === void 0 ? void 0 : _c.filter(field => {
|
138
138
|
const fieldNode = field.rawNode();
|
139
139
|
const isValidIdName = options.acceptedIdNames.includes(fieldNode.name.value);
|
140
140
|
// To be a valid type, it must be non-null and one of the accepted types.
|
@@ -148,7 +148,7 @@ exports.rule = {
|
|
148
148
|
// Usually, there should be only one unique identifier field per type.
|
149
149
|
// Some clients allow multiple fields to be used. If more people need this,
|
150
150
|
// we can extend this rule later.
|
151
|
-
if (validIds.length !== 1) {
|
151
|
+
if ((validIds === null || validIds === void 0 ? void 0 : validIds.length) !== 1) {
|
152
152
|
const pluralNamesSuffix = options.acceptedIdNames.length > 1 ? 's' : '';
|
153
153
|
const pluralTypesSuffix = options.acceptedIdTypes.length > 1 ? 's' : '';
|
154
154
|
context.report({
|
package/cjs/schema.js
CHANGED
@@ -34,7 +34,9 @@ function getSchema(project, schemaOptions) {
|
|
34
34
|
schemaCache.set(schemaKey, schema);
|
35
35
|
}
|
36
36
|
catch (error) {
|
37
|
-
error
|
37
|
+
if (error instanceof Error) {
|
38
|
+
error.message = chalk_1.default.red(`Error while loading schema: ${error.message}`);
|
39
|
+
}
|
38
40
|
schema = error;
|
39
41
|
}
|
40
42
|
return schema;
|
package/cjs/testkit.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.GraphQLRuleTester = void 0;
|
4
|
-
/* eslint-env
|
4
|
+
/* eslint-env vitest */
|
5
5
|
const fs_1 = require("fs");
|
6
6
|
const path_1 = require("path");
|
7
7
|
const eslint_1 = require("eslint");
|
@@ -60,7 +60,7 @@ class GraphQLRuleTester extends eslint_1.RuleTester {
|
|
60
60
|
// continue;
|
61
61
|
// }
|
62
62
|
//
|
63
|
-
// const verifyConfig = getVerifyConfig(ruleId, this.config, testCase);
|
63
|
+
// const verifyConfig = getVerifyConfig<Options>(ruleId, this.config, testCase);
|
64
64
|
// defineParser(linter, verifyConfig.parser);
|
65
65
|
//
|
66
66
|
// const messages = linter.verify(code, verifyConfig, { filename });
|
@@ -94,11 +94,10 @@ class GraphQLRuleTester extends eslint_1.RuleTester {
|
|
94
94
|
}
|
95
95
|
const codeWithMessage = printCode(code, message, 1);
|
96
96
|
messageForSnapshot.push(printWithIndex('#### ❌ Error', index, messages.length), indentCode(codeWithMessage));
|
97
|
-
const { suggestions } = message;
|
98
97
|
// Don't print suggestions in snapshots for too big codes
|
99
|
-
if (suggestions && (code.match(/\n/g) || '').length < 1000) {
|
98
|
+
if (message.suggestions && (code.match(/\n/g) || '').length < 1000) {
|
100
99
|
for (const [i, suggestion] of message.suggestions.entries()) {
|
101
|
-
const title = printWithIndex('#### 💡 Suggestion', i, suggestions.length, suggestion.desc);
|
100
|
+
const title = printWithIndex('#### 💡 Suggestion', i, message.suggestions.length, suggestion.desc);
|
102
101
|
const output = applyFix(code, suggestion.fix);
|
103
102
|
const codeFrame = printCode(output, { line: 0, column: 0 });
|
104
103
|
messageForSnapshot.push(title, indentCode(codeFrame, 2));
|
@@ -111,9 +110,7 @@ class GraphQLRuleTester extends eslint_1.RuleTester {
|
|
111
110
|
messageForSnapshot.push('#### 🔧 Autofix output', indentCode(printCode(output)));
|
112
111
|
}
|
113
112
|
}
|
114
|
-
// @ts-expect-error -- we should import `vitest` but somebody could use globals from `jest`
|
115
113
|
it(name || `Invalid #${idx + 1}`, () => {
|
116
|
-
// @ts-expect-error -- ^ same
|
117
114
|
expect(messageForSnapshot.join('\n\n')).toMatchSnapshot();
|
118
115
|
});
|
119
116
|
}
|
package/cjs/utils.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
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;
|
3
|
+
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 graphql_1 = require("graphql");
|
6
6
|
const lodash_lowercase_1 = tslib_1.__importDefault(require("lodash.lowercase"));
|
@@ -25,16 +25,18 @@ function requireGraphQLSchemaFromContext(ruleId, context) {
|
|
25
25
|
}
|
26
26
|
exports.requireGraphQLSchemaFromContext = requireGraphQLSchemaFromContext;
|
27
27
|
exports.logger = {
|
28
|
+
error: (...args) =>
|
28
29
|
// eslint-disable-next-line no-console
|
29
|
-
|
30
|
+
console.error(chalk_1.default.red('error'), '[graphql-eslint]', (0, chalk_1.default)(...args)),
|
31
|
+
warn: (...args) =>
|
30
32
|
// eslint-disable-next-line no-console
|
31
|
-
|
33
|
+
console.warn(chalk_1.default.yellow('warning'), '[graphql-eslint]', (0, chalk_1.default)(...args)),
|
32
34
|
};
|
33
35
|
const normalizePath = (path) => (path || '').replace(/\\/g, '/');
|
34
36
|
exports.normalizePath = normalizePath;
|
35
37
|
exports.VIRTUAL_DOCUMENT_REGEX = /\/\d+_document.graphql$/;
|
36
38
|
exports.CWD = process.cwd();
|
37
|
-
const getTypeName = (node) => 'type' in node ? (0, exports.getTypeName)(node.type) : node.name.value;
|
39
|
+
const getTypeName = (node) => 'type' in node ? (0, exports.getTypeName)(node.type) : 'name' in node && node.name ? node.name.value : '';
|
38
40
|
exports.getTypeName = getTypeName;
|
39
41
|
exports.TYPES_KINDS = [
|
40
42
|
graphql_1.Kind.OBJECT_TYPE_DEFINITION,
|
@@ -92,5 +94,9 @@ exports.ARRAY_DEFAULT_OPTIONS = {
|
|
92
94
|
type: 'string',
|
93
95
|
},
|
94
96
|
};
|
95
|
-
const englishJoinWords = words => new Intl.ListFormat('en-US', { type: 'disjunction' }).format(words);
|
97
|
+
const englishJoinWords = (words) => new Intl.ListFormat('en-US', { type: 'disjunction' }).format(words);
|
96
98
|
exports.englishJoinWords = englishJoinWords;
|
99
|
+
function truthy(value) {
|
100
|
+
return Boolean(value);
|
101
|
+
}
|
102
|
+
exports.truthy = truthy;
|
package/esm/cache.js
CHANGED
@@ -11,11 +11,12 @@ export class ModuleCache {
|
|
11
11
|
log('setting entry for', cacheKey);
|
12
12
|
}
|
13
13
|
get(cacheKey, settings = { lifetime: 10 /* seconds */ }) {
|
14
|
-
|
14
|
+
const value = this.map.get(cacheKey);
|
15
|
+
if (!value) {
|
15
16
|
log('cache miss for', cacheKey);
|
16
17
|
return;
|
17
18
|
}
|
18
|
-
const { lastSeen, result } =
|
19
|
+
const { lastSeen, result } = value;
|
19
20
|
// check freshness
|
20
21
|
if (process.env.NODE /* don't check for ESLint CLI */ ||
|
21
22
|
process.hrtime(lastSeen)[0] < settings.lifetime) {
|