@graphql-eslint/eslint-plugin 3.1.0-alpha-878c908.0 → 3.1.0-alpha-27dcb49.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/docs/README.md CHANGED
@@ -4,67 +4,66 @@ Each rule has emojis denoting:
4
4
 
5
5
  - 🚀 `graphql-eslint` rule
6
6
  - 🔮 `graphql-js` rule
7
- - 🔧 if some problems reported by the rule are automatically fixable by the `--fix` [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) option
8
7
 
9
8
  <!-- 🚨 IMPORTANT! Do not manually modify this table. Run: `yarn generate:docs` -->
10
9
  <!-- prettier-ignore-start -->
11
- Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|Description|&nbsp;&nbsp;&nbsp;&nbsp;Config&nbsp;&nbsp;&nbsp;&nbsp;|🚀&nbsp;/&nbsp;🔮|🔧
12
- -|-|:-:|:-:|-
13
- [alphabetize](rules/alphabetize.md)|Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.|![all][]|🚀|
14
- [description-style](rules/description-style.md)|Require all comments to follow the same style (either block or inline).|![recommended][]|🚀|
15
- [executable-definitions](rules/executable-definitions.md)|A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.|![recommended][]|🔮|
16
- [fields-on-correct-type](rules/fields-on-correct-type.md)|A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.|![recommended][]|🔮|
17
- [fragments-on-composite-type](rules/fragments-on-composite-type.md)|Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.|![recommended][]|🔮|
18
- [input-name](rules/input-name.md)|Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".|![all][]|🚀|
19
- [known-argument-names](rules/known-argument-names.md)|A GraphQL field is only valid if all supplied arguments are defined by that field.|![recommended][]|🔮|
20
- [known-directives](rules/known-directives.md)|A GraphQL document is only valid if all `@directives` are known by the schema and legally positioned.|![recommended][]|🔮|
21
- [known-fragment-names](rules/known-fragment-names.md)|A GraphQL document is only valid if all `...Fragment` fragment spreads refer to fragments defined in the same document.|![recommended][]|🔮|
22
- [known-type-names](rules/known-type-names.md)|A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.|![recommended][]|🔮|
23
- [lone-anonymous-operation](rules/lone-anonymous-operation.md)|A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.|![recommended][]|🔮|
24
- [lone-schema-definition](rules/lone-schema-definition.md)|A GraphQL document is only valid if it contains only one schema definition.|![recommended][]|🔮|
25
- [match-document-filename](rules/match-document-filename.md)|This rule allows you to enforce that the file name should match the operation name.|![all][]|🚀|
26
- [naming-convention](rules/naming-convention.md)|Require names to follow specified conventions.|![recommended][]|🚀|
27
- [no-anonymous-operations](rules/no-anonymous-operations.md)|Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.|![recommended][]|🚀|
28
- [no-case-insensitive-enum-values-duplicates](rules/no-case-insensitive-enum-values-duplicates.md)|Disallow case-insensitive enum values duplicates.|![recommended][]|🚀|
29
- [no-deprecated](rules/no-deprecated.md)|Enforce that deprecated fields or enum values are not in use by operations.|![recommended][]|🚀|
30
- [no-duplicate-fields](rules/no-duplicate-fields.md)|Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.|![recommended][]|🚀|
31
- [no-fragment-cycles](rules/no-fragment-cycles.md)|A GraphQL fragment is only valid when it does not have cycles in fragments usage.|![recommended][]|🔮|
32
- [no-hashtag-description](rules/no-hashtag-description.md)|Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.|![recommended][]|🚀|
33
- [no-root-type](rules/no-root-type.md)|Disallow using root types `mutation` and/or `subscription`.||🚀|
34
- [no-scalar-result-type-on-mutation](rules/no-scalar-result-type-on-mutation.md)|Avoid scalar result type on mutation type to make sure to return a valid state.|![all][]|🚀|
35
- [no-typename-prefix](rules/no-typename-prefix.md)|Enforces users to avoid using the type name in a field name while defining your schema.|![recommended][]|🚀|
36
- [no-undefined-variables](rules/no-undefined-variables.md)|A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.|![recommended][]|🔮|
37
- [no-unreachable-types](rules/no-unreachable-types.md)|Requires all types to be reachable at some level by root level fields.|![recommended][]|🚀|🔧
38
- [no-unused-fields](rules/no-unused-fields.md)|Requires all fields to be used at some level by siblings operations.||🚀|🔧
39
- [no-unused-fragments](rules/no-unused-fragments.md)|A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.|![recommended][]|🔮|
40
- [no-unused-variables](rules/no-unused-variables.md)|A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.|![recommended][]|🔮|
41
- [one-field-subscriptions](rules/one-field-subscriptions.md)|A GraphQL subscription is valid only if it contains a single root field.|![recommended][]|🔮|
42
- [overlapping-fields-can-be-merged](rules/overlapping-fields-can-be-merged.md)|A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.|![recommended][]|🔮|
43
- [possible-fragment-spread](rules/possible-fragment-spread.md)|A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.|![recommended][]|🔮|
44
- [possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind.||🔮|
45
- [provided-required-arguments](rules/provided-required-arguments.md)|A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.|![recommended][]|🔮|
46
- [require-deprecation-date](rules/require-deprecation-date.md)|Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.|![all][]|🚀|
47
- [require-deprecation-reason](rules/require-deprecation-reason.md)|Require all deprecation directives to specify a reason.|![recommended][]|🚀|
48
- [require-description](rules/require-description.md)|Enforce descriptions in your type definitions.|![recommended][]|🚀|
49
- [require-field-of-type-query-in-mutation-result](rules/require-field-of-type-query-in-mutation-result.md)|Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.|![all][]|🚀|
50
- [require-id-when-available](rules/require-id-when-available.md)|Enforce selecting specific fields when they are available on the GraphQL type.|![recommended][]|🚀|
51
- [scalar-leafs](rules/scalar-leafs.md)|A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.|![recommended][]|🔮|
52
- [selection-set-depth](rules/selection-set-depth.md)|Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).|![recommended][]|🚀|
53
- [strict-id-in-types](rules/strict-id-in-types.md)|Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.|![recommended][]|🚀|
54
- [unique-argument-names](rules/unique-argument-names.md)|A GraphQL field or directive is only valid if all supplied arguments are uniquely named.|![recommended][]|🔮|
55
- [unique-directive-names](rules/unique-directive-names.md)|A GraphQL document is only valid if all defined directives have unique names.|![recommended][]|🔮|
56
- [unique-directive-names-per-location](rules/unique-directive-names-per-location.md)|A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.|![recommended][]|🔮|
57
- [unique-enum-value-names](rules/unique-enum-value-names.md)|A GraphQL enum type is only valid if all its values are uniquely named.||🔮|
58
- [unique-field-definition-names](rules/unique-field-definition-names.md)|A GraphQL complex type is only valid if all its fields are uniquely named.|![recommended][]|🔮|
59
- [unique-fragment-name](rules/unique-fragment-name.md)|Enforce unique fragment names across your project.|![all][]|🚀|
60
- [unique-input-field-names](rules/unique-input-field-names.md)|A GraphQL input object value is only valid if all supplied fields are uniquely named.|![recommended][]|🔮|
61
- [unique-operation-name](rules/unique-operation-name.md)|Enforce unique operation names across your project.|![all][]|🚀|
62
- [unique-operation-types](rules/unique-operation-types.md)|A GraphQL document is only valid if it has only one type per operation.|![recommended][]|🔮|
63
- [unique-type-names](rules/unique-type-names.md)|A GraphQL document is only valid if all defined types have unique names.|![recommended][]|🔮|
64
- [unique-variable-names](rules/unique-variable-names.md)|A GraphQL operation is only valid if all its variables are uniquely named.|![recommended][]|🔮|
65
- [value-literals-of-correct-type](rules/value-literals-of-correct-type.md)|A GraphQL document is only valid if all value literals are of the type expected at their position.|![recommended][]|🔮|
66
- [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][]|🔮|
67
- [variables-in-allowed-position](rules/variables-in-allowed-position.md)|Variables passed to field arguments conform to type.|![recommended][]|🔮|
10
+ Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|Description|&nbsp;&nbsp;&nbsp;&nbsp;Config&nbsp;&nbsp;&nbsp;&nbsp;|🚀&nbsp;/&nbsp;🔮
11
+ -|-|:-:|:-:
12
+ [alphabetize](rules/alphabetize.md)|Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.|![all][]|🚀
13
+ [description-style](rules/description-style.md)|Require all comments to follow the same style (either block or inline).|![recommended][]|🚀
14
+ [executable-definitions](rules/executable-definitions.md)|A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.|![recommended][]|🔮
15
+ [fields-on-correct-type](rules/fields-on-correct-type.md)|A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.|![recommended][]|🔮
16
+ [fragments-on-composite-type](rules/fragments-on-composite-type.md)|Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.|![recommended][]|🔮
17
+ [input-name](rules/input-name.md)|Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".|![all][]|🚀
18
+ [known-argument-names](rules/known-argument-names.md)|A GraphQL field is only valid if all supplied arguments are defined by that field.|![recommended][]|🔮
19
+ [known-directives](rules/known-directives.md)|A GraphQL document is only valid if all `@directives` are known by the schema and legally positioned.|![recommended][]|🔮
20
+ [known-fragment-names](rules/known-fragment-names.md)|A GraphQL document is only valid if all `...Fragment` fragment spreads refer to fragments defined in the same document.|![recommended][]|🔮
21
+ [known-type-names](rules/known-type-names.md)|A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.|![recommended][]|🔮
22
+ [lone-anonymous-operation](rules/lone-anonymous-operation.md)|A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.|![recommended][]|🔮
23
+ [lone-schema-definition](rules/lone-schema-definition.md)|A GraphQL document is only valid if it contains only one schema definition.|![recommended][]|🔮
24
+ [match-document-filename](rules/match-document-filename.md)|This rule allows you to enforce that the file name should match the operation name.|![all][]|🚀
25
+ [naming-convention](rules/naming-convention.md)|Require names to follow specified conventions.|![recommended][]|🚀
26
+ [no-anonymous-operations](rules/no-anonymous-operations.md)|Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.|![recommended][]|🚀
27
+ [no-case-insensitive-enum-values-duplicates](rules/no-case-insensitive-enum-values-duplicates.md)|Disallow case-insensitive enum values duplicates.|![recommended][]|🚀
28
+ [no-deprecated](rules/no-deprecated.md)|Enforce that deprecated fields or enum values are not in use by operations.|![recommended][]|🚀
29
+ [no-duplicate-fields](rules/no-duplicate-fields.md)|Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.|![recommended][]|🚀
30
+ [no-fragment-cycles](rules/no-fragment-cycles.md)|A GraphQL fragment is only valid when it does not have cycles in fragments usage.|![recommended][]|🔮
31
+ [no-hashtag-description](rules/no-hashtag-description.md)|Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.|![recommended][]|🚀
32
+ [no-root-type](rules/no-root-type.md)|Disallow using root types `mutation` and/or `subscription`.||🚀
33
+ [no-scalar-result-type-on-mutation](rules/no-scalar-result-type-on-mutation.md)|Avoid scalar result type on mutation type to make sure to return a valid state.|![all][]|🚀
34
+ [no-typename-prefix](rules/no-typename-prefix.md)|Enforces users to avoid using the type name in a field name while defining your schema.|![recommended][]|🚀
35
+ [no-undefined-variables](rules/no-undefined-variables.md)|A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.|![recommended][]|🔮
36
+ [no-unreachable-types](rules/no-unreachable-types.md)|Requires all types to be reachable at some level by root level fields.|![recommended][]|🚀
37
+ [no-unused-fields](rules/no-unused-fields.md)|Requires all fields to be used at some level by siblings operations.||🚀
38
+ [no-unused-fragments](rules/no-unused-fragments.md)|A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.|![recommended][]|🔮
39
+ [no-unused-variables](rules/no-unused-variables.md)|A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.|![recommended][]|🔮
40
+ [one-field-subscriptions](rules/one-field-subscriptions.md)|A GraphQL subscription is valid only if it contains a single root field.|![recommended][]|🔮
41
+ [overlapping-fields-can-be-merged](rules/overlapping-fields-can-be-merged.md)|A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.|![recommended][]|🔮
42
+ [possible-fragment-spread](rules/possible-fragment-spread.md)|A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.|![recommended][]|🔮
43
+ [possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind.||🔮
44
+ [provided-required-arguments](rules/provided-required-arguments.md)|A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.|![recommended][]|🔮
45
+ [require-deprecation-date](rules/require-deprecation-date.md)|Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.|![all][]|🚀
46
+ [require-deprecation-reason](rules/require-deprecation-reason.md)|Require all deprecation directives to specify a reason.|![recommended][]|🚀
47
+ [require-description](rules/require-description.md)|Enforce descriptions in your type definitions.|![recommended][]|🚀
48
+ [require-field-of-type-query-in-mutation-result](rules/require-field-of-type-query-in-mutation-result.md)|Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.|![all][]|🚀
49
+ [require-id-when-available](rules/require-id-when-available.md)|Enforce selecting specific fields when they are available on the GraphQL type.|![recommended][]|🚀
50
+ [scalar-leafs](rules/scalar-leafs.md)|A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.|![recommended][]|🔮
51
+ [selection-set-depth](rules/selection-set-depth.md)|Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).|![recommended][]|🚀
52
+ [strict-id-in-types](rules/strict-id-in-types.md)|Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.|![recommended][]|🚀
53
+ [unique-argument-names](rules/unique-argument-names.md)|A GraphQL field or directive is only valid if all supplied arguments are uniquely named.|![recommended][]|🔮
54
+ [unique-directive-names](rules/unique-directive-names.md)|A GraphQL document is only valid if all defined directives have unique names.|![recommended][]|🔮
55
+ [unique-directive-names-per-location](rules/unique-directive-names-per-location.md)|A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.|![recommended][]|🔮
56
+ [unique-enum-value-names](rules/unique-enum-value-names.md)|A GraphQL enum type is only valid if all its values are uniquely named.||🔮
57
+ [unique-field-definition-names](rules/unique-field-definition-names.md)|A GraphQL complex type is only valid if all its fields are uniquely named.|![recommended][]|🔮
58
+ [unique-fragment-name](rules/unique-fragment-name.md)|Enforce unique fragment names across your project.|![all][]|🚀
59
+ [unique-input-field-names](rules/unique-input-field-names.md)|A GraphQL input object value is only valid if all supplied fields are uniquely named.|![recommended][]|🔮
60
+ [unique-operation-name](rules/unique-operation-name.md)|Enforce unique operation names across your project.|![all][]|🚀
61
+ [unique-operation-types](rules/unique-operation-types.md)|A GraphQL document is only valid if it has only one type per operation.|![recommended][]|🔮
62
+ [unique-type-names](rules/unique-type-names.md)|A GraphQL document is only valid if all defined types have unique names.|![recommended][]|🔮
63
+ [unique-variable-names](rules/unique-variable-names.md)|A GraphQL operation is only valid if all its variables are uniquely named.|![recommended][]|🔮
64
+ [value-literals-of-correct-type](rules/value-literals-of-correct-type.md)|A GraphQL document is only valid if all value literals are of the type expected at their position.|![recommended][]|🔮
65
+ [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][]|🔮
66
+ [variables-in-allowed-position](rules/variables-in-allowed-position.md)|Variables passed to field arguments conform to type.|![recommended][]|🔮
68
67
  <!-- prettier-ignore-end -->
69
68
  [recommended]: https://img.shields.io/badge/-recommended-green.svg
70
69
  [all]: https://img.shields.io/badge/-all-blue.svg
@@ -2,8 +2,6 @@
2
2
 
3
3
  ✅ The `"extends": "plugin:@graphql-eslint/schema-recommended"` property in a configuration file enables this rule.
4
4
 
5
- 🔧 The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#--fix) can automatically fix some of the problems reported by this rule.
6
-
7
5
  - Category: `Schema`
8
6
  - Rule name: `@graphql-eslint/no-unreachable-types`
9
7
  - Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
@@ -1,7 +1,5 @@
1
1
  # `no-unused-fields`
2
2
 
3
- 🔧 The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#--fix) can automatically fix some of the problems reported by this rule.
4
-
5
3
  - Category: `Schema`
6
4
  - Rule name: `@graphql-eslint/no-unused-fields`
7
5
  - Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
@@ -54,25 +54,10 @@ query user {
54
54
 
55
55
  The schema defines the following properties:
56
56
 
57
- ### `fieldName`
58
-
59
- The object must be one of the following types:
60
-
61
- * `asString`
62
- * `asArray`
57
+ ### `fieldName` (string)
63
58
 
64
59
  Default: `"id"`
65
60
 
66
- ---
67
-
68
- # Sub Schemas
69
-
70
- The schema defines the following additional types:
71
-
72
- ## `asString` (string)
73
-
74
- ## `asArray` (array)
75
-
76
61
  ## Resources
77
62
 
78
63
  - [Rule source](../../packages/plugin/src/rules/require-id-when-available.ts)
package/index.js CHANGED
@@ -2106,7 +2106,22 @@ const rule$c = {
2106
2106
  };
2107
2107
 
2108
2108
  const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
2109
- const RULE_NAME = 'no-unreachable-types';
2109
+ const RULE_ID = 'no-unreachable-types';
2110
+ const KINDS = [
2111
+ graphql.Kind.DIRECTIVE_DEFINITION,
2112
+ graphql.Kind.OBJECT_TYPE_DEFINITION,
2113
+ graphql.Kind.OBJECT_TYPE_EXTENSION,
2114
+ graphql.Kind.INTERFACE_TYPE_DEFINITION,
2115
+ graphql.Kind.INTERFACE_TYPE_EXTENSION,
2116
+ graphql.Kind.SCALAR_TYPE_DEFINITION,
2117
+ graphql.Kind.SCALAR_TYPE_EXTENSION,
2118
+ graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
2119
+ graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION,
2120
+ graphql.Kind.UNION_TYPE_DEFINITION,
2121
+ graphql.Kind.UNION_TYPE_EXTENSION,
2122
+ graphql.Kind.ENUM_TYPE_DEFINITION,
2123
+ graphql.Kind.ENUM_TYPE_EXTENSION,
2124
+ ];
2110
2125
  const rule$d = {
2111
2126
  meta: {
2112
2127
  messages: {
@@ -2115,7 +2130,7 @@ const rule$d = {
2115
2130
  docs: {
2116
2131
  description: `Requires all types to be reachable at some level by root level fields.`,
2117
2132
  category: 'Schema',
2118
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
2133
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
2119
2134
  requiresSchema: true,
2120
2135
  examples: [
2121
2136
  {
@@ -2147,43 +2162,36 @@ const rule$d = {
2147
2162
  ],
2148
2163
  recommended: true,
2149
2164
  },
2150
- fixable: 'code',
2151
2165
  type: 'suggestion',
2152
2166
  schema: [],
2167
+ hasSuggestions: true,
2153
2168
  },
2154
2169
  create(context) {
2155
- const reachableTypes = requireReachableTypesFromContext(RULE_NAME, context);
2156
- function ensureReachability(node) {
2157
- const typeName = node.name.value;
2158
- if (!reachableTypes.has(typeName)) {
2159
- context.report({
2160
- loc: getLocation(node.name.loc, typeName, { offsetStart: node.kind === graphql.Kind.DIRECTIVE_DEFINITION ? 2 : 1 }),
2161
- messageId: UNREACHABLE_TYPE,
2162
- data: { typeName },
2163
- fix: fixer => fixer.remove(node),
2164
- });
2165
- }
2166
- }
2170
+ const reachableTypes = requireReachableTypesFromContext(RULE_ID, context);
2171
+ const selector = KINDS.join(',');
2167
2172
  return {
2168
- DirectiveDefinition: ensureReachability,
2169
- ObjectTypeDefinition: ensureReachability,
2170
- ObjectTypeExtension: ensureReachability,
2171
- InterfaceTypeDefinition: ensureReachability,
2172
- InterfaceTypeExtension: ensureReachability,
2173
- ScalarTypeDefinition: ensureReachability,
2174
- ScalarTypeExtension: ensureReachability,
2175
- InputObjectTypeDefinition: ensureReachability,
2176
- InputObjectTypeExtension: ensureReachability,
2177
- UnionTypeDefinition: ensureReachability,
2178
- UnionTypeExtension: ensureReachability,
2179
- EnumTypeDefinition: ensureReachability,
2180
- EnumTypeExtension: ensureReachability,
2173
+ [selector](node) {
2174
+ const typeName = node.name.value;
2175
+ if (!reachableTypes.has(typeName)) {
2176
+ context.report({
2177
+ loc: getLocation(node.name.loc, typeName, { offsetStart: node.kind === graphql.Kind.DIRECTIVE_DEFINITION ? 2 : 1 }),
2178
+ messageId: UNREACHABLE_TYPE,
2179
+ data: { typeName },
2180
+ suggest: [
2181
+ {
2182
+ desc: `Remove ${typeName}`,
2183
+ fix: fixer => fixer.remove(node),
2184
+ },
2185
+ ],
2186
+ });
2187
+ }
2188
+ },
2181
2189
  };
2182
2190
  },
2183
2191
  };
2184
2192
 
2185
2193
  const UNUSED_FIELD = 'UNUSED_FIELD';
2186
- const RULE_NAME$1 = 'no-unused-fields';
2194
+ const RULE_ID$1 = 'no-unused-fields';
2187
2195
  const rule$e = {
2188
2196
  meta: {
2189
2197
  messages: {
@@ -2192,7 +2200,7 @@ const rule$e = {
2192
2200
  docs: {
2193
2201
  description: `Requires all fields to be used at some level by siblings operations.`,
2194
2202
  category: 'Schema',
2195
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
2203
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$1}.md`,
2196
2204
  requiresSiblings: true,
2197
2205
  requiresSchema: true,
2198
2206
  examples: [
@@ -2239,12 +2247,12 @@ const rule$e = {
2239
2247
  },
2240
2248
  ],
2241
2249
  },
2242
- fixable: 'code',
2243
2250
  type: 'suggestion',
2244
2251
  schema: [],
2252
+ hasSuggestions: true,
2245
2253
  },
2246
2254
  create(context) {
2247
- const usedFields = requireUsedFieldsFromContext(RULE_NAME$1, context);
2255
+ const usedFields = requireUsedFieldsFromContext(RULE_ID$1, context);
2248
2256
  return {
2249
2257
  FieldDefinition(node) {
2250
2258
  var _a;
@@ -2258,22 +2266,18 @@ const rule$e = {
2258
2266
  loc: getLocation(node.loc, fieldName),
2259
2267
  messageId: UNUSED_FIELD,
2260
2268
  data: { fieldName },
2261
- fix(fixer) {
2262
- const sourceCode = context.getSourceCode();
2263
- const tokenBefore = sourceCode.getTokenBefore(node);
2264
- const tokenAfter = sourceCode.getTokenAfter(node);
2265
- const isEmptyType = tokenBefore.type === '{' && tokenAfter.type === '}';
2266
- if (isEmptyType) {
2267
- // Remove type
2268
- const { parent } = node;
2269
- const parentBeforeToken = sourceCode.getTokenBefore(parent);
2270
- return parentBeforeToken
2271
- ? fixer.removeRange([parentBeforeToken.range[1], parent.range[1]])
2272
- : fixer.remove(parent);
2273
- }
2274
- // Remove whitespace before token
2275
- return fixer.removeRange([tokenBefore.range[1], node.range[1]]);
2276
- },
2269
+ suggest: [
2270
+ {
2271
+ desc: `Remove "${fieldName}" field`,
2272
+ fix(fixer) {
2273
+ const sourceCode = context.getSourceCode();
2274
+ const tokenBefore = sourceCode.getTokenBefore(node);
2275
+ const tokenAfter = sourceCode.getTokenAfter(node);
2276
+ const isEmptyType = tokenBefore.type === '{' && tokenAfter.type === '}';
2277
+ return isEmptyType ? fixer.remove(node.parent) : fixer.remove(node);
2278
+ },
2279
+ },
2280
+ ],
2277
2281
  });
2278
2282
  },
2279
2283
  };
@@ -2636,14 +2640,14 @@ const rule$h = {
2636
2640
  },
2637
2641
  };
2638
2642
 
2639
- const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
2643
+ const RULE_NAME = 'require-field-of-type-query-in-mutation-result';
2640
2644
  const rule$i = {
2641
2645
  meta: {
2642
2646
  type: 'suggestion',
2643
2647
  docs: {
2644
2648
  category: 'Schema',
2645
2649
  description: 'Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.\n> Currently, no errors are reported for result type `union`, `interface` and `scalar`.',
2646
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
2650
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
2647
2651
  requiresSchema: true,
2648
2652
  examples: [
2649
2653
  {
@@ -2678,7 +2682,7 @@ const rule$i = {
2678
2682
  schema: [],
2679
2683
  },
2680
2684
  create(context) {
2681
- const schema = requireGraphQLSchemaFromContext(RULE_NAME$2, context);
2685
+ const schema = requireGraphQLSchemaFromContext(RULE_NAME, context);
2682
2686
  const mutationType = schema.getMutationType();
2683
2687
  const queryType = schema.getQueryType();
2684
2688
  if (!mutationType || !queryType) {
@@ -2852,22 +2856,9 @@ const rule$j = {
2852
2856
  recommended: true,
2853
2857
  },
2854
2858
  messages: {
2855
- [REQUIRE_ID_WHEN_AVAILABLE]: [
2856
- `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2857
- `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2858
- ].join('\n'),
2859
+ [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{ checkedFragments }} specifies the field "{{ fieldName }}".`,
2859
2860
  },
2860
2861
  schema: {
2861
- definitions: {
2862
- asString: {
2863
- type: 'string',
2864
- },
2865
- asArray: {
2866
- type: 'array',
2867
- minItems: 1,
2868
- uniqueItems: true,
2869
- },
2870
- },
2871
2862
  type: 'array',
2872
2863
  maxItems: 1,
2873
2864
  items: {
@@ -2875,7 +2866,7 @@ const rule$j = {
2875
2866
  additionalProperties: false,
2876
2867
  properties: {
2877
2868
  fieldName: {
2878
- oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asArray' }],
2869
+ type: 'string',
2879
2870
  default: DEFAULT_ID_FIELD_NAME,
2880
2871
  },
2881
2872
  },
@@ -2883,64 +2874,69 @@ const rule$j = {
2883
2874
  },
2884
2875
  },
2885
2876
  create(context) {
2886
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2887
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2888
- const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2889
- const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2890
- const isFound = (s) => s.kind === graphql.Kind.FIELD && idNames.includes(s.name.value);
2891
2877
  return {
2892
2878
  SelectionSet(node) {
2893
2879
  var _a, _b;
2894
- const typeInfo = node.typeInfo();
2895
- if (!typeInfo.gqlType) {
2896
- return;
2897
- }
2898
- const rawType = getBaseType(typeInfo.gqlType);
2899
- const isObjectType = rawType instanceof graphql.GraphQLObjectType;
2900
- const isInterfaceType = rawType instanceof graphql.GraphQLInterfaceType;
2901
- if (!isObjectType && !isInterfaceType) {
2880
+ requireGraphQLSchemaFromContext('require-id-when-available', context);
2881
+ const siblings = requireSiblingsOperations('require-id-when-available', context);
2882
+ const fieldName = (context.options[0] || {}).fieldName || DEFAULT_ID_FIELD_NAME;
2883
+ if (!node.selections || node.selections.length === 0) {
2902
2884
  return;
2903
2885
  }
2904
- const fields = rawType.getFields();
2905
- const hasIdFieldInType = idNames.some(name => fields[name]);
2906
- if (!hasIdFieldInType) {
2907
- return;
2908
- }
2909
- const checkedFragmentSpreads = new Set();
2910
- let found = false;
2911
- for (const selection of node.selections) {
2912
- if (isFound(selection)) {
2913
- found = true;
2914
- }
2915
- else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
2916
- found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
2917
- }
2918
- else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
2919
- const [foundSpread] = siblings.getFragment(selection.name.value);
2920
- if (foundSpread) {
2921
- checkedFragmentSpreads.add(foundSpread.document.name.value);
2922
- found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
2886
+ const typeInfo = node.typeInfo();
2887
+ if (typeInfo && typeInfo.gqlType) {
2888
+ const rawType = getBaseType(typeInfo.gqlType);
2889
+ if (rawType instanceof graphql.GraphQLObjectType || rawType instanceof graphql.GraphQLInterfaceType) {
2890
+ const fields = rawType.getFields();
2891
+ const hasIdFieldInType = !!fields[fieldName];
2892
+ const checkedFragmentSpreads = new Set();
2893
+ if (hasIdFieldInType) {
2894
+ let found = false;
2895
+ for (const selection of node.selections) {
2896
+ if (selection.kind === 'Field' && selection.name.value === fieldName) {
2897
+ found = true;
2898
+ }
2899
+ else if (selection.kind === 'InlineFragment') {
2900
+ found = (((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2901
+ }
2902
+ else if (selection.kind === 'FragmentSpread') {
2903
+ const foundSpread = siblings.getFragment(selection.name.value);
2904
+ if (foundSpread[0]) {
2905
+ checkedFragmentSpreads.add(foundSpread[0].document.name.value);
2906
+ found = (((_b = foundSpread[0].document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2907
+ }
2908
+ }
2909
+ if (found) {
2910
+ break;
2911
+ }
2912
+ }
2913
+ const { parent } = node;
2914
+ const hasIdFieldInInterfaceSelectionSet = parent &&
2915
+ parent.kind === 'InlineFragment' &&
2916
+ parent.parent &&
2917
+ parent.parent.kind === 'SelectionSet' &&
2918
+ parent.parent.selections.some(s => s.kind === 'Field' && s.name.value === fieldName);
2919
+ if (!found && !hasIdFieldInInterfaceSelectionSet) {
2920
+ context.report({
2921
+ loc: {
2922
+ start: {
2923
+ line: node.loc.start.line,
2924
+ column: node.loc.start.column - 1,
2925
+ },
2926
+ end: {
2927
+ line: node.loc.end.line,
2928
+ column: node.loc.end.column - 1,
2929
+ },
2930
+ },
2931
+ messageId: REQUIRE_ID_WHEN_AVAILABLE,
2932
+ data: {
2933
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${Array.from(checkedFragmentSpreads).join(', ')})`,
2934
+ fieldName,
2935
+ },
2936
+ });
2937
+ }
2923
2938
  }
2924
2939
  }
2925
- if (found) {
2926
- break;
2927
- }
2928
- }
2929
- const { parent } = node;
2930
- const hasIdFieldInInterfaceSelectionSet = parent &&
2931
- parent.kind === graphql.Kind.INLINE_FRAGMENT &&
2932
- parent.parent &&
2933
- parent.parent.kind === graphql.Kind.SELECTION_SET &&
2934
- parent.parent.selections.some(s => isFound(s));
2935
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
2936
- context.report({
2937
- loc: getLocation(node.loc),
2938
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
2939
- data: {
2940
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
2941
- fieldName: idNames.map(name => `"${name}"`).join(' or '),
2942
- },
2943
- });
2944
2940
  }
2945
2941
  },
2946
2942
  };
@@ -3032,7 +3028,7 @@ const rule$k = {
3032
3028
  // eslint-disable-next-line no-console
3033
3029
  console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3034
3030
  }
3035
- const { maxDepth } = context.options[0];
3031
+ const maxDepth = context.options[0].maxDepth;
3036
3032
  const ignore = context.options[0].ignore || [];
3037
3033
  const checkFn = depthLimit(maxDepth, { ignore });
3038
3034
  return {
@@ -3229,7 +3225,7 @@ const rule$l = {
3229
3225
  },
3230
3226
  };
3231
3227
 
3232
- const RULE_NAME$3 = 'unique-fragment-name';
3228
+ const RULE_NAME$1 = 'unique-fragment-name';
3233
3229
  const UNIQUE_FRAGMENT_NAME = 'UNIQUE_FRAGMENT_NAME';
3234
3230
  const checkNode = (context, node, ruleName, messageId) => {
3235
3231
  const documentName = node.name.value;
@@ -3261,7 +3257,7 @@ const rule$m = {
3261
3257
  docs: {
3262
3258
  category: 'Operations',
3263
3259
  description: `Enforce unique fragment names across your project.`,
3264
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
3260
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
3265
3261
  requiresSiblings: true,
3266
3262
  examples: [
3267
3263
  {
@@ -3306,13 +3302,13 @@ const rule$m = {
3306
3302
  create(context) {
3307
3303
  return {
3308
3304
  FragmentDefinition(node) {
3309
- checkNode(context, node, RULE_NAME$3, UNIQUE_FRAGMENT_NAME);
3305
+ checkNode(context, node, RULE_NAME$1, UNIQUE_FRAGMENT_NAME);
3310
3306
  },
3311
3307
  };
3312
3308
  },
3313
3309
  };
3314
3310
 
3315
- const RULE_NAME$4 = 'unique-operation-name';
3311
+ const RULE_NAME$2 = 'unique-operation-name';
3316
3312
  const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
3317
3313
  const rule$n = {
3318
3314
  meta: {
@@ -3320,7 +3316,7 @@ const rule$n = {
3320
3316
  docs: {
3321
3317
  category: 'Operations',
3322
3318
  description: `Enforce unique operation names across your project.`,
3323
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
3319
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
3324
3320
  requiresSiblings: true,
3325
3321
  examples: [
3326
3322
  {
@@ -3369,7 +3365,7 @@ const rule$n = {
3369
3365
  create(context) {
3370
3366
  return {
3371
3367
  'OperationDefinition[name!=undefined]'(node) {
3372
- checkNode(context, node, RULE_NAME$4, UNIQUE_OPERATION_NAME);
3368
+ checkNode(context, node, RULE_NAME$2, UNIQUE_OPERATION_NAME);
3373
3369
  },
3374
3370
  };
3375
3371
  },
package/index.mjs CHANGED
@@ -2100,7 +2100,22 @@ const rule$c = {
2100
2100
  };
2101
2101
 
2102
2102
  const UNREACHABLE_TYPE = 'UNREACHABLE_TYPE';
2103
- const RULE_NAME = 'no-unreachable-types';
2103
+ const RULE_ID = 'no-unreachable-types';
2104
+ const KINDS = [
2105
+ Kind.DIRECTIVE_DEFINITION,
2106
+ Kind.OBJECT_TYPE_DEFINITION,
2107
+ Kind.OBJECT_TYPE_EXTENSION,
2108
+ Kind.INTERFACE_TYPE_DEFINITION,
2109
+ Kind.INTERFACE_TYPE_EXTENSION,
2110
+ Kind.SCALAR_TYPE_DEFINITION,
2111
+ Kind.SCALAR_TYPE_EXTENSION,
2112
+ Kind.INPUT_OBJECT_TYPE_DEFINITION,
2113
+ Kind.INPUT_OBJECT_TYPE_EXTENSION,
2114
+ Kind.UNION_TYPE_DEFINITION,
2115
+ Kind.UNION_TYPE_EXTENSION,
2116
+ Kind.ENUM_TYPE_DEFINITION,
2117
+ Kind.ENUM_TYPE_EXTENSION,
2118
+ ];
2104
2119
  const rule$d = {
2105
2120
  meta: {
2106
2121
  messages: {
@@ -2109,7 +2124,7 @@ const rule$d = {
2109
2124
  docs: {
2110
2125
  description: `Requires all types to be reachable at some level by root level fields.`,
2111
2126
  category: 'Schema',
2112
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
2127
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
2113
2128
  requiresSchema: true,
2114
2129
  examples: [
2115
2130
  {
@@ -2141,43 +2156,36 @@ const rule$d = {
2141
2156
  ],
2142
2157
  recommended: true,
2143
2158
  },
2144
- fixable: 'code',
2145
2159
  type: 'suggestion',
2146
2160
  schema: [],
2161
+ hasSuggestions: true,
2147
2162
  },
2148
2163
  create(context) {
2149
- const reachableTypes = requireReachableTypesFromContext(RULE_NAME, context);
2150
- function ensureReachability(node) {
2151
- const typeName = node.name.value;
2152
- if (!reachableTypes.has(typeName)) {
2153
- context.report({
2154
- loc: getLocation(node.name.loc, typeName, { offsetStart: node.kind === Kind.DIRECTIVE_DEFINITION ? 2 : 1 }),
2155
- messageId: UNREACHABLE_TYPE,
2156
- data: { typeName },
2157
- fix: fixer => fixer.remove(node),
2158
- });
2159
- }
2160
- }
2164
+ const reachableTypes = requireReachableTypesFromContext(RULE_ID, context);
2165
+ const selector = KINDS.join(',');
2161
2166
  return {
2162
- DirectiveDefinition: ensureReachability,
2163
- ObjectTypeDefinition: ensureReachability,
2164
- ObjectTypeExtension: ensureReachability,
2165
- InterfaceTypeDefinition: ensureReachability,
2166
- InterfaceTypeExtension: ensureReachability,
2167
- ScalarTypeDefinition: ensureReachability,
2168
- ScalarTypeExtension: ensureReachability,
2169
- InputObjectTypeDefinition: ensureReachability,
2170
- InputObjectTypeExtension: ensureReachability,
2171
- UnionTypeDefinition: ensureReachability,
2172
- UnionTypeExtension: ensureReachability,
2173
- EnumTypeDefinition: ensureReachability,
2174
- EnumTypeExtension: ensureReachability,
2167
+ [selector](node) {
2168
+ const typeName = node.name.value;
2169
+ if (!reachableTypes.has(typeName)) {
2170
+ context.report({
2171
+ loc: getLocation(node.name.loc, typeName, { offsetStart: node.kind === Kind.DIRECTIVE_DEFINITION ? 2 : 1 }),
2172
+ messageId: UNREACHABLE_TYPE,
2173
+ data: { typeName },
2174
+ suggest: [
2175
+ {
2176
+ desc: `Remove ${typeName}`,
2177
+ fix: fixer => fixer.remove(node),
2178
+ },
2179
+ ],
2180
+ });
2181
+ }
2182
+ },
2175
2183
  };
2176
2184
  },
2177
2185
  };
2178
2186
 
2179
2187
  const UNUSED_FIELD = 'UNUSED_FIELD';
2180
- const RULE_NAME$1 = 'no-unused-fields';
2188
+ const RULE_ID$1 = 'no-unused-fields';
2181
2189
  const rule$e = {
2182
2190
  meta: {
2183
2191
  messages: {
@@ -2186,7 +2194,7 @@ const rule$e = {
2186
2194
  docs: {
2187
2195
  description: `Requires all fields to be used at some level by siblings operations.`,
2188
2196
  category: 'Schema',
2189
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
2197
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$1}.md`,
2190
2198
  requiresSiblings: true,
2191
2199
  requiresSchema: true,
2192
2200
  examples: [
@@ -2233,12 +2241,12 @@ const rule$e = {
2233
2241
  },
2234
2242
  ],
2235
2243
  },
2236
- fixable: 'code',
2237
2244
  type: 'suggestion',
2238
2245
  schema: [],
2246
+ hasSuggestions: true,
2239
2247
  },
2240
2248
  create(context) {
2241
- const usedFields = requireUsedFieldsFromContext(RULE_NAME$1, context);
2249
+ const usedFields = requireUsedFieldsFromContext(RULE_ID$1, context);
2242
2250
  return {
2243
2251
  FieldDefinition(node) {
2244
2252
  var _a;
@@ -2252,22 +2260,18 @@ const rule$e = {
2252
2260
  loc: getLocation(node.loc, fieldName),
2253
2261
  messageId: UNUSED_FIELD,
2254
2262
  data: { fieldName },
2255
- fix(fixer) {
2256
- const sourceCode = context.getSourceCode();
2257
- const tokenBefore = sourceCode.getTokenBefore(node);
2258
- const tokenAfter = sourceCode.getTokenAfter(node);
2259
- const isEmptyType = tokenBefore.type === '{' && tokenAfter.type === '}';
2260
- if (isEmptyType) {
2261
- // Remove type
2262
- const { parent } = node;
2263
- const parentBeforeToken = sourceCode.getTokenBefore(parent);
2264
- return parentBeforeToken
2265
- ? fixer.removeRange([parentBeforeToken.range[1], parent.range[1]])
2266
- : fixer.remove(parent);
2267
- }
2268
- // Remove whitespace before token
2269
- return fixer.removeRange([tokenBefore.range[1], node.range[1]]);
2270
- },
2263
+ suggest: [
2264
+ {
2265
+ desc: `Remove "${fieldName}" field`,
2266
+ fix(fixer) {
2267
+ const sourceCode = context.getSourceCode();
2268
+ const tokenBefore = sourceCode.getTokenBefore(node);
2269
+ const tokenAfter = sourceCode.getTokenAfter(node);
2270
+ const isEmptyType = tokenBefore.type === '{' && tokenAfter.type === '}';
2271
+ return isEmptyType ? fixer.remove(node.parent) : fixer.remove(node);
2272
+ },
2273
+ },
2274
+ ],
2271
2275
  });
2272
2276
  },
2273
2277
  };
@@ -2630,14 +2634,14 @@ const rule$h = {
2630
2634
  },
2631
2635
  };
2632
2636
 
2633
- const RULE_NAME$2 = 'require-field-of-type-query-in-mutation-result';
2637
+ const RULE_NAME = 'require-field-of-type-query-in-mutation-result';
2634
2638
  const rule$i = {
2635
2639
  meta: {
2636
2640
  type: 'suggestion',
2637
2641
  docs: {
2638
2642
  category: 'Schema',
2639
2643
  description: 'Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.\n> Currently, no errors are reported for result type `union`, `interface` and `scalar`.',
2640
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
2644
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME}.md`,
2641
2645
  requiresSchema: true,
2642
2646
  examples: [
2643
2647
  {
@@ -2672,7 +2676,7 @@ const rule$i = {
2672
2676
  schema: [],
2673
2677
  },
2674
2678
  create(context) {
2675
- const schema = requireGraphQLSchemaFromContext(RULE_NAME$2, context);
2679
+ const schema = requireGraphQLSchemaFromContext(RULE_NAME, context);
2676
2680
  const mutationType = schema.getMutationType();
2677
2681
  const queryType = schema.getQueryType();
2678
2682
  if (!mutationType || !queryType) {
@@ -2846,22 +2850,9 @@ const rule$j = {
2846
2850
  recommended: true,
2847
2851
  },
2848
2852
  messages: {
2849
- [REQUIRE_ID_WHEN_AVAILABLE]: [
2850
- `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2851
- `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2852
- ].join('\n'),
2853
+ [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{ checkedFragments }} specifies the field "{{ fieldName }}".`,
2853
2854
  },
2854
2855
  schema: {
2855
- definitions: {
2856
- asString: {
2857
- type: 'string',
2858
- },
2859
- asArray: {
2860
- type: 'array',
2861
- minItems: 1,
2862
- uniqueItems: true,
2863
- },
2864
- },
2865
2856
  type: 'array',
2866
2857
  maxItems: 1,
2867
2858
  items: {
@@ -2869,7 +2860,7 @@ const rule$j = {
2869
2860
  additionalProperties: false,
2870
2861
  properties: {
2871
2862
  fieldName: {
2872
- oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asArray' }],
2863
+ type: 'string',
2873
2864
  default: DEFAULT_ID_FIELD_NAME,
2874
2865
  },
2875
2866
  },
@@ -2877,64 +2868,69 @@ const rule$j = {
2877
2868
  },
2878
2869
  },
2879
2870
  create(context) {
2880
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2881
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2882
- const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2883
- const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2884
- const isFound = (s) => s.kind === Kind.FIELD && idNames.includes(s.name.value);
2885
2871
  return {
2886
2872
  SelectionSet(node) {
2887
2873
  var _a, _b;
2888
- const typeInfo = node.typeInfo();
2889
- if (!typeInfo.gqlType) {
2890
- return;
2891
- }
2892
- const rawType = getBaseType(typeInfo.gqlType);
2893
- const isObjectType = rawType instanceof GraphQLObjectType;
2894
- const isInterfaceType = rawType instanceof GraphQLInterfaceType;
2895
- if (!isObjectType && !isInterfaceType) {
2874
+ requireGraphQLSchemaFromContext('require-id-when-available', context);
2875
+ const siblings = requireSiblingsOperations('require-id-when-available', context);
2876
+ const fieldName = (context.options[0] || {}).fieldName || DEFAULT_ID_FIELD_NAME;
2877
+ if (!node.selections || node.selections.length === 0) {
2896
2878
  return;
2897
2879
  }
2898
- const fields = rawType.getFields();
2899
- const hasIdFieldInType = idNames.some(name => fields[name]);
2900
- if (!hasIdFieldInType) {
2901
- return;
2902
- }
2903
- const checkedFragmentSpreads = new Set();
2904
- let found = false;
2905
- for (const selection of node.selections) {
2906
- if (isFound(selection)) {
2907
- found = true;
2908
- }
2909
- else if (selection.kind === Kind.INLINE_FRAGMENT) {
2910
- found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
2911
- }
2912
- else if (selection.kind === Kind.FRAGMENT_SPREAD) {
2913
- const [foundSpread] = siblings.getFragment(selection.name.value);
2914
- if (foundSpread) {
2915
- checkedFragmentSpreads.add(foundSpread.document.name.value);
2916
- found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
2880
+ const typeInfo = node.typeInfo();
2881
+ if (typeInfo && typeInfo.gqlType) {
2882
+ const rawType = getBaseType(typeInfo.gqlType);
2883
+ if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType) {
2884
+ const fields = rawType.getFields();
2885
+ const hasIdFieldInType = !!fields[fieldName];
2886
+ const checkedFragmentSpreads = new Set();
2887
+ if (hasIdFieldInType) {
2888
+ let found = false;
2889
+ for (const selection of node.selections) {
2890
+ if (selection.kind === 'Field' && selection.name.value === fieldName) {
2891
+ found = true;
2892
+ }
2893
+ else if (selection.kind === 'InlineFragment') {
2894
+ found = (((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2895
+ }
2896
+ else if (selection.kind === 'FragmentSpread') {
2897
+ const foundSpread = siblings.getFragment(selection.name.value);
2898
+ if (foundSpread[0]) {
2899
+ checkedFragmentSpreads.add(foundSpread[0].document.name.value);
2900
+ found = (((_b = foundSpread[0].document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2901
+ }
2902
+ }
2903
+ if (found) {
2904
+ break;
2905
+ }
2906
+ }
2907
+ const { parent } = node;
2908
+ const hasIdFieldInInterfaceSelectionSet = parent &&
2909
+ parent.kind === 'InlineFragment' &&
2910
+ parent.parent &&
2911
+ parent.parent.kind === 'SelectionSet' &&
2912
+ parent.parent.selections.some(s => s.kind === 'Field' && s.name.value === fieldName);
2913
+ if (!found && !hasIdFieldInInterfaceSelectionSet) {
2914
+ context.report({
2915
+ loc: {
2916
+ start: {
2917
+ line: node.loc.start.line,
2918
+ column: node.loc.start.column - 1,
2919
+ },
2920
+ end: {
2921
+ line: node.loc.end.line,
2922
+ column: node.loc.end.column - 1,
2923
+ },
2924
+ },
2925
+ messageId: REQUIRE_ID_WHEN_AVAILABLE,
2926
+ data: {
2927
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${Array.from(checkedFragmentSpreads).join(', ')})`,
2928
+ fieldName,
2929
+ },
2930
+ });
2931
+ }
2917
2932
  }
2918
2933
  }
2919
- if (found) {
2920
- break;
2921
- }
2922
- }
2923
- const { parent } = node;
2924
- const hasIdFieldInInterfaceSelectionSet = parent &&
2925
- parent.kind === Kind.INLINE_FRAGMENT &&
2926
- parent.parent &&
2927
- parent.parent.kind === Kind.SELECTION_SET &&
2928
- parent.parent.selections.some(s => isFound(s));
2929
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
2930
- context.report({
2931
- loc: getLocation(node.loc),
2932
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
2933
- data: {
2934
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
2935
- fieldName: idNames.map(name => `"${name}"`).join(' or '),
2936
- },
2937
- });
2938
2934
  }
2939
2935
  },
2940
2936
  };
@@ -3026,7 +3022,7 @@ const rule$k = {
3026
3022
  // eslint-disable-next-line no-console
3027
3023
  console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3028
3024
  }
3029
- const { maxDepth } = context.options[0];
3025
+ const maxDepth = context.options[0].maxDepth;
3030
3026
  const ignore = context.options[0].ignore || [];
3031
3027
  const checkFn = depthLimit(maxDepth, { ignore });
3032
3028
  return {
@@ -3223,7 +3219,7 @@ const rule$l = {
3223
3219
  },
3224
3220
  };
3225
3221
 
3226
- const RULE_NAME$3 = 'unique-fragment-name';
3222
+ const RULE_NAME$1 = 'unique-fragment-name';
3227
3223
  const UNIQUE_FRAGMENT_NAME = 'UNIQUE_FRAGMENT_NAME';
3228
3224
  const checkNode = (context, node, ruleName, messageId) => {
3229
3225
  const documentName = node.name.value;
@@ -3255,7 +3251,7 @@ const rule$m = {
3255
3251
  docs: {
3256
3252
  category: 'Operations',
3257
3253
  description: `Enforce unique fragment names across your project.`,
3258
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$3}.md`,
3254
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$1}.md`,
3259
3255
  requiresSiblings: true,
3260
3256
  examples: [
3261
3257
  {
@@ -3300,13 +3296,13 @@ const rule$m = {
3300
3296
  create(context) {
3301
3297
  return {
3302
3298
  FragmentDefinition(node) {
3303
- checkNode(context, node, RULE_NAME$3, UNIQUE_FRAGMENT_NAME);
3299
+ checkNode(context, node, RULE_NAME$1, UNIQUE_FRAGMENT_NAME);
3304
3300
  },
3305
3301
  };
3306
3302
  },
3307
3303
  };
3308
3304
 
3309
- const RULE_NAME$4 = 'unique-operation-name';
3305
+ const RULE_NAME$2 = 'unique-operation-name';
3310
3306
  const UNIQUE_OPERATION_NAME = 'UNIQUE_OPERATION_NAME';
3311
3307
  const rule$n = {
3312
3308
  meta: {
@@ -3314,7 +3310,7 @@ const rule$n = {
3314
3310
  docs: {
3315
3311
  category: 'Operations',
3316
3312
  description: `Enforce unique operation names across your project.`,
3317
- url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$4}.md`,
3313
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_NAME$2}.md`,
3318
3314
  requiresSiblings: true,
3319
3315
  examples: [
3320
3316
  {
@@ -3363,7 +3359,7 @@ const rule$n = {
3363
3359
  create(context) {
3364
3360
  return {
3365
3361
  'OperationDefinition[name!=undefined]'(node) {
3366
- checkNode(context, node, RULE_NAME$4, UNIQUE_OPERATION_NAME);
3362
+ checkNode(context, node, RULE_NAME$2, UNIQUE_OPERATION_NAME);
3367
3363
  },
3368
3364
  };
3369
3365
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.1.0-alpha-878c908.0",
3
+ "version": "3.1.0-alpha-27dcb49.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"