123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true,
- });
- exports.OverlappingFieldsCanBeMergedRule = OverlappingFieldsCanBeMergedRule;
- var _inspect = require('../../jsutils/inspect.js');
- var _GraphQLError = require('../../error/GraphQLError.js');
- var _kinds = require('../../language/kinds.js');
- var _printer = require('../../language/printer.js');
- var _definition = require('../../type/definition.js');
- var _sortValueNode = require('../../utilities/sortValueNode.js');
- var _typeFromAST = require('../../utilities/typeFromAST.js');
- function reasonMessage(reason) {
- if (Array.isArray(reason)) {
- return reason
- .map(
- ([responseName, subReason]) =>
- `subfields "${responseName}" conflict because ` +
- reasonMessage(subReason),
- )
- .join(' and ');
- }
- return reason;
- }
- function OverlappingFieldsCanBeMergedRule(context) {
-
-
-
- const comparedFragmentPairs = new PairSet();
-
-
- const cachedFieldsAndFragmentNames = new Map();
- return {
- SelectionSet(selectionSet) {
- const conflicts = findConflictsWithinSelectionSet(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- context.getParentType(),
- selectionSet,
- );
- for (const [[responseName, reason], fields1, fields2] of conflicts) {
- const reasonMsg = reasonMessage(reason);
- context.reportError(
- new _GraphQLError.GraphQLError(
- `Fields "${responseName}" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`,
- {
- nodes: fields1.concat(fields2),
- },
- ),
- );
- }
- },
- };
- }
- function findConflictsWithinSelectionSet(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- parentType,
- selectionSet,
- ) {
- const conflicts = [];
- const [fieldMap, fragmentNames] = getFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- parentType,
- selectionSet,
- );
-
- collectConflictsWithin(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- fieldMap,
- );
- if (fragmentNames.length !== 0) {
-
-
- for (let i = 0; i < fragmentNames.length; i++) {
- collectConflictsBetweenFieldsAndFragment(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- false,
- fieldMap,
- fragmentNames[i],
- );
-
-
-
- for (let j = i + 1; j < fragmentNames.length; j++) {
- collectConflictsBetweenFragments(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- false,
- fragmentNames[i],
- fragmentNames[j],
- );
- }
- }
- }
- return conflicts;
- }
- function collectConflictsBetweenFieldsAndFragment(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap,
- fragmentName,
- ) {
- const fragment = context.getFragment(fragmentName);
- if (!fragment) {
- return;
- }
- const [fieldMap2, referencedFragmentNames] =
- getReferencedFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- fragment,
- );
- if (fieldMap === fieldMap2) {
- return;
- }
-
- collectConflictsBetween(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap,
- fieldMap2,
- );
-
- for (const referencedFragmentName of referencedFragmentNames) {
-
- if (
- comparedFragmentPairs.has(
- referencedFragmentName,
- fragmentName,
- areMutuallyExclusive,
- )
- ) {
- continue;
- }
- comparedFragmentPairs.add(
- referencedFragmentName,
- fragmentName,
- areMutuallyExclusive,
- );
- collectConflictsBetweenFieldsAndFragment(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap,
- referencedFragmentName,
- );
- }
- }
- function collectConflictsBetweenFragments(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fragmentName1,
- fragmentName2,
- ) {
-
- if (fragmentName1 === fragmentName2) {
- return;
- }
- if (
- comparedFragmentPairs.has(
- fragmentName1,
- fragmentName2,
- areMutuallyExclusive,
- )
- ) {
- return;
- }
- comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);
- const fragment1 = context.getFragment(fragmentName1);
- const fragment2 = context.getFragment(fragmentName2);
- if (!fragment1 || !fragment2) {
- return;
- }
- const [fieldMap1, referencedFragmentNames1] =
- getReferencedFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- fragment1,
- );
- const [fieldMap2, referencedFragmentNames2] =
- getReferencedFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- fragment2,
- );
-
- collectConflictsBetween(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap1,
- fieldMap2,
- );
-
- for (const referencedFragmentName2 of referencedFragmentNames2) {
- collectConflictsBetweenFragments(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fragmentName1,
- referencedFragmentName2,
- );
- }
-
- for (const referencedFragmentName1 of referencedFragmentNames1) {
- collectConflictsBetweenFragments(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- referencedFragmentName1,
- fragmentName2,
- );
- }
- }
- function findConflictsBetweenSubSelectionSets(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- parentType1,
- selectionSet1,
- parentType2,
- selectionSet2,
- ) {
- const conflicts = [];
- const [fieldMap1, fragmentNames1] = getFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- parentType1,
- selectionSet1,
- );
- const [fieldMap2, fragmentNames2] = getFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- parentType2,
- selectionSet2,
- );
- collectConflictsBetween(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap1,
- fieldMap2,
- );
-
- for (const fragmentName2 of fragmentNames2) {
- collectConflictsBetweenFieldsAndFragment(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap1,
- fragmentName2,
- );
- }
-
- for (const fragmentName1 of fragmentNames1) {
- collectConflictsBetweenFieldsAndFragment(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fieldMap2,
- fragmentName1,
- );
- }
-
-
- for (const fragmentName1 of fragmentNames1) {
- for (const fragmentName2 of fragmentNames2) {
- collectConflictsBetweenFragments(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- fragmentName1,
- fragmentName2,
- );
- }
- }
- return conflicts;
- }
- function collectConflictsWithin(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- fieldMap,
- ) {
-
-
-
-
- for (const [responseName, fields] of Object.entries(fieldMap)) {
-
-
-
- if (fields.length > 1) {
- for (let i = 0; i < fields.length; i++) {
- for (let j = i + 1; j < fields.length; j++) {
- const conflict = findConflict(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- false,
- responseName,
- fields[i],
- fields[j],
- );
- if (conflict) {
- conflicts.push(conflict);
- }
- }
- }
- }
- }
- }
- function collectConflictsBetween(
- context,
- conflicts,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- parentFieldsAreMutuallyExclusive,
- fieldMap1,
- fieldMap2,
- ) {
-
-
-
-
-
- for (const [responseName, fields1] of Object.entries(fieldMap1)) {
- const fields2 = fieldMap2[responseName];
- if (fields2) {
- for (const field1 of fields1) {
- for (const field2 of fields2) {
- const conflict = findConflict(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- parentFieldsAreMutuallyExclusive,
- responseName,
- field1,
- field2,
- );
- if (conflict) {
- conflicts.push(conflict);
- }
- }
- }
- }
- }
- }
- function findConflict(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- parentFieldsAreMutuallyExclusive,
- responseName,
- field1,
- field2,
- ) {
- const [parentType1, node1, def1] = field1;
- const [parentType2, node2, def2] = field2;
-
-
-
-
-
-
-
- const areMutuallyExclusive =
- parentFieldsAreMutuallyExclusive ||
- (parentType1 !== parentType2 &&
- (0, _definition.isObjectType)(parentType1) &&
- (0, _definition.isObjectType)(parentType2));
- if (!areMutuallyExclusive) {
-
- const name1 = node1.name.value;
- const name2 = node2.name.value;
- if (name1 !== name2) {
- return [
- [responseName, `"${name1}" and "${name2}" are different fields`],
- [node1],
- [node2],
- ];
- }
- if (!sameArguments(node1, node2)) {
- return [
- [responseName, 'they have differing arguments'],
- [node1],
- [node2],
- ];
- }
- }
- const type1 = def1 === null || def1 === void 0 ? void 0 : def1.type;
- const type2 = def2 === null || def2 === void 0 ? void 0 : def2.type;
- if (type1 && type2 && doTypesConflict(type1, type2)) {
- return [
- [
- responseName,
- `they return conflicting types "${(0, _inspect.inspect)(
- type1,
- )}" and "${(0, _inspect.inspect)(type2)}"`,
- ],
- [node1],
- [node2],
- ];
- }
-
-
- const selectionSet1 = node1.selectionSet;
- const selectionSet2 = node2.selectionSet;
- if (selectionSet1 && selectionSet2) {
- const conflicts = findConflictsBetweenSubSelectionSets(
- context,
- cachedFieldsAndFragmentNames,
- comparedFragmentPairs,
- areMutuallyExclusive,
- (0, _definition.getNamedType)(type1),
- selectionSet1,
- (0, _definition.getNamedType)(type2),
- selectionSet2,
- );
- return subfieldConflicts(conflicts, responseName, node1, node2);
- }
- }
- function sameArguments(node1, node2) {
- const args1 = node1.arguments;
- const args2 = node2.arguments;
- if (args1 === undefined || args1.length === 0) {
- return args2 === undefined || args2.length === 0;
- }
- if (args2 === undefined || args2.length === 0) {
- return false;
- }
-
- if (args1.length !== args2.length) {
-
- return false;
-
- }
- const values2 = new Map(args2.map(({ name, value }) => [name.value, value]));
- return args1.every((arg1) => {
- const value1 = arg1.value;
- const value2 = values2.get(arg1.name.value);
- if (value2 === undefined) {
- return false;
- }
- return stringifyValue(value1) === stringifyValue(value2);
- });
- }
- function stringifyValue(value) {
- return (0, _printer.print)((0, _sortValueNode.sortValueNode)(value));
- }
- function doTypesConflict(type1, type2) {
- if ((0, _definition.isListType)(type1)) {
- return (0, _definition.isListType)(type2)
- ? doTypesConflict(type1.ofType, type2.ofType)
- : true;
- }
- if ((0, _definition.isListType)(type2)) {
- return true;
- }
- if ((0, _definition.isNonNullType)(type1)) {
- return (0, _definition.isNonNullType)(type2)
- ? doTypesConflict(type1.ofType, type2.ofType)
- : true;
- }
- if ((0, _definition.isNonNullType)(type2)) {
- return true;
- }
- if (
- (0, _definition.isLeafType)(type1) ||
- (0, _definition.isLeafType)(type2)
- ) {
- return type1 !== type2;
- }
- return false;
- }
- function getFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- parentType,
- selectionSet,
- ) {
- const cached = cachedFieldsAndFragmentNames.get(selectionSet);
- if (cached) {
- return cached;
- }
- const nodeAndDefs = Object.create(null);
- const fragmentNames = Object.create(null);
- _collectFieldsAndFragmentNames(
- context,
- parentType,
- selectionSet,
- nodeAndDefs,
- fragmentNames,
- );
- const result = [nodeAndDefs, Object.keys(fragmentNames)];
- cachedFieldsAndFragmentNames.set(selectionSet, result);
- return result;
- }
- function getReferencedFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- fragment,
- ) {
-
- const cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);
- if (cached) {
- return cached;
- }
- const fragmentType = (0, _typeFromAST.typeFromAST)(
- context.getSchema(),
- fragment.typeCondition,
- );
- return getFieldsAndFragmentNames(
- context,
- cachedFieldsAndFragmentNames,
- fragmentType,
- fragment.selectionSet,
- );
- }
- function _collectFieldsAndFragmentNames(
- context,
- parentType,
- selectionSet,
- nodeAndDefs,
- fragmentNames,
- ) {
- for (const selection of selectionSet.selections) {
- switch (selection.kind) {
- case _kinds.Kind.FIELD: {
- const fieldName = selection.name.value;
- let fieldDef;
- if (
- (0, _definition.isObjectType)(parentType) ||
- (0, _definition.isInterfaceType)(parentType)
- ) {
- fieldDef = parentType.getFields()[fieldName];
- }
- const responseName = selection.alias
- ? selection.alias.value
- : fieldName;
- if (!nodeAndDefs[responseName]) {
- nodeAndDefs[responseName] = [];
- }
- nodeAndDefs[responseName].push([parentType, selection, fieldDef]);
- break;
- }
- case _kinds.Kind.FRAGMENT_SPREAD:
- fragmentNames[selection.name.value] = true;
- break;
- case _kinds.Kind.INLINE_FRAGMENT: {
- const typeCondition = selection.typeCondition;
- const inlineFragmentType = typeCondition
- ? (0, _typeFromAST.typeFromAST)(context.getSchema(), typeCondition)
- : parentType;
- _collectFieldsAndFragmentNames(
- context,
- inlineFragmentType,
- selection.selectionSet,
- nodeAndDefs,
- fragmentNames,
- );
- break;
- }
- }
- }
- }
- function subfieldConflicts(conflicts, responseName, node1, node2) {
- if (conflicts.length > 0) {
- return [
- [responseName, conflicts.map(([reason]) => reason)],
- [node1, ...conflicts.map(([, fields1]) => fields1).flat()],
- [node2, ...conflicts.map(([, , fields2]) => fields2).flat()],
- ];
- }
- }
- class PairSet {
- constructor() {
- this._data = new Map();
- }
- has(a, b, areMutuallyExclusive) {
- var _this$_data$get;
- const [key1, key2] = a < b ? [a, b] : [b, a];
- const result =
- (_this$_data$get = this._data.get(key1)) === null ||
- _this$_data$get === void 0
- ? void 0
- : _this$_data$get.get(key2);
- if (result === undefined) {
- return false;
- }
-
-
- return areMutuallyExclusive ? true : areMutuallyExclusive === result;
- }
- add(a, b, areMutuallyExclusive) {
- const [key1, key2] = a < b ? [a, b] : [b, a];
- const map = this._data.get(key1);
- if (map === undefined) {
- this._data.set(key1, new Map([[key2, areMutuallyExclusive]]));
- } else {
- map.set(key2, areMutuallyExclusive);
- }
- }
- }
|