@graphql-eslint/eslint-plugin 3.11.0-alpha-20220828135635-ce6bf36 → 3.11.0-alpha-20220923192439-db921ff

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/README.md CHANGED
@@ -9,7 +9,7 @@ This project integrates GraphQL and ESLint, for a better developer experience.
9
9
  ## Key Features
10
10
 
11
11
  - 🚀 Integrates with ESLint core (as a ESTree parser)
12
- - 🚀 Works on `.graphql` files, `gql` usages and `/* GraphQL */` magic comments
12
+ - 🚀 Works on `.graphql` files, `gql` usages and `/* GraphQL */` magic comments
13
13
  - 🚀 Lints both GraphQL schema and GraphQL operations
14
14
  - 🚀 Extended type info for more advanced usages
15
15
  - 🚀 Supports ESLint directives (for example: `eslint-disable-next-line`)
@@ -188,7 +188,7 @@ See [docs/deprecated-rules.md](docs/deprecated-rules.md).
188
188
  |[`relay`](packages/plugin/src/configs/relay.json)|enables rules from Relay specification for schema (SDL) development|
189
189
  <!-- prettier-ignore-end -->
190
190
 
191
- > If you are in a project that develops the GraphQL schema, you'll need `schema` rules.
191
+ > If you are in a project that develops the GraphQL schema, you'll need `schema` rules.
192
192
 
193
193
  > If you are in a project that develops GraphQL operations (query/mutation/subscription), you'll need `operations` rules.
194
194
 
@@ -4,18 +4,9 @@
4
4
  "@graphql-eslint/alphabetize": [
5
5
  "error",
6
6
  {
7
- "fields": [
8
- "ObjectTypeDefinition",
9
- "InterfaceTypeDefinition",
10
- "InputObjectTypeDefinition"
11
- ],
7
+ "fields": ["ObjectTypeDefinition", "InterfaceTypeDefinition", "InputObjectTypeDefinition"],
12
8
  "values": ["EnumTypeDefinition"],
13
- "arguments": [
14
- "FieldDefinition",
15
- "Field",
16
- "DirectiveDefinition",
17
- "Directive"
18
- ]
9
+ "arguments": ["FieldDefinition", "Field", "DirectiveDefinition", "Directive"]
19
10
  }
20
11
  ],
21
12
  "@graphql-eslint/input-name": "error",
package/docs/README.md CHANGED
@@ -71,5 +71,6 @@ Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
71
71
  [variables-are-input-types](rules/variables-are-input-types.md)|A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).|![recommended][]|🔮|
72
72
  [variables-in-allowed-position](rules/variables-in-allowed-position.md)|Variables passed to field arguments conform to type.|![recommended][]|🔮|
73
73
  <!-- prettier-ignore-end -->
74
+
74
75
  [recommended]: https://img.shields.io/badge/-recommended-green.svg
75
76
  [all]: https://img.shields.io/badge/-all-blue.svg
@@ -141,7 +141,7 @@ ruleTester.runGraphQLTests('my-rule', rule, {
141
141
  invalid: [
142
142
  {
143
143
  code: 'query invalid { foo }',
144
- errors: [{ message: 'Your error message.' }],
144
+ errors: [{ message: 'Your error message.' }]
145
145
  }
146
146
  ]
147
147
  })
@@ -39,7 +39,8 @@ type User {
39
39
  # eslint @graphql-eslint/require-deprecation-date: 'error'
40
40
 
41
41
  type User {
42
- firstname: String @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
42
+ firstname: String
43
+ @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
43
44
  firstName: String
44
45
  }
45
46
  ```
package/index.js CHANGED
@@ -114,7 +114,7 @@ const getOnDiskFilepath = (filepath) => {
114
114
  }
115
115
  return filepath;
116
116
  };
117
- const getTypeName = (node) => ('type' in node ? getTypeName(node.type) : node.name.value);
117
+ const getTypeName = (node) => 'type' in node ? getTypeName(node.type) : node.name.value;
118
118
  const TYPES_KINDS = [
119
119
  graphql.Kind.OBJECT_TYPE_DEFINITION,
120
120
  graphql.Kind.INTERFACE_TYPE_DEFINITION,
@@ -189,7 +189,9 @@ function validateDocument(context, schema = null, documentNode, rule) {
189
189
  if (token) {
190
190
  loc =
191
191
  // if cursor on `@` symbol than use next node
192
- token.type === '@' ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc : token.loc;
192
+ token.type === '@'
193
+ ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc
194
+ : token.loc;
193
195
  }
194
196
  context.report({
195
197
  loc,
@@ -279,7 +281,9 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode, schema = [])
279
281
  }
280
282
  return {
281
283
  Document(node) {
282
- const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
284
+ const schema = docs.requiresSchema
285
+ ? requireGraphQLSchemaFromContext(ruleId, context)
286
+ : null;
283
287
  const documentNode = getDocumentNode
284
288
  ? getDocumentNode({ ruleId, context, node: node.rawNode() })
285
289
  : node.rawNode();
@@ -425,7 +429,10 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
425
429
  requiresSiblings: true,
426
430
  }, ({ ruleId, context, node }) => {
427
431
  const siblings = requireSiblingsOperations(ruleId, context);
428
- const FilePathToDocumentsMap = [...siblings.getOperations(), ...siblings.getFragments()].reduce((map, { filePath, document }) => {
432
+ const FilePathToDocumentsMap = [
433
+ ...siblings.getOperations(),
434
+ ...siblings.getFragments(),
435
+ ].reduce((map, { filePath, document }) => {
429
436
  var _a;
430
437
  (_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
431
438
  map[filePath].push(document);
@@ -705,14 +712,6 @@ const rule = {
705
712
  description: 'Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `directive`.',
706
713
  default: false,
707
714
  },
708
- ignorePrefix: {
709
- type: 'array',
710
- default: [],
711
- },
712
- ignoreSuffix: {
713
- type: 'array',
714
- default: [],
715
- },
716
715
  },
717
716
  },
718
717
  },
@@ -751,7 +750,9 @@ const rule = {
751
750
  const [firstBeforeComment] = getBeforeComments(node);
752
751
  const [firstAfterComment] = sourceCode.getCommentsAfter(node);
753
752
  const from = firstBeforeComment || node;
754
- const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment) ? firstAfterComment : node;
753
+ const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment)
754
+ ? firstAfterComment
755
+ : node;
755
756
  return [from.range[0], to.range[1]];
756
757
  }
757
758
  function checkNodes(nodes) {
@@ -759,32 +760,24 @@ const rule = {
759
760
  // Starts from 1, ignore nodes.length <= 1
760
761
  for (let i = 1; i < nodes.length; i += 1) {
761
762
  const currNode = nodes[i];
762
- const currName = ('alias' in currNode && ((_a = currNode.alias) === null || _a === void 0 ? void 0 : _a.value)) || ('name' in currNode && ((_b = currNode.name) === null || _b === void 0 ? void 0 : _b.value));
763
+ const currName = ('alias' in currNode && ((_a = currNode.alias) === null || _a === void 0 ? void 0 : _a.value)) ||
764
+ ('name' in currNode && ((_b = currNode.name) === null || _b === void 0 ? void 0 : _b.value));
763
765
  if (!currName) {
764
766
  // we don't move unnamed current nodes
765
767
  continue;
766
768
  }
767
769
  const prevNode = nodes[i - 1];
768
- const prevName = ('alias' in prevNode && ((_c = prevNode.alias) === null || _c === void 0 ? void 0 : _c.value)) || ('name' in prevNode && ((_d = prevNode.name) === null || _d === void 0 ? void 0 : _d.value));
770
+ const prevName = ('alias' in prevNode && ((_c = prevNode.alias) === null || _c === void 0 ? void 0 : _c.value)) ||
771
+ ('name' in prevNode && ((_d = prevNode.name) === null || _d === void 0 ? void 0 : _d.value));
769
772
  if (prevName) {
770
- if ((opts.ignorePrefix || []).length > 0) {
771
- const shouldSkipIgnorePrefix = opts.ignorePrefix.some(prefix => prefix === prevName || prefix === currName || prevName.startsWith(prefix) || currName.startsWith(prefix));
772
- if (shouldSkipIgnorePrefix) {
773
- continue;
774
- }
775
- }
776
- if ((opts.ignoreSuffix || []).length > 0) {
777
- const shouldSkipIgnoreSuffix = opts.ignoreSuffix.some(suffix => suffix === prevName || suffix === currName || prevName.endsWith(suffix) || currName.endsWith(suffix));
778
- if (shouldSkipIgnoreSuffix) {
779
- continue;
780
- }
781
- }
782
773
  // Compare with lexicographic order
783
774
  const compareResult = prevName.localeCompare(currName);
784
775
  const shouldSort = compareResult === 1;
785
776
  if (!shouldSort) {
786
777
  const isSameName = compareResult === 0;
787
- if (!isSameName || !prevNode.kind.endsWith('Extension') || currNode.kind.endsWith('Extension')) {
778
+ if (!isSameName ||
779
+ !prevNode.kind.endsWith('Extension') ||
780
+ currNode.kind.endsWith('Extension')) {
788
781
  continue;
789
782
  }
790
783
  }
@@ -809,8 +802,14 @@ const rule = {
809
802
  const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
810
803
  const listeners = {};
811
804
  const kinds = [
812
- fields.has(graphql.Kind.OBJECT_TYPE_DEFINITION) && [graphql.Kind.OBJECT_TYPE_DEFINITION, graphql.Kind.OBJECT_TYPE_EXTENSION],
813
- fields.has(graphql.Kind.INTERFACE_TYPE_DEFINITION) && [graphql.Kind.INTERFACE_TYPE_DEFINITION, graphql.Kind.INTERFACE_TYPE_EXTENSION],
805
+ fields.has(graphql.Kind.OBJECT_TYPE_DEFINITION) && [
806
+ graphql.Kind.OBJECT_TYPE_DEFINITION,
807
+ graphql.Kind.OBJECT_TYPE_EXTENSION,
808
+ ],
809
+ fields.has(graphql.Kind.INTERFACE_TYPE_DEFINITION) && [
810
+ graphql.Kind.INTERFACE_TYPE_DEFINITION,
811
+ graphql.Kind.INTERFACE_TYPE_EXTENSION,
812
+ ],
814
813
  fields.has(graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
815
814
  graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
816
815
  graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION,
@@ -1008,7 +1007,8 @@ const rule$2 = {
1008
1007
  checkMutations: true,
1009
1008
  ...context.options[0],
1010
1009
  };
1011
- const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
1010
+ const shouldCheckType = node => (options.checkMutations && isMutationType(node)) ||
1011
+ (options.checkQueries && isQueryType(node));
1012
1012
  const listeners = {
1013
1013
  'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
1014
1014
  if (shouldCheckType(node.parent.parent.parent)) {
@@ -1244,7 +1244,8 @@ const rule$3 = {
1244
1244
  const expectedExtension = options.fileExtension || fileExtension;
1245
1245
  let expectedFilename;
1246
1246
  if (option.style) {
1247
- expectedFilename = option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
1247
+ expectedFilename =
1248
+ option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
1248
1249
  }
1249
1250
  else {
1250
1251
  expectedFilename = filename;
@@ -1558,12 +1559,10 @@ const rule$4 = {
1558
1559
  };
1559
1560
  const listeners = {};
1560
1561
  if (!allowLeadingUnderscore) {
1561
- listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1562
- checkUnderscore(true);
1562
+ listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore(true);
1563
1563
  }
1564
1564
  if (!allowTrailingUnderscore) {
1565
- listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1566
- checkUnderscore(false);
1565
+ listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore(false);
1567
1566
  }
1568
1567
  const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
1569
1568
  for (const selector of selectors) {
@@ -1611,7 +1610,9 @@ const rule$5 = {
1611
1610
  return {
1612
1611
  'OperationDefinition[name=undefined]'(node) {
1613
1612
  const [firstSelection] = node.selectionSet.selections;
1614
- const suggestedName = firstSelection.kind === graphql.Kind.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
1613
+ const suggestedName = firstSelection.kind === graphql.Kind.FIELD
1614
+ ? (firstSelection.alias || firstSelection.name).value
1615
+ : node.operation;
1615
1616
  context.report({
1616
1617
  loc: getLocation(node.loc.start, node.operation),
1617
1618
  messageId: RULE_ID$1,
@@ -1672,7 +1673,8 @@ const rule$6 = {
1672
1673
  const selector = [graphql.Kind.ENUM_TYPE_DEFINITION, graphql.Kind.ENUM_TYPE_EXTENSION].join(',');
1673
1674
  return {
1674
1675
  [selector](node) {
1675
- const duplicates = node.values.filter((item, index, array) => array.findIndex(v => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !== index);
1676
+ const duplicates = node.values.filter((item, index, array) => array.findIndex(v => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !==
1677
+ index);
1676
1678
  for (const duplicate of duplicates) {
1677
1679
  const enumName = duplicate.name.value;
1678
1680
  context.report({
@@ -1982,7 +1984,10 @@ const rule$9 = {
1982
1984
  if (kind === graphql.TokenKind.COMMENT && prev && next) {
1983
1985
  const isEslintComment = value.trimStart().startsWith('eslint');
1984
1986
  const linesAfter = next.line - line;
1985
- if (!isEslintComment && line !== prev.line && next.kind === graphql.TokenKind.NAME && linesAfter < 2) {
1987
+ if (!isEslintComment &&
1988
+ line !== prev.line &&
1989
+ next.kind === graphql.TokenKind.NAME &&
1990
+ linesAfter < 2) {
1986
1991
  context.report({
1987
1992
  messageId: HASHTAG_COMMENT,
1988
1993
  loc: {
@@ -2691,7 +2696,8 @@ const rule$g = {
2691
2696
  }
2692
2697
  },
2693
2698
  ':matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=edges] > .gqlType'(node) {
2694
- const isListType = node.kind === graphql.Kind.LIST_TYPE || (node.kind === graphql.Kind.NON_NULL_TYPE && node.gqlType.kind === graphql.Kind.LIST_TYPE);
2699
+ const isListType = node.kind === graphql.Kind.LIST_TYPE ||
2700
+ (node.kind === graphql.Kind.NON_NULL_TYPE && node.gqlType.kind === graphql.Kind.LIST_TYPE);
2695
2701
  if (!isListType) {
2696
2702
  context.report({ node, messageId: EDGES_FIELD_MUST_RETURN_LIST_TYPE });
2697
2703
  }
@@ -2816,7 +2822,8 @@ const rule$h = {
2816
2822
  listTypeCanWrapOnlyEdgeType: true,
2817
2823
  ...context.options[0],
2818
2824
  };
2819
- const isNamedOrNonNullNamed = (node) => node.kind === graphql.Kind.NAMED_TYPE || (node.kind === graphql.Kind.NON_NULL_TYPE && node.gqlType.kind === graphql.Kind.NAMED_TYPE);
2825
+ const isNamedOrNonNullNamed = (node) => node.kind === graphql.Kind.NAMED_TYPE ||
2826
+ (node.kind === graphql.Kind.NON_NULL_TYPE && node.gqlType.kind === graphql.Kind.NAMED_TYPE);
2820
2827
  const checkNodeField = (node) => {
2821
2828
  const nodeField = node.fields.find(field => field.name.value === 'node');
2822
2829
  const message = 'return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types.';
@@ -2960,7 +2967,8 @@ const rule$i = {
2960
2967
  type.gqlType.name.value === 'Boolean';
2961
2968
  }
2962
2969
  else if (type.kind === graphql.Kind.NAMED_TYPE) {
2963
- isAllowedType = type.name.value === 'String' || graphql.isScalarType(schema.getType(type.name.value));
2970
+ isAllowedType =
2971
+ type.name.value === 'String' || graphql.isScalarType(schema.getType(type.name.value));
2964
2972
  }
2965
2973
  }
2966
2974
  if (!isAllowedType) {
@@ -3177,7 +3185,8 @@ const rule$j = {
3177
3185
  title: 'Correct',
3178
3186
  code: /* GraphQL */ `
3179
3187
  type User {
3180
- firstname: String @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
3188
+ firstname: String
3189
+ @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
3181
3190
  firstName: String
3182
3191
  }
3183
3192
  `,
@@ -3416,7 +3425,8 @@ const rule$l = {
3416
3425
  ...Object.fromEntries([...ALLOWED_KINDS$1].sort().map(kind => {
3417
3426
  let description = `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
3418
3427
  if (kind === graphql.Kind.OPERATION_DEFINITION) {
3419
- description += '\n\n> You must use only comment syntax `#` and not description syntax `"""` or `"`.';
3428
+ description +=
3429
+ '\n\n> You must use only comment syntax `#` and not description syntax `"""` or `"`.';
3420
3430
  }
3421
3431
  return [kind, { type: 'boolean', description }];
3422
3432
  })),
@@ -3734,7 +3744,6 @@ const RULE_ID$d = 'selection-set-depth';
3734
3744
  const rule$o = {
3735
3745
  meta: {
3736
3746
  type: 'suggestion',
3737
- // eslint-disable-next-line eslint-plugin/require-meta-has-suggestions -- optional since we can't provide fixes for fragments located in separate files
3738
3747
  hasSuggestions: true,
3739
3748
  docs: {
3740
3749
  category: 'Operations',
@@ -3971,7 +3980,11 @@ const rule$p = {
3971
3980
  ...context.options[0],
3972
3981
  };
3973
3982
  const schema = requireGraphQLSchemaFromContext(RULE_ID$e, context);
3974
- const rootTypeNames = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
3983
+ const rootTypeNames = [
3984
+ schema.getQueryType(),
3985
+ schema.getMutationType(),
3986
+ schema.getSubscriptionType(),
3987
+ ]
3975
3988
  .filter(Boolean)
3976
3989
  .map(type => type.name);
3977
3990
  const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join('|')})$/]`;
@@ -3989,7 +4002,8 @@ const rule$p = {
3989
4002
  const isValidIdName = options.acceptedIdNames.includes(fieldNode.name.value);
3990
4003
  // To be a valid type, it must be non-null and one of the accepted types.
3991
4004
  let isValidIdType = false;
3992
- if (fieldNode.type.kind === graphql.Kind.NON_NULL_TYPE && fieldNode.type.type.kind === graphql.Kind.NAMED_TYPE) {
4005
+ if (fieldNode.type.kind === graphql.Kind.NON_NULL_TYPE &&
4006
+ fieldNode.type.type.kind === graphql.Kind.NAMED_TYPE) {
3993
4007
  isValidIdType = options.acceptedIdTypes.includes(fieldNode.type.type.name.value);
3994
4008
  }
3995
4009
  return isValidIdName && isValidIdType;
@@ -4014,7 +4028,9 @@ const RULE_ID$f = 'unique-fragment-name';
4014
4028
  const checkNode = (context, node, ruleId) => {
4015
4029
  const documentName = node.name.value;
4016
4030
  const siblings = requireSiblingsOperations(ruleId, context);
4017
- const siblingDocuments = node.kind === graphql.Kind.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
4031
+ const siblingDocuments = node.kind === graphql.Kind.FRAGMENT_DEFINITION
4032
+ ? siblings.getFragment(documentName)
4033
+ : siblings.getOperation(documentName);
4018
4034
  const filepath = context.getFilename();
4019
4035
  const conflictingDocuments = siblingDocuments.filter(f => {
4020
4036
  var _a;
@@ -4410,7 +4426,9 @@ function parseForESLint(code, options = {}) {
4410
4426
  const filePath = options.filePath || '';
4411
4427
  const realFilepath = filePath && getOnDiskFilepath(filePath);
4412
4428
  const gqlConfig = loadGraphQLConfig(options);
4413
- const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
4429
+ const projectForFile = realFilepath
4430
+ ? gqlConfig.getProjectForFile(realFilepath)
4431
+ : gqlConfig.getDefault();
4414
4432
  const schema = getSchema(projectForFile, options);
4415
4433
  const siblingOperations = getSiblingOperations(projectForFile);
4416
4434
  const { document } = utils.parseGraphQLSDL(filePath, code, {
package/index.mjs CHANGED
@@ -108,7 +108,7 @@ const getOnDiskFilepath = (filepath) => {
108
108
  }
109
109
  return filepath;
110
110
  };
111
- const getTypeName = (node) => ('type' in node ? getTypeName(node.type) : node.name.value);
111
+ const getTypeName = (node) => 'type' in node ? getTypeName(node.type) : node.name.value;
112
112
  const TYPES_KINDS = [
113
113
  Kind.OBJECT_TYPE_DEFINITION,
114
114
  Kind.INTERFACE_TYPE_DEFINITION,
@@ -183,7 +183,9 @@ function validateDocument(context, schema = null, documentNode, rule) {
183
183
  if (token) {
184
184
  loc =
185
185
  // if cursor on `@` symbol than use next node
186
- token.type === '@' ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc : token.loc;
186
+ token.type === '@'
187
+ ? sourceCode.getNodeByRangeIndex(token.range[1] + 1).loc
188
+ : token.loc;
187
189
  }
188
190
  context.report({
189
191
  loc,
@@ -273,7 +275,9 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode, schema = [])
273
275
  }
274
276
  return {
275
277
  Document(node) {
276
- const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
278
+ const schema = docs.requiresSchema
279
+ ? requireGraphQLSchemaFromContext(ruleId, context)
280
+ : null;
277
281
  const documentNode = getDocumentNode
278
282
  ? getDocumentNode({ ruleId, context, node: node.rawNode() })
279
283
  : node.rawNode();
@@ -419,7 +423,10 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
419
423
  requiresSiblings: true,
420
424
  }, ({ ruleId, context, node }) => {
421
425
  const siblings = requireSiblingsOperations(ruleId, context);
422
- const FilePathToDocumentsMap = [...siblings.getOperations(), ...siblings.getFragments()].reduce((map, { filePath, document }) => {
426
+ const FilePathToDocumentsMap = [
427
+ ...siblings.getOperations(),
428
+ ...siblings.getFragments(),
429
+ ].reduce((map, { filePath, document }) => {
423
430
  var _a;
424
431
  (_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
425
432
  map[filePath].push(document);
@@ -699,14 +706,6 @@ const rule = {
699
706
  description: 'Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `directive`.',
700
707
  default: false,
701
708
  },
702
- ignorePrefix: {
703
- type: 'array',
704
- default: [],
705
- },
706
- ignoreSuffix: {
707
- type: 'array',
708
- default: [],
709
- },
710
709
  },
711
710
  },
712
711
  },
@@ -745,7 +744,9 @@ const rule = {
745
744
  const [firstBeforeComment] = getBeforeComments(node);
746
745
  const [firstAfterComment] = sourceCode.getCommentsAfter(node);
747
746
  const from = firstBeforeComment || node;
748
- const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment) ? firstAfterComment : node;
747
+ const to = firstAfterComment && isNodeAndCommentOnSameLine(node, firstAfterComment)
748
+ ? firstAfterComment
749
+ : node;
749
750
  return [from.range[0], to.range[1]];
750
751
  }
751
752
  function checkNodes(nodes) {
@@ -753,32 +754,24 @@ const rule = {
753
754
  // Starts from 1, ignore nodes.length <= 1
754
755
  for (let i = 1; i < nodes.length; i += 1) {
755
756
  const currNode = nodes[i];
756
- const currName = ('alias' in currNode && ((_a = currNode.alias) === null || _a === void 0 ? void 0 : _a.value)) || ('name' in currNode && ((_b = currNode.name) === null || _b === void 0 ? void 0 : _b.value));
757
+ const currName = ('alias' in currNode && ((_a = currNode.alias) === null || _a === void 0 ? void 0 : _a.value)) ||
758
+ ('name' in currNode && ((_b = currNode.name) === null || _b === void 0 ? void 0 : _b.value));
757
759
  if (!currName) {
758
760
  // we don't move unnamed current nodes
759
761
  continue;
760
762
  }
761
763
  const prevNode = nodes[i - 1];
762
- const prevName = ('alias' in prevNode && ((_c = prevNode.alias) === null || _c === void 0 ? void 0 : _c.value)) || ('name' in prevNode && ((_d = prevNode.name) === null || _d === void 0 ? void 0 : _d.value));
764
+ const prevName = ('alias' in prevNode && ((_c = prevNode.alias) === null || _c === void 0 ? void 0 : _c.value)) ||
765
+ ('name' in prevNode && ((_d = prevNode.name) === null || _d === void 0 ? void 0 : _d.value));
763
766
  if (prevName) {
764
- if ((opts.ignorePrefix || []).length > 0) {
765
- const shouldSkipIgnorePrefix = opts.ignorePrefix.some(prefix => prefix === prevName || prefix === currName || prevName.startsWith(prefix) || currName.startsWith(prefix));
766
- if (shouldSkipIgnorePrefix) {
767
- continue;
768
- }
769
- }
770
- if ((opts.ignoreSuffix || []).length > 0) {
771
- const shouldSkipIgnoreSuffix = opts.ignoreSuffix.some(suffix => suffix === prevName || suffix === currName || prevName.endsWith(suffix) || currName.endsWith(suffix));
772
- if (shouldSkipIgnoreSuffix) {
773
- continue;
774
- }
775
- }
776
767
  // Compare with lexicographic order
777
768
  const compareResult = prevName.localeCompare(currName);
778
769
  const shouldSort = compareResult === 1;
779
770
  if (!shouldSort) {
780
771
  const isSameName = compareResult === 0;
781
- if (!isSameName || !prevNode.kind.endsWith('Extension') || currNode.kind.endsWith('Extension')) {
772
+ if (!isSameName ||
773
+ !prevNode.kind.endsWith('Extension') ||
774
+ currNode.kind.endsWith('Extension')) {
782
775
  continue;
783
776
  }
784
777
  }
@@ -803,8 +796,14 @@ const rule = {
803
796
  const fields = new Set((_a = opts.fields) !== null && _a !== void 0 ? _a : []);
804
797
  const listeners = {};
805
798
  const kinds = [
806
- fields.has(Kind.OBJECT_TYPE_DEFINITION) && [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION],
807
- fields.has(Kind.INTERFACE_TYPE_DEFINITION) && [Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION],
799
+ fields.has(Kind.OBJECT_TYPE_DEFINITION) && [
800
+ Kind.OBJECT_TYPE_DEFINITION,
801
+ Kind.OBJECT_TYPE_EXTENSION,
802
+ ],
803
+ fields.has(Kind.INTERFACE_TYPE_DEFINITION) && [
804
+ Kind.INTERFACE_TYPE_DEFINITION,
805
+ Kind.INTERFACE_TYPE_EXTENSION,
806
+ ],
808
807
  fields.has(Kind.INPUT_OBJECT_TYPE_DEFINITION) && [
809
808
  Kind.INPUT_OBJECT_TYPE_DEFINITION,
810
809
  Kind.INPUT_OBJECT_TYPE_EXTENSION,
@@ -1002,7 +1001,8 @@ const rule$2 = {
1002
1001
  checkMutations: true,
1003
1002
  ...context.options[0],
1004
1003
  };
1005
- const shouldCheckType = node => (options.checkMutations && isMutationType(node)) || (options.checkQueries && isQueryType(node));
1004
+ const shouldCheckType = node => (options.checkMutations && isMutationType(node)) ||
1005
+ (options.checkQueries && isQueryType(node));
1006
1006
  const listeners = {
1007
1007
  'FieldDefinition > InputValueDefinition[name.value!=input] > Name'(node) {
1008
1008
  if (shouldCheckType(node.parent.parent.parent)) {
@@ -1238,7 +1238,8 @@ const rule$3 = {
1238
1238
  const expectedExtension = options.fileExtension || fileExtension;
1239
1239
  let expectedFilename;
1240
1240
  if (option.style) {
1241
- expectedFilename = option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
1241
+ expectedFilename =
1242
+ option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
1242
1243
  }
1243
1244
  else {
1244
1245
  expectedFilename = filename;
@@ -1552,12 +1553,10 @@ const rule$4 = {
1552
1553
  };
1553
1554
  const listeners = {};
1554
1555
  if (!allowLeadingUnderscore) {
1555
- listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1556
- checkUnderscore(true);
1556
+ listeners['Name[value=/^_/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore(true);
1557
1557
  }
1558
1558
  if (!allowTrailingUnderscore) {
1559
- listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] =
1560
- checkUnderscore(false);
1559
+ listeners['Name[value=/_$/]:matches([parent.kind!=Field], [parent.kind=Field][parent.alias])'] = checkUnderscore(false);
1561
1560
  }
1562
1561
  const selectors = new Set([types && TYPES_KINDS, Object.keys(restOptions)].flat().filter(Boolean));
1563
1562
  for (const selector of selectors) {
@@ -1605,7 +1604,9 @@ const rule$5 = {
1605
1604
  return {
1606
1605
  'OperationDefinition[name=undefined]'(node) {
1607
1606
  const [firstSelection] = node.selectionSet.selections;
1608
- const suggestedName = firstSelection.kind === Kind.FIELD ? (firstSelection.alias || firstSelection.name).value : node.operation;
1607
+ const suggestedName = firstSelection.kind === Kind.FIELD
1608
+ ? (firstSelection.alias || firstSelection.name).value
1609
+ : node.operation;
1609
1610
  context.report({
1610
1611
  loc: getLocation(node.loc.start, node.operation),
1611
1612
  messageId: RULE_ID$1,
@@ -1666,7 +1667,8 @@ const rule$6 = {
1666
1667
  const selector = [Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION].join(',');
1667
1668
  return {
1668
1669
  [selector](node) {
1669
- const duplicates = node.values.filter((item, index, array) => array.findIndex(v => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !== index);
1670
+ const duplicates = node.values.filter((item, index, array) => array.findIndex(v => v.name.value.toLowerCase() === item.name.value.toLowerCase()) !==
1671
+ index);
1670
1672
  for (const duplicate of duplicates) {
1671
1673
  const enumName = duplicate.name.value;
1672
1674
  context.report({
@@ -1976,7 +1978,10 @@ const rule$9 = {
1976
1978
  if (kind === TokenKind.COMMENT && prev && next) {
1977
1979
  const isEslintComment = value.trimStart().startsWith('eslint');
1978
1980
  const linesAfter = next.line - line;
1979
- if (!isEslintComment && line !== prev.line && next.kind === TokenKind.NAME && linesAfter < 2) {
1981
+ if (!isEslintComment &&
1982
+ line !== prev.line &&
1983
+ next.kind === TokenKind.NAME &&
1984
+ linesAfter < 2) {
1980
1985
  context.report({
1981
1986
  messageId: HASHTAG_COMMENT,
1982
1987
  loc: {
@@ -2685,7 +2690,8 @@ const rule$g = {
2685
2690
  }
2686
2691
  },
2687
2692
  ':matches(ObjectTypeDefinition, ObjectTypeExtension)[name.value=/Connection$/] > FieldDefinition[name.value=edges] > .gqlType'(node) {
2688
- const isListType = node.kind === Kind.LIST_TYPE || (node.kind === Kind.NON_NULL_TYPE && node.gqlType.kind === Kind.LIST_TYPE);
2693
+ const isListType = node.kind === Kind.LIST_TYPE ||
2694
+ (node.kind === Kind.NON_NULL_TYPE && node.gqlType.kind === Kind.LIST_TYPE);
2689
2695
  if (!isListType) {
2690
2696
  context.report({ node, messageId: EDGES_FIELD_MUST_RETURN_LIST_TYPE });
2691
2697
  }
@@ -2810,7 +2816,8 @@ const rule$h = {
2810
2816
  listTypeCanWrapOnlyEdgeType: true,
2811
2817
  ...context.options[0],
2812
2818
  };
2813
- const isNamedOrNonNullNamed = (node) => node.kind === Kind.NAMED_TYPE || (node.kind === Kind.NON_NULL_TYPE && node.gqlType.kind === Kind.NAMED_TYPE);
2819
+ const isNamedOrNonNullNamed = (node) => node.kind === Kind.NAMED_TYPE ||
2820
+ (node.kind === Kind.NON_NULL_TYPE && node.gqlType.kind === Kind.NAMED_TYPE);
2814
2821
  const checkNodeField = (node) => {
2815
2822
  const nodeField = node.fields.find(field => field.name.value === 'node');
2816
2823
  const message = 'return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types.';
@@ -2954,7 +2961,8 @@ const rule$i = {
2954
2961
  type.gqlType.name.value === 'Boolean';
2955
2962
  }
2956
2963
  else if (type.kind === Kind.NAMED_TYPE) {
2957
- isAllowedType = type.name.value === 'String' || isScalarType(schema.getType(type.name.value));
2964
+ isAllowedType =
2965
+ type.name.value === 'String' || isScalarType(schema.getType(type.name.value));
2958
2966
  }
2959
2967
  }
2960
2968
  if (!isAllowedType) {
@@ -3171,7 +3179,8 @@ const rule$j = {
3171
3179
  title: 'Correct',
3172
3180
  code: /* GraphQL */ `
3173
3181
  type User {
3174
- firstname: String @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
3182
+ firstname: String
3183
+ @deprecated(reason: "Use 'firstName' instead", deletionDate: "25/12/2022")
3175
3184
  firstName: String
3176
3185
  }
3177
3186
  `,
@@ -3410,7 +3419,8 @@ const rule$l = {
3410
3419
  ...Object.fromEntries([...ALLOWED_KINDS$1].sort().map(kind => {
3411
3420
  let description = `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
3412
3421
  if (kind === Kind.OPERATION_DEFINITION) {
3413
- description += '\n\n> You must use only comment syntax `#` and not description syntax `"""` or `"`.';
3422
+ description +=
3423
+ '\n\n> You must use only comment syntax `#` and not description syntax `"""` or `"`.';
3414
3424
  }
3415
3425
  return [kind, { type: 'boolean', description }];
3416
3426
  })),
@@ -3728,7 +3738,6 @@ const RULE_ID$d = 'selection-set-depth';
3728
3738
  const rule$o = {
3729
3739
  meta: {
3730
3740
  type: 'suggestion',
3731
- // eslint-disable-next-line eslint-plugin/require-meta-has-suggestions -- optional since we can't provide fixes for fragments located in separate files
3732
3741
  hasSuggestions: true,
3733
3742
  docs: {
3734
3743
  category: 'Operations',
@@ -3965,7 +3974,11 @@ const rule$p = {
3965
3974
  ...context.options[0],
3966
3975
  };
3967
3976
  const schema = requireGraphQLSchemaFromContext(RULE_ID$e, context);
3968
- const rootTypeNames = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
3977
+ const rootTypeNames = [
3978
+ schema.getQueryType(),
3979
+ schema.getMutationType(),
3980
+ schema.getSubscriptionType(),
3981
+ ]
3969
3982
  .filter(Boolean)
3970
3983
  .map(type => type.name);
3971
3984
  const selector = `ObjectTypeDefinition[name.value!=/^(${rootTypeNames.join('|')})$/]`;
@@ -3983,7 +3996,8 @@ const rule$p = {
3983
3996
  const isValidIdName = options.acceptedIdNames.includes(fieldNode.name.value);
3984
3997
  // To be a valid type, it must be non-null and one of the accepted types.
3985
3998
  let isValidIdType = false;
3986
- if (fieldNode.type.kind === Kind.NON_NULL_TYPE && fieldNode.type.type.kind === Kind.NAMED_TYPE) {
3999
+ if (fieldNode.type.kind === Kind.NON_NULL_TYPE &&
4000
+ fieldNode.type.type.kind === Kind.NAMED_TYPE) {
3987
4001
  isValidIdType = options.acceptedIdTypes.includes(fieldNode.type.type.name.value);
3988
4002
  }
3989
4003
  return isValidIdName && isValidIdType;
@@ -4008,7 +4022,9 @@ const RULE_ID$f = 'unique-fragment-name';
4008
4022
  const checkNode = (context, node, ruleId) => {
4009
4023
  const documentName = node.name.value;
4010
4024
  const siblings = requireSiblingsOperations(ruleId, context);
4011
- const siblingDocuments = node.kind === Kind.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
4025
+ const siblingDocuments = node.kind === Kind.FRAGMENT_DEFINITION
4026
+ ? siblings.getFragment(documentName)
4027
+ : siblings.getOperation(documentName);
4012
4028
  const filepath = context.getFilename();
4013
4029
  const conflictingDocuments = siblingDocuments.filter(f => {
4014
4030
  var _a;
@@ -4404,7 +4420,9 @@ function parseForESLint(code, options = {}) {
4404
4420
  const filePath = options.filePath || '';
4405
4421
  const realFilepath = filePath && getOnDiskFilepath(filePath);
4406
4422
  const gqlConfig = loadGraphQLConfig(options);
4407
- const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
4423
+ const projectForFile = realFilepath
4424
+ ? gqlConfig.getProjectForFile(realFilepath)
4425
+ : gqlConfig.getDefault();
4408
4426
  const schema = getSchema(projectForFile, options);
4409
4427
  const siblingOperations = getSiblingOperations(projectForFile);
4410
4428
  const { document } = parseGraphQLSDL(filePath, code, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.11.0-alpha-20220828135635-ce6bf36",
3
+ "version": "3.11.0-alpha-20220923192439-db921ff",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -11,8 +11,6 @@ export declare type AlphabetizeConfig = {
11
11
  variables?: typeof variablesEnum;
12
12
  arguments?: typeof argumentsEnum;
13
13
  definitions?: boolean;
14
- ignorePrefix?: string[];
15
- ignoreSuffix?: string[];
16
14
  };
17
15
  declare const rule: GraphQLESLintRule<[AlphabetizeConfig]>;
18
16
  export default rule;
package/types.d.ts CHANGED
@@ -47,26 +47,29 @@ export declare type GraphQLESLintRuleContext<Options = any[]> = Omit<Rule.RuleCo
47
47
  };
48
48
  export declare type CategoryType = 'Schema' | 'Operations';
49
49
  export declare type RuleDocsInfo<T> = {
50
- docs: Omit<Rule.RuleMetaData['docs'], 'category'> & {
51
- category: CategoryType | CategoryType[];
52
- requiresSchema?: true;
53
- requiresSiblings?: true;
54
- examples?: {
55
- title: string;
56
- code: string;
57
- usage?: T;
58
- }[];
59
- configOptions?: T | {
60
- schema?: T;
61
- operations?: T;
62
- };
63
- graphQLJSRuleName?: string;
64
- isDisabledForAllConfig?: true;
50
+ description: string;
51
+ category: CategoryType | CategoryType[];
52
+ recommended?: boolean;
53
+ url: string;
54
+ requiresSchema?: true;
55
+ requiresSiblings?: true;
56
+ examples?: {
57
+ title: string;
58
+ code: string;
59
+ usage?: T;
60
+ }[];
61
+ configOptions?: T | {
62
+ schema?: T;
63
+ operations?: T;
65
64
  };
65
+ graphQLJSRuleName?: string;
66
+ isDisabledForAllConfig?: true;
66
67
  };
67
68
  export declare type GraphQLESLintRule<Options = any[], WithTypeInfo extends boolean = false> = {
68
69
  create(context: GraphQLESLintRuleContext<Options>): GraphQLESLintRuleListener<WithTypeInfo>;
69
- meta: Omit<Rule.RuleMetaData, 'docs'> & RuleDocsInfo<Options>;
70
+ meta: Omit<Rule.RuleMetaData, 'docs'> & {
71
+ docs: RuleDocsInfo<Options>;
72
+ };
70
73
  };
71
74
  export declare type ValueOf<T> = T[keyof T];
72
75
  declare type Id<T> = {} & {