@graphql-eslint/eslint-plugin 3.14.3 → 3.14.4-alpha-20221229152648-0a153c6
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.
- 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) {
|