1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.OverlappingFieldsCanBeMergedRule = OverlappingFieldsCanBeMergedRule;
|
7 |
|
8 | var _find = _interopRequireDefault(require("../../polyfills/find.js"));
|
9 |
|
10 | var _objectEntries3 = _interopRequireDefault(require("../../polyfills/objectEntries.js"));
|
11 |
|
12 | var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
|
13 |
|
14 | var _GraphQLError = require("../../error/GraphQLError.js");
|
15 |
|
16 | var _kinds = require("../../language/kinds.js");
|
17 |
|
18 | var _printer = require("../../language/printer.js");
|
19 |
|
20 | var _definition = require("../../type/definition.js");
|
21 |
|
22 | var _typeFromAST = require("../../utilities/typeFromAST.js");
|
23 |
|
24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
25 |
|
26 | function reasonMessage(reason) {
|
27 | if (Array.isArray(reason)) {
|
28 | return reason.map(function (_ref) {
|
29 | var responseName = _ref[0],
|
30 | subReason = _ref[1];
|
31 | return "subfields \"".concat(responseName, "\" conflict because ") + reasonMessage(subReason);
|
32 | }).join(' and ');
|
33 | }
|
34 |
|
35 | return reason;
|
36 | }
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | function OverlappingFieldsCanBeMergedRule(context) {
|
47 |
|
48 |
|
49 |
|
50 | var comparedFragmentPairs = new PairSet();
|
51 |
|
52 |
|
53 |
|
54 | var cachedFieldsAndFragmentNames = new Map();
|
55 | return {
|
56 | SelectionSet: function SelectionSet(selectionSet) {
|
57 | var conflicts = findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, context.getParentType(), selectionSet);
|
58 |
|
59 | for (var _i2 = 0; _i2 < conflicts.length; _i2++) {
|
60 | var _ref3 = conflicts[_i2];
|
61 | var _ref2$ = _ref3[0];
|
62 | var responseName = _ref2$[0];
|
63 | var reason = _ref2$[1];
|
64 | var fields1 = _ref3[1];
|
65 | var fields2 = _ref3[2];
|
66 | var reasonMsg = reasonMessage(reason);
|
67 | context.reportError(new _GraphQLError.GraphQLError("Fields \"".concat(responseName, "\" conflict because ").concat(reasonMsg, ". Use different aliases on the fields to fetch both if this was intentional."), fields1.concat(fields2)));
|
68 | }
|
69 | }
|
70 | };
|
71 | }
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | function findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentType, selectionSet) {
|
131 | var conflicts = [];
|
132 |
|
133 | var _getFieldsAndFragment = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet),
|
134 | fieldMap = _getFieldsAndFragment[0],
|
135 | fragmentNames = _getFieldsAndFragment[1];
|
136 |
|
137 |
|
138 |
|
139 | collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap);
|
140 |
|
141 | if (fragmentNames.length !== 0) {
|
142 |
|
143 |
|
144 | for (var i = 0; i < fragmentNames.length; i++) {
|
145 | collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fieldMap, fragmentNames[i]);
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | for (var j = i + 1; j < fragmentNames.length; j++) {
|
151 | collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fragmentNames[i], fragmentNames[j]);
|
152 | }
|
153 | }
|
154 | }
|
155 |
|
156 | return conflicts;
|
157 | }
|
158 |
|
159 |
|
160 |
|
161 | function collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentName) {
|
162 | var fragment = context.getFragment(fragmentName);
|
163 |
|
164 | if (!fragment) {
|
165 | return;
|
166 | }
|
167 |
|
168 | var _getReferencedFieldsA = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment),
|
169 | fieldMap2 = _getReferencedFieldsA[0],
|
170 | fragmentNames2 = _getReferencedFieldsA[1];
|
171 |
|
172 |
|
173 | if (fieldMap === fieldMap2) {
|
174 | return;
|
175 | }
|
176 |
|
177 |
|
178 |
|
179 | collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fieldMap2);
|
180 |
|
181 |
|
182 | for (var i = 0; i < fragmentNames2.length; i++) {
|
183 | collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentNames2[i]);
|
184 | }
|
185 | }
|
186 |
|
187 |
|
188 |
|
189 | function collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentName2) {
|
190 |
|
191 | if (fragmentName1 === fragmentName2) {
|
192 | return;
|
193 | }
|
194 |
|
195 |
|
196 | if (comparedFragmentPairs.has(fragmentName1, fragmentName2, areMutuallyExclusive)) {
|
197 | return;
|
198 | }
|
199 |
|
200 | comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);
|
201 | var fragment1 = context.getFragment(fragmentName1);
|
202 | var fragment2 = context.getFragment(fragmentName2);
|
203 |
|
204 | if (!fragment1 || !fragment2) {
|
205 | return;
|
206 | }
|
207 |
|
208 | var _getReferencedFieldsA2 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment1),
|
209 | fieldMap1 = _getReferencedFieldsA2[0],
|
210 | fragmentNames1 = _getReferencedFieldsA2[1];
|
211 |
|
212 | var _getReferencedFieldsA3 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment2),
|
213 | fieldMap2 = _getReferencedFieldsA3[0],
|
214 | fragmentNames2 = _getReferencedFieldsA3[1];
|
215 |
|
216 |
|
217 |
|
218 | collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2);
|
219 |
|
220 |
|
221 | for (var j = 0; j < fragmentNames2.length; j++) {
|
222 | collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentNames2[j]);
|
223 | }
|
224 |
|
225 |
|
226 |
|
227 | for (var i = 0; i < fragmentNames1.length; i++) {
|
228 | collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[i], fragmentName2);
|
229 | }
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | function findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, parentType1, selectionSet1, parentType2, selectionSet2) {
|
236 | var conflicts = [];
|
237 |
|
238 | var _getFieldsAndFragment2 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType1, selectionSet1),
|
239 | fieldMap1 = _getFieldsAndFragment2[0],
|
240 | fragmentNames1 = _getFieldsAndFragment2[1];
|
241 |
|
242 | var _getFieldsAndFragment3 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType2, selectionSet2),
|
243 | fieldMap2 = _getFieldsAndFragment3[0],
|
244 | fragmentNames2 = _getFieldsAndFragment3[1];
|
245 |
|
246 |
|
247 | collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2);
|
248 |
|
249 |
|
250 | if (fragmentNames2.length !== 0) {
|
251 | for (var j = 0; j < fragmentNames2.length; j++) {
|
252 | collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fragmentNames2[j]);
|
253 | }
|
254 | }
|
255 |
|
256 |
|
257 |
|
258 | if (fragmentNames1.length !== 0) {
|
259 | for (var i = 0; i < fragmentNames1.length; i++) {
|
260 | collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap2, fragmentNames1[i]);
|
261 | }
|
262 | }
|
263 |
|
264 |
|
265 |
|
266 |
|
267 | for (var _i3 = 0; _i3 < fragmentNames1.length; _i3++) {
|
268 | for (var _j = 0; _j < fragmentNames2.length; _j++) {
|
269 | collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[_i3], fragmentNames2[_j]);
|
270 | }
|
271 | }
|
272 |
|
273 | return conflicts;
|
274 | }
|
275 |
|
276 |
|
277 | function collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap) {
|
278 |
|
279 |
|
280 |
|
281 |
|
282 | for (var _i5 = 0, _objectEntries2 = (0, _objectEntries3.default)(fieldMap); _i5 < _objectEntries2.length; _i5++) {
|
283 | var _ref5 = _objectEntries2[_i5];
|
284 | var responseName = _ref5[0];
|
285 | var fields = _ref5[1];
|
286 |
|
287 |
|
288 |
|
289 |
|
290 | if (fields.length > 1) {
|
291 | for (var i = 0; i < fields.length; i++) {
|
292 | for (var j = i + 1; j < fields.length; j++) {
|
293 | var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, false,
|
294 | responseName, fields[i], fields[j]);
|
295 |
|
296 | if (conflict) {
|
297 | conflicts.push(conflict);
|
298 | }
|
299 | }
|
300 | }
|
301 | }
|
302 | }
|
303 | }
|
304 |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 | function collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, fieldMap1, fieldMap2) {
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 | for (var _i7 = 0, _Object$keys2 = Object.keys(fieldMap1); _i7 < _Object$keys2.length; _i7++) {
|
317 | var responseName = _Object$keys2[_i7];
|
318 | var fields2 = fieldMap2[responseName];
|
319 |
|
320 | if (fields2) {
|
321 | var fields1 = fieldMap1[responseName];
|
322 |
|
323 | for (var i = 0; i < fields1.length; i++) {
|
324 | for (var j = 0; j < fields2.length; j++) {
|
325 | var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, fields1[i], fields2[j]);
|
326 |
|
327 | if (conflict) {
|
328 | conflicts.push(conflict);
|
329 | }
|
330 | }
|
331 | }
|
332 | }
|
333 | }
|
334 | }
|
335 |
|
336 |
|
337 |
|
338 | function findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, field1, field2) {
|
339 | var parentType1 = field1[0],
|
340 | node1 = field1[1],
|
341 | def1 = field1[2];
|
342 | var parentType2 = field2[0],
|
343 | node2 = field2[1],
|
344 | def2 = field2[2];
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 | var areMutuallyExclusive = parentFieldsAreMutuallyExclusive || parentType1 !== parentType2 && (0, _definition.isObjectType)(parentType1) && (0, _definition.isObjectType)(parentType2);
|
354 |
|
355 | if (!areMutuallyExclusive) {
|
356 | var _node1$arguments, _node2$arguments;
|
357 |
|
358 |
|
359 | var name1 = node1.name.value;
|
360 | var name2 = node2.name.value;
|
361 |
|
362 | if (name1 !== name2) {
|
363 | return [[responseName, "\"".concat(name1, "\" and \"").concat(name2, "\" are different fields")], [node1], [node2]];
|
364 | }
|
365 |
|
366 |
|
367 | var args1 = (_node1$arguments = node1.arguments) !== null && _node1$arguments !== void 0 ? _node1$arguments : [];
|
368 |
|
369 | var args2 = (_node2$arguments = node2.arguments) !== null && _node2$arguments !== void 0 ? _node2$arguments : [];
|
370 |
|
371 | if (!sameArguments(args1, args2)) {
|
372 | return [[responseName, 'they have differing arguments'], [node1], [node2]];
|
373 | }
|
374 | }
|
375 |
|
376 |
|
377 | var type1 = def1 === null || def1 === void 0 ? void 0 : def1.type;
|
378 | var type2 = def2 === null || def2 === void 0 ? void 0 : def2.type;
|
379 |
|
380 | if (type1 && type2 && doTypesConflict(type1, type2)) {
|
381 | return [[responseName, "they return conflicting types \"".concat((0, _inspect.default)(type1), "\" and \"").concat((0, _inspect.default)(type2), "\"")], [node1], [node2]];
|
382 | }
|
383 |
|
384 |
|
385 |
|
386 |
|
387 | var selectionSet1 = node1.selectionSet;
|
388 | var selectionSet2 = node2.selectionSet;
|
389 |
|
390 | if (selectionSet1 && selectionSet2) {
|
391 | var conflicts = findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, (0, _definition.getNamedType)(type1), selectionSet1, (0, _definition.getNamedType)(type2), selectionSet2);
|
392 | return subfieldConflicts(conflicts, responseName, node1, node2);
|
393 | }
|
394 | }
|
395 |
|
396 | function sameArguments(arguments1, arguments2) {
|
397 | if (arguments1.length !== arguments2.length) {
|
398 | return false;
|
399 | }
|
400 |
|
401 | return arguments1.every(function (argument1) {
|
402 | var argument2 = (0, _find.default)(arguments2, function (argument) {
|
403 | return argument.name.value === argument1.name.value;
|
404 | });
|
405 |
|
406 | if (!argument2) {
|
407 | return false;
|
408 | }
|
409 |
|
410 | return sameValue(argument1.value, argument2.value);
|
411 | });
|
412 | }
|
413 |
|
414 | function sameValue(value1, value2) {
|
415 | return (0, _printer.print)(value1) === (0, _printer.print)(value2);
|
416 | }
|
417 |
|
418 |
|
419 |
|
420 |
|
421 | function doTypesConflict(type1, type2) {
|
422 | if ((0, _definition.isListType)(type1)) {
|
423 | return (0, _definition.isListType)(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
|
424 | }
|
425 |
|
426 | if ((0, _definition.isListType)(type2)) {
|
427 | return true;
|
428 | }
|
429 |
|
430 | if ((0, _definition.isNonNullType)(type1)) {
|
431 | return (0, _definition.isNonNullType)(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
|
432 | }
|
433 |
|
434 | if ((0, _definition.isNonNullType)(type2)) {
|
435 | return true;
|
436 | }
|
437 |
|
438 | if ((0, _definition.isLeafType)(type1) || (0, _definition.isLeafType)(type2)) {
|
439 | return type1 !== type2;
|
440 | }
|
441 |
|
442 | return false;
|
443 | }
|
444 |
|
445 |
|
446 |
|
447 |
|
448 | function getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet) {
|
449 | var cached = cachedFieldsAndFragmentNames.get(selectionSet);
|
450 |
|
451 | if (!cached) {
|
452 | var nodeAndDefs = Object.create(null);
|
453 | var fragmentNames = Object.create(null);
|
454 |
|
455 | _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames);
|
456 |
|
457 | cached = [nodeAndDefs, Object.keys(fragmentNames)];
|
458 | cachedFieldsAndFragmentNames.set(selectionSet, cached);
|
459 | }
|
460 |
|
461 | return cached;
|
462 | }
|
463 |
|
464 |
|
465 |
|
466 | function getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment) {
|
467 |
|
468 | var cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);
|
469 |
|
470 | if (cached) {
|
471 | return cached;
|
472 | }
|
473 |
|
474 | var fragmentType = (0, _typeFromAST.typeFromAST)(context.getSchema(), fragment.typeCondition);
|
475 | return getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragmentType, fragment.selectionSet);
|
476 | }
|
477 |
|
478 | function _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames) {
|
479 | for (var _i9 = 0, _selectionSet$selecti2 = selectionSet.selections; _i9 < _selectionSet$selecti2.length; _i9++) {
|
480 | var selection = _selectionSet$selecti2[_i9];
|
481 |
|
482 | switch (selection.kind) {
|
483 | case _kinds.Kind.FIELD:
|
484 | {
|
485 | var fieldName = selection.name.value;
|
486 | var fieldDef = void 0;
|
487 |
|
488 | if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) {
|
489 | fieldDef = parentType.getFields()[fieldName];
|
490 | }
|
491 |
|
492 | var responseName = selection.alias ? selection.alias.value : fieldName;
|
493 |
|
494 | if (!nodeAndDefs[responseName]) {
|
495 | nodeAndDefs[responseName] = [];
|
496 | }
|
497 |
|
498 | nodeAndDefs[responseName].push([parentType, selection, fieldDef]);
|
499 | break;
|
500 | }
|
501 |
|
502 | case _kinds.Kind.FRAGMENT_SPREAD:
|
503 | fragmentNames[selection.name.value] = true;
|
504 | break;
|
505 |
|
506 | case _kinds.Kind.INLINE_FRAGMENT:
|
507 | {
|
508 | var typeCondition = selection.typeCondition;
|
509 | var inlineFragmentType = typeCondition ? (0, _typeFromAST.typeFromAST)(context.getSchema(), typeCondition) : parentType;
|
510 |
|
511 | _collectFieldsAndFragmentNames(context, inlineFragmentType, selection.selectionSet, nodeAndDefs, fragmentNames);
|
512 |
|
513 | break;
|
514 | }
|
515 | }
|
516 | }
|
517 | }
|
518 |
|
519 |
|
520 |
|
521 | function subfieldConflicts(conflicts, responseName, node1, node2) {
|
522 | if (conflicts.length > 0) {
|
523 | return [[responseName, conflicts.map(function (_ref6) {
|
524 | var reason = _ref6[0];
|
525 | return reason;
|
526 | })], conflicts.reduce(function (allFields, _ref7) {
|
527 | var fields1 = _ref7[1];
|
528 | return allFields.concat(fields1);
|
529 | }, [node1]), conflicts.reduce(function (allFields, _ref8) {
|
530 | var fields2 = _ref8[2];
|
531 | return allFields.concat(fields2);
|
532 | }, [node2])];
|
533 | }
|
534 | }
|
535 |
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 | var PairSet = function () {
|
542 | function PairSet() {
|
543 | this._data = Object.create(null);
|
544 | }
|
545 |
|
546 | var _proto = PairSet.prototype;
|
547 |
|
548 | _proto.has = function has(a, b, areMutuallyExclusive) {
|
549 | var first = this._data[a];
|
550 | var result = first && first[b];
|
551 |
|
552 | if (result === undefined) {
|
553 | return false;
|
554 | }
|
555 |
|
556 |
|
557 |
|
558 |
|
559 | if (areMutuallyExclusive === false) {
|
560 | return result === false;
|
561 | }
|
562 |
|
563 | return true;
|
564 | };
|
565 |
|
566 | _proto.add = function add(a, b, areMutuallyExclusive) {
|
567 | this._pairSetAdd(a, b, areMutuallyExclusive);
|
568 |
|
569 | this._pairSetAdd(b, a, areMutuallyExclusive);
|
570 | };
|
571 |
|
572 | _proto._pairSetAdd = function _pairSetAdd(a, b, areMutuallyExclusive) {
|
573 | var map = this._data[a];
|
574 |
|
575 | if (!map) {
|
576 | map = Object.create(null);
|
577 | this._data[a] = map;
|
578 | }
|
579 |
|
580 | map[b] = areMutuallyExclusive;
|
581 | };
|
582 |
|
583 | return PairSet;
|
584 | }();
|