@graphql-eslint/eslint-plugin 3.16.0 → 3.16.1-alpha-20230226184040-c96b828

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.
@@ -128,65 +128,83 @@ exports.rule = {
128
128
  // Can't access to node.parent in GraphQL AST.Node, so pass as argument
129
129
  parent, checkedFragmentSpreads = new Set()) {
130
130
  const rawType = (0, index_js_1.getBaseType)(type);
131
- const isObjectType = rawType instanceof graphql_1.GraphQLObjectType;
132
- const isInterfaceType = rawType instanceof graphql_1.GraphQLInterfaceType;
133
- if (!isObjectType && !isInterfaceType) {
134
- return;
131
+ if (rawType instanceof graphql_1.GraphQLObjectType || rawType instanceof graphql_1.GraphQLInterfaceType) {
132
+ checkFields(rawType);
135
133
  }
136
- const fields = rawType.getFields();
137
- const hasIdFieldInType = idNames.some(name => fields[name]);
138
- if (!hasIdFieldInType) {
139
- return;
140
- }
141
- function hasIdField({ selections }) {
142
- return selections.some(selection => {
143
- if (selection.kind === graphql_1.Kind.FIELD) {
144
- if (selection.alias && idNames.includes(selection.alias.value)) {
145
- return true;
146
- }
147
- return idNames.includes(selection.name.value);
148
- }
134
+ else if (rawType instanceof graphql_1.GraphQLUnionType) {
135
+ for (const selection of node.selections) {
149
136
  if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
150
- return hasIdField(selection.selectionSet);
151
- }
152
- if (selection.kind === graphql_1.Kind.FRAGMENT_SPREAD) {
153
- const [foundSpread] = siblings.getFragment(selection.name.value);
154
- if (foundSpread) {
155
- const fragmentSpread = foundSpread.document;
156
- checkedFragmentSpreads.add(fragmentSpread.name.value);
157
- return hasIdField(fragmentSpread.selectionSet);
137
+ const types = rawType.getTypes();
138
+ const t = types.find(t => t.name === selection.typeCondition.name.value);
139
+ if (t) {
140
+ checkFields(t);
158
141
  }
159
142
  }
160
- return false;
161
- });
162
- }
163
- const hasId = hasIdField(node);
164
- checkFragments(node);
165
- if (hasId) {
166
- return;
143
+ }
167
144
  }
168
- const pluralSuffix = idNames.length > 1 ? 's' : '';
169
- const fieldName = (0, utils_js_1.englishJoinWords)(idNames.map(name => `\`${(parent.alias || parent.name).value}.${name}\``));
170
- const addition = checkedFragmentSpreads.size === 0
171
- ? ''
172
- : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? 's' : ''} ${(0, utils_js_1.englishJoinWords)([...checkedFragmentSpreads].map(name => `\`${name}\``))}`;
173
- const problem = {
174
- loc,
175
- messageId: RULE_ID,
176
- data: {
177
- pluralSuffix,
178
- fieldName,
179
- addition,
180
- },
181
- };
182
- // Don't provide suggestions for selections in fragments as fragment can be in a separate file
183
- if ('type' in node) {
184
- problem.suggest = idNames.map(idName => ({
185
- desc: `Add \`${idName}\` selection`,
186
- fix: fixer => fixer.insertTextBefore(node.selections[0], `${idName} `),
187
- }));
145
+ function checkFields(rawType) {
146
+ const fields = rawType.getFields();
147
+ const hasIdFieldInType = idNames.some(name => fields[name]);
148
+ if (!hasIdFieldInType) {
149
+ return;
150
+ }
151
+ function hasIdField({ selections }) {
152
+ return selections.some(selection => {
153
+ if (selection.kind === graphql_1.Kind.FIELD) {
154
+ if (selection.alias && idNames.includes(selection.alias.value)) {
155
+ return true;
156
+ }
157
+ return idNames.includes(selection.name.value);
158
+ }
159
+ if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
160
+ return hasIdField(selection.selectionSet);
161
+ }
162
+ if (selection.kind === graphql_1.Kind.FRAGMENT_SPREAD) {
163
+ const [foundSpread] = siblings.getFragment(selection.name.value);
164
+ if (foundSpread) {
165
+ const fragmentSpread = foundSpread.document;
166
+ checkedFragmentSpreads.add(fragmentSpread.name.value);
167
+ return hasIdField(fragmentSpread.selectionSet);
168
+ }
169
+ }
170
+ return false;
171
+ });
172
+ }
173
+ const hasId = hasIdField(node);
174
+ checkFragments(node);
175
+ if (hasId) {
176
+ return;
177
+ }
178
+ const pluralSuffix = idNames.length > 1 ? 's' : '';
179
+ const fieldName = (0, utils_js_1.englishJoinWords)(idNames.map(name => `\`${(parent.alias || parent.name).value}.${name}\``));
180
+ const addition = checkedFragmentSpreads.size === 0
181
+ ? ''
182
+ : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? 's' : ''} ${(0, utils_js_1.englishJoinWords)([...checkedFragmentSpreads].map(name => `\`${name}\``))}`;
183
+ const problem = {
184
+ loc,
185
+ messageId: RULE_ID,
186
+ data: {
187
+ pluralSuffix,
188
+ fieldName,
189
+ addition,
190
+ },
191
+ };
192
+ // Don't provide suggestions for selections in fragments as fragment can be in a separate file
193
+ if ('type' in node) {
194
+ problem.suggest = idNames.map(idName => ({
195
+ desc: `Add \`${idName}\` selection`,
196
+ fix: fixer => {
197
+ let insertNode = node.selections[0];
198
+ insertNode =
199
+ insertNode.kind === graphql_1.Kind.INLINE_FRAGMENT
200
+ ? insertNode.selectionSet.selections[0]
201
+ : insertNode;
202
+ return fixer.insertTextBefore(insertNode, `${idName} `);
203
+ },
204
+ }));
205
+ }
206
+ context.report(problem);
188
207
  }
189
- context.report(problem);
190
208
  }
191
209
  return {
192
210
  [selector](node) {
@@ -1,5 +1,5 @@
1
1
  import { asArray } from '@graphql-tools/utils';
2
- import { GraphQLInterfaceType, GraphQLObjectType, Kind, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
2
+ import { GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, Kind, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
3
3
  import { getBaseType } from '../estree-converter/index.js';
4
4
  import { ARRAY_DEFAULT_OPTIONS, englishJoinWords, requireGraphQLSchemaFromContext, requireSiblingsOperations, } from '../utils.js';
5
5
  const RULE_ID = 'require-id-when-available';
@@ -125,65 +125,83 @@ export const rule = {
125
125
  // Can't access to node.parent in GraphQL AST.Node, so pass as argument
126
126
  parent, checkedFragmentSpreads = new Set()) {
127
127
  const rawType = getBaseType(type);
128
- const isObjectType = rawType instanceof GraphQLObjectType;
129
- const isInterfaceType = rawType instanceof GraphQLInterfaceType;
130
- if (!isObjectType && !isInterfaceType) {
131
- return;
128
+ if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType) {
129
+ checkFields(rawType);
132
130
  }
133
- const fields = rawType.getFields();
134
- const hasIdFieldInType = idNames.some(name => fields[name]);
135
- if (!hasIdFieldInType) {
136
- return;
137
- }
138
- function hasIdField({ selections }) {
139
- return selections.some(selection => {
140
- if (selection.kind === Kind.FIELD) {
141
- if (selection.alias && idNames.includes(selection.alias.value)) {
142
- return true;
143
- }
144
- return idNames.includes(selection.name.value);
145
- }
131
+ else if (rawType instanceof GraphQLUnionType) {
132
+ for (const selection of node.selections) {
146
133
  if (selection.kind === Kind.INLINE_FRAGMENT) {
147
- return hasIdField(selection.selectionSet);
148
- }
149
- if (selection.kind === Kind.FRAGMENT_SPREAD) {
150
- const [foundSpread] = siblings.getFragment(selection.name.value);
151
- if (foundSpread) {
152
- const fragmentSpread = foundSpread.document;
153
- checkedFragmentSpreads.add(fragmentSpread.name.value);
154
- return hasIdField(fragmentSpread.selectionSet);
134
+ const types = rawType.getTypes();
135
+ const t = types.find(t => t.name === selection.typeCondition.name.value);
136
+ if (t) {
137
+ checkFields(t);
155
138
  }
156
139
  }
157
- return false;
158
- });
159
- }
160
- const hasId = hasIdField(node);
161
- checkFragments(node);
162
- if (hasId) {
163
- return;
140
+ }
164
141
  }
165
- const pluralSuffix = idNames.length > 1 ? 's' : '';
166
- const fieldName = englishJoinWords(idNames.map(name => `\`${(parent.alias || parent.name).value}.${name}\``));
167
- const addition = checkedFragmentSpreads.size === 0
168
- ? ''
169
- : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? 's' : ''} ${englishJoinWords([...checkedFragmentSpreads].map(name => `\`${name}\``))}`;
170
- const problem = {
171
- loc,
172
- messageId: RULE_ID,
173
- data: {
174
- pluralSuffix,
175
- fieldName,
176
- addition,
177
- },
178
- };
179
- // Don't provide suggestions for selections in fragments as fragment can be in a separate file
180
- if ('type' in node) {
181
- problem.suggest = idNames.map(idName => ({
182
- desc: `Add \`${idName}\` selection`,
183
- fix: fixer => fixer.insertTextBefore(node.selections[0], `${idName} `),
184
- }));
142
+ function checkFields(rawType) {
143
+ const fields = rawType.getFields();
144
+ const hasIdFieldInType = idNames.some(name => fields[name]);
145
+ if (!hasIdFieldInType) {
146
+ return;
147
+ }
148
+ function hasIdField({ selections }) {
149
+ return selections.some(selection => {
150
+ if (selection.kind === Kind.FIELD) {
151
+ if (selection.alias && idNames.includes(selection.alias.value)) {
152
+ return true;
153
+ }
154
+ return idNames.includes(selection.name.value);
155
+ }
156
+ if (selection.kind === Kind.INLINE_FRAGMENT) {
157
+ return hasIdField(selection.selectionSet);
158
+ }
159
+ if (selection.kind === Kind.FRAGMENT_SPREAD) {
160
+ const [foundSpread] = siblings.getFragment(selection.name.value);
161
+ if (foundSpread) {
162
+ const fragmentSpread = foundSpread.document;
163
+ checkedFragmentSpreads.add(fragmentSpread.name.value);
164
+ return hasIdField(fragmentSpread.selectionSet);
165
+ }
166
+ }
167
+ return false;
168
+ });
169
+ }
170
+ const hasId = hasIdField(node);
171
+ checkFragments(node);
172
+ if (hasId) {
173
+ return;
174
+ }
175
+ const pluralSuffix = idNames.length > 1 ? 's' : '';
176
+ const fieldName = englishJoinWords(idNames.map(name => `\`${(parent.alias || parent.name).value}.${name}\``));
177
+ const addition = checkedFragmentSpreads.size === 0
178
+ ? ''
179
+ : ` or add to used fragment${checkedFragmentSpreads.size > 1 ? 's' : ''} ${englishJoinWords([...checkedFragmentSpreads].map(name => `\`${name}\``))}`;
180
+ const problem = {
181
+ loc,
182
+ messageId: RULE_ID,
183
+ data: {
184
+ pluralSuffix,
185
+ fieldName,
186
+ addition,
187
+ },
188
+ };
189
+ // Don't provide suggestions for selections in fragments as fragment can be in a separate file
190
+ if ('type' in node) {
191
+ problem.suggest = idNames.map(idName => ({
192
+ desc: `Add \`${idName}\` selection`,
193
+ fix: fixer => {
194
+ let insertNode = node.selections[0];
195
+ insertNode =
196
+ insertNode.kind === Kind.INLINE_FRAGMENT
197
+ ? insertNode.selectionSet.selections[0]
198
+ : insertNode;
199
+ return fixer.insertTextBefore(insertNode, `${idName} `);
200
+ },
201
+ }));
202
+ }
203
+ context.report(problem);
185
204
  }
186
- context.report(problem);
187
205
  }
188
206
  return {
189
207
  [selector](node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.16.0",
3
+ "version": "3.16.1-alpha-20230226184040-c96b828",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {