@graphql-eslint/eslint-plugin 2.4.0-alpha-0a1c477.0 → 3.0.0-alpha-5388f29.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/configs/all.d.ts +29 -1
- package/configs/index.d.ts +58 -2
- package/configs/recommended.d.ts +29 -1
- package/docs/rules/alphabetize.md +35 -10
- package/docs/rules/description-style.md +2 -2
- package/docs/rules/match-document-filename.md +7 -7
- package/docs/rules/naming-convention.md +54 -83
- package/docs/rules/no-deprecated.md +2 -2
- package/docs/rules/strict-id-in-types.md +4 -4
- package/estree-parser/converter.d.ts +3 -2
- package/index.js +256 -261
- package/index.mjs +256 -261
- package/package.json +1 -1
- package/rules/alphabetize.d.ts +5 -6
- package/rules/index.d.ts +122 -20
- package/rules/naming-convention.d.ts +32 -25
- package/rules/require-description.d.ts +1 -2
- package/testkit.d.ts +1 -1
- package/utils.d.ts +2 -7
package/index.js
CHANGED
@@ -35,7 +35,34 @@ const recommendedConfig = {
|
|
35
35
|
'@graphql-eslint/known-type-names': 'error',
|
36
36
|
'@graphql-eslint/lone-anonymous-operation': 'error',
|
37
37
|
'@graphql-eslint/lone-schema-definition': 'error',
|
38
|
-
'@graphql-eslint/naming-convention':
|
38
|
+
'@graphql-eslint/naming-convention': [
|
39
|
+
'error',
|
40
|
+
{
|
41
|
+
types: 'PascalCase',
|
42
|
+
fields: 'camelCase',
|
43
|
+
overrides: {
|
44
|
+
EnumValueDefinition: 'UPPER_CASE',
|
45
|
+
OperationDefinition: {
|
46
|
+
style: 'PascalCase',
|
47
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
48
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
49
|
+
},
|
50
|
+
FragmentDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Fragment'], forbiddenSuffixes: ['Fragment'] },
|
51
|
+
'FieldDefinition[parent.name.value=Query]': {
|
52
|
+
forbiddenPrefixes: ['query', 'get'],
|
53
|
+
forbiddenSuffixes: ['Query'],
|
54
|
+
},
|
55
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
56
|
+
forbiddenPrefixes: ['mutation'],
|
57
|
+
forbiddenSuffixes: ['Mutation'],
|
58
|
+
},
|
59
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
60
|
+
forbiddenPrefixes: ['subscription'],
|
61
|
+
forbiddenSuffixes: ['Subscription'],
|
62
|
+
},
|
63
|
+
},
|
64
|
+
},
|
65
|
+
],
|
39
66
|
'@graphql-eslint/no-anonymous-operations': 'error',
|
40
67
|
'@graphql-eslint/no-case-insensitive-enum-values-duplicates': 'error',
|
41
68
|
'@graphql-eslint/no-fragment-cycles': 'error',
|
@@ -211,9 +238,14 @@ const loaderCache = new Proxy(Object.create(null), {
|
|
211
238
|
return true;
|
212
239
|
},
|
213
240
|
});
|
214
|
-
const
|
215
|
-
|
216
|
-
|
241
|
+
const TYPES_KINDS = [
|
242
|
+
graphql.Kind.OBJECT_TYPE_DEFINITION,
|
243
|
+
graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
244
|
+
graphql.Kind.ENUM_TYPE_DEFINITION,
|
245
|
+
graphql.Kind.SCALAR_TYPE_DEFINITION,
|
246
|
+
graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
247
|
+
graphql.Kind.UNION_TYPE_DEFINITION,
|
248
|
+
];
|
217
249
|
var CaseStyle;
|
218
250
|
(function (CaseStyle) {
|
219
251
|
CaseStyle["camelCase"] = "camelCase";
|
@@ -264,7 +296,7 @@ function getLocation(loc, fieldName = '', offset) {
|
|
264
296
|
}
|
265
297
|
|
266
298
|
function extractRuleName(stack) {
|
267
|
-
const match = (stack || '').match(/validation[
|
299
|
+
const match = (stack || '').match(/validation[/\\]rules[/\\](.*?)\.js:/) || [];
|
268
300
|
return match[1] || null;
|
269
301
|
}
|
270
302
|
function validateDoc(sourceNode, context, schema, documentNode, rules, ruleName = null) {
|
@@ -625,38 +657,48 @@ const rule = {
|
|
625
657
|
properties: {
|
626
658
|
fields: {
|
627
659
|
type: 'array',
|
628
|
-
|
660
|
+
uniqueItems: true,
|
661
|
+
minItems: 1,
|
662
|
+
items: {
|
629
663
|
enum: fieldsEnum,
|
630
664
|
},
|
631
|
-
description: 'Fields of `type`, `interface`, and `input
|
665
|
+
description: 'Fields of `type`, `interface`, and `input`',
|
632
666
|
},
|
633
667
|
values: {
|
634
668
|
type: 'array',
|
635
|
-
|
669
|
+
uniqueItems: true,
|
670
|
+
minItems: 1,
|
671
|
+
items: {
|
636
672
|
enum: valuesEnum,
|
637
673
|
},
|
638
|
-
description: 'Values of `enum
|
674
|
+
description: 'Values of `enum`',
|
639
675
|
},
|
640
676
|
selections: {
|
641
677
|
type: 'array',
|
642
|
-
|
678
|
+
uniqueItems: true,
|
679
|
+
minItems: 1,
|
680
|
+
items: {
|
643
681
|
enum: selectionsEnum,
|
644
682
|
},
|
645
|
-
description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment
|
683
|
+
description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment`',
|
646
684
|
},
|
647
685
|
variables: {
|
648
686
|
type: 'array',
|
649
|
-
|
687
|
+
uniqueItems: true,
|
688
|
+
minItems: 1,
|
689
|
+
items: {
|
650
690
|
enum: variablesEnum,
|
651
691
|
},
|
652
|
-
description: 'Variables of operations (`query`, `mutation` and `subscription`)
|
692
|
+
description: 'Variables of operations (`query`, `mutation` and `subscription`)',
|
653
693
|
},
|
654
694
|
arguments: {
|
655
695
|
type: 'array',
|
656
|
-
|
696
|
+
uniqueItems: true,
|
697
|
+
minItems: 1,
|
698
|
+
items: {
|
657
699
|
enum: argumentsEnum,
|
658
700
|
},
|
659
|
-
description: 'Arguments of fields and directives
|
701
|
+
description: 'Arguments of fields and directives',
|
660
702
|
},
|
661
703
|
},
|
662
704
|
},
|
@@ -687,7 +729,7 @@ const rule = {
|
|
687
729
|
const opts = context.options[0];
|
688
730
|
const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
|
689
731
|
const listeners = {};
|
690
|
-
const
|
732
|
+
const kinds = [
|
691
733
|
fields.has(graphql.Kind.OBJECT_TYPE_DEFINITION) && [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION],
|
692
734
|
fields.has(graphql.Kind.INTERFACE_TYPE_DEFINITION) && [graphql.Kind.INTERFACE_TYPE_DEFINITION, graphql.Kind.INTERFACE_TYPE_EXTENSION],
|
693
735
|
fields.has(graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
|
@@ -695,8 +737,9 @@ const rule = {
|
|
695
737
|
graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION,
|
696
738
|
],
|
697
739
|
]
|
698
|
-
.
|
699
|
-
.
|
740
|
+
.filter(Boolean)
|
741
|
+
.flat();
|
742
|
+
const fieldsSelector = kinds.join(',');
|
700
743
|
const hasEnumValues = ((_b = opts.values) === null || _b === void 0 ? void 0 : _b[0]) === graphql.Kind.ENUM_TYPE_DEFINITION;
|
701
744
|
const selectionsSelector = (_c = opts.selections) === null || _c === void 0 ? void 0 : _c.join(',');
|
702
745
|
const hasVariables = ((_d = opts.variables) === null || _d === void 0 ? void 0 : _d[0]) === graphql.Kind.OPERATION_DEFINITION;
|
@@ -1096,6 +1139,9 @@ const rule$5 = {
|
|
1096
1139
|
},
|
1097
1140
|
};
|
1098
1141
|
|
1142
|
+
const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
1143
|
+
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
1144
|
+
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
1099
1145
|
const rule$6 = {
|
1100
1146
|
meta: {
|
1101
1147
|
type: 'suggestion',
|
@@ -1136,6 +1182,7 @@ const rule$6 = {
|
|
1136
1182
|
schema: [
|
1137
1183
|
{
|
1138
1184
|
type: 'object',
|
1185
|
+
additionalProperties: false,
|
1139
1186
|
properties: {
|
1140
1187
|
checkInputType: {
|
1141
1188
|
type: 'boolean',
|
@@ -1158,24 +1205,22 @@ const rule$6 = {
|
|
1158
1205
|
description: 'Apply the rule to Mutations',
|
1159
1206
|
},
|
1160
1207
|
},
|
1161
|
-
additionalProperties: false,
|
1162
1208
|
},
|
1163
1209
|
],
|
1164
1210
|
},
|
1165
1211
|
create(context) {
|
1166
|
-
var _a;
|
1167
1212
|
const options = {
|
1168
|
-
caseSensitiveInputType: true,
|
1169
1213
|
checkInputType: false,
|
1170
|
-
|
1214
|
+
caseSensitiveInputType: true,
|
1171
1215
|
checkQueries: false,
|
1172
|
-
|
1216
|
+
checkMutations: true,
|
1217
|
+
...context.options[0],
|
1173
1218
|
};
|
1174
1219
|
const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
|
1175
1220
|
const listeners = {
|
1176
|
-
'FieldDefinition > InputValueDefinition'
|
1177
|
-
|
1178
|
-
|
1221
|
+
'FieldDefinition > InputValueDefinition[name.value!=input]'(node) {
|
1222
|
+
if (shouldCheckType(node.parent.parent)) {
|
1223
|
+
const name = node.name.value;
|
1179
1224
|
context.report({
|
1180
1225
|
loc: getLocation(node.loc, name),
|
1181
1226
|
message: `Input "${name}" should be called "input"`,
|
@@ -1183,11 +1228,11 @@ const rule$6 = {
|
|
1183
1228
|
}
|
1184
1229
|
},
|
1185
1230
|
};
|
1186
|
-
if (options
|
1187
|
-
listeners['FieldDefinition > InputValueDefinition NamedType'] = node => {
|
1231
|
+
if (options.checkInputType) {
|
1232
|
+
listeners['FieldDefinition > InputValueDefinition NamedType'] = (node) => {
|
1188
1233
|
const findInputType = item => {
|
1189
1234
|
let currentNode = item;
|
1190
|
-
while (currentNode.type !==
|
1235
|
+
while (currentNode.type !== graphql.Kind.INPUT_VALUE_DEFINITION) {
|
1191
1236
|
currentNode = currentNode.parent;
|
1192
1237
|
}
|
1193
1238
|
return currentNode;
|
@@ -1404,69 +1449,40 @@ const rule$7 = {
|
|
1404
1449
|
},
|
1405
1450
|
};
|
1406
1451
|
|
1407
|
-
const
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
const acceptedStyles = [
|
1414
|
-
'camelCase',
|
1415
|
-
'PascalCase',
|
1416
|
-
'snake_case',
|
1417
|
-
'UPPER_CASE',
|
1452
|
+
const FIELDS_KINDS = [
|
1453
|
+
graphql.Kind.FIELD_DEFINITION,
|
1454
|
+
graphql.Kind.INPUT_VALUE_DEFINITION,
|
1455
|
+
graphql.Kind.VARIABLE_DEFINITION,
|
1456
|
+
graphql.Kind.ARGUMENT,
|
1457
|
+
graphql.Kind.DIRECTIVE_DEFINITION,
|
1418
1458
|
];
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
if (forbiddenPrefixes.some(forbiddenPrefix => name.startsWith(forbiddenPrefix))) {
|
1447
|
-
return {
|
1448
|
-
ok: false,
|
1449
|
-
errorMessage: '{{nodeType}} "{{nodeName}}" should not have one of the following prefix(es): {{forbiddenPrefixes}}',
|
1450
|
-
};
|
1451
|
-
}
|
1452
|
-
if (forbiddenSuffixes.some(forbiddenSuffix => name.endsWith(forbiddenSuffix))) {
|
1453
|
-
return {
|
1454
|
-
ok: false,
|
1455
|
-
errorMessage: '{{nodeType}} "{{nodeName}}" should not have one of the following suffix(es): {{forbiddenSuffixes}}',
|
1456
|
-
};
|
1457
|
-
}
|
1458
|
-
if (!formats[style]) {
|
1459
|
-
return { ok: true };
|
1460
|
-
}
|
1461
|
-
const ok = new RegExp(formats[style]).test(name);
|
1462
|
-
if (ok) {
|
1463
|
-
return { ok: true };
|
1464
|
-
}
|
1465
|
-
return {
|
1466
|
-
ok: false,
|
1467
|
-
errorMessage: '{{nodeType}} name "{{nodeName}}" should be in {{format}} format',
|
1468
|
-
};
|
1469
|
-
}
|
1459
|
+
const KindToDisplayName = {
|
1460
|
+
// types
|
1461
|
+
[graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
1462
|
+
[graphql.Kind.INTERFACE_TYPE_DEFINITION]: 'Interface',
|
1463
|
+
[graphql.Kind.ENUM_TYPE_DEFINITION]: 'Enumerator',
|
1464
|
+
[graphql.Kind.SCALAR_TYPE_DEFINITION]: 'Scalar',
|
1465
|
+
[graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'Input type',
|
1466
|
+
[graphql.Kind.UNION_TYPE_DEFINITION]: 'Union',
|
1467
|
+
// fields
|
1468
|
+
[graphql.Kind.FIELD_DEFINITION]: 'Field',
|
1469
|
+
[graphql.Kind.INPUT_VALUE_DEFINITION]: 'Input property',
|
1470
|
+
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1471
|
+
[graphql.Kind.ARGUMENT]: 'Argument',
|
1472
|
+
[graphql.Kind.DIRECTIVE_DEFINITION]: 'Directive',
|
1473
|
+
// rest
|
1474
|
+
[graphql.Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
|
1475
|
+
[graphql.Kind.OPERATION_DEFINITION]: 'Operation',
|
1476
|
+
[graphql.Kind.FRAGMENT_DEFINITION]: 'Fragment',
|
1477
|
+
};
|
1478
|
+
const StyleToRegex = {
|
1479
|
+
camelCase: /^[a-z][\dA-Za-z]*$/,
|
1480
|
+
PascalCase: /^[A-Z][\dA-Za-z]*$/,
|
1481
|
+
snake_case: /^[a-z][\d_a-z]*[\da-z]$/,
|
1482
|
+
UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]$/,
|
1483
|
+
};
|
1484
|
+
const ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
|
1485
|
+
const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
1470
1486
|
const schemaOption$1 = {
|
1471
1487
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1472
1488
|
};
|
@@ -1481,89 +1497,120 @@ const rule$8 = {
|
|
1481
1497
|
examples: [
|
1482
1498
|
{
|
1483
1499
|
title: 'Incorrect',
|
1484
|
-
usage: [{
|
1500
|
+
usage: [{ types: 'PascalCase', fields: 'camelCase' }],
|
1485
1501
|
code: /* GraphQL */ `
|
1486
|
-
type
|
1487
|
-
|
1502
|
+
type user {
|
1503
|
+
first_name: String!
|
1488
1504
|
}
|
1489
1505
|
`,
|
1490
1506
|
},
|
1491
1507
|
{
|
1492
1508
|
title: 'Correct',
|
1493
|
-
usage: [{
|
1509
|
+
usage: [{ types: 'PascalCase', fields: 'camelCase' }],
|
1494
1510
|
code: /* GraphQL */ `
|
1495
|
-
type
|
1496
|
-
|
1511
|
+
type User {
|
1512
|
+
firstName: String
|
1497
1513
|
}
|
1498
1514
|
`,
|
1499
1515
|
},
|
1500
1516
|
],
|
1517
|
+
optionsForConfig: [
|
1518
|
+
{
|
1519
|
+
types: 'PascalCase',
|
1520
|
+
fields: 'camelCase',
|
1521
|
+
overrides: {
|
1522
|
+
EnumValueDefinition: 'UPPER_CASE',
|
1523
|
+
OperationDefinition: {
|
1524
|
+
style: 'PascalCase',
|
1525
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1526
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1527
|
+
},
|
1528
|
+
FragmentDefinition: {
|
1529
|
+
style: 'PascalCase',
|
1530
|
+
forbiddenPrefixes: ['Fragment'],
|
1531
|
+
forbiddenSuffixes: ['Fragment'],
|
1532
|
+
},
|
1533
|
+
'FieldDefinition[parent.name.value=Query]': {
|
1534
|
+
forbiddenPrefixes: ['query', 'get'],
|
1535
|
+
forbiddenSuffixes: ['Query'],
|
1536
|
+
},
|
1537
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
1538
|
+
forbiddenPrefixes: ['mutation'],
|
1539
|
+
forbiddenSuffixes: ['Mutation'],
|
1540
|
+
},
|
1541
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
1542
|
+
forbiddenPrefixes: ['subscription'],
|
1543
|
+
forbiddenSuffixes: ['Subscription'],
|
1544
|
+
},
|
1545
|
+
},
|
1546
|
+
},
|
1547
|
+
],
|
1501
1548
|
},
|
1502
1549
|
schema: {
|
1503
1550
|
definitions: {
|
1504
1551
|
asString: {
|
1505
|
-
|
1506
|
-
description: `One of: ${
|
1507
|
-
enum: acceptedStyles,
|
1552
|
+
enum: ALLOWED_STYLES,
|
1553
|
+
description: `One of: ${ALLOWED_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1508
1554
|
},
|
1509
1555
|
asObject: {
|
1510
1556
|
type: 'object',
|
1557
|
+
additionalProperties: false,
|
1511
1558
|
properties: {
|
1512
|
-
style: {
|
1513
|
-
|
1514
|
-
|
1515
|
-
},
|
1516
|
-
prefix: {
|
1517
|
-
type: 'string',
|
1518
|
-
},
|
1519
|
-
suffix: {
|
1520
|
-
type: 'string',
|
1521
|
-
},
|
1559
|
+
style: { enum: ALLOWED_STYLES },
|
1560
|
+
prefix: { type: 'string' },
|
1561
|
+
suffix: { type: 'string' },
|
1522
1562
|
forbiddenPrefixes: {
|
1523
|
-
additionalItems: false,
|
1524
1563
|
type: 'array',
|
1564
|
+
uniqueItems: true,
|
1525
1565
|
minItems: 1,
|
1526
|
-
items: {
|
1527
|
-
type: 'string',
|
1528
|
-
},
|
1566
|
+
items: { type: 'string' },
|
1529
1567
|
},
|
1530
1568
|
forbiddenSuffixes: {
|
1531
|
-
additionalItems: false,
|
1532
1569
|
type: 'array',
|
1570
|
+
uniqueItems: true,
|
1533
1571
|
minItems: 1,
|
1534
|
-
items: {
|
1535
|
-
type: 'string',
|
1536
|
-
},
|
1572
|
+
items: { type: 'string' },
|
1537
1573
|
},
|
1538
1574
|
},
|
1539
1575
|
},
|
1540
1576
|
},
|
1541
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
1542
1577
|
type: 'array',
|
1578
|
+
maxItems: 1,
|
1543
1579
|
items: {
|
1544
1580
|
type: 'object',
|
1581
|
+
additionalProperties: false,
|
1545
1582
|
properties: {
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
[graphql.Kind.INPUT_VALUE_DEFINITION]: schemaOption$1,
|
1550
|
-
[graphql.Kind.OBJECT_TYPE_DEFINITION]: schemaOption$1,
|
1551
|
-
[graphql.Kind.INTERFACE_TYPE_DEFINITION]: schemaOption$1,
|
1552
|
-
[graphql.Kind.ENUM_TYPE_DEFINITION]: schemaOption$1,
|
1553
|
-
[graphql.Kind.UNION_TYPE_DEFINITION]: schemaOption$1,
|
1554
|
-
[graphql.Kind.SCALAR_TYPE_DEFINITION]: schemaOption$1,
|
1555
|
-
[graphql.Kind.OPERATION_DEFINITION]: schemaOption$1,
|
1556
|
-
[graphql.Kind.FRAGMENT_DEFINITION]: schemaOption$1,
|
1557
|
-
QueryDefinition: schemaOption$1,
|
1558
|
-
leadingUnderscore: {
|
1559
|
-
type: 'string',
|
1560
|
-
enum: ['allow', 'forbid'],
|
1561
|
-
default: 'forbid',
|
1583
|
+
types: {
|
1584
|
+
...schemaOption$1,
|
1585
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1562
1586
|
},
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1587
|
+
fields: {
|
1588
|
+
...schemaOption$1,
|
1589
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1590
|
+
},
|
1591
|
+
allowLeadingUnderscore: {
|
1592
|
+
type: 'boolean',
|
1593
|
+
default: false,
|
1594
|
+
},
|
1595
|
+
allowTrailingUnderscore: {
|
1596
|
+
type: 'boolean',
|
1597
|
+
default: false,
|
1598
|
+
},
|
1599
|
+
overrides: {
|
1600
|
+
type: 'object',
|
1601
|
+
additionalProperties: false,
|
1602
|
+
description: [
|
1603
|
+
'May contain the following `ASTNode` names:',
|
1604
|
+
'',
|
1605
|
+
...ALLOWED_KINDS.map(kind => `- \`${kind}\``),
|
1606
|
+
'',
|
1607
|
+
"> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
|
1608
|
+
'>',
|
1609
|
+
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`',
|
1610
|
+
].join('\n'),
|
1611
|
+
patternProperties: {
|
1612
|
+
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1613
|
+
},
|
1567
1614
|
},
|
1568
1615
|
},
|
1569
1616
|
},
|
@@ -1571,136 +1618,83 @@ const rule$8 = {
|
|
1571
1618
|
},
|
1572
1619
|
create(context) {
|
1573
1620
|
const options = {
|
1574
|
-
|
1575
|
-
|
1576
|
-
...(context.options[0] || {}),
|
1621
|
+
overrides: {},
|
1622
|
+
...context.options[0],
|
1577
1623
|
};
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
}
|
1590
|
-
|
1624
|
+
function normalisePropertyOption(kind) {
|
1625
|
+
let style = options.overrides[kind];
|
1626
|
+
if (!style) {
|
1627
|
+
style = TYPES_KINDS.includes(kind) ? options.types : options.fields;
|
1628
|
+
}
|
1629
|
+
return typeof style === 'object' ? style : { style };
|
1630
|
+
}
|
1631
|
+
const checkNode = (selector) => (node) => {
|
1632
|
+
const { name } = node.kind === graphql.Kind.VARIABLE_DEFINITION ? node.variable : node;
|
1633
|
+
if (!name) {
|
1634
|
+
return;
|
1635
|
+
}
|
1636
|
+
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
|
1637
|
+
const nodeType = KindToDisplayName[node.kind] || node.kind;
|
1638
|
+
const nodeName = name.value;
|
1639
|
+
const errorMessage = getErrorMessage();
|
1640
|
+
if (errorMessage) {
|
1591
1641
|
context.report({
|
1592
|
-
loc: getLocation(
|
1593
|
-
message:
|
1594
|
-
data: {
|
1595
|
-
prefix,
|
1596
|
-
suffix,
|
1597
|
-
format: style,
|
1598
|
-
forbiddenPrefixes: forbiddenPrefixes.join(', '),
|
1599
|
-
forbiddenSuffixes: forbiddenSuffixes.join(', '),
|
1600
|
-
nodeType,
|
1601
|
-
nodeName: node.value,
|
1602
|
-
},
|
1642
|
+
loc: getLocation(name.loc, name.value),
|
1643
|
+
message: `${nodeType} "${nodeName}" should ${errorMessage}`,
|
1603
1644
|
});
|
1604
1645
|
}
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
}
|
1610
|
-
return {
|
1611
|
-
style: value,
|
1612
|
-
prefix: '',
|
1613
|
-
suffix: '',
|
1614
|
-
};
|
1615
|
-
};
|
1616
|
-
return {
|
1617
|
-
Name: node => {
|
1618
|
-
if (node.value.startsWith('_') && options.leadingUnderscore === 'forbid') {
|
1619
|
-
context.report({
|
1620
|
-
loc: getLocation(node.loc, node.value),
|
1621
|
-
message: 'Leading underscores are not allowed',
|
1622
|
-
});
|
1646
|
+
function getErrorMessage() {
|
1647
|
+
let name = nodeName;
|
1648
|
+
if (options.allowLeadingUnderscore) {
|
1649
|
+
name = name.replace(/^_*/, '');
|
1623
1650
|
}
|
1624
|
-
if (
|
1625
|
-
|
1626
|
-
loc: getLocation(node.loc, node.value),
|
1627
|
-
message: 'Trailing underscores are not allowed',
|
1628
|
-
});
|
1651
|
+
if (options.allowTrailingUnderscore) {
|
1652
|
+
name = name.replace(/_*$/, '');
|
1629
1653
|
}
|
1630
|
-
|
1631
|
-
|
1632
|
-
if (options.ObjectTypeDefinition) {
|
1633
|
-
const property = normalisePropertyOption(options.ObjectTypeDefinition);
|
1634
|
-
checkNode(node.name, property, 'Type');
|
1654
|
+
if (prefix && !name.startsWith(prefix)) {
|
1655
|
+
return `have "${prefix}" prefix`;
|
1635
1656
|
}
|
1636
|
-
|
1637
|
-
|
1638
|
-
if (options.InterfaceTypeDefinition) {
|
1639
|
-
const property = normalisePropertyOption(options.InterfaceTypeDefinition);
|
1640
|
-
checkNode(node.name, property, 'Interface');
|
1657
|
+
if (suffix && !name.endsWith(suffix)) {
|
1658
|
+
return `have "${suffix}" suffix`;
|
1641
1659
|
}
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
const property = normalisePropertyOption(options.EnumTypeDefinition);
|
1646
|
-
checkNode(node.name, property, 'Enumerator');
|
1660
|
+
const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
|
1661
|
+
if (forbiddenPrefix) {
|
1662
|
+
return `not have "${forbiddenPrefix}" prefix`;
|
1647
1663
|
}
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
const property = normalisePropertyOption(options.InputObjectTypeDefinition);
|
1652
|
-
checkNode(node.name, property, 'Input type');
|
1664
|
+
const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
|
1665
|
+
if (forbiddenSuffix) {
|
1666
|
+
return `not have "${forbiddenSuffix}" suffix`;
|
1653
1667
|
}
|
1654
|
-
|
1655
|
-
|
1656
|
-
if (options.QueryDefinition && isQueryType(node.parent)) {
|
1657
|
-
const property = normalisePropertyOption(options.QueryDefinition);
|
1658
|
-
checkNode(node.name, property, 'Query');
|
1668
|
+
if (style && !ALLOWED_STYLES.includes(style)) {
|
1669
|
+
return `be in one of the following options: ${ALLOWED_STYLES.join(', ')}`;
|
1659
1670
|
}
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
}
|
1664
|
-
},
|
1665
|
-
EnumValueDefinition: node => {
|
1666
|
-
if (options.EnumValueDefinition) {
|
1667
|
-
const property = normalisePropertyOption(options.EnumValueDefinition);
|
1668
|
-
checkNode(node.name, property, 'Enumeration value');
|
1671
|
+
const caseRegex = StyleToRegex[style];
|
1672
|
+
if (caseRegex && !caseRegex.test(name)) {
|
1673
|
+
return `be in ${style} format`;
|
1669
1674
|
}
|
1670
|
-
}
|
1671
|
-
InputValueDefinition: node => {
|
1672
|
-
if (options.InputValueDefinition) {
|
1673
|
-
const property = normalisePropertyOption(options.InputValueDefinition);
|
1674
|
-
checkNode(node.name, property, 'Input property');
|
1675
|
-
}
|
1676
|
-
},
|
1677
|
-
OperationDefinition: node => {
|
1678
|
-
if (options.OperationDefinition) {
|
1679
|
-
const property = normalisePropertyOption(options.OperationDefinition);
|
1680
|
-
if (node.name) {
|
1681
|
-
checkNode(node.name, property, 'Operation');
|
1682
|
-
}
|
1683
|
-
}
|
1684
|
-
},
|
1685
|
-
FragmentDefinition: node => {
|
1686
|
-
if (options.FragmentDefinition) {
|
1687
|
-
const property = normalisePropertyOption(options.FragmentDefinition);
|
1688
|
-
checkNode(node.name, property, 'Fragment');
|
1689
|
-
}
|
1690
|
-
},
|
1691
|
-
ScalarTypeDefinition: node => {
|
1692
|
-
if (options.ScalarTypeDefinition) {
|
1693
|
-
const property = normalisePropertyOption(options.ScalarTypeDefinition);
|
1694
|
-
checkNode(node.name, property, 'Scalar');
|
1695
|
-
}
|
1696
|
-
},
|
1697
|
-
UnionTypeDefinition: node => {
|
1698
|
-
if (options.UnionTypeDefinition) {
|
1699
|
-
const property = normalisePropertyOption(options.UnionTypeDefinition);
|
1700
|
-
checkNode(node.name, property, 'Union');
|
1701
|
-
}
|
1702
|
-
},
|
1675
|
+
}
|
1703
1676
|
};
|
1677
|
+
const checkUnderscore = (node) => {
|
1678
|
+
const name = node.value;
|
1679
|
+
context.report({
|
1680
|
+
loc: getLocation(node.loc, name),
|
1681
|
+
message: `${name.startsWith('_') ? 'Leading' : 'Trailing'} underscores are not allowed`,
|
1682
|
+
});
|
1683
|
+
};
|
1684
|
+
const listeners = {};
|
1685
|
+
if (!options.allowLeadingUnderscore) {
|
1686
|
+
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1687
|
+
}
|
1688
|
+
if (!options.allowTrailingUnderscore) {
|
1689
|
+
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1690
|
+
}
|
1691
|
+
const selectors = new Set([options.types && TYPES_KINDS, options.fields && FIELDS_KINDS, Object.keys(options.overrides)]
|
1692
|
+
.flat()
|
1693
|
+
.filter(Boolean));
|
1694
|
+
for (const selector of selectors) {
|
1695
|
+
listeners[selector] = checkNode(selector);
|
1696
|
+
}
|
1697
|
+
return listeners;
|
1704
1698
|
},
|
1705
1699
|
};
|
1706
1700
|
|
@@ -1891,7 +1885,7 @@ const rule$b = {
|
|
1891
1885
|
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1892
1886
|
const typeInfo = node.typeInfo();
|
1893
1887
|
if (typeInfo && typeInfo.enumValue) {
|
1894
|
-
if (typeInfo.enumValue.
|
1888
|
+
if (typeInfo.enumValue.isDeprecated) {
|
1895
1889
|
const enumValueName = node.value;
|
1896
1890
|
context.report({
|
1897
1891
|
loc: getLocation(node.loc, enumValueName),
|
@@ -1908,7 +1902,7 @@ const rule$b = {
|
|
1908
1902
|
requireGraphQLSchemaFromContext('no-deprecated', context);
|
1909
1903
|
const typeInfo = node.typeInfo();
|
1910
1904
|
if (typeInfo && typeInfo.fieldDef) {
|
1911
|
-
if (typeInfo.fieldDef.
|
1905
|
+
if (typeInfo.fieldDef.isDeprecated) {
|
1912
1906
|
const fieldName = node.name.value;
|
1913
1907
|
context.report({
|
1914
1908
|
loc: getLocation(node.loc, fieldName),
|
@@ -2326,6 +2320,7 @@ function convertDescription(node) {
|
|
2326
2320
|
return [];
|
2327
2321
|
}
|
2328
2322
|
|
2323
|
+
// eslint-disable-next-line unicorn/better-regex
|
2329
2324
|
const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
|
2330
2325
|
const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
2331
2326
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
@@ -2523,7 +2518,7 @@ const rule$i = {
|
|
2523
2518
|
examples: [
|
2524
2519
|
{
|
2525
2520
|
title: 'Incorrect',
|
2526
|
-
usage: [{ on: [
|
2521
|
+
usage: [{ on: ['ObjectTypeDefinition', 'FieldDefinition'] }],
|
2527
2522
|
code: /* GraphQL */ `
|
2528
2523
|
type someTypeName {
|
2529
2524
|
name: String
|
@@ -2532,7 +2527,7 @@ const rule$i = {
|
|
2532
2527
|
},
|
2533
2528
|
{
|
2534
2529
|
title: 'Correct',
|
2535
|
-
usage: [{ on: [
|
2530
|
+
usage: [{ on: ['ObjectTypeDefinition', 'FieldDefinition'] }],
|
2536
2531
|
code: /* GraphQL */ `
|
2537
2532
|
"""
|
2538
2533
|
Some type description
|
@@ -3119,7 +3114,7 @@ const rule$m = {
|
|
3119
3114
|
acceptedIdNames: ['id'],
|
3120
3115
|
acceptedIdTypes: ['ID'],
|
3121
3116
|
exceptions: {},
|
3122
|
-
...
|
3117
|
+
...context.options[0],
|
3123
3118
|
};
|
3124
3119
|
return {
|
3125
3120
|
ObjectTypeDefinition(node) {
|