@graphql-eslint/eslint-plugin 3.1.0 → 3.2.0-alpha-45f5fcb.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
@@ -286,14 +286,6 @@ const TYPES_KINDS = [
286
286
  graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
287
287
  graphql.Kind.UNION_TYPE_DEFINITION,
288
288
  ];
289
- var CaseStyle;
290
- (function (CaseStyle) {
291
- CaseStyle["camelCase"] = "camelCase";
292
- CaseStyle["pascalCase"] = "PascalCase";
293
- CaseStyle["snakeCase"] = "snake_case";
294
- CaseStyle["upperCase"] = "UPPER_CASE";
295
- CaseStyle["kebabCase"] = "kebab-case";
296
- })(CaseStyle || (CaseStyle = {}));
297
289
  const pascalCase = (str) => lowerCase(str)
298
290
  .split(' ')
299
291
  .map(word => word.charAt(0).toUpperCase() + word.slice(1))
@@ -304,15 +296,15 @@ const camelCase = (str) => {
304
296
  };
305
297
  const convertCase = (style, str) => {
306
298
  switch (style) {
307
- case CaseStyle.camelCase:
299
+ case 'camelCase':
308
300
  return camelCase(str);
309
- case CaseStyle.pascalCase:
301
+ case 'PascalCase':
310
302
  return pascalCase(str);
311
- case CaseStyle.snakeCase:
303
+ case 'snake_case':
312
304
  return lowerCase(str).replace(/ /g, '_');
313
- case CaseStyle.upperCase:
305
+ case 'UPPER_CASE':
314
306
  return lowerCase(str).replace(/ /g, '_').toUpperCase();
315
- case CaseStyle.kebabCase:
307
+ case 'kebab-case':
316
308
  return lowerCase(str).replace(/ /g, '-');
317
309
  }
318
310
  };
@@ -1047,13 +1039,7 @@ const rule$2 = {
1047
1039
  const MATCH_EXTENSION = 'MATCH_EXTENSION';
1048
1040
  const MATCH_STYLE = 'MATCH_STYLE';
1049
1041
  const ACCEPTED_EXTENSIONS = ['.gql', '.graphql'];
1050
- const CASE_STYLES = [
1051
- CaseStyle.camelCase,
1052
- CaseStyle.pascalCase,
1053
- CaseStyle.snakeCase,
1054
- CaseStyle.upperCase,
1055
- CaseStyle.kebabCase,
1056
- ];
1042
+ const CASE_STYLES = ['camelCase', 'PascalCase', 'snake_case', 'UPPER_CASE', 'kebab-case'];
1057
1043
  const schemaOption = {
1058
1044
  oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
1059
1045
  };
@@ -1077,7 +1063,7 @@ const rule$3 = {
1077
1063
  },
1078
1064
  {
1079
1065
  title: 'Correct',
1080
- usage: [{ query: CaseStyle.snakeCase }],
1066
+ usage: [{ query: 'snake_case' }],
1081
1067
  code: /* GraphQL */ `
1082
1068
  # user_by_id.gql
1083
1069
  query UserById {
@@ -1091,7 +1077,7 @@ const rule$3 = {
1091
1077
  },
1092
1078
  {
1093
1079
  title: 'Correct',
1094
- usage: [{ fragment: { style: CaseStyle.kebabCase, suffix: '.fragment' } }],
1080
+ usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
1095
1081
  code: /* GraphQL */ `
1096
1082
  # user-fields.fragment.gql
1097
1083
  fragment user_fields on User {
@@ -1102,7 +1088,7 @@ const rule$3 = {
1102
1088
  },
1103
1089
  {
1104
1090
  title: 'Correct',
1105
- usage: [{ mutation: { style: CaseStyle.pascalCase, suffix: 'Mutation' } }],
1091
+ usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
1106
1092
  code: /* GraphQL */ `
1107
1093
  # DeleteUserMutation.gql
1108
1094
  mutation DELETE_USER {
@@ -1122,7 +1108,7 @@ const rule$3 = {
1122
1108
  },
1123
1109
  {
1124
1110
  title: 'Incorrect',
1125
- usage: [{ query: CaseStyle.pascalCase }],
1111
+ usage: [{ query: 'PascalCase' }],
1126
1112
  code: /* GraphQL */ `
1127
1113
  # user-by-id.gql
1128
1114
  query UserById {
@@ -1137,10 +1123,10 @@ const rule$3 = {
1137
1123
  ],
1138
1124
  configOptions: [
1139
1125
  {
1140
- query: CaseStyle.kebabCase,
1141
- mutation: CaseStyle.kebabCase,
1142
- subscription: CaseStyle.kebabCase,
1143
- fragment: CaseStyle.kebabCase,
1126
+ query: 'kebab-case',
1127
+ mutation: 'kebab-case',
1128
+ subscription: 'kebab-case',
1129
+ fragment: 'kebab-case',
1144
1130
  },
1145
1131
  ],
1146
1132
  },
@@ -1157,25 +1143,22 @@ const rule$3 = {
1157
1143
  asObject: {
1158
1144
  type: 'object',
1159
1145
  additionalProperties: false,
1146
+ minProperties: 1,
1160
1147
  properties: {
1161
- style: {
1162
- enum: CASE_STYLES,
1163
- },
1164
- suffix: {
1165
- type: 'string',
1166
- },
1148
+ style: { enum: CASE_STYLES },
1149
+ suffix: { type: 'string' },
1167
1150
  },
1168
1151
  },
1169
1152
  },
1170
1153
  type: 'array',
1154
+ minItems: 1,
1171
1155
  maxItems: 1,
1172
1156
  items: {
1173
1157
  type: 'object',
1174
1158
  additionalProperties: false,
1159
+ minProperties: 1,
1175
1160
  properties: {
1176
- fileExtension: {
1177
- enum: ACCEPTED_EXTENSIONS,
1178
- },
1161
+ fileExtension: { enum: ACCEPTED_EXTENSIONS },
1179
1162
  query: schemaOption,
1180
1163
  mutation: schemaOption,
1181
1164
  subscription: schemaOption,
@@ -1230,7 +1213,7 @@ const rule$3 = {
1230
1213
  option = { style: option };
1231
1214
  }
1232
1215
  const expectedExtension = options.fileExtension || fileExtension;
1233
- const expectedFilename = convertCase(option.style, docName) + (option.suffix || '') + expectedExtension;
1216
+ const expectedFilename = (option.style ? convertCase(option.style, docName) : filename) + (option.suffix || '') + expectedExtension;
1234
1217
  const filenameWithExtension = filename + expectedExtension;
1235
1218
  if (expectedFilename !== filenameWithExtension) {
1236
1219
  context.report({
@@ -1382,6 +1365,7 @@ const rule$4 = {
1382
1365
  ],
1383
1366
  },
1384
1367
  },
1368
+ hasSuggestions: true,
1385
1369
  schema: {
1386
1370
  definitions: {
1387
1371
  asString: {
@@ -1456,65 +1440,87 @@ const rule$4 = {
1456
1440
  const style = restOptions[kind] || types;
1457
1441
  return typeof style === 'object' ? style : { style };
1458
1442
  }
1459
- const checkNode = (selector) => (node) => {
1460
- const { name } = node.kind === graphql.Kind.VARIABLE_DEFINITION ? node.variable : node;
1461
- if (!name) {
1443
+ const checkNode = (selector) => (n) => {
1444
+ const { name: node } = n.kind === graphql.Kind.VARIABLE_DEFINITION ? n.variable : n;
1445
+ if (!node) {
1462
1446
  return;
1463
1447
  }
1464
1448
  const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
1465
- const nodeType = KindToDisplayName[node.kind] || node.kind;
1466
- const nodeName = name.value;
1467
- const errorMessage = getErrorMessage();
1468
- if (errorMessage) {
1449
+ const nodeType = KindToDisplayName[n.kind] || n.kind;
1450
+ const nodeName = node.value;
1451
+ const error = getError();
1452
+ if (error) {
1453
+ const { errorMessage, renameToName } = error;
1469
1454
  context.report({
1470
- loc: getLocation(name.loc, name.value),
1455
+ loc: getLocation(node.loc, node.value),
1471
1456
  message: `${nodeType} "${nodeName}" should ${errorMessage}`,
1457
+ suggest: [
1458
+ {
1459
+ desc: `Rename to "${renameToName}"`,
1460
+ fix: fixer => fixer.replaceText(node, renameToName),
1461
+ },
1462
+ ],
1472
1463
  });
1473
1464
  }
1474
- function getErrorMessage() {
1475
- let name = nodeName;
1476
- if (allowLeadingUnderscore) {
1477
- name = name.replace(/^_*/, '');
1478
- }
1479
- if (allowTrailingUnderscore) {
1480
- name = name.replace(/_*$/, '');
1481
- }
1465
+ function getError() {
1466
+ const name = nodeName.replace(/(^_+)|(_+$)/g, '');
1482
1467
  if (prefix && !name.startsWith(prefix)) {
1483
- return `have "${prefix}" prefix`;
1468
+ return {
1469
+ errorMessage: `have "${prefix}" prefix`,
1470
+ renameToName: prefix + nodeName,
1471
+ };
1484
1472
  }
1485
1473
  if (suffix && !name.endsWith(suffix)) {
1486
- return `have "${suffix}" suffix`;
1474
+ return {
1475
+ errorMessage: `have "${suffix}" suffix`,
1476
+ renameToName: nodeName + suffix,
1477
+ };
1487
1478
  }
1488
1479
  const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
1489
1480
  if (forbiddenPrefix) {
1490
- return `not have "${forbiddenPrefix}" prefix`;
1481
+ return {
1482
+ errorMessage: `not have "${forbiddenPrefix}" prefix`,
1483
+ renameToName: nodeName.replace(new RegExp(`^${forbiddenPrefix}`), ''),
1484
+ };
1491
1485
  }
1492
1486
  const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
1493
1487
  if (forbiddenSuffix) {
1494
- return `not have "${forbiddenSuffix}" suffix`;
1495
- }
1496
- if (style && !ALLOWED_STYLES.includes(style)) {
1497
- return `be in one of the following options: ${ALLOWED_STYLES.join(', ')}`;
1488
+ return {
1489
+ errorMessage: `not have "${forbiddenSuffix}" suffix`,
1490
+ renameToName: nodeName.replace(new RegExp(`${forbiddenSuffix}$`), ''),
1491
+ };
1498
1492
  }
1499
1493
  const caseRegex = StyleToRegex[style];
1500
1494
  if (caseRegex && !caseRegex.test(name)) {
1501
- return `be in ${style} format`;
1495
+ return {
1496
+ errorMessage: `be in ${style} format`,
1497
+ renameToName: convertCase(style, nodeName),
1498
+ };
1502
1499
  }
1503
1500
  }
1504
1501
  };
1505
- const checkUnderscore = (node) => {
1502
+ const checkUnderscore = (isLeading) => (node) => {
1506
1503
  const name = node.value;
1504
+ const renameToName = name.replace(new RegExp(isLeading ? '^_+' : '_+$'), '');
1507
1505
  context.report({
1508
1506
  loc: getLocation(node.loc, name),
1509
- message: `${name.startsWith('_') ? 'Leading' : 'Trailing'} underscores are not allowed`,
1507
+ message: `${isLeading ? 'Leading' : 'Trailing'} underscores are not allowed`,
1508
+ suggest: [
1509
+ {
1510
+ desc: `Rename to "${renameToName}"`,
1511
+ fix: fixer => fixer.replaceText(node, renameToName),
1512
+ },
1513
+ ],
1510
1514
  });
1511
1515
  };
1512
1516
  const listeners = {};
1513
1517
  if (!allowLeadingUnderscore) {
1514
- listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1518
+ listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1519
+ checkUnderscore(true);
1515
1520
  }
1516
1521
  if (!allowTrailingUnderscore) {
1517
- listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1522
+ listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1523
+ checkUnderscore(false);
1518
1524
  }
1519
1525
  const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
1520
1526
  for (const selector of selectors) {
package/index.mjs CHANGED
@@ -280,14 +280,6 @@ const TYPES_KINDS = [
280
280
  Kind.INPUT_OBJECT_TYPE_DEFINITION,
281
281
  Kind.UNION_TYPE_DEFINITION,
282
282
  ];
283
- var CaseStyle;
284
- (function (CaseStyle) {
285
- CaseStyle["camelCase"] = "camelCase";
286
- CaseStyle["pascalCase"] = "PascalCase";
287
- CaseStyle["snakeCase"] = "snake_case";
288
- CaseStyle["upperCase"] = "UPPER_CASE";
289
- CaseStyle["kebabCase"] = "kebab-case";
290
- })(CaseStyle || (CaseStyle = {}));
291
283
  const pascalCase = (str) => lowerCase(str)
292
284
  .split(' ')
293
285
  .map(word => word.charAt(0).toUpperCase() + word.slice(1))
@@ -298,15 +290,15 @@ const camelCase = (str) => {
298
290
  };
299
291
  const convertCase = (style, str) => {
300
292
  switch (style) {
301
- case CaseStyle.camelCase:
293
+ case 'camelCase':
302
294
  return camelCase(str);
303
- case CaseStyle.pascalCase:
295
+ case 'PascalCase':
304
296
  return pascalCase(str);
305
- case CaseStyle.snakeCase:
297
+ case 'snake_case':
306
298
  return lowerCase(str).replace(/ /g, '_');
307
- case CaseStyle.upperCase:
299
+ case 'UPPER_CASE':
308
300
  return lowerCase(str).replace(/ /g, '_').toUpperCase();
309
- case CaseStyle.kebabCase:
301
+ case 'kebab-case':
310
302
  return lowerCase(str).replace(/ /g, '-');
311
303
  }
312
304
  };
@@ -1041,13 +1033,7 @@ const rule$2 = {
1041
1033
  const MATCH_EXTENSION = 'MATCH_EXTENSION';
1042
1034
  const MATCH_STYLE = 'MATCH_STYLE';
1043
1035
  const ACCEPTED_EXTENSIONS = ['.gql', '.graphql'];
1044
- const CASE_STYLES = [
1045
- CaseStyle.camelCase,
1046
- CaseStyle.pascalCase,
1047
- CaseStyle.snakeCase,
1048
- CaseStyle.upperCase,
1049
- CaseStyle.kebabCase,
1050
- ];
1036
+ const CASE_STYLES = ['camelCase', 'PascalCase', 'snake_case', 'UPPER_CASE', 'kebab-case'];
1051
1037
  const schemaOption = {
1052
1038
  oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }],
1053
1039
  };
@@ -1071,7 +1057,7 @@ const rule$3 = {
1071
1057
  },
1072
1058
  {
1073
1059
  title: 'Correct',
1074
- usage: [{ query: CaseStyle.snakeCase }],
1060
+ usage: [{ query: 'snake_case' }],
1075
1061
  code: /* GraphQL */ `
1076
1062
  # user_by_id.gql
1077
1063
  query UserById {
@@ -1085,7 +1071,7 @@ const rule$3 = {
1085
1071
  },
1086
1072
  {
1087
1073
  title: 'Correct',
1088
- usage: [{ fragment: { style: CaseStyle.kebabCase, suffix: '.fragment' } }],
1074
+ usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
1089
1075
  code: /* GraphQL */ `
1090
1076
  # user-fields.fragment.gql
1091
1077
  fragment user_fields on User {
@@ -1096,7 +1082,7 @@ const rule$3 = {
1096
1082
  },
1097
1083
  {
1098
1084
  title: 'Correct',
1099
- usage: [{ mutation: { style: CaseStyle.pascalCase, suffix: 'Mutation' } }],
1085
+ usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
1100
1086
  code: /* GraphQL */ `
1101
1087
  # DeleteUserMutation.gql
1102
1088
  mutation DELETE_USER {
@@ -1116,7 +1102,7 @@ const rule$3 = {
1116
1102
  },
1117
1103
  {
1118
1104
  title: 'Incorrect',
1119
- usage: [{ query: CaseStyle.pascalCase }],
1105
+ usage: [{ query: 'PascalCase' }],
1120
1106
  code: /* GraphQL */ `
1121
1107
  # user-by-id.gql
1122
1108
  query UserById {
@@ -1131,10 +1117,10 @@ const rule$3 = {
1131
1117
  ],
1132
1118
  configOptions: [
1133
1119
  {
1134
- query: CaseStyle.kebabCase,
1135
- mutation: CaseStyle.kebabCase,
1136
- subscription: CaseStyle.kebabCase,
1137
- fragment: CaseStyle.kebabCase,
1120
+ query: 'kebab-case',
1121
+ mutation: 'kebab-case',
1122
+ subscription: 'kebab-case',
1123
+ fragment: 'kebab-case',
1138
1124
  },
1139
1125
  ],
1140
1126
  },
@@ -1151,25 +1137,22 @@ const rule$3 = {
1151
1137
  asObject: {
1152
1138
  type: 'object',
1153
1139
  additionalProperties: false,
1140
+ minProperties: 1,
1154
1141
  properties: {
1155
- style: {
1156
- enum: CASE_STYLES,
1157
- },
1158
- suffix: {
1159
- type: 'string',
1160
- },
1142
+ style: { enum: CASE_STYLES },
1143
+ suffix: { type: 'string' },
1161
1144
  },
1162
1145
  },
1163
1146
  },
1164
1147
  type: 'array',
1148
+ minItems: 1,
1165
1149
  maxItems: 1,
1166
1150
  items: {
1167
1151
  type: 'object',
1168
1152
  additionalProperties: false,
1153
+ minProperties: 1,
1169
1154
  properties: {
1170
- fileExtension: {
1171
- enum: ACCEPTED_EXTENSIONS,
1172
- },
1155
+ fileExtension: { enum: ACCEPTED_EXTENSIONS },
1173
1156
  query: schemaOption,
1174
1157
  mutation: schemaOption,
1175
1158
  subscription: schemaOption,
@@ -1224,7 +1207,7 @@ const rule$3 = {
1224
1207
  option = { style: option };
1225
1208
  }
1226
1209
  const expectedExtension = options.fileExtension || fileExtension;
1227
- const expectedFilename = convertCase(option.style, docName) + (option.suffix || '') + expectedExtension;
1210
+ const expectedFilename = (option.style ? convertCase(option.style, docName) : filename) + (option.suffix || '') + expectedExtension;
1228
1211
  const filenameWithExtension = filename + expectedExtension;
1229
1212
  if (expectedFilename !== filenameWithExtension) {
1230
1213
  context.report({
@@ -1376,6 +1359,7 @@ const rule$4 = {
1376
1359
  ],
1377
1360
  },
1378
1361
  },
1362
+ hasSuggestions: true,
1379
1363
  schema: {
1380
1364
  definitions: {
1381
1365
  asString: {
@@ -1450,65 +1434,87 @@ const rule$4 = {
1450
1434
  const style = restOptions[kind] || types;
1451
1435
  return typeof style === 'object' ? style : { style };
1452
1436
  }
1453
- const checkNode = (selector) => (node) => {
1454
- const { name } = node.kind === Kind.VARIABLE_DEFINITION ? node.variable : node;
1455
- if (!name) {
1437
+ const checkNode = (selector) => (n) => {
1438
+ const { name: node } = n.kind === Kind.VARIABLE_DEFINITION ? n.variable : n;
1439
+ if (!node) {
1456
1440
  return;
1457
1441
  }
1458
1442
  const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
1459
- const nodeType = KindToDisplayName[node.kind] || node.kind;
1460
- const nodeName = name.value;
1461
- const errorMessage = getErrorMessage();
1462
- if (errorMessage) {
1443
+ const nodeType = KindToDisplayName[n.kind] || n.kind;
1444
+ const nodeName = node.value;
1445
+ const error = getError();
1446
+ if (error) {
1447
+ const { errorMessage, renameToName } = error;
1463
1448
  context.report({
1464
- loc: getLocation(name.loc, name.value),
1449
+ loc: getLocation(node.loc, node.value),
1465
1450
  message: `${nodeType} "${nodeName}" should ${errorMessage}`,
1451
+ suggest: [
1452
+ {
1453
+ desc: `Rename to "${renameToName}"`,
1454
+ fix: fixer => fixer.replaceText(node, renameToName),
1455
+ },
1456
+ ],
1466
1457
  });
1467
1458
  }
1468
- function getErrorMessage() {
1469
- let name = nodeName;
1470
- if (allowLeadingUnderscore) {
1471
- name = name.replace(/^_*/, '');
1472
- }
1473
- if (allowTrailingUnderscore) {
1474
- name = name.replace(/_*$/, '');
1475
- }
1459
+ function getError() {
1460
+ const name = nodeName.replace(/(^_+)|(_+$)/g, '');
1476
1461
  if (prefix && !name.startsWith(prefix)) {
1477
- return `have "${prefix}" prefix`;
1462
+ return {
1463
+ errorMessage: `have "${prefix}" prefix`,
1464
+ renameToName: prefix + nodeName,
1465
+ };
1478
1466
  }
1479
1467
  if (suffix && !name.endsWith(suffix)) {
1480
- return `have "${suffix}" suffix`;
1468
+ return {
1469
+ errorMessage: `have "${suffix}" suffix`,
1470
+ renameToName: nodeName + suffix,
1471
+ };
1481
1472
  }
1482
1473
  const forbiddenPrefix = forbiddenPrefixes === null || forbiddenPrefixes === void 0 ? void 0 : forbiddenPrefixes.find(prefix => name.startsWith(prefix));
1483
1474
  if (forbiddenPrefix) {
1484
- return `not have "${forbiddenPrefix}" prefix`;
1475
+ return {
1476
+ errorMessage: `not have "${forbiddenPrefix}" prefix`,
1477
+ renameToName: nodeName.replace(new RegExp(`^${forbiddenPrefix}`), ''),
1478
+ };
1485
1479
  }
1486
1480
  const forbiddenSuffix = forbiddenSuffixes === null || forbiddenSuffixes === void 0 ? void 0 : forbiddenSuffixes.find(suffix => name.endsWith(suffix));
1487
1481
  if (forbiddenSuffix) {
1488
- return `not have "${forbiddenSuffix}" suffix`;
1489
- }
1490
- if (style && !ALLOWED_STYLES.includes(style)) {
1491
- return `be in one of the following options: ${ALLOWED_STYLES.join(', ')}`;
1482
+ return {
1483
+ errorMessage: `not have "${forbiddenSuffix}" suffix`,
1484
+ renameToName: nodeName.replace(new RegExp(`${forbiddenSuffix}$`), ''),
1485
+ };
1492
1486
  }
1493
1487
  const caseRegex = StyleToRegex[style];
1494
1488
  if (caseRegex && !caseRegex.test(name)) {
1495
- return `be in ${style} format`;
1489
+ return {
1490
+ errorMessage: `be in ${style} format`,
1491
+ renameToName: convertCase(style, nodeName),
1492
+ };
1496
1493
  }
1497
1494
  }
1498
1495
  };
1499
- const checkUnderscore = (node) => {
1496
+ const checkUnderscore = (isLeading) => (node) => {
1500
1497
  const name = node.value;
1498
+ const renameToName = name.replace(new RegExp(isLeading ? '^_+' : '_+$'), '');
1501
1499
  context.report({
1502
1500
  loc: getLocation(node.loc, name),
1503
- message: `${name.startsWith('_') ? 'Leading' : 'Trailing'} underscores are not allowed`,
1501
+ message: `${isLeading ? 'Leading' : 'Trailing'} underscores are not allowed`,
1502
+ suggest: [
1503
+ {
1504
+ desc: `Rename to "${renameToName}"`,
1505
+ fix: fixer => fixer.replaceText(node, renameToName),
1506
+ },
1507
+ ],
1504
1508
  });
1505
1509
  };
1506
1510
  const listeners = {};
1507
1511
  if (!allowLeadingUnderscore) {
1508
- listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1512
+ listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1513
+ checkUnderscore(true);
1509
1514
  }
1510
1515
  if (!allowTrailingUnderscore) {
1511
- listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore;
1516
+ listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1517
+ checkUnderscore(false);
1512
1518
  }
1513
1519
  const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
1514
1520
  for (const selector of selectors) {
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.1.0",
3
+ "version": "3.2.0-alpha-45f5fcb.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
7
7
  },
8
8
  "dependencies": {
9
9
  "@babel/code-frame": "7.16.0",
10
- "@graphql-tools/code-file-loader": "7.2.2",
10
+ "@graphql-tools/code-file-loader": "7.2.3",
11
11
  "@graphql-tools/graphql-tag-pluck": "7.1.4",
12
- "@graphql-tools/import": "6.6.1",
13
- "@graphql-tools/utils": "8.5.3",
12
+ "@graphql-tools/import": "6.6.2",
13
+ "@graphql-tools/utils": "8.5.4",
14
14
  "graphql-config": "4.1.0",
15
15
  "graphql-depth-limit": "1.1.0",
16
16
  "lodash.lowercase": "4.3.0"
package/rules/index.d.ts CHANGED
@@ -15,135 +15,8 @@ export declare const rules: {
15
15
  checkQueries?: boolean;
16
16
  checkMutations?: boolean;
17
17
  }], false>;
18
- 'match-document-filename': import("..").GraphQLESLintRule<[{
19
- fileExtension?: ".gql" | ".graphql";
20
- query?: import("../utils").CaseStyle | {
21
- style: import("../utils").CaseStyle;
22
- suffix: string;
23
- };
24
- mutation?: import("../utils").CaseStyle | {
25
- style: import("../utils").CaseStyle;
26
- suffix: string;
27
- };
28
- subscription?: import("../utils").CaseStyle | {
29
- style: import("../utils").CaseStyle;
30
- suffix: string;
31
- };
32
- fragment?: import("../utils").CaseStyle | {
33
- style: import("../utils").CaseStyle;
34
- suffix: string;
35
- };
36
- }], false>;
37
- 'naming-convention': import("..").GraphQLESLintRule<[{
38
- allowLeadingUnderscore?: boolean;
39
- allowTrailingUnderscore?: boolean;
40
- types?: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
41
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
42
- suffix?: string;
43
- prefix?: string;
44
- forbiddenPrefixes?: string[];
45
- forbiddenSuffixes?: string[];
46
- };
47
- } & {
48
- [x: `OperationDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
49
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
50
- suffix?: string;
51
- prefix?: string;
52
- forbiddenPrefixes?: string[];
53
- forbiddenSuffixes?: string[];
54
- };
55
- [x: `VariableDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
56
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
57
- suffix?: string;
58
- prefix?: string;
59
- forbiddenPrefixes?: string[];
60
- forbiddenSuffixes?: string[];
61
- };
62
- [x: `Argument${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
63
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
64
- suffix?: string;
65
- prefix?: string;
66
- forbiddenPrefixes?: string[];
67
- forbiddenSuffixes?: string[];
68
- };
69
- [x: `FragmentDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
70
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
71
- suffix?: string;
72
- prefix?: string;
73
- forbiddenPrefixes?: string[];
74
- forbiddenSuffixes?: string[];
75
- };
76
- [x: `ScalarTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
77
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
78
- suffix?: string;
79
- prefix?: string;
80
- forbiddenPrefixes?: string[];
81
- forbiddenSuffixes?: string[];
82
- };
83
- [x: `ObjectTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
84
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
85
- suffix?: string;
86
- prefix?: string;
87
- forbiddenPrefixes?: string[];
88
- forbiddenSuffixes?: string[];
89
- };
90
- [x: `FieldDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
91
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
92
- suffix?: string;
93
- prefix?: string;
94
- forbiddenPrefixes?: string[];
95
- forbiddenSuffixes?: string[];
96
- };
97
- [x: `InputValueDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
98
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
99
- suffix?: string;
100
- prefix?: string;
101
- forbiddenPrefixes?: string[];
102
- forbiddenSuffixes?: string[];
103
- };
104
- [x: `InterfaceTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
105
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
106
- suffix?: string;
107
- prefix?: string;
108
- forbiddenPrefixes?: string[];
109
- forbiddenSuffixes?: string[];
110
- };
111
- [x: `UnionTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
112
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
113
- suffix?: string;
114
- prefix?: string;
115
- forbiddenPrefixes?: string[];
116
- forbiddenSuffixes?: string[];
117
- };
118
- [x: `EnumTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
119
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
120
- suffix?: string;
121
- prefix?: string;
122
- forbiddenPrefixes?: string[];
123
- forbiddenSuffixes?: string[];
124
- };
125
- [x: `EnumValueDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
126
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
127
- suffix?: string;
128
- prefix?: string;
129
- forbiddenPrefixes?: string[];
130
- forbiddenSuffixes?: string[];
131
- };
132
- [x: `InputObjectTypeDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
133
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
134
- suffix?: string;
135
- prefix?: string;
136
- forbiddenPrefixes?: string[];
137
- forbiddenSuffixes?: string[];
138
- };
139
- [x: `DirectiveDefinition${string}`]: ("PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case") | {
140
- style?: "PascalCase" | "camelCase" | "UPPER_CASE" | "snake_case";
141
- suffix?: string;
142
- prefix?: string;
143
- forbiddenPrefixes?: string[];
144
- forbiddenSuffixes?: string[];
145
- };
146
- }], false>;
18
+ 'match-document-filename': import("..").GraphQLESLintRule<[import("./match-document-filename").MatchDocumentFilenameRuleConfig], false>;
19
+ 'naming-convention': import("..").GraphQLESLintRule<[import("./naming-convention").NamingConventionRuleConfig], false>;
147
20
  'no-anonymous-operations': import("..").GraphQLESLintRule<any[], false>;
148
21
  'no-case-insensitive-enum-values-duplicates': import("..").GraphQLESLintRule<any[], false>;
149
22
  'no-deprecated': import("..").GraphQLESLintRule<[], true>;
@@ -2,10 +2,10 @@ import { CaseStyle } from '../utils';
2
2
  import { GraphQLESLintRule } from '../types';
3
3
  declare const ACCEPTED_EXTENSIONS: ['.gql', '.graphql'];
4
4
  declare type PropertySchema = {
5
- style: CaseStyle;
6
- suffix: string;
5
+ style?: CaseStyle;
6
+ suffix?: string;
7
7
  };
8
- declare type MatchDocumentFilenameRuleConfig = {
8
+ export declare type MatchDocumentFilenameRuleConfig = {
9
9
  fileExtension?: typeof ACCEPTED_EXTENSIONS[number];
10
10
  query?: CaseStyle | PropertySchema;
11
11
  mutation?: CaseStyle | PropertySchema;
@@ -25,7 +25,7 @@ declare type PropertySchema = {
25
25
  forbiddenSuffixes?: string[];
26
26
  };
27
27
  declare type Options = AllowedStyle | PropertySchema;
28
- declare type NamingConventionRuleConfig = {
28
+ export declare type NamingConventionRuleConfig = {
29
29
  allowLeadingUnderscore?: boolean;
30
30
  allowTrailingUnderscore?: boolean;
31
31
  types?: Options;
package/utils.d.ts CHANGED
@@ -20,13 +20,7 @@ export declare const getOnDiskFilepath: (filepath: string) => string;
20
20
  export declare const getTypeName: (node: any) => any;
21
21
  export declare const loaderCache: Record<string, LoaderSource[]>;
22
22
  export declare const TYPES_KINDS: readonly [Kind.OBJECT_TYPE_DEFINITION, Kind.INTERFACE_TYPE_DEFINITION, Kind.ENUM_TYPE_DEFINITION, Kind.SCALAR_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.UNION_TYPE_DEFINITION];
23
- export declare enum CaseStyle {
24
- camelCase = "camelCase",
25
- pascalCase = "PascalCase",
26
- snakeCase = "snake_case",
27
- upperCase = "UPPER_CASE",
28
- kebabCase = "kebab-case"
29
- }
23
+ export declare type CaseStyle = 'camelCase' | 'PascalCase' | 'snake_case' | 'UPPER_CASE' | 'kebab-case';
30
24
  export declare const camelCase: (str: string) => string;
31
25
  export declare const convertCase: (style: CaseStyle, str: string) => string;
32
26
  export declare function getLocation(loc: Partial<AST.SourceLocation>, fieldName?: string, offset?: {