@graphql-eslint/eslint-plugin 3.1.1-alpha-f19a99b.0 → 3.2.0-alpha-001cd75.0
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/index.js +96 -99
- package/index.mjs +96 -99
- package/package.json +1 -1
- package/rules/graphql-js-validation.d.ts +1 -1
- package/rules/index.d.ts +2 -129
- package/rules/match-document-filename.d.ts +3 -3
- package/rules/naming-convention.d.ts +1 -1
- package/utils.d.ts +1 -7
package/index.js
CHANGED
@@ -286,14 +286,6 @@ const TYPES_KINDS = [
|
|
286
286
|
graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
287
287
|
graphql.Kind.UNION_TYPE_DEFINITION,
|
288
288
|
];
|
289
|
-
var CaseStyle;
|
290
|
-
(function (CaseStyle) {
|
291
|
-
CaseStyle["camelCase"] = "camelCase";
|
292
|
-
CaseStyle["pascalCase"] = "PascalCase";
|
293
|
-
CaseStyle["snakeCase"] = "snake_case";
|
294
|
-
CaseStyle["upperCase"] = "UPPER_CASE";
|
295
|
-
CaseStyle["kebabCase"] = "kebab-case";
|
296
|
-
})(CaseStyle || (CaseStyle = {}));
|
297
289
|
const pascalCase = (str) => lowerCase(str)
|
298
290
|
.split(' ')
|
299
291
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
@@ -304,15 +296,15 @@ const camelCase = (str) => {
|
|
304
296
|
};
|
305
297
|
const convertCase = (style, str) => {
|
306
298
|
switch (style) {
|
307
|
-
case
|
299
|
+
case 'camelCase':
|
308
300
|
return camelCase(str);
|
309
|
-
case
|
301
|
+
case 'PascalCase':
|
310
302
|
return pascalCase(str);
|
311
|
-
case
|
303
|
+
case 'snake_case':
|
312
304
|
return lowerCase(str).replace(/ /g, '_');
|
313
|
-
case
|
305
|
+
case 'UPPER_CASE':
|
314
306
|
return lowerCase(str).replace(/ /g, '_').toUpperCase();
|
315
|
-
case
|
307
|
+
case 'kebab-case':
|
316
308
|
return lowerCase(str).replace(/ /g, '-');
|
317
309
|
}
|
318
310
|
};
|
@@ -335,42 +327,30 @@ function getLocation(loc, fieldName = '', offset) {
|
|
335
327
|
};
|
336
328
|
}
|
337
329
|
|
338
|
-
function
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
* }
|
357
|
-
* }
|
358
|
-
*/
|
359
|
-
const { line, column } = error.locations[0];
|
360
|
-
const ancestors = context.getAncestors();
|
361
|
-
const token = ancestors[0].tokens.find(token => token.loc.start.line === line && token.loc.start.column === column);
|
330
|
+
function extractRuleName(stack) {
|
331
|
+
const match = (stack || '').match(/validation[/\\]rules[/\\](.*?)\.js:/) || [];
|
332
|
+
return match[1] || null;
|
333
|
+
}
|
334
|
+
function validateDoc(sourceNode, context, schema, documentNode, rules, ruleName = null) {
|
335
|
+
var _a;
|
336
|
+
if (((_a = documentNode === null || documentNode === void 0 ? void 0 : documentNode.definitions) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
337
|
+
try {
|
338
|
+
const validationErrors = schema ? graphql.validate(schema, documentNode, rules) : validate.validateSDL(documentNode, null, rules);
|
339
|
+
for (const error of validationErrors) {
|
340
|
+
const validateRuleName = ruleName || `[${extractRuleName(error.stack)}]`;
|
341
|
+
context.report({
|
342
|
+
loc: getLocation({ start: error.locations[0] }),
|
343
|
+
message: ruleName ? error.message : `${validateRuleName} ${error.message}`,
|
344
|
+
});
|
345
|
+
}
|
346
|
+
}
|
347
|
+
catch (e) {
|
362
348
|
context.report({
|
363
|
-
|
364
|
-
message:
|
349
|
+
node: sourceNode,
|
350
|
+
message: e.message,
|
365
351
|
});
|
366
352
|
}
|
367
353
|
}
|
368
|
-
catch (e) {
|
369
|
-
context.report({
|
370
|
-
node: sourceNode,
|
371
|
-
message: e.message,
|
372
|
-
});
|
373
|
-
}
|
374
354
|
}
|
375
355
|
const isGraphQLImportFile = rawSDL => {
|
376
356
|
const trimmedRawSDL = rawSDL.trimLeft();
|
@@ -417,7 +397,7 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
417
397
|
if (isRealFile && getDocumentNode) {
|
418
398
|
documentNode = getDocumentNode(context);
|
419
399
|
}
|
420
|
-
validateDoc(node, context, schema, documentNode || node.rawNode(), [ruleFn]);
|
400
|
+
validateDoc(node, context, schema, documentNode || node.rawNode(), [ruleFn], ruleName);
|
421
401
|
},
|
422
402
|
};
|
423
403
|
},
|
@@ -1059,13 +1039,7 @@ const rule$2 = {
|
|
1059
1039
|
const MATCH_EXTENSION = 'MATCH_EXTENSION';
|
1060
1040
|
const MATCH_STYLE = 'MATCH_STYLE';
|
1061
1041
|
const ACCEPTED_EXTENSIONS = ['.gql', '.graphql'];
|
1062
|
-
const CASE_STYLES = [
|
1063
|
-
CaseStyle.camelCase,
|
1064
|
-
CaseStyle.pascalCase,
|
1065
|
-
CaseStyle.snakeCase,
|
1066
|
-
CaseStyle.upperCase,
|
1067
|
-
CaseStyle.kebabCase,
|
1068
|
-
];
|
1042
|
+
const CASE_STYLES = ['camelCase', 'PascalCase', 'snake_case', 'UPPER_CASE', 'kebab-case'];
|
1069
1043
|
const schemaOption = {
|
1070
1044
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1071
1045
|
};
|
@@ -1089,7 +1063,7 @@ const rule$3 = {
|
|
1089
1063
|
},
|
1090
1064
|
{
|
1091
1065
|
title: 'Correct',
|
1092
|
-
usage: [{ query:
|
1066
|
+
usage: [{ query: 'snake_case' }],
|
1093
1067
|
code: /* GraphQL */ `
|
1094
1068
|
# user_by_id.gql
|
1095
1069
|
query UserById {
|
@@ -1103,7 +1077,7 @@ const rule$3 = {
|
|
1103
1077
|
},
|
1104
1078
|
{
|
1105
1079
|
title: 'Correct',
|
1106
|
-
usage: [{ fragment: { style:
|
1080
|
+
usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
|
1107
1081
|
code: /* GraphQL */ `
|
1108
1082
|
# user-fields.fragment.gql
|
1109
1083
|
fragment user_fields on User {
|
@@ -1114,7 +1088,7 @@ const rule$3 = {
|
|
1114
1088
|
},
|
1115
1089
|
{
|
1116
1090
|
title: 'Correct',
|
1117
|
-
usage: [{ mutation: { style:
|
1091
|
+
usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
|
1118
1092
|
code: /* GraphQL */ `
|
1119
1093
|
# DeleteUserMutation.gql
|
1120
1094
|
mutation DELETE_USER {
|
@@ -1134,7 +1108,7 @@ const rule$3 = {
|
|
1134
1108
|
},
|
1135
1109
|
{
|
1136
1110
|
title: 'Incorrect',
|
1137
|
-
usage: [{ query:
|
1111
|
+
usage: [{ query: 'PascalCase' }],
|
1138
1112
|
code: /* GraphQL */ `
|
1139
1113
|
# user-by-id.gql
|
1140
1114
|
query UserById {
|
@@ -1149,10 +1123,10 @@ const rule$3 = {
|
|
1149
1123
|
],
|
1150
1124
|
configOptions: [
|
1151
1125
|
{
|
1152
|
-
query:
|
1153
|
-
mutation:
|
1154
|
-
subscription:
|
1155
|
-
fragment:
|
1126
|
+
query: 'kebab-case',
|
1127
|
+
mutation: 'kebab-case',
|
1128
|
+
subscription: 'kebab-case',
|
1129
|
+
fragment: 'kebab-case',
|
1156
1130
|
},
|
1157
1131
|
],
|
1158
1132
|
},
|
@@ -1169,25 +1143,22 @@ const rule$3 = {
|
|
1169
1143
|
asObject: {
|
1170
1144
|
type: 'object',
|
1171
1145
|
additionalProperties: false,
|
1146
|
+
minProperties: 1,
|
1172
1147
|
properties: {
|
1173
|
-
style: {
|
1174
|
-
|
1175
|
-
},
|
1176
|
-
suffix: {
|
1177
|
-
type: 'string',
|
1178
|
-
},
|
1148
|
+
style: { enum: CASE_STYLES },
|
1149
|
+
suffix: { type: 'string' },
|
1179
1150
|
},
|
1180
1151
|
},
|
1181
1152
|
},
|
1182
1153
|
type: 'array',
|
1154
|
+
minItems: 1,
|
1183
1155
|
maxItems: 1,
|
1184
1156
|
items: {
|
1185
1157
|
type: 'object',
|
1186
1158
|
additionalProperties: false,
|
1159
|
+
minProperties: 1,
|
1187
1160
|
properties: {
|
1188
|
-
fileExtension: {
|
1189
|
-
enum: ACCEPTED_EXTENSIONS,
|
1190
|
-
},
|
1161
|
+
fileExtension: { enum: ACCEPTED_EXTENSIONS },
|
1191
1162
|
query: schemaOption,
|
1192
1163
|
mutation: schemaOption,
|
1193
1164
|
subscription: schemaOption,
|
@@ -1242,7 +1213,7 @@ const rule$3 = {
|
|
1242
1213
|
option = { style: option };
|
1243
1214
|
}
|
1244
1215
|
const expectedExtension = options.fileExtension || fileExtension;
|
1245
|
-
const expectedFilename = convertCase(option.style, docName) + (option.suffix || '') + expectedExtension;
|
1216
|
+
const expectedFilename = (option.style ? convertCase(option.style, docName) : filename) + (option.suffix || '') + expectedExtension;
|
1246
1217
|
const filenameWithExtension = filename + expectedExtension;
|
1247
1218
|
if (expectedFilename !== filenameWithExtension) {
|
1248
1219
|
context.report({
|
@@ -1394,6 +1365,7 @@ const rule$4 = {
|
|
1394
1365
|
],
|
1395
1366
|
},
|
1396
1367
|
},
|
1368
|
+
hasSuggestions: true,
|
1397
1369
|
schema: {
|
1398
1370
|
definitions: {
|
1399
1371
|
asString: {
|
@@ -1468,65 +1440,90 @@ const rule$4 = {
|
|
1468
1440
|
const style = restOptions[kind] || types;
|
1469
1441
|
return typeof style === 'object' ? style : { style };
|
1470
1442
|
}
|
1471
|
-
const checkNode = (selector) => (
|
1472
|
-
const { name } =
|
1473
|
-
if (!
|
1443
|
+
const checkNode = (selector) => (n) => {
|
1444
|
+
const { name: node } = n.kind === graphql.Kind.VARIABLE_DEFINITION ? n.variable : n;
|
1445
|
+
if (!node) {
|
1474
1446
|
return;
|
1475
1447
|
}
|
1476
1448
|
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
|
1477
|
-
const nodeType = KindToDisplayName[
|
1478
|
-
const nodeName =
|
1479
|
-
const
|
1480
|
-
if (
|
1449
|
+
const nodeType = KindToDisplayName[n.kind] || n.kind;
|
1450
|
+
const nodeName = node.value;
|
1451
|
+
const error = getError();
|
1452
|
+
if (error) {
|
1453
|
+
const { errorMessage, renameToName } = error;
|
1454
|
+
const [leadingUnderscore] = nodeName.match(/^_*/);
|
1455
|
+
const [trailingUnderscore] = nodeName.match(/_*$/);
|
1456
|
+
const suggestedName = leadingUnderscore + renameToName + trailingUnderscore;
|
1481
1457
|
context.report({
|
1482
|
-
loc: getLocation(
|
1458
|
+
loc: getLocation(node.loc, node.value),
|
1483
1459
|
message: `${nodeType} "${nodeName}" should ${errorMessage}`,
|
1460
|
+
suggest: [
|
1461
|
+
{
|
1462
|
+
desc: `Rename to "${suggestedName}"`,
|
1463
|
+
fix: fixer => fixer.replaceText(node, suggestedName),
|
1464
|
+
},
|
1465
|
+
],
|
1484
1466
|
});
|
1485
1467
|
}
|
1486
|
-
function
|
1487
|
-
|
1488
|
-
if (allowLeadingUnderscore) {
|
1489
|
-
name = name.replace(/^_*/, '');
|
1490
|
-
}
|
1491
|
-
if (allowTrailingUnderscore) {
|
1492
|
-
name = name.replace(/_*$/, '');
|
1493
|
-
}
|
1468
|
+
function getError() {
|
1469
|
+
const name = nodeName.replace(/(^_+)|(_+$)/g, '');
|
1494
1470
|
if (prefix && !name.startsWith(prefix)) {
|
1495
|
-
return
|
1471
|
+
return {
|
1472
|
+
errorMessage: `have "${prefix}" prefix`,
|
1473
|
+
renameToName: prefix + name,
|
1474
|
+
};
|
1496
1475
|
}
|
1497
1476
|
if (suffix && !name.endsWith(suffix)) {
|
1498
|
-
return
|
1477
|
+
return {
|
1478
|
+
errorMessage: `have "${suffix}" suffix`,
|
1479
|
+
renameToName: name + suffix,
|
1480
|
+
};
|
1499
1481
|
}
|
1500
1482
|
const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
|
1501
1483
|
if (forbiddenPrefix) {
|
1502
|
-
return
|
1484
|
+
return {
|
1485
|
+
errorMessage: `not have "${forbiddenPrefix}" prefix`,
|
1486
|
+
renameToName: name.replace(new RegExp(`^${forbiddenPrefix}`), ''),
|
1487
|
+
};
|
1503
1488
|
}
|
1504
1489
|
const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
|
1505
1490
|
if (forbiddenSuffix) {
|
1506
|
-
return
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1491
|
+
return {
|
1492
|
+
errorMessage: `not have "${forbiddenSuffix}" suffix`,
|
1493
|
+
renameToName: name.replace(new RegExp(`${forbiddenSuffix}$`), ''),
|
1494
|
+
};
|
1510
1495
|
}
|
1511
1496
|
const caseRegex = StyleToRegex[style];
|
1512
1497
|
if (caseRegex && !caseRegex.test(name)) {
|
1513
|
-
return
|
1498
|
+
return {
|
1499
|
+
errorMessage: `be in ${style} format`,
|
1500
|
+
renameToName: convertCase(style, name),
|
1501
|
+
};
|
1514
1502
|
}
|
1515
1503
|
}
|
1516
1504
|
};
|
1517
|
-
const checkUnderscore = (node) => {
|
1505
|
+
const checkUnderscore = (isLeading) => (node) => {
|
1518
1506
|
const name = node.value;
|
1507
|
+
const renameToName = name.replace(new RegExp(isLeading ? '^_+' : '_+$'), '');
|
1519
1508
|
context.report({
|
1520
1509
|
loc: getLocation(node.loc, name),
|
1521
|
-
message: `${
|
1510
|
+
message: `${isLeading ? 'Leading' : 'Trailing'} underscores are not allowed`,
|
1511
|
+
suggest: [
|
1512
|
+
{
|
1513
|
+
desc: `Rename to "${renameToName}"`,
|
1514
|
+
fix: fixer => fixer.replaceText(node, renameToName),
|
1515
|
+
},
|
1516
|
+
],
|
1522
1517
|
});
|
1523
1518
|
};
|
1524
1519
|
const listeners = {};
|
1525
1520
|
if (!allowLeadingUnderscore) {
|
1526
|
-
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1521
|
+
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1522
|
+
checkUnderscore(true);
|
1527
1523
|
}
|
1528
1524
|
if (!allowTrailingUnderscore) {
|
1529
|
-
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1525
|
+
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1526
|
+
checkUnderscore(false);
|
1530
1527
|
}
|
1531
1528
|
const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1532
1529
|
for (const selector of selectors) {
|
package/index.mjs
CHANGED
@@ -280,14 +280,6 @@ const TYPES_KINDS = [
|
|
280
280
|
Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
281
281
|
Kind.UNION_TYPE_DEFINITION,
|
282
282
|
];
|
283
|
-
var CaseStyle;
|
284
|
-
(function (CaseStyle) {
|
285
|
-
CaseStyle["camelCase"] = "camelCase";
|
286
|
-
CaseStyle["pascalCase"] = "PascalCase";
|
287
|
-
CaseStyle["snakeCase"] = "snake_case";
|
288
|
-
CaseStyle["upperCase"] = "UPPER_CASE";
|
289
|
-
CaseStyle["kebabCase"] = "kebab-case";
|
290
|
-
})(CaseStyle || (CaseStyle = {}));
|
291
283
|
const pascalCase = (str) => lowerCase(str)
|
292
284
|
.split(' ')
|
293
285
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
@@ -298,15 +290,15 @@ const camelCase = (str) => {
|
|
298
290
|
};
|
299
291
|
const convertCase = (style, str) => {
|
300
292
|
switch (style) {
|
301
|
-
case
|
293
|
+
case 'camelCase':
|
302
294
|
return camelCase(str);
|
303
|
-
case
|
295
|
+
case 'PascalCase':
|
304
296
|
return pascalCase(str);
|
305
|
-
case
|
297
|
+
case 'snake_case':
|
306
298
|
return lowerCase(str).replace(/ /g, '_');
|
307
|
-
case
|
299
|
+
case 'UPPER_CASE':
|
308
300
|
return lowerCase(str).replace(/ /g, '_').toUpperCase();
|
309
|
-
case
|
301
|
+
case 'kebab-case':
|
310
302
|
return lowerCase(str).replace(/ /g, '-');
|
311
303
|
}
|
312
304
|
};
|
@@ -329,42 +321,30 @@ function getLocation(loc, fieldName = '', offset) {
|
|
329
321
|
};
|
330
322
|
}
|
331
323
|
|
332
|
-
function
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
* }
|
351
|
-
* }
|
352
|
-
*/
|
353
|
-
const { line, column } = error.locations[0];
|
354
|
-
const ancestors = context.getAncestors();
|
355
|
-
const token = ancestors[0].tokens.find(token => token.loc.start.line === line && token.loc.start.column === column);
|
324
|
+
function extractRuleName(stack) {
|
325
|
+
const match = (stack || '').match(/validation[/\\]rules[/\\](.*?)\.js:/) || [];
|
326
|
+
return match[1] || null;
|
327
|
+
}
|
328
|
+
function validateDoc(sourceNode, context, schema, documentNode, rules, ruleName = null) {
|
329
|
+
var _a;
|
330
|
+
if (((_a = documentNode === null || documentNode === void 0 ? void 0 : documentNode.definitions) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
331
|
+
try {
|
332
|
+
const validationErrors = schema ? validate(schema, documentNode, rules) : validateSDL(documentNode, null, rules);
|
333
|
+
for (const error of validationErrors) {
|
334
|
+
const validateRuleName = ruleName || `[${extractRuleName(error.stack)}]`;
|
335
|
+
context.report({
|
336
|
+
loc: getLocation({ start: error.locations[0] }),
|
337
|
+
message: ruleName ? error.message : `${validateRuleName} ${error.message}`,
|
338
|
+
});
|
339
|
+
}
|
340
|
+
}
|
341
|
+
catch (e) {
|
356
342
|
context.report({
|
357
|
-
|
358
|
-
message:
|
343
|
+
node: sourceNode,
|
344
|
+
message: e.message,
|
359
345
|
});
|
360
346
|
}
|
361
347
|
}
|
362
|
-
catch (e) {
|
363
|
-
context.report({
|
364
|
-
node: sourceNode,
|
365
|
-
message: e.message,
|
366
|
-
});
|
367
|
-
}
|
368
348
|
}
|
369
349
|
const isGraphQLImportFile = rawSDL => {
|
370
350
|
const trimmedRawSDL = rawSDL.trimLeft();
|
@@ -411,7 +391,7 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
411
391
|
if (isRealFile && getDocumentNode) {
|
412
392
|
documentNode = getDocumentNode(context);
|
413
393
|
}
|
414
|
-
validateDoc(node, context, schema, documentNode || node.rawNode(), [ruleFn]);
|
394
|
+
validateDoc(node, context, schema, documentNode || node.rawNode(), [ruleFn], ruleName);
|
415
395
|
},
|
416
396
|
};
|
417
397
|
},
|
@@ -1053,13 +1033,7 @@ const rule$2 = {
|
|
1053
1033
|
const MATCH_EXTENSION = 'MATCH_EXTENSION';
|
1054
1034
|
const MATCH_STYLE = 'MATCH_STYLE';
|
1055
1035
|
const ACCEPTED_EXTENSIONS = ['.gql', '.graphql'];
|
1056
|
-
const CASE_STYLES = [
|
1057
|
-
CaseStyle.camelCase,
|
1058
|
-
CaseStyle.pascalCase,
|
1059
|
-
CaseStyle.snakeCase,
|
1060
|
-
CaseStyle.upperCase,
|
1061
|
-
CaseStyle.kebabCase,
|
1062
|
-
];
|
1036
|
+
const CASE_STYLES = ['camelCase', 'PascalCase', 'snake_case', 'UPPER_CASE', 'kebab-case'];
|
1063
1037
|
const schemaOption = {
|
1064
1038
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1065
1039
|
};
|
@@ -1083,7 +1057,7 @@ const rule$3 = {
|
|
1083
1057
|
},
|
1084
1058
|
{
|
1085
1059
|
title: 'Correct',
|
1086
|
-
usage: [{ query:
|
1060
|
+
usage: [{ query: 'snake_case' }],
|
1087
1061
|
code: /* GraphQL */ `
|
1088
1062
|
# user_by_id.gql
|
1089
1063
|
query UserById {
|
@@ -1097,7 +1071,7 @@ const rule$3 = {
|
|
1097
1071
|
},
|
1098
1072
|
{
|
1099
1073
|
title: 'Correct',
|
1100
|
-
usage: [{ fragment: { style:
|
1074
|
+
usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
|
1101
1075
|
code: /* GraphQL */ `
|
1102
1076
|
# user-fields.fragment.gql
|
1103
1077
|
fragment user_fields on User {
|
@@ -1108,7 +1082,7 @@ const rule$3 = {
|
|
1108
1082
|
},
|
1109
1083
|
{
|
1110
1084
|
title: 'Correct',
|
1111
|
-
usage: [{ mutation: { style:
|
1085
|
+
usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
|
1112
1086
|
code: /* GraphQL */ `
|
1113
1087
|
# DeleteUserMutation.gql
|
1114
1088
|
mutation DELETE_USER {
|
@@ -1128,7 +1102,7 @@ const rule$3 = {
|
|
1128
1102
|
},
|
1129
1103
|
{
|
1130
1104
|
title: 'Incorrect',
|
1131
|
-
usage: [{ query:
|
1105
|
+
usage: [{ query: 'PascalCase' }],
|
1132
1106
|
code: /* GraphQL */ `
|
1133
1107
|
# user-by-id.gql
|
1134
1108
|
query UserById {
|
@@ -1143,10 +1117,10 @@ const rule$3 = {
|
|
1143
1117
|
],
|
1144
1118
|
configOptions: [
|
1145
1119
|
{
|
1146
|
-
query:
|
1147
|
-
mutation:
|
1148
|
-
subscription:
|
1149
|
-
fragment:
|
1120
|
+
query: 'kebab-case',
|
1121
|
+
mutation: 'kebab-case',
|
1122
|
+
subscription: 'kebab-case',
|
1123
|
+
fragment: 'kebab-case',
|
1150
1124
|
},
|
1151
1125
|
],
|
1152
1126
|
},
|
@@ -1163,25 +1137,22 @@ const rule$3 = {
|
|
1163
1137
|
asObject: {
|
1164
1138
|
type: 'object',
|
1165
1139
|
additionalProperties: false,
|
1140
|
+
minProperties: 1,
|
1166
1141
|
properties: {
|
1167
|
-
style: {
|
1168
|
-
|
1169
|
-
},
|
1170
|
-
suffix: {
|
1171
|
-
type: 'string',
|
1172
|
-
},
|
1142
|
+
style: { enum: CASE_STYLES },
|
1143
|
+
suffix: { type: 'string' },
|
1173
1144
|
},
|
1174
1145
|
},
|
1175
1146
|
},
|
1176
1147
|
type: 'array',
|
1148
|
+
minItems: 1,
|
1177
1149
|
maxItems: 1,
|
1178
1150
|
items: {
|
1179
1151
|
type: 'object',
|
1180
1152
|
additionalProperties: false,
|
1153
|
+
minProperties: 1,
|
1181
1154
|
properties: {
|
1182
|
-
fileExtension: {
|
1183
|
-
enum: ACCEPTED_EXTENSIONS,
|
1184
|
-
},
|
1155
|
+
fileExtension: { enum: ACCEPTED_EXTENSIONS },
|
1185
1156
|
query: schemaOption,
|
1186
1157
|
mutation: schemaOption,
|
1187
1158
|
subscription: schemaOption,
|
@@ -1236,7 +1207,7 @@ const rule$3 = {
|
|
1236
1207
|
option = { style: option };
|
1237
1208
|
}
|
1238
1209
|
const expectedExtension = options.fileExtension || fileExtension;
|
1239
|
-
const expectedFilename = convertCase(option.style, docName) + (option.suffix || '') + expectedExtension;
|
1210
|
+
const expectedFilename = (option.style ? convertCase(option.style, docName) : filename) + (option.suffix || '') + expectedExtension;
|
1240
1211
|
const filenameWithExtension = filename + expectedExtension;
|
1241
1212
|
if (expectedFilename !== filenameWithExtension) {
|
1242
1213
|
context.report({
|
@@ -1388,6 +1359,7 @@ const rule$4 = {
|
|
1388
1359
|
],
|
1389
1360
|
},
|
1390
1361
|
},
|
1362
|
+
hasSuggestions: true,
|
1391
1363
|
schema: {
|
1392
1364
|
definitions: {
|
1393
1365
|
asString: {
|
@@ -1462,65 +1434,90 @@ const rule$4 = {
|
|
1462
1434
|
const style = restOptions[kind] || types;
|
1463
1435
|
return typeof style === 'object' ? style : { style };
|
1464
1436
|
}
|
1465
|
-
const checkNode = (selector) => (
|
1466
|
-
const { name } =
|
1467
|
-
if (!
|
1437
|
+
const checkNode = (selector) => (n) => {
|
1438
|
+
const { name: node } = n.kind === Kind.VARIABLE_DEFINITION ? n.variable : n;
|
1439
|
+
if (!node) {
|
1468
1440
|
return;
|
1469
1441
|
}
|
1470
1442
|
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
|
1471
|
-
const nodeType = KindToDisplayName[
|
1472
|
-
const nodeName =
|
1473
|
-
const
|
1474
|
-
if (
|
1443
|
+
const nodeType = KindToDisplayName[n.kind] || n.kind;
|
1444
|
+
const nodeName = node.value;
|
1445
|
+
const error = getError();
|
1446
|
+
if (error) {
|
1447
|
+
const { errorMessage, renameToName } = error;
|
1448
|
+
const [leadingUnderscore] = nodeName.match(/^_*/);
|
1449
|
+
const [trailingUnderscore] = nodeName.match(/_*$/);
|
1450
|
+
const suggestedName = leadingUnderscore + renameToName + trailingUnderscore;
|
1475
1451
|
context.report({
|
1476
|
-
loc: getLocation(
|
1452
|
+
loc: getLocation(node.loc, node.value),
|
1477
1453
|
message: `${nodeType} "${nodeName}" should ${errorMessage}`,
|
1454
|
+
suggest: [
|
1455
|
+
{
|
1456
|
+
desc: `Rename to "${suggestedName}"`,
|
1457
|
+
fix: fixer => fixer.replaceText(node, suggestedName),
|
1458
|
+
},
|
1459
|
+
],
|
1478
1460
|
});
|
1479
1461
|
}
|
1480
|
-
function
|
1481
|
-
|
1482
|
-
if (allowLeadingUnderscore) {
|
1483
|
-
name = name.replace(/^_*/, '');
|
1484
|
-
}
|
1485
|
-
if (allowTrailingUnderscore) {
|
1486
|
-
name = name.replace(/_*$/, '');
|
1487
|
-
}
|
1462
|
+
function getError() {
|
1463
|
+
const name = nodeName.replace(/(^_+)|(_+$)/g, '');
|
1488
1464
|
if (prefix && !name.startsWith(prefix)) {
|
1489
|
-
return
|
1465
|
+
return {
|
1466
|
+
errorMessage: `have "${prefix}" prefix`,
|
1467
|
+
renameToName: prefix + name,
|
1468
|
+
};
|
1490
1469
|
}
|
1491
1470
|
if (suffix && !name.endsWith(suffix)) {
|
1492
|
-
return
|
1471
|
+
return {
|
1472
|
+
errorMessage: `have "${suffix}" suffix`,
|
1473
|
+
renameToName: name + suffix,
|
1474
|
+
};
|
1493
1475
|
}
|
1494
1476
|
const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
|
1495
1477
|
if (forbiddenPrefix) {
|
1496
|
-
return
|
1478
|
+
return {
|
1479
|
+
errorMessage: `not have "${forbiddenPrefix}" prefix`,
|
1480
|
+
renameToName: name.replace(new RegExp(`^${forbiddenPrefix}`), ''),
|
1481
|
+
};
|
1497
1482
|
}
|
1498
1483
|
const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
|
1499
1484
|
if (forbiddenSuffix) {
|
1500
|
-
return
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1485
|
+
return {
|
1486
|
+
errorMessage: `not have "${forbiddenSuffix}" suffix`,
|
1487
|
+
renameToName: name.replace(new RegExp(`${forbiddenSuffix}$`), ''),
|
1488
|
+
};
|
1504
1489
|
}
|
1505
1490
|
const caseRegex = StyleToRegex[style];
|
1506
1491
|
if (caseRegex && !caseRegex.test(name)) {
|
1507
|
-
return
|
1492
|
+
return {
|
1493
|
+
errorMessage: `be in ${style} format`,
|
1494
|
+
renameToName: convertCase(style, name),
|
1495
|
+
};
|
1508
1496
|
}
|
1509
1497
|
}
|
1510
1498
|
};
|
1511
|
-
const checkUnderscore = (node) => {
|
1499
|
+
const checkUnderscore = (isLeading) => (node) => {
|
1512
1500
|
const name = node.value;
|
1501
|
+
const renameToName = name.replace(new RegExp(isLeading ? '^_+' : '_+$'), '');
|
1513
1502
|
context.report({
|
1514
1503
|
loc: getLocation(node.loc, name),
|
1515
|
-
message: `${
|
1504
|
+
message: `${isLeading ? 'Leading' : 'Trailing'} underscores are not allowed`,
|
1505
|
+
suggest: [
|
1506
|
+
{
|
1507
|
+
desc: `Rename to "${renameToName}"`,
|
1508
|
+
fix: fixer => fixer.replaceText(node, renameToName),
|
1509
|
+
},
|
1510
|
+
],
|
1516
1511
|
});
|
1517
1512
|
};
|
1518
1513
|
const listeners = {};
|
1519
1514
|
if (!allowLeadingUnderscore) {
|
1520
|
-
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1515
|
+
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1516
|
+
checkUnderscore(true);
|
1521
1517
|
}
|
1522
1518
|
if (!allowTrailingUnderscore) {
|
1523
|
-
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1519
|
+
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
|
1520
|
+
checkUnderscore(false);
|
1524
1521
|
}
|
1525
1522
|
const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
|
1526
1523
|
for (const selector of selectors) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@graphql-eslint/eslint-plugin",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.2.0-alpha-001cd75.0",
|
4
4
|
"sideEffects": false,
|
5
5
|
"peerDependencies": {
|
6
6
|
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { GraphQLSchema, DocumentNode, ASTNode, ValidationRule } from 'graphql';
|
2
2
|
import { GraphQLESLintRule, GraphQLESLintRuleContext } from '../types';
|
3
3
|
import { GraphQLESTreeNode } from '../estree-parser';
|
4
|
-
export declare function validateDoc(sourceNode: GraphQLESTreeNode<ASTNode>, context: GraphQLESLintRuleContext, schema: GraphQLSchema | null, documentNode: DocumentNode, rules: ReadonlyArray<ValidationRule
|
4
|
+
export declare function validateDoc(sourceNode: GraphQLESTreeNode<ASTNode>, context: GraphQLESLintRuleContext, schema: GraphQLSchema | null, documentNode: DocumentNode, rules: ReadonlyArray<ValidationRule>, ruleName?: string | null): void;
|
5
5
|
export declare const GRAPHQL_JS_VALIDATIONS: Record<string, GraphQLESLintRule<any[], false>>;
|
package/rules/index.d.ts
CHANGED
@@ -15,135 +15,8 @@ export declare const rules: {
|
|
15
15
|
checkQueries?: boolean;
|
16
16
|
checkMutations?: boolean;
|
17
17
|
}], false>;
|
18
|
-
'match-document-filename': import("..").GraphQLESLintRule<[
|
19
|
-
|
20
|
-
query?: import("../utils").CaseStyle | {
|
21
|
-
style: import("../utils").CaseStyle;
|
22
|
-
suffix: string;
|
23
|
-
};
|
24
|
-
mutation?: import("../utils").CaseStyle | {
|
25
|
-
style: import("../utils").CaseStyle;
|
26
|
-
suffix: string;
|
27
|
-
};
|
28
|
-
subscription?: import("../utils").CaseStyle | {
|
29
|
-
style: import("../utils").CaseStyle;
|
30
|
-
suffix: string;
|
31
|
-
};
|
32
|
-
fragment?: import("../utils").CaseStyle | {
|
33
|
-
style: import("../utils").CaseStyle;
|
34
|
-
suffix: string;
|
35
|
-
};
|
36
|
-
}], false>;
|
37
|
-
'naming-convention': import("..").GraphQLESLintRule<[{
|
38
|
-
allowLeadingUnderscore?: boolean;
|
39
|
-
allowTrailingUnderscore?: boolean;
|
40
|
-
types?: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
41
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
42
|
-
suffix?: string;
|
43
|
-
prefix?: string;
|
44
|
-
forbiddenPrefixes?: string[];
|
45
|
-
forbiddenSuffixes?: string[];
|
46
|
-
};
|
47
|
-
} & {
|
48
|
-
[x: `OperationDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
49
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
50
|
-
suffix?: string;
|
51
|
-
prefix?: string;
|
52
|
-
forbiddenPrefixes?: string[];
|
53
|
-
forbiddenSuffixes?: string[];
|
54
|
-
};
|
55
|
-
[x: `VariableDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
56
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
57
|
-
suffix?: string;
|
58
|
-
prefix?: string;
|
59
|
-
forbiddenPrefixes?: string[];
|
60
|
-
forbiddenSuffixes?: string[];
|
61
|
-
};
|
62
|
-
[x: `Argument${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
63
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
64
|
-
suffix?: string;
|
65
|
-
prefix?: string;
|
66
|
-
forbiddenPrefixes?: string[];
|
67
|
-
forbiddenSuffixes?: string[];
|
68
|
-
};
|
69
|
-
[x: `FragmentDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
70
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
71
|
-
suffix?: string;
|
72
|
-
prefix?: string;
|
73
|
-
forbiddenPrefixes?: string[];
|
74
|
-
forbiddenSuffixes?: string[];
|
75
|
-
};
|
76
|
-
[x: `ScalarTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
77
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
78
|
-
suffix?: string;
|
79
|
-
prefix?: string;
|
80
|
-
forbiddenPrefixes?: string[];
|
81
|
-
forbiddenSuffixes?: string[];
|
82
|
-
};
|
83
|
-
[x: `ObjectTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
84
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
85
|
-
suffix?: string;
|
86
|
-
prefix?: string;
|
87
|
-
forbiddenPrefixes?: string[];
|
88
|
-
forbiddenSuffixes?: string[];
|
89
|
-
};
|
90
|
-
[x: `FieldDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
91
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
92
|
-
suffix?: string;
|
93
|
-
prefix?: string;
|
94
|
-
forbiddenPrefixes?: string[];
|
95
|
-
forbiddenSuffixes?: string[];
|
96
|
-
};
|
97
|
-
[x: `InputValueDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
98
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
99
|
-
suffix?: string;
|
100
|
-
prefix?: string;
|
101
|
-
forbiddenPrefixes?: string[];
|
102
|
-
forbiddenSuffixes?: string[];
|
103
|
-
};
|
104
|
-
[x: `InterfaceTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
105
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
106
|
-
suffix?: string;
|
107
|
-
prefix?: string;
|
108
|
-
forbiddenPrefixes?: string[];
|
109
|
-
forbiddenSuffixes?: string[];
|
110
|
-
};
|
111
|
-
[x: `UnionTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
112
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
113
|
-
suffix?: string;
|
114
|
-
prefix?: string;
|
115
|
-
forbiddenPrefixes?: string[];
|
116
|
-
forbiddenSuffixes?: string[];
|
117
|
-
};
|
118
|
-
[x: `EnumTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
119
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
120
|
-
suffix?: string;
|
121
|
-
prefix?: string;
|
122
|
-
forbiddenPrefixes?: string[];
|
123
|
-
forbiddenSuffixes?: string[];
|
124
|
-
};
|
125
|
-
[x: `EnumValueDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
126
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
127
|
-
suffix?: string;
|
128
|
-
prefix?: string;
|
129
|
-
forbiddenPrefixes?: string[];
|
130
|
-
forbiddenSuffixes?: string[];
|
131
|
-
};
|
132
|
-
[x: `InputObjectTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
133
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
134
|
-
suffix?: string;
|
135
|
-
prefix?: string;
|
136
|
-
forbiddenPrefixes?: string[];
|
137
|
-
forbiddenSuffixes?: string[];
|
138
|
-
};
|
139
|
-
[x: `DirectiveDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
|
140
|
-
style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
|
141
|
-
suffix?: string;
|
142
|
-
prefix?: string;
|
143
|
-
forbiddenPrefixes?: string[];
|
144
|
-
forbiddenSuffixes?: string[];
|
145
|
-
};
|
146
|
-
}], false>;
|
18
|
+
'match-document-filename': import("..").GraphQLESLintRule<[import("./match-document-filename").MatchDocumentFilenameRuleConfig], false>;
|
19
|
+
'naming-convention': import("..").GraphQLESLintRule<[import("./naming-convention").NamingConventionRuleConfig], false>;
|
147
20
|
'no-anonymous-operations': import("..").GraphQLESLintRule<any[], false>;
|
148
21
|
'no-case-insensitive-enum-values-duplicates': import("..").GraphQLESLintRule<any[], false>;
|
149
22
|
'no-deprecated': import("..").GraphQLESLintRule<[], true>;
|
@@ -2,10 +2,10 @@ import { CaseStyle } from '../utils';
|
|
2
2
|
import { GraphQLESLintRule } from '../types';
|
3
3
|
declare const ACCEPTED_EXTENSIONS: ['.gql', '.graphql'];
|
4
4
|
declare type PropertySchema = {
|
5
|
-
style
|
6
|
-
suffix
|
5
|
+
style?: CaseStyle;
|
6
|
+
suffix?: string;
|
7
7
|
};
|
8
|
-
declare type MatchDocumentFilenameRuleConfig = {
|
8
|
+
export declare type MatchDocumentFilenameRuleConfig = {
|
9
9
|
fileExtension?: typeof ACCEPTED_EXTENSIONS[number];
|
10
10
|
query?: CaseStyle | PropertySchema;
|
11
11
|
mutation?: CaseStyle | PropertySchema;
|
@@ -25,7 +25,7 @@ declare type PropertySchema = {
|
|
25
25
|
forbiddenSuffixes?: string[];
|
26
26
|
};
|
27
27
|
declare type Options = AllowedStyle | PropertySchema;
|
28
|
-
declare type NamingConventionRuleConfig = {
|
28
|
+
export declare type NamingConventionRuleConfig = {
|
29
29
|
allowLeadingUnderscore?: boolean;
|
30
30
|
allowTrailingUnderscore?: boolean;
|
31
31
|
types?: Options;
|
package/utils.d.ts
CHANGED
@@ -20,13 +20,7 @@ export declare const getOnDiskFilepath: (filepath: string) => string;
|
|
20
20
|
export declare const getTypeName: (node: any) => any;
|
21
21
|
export declare const loaderCache: Record<string, LoaderSource[]>;
|
22
22
|
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];
|
23
|
-
export declare
|
24
|
-
camelCase = "camelCase",
|
25
|
-
pascalCase = "PascalCase",
|
26
|
-
snakeCase = "snake_case",
|
27
|
-
upperCase = "UPPER_CASE",
|
28
|
-
kebabCase = "kebab-case"
|
29
|
-
}
|
23
|
+
export declare type CaseStyle = 'camelCase' | 'PascalCase' | 'snake_case' | 'UPPER_CASE' | 'kebab-case';
|
30
24
|
export declare const camelCase: (str: string) => string;
|
31
25
|
export declare const convertCase: (style: CaseStyle, str: string) => string;
|
32
26
|
export declare function getLocation(loc: Partial<AST.SourceLocation>, fieldName?: string, offset?: {
|