@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/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': 'error',
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 isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
215
- const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
216
- const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
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[/\\\\]rules[/\\\\](.*?)\.js:/) || [];
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
- contains: {
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
- contains: {
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
- contains: {
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
- contains: {
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
- contains: {
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 fieldsSelector = [
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
- .flat()
699
- .join(',');
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
- checkMutations: true,
1214
+ caseSensitiveInputType: true,
1171
1215
  checkQueries: false,
1172
- ...(_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a[0],
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': node => {
1177
- const name = node.name.value;
1178
- if (name !== 'input' && shouldCheckType(node.parent.parent)) {
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 === null || options === void 0 ? void 0 : options.checkInputType) {
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 !== 'InputValueDefinition') {
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 formats = {
1408
- camelCase: /^[a-z][^_]*$/g,
1409
- PascalCase: /^[A-Z][^_]*$/g,
1410
- snake_case: /^[a-z_][a-z0-9_]*$/g,
1411
- UPPER_CASE: /^[A-Z_][A-Z0-9_]*$/g,
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
- function checkNameFormat(params) {
1420
- const { value, style, leadingUnderscore, trailingUnderscore, suffix, prefix, forbiddenPrefixes, forbiddenSuffixes, } = params;
1421
- let name = value;
1422
- if (leadingUnderscore === 'allow') {
1423
- [, name] = name.match(/^_*(.*)$/);
1424
- }
1425
- if (trailingUnderscore === 'allow') {
1426
- name = name.replace(/_*$/, '');
1427
- }
1428
- if (prefix && !name.startsWith(prefix)) {
1429
- return {
1430
- ok: false,
1431
- errorMessage: '{{nodeType}} name "{{nodeName}}" should have "{{prefix}}" prefix',
1432
- };
1433
- }
1434
- if (suffix && !name.endsWith(suffix)) {
1435
- return {
1436
- ok: false,
1437
- errorMessage: '{{nodeType}} name "{{nodeName}}" should have "{{suffix}}" suffix',
1438
- };
1439
- }
1440
- if (style && !acceptedStyles.includes(style)) {
1441
- return {
1442
- ok: false,
1443
- errorMessage: `{{nodeType}} name "{{nodeName}}" should be in one of the following options: ${acceptedStyles.join(',')}`,
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: [{ ObjectTypeDefinition: 'PascalCase' }],
1500
+ usage: [{ types: 'PascalCase', fields: 'camelCase' }],
1485
1501
  code: /* GraphQL */ `
1486
- type someTypeName {
1487
- f: String!
1502
+ type user {
1503
+ first_name: String!
1488
1504
  }
1489
1505
  `,
1490
1506
  },
1491
1507
  {
1492
1508
  title: 'Correct',
1493
- usage: [{ FieldDefinition: 'camelCase', ObjectTypeDefinition: 'PascalCase' }],
1509
+ usage: [{ types: 'PascalCase', fields: 'camelCase' }],
1494
1510
  code: /* GraphQL */ `
1495
- type SomeTypeName {
1496
- someFieldName: String
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
- type: 'string',
1506
- description: `One of: ${acceptedStyles.map(t => `\`${t}\``).join(', ')}`,
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
- type: 'string',
1514
- enum: acceptedStyles,
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
- [graphql.Kind.FIELD_DEFINITION]: schemaOption$1,
1547
- [graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: schemaOption$1,
1548
- [graphql.Kind.ENUM_VALUE_DEFINITION]: schemaOption$1,
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
- trailingUnderscore: {
1564
- type: 'string',
1565
- enum: ['allow', 'forbid'],
1566
- default: 'forbid',
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
- leadingUnderscore: 'forbid',
1575
- trailingUnderscore: 'forbid',
1576
- ...(context.options[0] || {}),
1621
+ overrides: {},
1622
+ ...context.options[0],
1577
1623
  };
1578
- const checkNode = (node, property, nodeType) => {
1579
- const { style, suffix = '', prefix = '', forbiddenPrefixes = [], forbiddenSuffixes = [] } = property;
1580
- const result = checkNameFormat({
1581
- value: node.value,
1582
- style,
1583
- leadingUnderscore: options.leadingUnderscore,
1584
- trailingUnderscore: options.trailingUnderscore,
1585
- prefix,
1586
- suffix,
1587
- forbiddenPrefixes,
1588
- forbiddenSuffixes,
1589
- });
1590
- if (result.ok === false) {
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(node.loc, node.value),
1593
- message: result.errorMessage,
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
- const normalisePropertyOption = (value) => {
1607
- if (typeof value === 'object') {
1608
- return value;
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 (node.value.endsWith('_') && options.trailingUnderscore === 'forbid') {
1625
- context.report({
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
- ObjectTypeDefinition: node => {
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
- InterfaceTypeDefinition: node => {
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
- EnumTypeDefinition: node => {
1644
- if (options.EnumTypeDefinition) {
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
- InputObjectTypeDefinition: node => {
1650
- if (options.InputObjectTypeDefinition) {
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
- FieldDefinition: (node) => {
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
- if (options.FieldDefinition && !isQueryType(node.parent)) {
1661
- const property = normalisePropertyOption(options.FieldDefinition);
1662
- checkNode(node.name, property, 'Field');
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.deprecationReason) {
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.deprecationReason) {
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: [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.FIELD_DEFINITION] }],
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: [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.FIELD_DEFINITION] }],
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
- ...(context.options[0] || {}),
3117
+ ...context.options[0],
3123
3118
  };
3124
3119
  return {
3125
3120
  ObjectTypeDefinition(node) {