@apollo/federation-internals 2.4.8 → 2.4.9

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.
@@ -25,6 +25,9 @@ class AbstractOperationElement extends definitions_1.DirectiveTargetElement {
25
25
  this.collectVariablesInElement(collector);
26
26
  this.collectVariablesInAppliedDirectives(collector);
27
27
  }
28
+ rebaseOnOrError(parentType) {
29
+ return this.rebaseOn({ parentType, errorIfCannotRebase: true });
30
+ }
28
31
  addAttachement(key, value) {
29
32
  if (!this.attachements) {
30
33
  this.attachements = new Map();
@@ -162,7 +165,7 @@ class Field extends AbstractOperationElement {
162
165
  }
163
166
  }
164
167
  }
165
- rebaseOn(parentType) {
168
+ rebaseOn({ parentType, errorIfCannotRebase }) {
166
169
  const fieldParent = this.definition.parent;
167
170
  if (parentType === fieldParent) {
168
171
  return this;
@@ -170,9 +173,12 @@ class Field extends AbstractOperationElement {
170
173
  if (this.name === definitions_1.typenameFieldName) {
171
174
  return this.withUpdatedDefinition(parentType.typenameField());
172
175
  }
173
- validate(this.canRebaseOn(parentType), () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${parentType}"`);
174
176
  const fieldDef = parentType.field(this.name);
175
- validate(fieldDef, () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${parentType}" (that does not declare that field)`);
177
+ const canRebase = this.canRebaseOn(parentType) && fieldDef;
178
+ if (!canRebase) {
179
+ validate(!errorIfCannotRebase, () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${parentType}"`);
180
+ return undefined;
181
+ }
176
182
  return this.withUpdatedDefinition(fieldDef);
177
183
  }
178
184
  canRebaseOn(parentType) {
@@ -276,14 +282,17 @@ class FragmentElement extends AbstractOperationElement {
276
282
  this.copyAttachementsTo(newFragment);
277
283
  return newFragment;
278
284
  }
279
- rebaseOn(parentType) {
285
+ rebaseOn({ parentType, errorIfCannotRebase }) {
280
286
  const fragmentParent = this.parentType;
281
287
  const typeCondition = this.typeCondition;
282
288
  if (parentType === fragmentParent) {
283
289
  return this;
284
290
  }
285
291
  const { canRebase, rebasedCondition } = this.canRebaseOn(parentType);
286
- validate(canRebase, () => `Cannot add fragment of condition "${typeCondition}" (runtimes: [${(0, definitions_1.possibleRuntimeTypes)(typeCondition)}]) to parent type "${parentType}" (runtimes: ${(0, definitions_1.possibleRuntimeTypes)(parentType)})`);
292
+ if (!canRebase) {
293
+ validate(!errorIfCannotRebase, () => `Cannot add fragment of condition "${typeCondition}" (runtimes: [${(0, definitions_1.possibleRuntimeTypes)(typeCondition)}]) to parent type "${parentType}" (runtimes: ${(0, definitions_1.possibleRuntimeTypes)(parentType)})`);
294
+ return undefined;
295
+ }
287
296
  return this.withUpdatedTypes(parentType, rebasedCondition);
288
297
  }
289
298
  canRebaseOn(parentType) {
@@ -553,9 +562,14 @@ class Operation {
553
562
  optimizedSelection = optimizedSelection.expandFragments(finalFragments);
554
563
  optimizedSelection = optimizedSelection.normalize({ parentType: optimizedSelection.parentType });
555
564
  if (finalFragments) {
556
- const usages = new Map();
557
- optimizedSelection.collectUsedFragmentNames(usages);
558
- finalFragments = finalFragments.filter((f) => { var _a; return ((_a = usages.get(f.name)) !== null && _a !== void 0 ? _a : 0) > 0; });
565
+ let beforeRemoval;
566
+ do {
567
+ beforeRemoval = finalFragments;
568
+ const usages = new Map();
569
+ optimizedSelection.collectUsedFragmentNames(usages);
570
+ finalFragments.collectUsedFragmentNames(usages);
571
+ finalFragments = finalFragments.filter((f) => { var _a; return ((_a = usages.get(f.name)) !== null && _a !== void 0 ? _a : 0) > 0; });
572
+ } while (finalFragments && finalFragments.size < beforeRemoval.size);
559
573
  }
560
574
  }
561
575
  return this.withUpdatedSelectionSetAndFragments(optimizedSelection, finalFragments !== null && finalFragments !== void 0 ? finalFragments : undefined);
@@ -707,7 +721,7 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
707
721
  return included;
708
722
  }
709
723
  toString(indent) {
710
- return (indent !== null && indent !== void 0 ? indent : '') + `fragment ${this.name} on ${this.typeCondition}${this.appliedDirectivesToString()} ${this.selectionSet.toString(false, true, indent)}`;
724
+ return `fragment ${this.name} on ${this.typeCondition}${this.appliedDirectivesToString()} ${this.selectionSet.toString(false, true, indent)}`;
711
725
  }
712
726
  }
713
727
  exports.NamedFragmentDefinition = NamedFragmentDefinition;
@@ -747,6 +761,11 @@ class NamedFragments {
747
761
  definitions() {
748
762
  return this.fragments.values();
749
763
  }
764
+ collectUsedFragmentNames(collector) {
765
+ for (const fragment of this.definitions()) {
766
+ fragment.collectUsedFragmentNames(collector);
767
+ }
768
+ }
750
769
  map(mapper) {
751
770
  const mapped = new NamedFragments();
752
771
  for (const def of this.fragments.values()) {
@@ -791,19 +810,28 @@ class NamedFragments {
791
810
  return fragment.withUpdatedSelectionSet(reoptimizedSelectionSet);
792
811
  });
793
812
  }
813
+ selectionSetIsWorthUsing(selectionSet) {
814
+ const selections = selectionSet.selections();
815
+ if (selections.length === 0) {
816
+ return false;
817
+ }
818
+ if (selections.length === 1) {
819
+ const s = selections[0];
820
+ return !(s.kind === 'FieldSelection' && s.element.isLeafField());
821
+ }
822
+ return true;
823
+ }
794
824
  rebaseOn(schema) {
795
825
  return this.mapInDependencyOrder((fragment, newFragments) => {
796
826
  const rebasedType = schema.type(fragment.selectionSet.parentType.name);
797
- try {
798
- if (!rebasedType || !(0, definitions_1.isCompositeType)(rebasedType)) {
799
- return undefined;
800
- }
801
- const rebasedSelection = fragment.selectionSet.rebaseOn(rebasedType, newFragments);
802
- return new NamedFragmentDefinition(schema, fragment.name, rebasedType).setSelectionSet(rebasedSelection);
803
- }
804
- catch (e) {
827
+ if (!rebasedType || !(0, definitions_1.isCompositeType)(rebasedType)) {
805
828
  return undefined;
806
829
  }
830
+ const rebasedSelection = fragment.selectionSet.rebaseOn({ parentType: rebasedType, fragments: newFragments, errorIfCannotRebase: false });
831
+ return this.selectionSetIsWorthUsing(rebasedSelection)
832
+ ? new NamedFragmentDefinition(schema, fragment.name, rebasedType).setSelectionSet(rebasedSelection)
833
+ : undefined;
834
+ ;
807
835
  });
808
836
  }
809
837
  filter(predicate) {
@@ -904,6 +932,18 @@ class SelectionSet {
904
932
  hasTopLevelTypenameField() {
905
933
  return this._keyedSelections.has(definitions_1.typenameFieldName);
906
934
  }
935
+ withoutTopLevelTypenameField() {
936
+ if (!this.hasTopLevelTypenameField) {
937
+ return this;
938
+ }
939
+ const newKeyedSelections = new Map();
940
+ for (const [key, selection] of this._keyedSelections) {
941
+ if (key !== definitions_1.typenameFieldName) {
942
+ newKeyedSelections.set(key, selection);
943
+ }
944
+ }
945
+ return new SelectionSet(this.parentType, newKeyedSelections);
946
+ }
907
947
  fieldsInSet() {
908
948
  const fields = new Array();
909
949
  for (const selection of this.selections()) {
@@ -955,7 +995,7 @@ class SelectionSet {
955
995
  return this;
956
996
  }
957
997
  const wrapped = new InlineFragmentSelection(new FragmentElement(this.parentType, this.parentType), this);
958
- const validator = FieldsConflictValidator.build(this);
998
+ const validator = FieldsConflictMultiBranchValidator.ofInitial(FieldsConflictValidator.build(this));
959
999
  const optimized = wrapped.optimize(fragments, validator);
960
1000
  return optimized instanceof FragmentSpreadSelection
961
1001
  ? selectionSetOf(this.parentType, optimized)
@@ -1011,13 +1051,16 @@ class SelectionSet {
1011
1051
  const updated = this.filterRecursiveDepthFirst((selection) => { var _a; return ((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.isEmpty()) !== true; });
1012
1052
  return updated.isEmpty() ? undefined : updated;
1013
1053
  }
1014
- rebaseOn(parentType, fragments) {
1054
+ rebaseOn({ parentType, fragments, errorIfCannotRebase, }) {
1015
1055
  if (this.parentType === parentType) {
1016
1056
  return this;
1017
1057
  }
1018
1058
  const newSelections = new Map();
1019
1059
  for (const selection of this.selections()) {
1020
- newSelections.set(selection.key(), selection.rebaseOn(parentType, fragments));
1060
+ const rebasedSelection = selection.rebaseOn({ parentType, fragments, errorIfCannotRebase });
1061
+ if (rebasedSelection) {
1062
+ newSelections.set(selection.key(), rebasedSelection);
1063
+ }
1021
1064
  }
1022
1065
  return new SelectionSet(parentType, newSelections);
1023
1066
  }
@@ -1036,14 +1079,21 @@ class SelectionSet {
1036
1079
  }
1037
1080
  return true;
1038
1081
  }
1039
- contains(that) {
1082
+ contains(that, options) {
1083
+ var _a;
1084
+ const ignoreMissingTypename = (_a = options === null || options === void 0 ? void 0 : options.ignoreMissingTypename) !== null && _a !== void 0 ? _a : false;
1040
1085
  if (that._selections.length > this._selections.length) {
1041
- return ContainsResult.NOT_CONTAINED;
1086
+ if (!ignoreMissingTypename || that._selections.length > this._selections.length + 1 || this.hasTopLevelTypenameField() || !that.hasTopLevelTypenameField()) {
1087
+ return ContainsResult.NOT_CONTAINED;
1088
+ }
1042
1089
  }
1043
1090
  let isEqual = true;
1044
1091
  for (const [key, thatSelection] of that._keyedSelections) {
1092
+ if (key === definitions_1.typenameFieldName && ignoreMissingTypename) {
1093
+ continue;
1094
+ }
1045
1095
  const thisSelection = this._keyedSelections.get(key);
1046
- const selectionResult = thisSelection === null || thisSelection === void 0 ? void 0 : thisSelection.contains(thatSelection);
1096
+ const selectionResult = thisSelection === null || thisSelection === void 0 ? void 0 : thisSelection.contains(thatSelection, options);
1047
1097
  if (selectionResult === undefined || selectionResult === ContainsResult.NOT_CONTAINED) {
1048
1098
  return ContainsResult.NOT_CONTAINED;
1049
1099
  }
@@ -1053,6 +1103,10 @@ class SelectionSet {
1053
1103
  ? ContainsResult.EQUAL
1054
1104
  : ContainsResult.STRICTLY_CONTAINED;
1055
1105
  }
1106
+ containsTopLevelField(field) {
1107
+ const selection = this._keyedSelections.get(field.key());
1108
+ return !!selection && selection.element.equals(field);
1109
+ }
1056
1110
  minus(that) {
1057
1111
  const updated = new SelectionSetUpdates();
1058
1112
  for (const [key, thisSelection] of this._keyedSelections) {
@@ -1304,9 +1358,9 @@ function makeSelection(parentType, updates, fragments) {
1304
1358
  (0, utils_1.assert)(updates.length > 0, 'Should not be called without any updates');
1305
1359
  const first = updates[0];
1306
1360
  if (updates.length === 1 && first instanceof AbstractSelection) {
1307
- return first.rebaseOn(parentType, fragments);
1361
+ return first.rebaseOnOrError({ parentType, fragments });
1308
1362
  }
1309
- const element = updateElement(first).rebaseOn(parentType);
1363
+ const element = updateElement(first).rebaseOnOrError(parentType);
1310
1364
  const subSelectionParentType = element.kind === 'Field' ? element.baseType() : element.castedType();
1311
1365
  if (!(0, definitions_1.isCompositeType)(subSelectionParentType)) {
1312
1366
  return selectionOfElement(element);
@@ -1437,6 +1491,9 @@ class AbstractSelection {
1437
1491
  constructor(element) {
1438
1492
  this.element = element;
1439
1493
  }
1494
+ rebaseOnOrError({ parentType, fragments }) {
1495
+ return this.rebaseOn({ parentType, fragments, errorIfCannotRebase: true });
1496
+ }
1440
1497
  get parentType() {
1441
1498
  return this.element.parentType;
1442
1499
  }
@@ -1500,12 +1557,11 @@ class AbstractSelection {
1500
1557
  }
1501
1558
  const applyingFragments = [];
1502
1559
  for (const candidate of candidates) {
1503
- const atType = candidate.expandedSelectionSetAtType(parentType);
1504
- const selectionSetAtType = atType.selectionSet;
1505
- if (selectionSetAtType.isEmpty() || (selectionSetAtType.selections().length === 1 && selectionSetAtType.selections()[0].isTypenameField())) {
1560
+ let atType = candidate.expandedSelectionSetAtType(parentType);
1561
+ if (atType.selectionSet.isEmpty() || (atType.selectionSet.selections().length === 1 && atType.selectionSet.selections()[0].isTypenameField())) {
1506
1562
  continue;
1507
1563
  }
1508
- const res = subSelection.contains(selectionSetAtType);
1564
+ const res = subSelection.contains(atType.selectionSet, { ignoreMissingTypename: true });
1509
1565
  if (res === ContainsResult.EQUAL) {
1510
1566
  if (canUseFullMatchingFragment(candidate)) {
1511
1567
  if (!validator.checkCanReuseFragmentAndTrackIt(atType)) {
@@ -1538,6 +1594,38 @@ class AbstractSelection {
1538
1594
  return optimized.add(notCoveredByFragments).toSelectionSet(parentType, fragments);
1539
1595
  }
1540
1596
  }
1597
+ class FieldsConflictMultiBranchValidator {
1598
+ constructor(validators) {
1599
+ this.validators = validators;
1600
+ }
1601
+ static ofInitial(validator) {
1602
+ return new FieldsConflictMultiBranchValidator([validator]);
1603
+ }
1604
+ forField(field) {
1605
+ const forAllBranches = this.validators.flatMap((vs) => vs.forField(field));
1606
+ (0, utils_1.assert)(forAllBranches.length > 0, `Shoud have found at least one validator for ${field}`);
1607
+ return new FieldsConflictMultiBranchValidator(forAllBranches);
1608
+ }
1609
+ checkCanReuseFragmentAndTrackIt(fragment) {
1610
+ const validator = fragment.validator;
1611
+ if (!validator) {
1612
+ return true;
1613
+ }
1614
+ if (!this.validators.every((v) => v.doMergeWith(validator))) {
1615
+ return false;
1616
+ }
1617
+ if (this.usedSpreadTrimmedPartAtLevel) {
1618
+ if (!this.usedSpreadTrimmedPartAtLevel.every((t) => validator.doMergeWith(t))) {
1619
+ return false;
1620
+ }
1621
+ }
1622
+ else {
1623
+ this.usedSpreadTrimmedPartAtLevel = [];
1624
+ }
1625
+ this.usedSpreadTrimmedPartAtLevel.push(validator);
1626
+ return true;
1627
+ }
1628
+ }
1541
1629
  class FieldsConflictValidator {
1542
1630
  constructor(byResponseName) {
1543
1631
  this.byResponseName = byResponseName;
@@ -1575,29 +1663,11 @@ class FieldsConflictValidator {
1575
1663
  return new FieldsConflictValidator(byResponseName);
1576
1664
  }
1577
1665
  forField(field) {
1578
- var _a;
1579
- const validator = (_a = this.byResponseName.get(field.responseName())) === null || _a === void 0 ? void 0 : _a.get(field);
1580
- (0, utils_1.assert)(validator, () => `Should have found validator for ${field}`);
1581
- return validator;
1582
- }
1583
- checkCanReuseFragmentAndTrackIt(fragment) {
1584
- const validator = fragment.validator;
1585
- if (!validator) {
1586
- return true;
1587
- }
1588
- if (!this.doMergeWith(validator)) {
1589
- return false;
1590
- }
1591
- if (this.usedSpreadTrimmedPartAtLevel) {
1592
- if (!this.usedSpreadTrimmedPartAtLevel.every((t) => validator.doMergeWith(t))) {
1593
- return false;
1594
- }
1666
+ const byResponseName = this.byResponseName.get(field.responseName());
1667
+ if (!byResponseName) {
1668
+ return [];
1595
1669
  }
1596
- else {
1597
- this.usedSpreadTrimmedPartAtLevel = [];
1598
- }
1599
- this.usedSpreadTrimmedPartAtLevel.push(validator);
1600
- return true;
1670
+ return (0, utils_1.mapValues)(byResponseName).filter((v) => !!v);
1601
1671
  }
1602
1672
  doMergeWith(that) {
1603
1673
  var _a, _b;
@@ -1690,21 +1760,19 @@ class FieldSelection extends AbstractSelection {
1690
1760
  return this;
1691
1761
  }
1692
1762
  const fieldValidator = validator.forField(this.element);
1693
- let optimizedSelection = this.selectionSet;
1694
- if ((0, definitions_1.isCompositeType)(fieldBaseType) && this.selectionSet) {
1695
- const optimized = this.tryOptimizeSubselectionWithFragments({
1696
- parentType: fieldBaseType,
1697
- subSelection: this.selectionSet,
1698
- fragments,
1699
- validator: fieldValidator,
1700
- canUseFullMatchingFragment: (fragment) => fragment.appliedDirectives.length === 0,
1701
- });
1702
- if (optimized instanceof NamedFragmentDefinition) {
1703
- optimizedSelection = selectionSetOf(fieldBaseType, new FragmentSpreadSelection(fieldBaseType, fragments, optimized, []));
1704
- }
1705
- else {
1706
- optimizedSelection = optimized;
1707
- }
1763
+ const optimized = this.tryOptimizeSubselectionWithFragments({
1764
+ parentType: fieldBaseType,
1765
+ subSelection: this.selectionSet,
1766
+ fragments,
1767
+ validator: fieldValidator,
1768
+ canUseFullMatchingFragment: (fragment) => fragment.appliedDirectives.length === 0,
1769
+ });
1770
+ let optimizedSelection;
1771
+ if (optimized instanceof NamedFragmentDefinition) {
1772
+ optimizedSelection = selectionSetOf(fieldBaseType, new FragmentSpreadSelection(fieldBaseType, fragments, optimized, []));
1773
+ }
1774
+ else {
1775
+ optimizedSelection = optimized;
1708
1776
  }
1709
1777
  optimizedSelection = optimizedSelection.optimizeSelections(fragments, fieldValidator);
1710
1778
  return this.selectionSet === optimizedSelection
@@ -1727,11 +1795,14 @@ class FieldSelection extends AbstractSelection {
1727
1795
  validate(this.element.isLeafField() || (this.selectionSet && !this.selectionSet.isEmpty()), () => `Invalid empty selection set for field "${this.element.definition.coordinate}" of non-leaf type ${this.element.definition.type}`, this.element.definition.sourceAST);
1728
1796
  (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.validate(variableDefinitions);
1729
1797
  }
1730
- rebaseOn(parentType, fragments) {
1798
+ rebaseOn({ parentType, fragments, errorIfCannotRebase, }) {
1731
1799
  if (this.element.parentType === parentType) {
1732
1800
  return this;
1733
1801
  }
1734
- const rebasedElement = this.element.rebaseOn(parentType);
1802
+ const rebasedElement = this.element.rebaseOn({ parentType, errorIfCannotRebase });
1803
+ if (!rebasedElement) {
1804
+ return undefined;
1805
+ }
1735
1806
  if (!this.selectionSet) {
1736
1807
  return this.withUpdatedElement(rebasedElement);
1737
1808
  }
@@ -1740,7 +1811,8 @@ class FieldSelection extends AbstractSelection {
1740
1811
  return this.withUpdatedElement(rebasedElement);
1741
1812
  }
1742
1813
  validate((0, definitions_1.isCompositeType)(rebasedBase), () => `Cannot rebase field selection ${this} on ${parentType}: rebased field base return type ${rebasedBase} is not composite`);
1743
- return this.withUpdatedComponents(rebasedElement, this.selectionSet.rebaseOn(rebasedBase, fragments));
1814
+ const rebasedSelectionSet = this.selectionSet.rebaseOn({ parentType: rebasedBase, fragments, errorIfCannotRebase });
1815
+ return rebasedSelectionSet.isEmpty() ? undefined : this.withUpdatedComponents(rebasedElement, rebasedSelectionSet);
1744
1816
  }
1745
1817
  canAddTo(parentType) {
1746
1818
  if (this.element.parentType === parentType) {
@@ -1816,7 +1888,7 @@ class FieldSelection extends AbstractSelection {
1816
1888
  }
1817
1889
  return !!that.selectionSet && this.selectionSet.equals(that.selectionSet);
1818
1890
  }
1819
- contains(that) {
1891
+ contains(that, options) {
1820
1892
  if (!(that instanceof FieldSelection) || !this.element.equals(that.element)) {
1821
1893
  return ContainsResult.NOT_CONTAINED;
1822
1894
  }
@@ -1825,7 +1897,7 @@ class FieldSelection extends AbstractSelection {
1825
1897
  return ContainsResult.EQUAL;
1826
1898
  }
1827
1899
  (0, utils_1.assert)(that.selectionSet, '`this` and `that` have the same element, so if one has sub-selection, the other one should too');
1828
- return this.selectionSet.contains(that.selectionSet);
1900
+ return this.selectionSet.contains(that.selectionSet, options);
1829
1901
  }
1830
1902
  toString(expandFragments = true, indent) {
1831
1903
  return (indent !== null && indent !== void 0 ? indent : '') + this.element + (this.selectionSet ? ' ' + this.selectionSet.toString(expandFragments, true, indent) : '');
@@ -1857,6 +1929,17 @@ class FragmentSelection extends AbstractSelection {
1857
1929
  hasDefer() {
1858
1930
  return this.element.hasDefer() || this.selectionSet.hasDefer();
1859
1931
  }
1932
+ normalize({ parentType, recursive }) {
1933
+ const thisCondition = this.element.typeCondition;
1934
+ if (thisCondition && parentType !== this.parentType) {
1935
+ const conditionRuntimes = (0, definitions_1.possibleRuntimeTypes)(thisCondition);
1936
+ const typeRuntimes = (0, definitions_1.possibleRuntimeTypes)(parentType);
1937
+ if (!conditionRuntimes.some((t) => typeRuntimes.includes(t))) {
1938
+ return undefined;
1939
+ }
1940
+ }
1941
+ return this.normalizeKnowingItIntersects({ parentType, recursive });
1942
+ }
1860
1943
  }
1861
1944
  exports.FragmentSelection = FragmentSelection;
1862
1945
  class InlineFragmentSelection extends FragmentSelection {
@@ -1881,16 +1964,20 @@ class InlineFragmentSelection extends FragmentSelection {
1881
1964
  validate(!this.selectionSet.isEmpty(), () => `Invalid empty selection set for fragment "${this.element}"`);
1882
1965
  this.selectionSet.validate(variableDefinitions);
1883
1966
  }
1884
- rebaseOn(parentType, fragments) {
1967
+ rebaseOn({ parentType, fragments, errorIfCannotRebase, }) {
1885
1968
  if (this.parentType === parentType) {
1886
1969
  return this;
1887
1970
  }
1888
- const rebasedFragment = this.element.rebaseOn(parentType);
1971
+ const rebasedFragment = this.element.rebaseOn({ parentType, errorIfCannotRebase });
1972
+ if (!rebasedFragment) {
1973
+ return undefined;
1974
+ }
1889
1975
  const rebasedCastedType = rebasedFragment.castedType();
1890
1976
  if (rebasedCastedType === this.selectionSet.parentType) {
1891
1977
  return this.withUpdatedElement(rebasedFragment);
1892
1978
  }
1893
- return this.withUpdatedComponents(rebasedFragment, this.selectionSet.rebaseOn(rebasedCastedType, fragments));
1979
+ const rebasedSelectionSet = this.selectionSet.rebaseOn({ parentType: rebasedCastedType, fragments, errorIfCannotRebase });
1980
+ return rebasedSelectionSet.isEmpty() ? undefined : this.withUpdatedComponents(rebasedFragment, rebasedSelectionSet);
1894
1981
  }
1895
1982
  canAddTo(parentType) {
1896
1983
  if (this.element.parentType === parentType) {
@@ -1981,16 +2068,9 @@ class InlineFragmentSelection extends FragmentSelection {
1981
2068
  ? this
1982
2069
  : this.withUpdatedComponents(newElement, newSelection);
1983
2070
  }
1984
- normalize({ parentType, recursive }) {
2071
+ normalizeKnowingItIntersects({ parentType, recursive }) {
1985
2072
  var _a;
1986
2073
  const thisCondition = this.element.typeCondition;
1987
- if (thisCondition && parentType !== this.parentType) {
1988
- const conditionRuntimes = (0, definitions_1.possibleRuntimeTypes)(thisCondition);
1989
- const typeRuntimes = (0, definitions_1.possibleRuntimeTypes)(parentType);
1990
- if (!conditionRuntimes.some((t) => typeRuntimes.includes(t))) {
1991
- return undefined;
1992
- }
1993
- }
1994
2074
  if (this.element.appliedDirectives.length === 0) {
1995
2075
  if (!thisCondition || parentType === this.element.typeCondition || (0, definitions_1.isObjectType)(parentType)) {
1996
2076
  const normalized = this.selectionSet.normalize({ parentType, recursive });
@@ -2005,7 +2085,7 @@ class InlineFragmentSelection extends FragmentSelection {
2005
2085
  return undefined;
2006
2086
  }
2007
2087
  else {
2008
- return this.withUpdatedComponents(this.element.rebaseOn(parentType), selectionSetOfElement(new Field(((_a = this.element.typeCondition) !== null && _a !== void 0 ? _a : parentType).typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
2088
+ return this.withUpdatedComponents(this.element.rebaseOnOrError(parentType), selectionSetOfElement(new Field(((_a = this.element.typeCondition) !== null && _a !== void 0 ? _a : parentType).typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
2009
2089
  }
2010
2090
  }
2011
2091
  }
@@ -2036,7 +2116,7 @@ class InlineFragmentSelection extends FragmentSelection {
2036
2116
  }
2037
2117
  return this.parentType === parentType && this.selectionSet === normalizedSelectionSet
2038
2118
  ? this
2039
- : this.withUpdatedComponents(this.element.rebaseOn(parentType), normalizedSelectionSet);
2119
+ : this.withUpdatedComponents(this.element.rebaseOnOrError(parentType), normalizedSelectionSet);
2040
2120
  }
2041
2121
  expandFragments(updatedFragments) {
2042
2122
  return this.mapToSelectionSet((s) => s.expandFragments(updatedFragments));
@@ -2049,11 +2129,11 @@ class InlineFragmentSelection extends FragmentSelection {
2049
2129
  && this.element.equals(that.element)
2050
2130
  && this.selectionSet.equals(that.selectionSet);
2051
2131
  }
2052
- contains(that) {
2132
+ contains(that, options) {
2053
2133
  if (!(that instanceof FragmentSelection) || !this.element.equals(that.element)) {
2054
2134
  return ContainsResult.NOT_CONTAINED;
2055
2135
  }
2056
- return this.selectionSet.contains(that.selectionSet);
2136
+ return this.selectionSet.contains(that.selectionSet, options);
2057
2137
  }
2058
2138
  toString(expandFragments = true, indent) {
2059
2139
  return (indent !== null && indent !== void 0 ? indent : '') + this.element + ' ' + this.selectionSet.toString(expandFragments, true, indent);
@@ -2081,9 +2161,9 @@ class FragmentSpreadSelection extends FragmentSelection {
2081
2161
  withUpdatedComponents(_fragment, _selectionSet) {
2082
2162
  (0, utils_1.assert)(false, `Unsupported`);
2083
2163
  }
2084
- normalize({ parentType }) {
2164
+ normalizeKnowingItIntersects({ parentType }) {
2085
2165
  (0, utils_1.assert)(parentType.schema() === this.parentType.schema(), 'Should not try to normalize using a type from another schema');
2086
- return this.rebaseOn(parentType, this.fragments);
2166
+ return this.rebaseOnOrError({ parentType, fragments: this.fragments });
2087
2167
  }
2088
2168
  validate() {
2089
2169
  this.validateDeferAndStream();
@@ -2111,14 +2191,17 @@ class FragmentSpreadSelection extends FragmentSelection {
2111
2191
  optimize(_1, _2) {
2112
2192
  return this;
2113
2193
  }
2114
- rebaseOn(parentType, fragments) {
2194
+ rebaseOn({ parentType, fragments, errorIfCannotRebase, }) {
2115
2195
  if (this.parentType === parentType) {
2116
2196
  return this;
2117
2197
  }
2118
2198
  (0, utils_1.assert)(fragments || this.parentType.schema() === parentType.schema(), `Must provide fragments is rebasing on other schema`);
2119
2199
  const newFragments = fragments !== null && fragments !== void 0 ? fragments : this.fragments;
2120
2200
  const namedFragment = newFragments.get(this.namedFragment.name);
2121
- (0, utils_1.assert)(namedFragment, () => `Cannot rebase ${this} if it isn't part of the provided fragments`);
2201
+ if (!namedFragment) {
2202
+ validate(!errorIfCannotRebase, () => `Cannot rebase ${this.toString(false)} if it isn't part of the provided fragments`);
2203
+ return undefined;
2204
+ }
2122
2205
  return new FragmentSpreadSelection(parentType, newFragments, namedFragment, this.spreadDirectives);
2123
2206
  }
2124
2207
  canAddTo(_) {
@@ -2155,14 +2238,14 @@ class FragmentSpreadSelection extends FragmentSelection {
2155
2238
  && this.namedFragment.name === that.namedFragment.name
2156
2239
  && (0, definitions_1.sameDirectiveApplications)(this.spreadDirectives, that.spreadDirectives);
2157
2240
  }
2158
- contains(that) {
2241
+ contains(that, options) {
2159
2242
  if (this.equals(that)) {
2160
2243
  return ContainsResult.EQUAL;
2161
2244
  }
2162
2245
  if (!(that instanceof FragmentSelection) || !this.element.equals(that.element)) {
2163
2246
  return ContainsResult.NOT_CONTAINED;
2164
2247
  }
2165
- return this.selectionSet.contains(that.selectionSet);
2248
+ return this.selectionSet.contains(that.selectionSet, options);
2166
2249
  }
2167
2250
  toString(expandFragments = true, indent) {
2168
2251
  if (expandFragments) {