@graphql-eslint/eslint-plugin 2.5.0-alpha-14532ce.0 → 3.0.0-alpha-069461d.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 +32 -1
- package/configs/index.d.ts +61 -2
- package/configs/recommended.d.ts +29 -1
- package/docs/README.md +1 -0
- 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/no-root-type.md +56 -0
- package/docs/rules/strict-id-in-types.md +4 -4
- package/index.js +382 -282
- package/index.mjs +382 -282
- package/package.json +1 -1
- package/rules/alphabetize.d.ts +5 -6
- package/rules/index.d.ts +124 -19
- package/rules/naming-convention.d.ts +32 -25
- package/rules/no-root-type.d.ts +7 -0
- 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',
|
@@ -91,6 +118,7 @@ const allConfig = {
|
|
91
118
|
'@graphql-eslint/match-document-filename': 'error',
|
92
119
|
'@graphql-eslint/no-deprecated': 'error',
|
93
120
|
'@graphql-eslint/no-hashtag-description': 'error',
|
121
|
+
'@graphql-eslint/no-root-type': ['error', { disallow: ['subscription'] }],
|
94
122
|
'@graphql-eslint/no-unreachable-types': 'error',
|
95
123
|
'@graphql-eslint/no-unused-fields': 'error',
|
96
124
|
'@graphql-eslint/require-deprecation-date': 'error',
|
@@ -211,9 +239,14 @@ const loaderCache = new Proxy(Object.create(null), {
|
|
211
239
|
return true;
|
212
240
|
},
|
213
241
|
});
|
214
|
-
const
|
215
|
-
|
216
|
-
|
242
|
+
const TYPES_KINDS = [
|
243
|
+
graphql.Kind.OBJECT_TYPE_DEFINITION,
|
244
|
+
graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
245
|
+
graphql.Kind.ENUM_TYPE_DEFINITION,
|
246
|
+
graphql.Kind.SCALAR_TYPE_DEFINITION,
|
247
|
+
graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
248
|
+
graphql.Kind.UNION_TYPE_DEFINITION,
|
249
|
+
];
|
217
250
|
var CaseStyle;
|
218
251
|
(function (CaseStyle) {
|
219
252
|
CaseStyle["camelCase"] = "camelCase";
|
@@ -264,7 +297,7 @@ function getLocation(loc, fieldName = '', offset) {
|
|
264
297
|
}
|
265
298
|
|
266
299
|
function extractRuleName(stack) {
|
267
|
-
const match = (stack || '').match(/validation[
|
300
|
+
const match = (stack || '').match(/validation[/\\]rules[/\\](.*?)\.js:/) || [];
|
268
301
|
return match[1] || null;
|
269
302
|
}
|
270
303
|
function validateDoc(sourceNode, context, schema, documentNode, rules, ruleName = null) {
|
@@ -513,11 +546,23 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
513
546
|
}));
|
514
547
|
|
515
548
|
const ALPHABETIZE = 'ALPHABETIZE';
|
516
|
-
const fieldsEnum = [
|
549
|
+
const fieldsEnum = [
|
550
|
+
graphql.Kind.OBJECT_TYPE_DEFINITION,
|
551
|
+
graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
552
|
+
graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
553
|
+
];
|
517
554
|
const valuesEnum = [graphql.Kind.ENUM_TYPE_DEFINITION];
|
518
|
-
const selectionsEnum = [
|
555
|
+
const selectionsEnum = [
|
556
|
+
graphql.Kind.OPERATION_DEFINITION,
|
557
|
+
graphql.Kind.FRAGMENT_DEFINITION,
|
558
|
+
];
|
519
559
|
const variablesEnum = [graphql.Kind.OPERATION_DEFINITION];
|
520
|
-
const argumentsEnum = [
|
560
|
+
const argumentsEnum = [
|
561
|
+
graphql.Kind.FIELD_DEFINITION,
|
562
|
+
graphql.Kind.FIELD,
|
563
|
+
graphql.Kind.DIRECTIVE_DEFINITION,
|
564
|
+
graphql.Kind.DIRECTIVE,
|
565
|
+
];
|
521
566
|
const rule = {
|
522
567
|
meta: {
|
523
568
|
type: 'suggestion',
|
@@ -625,38 +670,48 @@ const rule = {
|
|
625
670
|
properties: {
|
626
671
|
fields: {
|
627
672
|
type: 'array',
|
628
|
-
|
673
|
+
uniqueItems: true,
|
674
|
+
minItems: 1,
|
675
|
+
items: {
|
629
676
|
enum: fieldsEnum,
|
630
677
|
},
|
631
|
-
description: 'Fields of `type`, `interface`, and `input
|
678
|
+
description: 'Fields of `type`, `interface`, and `input`',
|
632
679
|
},
|
633
680
|
values: {
|
634
681
|
type: 'array',
|
635
|
-
|
682
|
+
uniqueItems: true,
|
683
|
+
minItems: 1,
|
684
|
+
items: {
|
636
685
|
enum: valuesEnum,
|
637
686
|
},
|
638
|
-
description: 'Values of `enum
|
687
|
+
description: 'Values of `enum`',
|
639
688
|
},
|
640
689
|
selections: {
|
641
690
|
type: 'array',
|
642
|
-
|
691
|
+
uniqueItems: true,
|
692
|
+
minItems: 1,
|
693
|
+
items: {
|
643
694
|
enum: selectionsEnum,
|
644
695
|
},
|
645
|
-
description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment
|
696
|
+
description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment`',
|
646
697
|
},
|
647
698
|
variables: {
|
648
699
|
type: 'array',
|
649
|
-
|
700
|
+
uniqueItems: true,
|
701
|
+
minItems: 1,
|
702
|
+
items: {
|
650
703
|
enum: variablesEnum,
|
651
704
|
},
|
652
|
-
description: 'Variables of operations (`query`, `mutation` and `subscription`)
|
705
|
+
description: 'Variables of operations (`query`, `mutation` and `subscription`)',
|
653
706
|
},
|
654
707
|
arguments: {
|
655
708
|
type: 'array',
|
656
|
-
|
709
|
+
uniqueItems: true,
|
710
|
+
minItems: 1,
|
711
|
+
items: {
|
657
712
|
enum: argumentsEnum,
|
658
713
|
},
|
659
|
-
description: 'Arguments of fields and directives
|
714
|
+
description: 'Arguments of fields and directives',
|
660
715
|
},
|
661
716
|
},
|
662
717
|
},
|
@@ -687,7 +742,7 @@ const rule = {
|
|
687
742
|
const opts = context.options[0];
|
688
743
|
const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
|
689
744
|
const listeners = {};
|
690
|
-
const
|
745
|
+
const kinds = [
|
691
746
|
fields.has(graphql.Kind.OBJECT_TYPE_DEFINITION) && [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION],
|
692
747
|
fields.has(graphql.Kind.INTERFACE_TYPE_DEFINITION) && [graphql.Kind.INTERFACE_TYPE_DEFINITION, graphql.Kind.INTERFACE_TYPE_EXTENSION],
|
693
748
|
fields.has(graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
|
@@ -695,8 +750,9 @@ const rule = {
|
|
695
750
|
graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION,
|
696
751
|
],
|
697
752
|
]
|
698
|
-
.
|
699
|
-
.
|
753
|
+
.filter(Boolean)
|
754
|
+
.flat();
|
755
|
+
const fieldsSelector = kinds.join(',');
|
700
756
|
const hasEnumValues = ((_b = opts.values) === null || _b === void 0 ? void 0 : _b[0]) === graphql.Kind.ENUM_TYPE_DEFINITION;
|
701
757
|
const selectionsSelector = (_c = opts.selections) === null || _c === void 0 ? void 0 : _c.join(',');
|
702
758
|
const hasVariables = ((_d = opts.variables) === null || _d === void 0 ? void 0 : _d[0]) === graphql.Kind.OPERATION_DEFINITION;
|
@@ -1096,6 +1152,9 @@ const rule$5 = {
|
|
1096
1152
|
},
|
1097
1153
|
};
|
1098
1154
|
|
1155
|
+
const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
|
1156
|
+
const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
|
1157
|
+
const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
|
1099
1158
|
const rule$6 = {
|
1100
1159
|
meta: {
|
1101
1160
|
type: 'suggestion',
|
@@ -1136,6 +1195,7 @@ const rule$6 = {
|
|
1136
1195
|
schema: [
|
1137
1196
|
{
|
1138
1197
|
type: 'object',
|
1198
|
+
additionalProperties: false,
|
1139
1199
|
properties: {
|
1140
1200
|
checkInputType: {
|
1141
1201
|
type: 'boolean',
|
@@ -1158,24 +1218,22 @@ const rule$6 = {
|
|
1158
1218
|
description: 'Apply the rule to Mutations',
|
1159
1219
|
},
|
1160
1220
|
},
|
1161
|
-
additionalProperties: false,
|
1162
1221
|
},
|
1163
1222
|
],
|
1164
1223
|
},
|
1165
1224
|
create(context) {
|
1166
|
-
var _a;
|
1167
1225
|
const options = {
|
1168
|
-
caseSensitiveInputType: true,
|
1169
1226
|
checkInputType: false,
|
1170
|
-
|
1227
|
+
caseSensitiveInputType: true,
|
1171
1228
|
checkQueries: false,
|
1172
|
-
|
1229
|
+
checkMutations: true,
|
1230
|
+
...context.options[0],
|
1173
1231
|
};
|
1174
1232
|
const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
|
1175
1233
|
const listeners = {
|
1176
|
-
'FieldDefinition > InputValueDefinition'
|
1177
|
-
|
1178
|
-
|
1234
|
+
'FieldDefinition > InputValueDefinition[name.value!=input]'(node) {
|
1235
|
+
if (shouldCheckType(node.parent.parent)) {
|
1236
|
+
const name = node.name.value;
|
1179
1237
|
context.report({
|
1180
1238
|
loc: getLocation(node.loc, name),
|
1181
1239
|
message: `Input "${name}" should be called "input"`,
|
@@ -1183,11 +1241,11 @@ const rule$6 = {
|
|
1183
1241
|
}
|
1184
1242
|
},
|
1185
1243
|
};
|
1186
|
-
if (options
|
1187
|
-
listeners['FieldDefinition > InputValueDefinition NamedType'] = node => {
|
1244
|
+
if (options.checkInputType) {
|
1245
|
+
listeners['FieldDefinition > InputValueDefinition NamedType'] = (node) => {
|
1188
1246
|
const findInputType = item => {
|
1189
1247
|
let currentNode = item;
|
1190
|
-
while (currentNode.type !==
|
1248
|
+
while (currentNode.type !== graphql.Kind.INPUT_VALUE_DEFINITION) {
|
1191
1249
|
currentNode = currentNode.parent;
|
1192
1250
|
}
|
1193
1251
|
return currentNode;
|
@@ -1404,69 +1462,40 @@ const rule$7 = {
|
|
1404
1462
|
},
|
1405
1463
|
};
|
1406
1464
|
|
1407
|
-
const
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
const acceptedStyles = [
|
1414
|
-
'camelCase',
|
1415
|
-
'PascalCase',
|
1416
|
-
'snake_case',
|
1417
|
-
'UPPER_CASE',
|
1465
|
+
const FIELDS_KINDS = [
|
1466
|
+
graphql.Kind.FIELD_DEFINITION,
|
1467
|
+
graphql.Kind.INPUT_VALUE_DEFINITION,
|
1468
|
+
graphql.Kind.VARIABLE_DEFINITION,
|
1469
|
+
graphql.Kind.ARGUMENT,
|
1470
|
+
graphql.Kind.DIRECTIVE_DEFINITION,
|
1418
1471
|
];
|
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
|
-
}
|
1472
|
+
const KindToDisplayName = {
|
1473
|
+
// types
|
1474
|
+
[graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
|
1475
|
+
[graphql.Kind.INTERFACE_TYPE_DEFINITION]: 'Interface',
|
1476
|
+
[graphql.Kind.ENUM_TYPE_DEFINITION]: 'Enumerator',
|
1477
|
+
[graphql.Kind.SCALAR_TYPE_DEFINITION]: 'Scalar',
|
1478
|
+
[graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'Input type',
|
1479
|
+
[graphql.Kind.UNION_TYPE_DEFINITION]: 'Union',
|
1480
|
+
// fields
|
1481
|
+
[graphql.Kind.FIELD_DEFINITION]: 'Field',
|
1482
|
+
[graphql.Kind.INPUT_VALUE_DEFINITION]: 'Input property',
|
1483
|
+
[graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
|
1484
|
+
[graphql.Kind.ARGUMENT]: 'Argument',
|
1485
|
+
[graphql.Kind.DIRECTIVE_DEFINITION]: 'Directive',
|
1486
|
+
// rest
|
1487
|
+
[graphql.Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
|
1488
|
+
[graphql.Kind.OPERATION_DEFINITION]: 'Operation',
|
1489
|
+
[graphql.Kind.FRAGMENT_DEFINITION]: 'Fragment',
|
1490
|
+
};
|
1491
|
+
const StyleToRegex = {
|
1492
|
+
camelCase: /^[a-z][\dA-Za-z]*$/,
|
1493
|
+
PascalCase: /^[A-Z][\dA-Za-z]*$/,
|
1494
|
+
snake_case: /^[a-z][\d_a-z]*[\da-z]$/,
|
1495
|
+
UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]$/,
|
1496
|
+
};
|
1497
|
+
const ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
|
1498
|
+
const ALLOWED_STYLES = Object.keys(StyleToRegex);
|
1470
1499
|
const schemaOption$1 = {
|
1471
1500
|
oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
|
1472
1501
|
};
|
@@ -1481,89 +1510,120 @@ const rule$8 = {
|
|
1481
1510
|
examples: [
|
1482
1511
|
{
|
1483
1512
|
title: 'Incorrect',
|
1484
|
-
usage: [{
|
1513
|
+
usage: [{ types: 'PascalCase', fields: 'camelCase' }],
|
1485
1514
|
code: /* GraphQL */ `
|
1486
|
-
type
|
1487
|
-
|
1515
|
+
type user {
|
1516
|
+
first_name: String!
|
1488
1517
|
}
|
1489
1518
|
`,
|
1490
1519
|
},
|
1491
1520
|
{
|
1492
1521
|
title: 'Correct',
|
1493
|
-
usage: [{
|
1522
|
+
usage: [{ types: 'PascalCase', fields: 'camelCase' }],
|
1494
1523
|
code: /* GraphQL */ `
|
1495
|
-
type
|
1496
|
-
|
1524
|
+
type User {
|
1525
|
+
firstName: String
|
1497
1526
|
}
|
1498
1527
|
`,
|
1499
1528
|
},
|
1500
1529
|
],
|
1530
|
+
optionsForConfig: [
|
1531
|
+
{
|
1532
|
+
types: 'PascalCase',
|
1533
|
+
fields: 'camelCase',
|
1534
|
+
overrides: {
|
1535
|
+
EnumValueDefinition: 'UPPER_CASE',
|
1536
|
+
OperationDefinition: {
|
1537
|
+
style: 'PascalCase',
|
1538
|
+
forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
|
1539
|
+
forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
|
1540
|
+
},
|
1541
|
+
FragmentDefinition: {
|
1542
|
+
style: 'PascalCase',
|
1543
|
+
forbiddenPrefixes: ['Fragment'],
|
1544
|
+
forbiddenSuffixes: ['Fragment'],
|
1545
|
+
},
|
1546
|
+
'FieldDefinition[parent.name.value=Query]': {
|
1547
|
+
forbiddenPrefixes: ['query', 'get'],
|
1548
|
+
forbiddenSuffixes: ['Query'],
|
1549
|
+
},
|
1550
|
+
'FieldDefinition[parent.name.value=Mutation]': {
|
1551
|
+
forbiddenPrefixes: ['mutation'],
|
1552
|
+
forbiddenSuffixes: ['Mutation'],
|
1553
|
+
},
|
1554
|
+
'FieldDefinition[parent.name.value=Subscription]': {
|
1555
|
+
forbiddenPrefixes: ['subscription'],
|
1556
|
+
forbiddenSuffixes: ['Subscription'],
|
1557
|
+
},
|
1558
|
+
},
|
1559
|
+
},
|
1560
|
+
],
|
1501
1561
|
},
|
1502
1562
|
schema: {
|
1503
1563
|
definitions: {
|
1504
1564
|
asString: {
|
1505
|
-
|
1506
|
-
description: `One of: ${
|
1507
|
-
enum: acceptedStyles,
|
1565
|
+
enum: ALLOWED_STYLES,
|
1566
|
+
description: `One of: ${ALLOWED_STYLES.map(t => `\`${t}\``).join(', ')}`,
|
1508
1567
|
},
|
1509
1568
|
asObject: {
|
1510
1569
|
type: 'object',
|
1570
|
+
additionalProperties: false,
|
1511
1571
|
properties: {
|
1512
|
-
style: {
|
1513
|
-
|
1514
|
-
|
1515
|
-
},
|
1516
|
-
prefix: {
|
1517
|
-
type: 'string',
|
1518
|
-
},
|
1519
|
-
suffix: {
|
1520
|
-
type: 'string',
|
1521
|
-
},
|
1572
|
+
style: { enum: ALLOWED_STYLES },
|
1573
|
+
prefix: { type: 'string' },
|
1574
|
+
suffix: { type: 'string' },
|
1522
1575
|
forbiddenPrefixes: {
|
1523
|
-
additionalItems: false,
|
1524
1576
|
type: 'array',
|
1577
|
+
uniqueItems: true,
|
1525
1578
|
minItems: 1,
|
1526
|
-
items: {
|
1527
|
-
type: 'string',
|
1528
|
-
},
|
1579
|
+
items: { type: 'string' },
|
1529
1580
|
},
|
1530
1581
|
forbiddenSuffixes: {
|
1531
|
-
additionalItems: false,
|
1532
1582
|
type: 'array',
|
1583
|
+
uniqueItems: true,
|
1533
1584
|
minItems: 1,
|
1534
|
-
items: {
|
1535
|
-
type: 'string',
|
1536
|
-
},
|
1585
|
+
items: { type: 'string' },
|
1537
1586
|
},
|
1538
1587
|
},
|
1539
1588
|
},
|
1540
1589
|
},
|
1541
|
-
$schema: 'http://json-schema.org/draft-04/schema#',
|
1542
1590
|
type: 'array',
|
1591
|
+
maxItems: 1,
|
1543
1592
|
items: {
|
1544
1593
|
type: 'object',
|
1594
|
+
additionalProperties: false,
|
1545
1595
|
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',
|
1596
|
+
types: {
|
1597
|
+
...schemaOption$1,
|
1598
|
+
description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1562
1599
|
},
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1600
|
+
fields: {
|
1601
|
+
...schemaOption$1,
|
1602
|
+
description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
|
1603
|
+
},
|
1604
|
+
allowLeadingUnderscore: {
|
1605
|
+
type: 'boolean',
|
1606
|
+
default: false,
|
1607
|
+
},
|
1608
|
+
allowTrailingUnderscore: {
|
1609
|
+
type: 'boolean',
|
1610
|
+
default: false,
|
1611
|
+
},
|
1612
|
+
overrides: {
|
1613
|
+
type: 'object',
|
1614
|
+
additionalProperties: false,
|
1615
|
+
description: [
|
1616
|
+
'May contain the following `ASTNode` names:',
|
1617
|
+
'',
|
1618
|
+
...ALLOWED_KINDS.map(kind => `- \`${kind}\``),
|
1619
|
+
'',
|
1620
|
+
"> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
|
1621
|
+
'>',
|
1622
|
+
'> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`',
|
1623
|
+
].join('\n'),
|
1624
|
+
patternProperties: {
|
1625
|
+
[`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
|
1626
|
+
},
|
1567
1627
|
},
|
1568
1628
|
},
|
1569
1629
|
},
|
@@ -1571,136 +1631,83 @@ const rule$8 = {
|
|
1571
1631
|
},
|
1572
1632
|
create(context) {
|
1573
1633
|
const options = {
|
1574
|
-
|
1575
|
-
|
1576
|
-
...(context.options[0] || {}),
|
1634
|
+
overrides: {},
|
1635
|
+
...context.options[0],
|
1577
1636
|
};
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
}
|
1590
|
-
|
1637
|
+
function normalisePropertyOption(kind) {
|
1638
|
+
let style = options.overrides[kind];
|
1639
|
+
if (!style) {
|
1640
|
+
style = TYPES_KINDS.includes(kind) ? options.types : options.fields;
|
1641
|
+
}
|
1642
|
+
return typeof style === 'object' ? style : { style };
|
1643
|
+
}
|
1644
|
+
const checkNode = (selector) => (node) => {
|
1645
|
+
const { name } = node.kind === graphql.Kind.VARIABLE_DEFINITION ? node.variable : node;
|
1646
|
+
if (!name) {
|
1647
|
+
return;
|
1648
|
+
}
|
1649
|
+
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
|
1650
|
+
const nodeType = KindToDisplayName[node.kind] || node.kind;
|
1651
|
+
const nodeName = name.value;
|
1652
|
+
const errorMessage = getErrorMessage();
|
1653
|
+
if (errorMessage) {
|
1591
1654
|
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
|
-
},
|
1655
|
+
loc: getLocation(name.loc, name.value),
|
1656
|
+
message: `${nodeType} "${nodeName}" should ${errorMessage}`,
|
1603
1657
|
});
|
1604
1658
|
}
|
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
|
-
});
|
1623
|
-
}
|
1624
|
-
if (node.value.endsWith('_') && options.trailingUnderscore === 'forbid') {
|
1625
|
-
context.report({
|
1626
|
-
loc: getLocation(node.loc, node.value),
|
1627
|
-
message: 'Trailing underscores are not allowed',
|
1628
|
-
});
|
1629
|
-
}
|
1630
|
-
},
|
1631
|
-
ObjectTypeDefinition: node => {
|
1632
|
-
if (options.ObjectTypeDefinition) {
|
1633
|
-
const property = normalisePropertyOption(options.ObjectTypeDefinition);
|
1634
|
-
checkNode(node.name, property, 'Type');
|
1635
|
-
}
|
1636
|
-
},
|
1637
|
-
InterfaceTypeDefinition: node => {
|
1638
|
-
if (options.InterfaceTypeDefinition) {
|
1639
|
-
const property = normalisePropertyOption(options.InterfaceTypeDefinition);
|
1640
|
-
checkNode(node.name, property, 'Interface');
|
1641
|
-
}
|
1642
|
-
},
|
1643
|
-
EnumTypeDefinition: node => {
|
1644
|
-
if (options.EnumTypeDefinition) {
|
1645
|
-
const property = normalisePropertyOption(options.EnumTypeDefinition);
|
1646
|
-
checkNode(node.name, property, 'Enumerator');
|
1659
|
+
function getErrorMessage() {
|
1660
|
+
let name = nodeName;
|
1661
|
+
if (options.allowLeadingUnderscore) {
|
1662
|
+
name = name.replace(/^_*/, '');
|
1647
1663
|
}
|
1648
|
-
|
1649
|
-
|
1650
|
-
if (options.InputObjectTypeDefinition) {
|
1651
|
-
const property = normalisePropertyOption(options.InputObjectTypeDefinition);
|
1652
|
-
checkNode(node.name, property, 'Input type');
|
1664
|
+
if (options.allowTrailingUnderscore) {
|
1665
|
+
name = name.replace(/_*$/, '');
|
1653
1666
|
}
|
1654
|
-
|
1655
|
-
|
1656
|
-
if (options.QueryDefinition && isQueryType(node.parent)) {
|
1657
|
-
const property = normalisePropertyOption(options.QueryDefinition);
|
1658
|
-
checkNode(node.name, property, 'Query');
|
1667
|
+
if (prefix && !name.startsWith(prefix)) {
|
1668
|
+
return `have "${prefix}" prefix`;
|
1659
1669
|
}
|
1660
|
-
if (
|
1661
|
-
|
1662
|
-
checkNode(node.name, property, 'Field');
|
1670
|
+
if (suffix && !name.endsWith(suffix)) {
|
1671
|
+
return `have "${suffix}" suffix`;
|
1663
1672
|
}
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
const property = normalisePropertyOption(options.EnumValueDefinition);
|
1668
|
-
checkNode(node.name, property, 'Enumeration value');
|
1673
|
+
const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
|
1674
|
+
if (forbiddenPrefix) {
|
1675
|
+
return `not have "${forbiddenPrefix}" prefix`;
|
1669
1676
|
}
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
1673
|
-
const property = normalisePropertyOption(options.InputValueDefinition);
|
1674
|
-
checkNode(node.name, property, 'Input property');
|
1677
|
+
const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
|
1678
|
+
if (forbiddenSuffix) {
|
1679
|
+
return `not have "${forbiddenSuffix}" suffix`;
|
1675
1680
|
}
|
1676
|
-
|
1677
|
-
|
1678
|
-
if (options.OperationDefinition) {
|
1679
|
-
const property = normalisePropertyOption(options.OperationDefinition);
|
1680
|
-
if (node.name) {
|
1681
|
-
checkNode(node.name, property, 'Operation');
|
1682
|
-
}
|
1681
|
+
if (style && !ALLOWED_STYLES.includes(style)) {
|
1682
|
+
return `be in one of the following options: ${ALLOWED_STYLES.join(', ')}`;
|
1683
1683
|
}
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
const property = normalisePropertyOption(options.FragmentDefinition);
|
1688
|
-
checkNode(node.name, property, 'Fragment');
|
1684
|
+
const caseRegex = StyleToRegex[style];
|
1685
|
+
if (caseRegex && !caseRegex.test(name)) {
|
1686
|
+
return `be in ${style} format`;
|
1689
1687
|
}
|
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
|
-
},
|
1688
|
+
}
|
1703
1689
|
};
|
1690
|
+
const checkUnderscore = (node) => {
|
1691
|
+
const name = node.value;
|
1692
|
+
context.report({
|
1693
|
+
loc: getLocation(node.loc, name),
|
1694
|
+
message: `${name.startsWith('_') ? 'Leading' : 'Trailing'} underscores are not allowed`,
|
1695
|
+
});
|
1696
|
+
};
|
1697
|
+
const listeners = {};
|
1698
|
+
if (!options.allowLeadingUnderscore) {
|
1699
|
+
listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1700
|
+
}
|
1701
|
+
if (!options.allowTrailingUnderscore) {
|
1702
|
+
listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
|
1703
|
+
}
|
1704
|
+
const selectors = new Set([options.types && TYPES_KINDS, options.fields && FIELDS_KINDS, Object.keys(options.overrides)]
|
1705
|
+
.flat()
|
1706
|
+
.filter(Boolean));
|
1707
|
+
for (const selector of selectors) {
|
1708
|
+
listeners[selector] = checkNode(selector);
|
1709
|
+
}
|
1710
|
+
return listeners;
|
1704
1711
|
},
|
1705
1712
|
};
|
1706
1713
|
|
@@ -2065,9 +2072,100 @@ const rule$d = {
|
|
2065
2072
|
},
|
2066
2073
|
};
|
2067
2074
|
|
2075
|
+
const ROOT_TYPES = ['query', 'mutation', 'subscription'];
|
2076
|
+
const rule$e = {
|
2077
|
+
meta: {
|
2078
|
+
type: 'suggestion',
|
2079
|
+
docs: {
|
2080
|
+
category: 'Validation',
|
2081
|
+
description: 'Disallow using root types for `read-only` or `write-only` schemas.',
|
2082
|
+
url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-root-type.md',
|
2083
|
+
requiresSchema: true,
|
2084
|
+
examples: [
|
2085
|
+
{
|
2086
|
+
title: 'Incorrect (`read-only` schema)',
|
2087
|
+
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2088
|
+
code: /* GraphQL */ `
|
2089
|
+
type Mutation {
|
2090
|
+
createUser(input: CreateUserInput!): User!
|
2091
|
+
}
|
2092
|
+
`,
|
2093
|
+
},
|
2094
|
+
{
|
2095
|
+
title: 'Incorrect (`write-only` schema)',
|
2096
|
+
usage: [{ disallow: ['query'] }],
|
2097
|
+
code: /* GraphQL */ `
|
2098
|
+
type Query {
|
2099
|
+
users: [User!]!
|
2100
|
+
}
|
2101
|
+
`,
|
2102
|
+
},
|
2103
|
+
{
|
2104
|
+
title: 'Correct (`read-only` schema)',
|
2105
|
+
usage: [{ disallow: ['mutation', 'subscription'] }],
|
2106
|
+
code: /* GraphQL */ `
|
2107
|
+
type Query {
|
2108
|
+
users: [User!]!
|
2109
|
+
}
|
2110
|
+
`,
|
2111
|
+
},
|
2112
|
+
],
|
2113
|
+
optionsForConfig: [{ disallow: ['subscription'] }],
|
2114
|
+
},
|
2115
|
+
schema: {
|
2116
|
+
type: 'array',
|
2117
|
+
minItems: 1,
|
2118
|
+
maxItems: 1,
|
2119
|
+
items: {
|
2120
|
+
type: 'object',
|
2121
|
+
additionalProperties: false,
|
2122
|
+
required: ['disallow'],
|
2123
|
+
properties: {
|
2124
|
+
disallow: {
|
2125
|
+
type: 'array',
|
2126
|
+
uniqueItems: true,
|
2127
|
+
minItems: 1,
|
2128
|
+
items: {
|
2129
|
+
enum: ROOT_TYPES,
|
2130
|
+
},
|
2131
|
+
},
|
2132
|
+
},
|
2133
|
+
},
|
2134
|
+
},
|
2135
|
+
},
|
2136
|
+
create(context) {
|
2137
|
+
const schema = requireGraphQLSchemaFromContext('no-root-type', context);
|
2138
|
+
const disallow = new Set(context.options[0].disallow);
|
2139
|
+
const rootTypeNames = [
|
2140
|
+
disallow.has('query') && schema.getQueryType(),
|
2141
|
+
disallow.has('mutation') && schema.getMutationType(),
|
2142
|
+
disallow.has('subscription') && schema.getSubscriptionType(),
|
2143
|
+
]
|
2144
|
+
.filter(Boolean)
|
2145
|
+
.map(type => type.name);
|
2146
|
+
if (rootTypeNames.length === 0) {
|
2147
|
+
return {};
|
2148
|
+
}
|
2149
|
+
const selector = [
|
2150
|
+
`:matches(${graphql.Kind.OBJECT_TYPE_DEFINITION}, ${graphql.Kind.OBJECT_TYPE_EXTENSION})`,
|
2151
|
+
'>',
|
2152
|
+
`${graphql.Kind.NAME}[value=/^(${rootTypeNames.join('|')})$/]`,
|
2153
|
+
].join(' ');
|
2154
|
+
return {
|
2155
|
+
[selector](node) {
|
2156
|
+
const typeName = node.value;
|
2157
|
+
context.report({
|
2158
|
+
loc: getLocation(node.loc, typeName),
|
2159
|
+
message: `Root type "${typeName}" is forbidden`,
|
2160
|
+
});
|
2161
|
+
},
|
2162
|
+
};
|
2163
|
+
},
|
2164
|
+
};
|
2165
|
+
|
2068
2166
|
const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
|
2069
2167
|
const RULE_NAME = 'no-unreachable-types';
|
2070
|
-
const rule$
|
2168
|
+
const rule$f = {
|
2071
2169
|
meta: {
|
2072
2170
|
messages: {
|
2073
2171
|
[UNREACHABLE_TYPE]: `Type "{{ typeName }}" is unreachable`,
|
@@ -2143,7 +2241,7 @@ const rule$e = {
|
|
2143
2241
|
|
2144
2242
|
const UNUSED_FIELD = 'UNUSED_FIELD';
|
2145
2243
|
const RULE_NAME$1 = 'no-unused-fields';
|
2146
|
-
const rule$
|
2244
|
+
const rule$g = {
|
2147
2245
|
meta: {
|
2148
2246
|
messages: {
|
2149
2247
|
[UNUSED_FIELD]: `Field "{{fieldName}}" is unused`,
|
@@ -2326,12 +2424,13 @@ function convertDescription(node) {
|
|
2326
2424
|
return [];
|
2327
2425
|
}
|
2328
2426
|
|
2427
|
+
// eslint-disable-next-line unicorn/better-regex
|
2329
2428
|
const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
|
2330
2429
|
const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
|
2331
2430
|
const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
|
2332
2431
|
const MESSAGE_INVALID_DATE = 'MESSAGE_INVALID_DATE';
|
2333
2432
|
const MESSAGE_CAN_BE_REMOVED = 'MESSAGE_CAN_BE_REMOVED';
|
2334
|
-
const rule$
|
2433
|
+
const rule$h = {
|
2335
2434
|
meta: {
|
2336
2435
|
type: 'suggestion',
|
2337
2436
|
docs: {
|
@@ -2434,7 +2533,7 @@ const rule$g = {
|
|
2434
2533
|
},
|
2435
2534
|
};
|
2436
2535
|
|
2437
|
-
const rule$
|
2536
|
+
const rule$i = {
|
2438
2537
|
meta: {
|
2439
2538
|
docs: {
|
2440
2539
|
description: `Require all deprecation directives to specify a reason.`,
|
@@ -2514,7 +2613,7 @@ function verifyRule(context, node) {
|
|
2514
2613
|
}
|
2515
2614
|
}
|
2516
2615
|
}
|
2517
|
-
const rule$
|
2616
|
+
const rule$j = {
|
2518
2617
|
meta: {
|
2519
2618
|
docs: {
|
2520
2619
|
category: 'Best Practices',
|
@@ -2579,7 +2678,7 @@ const rule$i = {
|
|
2579
2678
|
};
|
2580
2679
|
|
2581
2680
|
const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
|
2582
|
-
const rule$
|
2681
|
+
const rule$k = {
|
2583
2682
|
meta: {
|
2584
2683
|
type: 'suggestion',
|
2585
2684
|
docs: {
|
@@ -2747,7 +2846,7 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2747
2846
|
|
2748
2847
|
const REQUIRE_ID_WHEN_AVAILABLE = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2749
2848
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2750
|
-
const rule$
|
2849
|
+
const rule$l = {
|
2751
2850
|
meta: {
|
2752
2851
|
type: 'suggestion',
|
2753
2852
|
docs: {
|
@@ -2883,7 +2982,7 @@ const rule$k = {
|
|
2883
2982
|
},
|
2884
2983
|
};
|
2885
2984
|
|
2886
|
-
const rule$
|
2985
|
+
const rule$m = {
|
2887
2986
|
meta: {
|
2888
2987
|
docs: {
|
2889
2988
|
category: 'Best Practices',
|
@@ -3005,7 +3104,7 @@ const shouldIgnoreNode = ({ node, exceptions }) => {
|
|
3005
3104
|
}
|
3006
3105
|
return false;
|
3007
3106
|
};
|
3008
|
-
const rule$
|
3107
|
+
const rule$n = {
|
3009
3108
|
meta: {
|
3010
3109
|
type: 'suggestion',
|
3011
3110
|
docs: {
|
@@ -3119,7 +3218,7 @@ const rule$m = {
|
|
3119
3218
|
acceptedIdNames: ['id'],
|
3120
3219
|
acceptedIdTypes: ['ID'],
|
3121
3220
|
exceptions: {},
|
3122
|
-
...
|
3221
|
+
...context.options[0],
|
3123
3222
|
};
|
3124
3223
|
return {
|
3125
3224
|
ObjectTypeDefinition(node) {
|
@@ -3182,7 +3281,7 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3182
3281
|
});
|
3183
3282
|
}
|
3184
3283
|
};
|
3185
|
-
const rule$
|
3284
|
+
const rule$o = {
|
3186
3285
|
meta: {
|
3187
3286
|
type: 'suggestion',
|
3188
3287
|
docs: {
|
@@ -3241,7 +3340,7 @@ const rule$n = {
|
|
3241
3340
|
|
3242
3341
|
const RULE_NAME$4 = 'unique-operation-name';
|
3243
3342
|
const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
|
3244
|
-
const rule$
|
3343
|
+
const rule$p = {
|
3245
3344
|
meta: {
|
3246
3345
|
type: 'suggestion',
|
3247
3346
|
docs: {
|
@@ -3321,17 +3420,18 @@ const rules = {
|
|
3321
3420
|
'no-deprecated': rule$b,
|
3322
3421
|
'no-hashtag-description': rule$c,
|
3323
3422
|
'no-operation-name-suffix': rule$d,
|
3324
|
-
'no-
|
3325
|
-
'no-
|
3326
|
-
'
|
3327
|
-
'require-deprecation-
|
3328
|
-
'require-
|
3329
|
-
'require-
|
3330
|
-
'require-
|
3331
|
-
'
|
3332
|
-
'
|
3333
|
-
'
|
3334
|
-
'unique-
|
3423
|
+
'no-root-type': rule$e,
|
3424
|
+
'no-unreachable-types': rule$f,
|
3425
|
+
'no-unused-fields': rule$g,
|
3426
|
+
'require-deprecation-date': rule$h,
|
3427
|
+
'require-deprecation-reason': rule$i,
|
3428
|
+
'require-description': rule$j,
|
3429
|
+
'require-field-of-type-query-in-mutation-result': rule$k,
|
3430
|
+
'require-id-when-available': rule$l,
|
3431
|
+
'selection-set-depth': rule$m,
|
3432
|
+
'strict-id-in-types': rule$n,
|
3433
|
+
'unique-fragment-name': rule$o,
|
3434
|
+
'unique-operation-name': rule$p,
|
3335
3435
|
};
|
3336
3436
|
|
3337
3437
|
const RELEVANT_KEYWORDS = ['gql', 'graphql', '/* GraphQL */'];
|