@graphql-eslint/eslint-plugin 3.16.0 → 3.16.1-alpha-20230226183026-b86ac84

Sign up to get free protection for your applications and to get access to all the features.
@@ -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-20230226183026-b86ac84",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {