@graphql-eslint/eslint-plugin 2.5.0-alpha-e34c5d6.0 → 3.0.0-alpha-3168a9b.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',
@@ -212,9 +239,14 @@ const loaderCache = new Proxy(Object.create(null), {
212
239
  return true;
213
240
  },
214
241
  });
215
- const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
216
- const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
217
- const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
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
+ ];
218
250
  var CaseStyle;
219
251
  (function (CaseStyle) {
220
252
  CaseStyle["camelCase"] = "camelCase";
@@ -265,7 +297,7 @@ function getLocation(loc, fieldName = '', offset) {
265
297
  }
266
298
 
267
299
  function extractRuleName(stack) {
268
- const match = (stack || '').match(/validation[/\\\\]rules[/\\\\](.*?)\.js:/) || [];
300
+ const match = (stack || '').match(/validation[/\\]rules[/\\](.*?)\.js:/) || [];
269
301
  return match[1] || null;
270
302
  }
271
303
  function validateDoc(sourceNode, context, schema, documentNode, rules, ruleName = null) {
@@ -626,38 +658,48 @@ const rule = {
626
658
  properties: {
627
659
  fields: {
628
660
  type: 'array',
629
- contains: {
661
+ uniqueItems: true,
662
+ minItems: 1,
663
+ items: {
630
664
  enum: fieldsEnum,
631
665
  },
632
- description: 'Fields of `type`, `interface`, and `input`.',
666
+ description: 'Fields of `type`, `interface`, and `input`',
633
667
  },
634
668
  values: {
635
669
  type: 'array',
636
- contains: {
670
+ uniqueItems: true,
671
+ minItems: 1,
672
+ items: {
637
673
  enum: valuesEnum,
638
674
  },
639
- description: 'Values of `enum`.',
675
+ description: 'Values of `enum`',
640
676
  },
641
677
  selections: {
642
678
  type: 'array',
643
- contains: {
679
+ uniqueItems: true,
680
+ minItems: 1,
681
+ items: {
644
682
  enum: selectionsEnum,
645
683
  },
646
- description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment`.',
684
+ description: 'Selections of operations (`query`, `mutation` and `subscription`) and `fragment`',
647
685
  },
648
686
  variables: {
649
687
  type: 'array',
650
- contains: {
688
+ uniqueItems: true,
689
+ minItems: 1,
690
+ items: {
651
691
  enum: variablesEnum,
652
692
  },
653
- description: 'Variables of operations (`query`, `mutation` and `subscription`).',
693
+ description: 'Variables of operations (`query`, `mutation` and `subscription`)',
654
694
  },
655
695
  arguments: {
656
696
  type: 'array',
657
- contains: {
697
+ uniqueItems: true,
698
+ minItems: 1,
699
+ items: {
658
700
  enum: argumentsEnum,
659
701
  },
660
- description: 'Arguments of fields and directives.',
702
+ description: 'Arguments of fields and directives',
661
703
  },
662
704
  },
663
705
  },
@@ -688,7 +730,7 @@ const rule = {
688
730
  const opts = context.options[0];
689
731
  const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
690
732
  const listeners = {};
691
- const fieldsSelector = [
733
+ const kinds = [
692
734
  fields.has(graphql.Kind.OBJECT_TYPE_DEFINITION) && [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION],
693
735
  fields.has(graphql.Kind.INTERFACE_TYPE_DEFINITION) && [graphql.Kind.INTERFACE_TYPE_DEFINITION, graphql.Kind.INTERFACE_TYPE_EXTENSION],
694
736
  fields.has(graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
@@ -696,8 +738,9 @@ const rule = {
696
738
  graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION,
697
739
  ],
698
740
  ]
699
- .flat()
700
- .join(',');
741
+ .filter(Boolean)
742
+ .flat();
743
+ const fieldsSelector = kinds.join(',');
701
744
  const hasEnumValues = ((_b = opts.values) === null || _b === void 0 ? void 0 : _b[0]) === graphql.Kind.ENUM_TYPE_DEFINITION;
702
745
  const selectionsSelector = (_c = opts.selections) === null || _c === void 0 ? void 0 : _c.join(',');
703
746
  const hasVariables = ((_d = opts.variables) === null || _d === void 0 ? void 0 : _d[0]) === graphql.Kind.OPERATION_DEFINITION;
@@ -1097,6 +1140,9 @@ const rule$5 = {
1097
1140
  },
1098
1141
  };
1099
1142
 
1143
+ const isObjectType = (node) => [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION].includes(node.type);
1144
+ const isQueryType = (node) => isObjectType(node) && node.name.value === 'Query';
1145
+ const isMutationType = (node) => isObjectType(node) && node.name.value === 'Mutation';
1100
1146
  const rule$6 = {
1101
1147
  meta: {
1102
1148
  type: 'suggestion',
@@ -1137,6 +1183,7 @@ const rule$6 = {
1137
1183
  schema: [
1138
1184
  {
1139
1185
  type: 'object',
1186
+ additionalProperties: false,
1140
1187
  properties: {
1141
1188
  checkInputType: {
1142
1189
  type: 'boolean',
@@ -1159,24 +1206,22 @@ const rule$6 = {
1159
1206
  description: 'Apply the rule to Mutations',
1160
1207
  },
1161
1208
  },
1162
- additionalProperties: false,
1163
1209
  },
1164
1210
  ],
1165
1211
  },
1166
1212
  create(context) {
1167
- var _a;
1168
1213
  const options = {
1169
- caseSensitiveInputType: true,
1170
1214
  checkInputType: false,
1171
- checkMutations: true,
1215
+ caseSensitiveInputType: true,
1172
1216
  checkQueries: false,
1173
- ...(_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a[0],
1217
+ checkMutations: true,
1218
+ ...context.options[0],
1174
1219
  };
1175
1220
  const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
1176
1221
  const listeners = {
1177
- 'FieldDefinition > InputValueDefinition': node => {
1178
- const name = node.name.value;
1179
- if (name !== 'input' && shouldCheckType(node.parent.parent)) {
1222
+ 'FieldDefinition > InputValueDefinition[name.value!=input]'(node) {
1223
+ if (shouldCheckType(node.parent.parent)) {
1224
+ const name = node.name.value;
1180
1225
  context.report({
1181
1226
  loc: getLocation(node.loc, name),
1182
1227
  message: `Input "${name}" should be called "input"`,
@@ -1184,11 +1229,11 @@ const rule$6 = {
1184
1229
  }
1185
1230
  },
1186
1231
  };
1187
- if (options === null || options === void 0 ? void 0 : options.checkInputType) {
1188
- listeners['FieldDefinition > InputValueDefinition NamedType'] = node => {
1232
+ if (options.checkInputType) {
1233
+ listeners['FieldDefinition > InputValueDefinition NamedType'] = (node) => {
1189
1234
  const findInputType = item => {
1190
1235
  let currentNode = item;
1191
- while (currentNode.type !== 'InputValueDefinition') {
1236
+ while (currentNode.type !== graphql.Kind.INPUT_VALUE_DEFINITION) {
1192
1237
  currentNode = currentNode.parent;
1193
1238
  }
1194
1239
  return currentNode;
@@ -1405,69 +1450,40 @@ const rule$7 = {
1405
1450
  },
1406
1451
  };
1407
1452
 
1408
- const formats = {
1409
- camelCase: /^[a-z][^_]*$/g,
1410
- PascalCase: /^[A-Z][^_]*$/g,
1411
- snake_case: /^[a-z_][a-z0-9_]*$/g,
1412
- UPPER_CASE: /^[A-Z_][A-Z0-9_]*$/g,
1413
- };
1414
- const acceptedStyles = [
1415
- 'camelCase',
1416
- 'PascalCase',
1417
- 'snake_case',
1418
- 'UPPER_CASE',
1453
+ const FIELDS_KINDS = [
1454
+ graphql.Kind.FIELD_DEFINITION,
1455
+ graphql.Kind.INPUT_VALUE_DEFINITION,
1456
+ graphql.Kind.VARIABLE_DEFINITION,
1457
+ graphql.Kind.ARGUMENT,
1458
+ graphql.Kind.DIRECTIVE_DEFINITION,
1419
1459
  ];
1420
- function checkNameFormat(params) {
1421
- const { value, style, leadingUnderscore, trailingUnderscore, suffix, prefix, forbiddenPrefixes, forbiddenSuffixes, } = params;
1422
- let name = value;
1423
- if (leadingUnderscore === 'allow') {
1424
- [, name] = name.match(/^_*(.*)$/);
1425
- }
1426
- if (trailingUnderscore === 'allow') {
1427
- name = name.replace(/_*$/, '');
1428
- }
1429
- if (prefix && !name.startsWith(prefix)) {
1430
- return {
1431
- ok: false,
1432
- errorMessage: '{{nodeType}} name "{{nodeName}}" should have "{{prefix}}" prefix',
1433
- };
1434
- }
1435
- if (suffix && !name.endsWith(suffix)) {
1436
- return {
1437
- ok: false,
1438
- errorMessage: '{{nodeType}} name "{{nodeName}}" should have "{{suffix}}" suffix',
1439
- };
1440
- }
1441
- if (style && !acceptedStyles.includes(style)) {
1442
- return {
1443
- ok: false,
1444
- errorMessage: `{{nodeType}} name "{{nodeName}}" should be in one of the following options: ${acceptedStyles.join(',')}`,
1445
- };
1446
- }
1447
- if (forbiddenPrefixes.some(forbiddenPrefix => name.startsWith(forbiddenPrefix))) {
1448
- return {
1449
- ok: false,
1450
- errorMessage: '{{nodeType}} "{{nodeName}}" should not have one of the following prefix(es): {{forbiddenPrefixes}}',
1451
- };
1452
- }
1453
- if (forbiddenSuffixes.some(forbiddenSuffix => name.endsWith(forbiddenSuffix))) {
1454
- return {
1455
- ok: false,
1456
- errorMessage: '{{nodeType}} "{{nodeName}}" should not have one of the following suffix(es): {{forbiddenSuffixes}}',
1457
- };
1458
- }
1459
- if (!formats[style]) {
1460
- return { ok: true };
1461
- }
1462
- const ok = new RegExp(formats[style]).test(name);
1463
- if (ok) {
1464
- return { ok: true };
1465
- }
1466
- return {
1467
- ok: false,
1468
- errorMessage: '{{nodeType}} name "{{nodeName}}" should be in {{format}} format',
1469
- };
1470
- }
1460
+ const KindToDisplayName = {
1461
+ // types
1462
+ [graphql.Kind.OBJECT_TYPE_DEFINITION]: 'Type',
1463
+ [graphql.Kind.INTERFACE_TYPE_DEFINITION]: 'Interface',
1464
+ [graphql.Kind.ENUM_TYPE_DEFINITION]: 'Enumerator',
1465
+ [graphql.Kind.SCALAR_TYPE_DEFINITION]: 'Scalar',
1466
+ [graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'Input type',
1467
+ [graphql.Kind.UNION_TYPE_DEFINITION]: 'Union',
1468
+ // fields
1469
+ [graphql.Kind.FIELD_DEFINITION]: 'Field',
1470
+ [graphql.Kind.INPUT_VALUE_DEFINITION]: 'Input property',
1471
+ [graphql.Kind.VARIABLE_DEFINITION]: 'Variable',
1472
+ [graphql.Kind.ARGUMENT]: 'Argument',
1473
+ [graphql.Kind.DIRECTIVE_DEFINITION]: 'Directive',
1474
+ // rest
1475
+ [graphql.Kind.ENUM_VALUE_DEFINITION]: 'Enumeration value',
1476
+ [graphql.Kind.OPERATION_DEFINITION]: 'Operation',
1477
+ [graphql.Kind.FRAGMENT_DEFINITION]: 'Fragment',
1478
+ };
1479
+ const StyleToRegex = {
1480
+ camelCase: /^[a-z][\dA-Za-z]*$/,
1481
+ PascalCase: /^[A-Z][\dA-Za-z]*$/,
1482
+ snake_case: /^[a-z][\d_a-z]*[\da-z]$/,
1483
+ UPPER_CASE: /^[A-Z][\dA-Z_]*[\dA-Z]$/,
1484
+ };
1485
+ const ALLOWED_KINDS = Object.keys(KindToDisplayName).sort();
1486
+ const ALLOWED_STYLES = Object.keys(StyleToRegex);
1471
1487
  const schemaOption$1 = {
1472
1488
  oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
1473
1489
  };
@@ -1482,89 +1498,120 @@ const rule$8 = {
1482
1498
  examples: [
1483
1499
  {
1484
1500
  title: 'Incorrect',
1485
- usage: [{ ObjectTypeDefinition: 'PascalCase' }],
1501
+ usage: [{ types: 'PascalCase', fields: 'camelCase' }],
1486
1502
  code: /* GraphQL */ `
1487
- type someTypeName {
1488
- f: String!
1503
+ type user {
1504
+ first_name: String!
1489
1505
  }
1490
1506
  `,
1491
1507
  },
1492
1508
  {
1493
1509
  title: 'Correct',
1494
- usage: [{ FieldDefinition: 'camelCase', ObjectTypeDefinition: 'PascalCase' }],
1510
+ usage: [{ types: 'PascalCase', fields: 'camelCase' }],
1495
1511
  code: /* GraphQL */ `
1496
- type SomeTypeName {
1497
- someFieldName: String
1512
+ type User {
1513
+ firstName: String
1498
1514
  }
1499
1515
  `,
1500
1516
  },
1501
1517
  ],
1518
+ optionsForConfig: [
1519
+ {
1520
+ types: 'PascalCase',
1521
+ fields: 'camelCase',
1522
+ overrides: {
1523
+ EnumValueDefinition: 'UPPER_CASE',
1524
+ OperationDefinition: {
1525
+ style: 'PascalCase',
1526
+ forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'],
1527
+ forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'],
1528
+ },
1529
+ FragmentDefinition: {
1530
+ style: 'PascalCase',
1531
+ forbiddenPrefixes: ['Fragment'],
1532
+ forbiddenSuffixes: ['Fragment'],
1533
+ },
1534
+ 'FieldDefinition[parent.name.value=Query]': {
1535
+ forbiddenPrefixes: ['query', 'get'],
1536
+ forbiddenSuffixes: ['Query'],
1537
+ },
1538
+ 'FieldDefinition[parent.name.value=Mutation]': {
1539
+ forbiddenPrefixes: ['mutation'],
1540
+ forbiddenSuffixes: ['Mutation'],
1541
+ },
1542
+ 'FieldDefinition[parent.name.value=Subscription]': {
1543
+ forbiddenPrefixes: ['subscription'],
1544
+ forbiddenSuffixes: ['Subscription'],
1545
+ },
1546
+ },
1547
+ },
1548
+ ],
1502
1549
  },
1503
1550
  schema: {
1504
1551
  definitions: {
1505
1552
  asString: {
1506
- type: 'string',
1507
- description: `One of: ${acceptedStyles.map(t => `\`${t}\``).join(', ')}`,
1508
- enum: acceptedStyles,
1553
+ enum: ALLOWED_STYLES,
1554
+ description: `One of: ${ALLOWED_STYLES.map(t => `\`${t}\``).join(', ')}`,
1509
1555
  },
1510
1556
  asObject: {
1511
1557
  type: 'object',
1558
+ additionalProperties: false,
1512
1559
  properties: {
1513
- style: {
1514
- type: 'string',
1515
- enum: acceptedStyles,
1516
- },
1517
- prefix: {
1518
- type: 'string',
1519
- },
1520
- suffix: {
1521
- type: 'string',
1522
- },
1560
+ style: { enum: ALLOWED_STYLES },
1561
+ prefix: { type: 'string' },
1562
+ suffix: { type: 'string' },
1523
1563
  forbiddenPrefixes: {
1524
- additionalItems: false,
1525
1564
  type: 'array',
1565
+ uniqueItems: true,
1526
1566
  minItems: 1,
1527
- items: {
1528
- type: 'string',
1529
- },
1567
+ items: { type: 'string' },
1530
1568
  },
1531
1569
  forbiddenSuffixes: {
1532
- additionalItems: false,
1533
1570
  type: 'array',
1571
+ uniqueItems: true,
1534
1572
  minItems: 1,
1535
- items: {
1536
- type: 'string',
1537
- },
1573
+ items: { type: 'string' },
1538
1574
  },
1539
1575
  },
1540
1576
  },
1541
1577
  },
1542
- $schema: 'http://json-schema.org/draft-04/schema#',
1543
1578
  type: 'array',
1579
+ maxItems: 1,
1544
1580
  items: {
1545
1581
  type: 'object',
1582
+ additionalProperties: false,
1546
1583
  properties: {
1547
- [graphql.Kind.FIELD_DEFINITION]: schemaOption$1,
1548
- [graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: schemaOption$1,
1549
- [graphql.Kind.ENUM_VALUE_DEFINITION]: schemaOption$1,
1550
- [graphql.Kind.INPUT_VALUE_DEFINITION]: schemaOption$1,
1551
- [graphql.Kind.OBJECT_TYPE_DEFINITION]: schemaOption$1,
1552
- [graphql.Kind.INTERFACE_TYPE_DEFINITION]: schemaOption$1,
1553
- [graphql.Kind.ENUM_TYPE_DEFINITION]: schemaOption$1,
1554
- [graphql.Kind.UNION_TYPE_DEFINITION]: schemaOption$1,
1555
- [graphql.Kind.SCALAR_TYPE_DEFINITION]: schemaOption$1,
1556
- [graphql.Kind.OPERATION_DEFINITION]: schemaOption$1,
1557
- [graphql.Kind.FRAGMENT_DEFINITION]: schemaOption$1,
1558
- QueryDefinition: schemaOption$1,
1559
- leadingUnderscore: {
1560
- type: 'string',
1561
- enum: ['allow', 'forbid'],
1562
- default: 'forbid',
1584
+ types: {
1585
+ ...schemaOption$1,
1586
+ description: `Includes:\n\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
1563
1587
  },
1564
- trailingUnderscore: {
1565
- type: 'string',
1566
- enum: ['allow', 'forbid'],
1567
- default: 'forbid',
1588
+ fields: {
1589
+ ...schemaOption$1,
1590
+ description: `Includes:\n\n${FIELDS_KINDS.map(kind => `- \`${kind}\``).join('\n')}`,
1591
+ },
1592
+ allowLeadingUnderscore: {
1593
+ type: 'boolean',
1594
+ default: false,
1595
+ },
1596
+ allowTrailingUnderscore: {
1597
+ type: 'boolean',
1598
+ default: false,
1599
+ },
1600
+ overrides: {
1601
+ type: 'object',
1602
+ additionalProperties: false,
1603
+ description: [
1604
+ 'May contain the following `ASTNode` names:',
1605
+ '',
1606
+ ...ALLOWED_KINDS.map(kind => `- \`${kind}\``),
1607
+ '',
1608
+ "> It's also possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with `ASTNode` name",
1609
+ '>',
1610
+ '> Example: pattern property `FieldDefinition[parent.name.value=Query]` will match only fields for type `Query`',
1611
+ ].join('\n'),
1612
+ patternProperties: {
1613
+ [`^(${ALLOWED_KINDS.join('|')})(.+)?$`]: schemaOption$1,
1614
+ },
1568
1615
  },
1569
1616
  },
1570
1617
  },
@@ -1572,136 +1619,83 @@ const rule$8 = {
1572
1619
  },
1573
1620
  create(context) {
1574
1621
  const options = {
1575
- leadingUnderscore: 'forbid',
1576
- trailingUnderscore: 'forbid',
1577
- ...(context.options[0] || {}),
1622
+ overrides: {},
1623
+ ...context.options[0],
1578
1624
  };
1579
- const checkNode = (node, property, nodeType) => {
1580
- const { style, suffix = '', prefix = '', forbiddenPrefixes = [], forbiddenSuffixes = [] } = property;
1581
- const result = checkNameFormat({
1582
- value: node.value,
1583
- style,
1584
- leadingUnderscore: options.leadingUnderscore,
1585
- trailingUnderscore: options.trailingUnderscore,
1586
- prefix,
1587
- suffix,
1588
- forbiddenPrefixes,
1589
- forbiddenSuffixes,
1590
- });
1591
- if (result.ok === false) {
1625
+ function normalisePropertyOption(kind) {
1626
+ let style = options.overrides[kind];
1627
+ if (!style) {
1628
+ style = TYPES_KINDS.includes(kind) ? options.types : options.fields;
1629
+ }
1630
+ return typeof style === 'object' ? style : { style };
1631
+ }
1632
+ const checkNode = (selector) => (node) => {
1633
+ const { name } = node.kind === graphql.Kind.VARIABLE_DEFINITION ? node.variable : node;
1634
+ if (!name) {
1635
+ return;
1636
+ }
1637
+ const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
1638
+ const nodeType = KindToDisplayName[node.kind] || node.kind;
1639
+ const nodeName = name.value;
1640
+ const errorMessage = getErrorMessage();
1641
+ if (errorMessage) {
1592
1642
  context.report({
1593
- loc: getLocation(node.loc, node.value),
1594
- message: result.errorMessage,
1595
- data: {
1596
- prefix,
1597
- suffix,
1598
- format: style,
1599
- forbiddenPrefixes: forbiddenPrefixes.join(', '),
1600
- forbiddenSuffixes: forbiddenSuffixes.join(', '),
1601
- nodeType,
1602
- nodeName: node.value,
1603
- },
1643
+ loc: getLocation(name.loc, name.value),
1644
+ message: `${nodeType} "${nodeName}" should ${errorMessage}`,
1604
1645
  });
1605
1646
  }
1606
- };
1607
- const normalisePropertyOption = (value) => {
1608
- if (typeof value === 'object') {
1609
- return value;
1610
- }
1611
- return {
1612
- style: value,
1613
- prefix: '',
1614
- suffix: '',
1615
- };
1616
- };
1617
- return {
1618
- Name: node => {
1619
- if (node.value.startsWith('_') && options.leadingUnderscore === 'forbid') {
1620
- context.report({
1621
- loc: getLocation(node.loc, node.value),
1622
- message: 'Leading underscores are not allowed',
1623
- });
1624
- }
1625
- if (node.value.endsWith('_') && options.trailingUnderscore === 'forbid') {
1626
- context.report({
1627
- loc: getLocation(node.loc, node.value),
1628
- message: 'Trailing underscores are not allowed',
1629
- });
1630
- }
1631
- },
1632
- ObjectTypeDefinition: node => {
1633
- if (options.ObjectTypeDefinition) {
1634
- const property = normalisePropertyOption(options.ObjectTypeDefinition);
1635
- checkNode(node.name, property, 'Type');
1636
- }
1637
- },
1638
- InterfaceTypeDefinition: node => {
1639
- if (options.InterfaceTypeDefinition) {
1640
- const property = normalisePropertyOption(options.InterfaceTypeDefinition);
1641
- checkNode(node.name, property, 'Interface');
1642
- }
1643
- },
1644
- EnumTypeDefinition: node => {
1645
- if (options.EnumTypeDefinition) {
1646
- const property = normalisePropertyOption(options.EnumTypeDefinition);
1647
- checkNode(node.name, property, 'Enumerator');
1648
- }
1649
- },
1650
- InputObjectTypeDefinition: node => {
1651
- if (options.InputObjectTypeDefinition) {
1652
- const property = normalisePropertyOption(options.InputObjectTypeDefinition);
1653
- checkNode(node.name, property, 'Input type');
1654
- }
1655
- },
1656
- FieldDefinition: (node) => {
1657
- if (options.QueryDefinition && isQueryType(node.parent)) {
1658
- const property = normalisePropertyOption(options.QueryDefinition);
1659
- checkNode(node.name, property, 'Query');
1647
+ function getErrorMessage() {
1648
+ let name = nodeName;
1649
+ if (options.allowLeadingUnderscore) {
1650
+ name = name.replace(/^_*/, '');
1660
1651
  }
1661
- if (options.FieldDefinition && !isQueryType(node.parent)) {
1662
- const property = normalisePropertyOption(options.FieldDefinition);
1663
- checkNode(node.name, property, 'Field');
1652
+ if (options.allowTrailingUnderscore) {
1653
+ name = name.replace(/_*$/, '');
1664
1654
  }
1665
- },
1666
- EnumValueDefinition: node => {
1667
- if (options.EnumValueDefinition) {
1668
- const property = normalisePropertyOption(options.EnumValueDefinition);
1669
- checkNode(node.name, property, 'Enumeration value');
1655
+ if (prefix && !name.startsWith(prefix)) {
1656
+ return `have "${prefix}" prefix`;
1670
1657
  }
1671
- },
1672
- InputValueDefinition: node => {
1673
- if (options.InputValueDefinition) {
1674
- const property = normalisePropertyOption(options.InputValueDefinition);
1675
- checkNode(node.name, property, 'Input property');
1658
+ if (suffix && !name.endsWith(suffix)) {
1659
+ return `have "${suffix}" suffix`;
1676
1660
  }
1677
- },
1678
- OperationDefinition: node => {
1679
- if (options.OperationDefinition) {
1680
- const property = normalisePropertyOption(options.OperationDefinition);
1681
- if (node.name) {
1682
- checkNode(node.name, property, 'Operation');
1683
- }
1661
+ const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
1662
+ if (forbiddenPrefix) {
1663
+ return `not have "${forbiddenPrefix}" prefix`;
1684
1664
  }
1685
- },
1686
- FragmentDefinition: node => {
1687
- if (options.FragmentDefinition) {
1688
- const property = normalisePropertyOption(options.FragmentDefinition);
1689
- checkNode(node.name, property, 'Fragment');
1665
+ const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
1666
+ if (forbiddenSuffix) {
1667
+ return `not have "${forbiddenSuffix}" suffix`;
1690
1668
  }
1691
- },
1692
- ScalarTypeDefinition: node => {
1693
- if (options.ScalarTypeDefinition) {
1694
- const property = normalisePropertyOption(options.ScalarTypeDefinition);
1695
- checkNode(node.name, property, 'Scalar');
1669
+ if (style && !ALLOWED_STYLES.includes(style)) {
1670
+ return `be in one of the following options: ${ALLOWED_STYLES.join(', ')}`;
1696
1671
  }
1697
- },
1698
- UnionTypeDefinition: node => {
1699
- if (options.UnionTypeDefinition) {
1700
- const property = normalisePropertyOption(options.UnionTypeDefinition);
1701
- checkNode(node.name, property, 'Union');
1672
+ const caseRegex = StyleToRegex[style];
1673
+ if (caseRegex && !caseRegex.test(name)) {
1674
+ return `be in ${style} format`;
1702
1675
  }
1703
- },
1676
+ }
1704
1677
  };
1678
+ const checkUnderscore = (node) => {
1679
+ const name = node.value;
1680
+ context.report({
1681
+ loc: getLocation(node.loc, name),
1682
+ message: `${name.startsWith('_') ? 'Leading' : 'Trailing'} underscores are not allowed`,
1683
+ });
1684
+ };
1685
+ const listeners = {};
1686
+ if (!options.allowLeadingUnderscore) {
1687
+ listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1688
+ }
1689
+ if (!options.allowTrailingUnderscore) {
1690
+ listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1691
+ }
1692
+ const selectors = new Set([options.types && TYPES_KINDS, options.fields && FIELDS_KINDS, Object.keys(options.overrides)]
1693
+ .flat()
1694
+ .filter(Boolean));
1695
+ for (const selector of selectors) {
1696
+ listeners[selector] = checkNode(selector);
1697
+ }
1698
+ return listeners;
1705
1699
  },
1706
1700
  };
1707
1701
 
@@ -2418,6 +2412,7 @@ function convertDescription(node) {
2418
2412
  return [];
2419
2413
  }
2420
2414
 
2415
+ // eslint-disable-next-line unicorn/better-regex
2421
2416
  const DATE_REGEX = /^\d{2}\/\d{2}\/\d{4}$/;
2422
2417
  const MESSAGE_REQUIRE_DATE = 'MESSAGE_REQUIRE_DATE';
2423
2418
  const MESSAGE_INVALID_FORMAT = 'MESSAGE_INVALID_FORMAT';
@@ -3211,7 +3206,7 @@ const rule$n = {
3211
3206
  acceptedIdNames: ['id'],
3212
3207
  acceptedIdTypes: ['ID'],
3213
3208
  exceptions: {},
3214
- ...(context.options[0] || {}),
3209
+ ...context.options[0],
3215
3210
  };
3216
3211
  return {
3217
3212
  ObjectTypeDefinition(node) {